refactor(block-h): ai sidebar tabs resolve via plugin-contributable registry
This commit is contained in:
@@ -5,6 +5,7 @@ import { SuggestionList } from '@/components/ai/SuggestionSidebar';
|
||||
import { ImprovementPanel } from '@/components/ai/ImprovementPanel';
|
||||
import { createSession, fetchSessions } from '@/api/ai';
|
||||
import { useUIStore } from '@/store/uiStore';
|
||||
import { getContributedTabs } from './sidebarTabs';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useUsers, useGroups } from '@/api/hooks';
|
||||
import { Avatar } from '@/components/ui/Avatar';
|
||||
@@ -35,7 +36,7 @@ const chevronRightIcon = (
|
||||
);
|
||||
|
||||
interface TabDef {
|
||||
key: 'proactive' | 'chat' | 'notifications' | 'team' | 'chatroom';
|
||||
key: string;
|
||||
label: string;
|
||||
icon: (cls: string) => React.ReactNode;
|
||||
testId: string;
|
||||
@@ -139,6 +140,13 @@ export function AISidebar() {
|
||||
{ key: 'notifications', label: t('topbar.notifications'), icon: bellIcon, testId: 'ai-sidebar-tab-notifications' },
|
||||
{ key: 'team', label: 'Team', icon: teamIcon, testId: 'ai-sidebar-tab-team' },
|
||||
{ key: 'chatroom', label: 'Chat', icon: chatBubbleIcon, testId: 'ai-sidebar-tab-chatroom' },
|
||||
// Plugin-contributed tabs (Block H / HC-G)
|
||||
...getContributedTabs().map((ct) => ({
|
||||
key: ct.key,
|
||||
label: ct.label,
|
||||
icon: ct.icon,
|
||||
testId: ct.testId,
|
||||
})),
|
||||
];
|
||||
|
||||
const activeTab = tabs.find((tab) => tab.key === aiSidebarTab) || tabs[0];
|
||||
@@ -209,6 +217,12 @@ export function AISidebar() {
|
||||
if (aiSidebarTab === 'chatroom') {
|
||||
return <ChatPanel />;
|
||||
}
|
||||
// Plugin-contributed tabs (Block H / HC-G)
|
||||
const contributed = getContributedTabs().find((ct) => ct.key === aiSidebarTab);
|
||||
if (contributed) {
|
||||
const ContributedComponent = contributed.component;
|
||||
return <ContributedComponent />;
|
||||
}
|
||||
// chat tab
|
||||
if (loading) {
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* AI sidebar tab registry.
|
||||
*
|
||||
* Core owns the base tabs (chat/proactive/notifications/team/chatroom);
|
||||
* plugins contribute additional tabs via ``registerSidebarTab`` during their
|
||||
* frontend activation lifecycle (Block H / HC-G). Contributed tabs render a
|
||||
* generic container component provided by the plugin.
|
||||
*/
|
||||
import type { ComponentType } from 'react';
|
||||
|
||||
type IconFn = (className: string) => JSX.Element;
|
||||
|
||||
export interface ContributedTab {
|
||||
key: string;
|
||||
label: string;
|
||||
icon: IconFn;
|
||||
testId: string;
|
||||
component: ComponentType;
|
||||
}
|
||||
|
||||
const _tabs = new Map<string, ContributedTab>();
|
||||
|
||||
export function registerSidebarTab(tab: ContributedTab): void {
|
||||
if (_tabs.has(tab.key)) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(`[sidebarTabs] tab '${tab.key}' re-registered — overwriting`);
|
||||
}
|
||||
_tabs.set(tab.key, tab);
|
||||
}
|
||||
|
||||
export function unregisterSidebarTabs(owner: string): void {
|
||||
for (const [key, tab] of _tabs.entries()) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
if ((tab.component as any).__sidebar_owner__ === owner) {
|
||||
_tabs.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getContributedTabs(): ContributedTab[] {
|
||||
return Array.from(_tabs.values());
|
||||
}
|
||||
@@ -2,7 +2,9 @@ import { create } from 'zustand';
|
||||
|
||||
export type Theme = 'light' | 'dark' | 'system';
|
||||
export type Locale = 'de' | 'en';
|
||||
export type AISidebarTab = 'proactive' | 'chat' | 'notifications' | 'team' | 'chatroom';
|
||||
// Plugin-contributed tabs add arbitrary keys (Block H / HC-G) — the union
|
||||
// keeps autocomplete for the base tabs while allowing any string key.
|
||||
export type AISidebarTab = 'proactive' | 'chat' | 'notifications' | 'team' | 'chatroom' | (string & {});
|
||||
|
||||
export interface Toast {
|
||||
id: string;
|
||||
|
||||
Reference in New Issue
Block a user