fix: cluster page references

Signed-off-by: allanice001 <allanice001@gmail.com>
This commit is contained in:
allanice001
2025-12-05 12:31:16 +00:00
parent 2d3800b576
commit 2cd6ee91eb
10 changed files with 54 additions and 94 deletions

View File

@@ -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>

View File

@@ -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 }) {

View File

@@ -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"