Skip to content

Commit

Permalink
feat: pause reconciliation
Browse files Browse the repository at this point in the history
Signed-off-by: hemahg <[email protected]>
  • Loading branch information
hemahg committed Oct 10, 2024
1 parent 201fc88 commit 580b5a7
Show file tree
Hide file tree
Showing 10 changed files with 242 additions and 8 deletions.
33 changes: 33 additions & 0 deletions ui/api/kafka/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,3 +360,36 @@ export async function getKafkaTopicMetrics(
};
}
}

export async function updateKafkaCluster(
clusterId: string,
reconciliationPaused?: boolean,
): Promise<boolean> {
const url = `${process.env.BACKEND_URL}/api/kafkas/${clusterId}`;
const body = {
data: {
type: "kafkas",
id: clusterId,
meta: {
reconciliationPaused: reconciliationPaused,
},
attributes: {},
},
};

try {
const res = await fetch(url, {
headers: await getHeaders(),
method: "PATCH",
body: JSON.stringify(body),
});

if (res.status === 204) {
return true;
} else {
return false;
}
} catch (e) {
return false;
}
}
5 changes: 5 additions & 0 deletions ui/api/kafka/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ export type ClusterList = z.infer<typeof ClusterListSchema>;
const ClusterDetailSchema = z.object({
id: z.string(),
type: z.literal("kafkas"),
meta: z
.object({
reconciliationPaused: z.boolean(),
})
.optional(),
attributes: z.object({
name: z.string(),
namespace: z.string().nullable().optional(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,56 @@
"use client";

import { updateKafkaCluster } from "@/api/kafka/actions";
import { useOpenClusterConnectionPanel } from "@/components/ClusterDrawerContext";
import { Button } from "@/libs/patternfly/react-core";
import { ReconciliationModal } from "@/components/ClusterOverview/ReconciliationModal";
import {
Button,
Flex,
FlexItem,
Grid,
GridItem,
} from "@/libs/patternfly/react-core";
import { useTranslations } from "next-intl";
import { useState } from "react";

export function ConnectButton({ clusterId }: { clusterId: string }) {
const t = useTranslations();
const open = useOpenClusterConnectionPanel();

const [isModalOpen, setIsModalOpen] = useState<boolean>(false);

const handleSave = async () => {
try {
const success = await updateKafkaCluster(clusterId, true);
if (success) {
setIsModalOpen(false);
}
} catch (e: unknown) {
console.log("Unknown error occurred");
}
};

return (
<Button onClick={() => open(clusterId)}>
{t("ConnectButton.cluster_connection_details")}
</Button>
<>
<Flex>
<FlexItem>
<Button variant="secondary" onClick={() => setIsModalOpen(true)}>
{t("reconciliation.pause_reconciliation_button")}
</Button>
</FlexItem>
<FlexItem>
<Button onClick={() => open(clusterId)}>
{t("ConnectButton.cluster_connection_details")}
</Button>
</FlexItem>
</Flex>
{isModalOpen && (
<ReconciliationModal
isModalOpen={isModalOpen}
onClickClose={() => setIsModalOpen(false)}
onClickPauseReconciliation={handleSave}
/>
)}
</>
);
}
12 changes: 12 additions & 0 deletions ui/app/[locale]/(authorized)/kafka/[kafkaId]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { getServerSession } from "next-auth";
import { useTranslations } from "next-intl";
import { PropsWithChildren, ReactNode, Suspense } from "react";
import { KafkaParams } from "./kafka.params";
import { getKafkaCluster } from "@/api/kafka/actions";

export default async function AsyncLayout({
children,
Expand All @@ -26,13 +27,21 @@ export default async function AsyncLayout({
}>) {
const authOptions = await getAuthOptions();
const session = await getServerSession(authOptions);

const data = await getKafkaCluster(kafkaId);
if (!data) {
return null;
}
const reconciliationPaused = data.meta?.reconciliationPaused;

return (
<Layout
username={(session?.user?.name || session?.user?.email) ?? "User"}
kafkaId={kafkaId}
activeBreadcrumb={activeBreadcrumb}
header={header}
modal={modal}
reconciliationPaused={reconciliationPaused && reconciliationPaused}
>
{children}
</Layout>
Expand All @@ -46,19 +55,22 @@ function Layout({
modal,
kafkaId,
username,
reconciliationPaused,
}: PropsWithChildren<{
kafkaId: string;
username: string;
header: ReactNode;
activeBreadcrumb: ReactNode;
modal: ReactNode;
reconciliationPaused?: boolean;
}>) {
const t = useTranslations();
return (
<AppLayoutProvider>
<AppLayout
username={username}
sidebar={<ClusterLinks kafkaId={kafkaId} />}
reconciliationPaused={reconciliationPaused}
>
<PageGroup stickyOnBreakpoint={{ default: "top" }}>
<PageBreadcrumb>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export async function ConnectedClusterCard({
brokersOnline={undefined}
brokersTotal={undefined}
kafkaVersion={res?.cluster.attributes.kafkaVersion || "n/a"}
reconciliationPuased={res?.cluster.meta?.reconciliationPaused}
/>
);
}
Expand Down Expand Up @@ -55,6 +56,7 @@ export async function ConnectedClusterCard({
brokersOnline={brokersOnline}
brokersTotal={brokersTotal}
kafkaVersion={res?.cluster.attributes.kafkaVersion || "n/a"}
reconciliationPuased={res?.cluster.meta?.reconciliationPaused}
/>
);
}
35 changes: 32 additions & 3 deletions ui/components/AppLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { Nav, Page } from "@/libs/patternfly/react-core";
import {
Banner,
Bullseye,
Button,
Flex,
FlexItem,
Nav,
Page,
} from "@/libs/patternfly/react-core";
import { useTranslations } from "next-intl";
import { PropsWithChildren, ReactNode } from "react";
import { AppMasthead } from "./AppMasthead";
Expand All @@ -11,7 +19,12 @@ export function AppLayout({
username,
sidebar,
children,
}: PropsWithChildren<{ username?: string; sidebar?: ReactNode }>) {
reconciliationPaused,
}: PropsWithChildren<{
username?: string;
sidebar?: ReactNode;
reconciliationPaused?: boolean;
}>) {
const t = useTranslations();
return (
<Page
Expand All @@ -28,7 +41,23 @@ export function AppLayout({
>
{/*<HelpContainer>*/}
<ClusterDrawerProvider>
<ClusterDrawer>{children}</ClusterDrawer>
<ClusterDrawer>
<Banner variant="gold">
<Bullseye>
<Flex>
<FlexItem spacer={{ default: "spacerNone" }}>
{t("reconciliation.reconciliation_paused_warning")}
</FlexItem>
<FlexItem spacer={{ default: "spacerLg" }}>
<Button variant="link" isInline>
{t("reconciliation.resume")}
</Button>
</FlexItem>
</Flex>
</Bullseye>
</Banner>
{children}
</ClusterDrawer>
</ClusterDrawerProvider>
{/*</HelpContainer>*/}
</Page>
Expand Down
2 changes: 2 additions & 0 deletions ui/components/ClusterOverview/ClusterCard.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Story = StoryObj<typeof ClusterCard>;
export const WithData: Story = {
args: {
isLoading: false,
reconciliationPuased: true,
name: "my-kafka-cluster",
status: "ready",
brokersTotal: 9999,
Expand Down Expand Up @@ -71,6 +72,7 @@ export const NoMessages: Story = {
brokersOnline: 9999,
consumerGroups: 9999,
kafkaVersion: "3.5.6",
reconciliationPuased: false,
messages: [],
},
};
Expand Down
64 changes: 63 additions & 1 deletion ui/components/ClusterOverview/ClusterCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { DateTime } from "@/components/Format/DateTime";
import { Number } from "@/components/Format/Number";
import {
Button,
Card,
CardBody,
DataList,
Expand Down Expand Up @@ -37,6 +38,7 @@ type ClusterCardProps = {
brokersTotal?: number;
consumerGroups?: number;
kafkaVersion: string;
reconciliationPuased?: boolean;
messages: Array<{
variant: "danger" | "warning";
subject: { type: "cluster" | "broker" | "topic"; name: string; id: string };
Expand All @@ -54,6 +56,7 @@ export function ClusterCard({
consumerGroups,
kafkaVersion,
messages,
reconciliationPuased,
}:
| ({
isLoading: false;
Expand Down Expand Up @@ -203,7 +206,7 @@ export function ClusterCard({
))
) : (
<>
{messages.length === 0 && (
{!reconciliationPuased && messages.length === 0 && (
<DataListItem aria-labelledby={`no-messages`}>
<DataListItemRow>
<DataListItemCells
Expand All @@ -218,6 +221,65 @@ export function ClusterCard({
</DataListItemRow>
</DataListItem>
)}
{reconciliationPuased && (
<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>
{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 Down
38 changes: 38 additions & 0 deletions ui/components/ClusterOverview/ReconciliationModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"use client";

import { Button, Modal, ModalVariant } from "@/libs/patternfly/react-core";
import { useTranslations } from "next-intl";

export function ReconciliationModal({
isModalOpen,
onClickClose,
onClickPauseReconciliation,
}: {
isModalOpen: boolean;
onClickClose: () => void;
onClickPauseReconciliation: () => void;
}) {
const t = useTranslations();
return (
<Modal
title={t("reconciliation.pause_reconciliation")}
isOpen={isModalOpen}
variant={ModalVariant.medium}
onClose={onClickClose}
actions={[
<Button
key="confirm"
variant="primary"
onClick={onClickPauseReconciliation}
>
{t("reconciliation.confirm")}
</Button>,
<Button key="cancel" variant="link" onClick={onClickClose}>
{t("reconciliation.cancel")}
</Button>,
]}
>
{t("reconciliation.pause_reconciliation_description")}
</Modal>
);
}
Loading

0 comments on commit 580b5a7

Please sign in to comment.