Component: Knowledge Base Card
Component
Section titled “Component”- Name:
KnowledgeBaseCard - Used in:
- Ownership: Shared UI
Purpose / responsibility
Section titled “Purpose / responsibility”Display KB identity, status, linkage, and KB-local detail counts in a standard shadcn Card. Supports navigation to KB detail via optional openHref.
Structure (3 sections)
Section titled “Structure (3 sections)”- Section 1 — Header (2-line layout):
- Line 1: Material icon
database+ KB name (title,flex-1 min-w-0 truncate) + three-dots overflow menu trigger (more_horizicon,opacity-0 group-hover:opacity-100) — flex row,items-center. - Line 2: Workspace name + optional group
Badge— rendered on the same line below the title row. WhengroupNameis provided, a<Badge variant="secondary">appears inline after the workspace name. - The icon must not span both lines; it aligns only with the title on line 1.
- Line 1: Material icon
- Section 2: KB status (Incomplete / Complete), Linkage (Independent / Linked).
- Section 3 (small title “Details”): KB-local values only —
Objectives,Documents.
Section 1 layout spec
Section titled “Section 1 layout spec”CardHeader (flex-col, p-4 pb-4, border-b border-border)├── div.title-row (flex flex-row items-center gap-3)│ ├── [when isDefaultKb] Tooltip > (icon wrapper + h3) else span.database + h3│ │ icon wrapper: relative shrink-0; database 24px; [when isDefaultKb] circle marker size-1.5 rounded-full bg-foreground absolute -right-0.5 -top-0.5 (theme-aware)│ ├── h3 (flex-1 min-w-0 truncate text-[16px] font-semibold leading-tight) ← KB name│ └── div.menu-trigger (relative flex-shrink-0, opacity-0 group-hover:opacity-100)│ ├── button (more_horiz icon, 20px)│ └── [when open] overlay (fixed inset-0 z-10) + dropdown (absolute right-0 top-full z-20)└── div (mt-1 flex items-center gap-2) ← workspace + group row ├── p (text-[14px] text-muted-foreground) ← workspace name └── [when groupName] Badge variant="secondary" ← KB group nameCardHeaderswitches fromflex-rowtoflex-colso the two lines stack.- The inner
div.title-rowisflex flex-row items-center gap-3— this centers the icon with the title text. - The workspace
<p>sits outsidediv.title-row, naturally flowing to a new line. - Remove
items-startfromCardHeader; it is no longer needed once the header isflex-col. CardHeaderhas a 1px bottom border (border-b border-border) matching the card’s own border color (--bordertheme token). This visually separates the header from the card body.
Default indicator (when isDefaultKb)
Section titled “Default indicator (when isDefaultKb)”When the KB is the workspace default: (1) the lead (database) icon shows a small circular marker at its top-right: size-1.5 rounded-full bg-foreground, absolute -right-0.5 -top-0.5. The marker uses bg-foreground so its color follows the active theme (e.g. dark in light theme, light in dark theme). (2) The title section (icon + KB name) is wrapped in a tooltip; on hover, the hint “Default knowledge base” is shown (Tooltip from @/components/ui/tooltip, TooltipContent side="top").
Section title labels
Section titled “Section title labels”All section small titles — KB status, Linkage, Details — use the same canonical style:
mb-1 text-[13px] font-semibold text-zinc-950No section title should deviate in margin, weight, or color. (The “Details” title was previously inconsistent — mb-2 font-medium text-[#666] — and must be corrected to match.)
Props / inputs / outputs
Section titled “Props / inputs / outputs”- Inputs:
kb(KnowledgeBase) — the enriched KB record.workspaceName(string) — display name of the owning workspace.groupName?(string) — display name of the KB group (workspace-scoped). When provided, shown as aBadgeafter the workspace name in the card header. Resolved by the parent fromkbGroupsviakb.groupId.openHref?(string) — when set, clicking the card (outside the menu trigger) navigates here.onEdit?(kb) => void — called when Edit is clicked; falls back toopenHrefnavigation if omitted.onSetAsMain?(kb) => void — called to set this KB as the workspace default.isDefaultKb?(boolean) — disables “Set as default” whentrue(this KB is already the default).onDuplicate(kb) => void — called to duplicate the KB.onDelete(kb) => void — called to delete the KB.canDelete(boolean) — disables Delete whenfalse(workspace has only one KB).className?(string) — optional CSS class override on the root<Card>.
- Outputs: Card click navigates to
openHrefwhen provided (and menu is not open). Menu actions invoke the corresponding callbacks.
Note on data: The card uses KB-local fields only (
kbDraft/objectivesCount,kbDocuments/documentsCount) and does not render channel/app aggregates.
Overflow menu
Section titled “Overflow menu”The card shows a three-dots (more_horiz) button in the header row on hover. The button is hidden by default (opacity-0) and becomes visible when the card is hovered (group-hover:opacity-100). Clicking the button opens an inline dropdown popover.
Menu items
Section titled “Menu items”| Action | Icon | Behaviour | Disabled when |
|---|---|---|---|
| Edit | edit | Calls onEdit(kb) if provided; parent opens the Edit knowledge base dialog. If onEdit is omitted, falls back to navigating to openHref. Closes menu. | Never |
| Set as default | star | Calls onSetAsMain(kb). Parent calls updateWorkspace(kb.workspaceId, { defaultKbId: kb.id }). Closes menu. | isDefaultKb === true (this KB is already the workspace default) |
| Duplicate | content_copy | Calls onDuplicate(kb). Parent creates a copy with name "{kb.name} (Copy)" and same workspaceId. Closes menu. | Never |
| (divider) | — | Visual border-t separator | — |
| Delete | delete | Calls onDelete(kb). Closes menu. Styled destructive (text-destructive). | canDelete === false (workspace has only one KB — see business rule 7 in Default Workspace, Knowledge Base & Agent) |
Popover styling
Section titled “Popover styling”w-[180px], rounded-[10px], border border-border, bg-popover, shadow-md, absolute right-0 top-full mt-1 z-20. A fixed inset-0 z-10 overlay closes the menu on outside click. Escape key also closes the menu.
Card click behaviour
Section titled “Card click behaviour”When openHref is set, the card is clickable. Clicks on the menu trigger (menuTriggerRef) are ignored (via stopPropagation on the trigger div and a contains check in handleCardClick). Clicks while the menu is open are also ignored.
Parent responsibilities
Section titled “Parent responsibilities”- Edit: When user clicks Edit, parent sets state to open the Edit knowledge base dialog with the selected KB. On dialog submit, parent calls
actions.updateKnowledgeBase(kbId, { name, workspaceId })and, if the user changed the workspace’s group in the dialog,actions.updateWorkspace(workspaceId, { groupId }); then closes the dialog. canDelete:truewhen the workspace (kb.workspaceId) has more than one KB in the full context KB list (not the filtered list).isDefaultKb:truewhenworkspace.defaultKbId === kb.id(look up workspace viaselectors.getWorkspace(kb.workspaceId)).onSetAsMain: callsactions.updateWorkspace(kb.workspaceId, { defaultKbId: kb.id }).onDuplicate: callsactions.addKnowledgeBase({ ...kb, id: newId, name: \${kb.name} (Copy)` })`.onDelete: callsactions.deleteKnowledgeBase(kb.id).
Variants
Section titled “Variants”- Status badge: Incomplete (orange) vs Complete (green)
States
Section titled “States”- Default: KB shown
- Loading: skeleton
- Error: cannot load KB summary
- Disabled: user lacks
kb.view
Accessibility requirements
Section titled “Accessibility requirements”- Clickable card must be keyboard-accessible
- Badges must have text equivalents
Security & privacy considerations (if applicable)
Section titled “Security & privacy considerations (if applicable)”- Do not expose KB internal content on the card
Analytics hooks (if applicable)
Section titled “Analytics hooks (if applicable)”kb.card.clicked(optional)
Dependencies
Section titled “Dependencies”- Domain refs: Domain: Knowledge Bases