Skip to content

Commit

Permalink
Pass Kafka cluster from layout for drawer/paused banner
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Edgar <[email protected]>
  • Loading branch information
MikeEdgar committed Oct 17, 2024
1 parent ae3275c commit 18d0ca0
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 115 deletions.
2 changes: 1 addition & 1 deletion ui/api/kafka/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
25 changes: 5 additions & 20 deletions ui/app/[locale]/(authorized)/kafka/[kafkaId]/ClusterLinks.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<NavList>
<NavGroup
title={
(
<Suspense>
<ClusterName kafkaId={kafkaId} />
</Suspense>
) as unknown as string
}
title={ kafkaCluster?.attributes.name ?? `Cluster ${kafkaId}` }
>
<NavItemLink url={`/kafka/${kafkaId}/overview`}>
{t("AppLayout.cluster_overview")}
Expand All @@ -26,20 +21,10 @@ export function ClusterLinks({ kafkaId }: { kafkaId: string }) {
<NavItemLink url={`/kafka/${kafkaId}/nodes`}>
{t("AppLayout.brokers")}
</NavItemLink>
{/*
<NavItemLink url={`/kafka/${kafkaId}/service-registry`}>
Service registry
</NavItemLink>
*/}
<NavItemLink url={`/kafka/${kafkaId}/consumer-groups`}>
{t("AppLayout.consumer_groups")}
</NavItemLink>
</NavGroup>
</NavList>
);
}

async function ClusterName({ kafkaId }: { kafkaId: string }) {
const cluster = await getKafkaCluster(kafkaId);
return cluster?.attributes.name ?? `Cluster ${kafkaId}`;
}
22 changes: 14 additions & 8 deletions ui/app/[locale]/(authorized)/kafka/[kafkaId]/layout.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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,
Expand All @@ -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 (
<Layout
username={(session?.user?.name || session?.user?.email) ?? "User"}
kafkaId={kafkaId}
username={(session?.user?.name ?? session?.user?.email) ?? "User"}
kafkaCluster={cluster}
activeBreadcrumb={activeBreadcrumb}
header={header}
modal={modal}
Expand All @@ -45,22 +52,21 @@ function Layout({
activeBreadcrumb,
header,
modal,
kafkaId,
kafkaCluster,
username,
}: PropsWithChildren<{
kafkaId: string;
kafkaCluster: ClusterDetail;
username: string;
header: ReactNode;
activeBreadcrumb: ReactNode;
modal: ReactNode;
}>) {
const t = useTranslations();
return (
<AppLayoutProvider>
<AppLayout
username={username}
sidebar={<ClusterLinks kafkaId={kafkaId} />}
kafkaId={kafkaId}
sidebar={<ClusterLinks kafkaCluster={kafkaCluster} />}
kafkaCluster={kafkaCluster}
>
<PageGroup stickyOnBreakpoint={{ default: "top" }}>
<PageBreadcrumb>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,32 @@ export async function ConnectedClusterCard({
return (
<ClusterCard
isLoading={false}
status={res?.cluster.attributes.status || "n/a"}
status={res?.cluster.attributes.status ?? "n/a"}
messages={[]}
name={res?.cluster.attributes.name || "n/a"}
name={res?.cluster.attributes.name ?? "n/a"}
consumerGroups={undefined}
brokersOnline={undefined}
brokersTotal={undefined}
kafkaVersion={res?.cluster.attributes.kafkaVersion || "n/a"}
kafkaVersion={res?.cluster.attributes.kafkaVersion ?? "n/a"}
kafkaId={res?.cluster.id}
reconciliationPaused={res?.cluster.meta?.reconciliationPaused ?? false}
/>
);
}
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)
.map((c) => ({
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 ?? "",
},
Expand All @@ -49,14 +50,15 @@ export async function ConnectedClusterCard({
return (
<ClusterCard
isLoading={false}
status={res?.cluster.attributes.status || "n/a"}
status={res?.cluster.attributes.status ?? "n/a"}
messages={messages ?? []}
name={res?.cluster.attributes.name || "n/a"}
consumerGroups={groupCount}
brokersOnline={brokersOnline}
brokersTotal={brokersTotal}
kafkaVersion={res?.cluster.attributes.kafkaVersion || "n/a"}
kafkaVersion={res?.cluster.attributes.kafkaVersion ?? "n/a"}
kafkaId={res.cluster.id}
reconciliationPaused={res?.cluster.meta?.reconciliationPaused ?? false}
/>
);
}
9 changes: 6 additions & 3 deletions ui/components/AppLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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();

Expand All @@ -37,7 +38,9 @@ export function AppLayout({
{/*<HelpContainer>*/}
<ClusterDrawerProvider>
<ReconciliationProvider>
<ReconciliationPausedBanner kafkaId={kafkaId} />
{kafkaCluster && (
<ReconciliationPausedBanner kafkaCluster={kafkaCluster} />
)}
<ClusterDrawer>{children}</ClusterDrawer>
</ReconciliationProvider>
</ClusterDrawerProvider>
Expand Down
92 changes: 21 additions & 71 deletions ui/components/ClusterOverview/ClusterCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}>;
Expand All @@ -59,6 +60,7 @@ export function ClusterCard({
kafkaVersion,
messages,
kafkaId,
reconciliationPaused,
}:
| ({
isLoading: false;
Expand All @@ -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");
Expand Down Expand Up @@ -232,7 +236,7 @@ export function ClusterCard({
))
) : (
<>
{!isReconciliationPaused && messages.length === 0 && (
{messages.length === 0 && (
<DataListItem aria-labelledby={`no-messages`}>
<DataListItemRow>
<DataListItemCells
Expand All @@ -247,69 +251,6 @@ export function ClusterCard({
</DataListItemRow>
</DataListItem>
)}
{isReconciliationPaused && (
<DataListItem aria-labelledby={`reconciliation-warning`}>
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell
key="warning-message"
className={"pf-v5-u-text-nowrap"}
width={2}
>
<Icon status={"warning"}>
<ExclamationTriangleIcon />
</Icon>
&nbsp;
<Truncate
content={t(
"reconciliation.reconciliation_paused",
)}
/>
</DataListCell>,
<DataListCell key="message" width={3}>
<div
className={
"pf-v5-u-display-none pf-v5-u-display-block-on-md"
}
>
<Truncate
content={t(
"reconciliation.reconciliation_paused_warning",
)}
/>
</div>
</DataListCell>,
<DataListCell
key="button"
width={1}
className={"pf-v5-u-text-nowrap"}
>
<Button
variant="link"
isInline
onClick={resumeReconciliation}
>
{t("reconciliation.resume")}
</Button>
</DataListCell>,
<DataListCell
key="date"
width={1}
className={"pf-v5-u-text-nowrap"}
>
<DateTime
value={new Date(Date.now())}
tz={"UTC"}
dateStyle={"short"}
timeStyle={"short"}
/>
</DataListCell>,
]}
/>
</DataListItemRow>
</DataListItem>
)}
{messages
.sort((a, b) => a.date.localeCompare(b.date))
.reverse()
Expand All @@ -321,7 +262,7 @@ export function ClusterCard({
<DataListCell
key="name"
className={"pf-v5-u-text-nowrap"}
width={2}
width={1}
>
<Icon status={m.variant}>
{m.variant === "danger" && (
Expand All @@ -332,17 +273,26 @@ export function ClusterCard({
)}
</Icon>
&nbsp;
<Link href={""} id={`message-${i}`}>
<Truncate content={m.subject.name} />
</Link>
{m.subject.type}
</DataListCell>,
<DataListCell key="message" width={4}>
<DataListCell key="message" width={5}>
<div
className={
"pf-v5-u-display-none pf-v5-u-display-block-on-md"
}
>
<Truncate content={m.message} />
<Truncate content={ m.subject.type === 'ReconciliationPaused'
? t("reconciliation.reconciliation_paused_warning",)
: m.message}
/>
{m.subject.type === 'ReconciliationPaused' && (
<>
&nbsp;
<Button variant="link" isInline onClick={resumeReconciliation}>
{t("reconciliation.resume")}
</Button>
</>
)}
</div>
<div
className={
Expand Down
12 changes: 8 additions & 4 deletions ui/components/ReconciliationPausedBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,23 @@ import { Banner, Bullseye, Button, FlexItem, Flex } from "@/libs/patternfly/reac
import { useTranslations } from "next-intl";
import { useReconciliationContext } from "./ReconciliationContext";
import { updateKafkaCluster } from "@/api/kafka/actions";
import { ClusterDetail } from "@/api/kafka/schema";

export function ReconciliationPausedBanner({ kafkaId }: { kafkaId: string | undefined }) {
export function ReconciliationPausedBanner({ kafkaCluster }: { kafkaCluster: ClusterDetail; }) {
const t = useTranslations();

const { isReconciliationPaused, setReconciliationPaused } = useReconciliationContext();

setReconciliationPaused(kafkaCluster.meta?.reconciliationPaused ?? false);

const resumeReconciliation = async () => {
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);
Expand All @@ -36,6 +39,7 @@ export function ReconciliationPausedBanner({ kafkaId }: { kafkaId: string | unde
<FlexItem spacer={{ default: "spacerNone" }}>
{t("reconciliation.reconciliation_paused_warning")}
</FlexItem>
&nbsp;
<FlexItem spacer={{ default: "spacerLg" }}>
<Button variant="link" isInline onClick={resumeReconciliation}>
{t("reconciliation.resume")}
Expand Down

0 comments on commit 18d0ca0

Please sign in to comment.