diff --git a/ui/api/kafka/schema.ts b/ui/api/kafka/schema.ts index 7e39d34af..78fec0091 100644 --- a/ui/api/kafka/schema.ts +++ b/ui/api/kafka/schema.ts @@ -43,7 +43,7 @@ const ClusterDetailSchema = z.object({ type: z.literal("kafkas"), meta: z .object({ - reconciliationPaused: z.boolean(), + reconciliationPaused: z.boolean().optional(), }) .optional(), attributes: z.object({ diff --git a/ui/app/[locale]/(authorized)/kafka/[kafkaId]/ClusterLinks.tsx b/ui/app/[locale]/(authorized)/kafka/[kafkaId]/ClusterLinks.tsx index 00fb29196..bb239a5eb 100644 --- a/ui/app/[locale]/(authorized)/kafka/[kafkaId]/ClusterLinks.tsx +++ b/ui/app/[locale]/(authorized)/kafka/[kafkaId]/ClusterLinks.tsx @@ -1,21 +1,16 @@ -import { getKafkaCluster } from "@/api/kafka/actions"; import { NavItemLink } from "@/components/Navigation/NavItemLink"; import { NavGroup, NavList } from "@/libs/patternfly/react-core"; import { useTranslations } from "next-intl"; -import { Suspense } from "react"; +import { ClusterDetail } from "@/api/kafka/schema"; -export function ClusterLinks({ kafkaId }: { kafkaId: string }) { +export function ClusterLinks({ kafkaCluster }: { kafkaCluster: ClusterDetail; }) { const t = useTranslations(); + const kafkaId = kafkaCluster.id; + return ( - - - ) as unknown as string - } + title={ kafkaCluster?.attributes.name ?? `Cluster ${kafkaId}` } > {t("AppLayout.cluster_overview")} @@ -26,11 +21,6 @@ export function ClusterLinks({ kafkaId }: { kafkaId: string }) { {t("AppLayout.brokers")} - {/* - - Service registry - -*/} {t("AppLayout.consumer_groups")} @@ -38,8 +28,3 @@ export function ClusterLinks({ kafkaId }: { kafkaId: string }) { ); } - -async function ClusterName({ kafkaId }: { kafkaId: string }) { - const cluster = await getKafkaCluster(kafkaId); - return cluster?.attributes.name ?? `Cluster ${kafkaId}`; -} diff --git a/ui/app/[locale]/(authorized)/kafka/[kafkaId]/layout.tsx b/ui/app/[locale]/(authorized)/kafka/[kafkaId]/layout.tsx index e6125a469..53abb6d02 100644 --- a/ui/app/[locale]/(authorized)/kafka/[kafkaId]/layout.tsx +++ b/ui/app/[locale]/(authorized)/kafka/[kafkaId]/layout.tsx @@ -1,3 +1,5 @@ +import { notFound } from "next/navigation"; +import { getKafkaCluster } from "@/api/kafka/actions"; import { ClusterLinks } from "@/app/[locale]/(authorized)/kafka/[kafkaId]/ClusterLinks"; import { getAuthOptions } from "@/app/api/auth/[...nextauth]/route"; import { AppLayout } from "@/components/AppLayout"; @@ -8,9 +10,9 @@ import { PageGroup, } from "@/libs/patternfly/react-core"; import { getServerSession } from "next-auth"; -import { useTranslations } from "next-intl"; import { PropsWithChildren, ReactNode, Suspense } from "react"; import { KafkaParams } from "./kafka.params"; +import { ClusterDetail } from "@/api/kafka/schema"; export default async function AsyncLayout({ children, @@ -26,11 +28,16 @@ export default async function AsyncLayout({ }>) { const authOptions = await getAuthOptions(); const session = await getServerSession(authOptions); + const cluster = await getKafkaCluster(kafkaId); + + if (!cluster) { + notFound(); + } return ( ) { - const t = useTranslations(); return ( } - kafkaId={kafkaId} + sidebar={} + kafkaCluster={kafkaCluster} > diff --git a/ui/app/[locale]/(authorized)/kafka/[kafkaId]/overview/ConnectedClusterCard.tsx b/ui/app/[locale]/(authorized)/kafka/[kafkaId]/overview/ConnectedClusterCard.tsx index 08beea6cf..a32961694 100644 --- a/ui/app/[locale]/(authorized)/kafka/[kafkaId]/overview/ConnectedClusterCard.tsx +++ b/ui/app/[locale]/(authorized)/kafka/[kafkaId]/overview/ConnectedClusterCard.tsx @@ -14,23 +14,24 @@ export async function ConnectedClusterCard({ return ( ); } const groupCount = await consumerGroups.then( (grpResp) => grpResp?.meta.page.total ?? 0, ); - const brokersTotal = Object.keys(res?.kpis.broker_state || {}).length; + const brokersTotal = Object.keys(res?.kpis.broker_state ?? {}).length; const brokersOnline = - Object.values(res?.kpis.broker_state || {}).filter((s) => s === 3).length || + Object.values(res?.kpis.broker_state ?? {}).filter((s) => s === 3).length || 0; const messages = res?.cluster.attributes.conditions ?.filter((c) => "Ready" !== c.type) @@ -38,7 +39,7 @@ export async function ConnectedClusterCard({ variant: c.type === "Error" ? "danger" : ("warning" as "danger" | "warning"), subject: { - type: "cluster" as "cluster" | "broker" | "topic", + type: c.type!, name: res?.cluster.attributes.name ?? "", id: res?.cluster.id ?? "", }, @@ -49,14 +50,15 @@ export async function ConnectedClusterCard({ return ( ); } diff --git a/ui/components/AppLayout.tsx b/ui/components/AppLayout.tsx index bfcfc94be..830a61d7f 100644 --- a/ui/components/AppLayout.tsx +++ b/ui/components/AppLayout.tsx @@ -3,6 +3,7 @@ import { useTranslations } from "next-intl"; import { PropsWithChildren, ReactNode } from "react"; import { AppMasthead } from "./AppMasthead"; import { AppSidebar } from "./AppSidebar"; +import { ClusterDetail } from "@/api/kafka/schema"; import { ClusterDrawer } from "./ClusterDrawer"; import { ClusterDrawerProvider } from "./ClusterDrawerProvider"; @@ -12,12 +13,12 @@ import { ReconciliationPausedBanner } from "./ReconciliationPausedBanner"; export function AppLayout({ username, sidebar, + kafkaCluster, children, - kafkaId, }: PropsWithChildren<{ username?: string; sidebar?: ReactNode; - kafkaId?: string; + kafkaCluster: ClusterDetail; }>) { const t = useTranslations(); @@ -37,7 +38,7 @@ export function AppLayout({ {/**/} - + {children} diff --git a/ui/components/ClusterOverview/ClusterCard.tsx b/ui/components/ClusterOverview/ClusterCard.tsx index 68153c4cc..e581129ab 100644 --- a/ui/components/ClusterOverview/ClusterCard.tsx +++ b/ui/components/ClusterOverview/ClusterCard.tsx @@ -41,9 +41,10 @@ type ClusterCardProps = { consumerGroups?: number; kafkaVersion: string; kafkaId: string | undefined; + reconciliationPaused: boolean; messages: Array<{ variant: "danger" | "warning"; - subject: { type: "cluster" | "broker" | "topic"; name: string; id: string }; + subject: { type: string; name: string; id: string }; message: string; date: string; }>; @@ -59,6 +60,7 @@ export function ClusterCard({ kafkaVersion, messages, kafkaId, + reconciliationPaused, }: | ({ isLoading: false; @@ -69,6 +71,8 @@ export function ClusterCard({ const { isReconciliationPaused, setReconciliationPaused } = useReconciliationContext(); + setReconciliationPaused(reconciliationPaused as boolean); + const resumeReconciliation = async () => { if (!kafkaId) { console.log("kafkaId is undefined"); @@ -232,7 +236,7 @@ export function ClusterCard({ )) ) : ( <> - {!isReconciliationPaused && messages.length === 0 && ( + {messages.length === 0 && ( )} - {isReconciliationPaused && ( - - - - - - -   - - , - -
- -
-
, - - - , - - - , - ]} - /> -
-
- )} {messages .sort((a, b) => a.date.localeCompare(b.date)) .reverse() @@ -321,7 +262,7 @@ export function ClusterCard({ {m.variant === "danger" && ( @@ -332,17 +273,26 @@ export function ClusterCard({ )}   - - - + {m.subject.type} , - +
- + + {m.subject.type === 'ReconciliationPaused' && ( + <> +   + + + )}
{ - if (!kafkaId) { - console.log("kafkaId is undefined"); + if (!kafkaCluster) { + console.log("kafkaCluster is undefined"); return; } try { - const success = await updateKafkaCluster(kafkaId, false); + const success = await updateKafkaCluster(kafkaCluster.id, false); if (success) { setReconciliationPaused(false); @@ -36,6 +39,7 @@ export function ReconciliationPausedBanner({ kafkaId }: { kafkaId: string | unde {t("reconciliation.reconciliation_paused_warning")} +