Skip to content

Commit

Permalink
Move Reconciliation pause button to kafka details card (#1374)
Browse files Browse the repository at this point in the history
* Move Reconcilation pause button to kafka details card

Signed-off-by: hemahg <[email protected]>

* Fix stories

Signed-off-by: hemahg <[email protected]>

* Hide error/ warning icon labels when there is no alerts

Signed-off-by: hemahg <[email protected]>

---------

Signed-off-by: hemahg <[email protected]>
  • Loading branch information
hemahg authored Jan 16, 2025
1 parent d0d6edc commit ff446de
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 100 deletions.
Original file line number Diff line number Diff line change
@@ -1,75 +1,15 @@
"use client";

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

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

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

const { isReconciliationPaused, setReconciliationPaused } =
useReconciliationContext();

const onClickUpdate = async (pausedState: boolean) => {
try {
const response = await updateKafkaCluster(clusterId, pausedState);

if (response.errors) {
console.log("Unknown error occurred", response.errors);
} else {
setReconciliationPaused(pausedState);
setIsModalOpen(false);
}
} catch (e: unknown) {
console.log("Unknown error occurred");
}
};

return (
<>
<Flex>
{managed && (
<FlexItem>
<Button
variant="secondary"
onClick={
isReconciliationPaused
? () => onClickUpdate(false)
: () => setIsModalOpen(true)
}
>
{isReconciliationPaused
? t("reconciliation.resume_reconciliation")
: 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={() => onClickUpdate(true)}
/>
)}
</>
<Button onClick={() => open(clusterId)}>
{t("ConnectButton.cluster_connection_details")}
</Button>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ export default function Header({
params: KafkaParams;
}) {
return (
<Suspense
fallback={<OverviewHeader params={{ kafkaId }} managed={false} />}
>
<Suspense fallback={<OverviewHeader params={{ kafkaId }} />}>
<ConnectedHeader params={{ kafkaId }} />
</Suspense>
);
Expand All @@ -25,30 +23,21 @@ async function ConnectedHeader({
params: KafkaParams;
}) {
const cluster = (await getKafkaCluster(kafkaId))?.payload;

return (
<OverviewHeader
params={{ kafkaId }}
managed={cluster?.meta?.managed ?? false}
/>
);

return <OverviewHeader params={{ kafkaId }} />;
}

export function OverviewHeader({
params: { kafkaId },
managed,
}: {
params: KafkaParams;
managed: boolean;
}) {
const t = useTranslations();
return (
<AppHeader
title={t("ClusterOverview.header")}
subTitle={t("ClusterOverview.description")}
actions={[
<ConnectButton key={"cd"} clusterId={kafkaId} managed={managed} />,
]}
actions={[<ConnectButton key={"cd"} clusterId={kafkaId} />]}
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,19 @@ export async function ConnectedClusterCard({
brokersTotal={undefined}
kafkaVersion={res?.attributes.kafkaVersion ?? "n/a"}
kafkaId={res?.id}
managed={res?.meta?.managed || false}
/>
);
}
const groupCount = await consumerGroups.then(
(grpResp) => grpResp.errors ? undefined : grpResp.payload?.meta.page.total ?? 0,
const groupCount = await consumerGroups.then((grpResp) =>
grpResp.errors ? undefined : (grpResp.payload?.meta.page.total ?? 0),
);

const brokersTotal = res?.attributes.metrics?.values?.["broker_state"]?.length ?? 0;
const brokersOnline = (res?.attributes.metrics?.values?.["broker_state"] ?? [])
.filter((s) => s.value === "3")
.length;
const brokersTotal =
res?.attributes.metrics?.values?.["broker_state"]?.length ?? 0;
const brokersOnline = (
res?.attributes.metrics?.values?.["broker_state"] ?? []
).filter((s) => s.value === "3").length;

const messages = res?.attributes.conditions
?.filter((c) => "Ready" !== c.type)
Expand All @@ -53,14 +55,18 @@ export async function ConnectedClusterCard({
return (
<ClusterCard
isLoading={false}
status={res?.attributes.status ?? (brokersOnline == brokersTotal ? "Ready" : "Not Available")}
status={
res?.attributes.status ??
(brokersOnline == brokersTotal ? "Ready" : "Not Available")
}
messages={messages ?? []}
name={res?.attributes.name ?? "n/a"}
consumerGroups={groupCount}
brokersOnline={brokersOnline}
brokersTotal={brokersTotal}
kafkaVersion={res?.attributes.kafkaVersion ?? "Not Available"}
kafkaId={res.id}
managed={res.meta?.managed || false}
/>
);
}
8 changes: 4 additions & 4 deletions ui/components/ClusterOverview/ClusterCard.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ const meta: Meta<typeof ClusterCard> = {
(Story) => (
<ReconciliationContext.Provider
value={{
isReconciliationPaused: true,
setReconciliationPaused: () => { }
isReconciliationPaused: false,
setReconciliationPaused: () => {},
}}
>
<Story />
</ReconciliationContext.Provider>
)
]
),
],
};

export default meta;
Expand Down
16 changes: 16 additions & 0 deletions ui/components/ClusterOverview/ClusterCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { useTranslations } from "next-intl";
import { ErrorsAndWarnings } from "./components/ErrorsAndWarnings";
import { updateKafkaCluster } from "@/api/kafka/actions";
import { useReconciliationContext } from "../ReconciliationContext";
import { ReconciliationPauseButton } from "./ReconciliationPauseButton";

type ClusterCardProps = {
name: string;
Expand All @@ -47,6 +48,7 @@ type ClusterCardProps = {
message: string;
date: string;
}>;
managed: boolean;
};

export function ClusterCard({
Expand All @@ -59,6 +61,7 @@ export function ClusterCard({
kafkaVersion,
messages,
kafkaId,
managed,
}:
| ({
isLoading: false;
Expand Down Expand Up @@ -96,6 +99,19 @@ export function ClusterCard({
return (
<Card component={"div"}>
<CardBody>
<Flex>
<FlexItem>
<Title headingLevel={"h2"}>
{t("ClusterCard.Kafka_cluster_details")}
</Title>
</FlexItem>
<FlexItem align={{ default: "alignRight" }}>
<ReconciliationPauseButton
clusterId={kafkaId || ""}
managed={managed || false}
/>
</FlexItem>
</Flex>
<Flex direction={{ default: "column" }} gap={{ default: "gap" }}>
<Flex
flexWrap={{ default: "wrap", sm: "nowrap" }}
Expand Down
65 changes: 65 additions & 0 deletions ui/components/ClusterOverview/ReconciliationPauseButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"use client";

import { updateKafkaCluster } from "@/api/kafka/actions";
import { ReconciliationModal } from "@/components/ClusterOverview/ReconciliationModal";
import { useReconciliationContext } from "@/components/ReconciliationContext";
import { Button } from "@/libs/patternfly/react-core";
import { useTranslations } from "next-intl";
import { useState } from "react";
import { PauseCircleIcon, PlayIcon } from "@/libs/patternfly/react-icons";

export function ReconciliationPauseButton({
clusterId,
managed,
}: {
clusterId: string;
managed: boolean;
}) {
const t = useTranslations();
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);

const { isReconciliationPaused, setReconciliationPaused } =
useReconciliationContext();

const onClickUpdate = async (pausedState: boolean) => {
try {
const response = await updateKafkaCluster(clusterId, pausedState);

if (response.errors) {
console.log("Unknown error occurred", response.errors);
} else {
setReconciliationPaused(pausedState);
setIsModalOpen(false);
}
} catch (e: unknown) {
console.log("Unknown error occurred");
}
};

return (
<>
{managed && (
<Button
variant="link"
icon={isReconciliationPaused ? <PlayIcon /> : <PauseCircleIcon />}
onClick={
isReconciliationPaused
? () => onClickUpdate(false)
: () => setIsModalOpen(true)
}
>
{isReconciliationPaused
? t("reconciliation.resume_reconciliation")
: t("reconciliation.pause_reconciliation_button")}
</Button>
)}
{isModalOpen && (
<ReconciliationModal
isModalOpen={isModalOpen}
onClickClose={() => setIsModalOpen(false)}
onClickPauseReconciliation={() => onClickUpdate(true)}
/>
)}
</>
);
}
16 changes: 10 additions & 6 deletions ui/components/ClusterOverview/components/ErrorsAndWarnings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,16 @@ export function ErrorsAndWarnings({
<HelpIcon />
</Tooltip>{" "}
<LabelGroup>
<Label color={"red"} isCompact={true}>
<ExclamationCircleIcon /> {dangers}
</Label>
<Label color={"gold"} isCompact={true}>
<ExclamationTriangleIcon /> {warnings}
</Label>
{dangers > 0 && (
<Label color={"red"} isCompact={true}>
<ExclamationCircleIcon /> {dangers}
</Label>
)}
{warnings > 0 && (
<Label color={"gold"} isCompact={true}>
<ExclamationTriangleIcon /> {warnings}
</Label>
)}
</LabelGroup>
</Title>
}
Expand Down
7 changes: 4 additions & 3 deletions ui/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,8 @@
"consumer_groups": "Consumer groups",
"kafka_version": "Kafka version",
"cluster_errors_and_warnings": "Cluster errors and warnings",
"no_messages": "No messages"
"no_messages": "No messages",
"Kafka_cluster_details": "Kafka cluster details"
},
"ClusterChartsCard": {
"data_unavailable": "Cluster metrics are not available for this cluster. Please check your configuration.",
Expand Down Expand Up @@ -509,9 +510,9 @@
"tooltip": "Issues encountered in the Kafka cluster. Investigate and address these issues to ensure continued operation of the cluster."
},
"topic_header": "Topics",
"total_topics": "total topics",
"total_topics": "topics",
"partition": "Partition",
"total_partitions": "total partitions",
"total_partitions": "partitions",
"view_all_topics": "View all",
"fully_replicated_partition": "Fully replicated",
"fully_replicated_partition_tooltip": "All partitions are fully replicated. A partition is fully-replicated when its replicas (followers) are 'in sync' with the designated partition leader. Replicas are 'in sync' if they have fetched records up to the log end offset of the leader partition within an allowable lag time, as determined by replica.lag.time.max.ms.",
Expand Down

0 comments on commit ff446de

Please sign in to comment.