feat(kafka): add consumer group backlog view

This commit is contained in:
Guoyu Su authored and GitHub committed 2026-08-20 08:47:05 +08:00
1 parent dc8b083c63
commit f88167c3d0
28 files changed
+1274 -2

No files matched your search

+18
View File
@@ -42,4 +42,22 @@ describe("MQ list panels", () => {
expect(consoleSource).toContain(':namespace="selectedNamespace"');
expect(consoleSource).toContain(':topic="selectedTopic"');
});
it("keeps Kafka topic subscriptions and cluster-wide consumer groups on separate panels", () => {
const consoleSource = componentSource("MqAdminConsole.vue");
expect(consoleSource).toContain("KafkaConsumerGroupsPanel");
expect(consoleSource).toContain("activeTab === 'subscriptions' && canManageSubscriptions");
expect(consoleSource).toContain("activeTab === 'consumerGroups' && isKafkaCluster");
expect(consoleSource).not.toContain("activeTab === 'subscriptions' && canManageSubscriptions && isKafkaCluster");
});
it("routes a Kafka consumer-group partition topic to its topic-scoped subscriptions", () => {
const consoleSource = componentSource("MqAdminConsole.vue");
expect(consoleSource).toContain("function handleKafkaConsumerGroupTopicSelected(topic: string)");
expect(consoleSource).toContain("shortName: topic");
expect(consoleSource).toContain('setActiveTab("subscriptions")');
expect(consoleSource).toContain('@navigate-subscriptions="handleKafkaConsumerGroupTopicSelected"');
});
});
+1
View File
@@ -639,6 +639,7 @@ export const mqListClientChannels = forward("mqListClientChannels");
export const mqCloseClientConnection = forward("mqCloseClientConnection");
export const mqListSubscriptions = forward("mqListSubscriptions");
export const mqEnrichSubscriptions = forward("mqEnrichSubscriptions");
export const mqGetKafkaConsumerGroupSnapshot = forward("mqGetKafkaConsumerGroupSnapshot");
export const mqCreateSubscription = forward("mqCreateSubscription");
export const mqDeleteSubscription = forward("mqDeleteSubscription");
export const mqSkipMessages = forward("mqSkipMessages");
+5
View File
@@ -13,6 +13,7 @@ import type {
ListTopicsOpts,
TopicStats,
SubscriptionInfo,
KafkaConsumerGroupSnapshot,
ResetPosition,
SkipCount,
ConsumerInfo,
@@ -221,6 +222,10 @@ export async function mqEnrichSubscriptions(connectionId: string, topic: TopicRe
return post("/api/mq/subscriptions/enrich", { connectionId, topic });
}
export async function mqGetKafkaConsumerGroupSnapshot(connectionId: string): Promise<KafkaConsumerGroupSnapshot> {
return post("/api/mq/kafka/consumer-groups", { connectionId });
}
export async function mqCreateSubscription(connectionId: string, topic: TopicRef, sub: string, pos: ResetPosition): Promise<void> {
return post("/api/mq/subscriptions/create", { connectionId, topic, sub, pos });
}
+5
View File
@@ -13,6 +13,7 @@ import type {
ListTopicsOpts,
TopicStats,
SubscriptionInfo,
KafkaConsumerGroupSnapshot,
ResetPosition,
SkipCount,
ConsumerInfo,
@@ -215,6 +216,10 @@ export async function mqEnrichSubscriptions(connectionId: string, topic: TopicRe
return invoke("mq_enrich_subscriptions", { connectionId, topic });
}
export async function mqGetKafkaConsumerGroupSnapshot(connectionId: string): Promise<KafkaConsumerGroupSnapshot> {
return invoke("mq_get_kafka_consumer_group_snapshot", { connectionId });
}
export async function mqCreateSubscription(connectionId: string, topic: TopicRef, sub: string, pos: ResetPosition): Promise<void> {
return invoke("mq_create_subscription", { connectionId, topic, sub, pos });
}
@@ -85,6 +85,17 @@ describe("mqConsoleDefaults", () => {
expect(resolveAvailableMqTabs({ systemKind: "kafka", capabilities: caps })).toContain("messages");
});
it("keeps Kafka topic subscriptions alongside the cluster-wide consumer groups tab", () => {
const tabs = resolveAvailableMqTabs({
systemKind: "kafka",
capabilities: defaultMqCapabilitiesForSystemKind("kafka"),
});
expect(tabs).toContain("subscriptions");
expect(tabs).toContain("consumerGroups");
expect(tabs.indexOf("consumerGroups")).toBe(tabs.indexOf("subscriptions") + 1);
});
it("exposes the namespaces tab for RabbitMQ vhost management", () => {
const caps = defaultMqCapabilitiesForSystemKind("rabbitmq");
expect(resolveAvailableMqTabs({ systemKind: "rabbitmq", capabilities: caps })).toEqual(["namespaces", "topics", "subscriptions", "monitoring", "clients", "messages", "broker", "policies", "permissions"]);
+5 -2
View File
@@ -158,7 +158,7 @@ export function resolveRabbitMqDefaultVhost(config: ConnectionConfig | undefined
return typeof vhost === "string" && vhost.trim() ? vhost.trim() : "/";
}
export type MqTab = "tenants" | "namespaces" | "topics" | "subscriptions" | "monitoring" | "clients" | "producers" | "policies" | "permissions" | "messages" | "raw" | "broker" | "dlq" | "trace";
export type MqTab = "tenants" | "namespaces" | "topics" | "subscriptions" | "consumerGroups" | "monitoring" | "clients" | "producers" | "policies" | "permissions" | "messages" | "raw" | "broker" | "dlq" | "trace";
export function resolveAvailableMqTabs(options: { systemKind?: MqSystemKind; capabilities: MqCapabilities }): MqTab[] {
const { systemKind, capabilities } = options;
@@ -174,7 +174,10 @@ export function resolveAvailableMqTabs(options: { systemKind?: MqSystemKind; cap
if (capabilities.supportsTenants) tabs.push("tenants");
if (capabilities.supportsNamespaces) tabs.push("namespaces");
tabs.push("topics");
if (capabilities.supportsSubscriptions) tabs.push("subscriptions");
if (capabilities.supportsSubscriptions) {
tabs.push("subscriptions");
if (systemKind === "kafka") tabs.push("consumerGroups");
}
tabs.push("monitoring");
tabs.push("clients");
if (capabilities.supportsSendMessage || (systemKind === "kafka" && capabilities.supportsPeekMessages)) tabs.push("messages");