diff --git a/frontend/src/components/layout/AISidebar.tsx b/frontend/src/components/layout/AISidebar.tsx
index 45ef3e6..a3ef5c8 100644
--- a/frontend/src/components/layout/AISidebar.tsx
+++ b/frontend/src/components/layout/AISidebar.tsx
@@ -9,6 +9,7 @@ import { getContributedTabs } from './sidebarTabs';
import { useTranslation } from 'react-i18next';
import { useUsers, useGroups } from '@/api/hooks';
import { Avatar } from '@/components/ui/Avatar';
+import { SharedTeamPanel as TeamPanel } from '@/components/shared/TeamPanel';
import { Bell, Bot, ChevronLeft, ChevronRight, Lightbulb, MessageSquare, Users, X } from 'lucide-react';
const robotIcon = (className: string) => (
@@ -42,64 +43,6 @@ interface TabDef {
testId: string;
}
-function TeamPanel() {
- const { data: usersData, isLoading: usersLoading } = useUsers();
- const { data: groupsData, isLoading: groupsLoading } = useGroups();
- const users: any[] = usersData?.items || [];
- const groups: any[] = groupsData?.items || [];
-
- return (
-
diff --git a/frontend/src/components/layout/MessageSidebar.tsx b/frontend/src/components/layout/MessageSidebar.tsx
index 0ce7536..074e92e 100644
--- a/frontend/src/components/layout/MessageSidebar.tsx
+++ b/frontend/src/components/layout/MessageSidebar.tsx
@@ -6,6 +6,7 @@ import { useCommStore } from '@/store/commStore';
import { useTranslation } from 'react-i18next';
import { useUsers, useGroups } from '@/api/hooks';
import { Avatar } from '@/components/ui/Avatar';
+import { SharedTeamPanel } from '@/components/shared/TeamPanel';
import {
listConversations,
getMessages,
@@ -67,66 +68,8 @@ interface QuickAccessDef {
// ─── Team Panel (reused from AISidebar) ───
-function TeamPanel({ onStartDirectChat }: { onStartDirectChat: (userId: string, userName: string) => void }) {
- const { data: usersData, isLoading: usersLoading } = useUsers();
- const { data: groupsData, isLoading: groupsLoading } = useGroups();
- const users: any[] = usersData?.items || [];
- const groups: any[] = groupsData?.items || [];
-
- return (
-
-
-
Mitarbeiter
- {usersLoading ? (
-
Laden...
- ) : users.length === 0 ? (
-
Keine Mitarbeiter
- ) : (
-
- {users.map((u) => (
-
- ))}
-
- )}
-
-
-
Gruppen
- {groupsLoading ? (
-
Laden...
- ) : groups.length === 0 ? (
-
Keine Gruppen
- ) : (
-
- {groups.map((g) => (
-
-
-
-
-
-
{g.name}
- {g.description &&
{g.description}
}
-
-
- ))}
-
- )}
-
-
- );
+function TeamPanel(props: { onStartDirectChat: (userId: string, userName: string) => void }) {
+ return
;
}
// ─── Conversation List Item ───
diff --git a/frontend/src/components/layout/SortableMenuItem.tsx b/frontend/src/components/layout/SortableMenuItem.tsx
index 4e82b92..eb86ff2 100644
--- a/frontend/src/components/layout/SortableMenuItem.tsx
+++ b/frontend/src/components/layout/SortableMenuItem.tsx
@@ -1,10 +1,61 @@
import React from 'react';
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
-import { GripVertical, FolderOpen } from 'lucide-react';
-import * as LucideIcons from 'lucide-react';
+import {
+ Activity,
+ ArrowUpDown,
+ BarChart3,
+ Bell,
+ BookOpen,
+ Bot,
+ Calendar,
+ CheckSquare,
+ Copy,
+ FileText,
+ FolderOpen,
+ Link as LinkIcon,
+ Mail,
+ MessageSquare,
+ Settings,
+ Shield,
+ Sparkles,
+ Tag,
+ GripVertical,
+ Trash2,
+ Users,
+ UsersRound,
+ Workflow,
+} from 'lucide-react';
import clsx from 'clsx';
+// Curated icon map — avoids `import * as LucideIcons` which loads ALL icons
+// and causes OOM in tests (ARCH-063).
+const ICON_MAP: Record
> = {
+ Activity,
+ ArrowUpDown,
+ BarChart: BarChart3,
+ BarChart3,
+ Bell,
+ BookOpen,
+ Bot,
+ Calendar,
+ CheckSquare,
+ Copy,
+ FolderOpen,
+ Link: LinkIcon,
+ Mail,
+ MessageSquare,
+ Settings,
+ Shield,
+ Sparkles,
+ Tag,
+ Trash: Trash2,
+ Trash2,
+ Users,
+ UsersRound,
+ Workflow,
+};
+
interface SortableMenuItemProps {
id: string;
label: string;
@@ -13,8 +64,8 @@ interface SortableMenuItemProps {
}
function getIcon(name: string): React.ReactNode {
- const Icon = (LucideIcons as any)[name];
- return Icon ? : ;
+ const Icon = ICON_MAP[name];
+ return Icon ? : ;
}
export function SortableMenuItem({ id, label, icon, isGroup }: SortableMenuItemProps) {
diff --git a/frontend/src/components/shared/TeamPanel.tsx b/frontend/src/components/shared/TeamPanel.tsx
new file mode 100644
index 0000000..02b58f8
--- /dev/null
+++ b/frontend/src/components/shared/TeamPanel.tsx
@@ -0,0 +1,92 @@
+/**
+ * SharedTeamPanel — single source of truth for the team list panel used by
+ * AISidebar and MessageSidebar (ARCH-062).
+ *
+ * Pass `onStartDirectChat` to make user rows clickable (MessageSidebar);
+ * omit it for a read-only list (AISidebar).
+ */
+
+import React from 'react';
+import { Users } from 'lucide-react';
+import { useUsers, useGroups } from '@/api/hooks';
+import { Avatar } from '@/components/ui/Avatar';
+
+interface SharedTeamPanelProps {
+ onStartDirectChat?: (userId: string, userName: string) => void;
+}
+
+export function SharedTeamPanel({ onStartDirectChat }: SharedTeamPanelProps) {
+ const { data: usersData, isLoading: usersLoading } = useUsers();
+ const { data: groupsData, isLoading: groupsLoading } = useGroups();
+ const users: any[] = usersData?.items || [];
+ const groups: any[] = groupsData?.items || [];
+
+ return (
+
+
+
Mitarbeiter
+ {usersLoading ? (
+
Laden...
+ ) : users.length === 0 ? (
+
Keine Mitarbeiter
+ ) : (
+
+ {users.map((u) =>
+ onStartDirectChat ? (
+
+ ) : (
+
+ )
+ )}
+
+ )}
+
+
+
Gruppen
+ {groupsLoading ? (
+
Laden...
+ ) : groups.length === 0 ? (
+
Keine Gruppen
+ ) : (
+
+ {groups.map((g) => (
+
+
+
+
+
+
{g.name}
+ {g.description &&
{g.description}
}
+
+
+ ))}
+
+ )}
+
+
+ );
+}