mirror of
https://github.com/GlueOps/autoglue.git
synced 2026-02-13 04:40:05 +01:00
fix: cluster page references
Signed-off-by: allanice001 <allanice001@gmail.com>
This commit is contained in:
@@ -27,7 +27,7 @@ export type NavItem = {
|
|||||||
|
|
||||||
export const mainNav: NavItem[] = [
|
export const mainNav: NavItem[] = [
|
||||||
{ to: "/clusters", label: "Clusters", icon: AiOutlineCluster },
|
{ to: "/clusters", label: "Clusters", icon: AiOutlineCluster },
|
||||||
{ to: "/load-balancers", label: "Load Balancers", icon: TbLoadBalancer},
|
{ to: "/load-balancers", label: "Load Balancers", icon: TbLoadBalancer },
|
||||||
{ to: "/dns", label: "DNS", icon: MdOutlineDns },
|
{ to: "/dns", label: "DNS", icon: MdOutlineDns },
|
||||||
{ to: "/node-pools", label: "Node Pools", icon: BoxesIcon },
|
{ to: "/node-pools", label: "Node Pools", icon: BoxesIcon },
|
||||||
{ to: "/annotations", label: "Annotations", icon: ComponentIcon },
|
{ to: "/annotations", label: "Annotations", icon: ComponentIcon },
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
;
|
;
|
||||||
|
|
||||||
// src/pages/ClustersPage.tsx
|
// src/pages/ClustersPage.tsx
|
||||||
|
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
@@ -28,36 +27,6 @@ import { Label } from "@/components/ui/label.tsx";
|
|||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select.tsx";
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select.tsx";
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table.tsx";
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table.tsx";
|
||||||
import { Textarea } from "@/components/ui/textarea.tsx";
|
import { Textarea } from "@/components/ui/textarea.tsx";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -67,7 +36,7 @@ import { Textarea } from "@/components/ui/textarea.tsx";
|
|||||||
|
|
||||||
const createClusterSchema = z.object({
|
const createClusterSchema = z.object({
|
||||||
name: z.string().trim().min(1, "Name is required").max(120, "Max 120 chars"),
|
name: z.string().trim().min(1, "Name is required").max(120, "Max 120 chars"),
|
||||||
provider: z.string().trim().min(1, "Provider is required").max(120, "Max 120 chars"),
|
cluster_provider: z.string().trim().min(1, "Provider is required").max(120, "Max 120 chars"),
|
||||||
region: z.string().trim().min(1, "Region is required").max(120, "Max 120 chars"),
|
region: z.string().trim().min(1, "Region is required").max(120, "Max 120 chars"),
|
||||||
})
|
})
|
||||||
type CreateClusterInput = z.input<typeof createClusterSchema>
|
type CreateClusterInput = z.input<typeof createClusterSchema>
|
||||||
@@ -133,12 +102,12 @@ function StatusBadge({ status }: { status?: string | null }) {
|
|||||||
|
|
||||||
function ClusterSummary({ c }: { c: DtoClusterResponse }) {
|
function ClusterSummary({ c }: { c: DtoClusterResponse }) {
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-1 text-xs text-muted-foreground">
|
<div className="text-muted-foreground flex flex-col gap-1 text-xs">
|
||||||
<div className="flex flex-wrap items-center gap-2">
|
<div className="flex flex-wrap items-center gap-2">
|
||||||
{c.provider && (
|
{c.cluster_provider && (
|
||||||
<span className="inline-flex items-center gap-1">
|
<span className="inline-flex items-center gap-1">
|
||||||
<Globe2 className="h-3 w-3" />
|
<Globe2 className="h-3 w-3" />
|
||||||
{c.provider}
|
{c.cluster_provider}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{c.region && (
|
{c.region && (
|
||||||
@@ -227,7 +196,7 @@ export const ClustersPage = () => {
|
|||||||
resolver: zodResolver(createClusterSchema),
|
resolver: zodResolver(createClusterSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: "",
|
name: "",
|
||||||
provider: "",
|
cluster_provider: "",
|
||||||
region: "",
|
region: "",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -275,7 +244,7 @@ export const ClustersPage = () => {
|
|||||||
setEditingId(cluster.id)
|
setEditingId(cluster.id)
|
||||||
updateForm.reset({
|
updateForm.reset({
|
||||||
name: cluster.name ?? "",
|
name: cluster.name ?? "",
|
||||||
provider: cluster.provider ?? "",
|
cluster_provider: cluster.cluster_provider ?? "",
|
||||||
region: cluster.region ?? "",
|
region: cluster.region ?? "",
|
||||||
})
|
})
|
||||||
setUpdateOpen(true)
|
setUpdateOpen(true)
|
||||||
@@ -305,7 +274,7 @@ export const ClustersPage = () => {
|
|||||||
? data.filter((c) => {
|
? data.filter((c) => {
|
||||||
return (
|
return (
|
||||||
c.name?.toLowerCase().includes(q) ||
|
c.name?.toLowerCase().includes(q) ||
|
||||||
c.provider?.toLowerCase().includes(q) ||
|
c.cluster_provider?.toLowerCase().includes(q) ||
|
||||||
c.region?.toLowerCase().includes(q) ||
|
c.region?.toLowerCase().includes(q) ||
|
||||||
c.status?.toLowerCase().includes(q)
|
c.status?.toLowerCase().includes(q)
|
||||||
)
|
)
|
||||||
@@ -647,7 +616,7 @@ export const ClustersPage = () => {
|
|||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={createForm.control}
|
control={createForm.control}
|
||||||
name="provider"
|
name="cluster_provider"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Provider</FormLabel>
|
<FormLabel>Provider</FormLabel>
|
||||||
@@ -705,7 +674,7 @@ export const ClustersPage = () => {
|
|||||||
{filtered.map((c: DtoClusterResponse) => (
|
{filtered.map((c: DtoClusterResponse) => (
|
||||||
<TableRow key={c.id}>
|
<TableRow key={c.id}>
|
||||||
<TableCell className="font-medium">{c.name}</TableCell>
|
<TableCell className="font-medium">{c.name}</TableCell>
|
||||||
<TableCell>{c.provider}</TableCell>
|
<TableCell>{c.cluster_provider}</TableCell>
|
||||||
<TableCell>{c.region}</TableCell>
|
<TableCell>{c.region}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<StatusBadge status={c.status} />
|
<StatusBadge status={c.status} />
|
||||||
@@ -787,7 +756,7 @@ export const ClustersPage = () => {
|
|||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={updateForm.control}
|
control={updateForm.control}
|
||||||
name="provider"
|
name="cluster_provider"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Provider</FormLabel>
|
<FormLabel>Provider</FormLabel>
|
||||||
@@ -843,7 +812,7 @@ export const ClustersPage = () => {
|
|||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<FileCode2 className="h-4 w-4" />
|
<FileCode2 className="h-4 w-4" />
|
||||||
<h3 className="font-semibold text-sm">Kubeconfig</h3>
|
<h3 className="text-sm font-semibold">Kubeconfig</h3>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-muted-foreground text-xs">
|
<p className="text-muted-foreground text-xs">
|
||||||
Paste the kubeconfig for this cluster. It will be stored encrypted and never
|
Paste the kubeconfig for this cluster. It will be stored encrypted and never
|
||||||
@@ -861,11 +830,7 @@ export const ClustersPage = () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
<Button
|
<Button size="sm" onClick={handleSetKubeconfig} disabled={isBusy("kubeconfig")}>
|
||||||
size="sm"
|
|
||||||
onClick={handleSetKubeconfig}
|
|
||||||
disabled={isBusy("kubeconfig")}
|
|
||||||
>
|
|
||||||
{isBusy("kubeconfig") ? "Saving…" : "Save kubeconfig"}
|
{isBusy("kubeconfig") ? "Saving…" : "Save kubeconfig"}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -883,7 +848,7 @@ export const ClustersPage = () => {
|
|||||||
<section className="space-y-2 rounded-xl border p-4">
|
<section className="space-y-2 rounded-xl border p-4">
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold text-sm">Captain Domain</h3>
|
<h3 className="text-sm font-semibold">Captain Domain</h3>
|
||||||
<p className="text-muted-foreground text-xs">
|
<p className="text-muted-foreground text-xs">
|
||||||
Domain used for the AutoGlue captain endpoint.
|
Domain used for the AutoGlue captain endpoint.
|
||||||
</p>
|
</p>
|
||||||
@@ -909,9 +874,7 @@ export const ClustersPage = () => {
|
|||||||
>
|
>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
<SelectValue
|
<SelectValue
|
||||||
placeholder={
|
placeholder={domainsQ.isLoading ? "Loading domains…" : "Select domain"}
|
||||||
domainsQ.isLoading ? "Loading domains…" : "Select domain"
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@@ -952,7 +915,7 @@ export const ClustersPage = () => {
|
|||||||
<section className="space-y-2 rounded-xl border p-4">
|
<section className="space-y-2 rounded-xl border p-4">
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold text-sm">Control Plane Record Set</h3>
|
<h3 className="text-sm font-semibold">Control Plane Record Set</h3>
|
||||||
<p className="text-muted-foreground text-xs">
|
<p className="text-muted-foreground text-xs">
|
||||||
DNS record set used for the cluster control plane endpoint.
|
DNS record set used for the cluster control plane endpoint.
|
||||||
</p>
|
</p>
|
||||||
@@ -973,9 +936,7 @@ export const ClustersPage = () => {
|
|||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
<SelectValue
|
<SelectValue
|
||||||
placeholder={
|
placeholder={
|
||||||
recordSetsQ.isLoading
|
recordSetsQ.isLoading ? "Loading record sets…" : "Select record set"
|
||||||
? "Loading record sets…"
|
|
||||||
: "Select record set"
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
@@ -1000,9 +961,7 @@ export const ClustersPage = () => {
|
|||||||
size="sm"
|
size="sm"
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={handleDetachRecordSet}
|
onClick={handleDetachRecordSet}
|
||||||
disabled={
|
disabled={isBusy("recordset") || !configCluster.control_plane_record_set}
|
||||||
isBusy("recordset") || !configCluster.control_plane_record_set
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
Detach
|
Detach
|
||||||
</Button>
|
</Button>
|
||||||
@@ -1015,7 +974,7 @@ export const ClustersPage = () => {
|
|||||||
<section className="space-y-2 rounded-xl border p-4">
|
<section className="space-y-2 rounded-xl border p-4">
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold text-sm">Apps Load Balancer</h3>
|
<h3 className="text-sm font-semibold">Apps Load Balancer</h3>
|
||||||
<p className="text-muted-foreground text-xs">
|
<p className="text-muted-foreground text-xs">
|
||||||
Frontend load balancer for application traffic.
|
Frontend load balancer for application traffic.
|
||||||
</p>
|
</p>
|
||||||
@@ -1073,7 +1032,7 @@ export const ClustersPage = () => {
|
|||||||
<section className="space-y-2 rounded-xl border p-4">
|
<section className="space-y-2 rounded-xl border p-4">
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold text-sm">GlueOps / Control-plane Load Balancer</h3>
|
<h3 className="text-sm font-semibold">GlueOps / Control-plane Load Balancer</h3>
|
||||||
<p className="text-muted-foreground text-xs">
|
<p className="text-muted-foreground text-xs">
|
||||||
Load balancer for GlueOps/control-plane traffic.
|
Load balancer for GlueOps/control-plane traffic.
|
||||||
</p>
|
</p>
|
||||||
@@ -1133,7 +1092,7 @@ export const ClustersPage = () => {
|
|||||||
<div>
|
<div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Server className="h-4 w-4" />
|
<Server className="h-4 w-4" />
|
||||||
<h3 className="font-semibold text-sm">Bastion Server</h3>
|
<h3 className="text-sm font-semibold">Bastion Server</h3>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-muted-foreground text-xs">
|
<p className="text-muted-foreground text-xs">
|
||||||
SSH bastion used to reach the cluster nodes.
|
SSH bastion used to reach the cluster nodes.
|
||||||
@@ -1142,8 +1101,7 @@ export const ClustersPage = () => {
|
|||||||
<div className="text-right text-xs">
|
<div className="text-right text-xs">
|
||||||
<div className="font-mono">
|
<div className="font-mono">
|
||||||
{configCluster.bastion_server
|
{configCluster.bastion_server
|
||||||
? configCluster.bastion_server.hostname ??
|
? (configCluster.bastion_server.hostname ?? configCluster.bastion_server.id)
|
||||||
configCluster.bastion_server.id
|
|
||||||
: "Not attached"}
|
: "Not attached"}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1155,9 +1113,7 @@ export const ClustersPage = () => {
|
|||||||
<Select value={bastionId} onValueChange={(val) => setBastionId(val)}>
|
<Select value={bastionId} onValueChange={(val) => setBastionId(val)}>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
<SelectValue
|
<SelectValue
|
||||||
placeholder={
|
placeholder={serversQ.isLoading ? "Loading servers…" : "Select server"}
|
||||||
serversQ.isLoading ? "Loading servers…" : "Select server"
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
@@ -1193,7 +1149,7 @@ export const ClustersPage = () => {
|
|||||||
<section className="space-y-2 rounded-xl border p-4">
|
<section className="space-y-2 rounded-xl border p-4">
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="font-semibold text-sm">Node Pools</h3>
|
<h3 className="text-sm font-semibold">Node Pools</h3>
|
||||||
<p className="text-muted-foreground text-xs">
|
<p className="text-muted-foreground text-xs">
|
||||||
Attach node pools to this cluster. Each node pool may have its own labels,
|
Attach node pools to this cluster. Each node pool may have its own labels,
|
||||||
taints, and backing servers.
|
taints, and backing servers.
|
||||||
@@ -1207,9 +1163,7 @@ export const ClustersPage = () => {
|
|||||||
<Select value={nodePoolId} onValueChange={(val) => setNodePoolId(val)}>
|
<Select value={nodePoolId} onValueChange={(val) => setNodePoolId(val)}>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
<SelectValue
|
<SelectValue
|
||||||
placeholder={
|
placeholder={npQ.isLoading ? "Loading node pools…" : "Select node pool"}
|
||||||
npQ.isLoading ? "Loading node pools…" : "Select node pool"
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
|
|||||||
@@ -160,10 +160,22 @@ function extractErr(e: any): string {
|
|||||||
return "Unknown error"
|
return "Unknown error"
|
||||||
}
|
}
|
||||||
|
|
||||||
function isAwsServiceScope({ credential_provider, scope_kind }: { credential_provider?: string; scope_kind?: string }) {
|
function isAwsServiceScope({
|
||||||
|
credential_provider,
|
||||||
|
scope_kind,
|
||||||
|
}: {
|
||||||
|
credential_provider?: string
|
||||||
|
scope_kind?: string
|
||||||
|
}) {
|
||||||
return credential_provider === "aws" && scope_kind === "service"
|
return credential_provider === "aws" && scope_kind === "service"
|
||||||
}
|
}
|
||||||
function isAwsResourceScope({ credential_provider, scope_kind }: { credential_provider?: string; scope_kind?: string }) {
|
function isAwsResourceScope({
|
||||||
|
credential_provider,
|
||||||
|
scope_kind,
|
||||||
|
}: {
|
||||||
|
credential_provider?: string
|
||||||
|
scope_kind?: string
|
||||||
|
}) {
|
||||||
return credential_provider === "aws" && scope_kind === "resource"
|
return credential_provider === "aws" && scope_kind === "resource"
|
||||||
}
|
}
|
||||||
function isProviderScope({ scope_kind }: { scope_kind?: string }) {
|
function isProviderScope({ scope_kind }: { scope_kind?: string }) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useRef, useState, type FC } from "react"
|
import { type FC, useEffect, useRef, useState } from "react"
|
||||||
import { useTheme } from "next-themes"
|
import { useTheme } from "next-themes"
|
||||||
|
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
@@ -7,13 +7,7 @@ import { Input } from "@/components/ui/input"
|
|||||||
import "rapidoc"
|
import "rapidoc"
|
||||||
|
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx"
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card.tsx"
|
||||||
import {
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select.tsx"
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from "@/components/ui/select.tsx"
|
|
||||||
|
|
||||||
type RdThemeMode = "auto" | "light" | "dark"
|
type RdThemeMode = "auto" | "light" | "dark"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user