Skip to content

Commit

Permalink
feat: Add reset offset in consumer group
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewinci committed Oct 23, 2022
1 parent 6638702 commit 2a3d4b7
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 15 deletions.
68 changes: 56 additions & 12 deletions src/pages/consumer-groups/consumer-group.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,58 @@
import { Text, Button, Container, Divider, Group, Stack, Grid, Center, Loader } from "@mantine/core";
import { IconRefresh } from "@tabler/icons";
import { Text, Button, Container, Divider, Group, Stack, Grid, Center, Loader, Menu } from "@mantine/core";
import { useSetState } from "@mantine/hooks";
import { openConfirmModal } from "@mantine/modals";
import { IconFlag, IconPlayerPlay, IconRefresh, IconTool } from "@tabler/icons";
import { useQuery } from "@tanstack/react-query";
import { PageHeader } from "../../components";
import { describeConsumerGroup } from "../../tauri/admin";
import { ConsumerSettingsFrom } from "../../models";
import { describeConsumerGroup, setConsumerGroup } from "../../tauri/admin";

export const ConsumerGroup = ({ name, clusterId }: { name: string; clusterId: string }) => {
const [state, setState] = useSetState<{ isResetting: boolean }>({ isResetting: false });
const { isLoading, data, refetch, isRefetching } = useQuery(
["describeConsumerGroup", clusterId, name],
() => describeConsumerGroup(clusterId, name),
{ refetchOnWindowFocus: false, refetchOnMount: false }
);

const resetOffset = (offset: ConsumerSettingsFrom) => {
if (data) {
openConfirmModal({
title: "Reset offset",
children: (
<>
<Text size="sm">
Are you sure to reset the offset of the consumer group{" "}
<Text component="span" weight={"bold"}>
{data.name}
</Text>{" "}
to{" "}
<Text component="span" weight={"bold"}>
{offset.toString()}
</Text>
?
</Text>
<Text my={10} size="sm" color={"red"}>
This action is irreversible.
</Text>
</>
),
labels: { confirm: "Confirm", cancel: "Cancel" },
onCancel: () => console.log("Cancel"),
onConfirm: async () => {
setState({ isResetting: true });
await setConsumerGroup(
clusterId,
data.name,
data.offsets.map((o) => o.topic),
offset
).then((_) => refetch());
setState({ isResetting: false });
},
});
}
};

return (
<Container>
<PageHeader title={name} subtitle={`status: ${data?.state ?? "..."}`} />
Expand All @@ -22,20 +64,22 @@ export const ConsumerGroup = ({ name, clusterId }: { name: string; clusterId: st
Refresh
</Button>

{/*
todo: allow reset each single topic/partition
<Menu shadow="md" width={200}>
<Menu shadow="md" width={200}>
<Menu.Target>
<Button mb={10} size="xs">
<IconTool /> Reset offset tool
<Button mb={10} size="xs" leftIcon={<IconTool />} loading={state.isResetting}>
Reset offset
</Button>
</Menu.Target>
<Menu.Dropdown>
<Menu.Item icon={<IconPlayerPlay size={14} />}>Reset to the beginning</Menu.Item>
<Menu.Item icon={<IconFlag size={14} />}>Reset to end</Menu.Item>
<Menu.Item icon={<IconClock size={14} />}>Reset to a point in time</Menu.Item>
<Menu.Item onClick={() => resetOffset("Beginning")} icon={<IconPlayerPlay size={14} />}>
Reset to the beginning
</Menu.Item>
<Menu.Item onClick={() => resetOffset("End")} icon={<IconFlag size={14} />}>
Reset to end
</Menu.Item>
{/* <Menu.Item icon={<IconClock size={14} />}>Reset to a point in time</Menu.Item> */}
</Menu.Dropdown>
</Menu> */}
</Menu>
</Group>
{isLoading && (
<Center mt={10}>
Expand Down
28 changes: 25 additions & 3 deletions src/pages/consumer-groups/consumer-groups-list.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { ActionIcon, Button, Center, Group, Modal, Select, Stack, Text, TextInput, Title } from "@mantine/core";
import { ActionIcon, Button, Center, Chip, Group, Modal, Select, Stack, Text, TextInput, Title } from "@mantine/core";
import { IconTrash } from "@tabler/icons";
import { useQuery } from "@tanstack/react-query";
import { useState } from "react";
import { SingleLineTitle } from "../../components";
import { ConsumerSettingsFrom } from "../../models";
import { setConsumerGroup, getConsumerGroups, listTopics } from "../../tauri/admin";
import { ItemList } from "../common";

Expand Down Expand Up @@ -44,7 +45,11 @@ export const ConsumerGroupsList = (props: SchemaListProps) => {

const CreateConsumerGroupModal = ({ clusterId, close }: { clusterId: string; close: () => void }) => {
const { data } = useQuery(["listTopics", clusterId], () => listTopics(clusterId));
const [state, setState] = useState<{ name: string; topics: string[] }>({ name: "", topics: [] });
const [state, setState] = useState<{ name: string; topics: string[]; offset: string }>({
name: "",
topics: [],
offset: "Beginning",
});

return (
<Stack spacing={0}>
Expand All @@ -53,7 +58,20 @@ const CreateConsumerGroupModal = ({ clusterId, close }: { clusterId: string; clo
value={state.name}
onChange={(event) => setState((s) => ({ ...s, name: event.currentTarget.value }))}
label="Consumer group name"></TextInput>
<Text mt={10} size={15}>
Set offset
</Text>
<Chip.Group
position="left"
multiple={false}
onChange={(v) => setState((s) => ({ ...s, offset: v }))}
value={state.offset}>
<Chip value="End">End</Chip>
<Chip value="Beginning">Beginning</Chip>
{/* <Chip value="Custom">Custom Time</Chip> */}
</Chip.Group>
<Select
mt={10}
label="Add topics to the consumer group"
data={data?.filter((t) => !state.topics.includes(t)) ?? []}
onChange={(t) => {
Expand Down Expand Up @@ -85,7 +103,11 @@ const CreateConsumerGroupModal = ({ clusterId, close }: { clusterId: string; clo
</Stack>
<Group mt={10} position="right">
<Button
onClick={() => setConsumerGroup(clusterId, state.name, state.topics, "Beginning").then((_) => close())}
onClick={() =>
setConsumerGroup(clusterId, state.name, state.topics, state.offset as ConsumerSettingsFrom).then((_) =>
close()
)
}
type="submit">
Create 🚀
</Button>
Expand Down

0 comments on commit 2a3d4b7

Please sign in to comment.