@burdenoff/microfe-vibecontrols 2026.623.2 → 2026.623.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/components/actions/ActionTypeBadge.js +1 -1
  2. package/dist/components/actions/ActionTypeBadge.js.map +1 -1
  3. package/dist/components/agent-manager/AgentManagerAdminBar.js +1 -1
  4. package/dist/components/agent-manager/AgentManagerAdminBar.js.map +1 -1
  5. package/dist/components/agent-manager/AgentManagerChatPane.js +1 -1
  6. package/dist/components/agent-manager/AgentManagerChatPane.js.map +1 -1
  7. package/dist/components/agent-manager/AgentManagerInputArea.js +1 -1
  8. package/dist/components/agent-manager/AgentManagerInputArea.js.map +1 -1
  9. package/dist/components/agent-manager/BridleConfigPanel.js +2 -2
  10. package/dist/components/agent-manager/BridleConfigPanel.js.map +1 -1
  11. package/dist/components/agent-manager/ProfilesPanel.js +1 -1
  12. package/dist/components/agent-manager/ProfilesPanel.js.map +1 -1
  13. package/dist/components/agent-manager/controls/AutonomySelector.js +1 -1
  14. package/dist/components/agent-manager/controls/AutonomySelector.js.map +1 -1
  15. package/dist/components/agent-manager/controls/SdkSelector.js +1 -1
  16. package/dist/components/agent-manager/controls/SdkSelector.js.map +1 -1
  17. package/dist/components/agent-manager/controls/VoiceToggle.js +1 -1
  18. package/dist/components/agent-manager/controls/VoiceToggle.js.map +1 -1
  19. package/dist/components/agent-manager/detail/SessionLogsPanel.js +2 -2
  20. package/dist/components/agent-manager/detail/SessionLogsPanel.js.map +1 -1
  21. package/dist/components/ai/AIContextsTab.js +1 -1
  22. package/dist/components/ai/AIContextsTab.js.map +1 -1
  23. package/dist/components/ai/AIOverviewTab.js +1 -1
  24. package/dist/components/ai/AIOverviewTab.js.map +1 -1
  25. package/dist/components/ai/AIPromptsTab.js +1 -1
  26. package/dist/components/ai/AIPromptsTab.js.map +1 -1
  27. package/dist/components/ai/AIQueueTab.js +1 -1
  28. package/dist/components/ai/AIQueueTab.js.map +1 -1
  29. package/dist/components/ai/AISessionsTab.js +1 -1
  30. package/dist/components/ai/AISessionsTab.js.map +1 -1
  31. package/dist/components/audit/AuditLogTable.js +1 -1
  32. package/dist/components/audit/AuditLogTable.js.map +1 -1
  33. package/dist/components/docs/DocsPageTree.js +1 -1
  34. package/dist/components/docs/DocsPageTree.js.map +1 -1
  35. package/dist/components/graph/ConnectionPermissionsDialog.js +2 -2
  36. package/dist/components/graph/ConnectionPermissionsDialog.js.map +1 -1
  37. package/dist/components/graph/MeshDeployWizard.js +3 -3
  38. package/dist/components/graph/MeshDeployWizard.js.map +1 -1
  39. package/dist/components/graph/MeshRequestPanel.js +2 -2
  40. package/dist/components/graph/MeshRequestPanel.js.map +1 -1
  41. package/dist/components/notes/NoteCard.js +1 -1
  42. package/dist/components/notes/NoteCard.js.map +1 -1
  43. package/dist/components/notes/NoteEditor.js +1 -1
  44. package/dist/components/notes/NoteEditor.js.map +1 -1
  45. package/dist/components/notes/NoteList.js +1 -1
  46. package/dist/components/notes/NoteList.js.map +1 -1
  47. package/dist/components/shared/AgentSetupBanner.js +3 -3
  48. package/dist/components/shared/AgentSetupBanner.js.map +1 -1
  49. package/dist/components/templates/TemplateCard.js +1 -1
  50. package/dist/components/templates/TemplateCard.js.map +1 -1
  51. package/dist/components/vibecalendar/types.js +1 -1
  52. package/dist/components/vibecalendar/types.js.map +1 -1
  53. package/dist/components/vibedeck/VibeDeckButtonForm.js +1 -1
  54. package/dist/components/vibedeck/VibeDeckButtonForm.js.map +1 -1
  55. package/dist/components/vibedeck/VibeDeckExecutionLog.js +2 -2
  56. package/dist/components/vibedeck/VibeDeckExecutionLog.js.map +1 -1
  57. package/dist/components/vibedeck/VibeDeckForm.js +1 -1
  58. package/dist/components/vibedeck/VibeDeckForm.js.map +1 -1
  59. package/dist/components/vibedeck/VibeDeckGrid.js +1 -1
  60. package/dist/components/vibedeck/VibeDeckGrid.js.map +1 -1
  61. package/dist/pages/AgentsPage.js +2 -2
  62. package/dist/pages/AgentsPage.js.map +1 -1
  63. package/dist/pages/CatalogDetailPage.js +1 -1
  64. package/dist/pages/CatalogDetailPage.js.map +1 -1
  65. package/dist/pages/ComponentDetailPage.js +1 -1
  66. package/dist/pages/ComponentDetailPage.js.map +1 -1
  67. package/dist/pages/OverviewPage.js +10 -10
  68. package/dist/pages/OverviewPage.js.map +1 -1
  69. package/dist/pages/PluginsCatalogPage.js +1 -1
  70. package/dist/pages/PluginsCatalogPage.js.map +1 -1
  71. package/dist/pages/SessionsPage.js +3 -3
  72. package/dist/pages/SessionsPage.js.map +1 -1
  73. package/dist/pages/SharedSessionPage.js +2 -2
  74. package/dist/pages/SharedSessionPage.js.map +1 -1
  75. package/dist/pages/TargetsPage.js +2 -2
  76. package/dist/pages/TargetsPage.js.map +1 -1
  77. package/dist/pages/TemplateDetailPage.js +2 -2
  78. package/dist/pages/TemplateDetailPage.js.map +1 -1
  79. package/dist/pages/VibesPage.js +2 -2
  80. package/dist/pages/VibesPage.js.map +1 -1
  81. package/dist/pages/WebhooksPage.js +2 -2
  82. package/dist/pages/WebhooksPage.js.map +1 -1
  83. package/dist/pages/ai/AISessionDetailPage.js +2 -2
  84. package/dist/pages/ai/AISessionDetailPage.js.map +1 -1
  85. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ComponentDetailPage.js","names":[],"sources":["../../src/pages/ComponentDetailPage.tsx"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport { AnimatePresence, motion } from 'framer-motion';\nimport {\n ArrowLeft,\n Box,\n BookOpen,\n BarChart3,\n FileText,\n Settings,\n RefreshCw,\n FileCode,\n Layers,\n Upload,\n Trash2,\n Tag,\n Plus,\n X,\n Share2,\n} from 'lucide-react';\nimport {\n PageHeader,\n Card,\n StatCard,\n EmptyState,\n ErrorState,\n QuotaExhaustedDialog,\n ConfirmDialog,\n} from '@/components/shared';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { PageSkeleton } from '@/components/shared/PageSkeleton';\nimport { MotionPage, MotionList, MotionItem } from '@burdenoff/fe-libs/shared/motion';\n\nimport { DocsTabPanel } from '@/components/docs';\nimport { ScorecardPanel } from '@/components/scorecard';\nimport { CatalogCard } from '@/components/catalog';\nimport type { CatalogCardData } from '@/components/catalog';\nimport { ComponentForm, DependencyGraphTab } from '@/components/idp-components';\nimport type { ComponentFormData } from '@/components/idp-components';\nimport { PublishTemplateForm } from '@/components/templates';\nimport type { PublishTemplateFormData } from '@/components/templates';\nimport { EntityShareButton } from '@/components/sharing';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useQueryBackedTab } from '@/hooks/useQueryBackedTab';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { isQuotaExhaustedError, markQuotaHandledLocally } from '@/utils/quotaUtils';\nimport {\n useGetComponentQuery,\n useUpdateComponentMutation,\n useDeleteComponentMutation,\n usePublishComponentAsTemplateMutation,\n useAddComponentToCatalogMutation,\n useListCatalogsQuery,\n} from '@/generated/wspace-operations';\nimport type { VibecontrolsTemplateCategory } from '@/generated/wspace-types';\n\ntype ComponentTab =\n | 'overview'\n | 'catalogs'\n | 'scorecard'\n | 'docs'\n | 'dependencies'\n | 'template'\n | 'settings';\nconst COMPONENT_TABS: readonly ComponentTab[] = [\n 'overview',\n 'catalogs',\n 'scorecard',\n 'docs',\n 'dependencies',\n 'template',\n 'settings',\n];\n\nexport function ComponentDetailPage() {\n const { t } = useI18n();\n const { id } = useParams<{ id: string }>();\n const navigate = useVibeNavigate();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const canReadComponent = hasPermission(VIBE_PERMISSIONS.COMPONENT_READ);\n const canUpdateComponent = hasPermission(VIBE_PERMISSIONS.COMPONENT_UPDATE);\n const canDeleteComponent = hasPermission(VIBE_PERMISSIONS.COMPONENT_DELETE);\n const canReadCatalog = hasPermission(VIBE_PERMISSIONS.CATALOG_READ);\n const canUpdateCatalog = hasPermission(VIBE_PERMISSIONS.CATALOG_UPDATE);\n const canUseCatalogPicker = canReadCatalog && canUpdateCatalog;\n const canCreateTemplate = hasPermission(VIBE_PERMISSIONS.TEMPLATE_CREATE);\n\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n const [activeTab, setActiveTab] = useQueryBackedTab<ComponentTab>(COMPONENT_TABS, 'overview');\n const [showEditForm, setShowEditForm] = useState(false);\n const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);\n const [isDeleting, setIsDeleting] = useState(false);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n const [showQuotaExhausted, setShowQuotaExhausted] = useState(false);\n const [showPublishForm, setShowPublishForm] = useState(false);\n const [showAddToCatalog, setShowAddToCatalog] = useState(false);\n\n const { data, loading, error, refetch } = useGetComponentQuery({\n variables: { id: id || '' },\n skip: !id || permissionsLoading || !canReadComponent,\n fetchPolicy: 'cache-and-network',\n });\n\n const [updateComponent] = useUpdateComponentMutation({ refetchQueries: ['GetComponent'] });\n const [deleteComponent] = useDeleteComponentMutation({ refetchQueries: ['ListComponents'] });\n const [publishAsTemplate] = usePublishComponentAsTemplateMutation({\n refetchQueries: ['GetComponent'],\n });\n const [addToCatalog] = useAddComponentToCatalogMutation({ refetchQueries: ['GetComponent'] });\n const { data: catalogsData } = useListCatalogsQuery({\n variables: { pagination: { limit: 100, offset: 0 } },\n skip: !showAddToCatalog || !canUseCatalogPicker,\n fetchPolicy: 'cache-and-network',\n });\n\n const component = data?.vibecontrolsComponent ?? null;\n\n const catalogs: CatalogCardData[] = useMemo(() => {\n return (component?.catalogs ?? []).map((entry: Record<string, any>) => {\n const c = entry.catalog || {};\n return {\n id: c.id as string,\n name: c.name as string,\n description: (c.description as string) || null,\n visibility: c.visibility as CatalogCardData['visibility'],\n componentCount: (c.componentCount as number) || 0,\n vibeCount: (c.vibeCount as number) || 0,\n tags: (c.tags as string[]) || [],\n createdAt: c.createdAt as string,\n updatedAt: c.updatedAt as string,\n };\n });\n }, [component?.catalogs]);\n\n if (permissionsLoading)\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <p className=\"text-text-secondary\">Loading permissions…</p>\n </div>\n );\n if (!canReadComponent)\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Access Denied</h2>\n <p className=\"text-sm text-text-secondary\">\n You don't have permission to access this page.\n </p>\n </div>\n </div>\n );\n\n const handleBack = () => {\n navigate('/components');\n };\n\n const handleCatalogClick = (catalog: CatalogCardData) => {\n navigate(`/catalogs/${catalog.id}`);\n };\n\n const handleUpdateComponent = async (formData: ComponentFormData) => {\n if (!id || !canUpdateComponent) return;\n await updateComponent({\n variables: {\n id,\n input: {\n name: formData.name,\n description: formData.description || undefined,\n type: formData.type,\n lifecycle: formData.lifecycle,\n language: formData.language || undefined,\n framework: formData.framework || undefined,\n version: formData.version || undefined,\n ownerName: formData.ownerName || undefined,\n tags: formData.tags.length > 0 ? formData.tags : undefined,\n repositoryUrl: formData.repositoryUrl || undefined,\n documentationUrl: formData.documentationUrl || undefined,\n dependencies: formData.dependencies ?? undefined,\n sbomData: formData.sbomData ?? undefined,\n },\n },\n });\n setSuccessMessage(tr('component.updatedSuccess', 'Component updated successfully'));\n setTimeout(() => setSuccessMessage(null), 3000);\n };\n\n const handleDeleteComponent = async () => {\n if (!id) return;\n setIsDeleting(true);\n try {\n await deleteComponent({ variables: { id } });\n setShowDeleteConfirm(false);\n navigate('/components');\n } finally {\n setIsDeleting(false);\n }\n };\n\n const handlePublishAsTemplate = async (formData: PublishTemplateFormData) => {\n if (!id || !canCreateTemplate) return;\n try {\n const res = await publishAsTemplate({\n variables: {\n componentId: id,\n input: {\n name: formData.name,\n description: formData.description || undefined,\n category: formData.category as VibecontrolsTemplateCategory,\n version: formData.version || undefined,\n setupInstructions: formData.setupInstructions || undefined,\n variables: formData.variables.length > 0 ? formData.variables : undefined,\n sourceRepositoryUrl: formData.sourceRepositoryUrl,\n },\n },\n });\n if (res.error && isQuotaExhaustedError(res.error)) {\n setShowPublishForm(false);\n setShowQuotaExhausted(true);\n return;\n }\n setShowPublishForm(false);\n setSuccessMessage(tr('component.publishedAsTemplate', 'Published as template successfully'));\n setTimeout(() => setSuccessMessage(null), 3000);\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n setShowPublishForm(false);\n markQuotaHandledLocally();\n setShowQuotaExhausted(true);\n return;\n }\n throw err;\n }\n };\n\n const lifecycleStyles: Record<string, string> = {\n EXPERIMENTAL: 'bg-status-warning-bg text-status-warning-text',\n ACTIVE: 'bg-status-success-bg text-status-success-text',\n DEPRECATED: 'bg-status-error-bg text-status-error-text',\n END_OF_LIFE: 'bg-status-error-bg text-status-error-text',\n };\n\n const deps = Array.isArray(component?.dependencies)\n ? (component.dependencies as Array<{\n name: string;\n version?: string | null;\n type?: string | null;\n }>)\n : [];\n\n const tabs: { id: ComponentTab; label: string; icon: typeof Box; badge?: string }[] = [\n { id: 'overview', label: tr('nav.overview', 'Overview'), icon: Box },\n {\n id: 'catalogs',\n label: tr('component.catalogs', 'Catalogs'),\n icon: BookOpen,\n badge: `${catalogs.length}`,\n },\n { id: 'scorecard', label: tr('component.scorecard', 'Scorecard'), icon: BarChart3 },\n { id: 'docs', label: tr('component.docs', 'Docs'), icon: FileText },\n {\n id: 'dependencies',\n label: tr('component.dependencies', 'Dependencies'),\n icon: Share2,\n badge: deps.length > 0 ? `${deps.length}` : undefined,\n },\n { id: 'template', label: tr('component.template', 'Template'), icon: FileCode },\n { id: 'settings', label: tr('common.settings', 'Settings'), icon: Settings },\n ];\n\n // Guard states\n if (loading && !component) {\n return (\n <MotionPage className=\"space-y-6 px-6 lg:px-8 py-6 bg-bg-canvas min-h-screen\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('component.backToComponents', 'Back to Components')}\n </button>\n <PageSkeleton variant=\"detail\" />\n </MotionPage>\n );\n }\n\n if (error && !component) {\n return (\n <MotionPage className=\"space-y-6 px-6 lg:px-8 py-6 bg-bg-canvas min-h-screen\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('component.backToComponents', 'Back to Components')}\n </button>\n <ErrorState\n title={tr('component.failedLoad', 'Failed to load component')}\n message={error.message}\n onRetry={() => refetch()}\n />\n </MotionPage>\n );\n }\n\n if (!component) {\n return (\n <MotionPage className=\"space-y-6 px-6 lg:px-8 py-6 bg-bg-canvas min-h-screen\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('component.backToComponents', 'Back to Components')}\n </button>\n <EmptyState\n icon={<Box className=\"size-8 text-text-secondary\" />}\n title={tr('component.notFound', 'Component not found')}\n description={`No component with ID \"${id}\" exists`}\n action={\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n {tr('component.backToComponents', 'Back to Components')}\n </button>\n }\n />\n </MotionPage>\n );\n }\n\n return (\n <MotionPage className=\"space-y-6 px-6 lg:px-8 py-6 bg-bg-canvas min-h-screen\">\n {/* Success Toast */}\n {successMessage && (\n <div className=\"fixed top-4 left-4 right-4 sm:left-auto z-50 bg-status-success-bg text-status-success-text px-4 py-3 rounded-md shadow-lg\">\n {successMessage}\n </div>\n )}\n\n {/* Back Button */}\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('component.backToComponents', 'Back to Components')}\n </button>\n\n {/* Header */}\n <PageHeader\n title={component.name}\n description={component.description || tr('component.noDescription', 'No description')}\n actions={\n <div className=\"flex items-center gap-2 flex-wrap\">\n <EntityShareButton\n entity=\"component\"\n resource={{ id: component.id, name: component.name }}\n label={tr('component.share', 'Share')}\n variant=\"button\"\n />\n <button\n type=\"button\"\n onClick={() => refetch()}\n disabled={loading}\n className=\"flex items-center justify-center p-2 bg-bg-sunken text-text-primary rounded-md hover:bg-action-secondary-bg-hover transition-colors disabled:opacity-50\"\n title={tr('common.refresh', 'Refresh')}\n >\n <RefreshCw className={`size-4 ${loading ? 'animate-spin' : ''}`} />\n </button>\n <span className=\"inline-flex items-center px-2.5 py-1 text-xs font-medium bg-bg-sunken text-text-secondary rounded\">\n {component.type}\n </span>\n <span\n className={`inline-flex items-center px-2.5 py-1 text-xs font-medium rounded ${lifecycleStyles[component.lifecycle] || 'bg-bg-sunken text-text-secondary'}`}\n >\n {component.lifecycle}\n </span>\n </div>\n }\n />\n\n {/* Stat Cards */}\n <MotionList stagger={0.04} className=\"grid grid-cols-2 sm:grid-cols-4 gap-3 sm:gap-4\">\n <MotionItem>\n <StatCard\n title={tr('component.type', 'Type')}\n value={component.type}\n icon={<Box className=\"size-4\" />}\n />\n </MotionItem>\n <MotionItem>\n <StatCard\n title={tr('component.lifecycle', 'Lifecycle')}\n value={component.lifecycle}\n icon={<Layers className=\"size-4\" />}\n variant={\n component.lifecycle === 'ACTIVE'\n ? 'success'\n : component.lifecycle === 'DEPRECATED' || component.lifecycle === 'END_OF_LIFE'\n ? 'error'\n : 'warning'\n }\n />\n </MotionItem>\n <MotionItem>\n <StatCard\n title={tr('component.version', 'Version')}\n value={component.version || '-'}\n icon={<FileCode className=\"size-4\" />}\n />\n </MotionItem>\n <MotionItem>\n <StatCard\n title={tr('component.catalogs', 'Catalogs')}\n value={catalogs.length}\n icon={<BookOpen className=\"size-4\" />}\n />\n </MotionItem>\n </MotionList>\n\n {/* Universal tags */}\n <Card>\n <div className=\"p-4 border-b border-border-default flex items-center gap-2\">\n <Tag className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">{tr('component.tags', 'Tags')}</h3>\n </div>\n <div className=\"p-4\">\n <EntityTagPicker entityType=\"VIBECONTROLS_COMPONENT\" entityId={component.id} />\n </div>\n </Card>\n\n {/* Tab Navigation */}\n <div className=\"border-b border-border-default\">\n <nav\n className=\"flex gap-1 -mb-px overflow-x-auto pb-1\"\n aria-label={tr('component.tabsAriaLabel', 'Component tabs')}\n >\n {tabs.map((tab) => {\n const Icon = tab.icon;\n const isActiveTab = activeTab === tab.id;\n return (\n <button\n type=\"button\"\n key={tab.id}\n onClick={() => setActiveTab(tab.id)}\n className={`flex shrink-0 items-center gap-1.5 px-3 py-2.5 text-xs sm:gap-2 sm:px-4 sm:text-sm font-medium border-b-2 transition-colors whitespace-nowrap ${\n isActiveTab\n ? 'border-action-primary-bg text-action-primary-text'\n : 'border-transparent text-text-secondary hover:text-text-primary hover:border-border-default'\n }`}\n aria-selected={isActiveTab}\n role=\"tab\"\n >\n <Icon className=\"size-4\" />\n {tab.label}\n {tab.badge && (\n <span\n className={`hidden rounded-full px-1.5 py-0.5 text-[10px] sm:inline-flex sm:text-xs ${\n isActiveTab\n ? 'bg-[var(--color-accent-soft)] text-action-primary-bg'\n : 'bg-bg-sunken text-text-muted'\n }`}\n >\n {tab.badge}\n </span>\n )}\n </button>\n );\n })}\n </nav>\n </div>\n\n {/* Tab Panels */}\n <AnimatePresence mode=\"wait\">\n {activeTab === 'overview' && (\n <motion.div\n key=\"overview\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n {component.description && (\n <Card>\n <div className=\"p-4\">\n <p className=\"text-text-primary\">{component.description}</p>\n </div>\n </Card>\n )}\n\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary\">\n {tr('component.metadata', 'Metadata')}\n </h3>\n </div>\n <div className=\"p-4\">\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4 text-sm\">\n <div>\n <p className=\"text-text-secondary\">{tr('component.ownerNameLabel', 'Owner')}</p>\n <p className=\"font-medium text-text-primary\">\n {component.ownerName || tr('common.unset', 'Unset')}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">\n {tr('component.languageLabel', 'Language')}\n </p>\n <p className=\"font-medium text-text-primary\">\n {component.language || tr('common.unset', 'Unset')}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">\n {tr('component.frameworkLabel', 'Framework')}\n </p>\n <p className=\"font-medium text-text-primary\">\n {component.framework || tr('common.unset', 'Unset')}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">{tr('component.versionLabel', 'Version')}</p>\n <p className=\"font-medium text-text-primary\">\n {component.version || tr('common.unset', 'Unset')}\n </p>\n </div>\n {component.repositoryUrl && (\n <div className=\"sm:col-span-2\">\n <p className=\"text-text-secondary\">\n {tr('component.repository', 'Repository')}\n </p>\n <a\n href={component.repositoryUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"font-medium text-action-primary-bg hover:underline break-all\"\n >\n {component.repositoryUrl}\n </a>\n </div>\n )}\n <div>\n <p className=\"text-text-secondary\">{tr('common.created', 'Created')}</p>\n <p className=\"font-medium text-text-primary\">\n {new Date(component.createdAt).toLocaleDateString()}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">{tr('common.updated', 'Updated')}</p>\n <p className=\"font-medium text-text-primary\">\n {new Date(component.updatedAt).toLocaleDateString()}\n </p>\n </div>\n </div>\n </div>\n </Card>\n\n {component.tags?.length > 0 && (\n <Card>\n <div className=\"p-4\">\n <h3 className=\"font-semibold text-text-primary mb-3\">\n {tr('component.tags', 'Tags')}\n </h3>\n <div className=\"flex flex-wrap gap-2\">\n {component.tags.map((tag: string) => (\n <span\n key={tag}\n className=\"px-2.5 py-1 text-sm bg-bg-sunken text-text-secondary rounded-md\"\n >\n {tag}\n </span>\n ))}\n </div>\n </div>\n </Card>\n )}\n </motion.div>\n )}\n\n {activeTab === 'catalogs' && (\n <motion.div\n key=\"catalogs\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-4\"\n >\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm text-text-secondary\">\n {catalogs.length}{' '}\n {tr('component.catalogsContaining', 'catalogs containing this component')}\n </p>\n {canUseCatalogPicker && (\n <button\n type=\"button\"\n onClick={() => setShowAddToCatalog(true)}\n className=\"flex items-center gap-2 px-3 py-2 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('component.addToCatalog', 'Add to Catalog')}\n </button>\n )}\n </div>\n {catalogs.length > 0 ? (\n <MotionList\n stagger={0.04}\n className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\"\n >\n {catalogs.map((catalog) => (\n <MotionItem key={catalog.id}>\n <CatalogCard catalog={catalog} onOpen={handleCatalogClick} />\n </MotionItem>\n ))}\n </MotionList>\n ) : (\n <EmptyState\n icon={<BookOpen className=\"size-8 text-text-secondary\" />}\n title={tr('component.noCatalogs', 'Not in any catalogs')}\n description={tr(\n 'component.noCatalogsDescription',\n 'This component has not been added to any catalogs yet'\n )}\n action={\n canUseCatalogPicker ? (\n <button\n type=\"button\"\n onClick={() => setShowAddToCatalog(true)}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('component.addToCatalog', 'Add to Catalog')}\n </button>\n ) : undefined\n }\n />\n )}\n </motion.div>\n )}\n\n {activeTab === 'scorecard' && (\n <motion.div\n key=\"scorecard\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <ScorecardPanel ownerType=\"COMPONENT\" ownerId={id || ''} />\n </motion.div>\n )}\n\n {activeTab === 'docs' && (\n <motion.div\n key=\"docs\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <DocsTabPanel ownerType=\"COMPONENT\" ownerId={id || ''} />\n </motion.div>\n )}\n\n {activeTab === 'dependencies' && (\n <motion.div\n key=\"dependencies\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n >\n <DependencyGraphTab\n componentName={component.name}\n componentType={component.type}\n dependencies={deps}\n />\n </motion.div>\n )}\n\n {activeTab === 'template' && (\n <motion.div\n key=\"template\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-4\"\n >\n {(component.templates?.length ?? 0) === 0 ? (\n <Card padding=\"lg\">\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <FileCode className=\"size-12 text-text-muted mb-4\" />\n <h3 className=\"text-lg font-semibold text-text-primary mb-2\">\n {tr('component.template', 'Publish as Template')}\n </h3>\n <p className=\"text-sm text-text-secondary max-w-md mb-6\">\n {tr(\n 'component.publishDescription',\n 'Turn this component into a reusable template. Others can clone it and fill in configuration variables to create new components.'\n )}\n </p>\n {canCreateTemplate && (\n <button\n type=\"button\"\n onClick={() => setShowPublishForm(true)}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Upload className=\"size-4\" />\n {tr('component.publishAsTemplate', 'Publish as Template')}\n </button>\n )}\n </div>\n </Card>\n ) : (\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary\">Published Templates</h3>\n </div>\n <div className=\"p-4 space-y-3\">\n {component.templates.map((tmpl: Record<string, string>) => (\n <div\n key={tmpl.id}\n className=\"flex items-center justify-between p-3 bg-bg-sunken rounded-lg\"\n >\n <div className=\"flex items-center gap-3\">\n <FileCode className=\"size-5 text-action-primary-bg\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">{tmpl.name}</p>\n <p className=\"text-xs text-text-muted\">\n {tmpl.category} · v{tmpl.version || '—'}\n </p>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={() => navigate(`/templates/${tmpl.id}`)}\n className=\"text-xs text-action-primary-bg hover:underline\"\n >\n View Template →\n </button>\n </div>\n ))}\n {canCreateTemplate && (\n <button\n type=\"button\"\n onClick={() => setShowPublishForm(true)}\n className=\"flex items-center gap-2 px-3 py-2 text-sm text-text-secondary border border-dashed border-border-default hover:border-border-strong rounded-lg w-full justify-center transition-colors\"\n >\n <Upload className=\"size-4\" />\n Update template\n </button>\n )}\n </div>\n </Card>\n )}\n </motion.div>\n )}\n\n {activeTab === 'settings' && (\n <motion.div\n key=\"settings\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n >\n <div className=\"space-y-4\">\n {canUpdateComponent && (\n <Card padding=\"lg\">\n <h3 className=\"font-semibold text-text-primary mb-4\">\n {tr('component.editComponent', 'Edit Component')}\n </h3>\n <button\n type=\"button\"\n onClick={() => setShowEditForm(true)}\n className=\"px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n {tr('component.editDetails', 'Edit Details')}\n </button>\n </Card>\n )}\n {canDeleteComponent && (\n <Card padding=\"lg\">\n <h3 className=\"font-semibold text-status-error-text mb-2\">\n {tr('component.dangerZone', 'Danger Zone')}\n </h3>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n 'component.deleteWarning',\n 'Deleting this component will remove it from all catalogs and break any templates derived from it. This cannot be undone.'\n )}\n </p>\n <button\n type=\"button\"\n data-testid=\"component-delete-button\"\n onClick={() => setShowDeleteConfirm(true)}\n className=\"inline-flex items-center gap-2 px-4 py-2 bg-status-error-bg text-status-error-text rounded-md hover:opacity-90 transition-opacity\"\n >\n <Trash2 className=\"size-4\" aria-hidden=\"true\" />\n {tr('component.deleteComponent', 'Delete Component')}\n </button>\n </Card>\n )}\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n\n {/* Edit Form */}\n {canUpdateComponent && (\n <ComponentForm\n isOpen={showEditForm}\n onClose={() => setShowEditForm(false)}\n onSubmit={handleUpdateComponent}\n initialData={{\n name: component.name,\n description: component.description || '',\n type: component.type,\n lifecycle: component.lifecycle,\n language: component.language || '',\n framework: component.framework || '',\n version: component.version || '',\n ownerName: component.ownerName || '',\n tags: component.tags || [],\n repositoryUrl: component.repositoryUrl || '',\n documentationUrl: component.documentationUrl || '',\n dependencies: Array.isArray(component.dependencies) ? component.dependencies : null,\n sbomData:\n component.sbomData && typeof component.sbomData === 'object'\n ? (component.sbomData as Record<string, unknown>)\n : null,\n }}\n title={tr('component.editComponent', 'Edit Component')}\n />\n )}\n\n <ConfirmDialog\n isOpen={showDeleteConfirm}\n onClose={() => setShowDeleteConfirm(false)}\n onConfirm={handleDeleteComponent}\n title={tr('component.deleteComponent', 'Delete Component')}\n message={tr(\n 'component.deleteConfirmMessage',\n `Are you sure you want to delete \"${component.name}\"? This action cannot be undone.`\n )}\n confirmLabel={tr('common.delete', 'Delete')}\n variant=\"danger\"\n isLoading={isDeleting}\n />\n\n <QuotaExhaustedDialog\n isOpen={showQuotaExhausted}\n onClose={() => setShowQuotaExhausted(false)}\n onConfirm={() => {\n setShowQuotaExhausted(false);\n navigate('/billing/plans');\n }}\n title=\"Template Quota Reached\"\n message=\"You've reached the maximum number of published templates on your current plan. Upgrade your plan or purchase an add-on to publish more templates.\"\n />\n\n {showPublishForm && canCreateTemplate && (\n <PublishTemplateForm\n componentName={component.name}\n componentRepositoryUrl={component.repositoryUrl}\n onClose={() => setShowPublishForm(false)}\n onSubmit={handlePublishAsTemplate}\n />\n )}\n\n {showAddToCatalog && canUseCatalogPicker && (\n <div\n className=\"fixed inset-0 flex items-center justify-center z-50 p-4\"\n style={{ backgroundColor: 'rgba(0,0,0,0.55)' }}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n className=\"bg-bg-surface rounded-lg w-full max-w-md shadow-xl\"\n >\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-default\">\n <h2 className=\"text-base font-semibold text-text-primary\">\n {tr('component.addToCatalog', 'Add to Catalog')}\n </h2>\n <button\n type=\"button\"\n onClick={() => setShowAddToCatalog(false)}\n className=\"p-1.5 text-text-secondary hover:text-text-primary rounded-md hover:bg-bg-sunken transition-colors\"\n >\n <X className=\"size-4\" />\n </button>\n </div>\n <div className=\"p-2 max-h-80 overflow-y-auto\">\n {(catalogsData?.vibecontrolsCatalogs?.items ?? []).length === 0 ? (\n <p className=\"text-sm text-text-secondary text-center py-6\">\n No catalogs found.{' '}\n <button\n type=\"button\"\n onClick={() => {\n setShowAddToCatalog(false);\n navigate('/catalogs');\n }}\n className=\"text-action-primary-bg hover:underline\"\n >\n Create one first.\n </button>\n </p>\n ) : (\n (catalogsData?.vibecontrolsCatalogs?.items ?? []).map(\n (cat: { id: string; name: string }) => {\n const alreadyIn = catalogs.some((c) => c.id === cat.id);\n return (\n <button\n type=\"button\"\n key={cat.id}\n disabled={alreadyIn}\n onClick={async () => {\n if (!id || alreadyIn) return;\n try {\n await addToCatalog({\n variables: { catalogId: cat.id, componentId: id },\n });\n setShowAddToCatalog(false);\n setSuccessMessage(`Added to ${cat.name}`);\n setTimeout(() => setSuccessMessage(null), 3000);\n } catch {\n // error shown by Apollo\n }\n }}\n className={`flex items-center justify-between w-full px-3 py-2.5 text-left rounded-md transition-colors ${\n alreadyIn\n ? 'opacity-40 cursor-not-allowed'\n : 'hover:bg-bg-sunken cursor-pointer'\n }`}\n >\n <div className=\"flex items-center gap-2\">\n <BookOpen className=\"size-4 text-action-primary-bg flex-shrink-0\" />\n <span className=\"text-sm text-text-primary\">{cat.name}</span>\n </div>\n {alreadyIn && (\n <span className=\"text-xs text-text-muted\">already added</span>\n )}\n </button>\n );\n }\n )\n )}\n </div>\n </motion.div>\n </div>\n )}\n </MotionPage>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ComponentDetailPage.js","names":[],"sources":["../../src/pages/ComponentDetailPage.tsx"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport { AnimatePresence, motion } from 'framer-motion';\nimport {\n ArrowLeft,\n Box,\n BookOpen,\n BarChart3,\n FileText,\n Settings,\n RefreshCw,\n FileCode,\n Layers,\n Upload,\n Trash2,\n Tag,\n Plus,\n X,\n Share2,\n} from 'lucide-react';\nimport {\n PageHeader,\n Card,\n StatCard,\n EmptyState,\n ErrorState,\n QuotaExhaustedDialog,\n ConfirmDialog,\n} from '@/components/shared';\nimport { EntityTagPicker } from '@/components/shared/EntityTagPicker';\nimport { PageSkeleton } from '@/components/shared/PageSkeleton';\nimport { MotionPage, MotionList, MotionItem } from '@burdenoff/fe-libs/shared/motion';\n\nimport { DocsTabPanel } from '@/components/docs';\nimport { ScorecardPanel } from '@/components/scorecard';\nimport { CatalogCard } from '@/components/catalog';\nimport type { CatalogCardData } from '@/components/catalog';\nimport { ComponentForm, DependencyGraphTab } from '@/components/idp-components';\nimport type { ComponentFormData } from '@/components/idp-components';\nimport { PublishTemplateForm } from '@/components/templates';\nimport type { PublishTemplateFormData } from '@/components/templates';\nimport { EntityShareButton } from '@/components/sharing';\nimport { useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useQueryBackedTab } from '@/hooks/useQueryBackedTab';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { isQuotaExhaustedError, markQuotaHandledLocally } from '@/utils/quotaUtils';\nimport {\n useGetComponentQuery,\n useUpdateComponentMutation,\n useDeleteComponentMutation,\n usePublishComponentAsTemplateMutation,\n useAddComponentToCatalogMutation,\n useListCatalogsQuery,\n} from '@/generated/wspace-operations';\nimport type { VibecontrolsTemplateCategory } from '@/generated/wspace-types';\n\ntype ComponentTab =\n | 'overview'\n | 'catalogs'\n | 'scorecard'\n | 'docs'\n | 'dependencies'\n | 'template'\n | 'settings';\nconst COMPONENT_TABS: readonly ComponentTab[] = [\n 'overview',\n 'catalogs',\n 'scorecard',\n 'docs',\n 'dependencies',\n 'template',\n 'settings',\n];\n\nexport function ComponentDetailPage() {\n const { t } = useI18n();\n const { id } = useParams<{ id: string }>();\n const navigate = useVibeNavigate();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const canReadComponent = hasPermission(VIBE_PERMISSIONS.COMPONENT_READ);\n const canUpdateComponent = hasPermission(VIBE_PERMISSIONS.COMPONENT_UPDATE);\n const canDeleteComponent = hasPermission(VIBE_PERMISSIONS.COMPONENT_DELETE);\n const canReadCatalog = hasPermission(VIBE_PERMISSIONS.CATALOG_READ);\n const canUpdateCatalog = hasPermission(VIBE_PERMISSIONS.CATALOG_UPDATE);\n const canUseCatalogPicker = canReadCatalog && canUpdateCatalog;\n const canCreateTemplate = hasPermission(VIBE_PERMISSIONS.TEMPLATE_CREATE);\n\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n const [activeTab, setActiveTab] = useQueryBackedTab<ComponentTab>(COMPONENT_TABS, 'overview');\n const [showEditForm, setShowEditForm] = useState(false);\n const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);\n const [isDeleting, setIsDeleting] = useState(false);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n const [showQuotaExhausted, setShowQuotaExhausted] = useState(false);\n const [showPublishForm, setShowPublishForm] = useState(false);\n const [showAddToCatalog, setShowAddToCatalog] = useState(false);\n\n const { data, loading, error, refetch } = useGetComponentQuery({\n variables: { id: id || '' },\n skip: !id || permissionsLoading || !canReadComponent,\n fetchPolicy: 'cache-and-network',\n });\n\n const [updateComponent] = useUpdateComponentMutation({ refetchQueries: ['GetComponent'] });\n const [deleteComponent] = useDeleteComponentMutation({ refetchQueries: ['ListComponents'] });\n const [publishAsTemplate] = usePublishComponentAsTemplateMutation({\n refetchQueries: ['GetComponent'],\n });\n const [addToCatalog] = useAddComponentToCatalogMutation({ refetchQueries: ['GetComponent'] });\n const { data: catalogsData } = useListCatalogsQuery({\n variables: { pagination: { limit: 100, offset: 0 } },\n skip: !showAddToCatalog || !canUseCatalogPicker,\n fetchPolicy: 'cache-and-network',\n });\n\n const component = data?.vibecontrolsComponent ?? null;\n\n const catalogs: CatalogCardData[] = useMemo(() => {\n return (component?.catalogs ?? []).map((entry: Record<string, any>) => {\n const c = entry.catalog || {};\n return {\n id: c.id as string,\n name: c.name as string,\n description: (c.description as string) || null,\n visibility: c.visibility as CatalogCardData['visibility'],\n componentCount: (c.componentCount as number) || 0,\n vibeCount: (c.vibeCount as number) || 0,\n tags: (c.tags as string[]) || [],\n createdAt: c.createdAt as string,\n updatedAt: c.updatedAt as string,\n };\n });\n }, [component?.catalogs]);\n\n if (permissionsLoading)\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <p className=\"text-text-secondary\">Loading permissions…</p>\n </div>\n );\n if (!canReadComponent)\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Access Denied</h2>\n <p className=\"text-sm text-text-secondary\">\n You don't have permission to access this page.\n </p>\n </div>\n </div>\n );\n\n const handleBack = () => {\n navigate('/components');\n };\n\n const handleCatalogClick = (catalog: CatalogCardData) => {\n navigate(`/catalogs/${catalog.id}`);\n };\n\n const handleUpdateComponent = async (formData: ComponentFormData) => {\n if (!id || !canUpdateComponent) return;\n await updateComponent({\n variables: {\n id,\n input: {\n name: formData.name,\n description: formData.description || undefined,\n type: formData.type,\n lifecycle: formData.lifecycle,\n language: formData.language || undefined,\n framework: formData.framework || undefined,\n version: formData.version || undefined,\n ownerName: formData.ownerName || undefined,\n tags: formData.tags.length > 0 ? formData.tags : undefined,\n repositoryUrl: formData.repositoryUrl || undefined,\n documentationUrl: formData.documentationUrl || undefined,\n dependencies: formData.dependencies ?? undefined,\n sbomData: formData.sbomData ?? undefined,\n },\n },\n });\n setSuccessMessage(tr('component.updatedSuccess', 'Component updated successfully'));\n setTimeout(() => setSuccessMessage(null), 3000);\n };\n\n const handleDeleteComponent = async () => {\n if (!id) return;\n setIsDeleting(true);\n try {\n await deleteComponent({ variables: { id } });\n setShowDeleteConfirm(false);\n navigate('/components');\n } finally {\n setIsDeleting(false);\n }\n };\n\n const handlePublishAsTemplate = async (formData: PublishTemplateFormData) => {\n if (!id || !canCreateTemplate) return;\n try {\n const res = await publishAsTemplate({\n variables: {\n componentId: id,\n input: {\n name: formData.name,\n description: formData.description || undefined,\n category: formData.category as VibecontrolsTemplateCategory,\n version: formData.version || undefined,\n setupInstructions: formData.setupInstructions || undefined,\n variables: formData.variables.length > 0 ? formData.variables : undefined,\n sourceRepositoryUrl: formData.sourceRepositoryUrl,\n },\n },\n });\n if (res.error && isQuotaExhaustedError(res.error)) {\n setShowPublishForm(false);\n setShowQuotaExhausted(true);\n return;\n }\n setShowPublishForm(false);\n setSuccessMessage(tr('component.publishedAsTemplate', 'Published as template successfully'));\n setTimeout(() => setSuccessMessage(null), 3000);\n } catch (err) {\n if (isQuotaExhaustedError(err)) {\n setShowPublishForm(false);\n markQuotaHandledLocally();\n setShowQuotaExhausted(true);\n return;\n }\n throw err;\n }\n };\n\n const lifecycleStyles: Record<string, string> = {\n EXPERIMENTAL: 'bg-status-warning-bg text-status-warning-text',\n ACTIVE: 'bg-status-success-bg text-status-success-text',\n DEPRECATED: 'bg-status-error-bg text-status-error-text',\n END_OF_LIFE: 'bg-status-error-bg text-status-error-text',\n };\n\n const deps = Array.isArray(component?.dependencies)\n ? (component.dependencies as Array<{\n name: string;\n version?: string | null;\n type?: string | null;\n }>)\n : [];\n\n const tabs: { id: ComponentTab; label: string; icon: typeof Box; badge?: string }[] = [\n { id: 'overview', label: tr('nav.overview', 'Overview'), icon: Box },\n {\n id: 'catalogs',\n label: tr('component.catalogs', 'Catalogs'),\n icon: BookOpen,\n badge: `${catalogs.length}`,\n },\n { id: 'scorecard', label: tr('component.scorecard', 'Scorecard'), icon: BarChart3 },\n { id: 'docs', label: tr('component.docs', 'Docs'), icon: FileText },\n {\n id: 'dependencies',\n label: tr('component.dependencies', 'Dependencies'),\n icon: Share2,\n badge: deps.length > 0 ? `${deps.length}` : undefined,\n },\n { id: 'template', label: tr('component.template', 'Template'), icon: FileCode },\n { id: 'settings', label: tr('common.settings', 'Settings'), icon: Settings },\n ];\n\n // Guard states\n if (loading && !component) {\n return (\n <MotionPage className=\"space-y-6 px-6 lg:px-8 py-6 bg-bg-canvas min-h-screen\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('component.backToComponents', 'Back to Components')}\n </button>\n <PageSkeleton variant=\"detail\" />\n </MotionPage>\n );\n }\n\n if (error && !component) {\n return (\n <MotionPage className=\"space-y-6 px-6 lg:px-8 py-6 bg-bg-canvas min-h-screen\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('component.backToComponents', 'Back to Components')}\n </button>\n <ErrorState\n title={tr('component.failedLoad', 'Failed to load component')}\n message={error.message}\n onRetry={() => refetch()}\n />\n </MotionPage>\n );\n }\n\n if (!component) {\n return (\n <MotionPage className=\"space-y-6 px-6 lg:px-8 py-6 bg-bg-canvas min-h-screen\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('component.backToComponents', 'Back to Components')}\n </button>\n <EmptyState\n icon={<Box className=\"size-8 text-text-secondary\" />}\n title={tr('component.notFound', 'Component not found')}\n description={`No component with ID \"${id}\" exists`}\n action={\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n {tr('component.backToComponents', 'Back to Components')}\n </button>\n }\n />\n </MotionPage>\n );\n }\n\n return (\n <MotionPage className=\"space-y-6 px-6 lg:px-8 py-6 bg-bg-canvas min-h-screen\">\n {/* Success Toast */}\n {successMessage && (\n <div className=\"fixed top-4 left-4 right-4 sm:left-auto z-50 bg-status-success-bg text-status-success-text px-4 py-3 rounded-md shadow-lg\">\n {successMessage}\n </div>\n )}\n\n {/* Back Button */}\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex items-center gap-2 text-text-secondary hover:text-text-primary transition-colors\"\n >\n <ArrowLeft className=\"size-4\" />\n {tr('component.backToComponents', 'Back to Components')}\n </button>\n\n {/* Header */}\n <PageHeader\n title={component.name}\n description={component.description || tr('component.noDescription', 'No description')}\n actions={\n <div className=\"flex items-center gap-2 flex-wrap\">\n <EntityShareButton\n entity=\"component\"\n resource={{ id: component.id, name: component.name }}\n label={tr('component.share', 'Share')}\n variant=\"button\"\n />\n <button\n type=\"button\"\n onClick={() => refetch()}\n disabled={loading}\n className=\"flex items-center justify-center p-2 bg-bg-sunken text-text-primary rounded-md hover:bg-action-secondary-bg-hover transition-colors disabled:opacity-50\"\n title={tr('common.refresh', 'Refresh')}\n >\n <RefreshCw className={`size-4 ${loading ? 'animate-spin' : ''}`} />\n </button>\n <span className=\"inline-flex items-center px-2.5 py-1 text-xs font-medium bg-bg-sunken text-text-secondary rounded\">\n {component.type}\n </span>\n <span\n className={`inline-flex items-center px-2.5 py-1 text-xs font-medium rounded ${lifecycleStyles[component.lifecycle] || 'bg-bg-sunken text-text-secondary'}`}\n >\n {component.lifecycle}\n </span>\n </div>\n }\n />\n\n {/* Stat Cards */}\n <MotionList stagger={0.04} className=\"grid grid-cols-2 sm:grid-cols-4 gap-3 sm:gap-4\">\n <MotionItem>\n <StatCard\n title={tr('component.type', 'Type')}\n value={component.type}\n icon={<Box className=\"size-4\" />}\n />\n </MotionItem>\n <MotionItem>\n <StatCard\n title={tr('component.lifecycle', 'Lifecycle')}\n value={component.lifecycle}\n icon={<Layers className=\"size-4\" />}\n variant={\n component.lifecycle === 'ACTIVE'\n ? 'success'\n : component.lifecycle === 'DEPRECATED' || component.lifecycle === 'END_OF_LIFE'\n ? 'error'\n : 'warning'\n }\n />\n </MotionItem>\n <MotionItem>\n <StatCard\n title={tr('component.version', 'Version')}\n value={component.version || '-'}\n icon={<FileCode className=\"size-4\" />}\n />\n </MotionItem>\n <MotionItem>\n <StatCard\n title={tr('component.catalogs', 'Catalogs')}\n value={catalogs.length}\n icon={<BookOpen className=\"size-4\" />}\n />\n </MotionItem>\n </MotionList>\n\n {/* Universal tags */}\n <Card>\n <div className=\"p-4 border-b border-border-default flex items-center gap-2\">\n <Tag className=\"size-5\" />\n <h3 className=\"font-semibold text-text-primary\">{tr('component.tags', 'Tags')}</h3>\n </div>\n <div className=\"p-4\">\n <EntityTagPicker entityType=\"VIBECONTROLS_COMPONENT\" entityId={component.id} />\n </div>\n </Card>\n\n {/* Tab Navigation */}\n <div className=\"border-b border-border-default\">\n <nav\n className=\"flex gap-1 -mb-px overflow-x-auto pb-1\"\n aria-label={tr('component.tabsAriaLabel', 'Component tabs')}\n >\n {tabs.map((tab) => {\n const Icon = tab.icon;\n const isActiveTab = activeTab === tab.id;\n return (\n <button\n type=\"button\"\n key={tab.id}\n onClick={() => setActiveTab(tab.id)}\n className={`flex shrink-0 items-center gap-1.5 px-3 py-2.5 text-xs sm:gap-2 sm:px-4 sm:text-sm font-medium border-b-2 transition-colors whitespace-nowrap ${\n isActiveTab\n ? 'border-action-primary-bg text-action-primary-text'\n : 'border-transparent text-text-secondary hover:text-text-primary hover:border-border-default'\n }`}\n aria-selected={isActiveTab}\n role=\"tab\"\n >\n <Icon className=\"size-4\" />\n {tab.label}\n {tab.badge && (\n <span\n className={`hidden rounded-full px-1.5 py-0.5 text-[10px] sm:inline-flex sm:text-xs ${\n isActiveTab\n ? 'bg-[var(--color-accent-soft)] text-text-primary'\n : 'bg-bg-sunken text-text-muted'\n }`}\n >\n {tab.badge}\n </span>\n )}\n </button>\n );\n })}\n </nav>\n </div>\n\n {/* Tab Panels */}\n <AnimatePresence mode=\"wait\">\n {activeTab === 'overview' && (\n <motion.div\n key=\"overview\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n {component.description && (\n <Card>\n <div className=\"p-4\">\n <p className=\"text-text-primary\">{component.description}</p>\n </div>\n </Card>\n )}\n\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary\">\n {tr('component.metadata', 'Metadata')}\n </h3>\n </div>\n <div className=\"p-4\">\n <div className=\"grid grid-cols-1 sm:grid-cols-2 gap-4 text-sm\">\n <div>\n <p className=\"text-text-secondary\">{tr('component.ownerNameLabel', 'Owner')}</p>\n <p className=\"font-medium text-text-primary\">\n {component.ownerName || tr('common.unset', 'Unset')}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">\n {tr('component.languageLabel', 'Language')}\n </p>\n <p className=\"font-medium text-text-primary\">\n {component.language || tr('common.unset', 'Unset')}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">\n {tr('component.frameworkLabel', 'Framework')}\n </p>\n <p className=\"font-medium text-text-primary\">\n {component.framework || tr('common.unset', 'Unset')}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">{tr('component.versionLabel', 'Version')}</p>\n <p className=\"font-medium text-text-primary\">\n {component.version || tr('common.unset', 'Unset')}\n </p>\n </div>\n {component.repositoryUrl && (\n <div className=\"sm:col-span-2\">\n <p className=\"text-text-secondary\">\n {tr('component.repository', 'Repository')}\n </p>\n <a\n href={component.repositoryUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"font-medium text-action-primary-bg hover:underline break-all\"\n >\n {component.repositoryUrl}\n </a>\n </div>\n )}\n <div>\n <p className=\"text-text-secondary\">{tr('common.created', 'Created')}</p>\n <p className=\"font-medium text-text-primary\">\n {new Date(component.createdAt).toLocaleDateString()}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">{tr('common.updated', 'Updated')}</p>\n <p className=\"font-medium text-text-primary\">\n {new Date(component.updatedAt).toLocaleDateString()}\n </p>\n </div>\n </div>\n </div>\n </Card>\n\n {component.tags?.length > 0 && (\n <Card>\n <div className=\"p-4\">\n <h3 className=\"font-semibold text-text-primary mb-3\">\n {tr('component.tags', 'Tags')}\n </h3>\n <div className=\"flex flex-wrap gap-2\">\n {component.tags.map((tag: string) => (\n <span\n key={tag}\n className=\"px-2.5 py-1 text-sm bg-bg-sunken text-text-secondary rounded-md\"\n >\n {tag}\n </span>\n ))}\n </div>\n </div>\n </Card>\n )}\n </motion.div>\n )}\n\n {activeTab === 'catalogs' && (\n <motion.div\n key=\"catalogs\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-4\"\n >\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm text-text-secondary\">\n {catalogs.length}{' '}\n {tr('component.catalogsContaining', 'catalogs containing this component')}\n </p>\n {canUseCatalogPicker && (\n <button\n type=\"button\"\n onClick={() => setShowAddToCatalog(true)}\n className=\"flex items-center gap-2 px-3 py-2 text-sm bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('component.addToCatalog', 'Add to Catalog')}\n </button>\n )}\n </div>\n {catalogs.length > 0 ? (\n <MotionList\n stagger={0.04}\n className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\"\n >\n {catalogs.map((catalog) => (\n <MotionItem key={catalog.id}>\n <CatalogCard catalog={catalog} onOpen={handleCatalogClick} />\n </MotionItem>\n ))}\n </MotionList>\n ) : (\n <EmptyState\n icon={<BookOpen className=\"size-8 text-text-secondary\" />}\n title={tr('component.noCatalogs', 'Not in any catalogs')}\n description={tr(\n 'component.noCatalogsDescription',\n 'This component has not been added to any catalogs yet'\n )}\n action={\n canUseCatalogPicker ? (\n <button\n type=\"button\"\n onClick={() => setShowAddToCatalog(true)}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Plus className=\"size-4\" />\n {tr('component.addToCatalog', 'Add to Catalog')}\n </button>\n ) : undefined\n }\n />\n )}\n </motion.div>\n )}\n\n {activeTab === 'scorecard' && (\n <motion.div\n key=\"scorecard\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <ScorecardPanel ownerType=\"COMPONENT\" ownerId={id || ''} />\n </motion.div>\n )}\n\n {activeTab === 'docs' && (\n <motion.div\n key=\"docs\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-6\"\n >\n <DocsTabPanel ownerType=\"COMPONENT\" ownerId={id || ''} />\n </motion.div>\n )}\n\n {activeTab === 'dependencies' && (\n <motion.div\n key=\"dependencies\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n >\n <DependencyGraphTab\n componentName={component.name}\n componentType={component.type}\n dependencies={deps}\n />\n </motion.div>\n )}\n\n {activeTab === 'template' && (\n <motion.div\n key=\"template\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n className=\"space-y-4\"\n >\n {(component.templates?.length ?? 0) === 0 ? (\n <Card padding=\"lg\">\n <div className=\"flex flex-col items-center justify-center py-12 text-center\">\n <FileCode className=\"size-12 text-text-muted mb-4\" />\n <h3 className=\"text-lg font-semibold text-text-primary mb-2\">\n {tr('component.template', 'Publish as Template')}\n </h3>\n <p className=\"text-sm text-text-secondary max-w-md mb-6\">\n {tr(\n 'component.publishDescription',\n 'Turn this component into a reusable template. Others can clone it and fill in configuration variables to create new components.'\n )}\n </p>\n {canCreateTemplate && (\n <button\n type=\"button\"\n onClick={() => setShowPublishForm(true)}\n className=\"flex items-center gap-2 px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n <Upload className=\"size-4\" />\n {tr('component.publishAsTemplate', 'Publish as Template')}\n </button>\n )}\n </div>\n </Card>\n ) : (\n <Card>\n <div className=\"p-4 border-b border-border-default\">\n <h3 className=\"font-semibold text-text-primary\">Published Templates</h3>\n </div>\n <div className=\"p-4 space-y-3\">\n {component.templates.map((tmpl: Record<string, string>) => (\n <div\n key={tmpl.id}\n className=\"flex items-center justify-between p-3 bg-bg-sunken rounded-lg\"\n >\n <div className=\"flex items-center gap-3\">\n <FileCode className=\"size-5 text-action-primary-bg\" />\n <div>\n <p className=\"text-sm font-medium text-text-primary\">{tmpl.name}</p>\n <p className=\"text-xs text-text-muted\">\n {tmpl.category} · v{tmpl.version || '—'}\n </p>\n </div>\n </div>\n <button\n type=\"button\"\n onClick={() => navigate(`/templates/${tmpl.id}`)}\n className=\"text-xs text-action-primary-bg hover:underline\"\n >\n View Template →\n </button>\n </div>\n ))}\n {canCreateTemplate && (\n <button\n type=\"button\"\n onClick={() => setShowPublishForm(true)}\n className=\"flex items-center gap-2 px-3 py-2 text-sm text-text-secondary border border-dashed border-border-default hover:border-border-strong rounded-lg w-full justify-center transition-colors\"\n >\n <Upload className=\"size-4\" />\n Update template\n </button>\n )}\n </div>\n </Card>\n )}\n </motion.div>\n )}\n\n {activeTab === 'settings' && (\n <motion.div\n key=\"settings\"\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -8 }}\n transition={{ duration: 0.2 }}\n >\n <div className=\"space-y-4\">\n {canUpdateComponent && (\n <Card padding=\"lg\">\n <h3 className=\"font-semibold text-text-primary mb-4\">\n {tr('component.editComponent', 'Edit Component')}\n </h3>\n <button\n type=\"button\"\n onClick={() => setShowEditForm(true)}\n className=\"px-4 py-2 bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg-hover transition-colors\"\n >\n {tr('component.editDetails', 'Edit Details')}\n </button>\n </Card>\n )}\n {canDeleteComponent && (\n <Card padding=\"lg\">\n <h3 className=\"font-semibold text-status-error-text mb-2\">\n {tr('component.dangerZone', 'Danger Zone')}\n </h3>\n <p className=\"text-sm text-text-secondary mb-4\">\n {tr(\n 'component.deleteWarning',\n 'Deleting this component will remove it from all catalogs and break any templates derived from it. This cannot be undone.'\n )}\n </p>\n <button\n type=\"button\"\n data-testid=\"component-delete-button\"\n onClick={() => setShowDeleteConfirm(true)}\n className=\"inline-flex items-center gap-2 px-4 py-2 bg-status-error-bg text-status-error-text rounded-md hover:opacity-90 transition-opacity\"\n >\n <Trash2 className=\"size-4\" aria-hidden=\"true\" />\n {tr('component.deleteComponent', 'Delete Component')}\n </button>\n </Card>\n )}\n </div>\n </motion.div>\n )}\n </AnimatePresence>\n\n {/* Edit Form */}\n {canUpdateComponent && (\n <ComponentForm\n isOpen={showEditForm}\n onClose={() => setShowEditForm(false)}\n onSubmit={handleUpdateComponent}\n initialData={{\n name: component.name,\n description: component.description || '',\n type: component.type,\n lifecycle: component.lifecycle,\n language: component.language || '',\n framework: component.framework || '',\n version: component.version || '',\n ownerName: component.ownerName || '',\n tags: component.tags || [],\n repositoryUrl: component.repositoryUrl || '',\n documentationUrl: component.documentationUrl || '',\n dependencies: Array.isArray(component.dependencies) ? component.dependencies : null,\n sbomData:\n component.sbomData && typeof component.sbomData === 'object'\n ? (component.sbomData as Record<string, unknown>)\n : null,\n }}\n title={tr('component.editComponent', 'Edit Component')}\n />\n )}\n\n <ConfirmDialog\n isOpen={showDeleteConfirm}\n onClose={() => setShowDeleteConfirm(false)}\n onConfirm={handleDeleteComponent}\n title={tr('component.deleteComponent', 'Delete Component')}\n message={tr(\n 'component.deleteConfirmMessage',\n `Are you sure you want to delete \"${component.name}\"? This action cannot be undone.`\n )}\n confirmLabel={tr('common.delete', 'Delete')}\n variant=\"danger\"\n isLoading={isDeleting}\n />\n\n <QuotaExhaustedDialog\n isOpen={showQuotaExhausted}\n onClose={() => setShowQuotaExhausted(false)}\n onConfirm={() => {\n setShowQuotaExhausted(false);\n navigate('/billing/plans');\n }}\n title=\"Template Quota Reached\"\n message=\"You've reached the maximum number of published templates on your current plan. Upgrade your plan or purchase an add-on to publish more templates.\"\n />\n\n {showPublishForm && canCreateTemplate && (\n <PublishTemplateForm\n componentName={component.name}\n componentRepositoryUrl={component.repositoryUrl}\n onClose={() => setShowPublishForm(false)}\n onSubmit={handlePublishAsTemplate}\n />\n )}\n\n {showAddToCatalog && canUseCatalogPicker && (\n <div\n className=\"fixed inset-0 flex items-center justify-center z-50 p-4\"\n style={{ backgroundColor: 'rgba(0,0,0,0.55)' }}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n className=\"bg-bg-surface rounded-lg w-full max-w-md shadow-xl\"\n >\n <div className=\"flex items-center justify-between px-4 py-3 border-b border-border-default\">\n <h2 className=\"text-base font-semibold text-text-primary\">\n {tr('component.addToCatalog', 'Add to Catalog')}\n </h2>\n <button\n type=\"button\"\n onClick={() => setShowAddToCatalog(false)}\n className=\"p-1.5 text-text-secondary hover:text-text-primary rounded-md hover:bg-bg-sunken transition-colors\"\n >\n <X className=\"size-4\" />\n </button>\n </div>\n <div className=\"p-2 max-h-80 overflow-y-auto\">\n {(catalogsData?.vibecontrolsCatalogs?.items ?? []).length === 0 ? (\n <p className=\"text-sm text-text-secondary text-center py-6\">\n No catalogs found.{' '}\n <button\n type=\"button\"\n onClick={() => {\n setShowAddToCatalog(false);\n navigate('/catalogs');\n }}\n className=\"text-action-primary-bg hover:underline\"\n >\n Create one first.\n </button>\n </p>\n ) : (\n (catalogsData?.vibecontrolsCatalogs?.items ?? []).map(\n (cat: { id: string; name: string }) => {\n const alreadyIn = catalogs.some((c) => c.id === cat.id);\n return (\n <button\n type=\"button\"\n key={cat.id}\n disabled={alreadyIn}\n onClick={async () => {\n if (!id || alreadyIn) return;\n try {\n await addToCatalog({\n variables: { catalogId: cat.id, componentId: id },\n });\n setShowAddToCatalog(false);\n setSuccessMessage(`Added to ${cat.name}`);\n setTimeout(() => setSuccessMessage(null), 3000);\n } catch {\n // error shown by Apollo\n }\n }}\n className={`flex items-center justify-between w-full px-3 py-2.5 text-left rounded-md transition-colors ${\n alreadyIn\n ? 'opacity-40 cursor-not-allowed'\n : 'hover:bg-bg-sunken cursor-pointer'\n }`}\n >\n <div className=\"flex items-center gap-2\">\n <BookOpen className=\"size-4 text-action-primary-bg flex-shrink-0\" />\n <span className=\"text-sm text-text-primary\">{cat.name}</span>\n </div>\n {alreadyIn && (\n <span className=\"text-xs text-text-muted\">already added</span>\n )}\n </button>\n );\n }\n )\n )}\n </div>\n </motion.div>\n </div>\n )}\n </MotionPage>\n );\n}\n"],"mappings":"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"}
@@ -163,12 +163,12 @@ function D() {
163
163
  module_installed: g
164
164
  }[e] || g, { className: "size-4" }), ce = (e) => ({
165
165
  green: "bg-status-success-bg-subtle text-status-success-text",
166
- blue: "bg-[var(--color-accent-soft)] text-action-primary-bg",
167
- purple: "bg-accent-purple-subtle text-accent-purple",
166
+ blue: "bg-[var(--color-accent-soft)] text-text-primary",
167
+ purple: "bg-accent-purple-subtle text-text-primary",
168
168
  orange: "bg-status-warning-bg-subtle text-status-warning-text",
169
169
  cyan: "bg-accent-teal-subtle text-accent-teal",
170
170
  yellow: "bg-status-warning-bg-subtle text-status-warning-text",
171
- pink: "bg-accent-purple-subtle text-accent-purple"
171
+ pink: "bg-accent-purple-subtle text-text-primary"
172
172
  })[e] || "bg-bg-sunken text-text-secondary";
173
173
  return /* @__PURE__ */ C(E, {
174
174
  className: "space-y-6 px-6 lg:px-8 py-6 bg-bg-canvas min-h-screen",
@@ -258,7 +258,7 @@ function D() {
258
258
  children: [/* @__PURE__ */ C("h2", {
259
259
  className: "text-lg font-semibold tracking-tight text-text-primary flex items-center gap-2.5",
260
260
  children: [/* @__PURE__ */ S("span", {
261
- className: "inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-action-primary-bg",
261
+ className: "inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary",
262
262
  children: /* @__PURE__ */ S(_, { className: "size-5" })
263
263
  }), A("overviewPage.sections.activeAgents", "Active Agents")]
264
264
  }), /* @__PURE__ */ S("button", {
@@ -279,7 +279,7 @@ function D() {
279
279
  className: "flex flex-1 flex-col items-center justify-center text-center py-8 text-text-secondary",
280
280
  children: [
281
281
  /* @__PURE__ */ S("span", {
282
- className: "inline-flex size-12 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-action-primary-bg mb-3",
282
+ className: "inline-flex size-12 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-text-primary mb-3",
283
283
  children: /* @__PURE__ */ S(_, { className: "size-6" })
284
284
  }),
285
285
  /* @__PURE__ */ S("p", {
@@ -323,7 +323,7 @@ function D() {
323
323
  children: [/* @__PURE__ */ C("h2", {
324
324
  className: "text-lg font-semibold tracking-tight text-text-primary flex items-center gap-2.5",
325
325
  children: [/* @__PURE__ */ S("span", {
326
- className: "inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-action-primary-bg",
326
+ className: "inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary",
327
327
  children: /* @__PURE__ */ S(g, { className: "size-5" })
328
328
  }), A("overviewPage.sections.recentActivity", "Recent Activity")]
329
329
  }), /* @__PURE__ */ S("button", {
@@ -379,7 +379,7 @@ function D() {
379
379
  children: [/* @__PURE__ */ C("h2", {
380
380
  className: "text-lg font-semibold tracking-tight text-text-primary flex items-center gap-2.5",
381
381
  children: [/* @__PURE__ */ S("span", {
382
- className: "inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-action-primary-bg",
382
+ className: "inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary",
383
383
  children: /* @__PURE__ */ S(y, { className: "size-5" })
384
384
  }), A("overviewPage.sections.runningSessions", "Running Sessions")]
385
385
  }), /* @__PURE__ */ S("button", {
@@ -399,7 +399,7 @@ function D() {
399
399
  className: "flex flex-col items-center text-center py-10 text-text-secondary",
400
400
  children: [
401
401
  /* @__PURE__ */ S("span", {
402
- className: "inline-flex size-12 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-action-primary-bg mb-3",
402
+ className: "inline-flex size-12 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-text-primary mb-3",
403
403
  children: /* @__PURE__ */ S(y, { className: "size-6" })
404
404
  }),
405
405
  /* @__PURE__ */ S("p", {
@@ -419,7 +419,7 @@ function D() {
419
419
  children: [/* @__PURE__ */ C("h2", {
420
420
  className: "text-lg font-semibold tracking-tight text-text-primary flex items-center gap-2.5",
421
421
  children: [/* @__PURE__ */ S("span", {
422
- className: "inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-action-primary-bg",
422
+ className: "inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary",
423
423
  children: /* @__PURE__ */ S(b, { className: "size-5" })
424
424
  }), A("overviewPage.sections.activeVibes", "Active Vibes")]
425
425
  }), /* @__PURE__ */ S("button", {
@@ -439,7 +439,7 @@ function D() {
439
439
  className: "flex flex-col items-center text-center py-10 text-text-secondary",
440
440
  children: [
441
441
  /* @__PURE__ */ S("span", {
442
- className: "inline-flex size-12 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-action-primary-bg mb-3",
442
+ className: "inline-flex size-12 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-text-primary mb-3",
443
443
  children: /* @__PURE__ */ S(b, { className: "size-6" })
444
444
  }),
445
445
  /* @__PURE__ */ S("p", {
@@ -1 +1 @@
1
- {"version":3,"file":"OverviewPage.js","names":[],"sources":["../../src/pages/OverviewPage.tsx"],"sourcesContent":["import { useCallback, useMemo } from 'react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport {\n Bot,\n Zap,\n Terminal,\n FileText,\n Activity,\n Server,\n Play,\n GitBranch,\n RefreshCw,\n} from 'lucide-react';\nimport { MotionPage, MotionList, MotionItem } from '@burdenoff/fe-libs/shared/motion';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { AgentCard } from '@/components/agents';\nimport { SessionCard } from '@/components/sessions';\nimport { VibeCard } from '@/components/vibes';\nimport {\n PageHeader,\n StatCard,\n Card,\n AgentSetupBanner,\n ErrorState,\n LoadingState,\n} from '@/components/shared';\nimport { useVibeNavigate, useVibeControls } from '@/providers/VibeControlsProvider';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport { useListTargetsQuery } from '@/generated/wspace-operations';\nimport type { Vibe } from '@/components/vibes/types';\nimport type { Session } from '@/components/sessions/types';\n\n/**\n * Overview page showing summary dashboard with stats, active resources, and recent activity\n *\n * This page now uses cached initial data from Apollo instead of independent queries,\n * reducing GraphQL calls from 5 to 0 for the initial render.\n * The refresh button triggers a refetch of the initial data.\n */\nexport function OverviewPage() {\n const handleNavigate = useVibeNavigate();\n const { t } = useI18n();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n\n const tr = (key: string, fallback: string, params?: Record<string, string | number>): string => {\n const translated = t(key, params);\n const template = translated === key ? fallback : translated;\n\n if (!params) return template;\n\n return Object.entries(params).reduce(\n (acc, [paramKey, paramValue]) => acc.replace(`{{${paramKey}}}`, String(paramValue)),\n template\n );\n };\n\n // Use cached initial data - reads from Apollo cache, no network request\n // Loading state reflects whether initial data has been loaded\n const {\n agents: cachedAgents,\n vibes: cachedVibes,\n sessions: cachedSessions,\n loading,\n error: dataError,\n totals,\n refetch,\n } = useCachedInitialData();\n\n // Targets is intentionally NOT part of VibeControlsInitialData (it caused a 25s\n // timeout there), so fetch the count with a lightweight standalone query — the\n // same pattern HealthPage uses.\n const { workspaceId } = useVibeControls();\n const targetsCountQuery = useListTargetsQuery({\n variables: { workspaceId: workspaceId || '', limit: 50 },\n skip: !workspaceId,\n fetchPolicy: 'cache-and-network',\n });\n\n const refetchTargets = targetsCountQuery.refetch;\n // The header Refresh button must refetch BOTH the cached initial data and the\n // standalone targets query — otherwise the Targets stat card stays stale after\n // a manual refresh.\n const handleRefresh = useCallback(() => {\n void refetch();\n void refetchTargets();\n }, [refetch, refetchTargets]);\n\n const targetItems: Array<{ status: string }> = targetsCountQuery.data?.targets.items ?? [];\n const targetsTotal = targetsCountQuery.data?.targets.total ?? 0;\n // `targetsConnected` is derived from `targetItems`, which is capped by the\n // query `limit`. When the workspace has more targets than the page size the\n // connected count would only reflect the first page and contradict the\n // server-side `targetsTotal`. Track truncation so we only surface the\n // connected detail when it is accurate for the full set.\n const targetsTruncated = targetsTotal > targetItems.length;\n const targetsConnected = targetItems.filter(\n (t) => t.status === 'connected' || t.status === 'active'\n ).length;\n\n if (dataError) {\n console.error('[overview] failed to load initial workspace data', dataError);\n }\n\n // Map cached data to component types\n // Using type assertion since we know the structure from the GraphQL query\n const agents = useMemo(() => {\n return cachedAgents.map((agent) => ({\n id: agent.id,\n workspaceId: '',\n name: agent.name,\n hostname: agent.hostname,\n platform: agent.platform,\n architecture: agent.architecture || '',\n version: agent.version || '',\n isActive: agent.isActive,\n status: agent.isActive ? ('ACTIVE' as const) : ('OFFLINE' as const),\n lastHeartbeat: agent.lastHeartbeat || null,\n tunnelUrl: agent.tunnelUrl ?? null,\n tunnelStatus: agent.tunnelStatus ?? null,\n agentApiKey: null,\n aiContext: null,\n configuration: {},\n capabilities: [],\n metadata: {},\n createdAt: agent.createdAt || '',\n updatedAt: '',\n }));\n }, [cachedAgents]);\n\n const vibes = useMemo(() => {\n return cachedVibes.map((vibe) => ({\n id: vibe.id,\n workspaceId: '',\n name: vibe.name,\n description: '',\n type: (vibe.type || 'PROJECT') as Vibe['type'],\n status: vibe.status as Vibe['status'],\n path: '',\n parentId: null,\n gitBranch: null,\n gitRemote: null,\n gitStatus: null,\n environmentVariables: {},\n tags: [],\n metadata: {},\n createdAt: '',\n updatedAt: '',\n archivedAt: null,\n // Multi-agent: surface attached agents so Overview cards can render a\n // count badge (\"+N agents\") or single name. Empty when none.\n agents: vibe.agents ?? [],\n }));\n }, [cachedVibes]);\n\n const sessions: Session[] = useMemo(() => {\n return cachedSessions.map((session) => ({\n id: session.id,\n workspaceId: '',\n agentId: session.agentId ?? null,\n vibeId: session.vibeId ?? null,\n name: session.name,\n type: (session.type || 'TERMINAL') as Session['type'],\n status: session.status as Session['status'],\n command: null,\n workingDirectory: null,\n environmentVariables: {},\n autoStart: false,\n pid: null,\n exitCode: null,\n lastOutput: null,\n metadata: {},\n createdAt: session.createdAt || '',\n updatedAt: '',\n agent: undefined,\n vibe: undefined,\n }));\n }, [cachedSessions]);\n\n // Calculate stats from cached totals\n const activeAgents = agents.filter((a) => a.isActive);\n const runningSessions = sessions.filter((s) => s.status === 'RUNNING');\n const activeVibes = vibes.filter((v) => v.status === 'ACTIVE');\n\n const stats = {\n agents: {\n total: totals.agents,\n active: activeAgents.length,\n offline: agents.filter((a) => !a.isActive).length,\n },\n vibes: {\n total: totals.vibes,\n active: activeVibes.length,\n archived: vibes.filter((v) => v.status === 'ARCHIVED').length,\n },\n sessions: {\n total: totals.sessions,\n running: runningSessions.length,\n stopped: sessions.filter((s) => s.status === 'STOPPED').length,\n },\n };\n\n // Recent activity - derive from session/agent data (simplified for now)\n const recentActivity = useMemo(() => {\n const activities: Array<{\n id: string;\n type: string;\n title: string;\n description: string;\n timestamp: string;\n color: string;\n }> = [];\n\n // Add recent sessions as activity\n sessions.slice(0, 3).forEach((session) => {\n activities.push({\n id: `session-${session.id}`,\n type: 'session_started',\n title:\n session.status === 'RUNNING'\n ? tr('overviewPage.activity.sessionRunning', 'Session Running')\n : tr('overviewPage.activity.sessionStatus', 'Session {{status}}', {\n status: session.status.toLowerCase(),\n }),\n description: `${session.name}`,\n timestamp: session.createdAt,\n color: session.status === 'RUNNING' ? 'green' : 'blue',\n });\n });\n\n // Add active agents as activity\n activeAgents.slice(0, 2).forEach((agent) => {\n activities.push({\n id: `agent-${agent.id}`,\n type: 'agent_connected',\n title: tr('overviewPage.activity.agentOnline', 'Agent Online'),\n description: tr('overviewPage.activity.agentOnlineDescription', '{{name}} is active', {\n name: agent.name,\n }),\n timestamp: agent.lastHeartbeat || agent.updatedAt,\n color: 'blue',\n });\n });\n\n // Sort by timestamp descending\n return activities\n .sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())\n .slice(0, 6);\n }, [sessions, activeAgents]);\n\n if (\n permissionsLoading ||\n (loading &&\n cachedAgents.length === 0 &&\n cachedVibes.length === 0 &&\n cachedSessions.length === 0)\n )\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <LoadingState message={tr('overviewPage.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n if (!hasPermission(VIBE_PERMISSIONS.VIBE_LIST))\n return (\n <div className=\"flex items-center justify-center min-h-[400px] px-4\">\n <div className=\"text-center space-y-2 max-w-sm\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary\">\n {tr('common.accessDeniedTitle', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'overviewPage.accessDeniedDescription',\n \"You don't have permission to access this page.\"\n )}\n </p>\n </div>\n </div>\n );\n\n const formatTimestamp = (timestamp: string) => {\n if (!timestamp) return tr('overviewPage.time.unknown', 'Unknown');\n const diff = Date.now() - new Date(timestamp).getTime();\n if (diff < 60000) return tr('overviewPage.time.justNow', 'Just now');\n if (diff < 3600000) {\n return tr('overviewPage.time.minutesAgo', '{{count}}m ago', {\n count: Math.floor(diff / 60000),\n });\n }\n if (diff < 86400000) {\n return tr('overviewPage.time.hoursAgo', '{{count}}h ago', {\n count: Math.floor(diff / 3600000),\n });\n }\n return tr('overviewPage.time.daysAgo', '{{count}}d ago', {\n count: Math.floor(diff / 86400000),\n });\n };\n\n const getActivityIcon = (type: string) => {\n const icons: Record<string, typeof Activity> = {\n session_started: Play,\n agent_connected: Server,\n vibe_updated: GitBranch,\n note_created: FileText,\n module_installed: Activity,\n };\n const Icon = icons[type] || Activity;\n return <Icon className=\"size-4\" />;\n };\n\n const getActivityColor = (color: string) => {\n const colors: Record<string, string> = {\n green: 'bg-status-success-bg-subtle text-status-success-text',\n blue: 'bg-[var(--color-accent-soft)] text-action-primary-bg',\n purple: 'bg-accent-purple-subtle text-accent-purple',\n orange: 'bg-status-warning-bg-subtle text-status-warning-text',\n cyan: 'bg-accent-teal-subtle text-accent-teal',\n yellow: 'bg-status-warning-bg-subtle text-status-warning-text',\n pink: 'bg-accent-purple-subtle text-accent-purple',\n };\n return colors[color] || 'bg-bg-sunken text-text-secondary';\n };\n\n return (\n <MotionPage className=\"space-y-6 px-6 lg:px-8 py-6 bg-bg-canvas min-h-screen\">\n <PageHeader\n title={tr('overviewPage.title', 'VibeControls Overview')}\n description={tr(\n 'overviewPage.description',\n 'Monitor and manage your development environments'\n )}\n actions={\n <button\n type=\"button\"\n onClick={handleRefresh}\n disabled={loading}\n className=\"inline-flex items-center gap-2 px-3 py-2 text-sm bg-bg-surface border border-border-subtle rounded-button text-text-primary hover:bg-bg-sunken hover:border-border-strong transition-all duration-200 disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus\"\n >\n <RefreshCw className={`size-4 ${loading ? 'animate-spin' : ''}`} aria-hidden=\"true\" />\n {tr('overviewPage.refresh', 'Refresh')}\n </button>\n }\n />\n\n {/* Friendly fallback when the initial workspace load fails — keeps the\n page header / refresh button rendered above so the user can recover\n without a hard reload. */}\n {dataError && !loading && (\n <ErrorState\n title={tr('overviewPage.loadFailed.title', 'Could not load workspace data')}\n message={tr(\n 'overviewPage.loadFailed.message',\n \"We couldn't load your VibeControls overview. Please try again in a moment.\"\n )}\n onRetry={handleRefresh}\n />\n )}\n\n {/* Agent CLI Setup Banner — shown when no agents exist */}\n {!dataError && agents.length === 0 && !loading && (\n <AgentSetupBanner variant=\"full\" dismissKey=\"vibecontrols-overview-setup-banner\" />\n )}\n\n {/* Stats Grid */}\n <MotionList\n data-tour=\"overview-stats\"\n className=\"grid grid-cols-2 sm:grid-cols-4 gap-4\"\n stagger={0.06}\n >\n <MotionItem variant=\"fadeScale\">\n <StatCard\n title={tr('overviewPage.stats.targets', 'Targets')}\n value={loading ? '-' : targetsTotal}\n subtitle={\n loading || targetsTruncated\n ? ''\n : tr('overviewPage.stats.connected', '{{count}} connected', {\n count: targetsConnected,\n })\n }\n icon={<Server className=\"size-6\" />}\n variant={!loading && targetsTotal > 0 ? 'success' : 'default'}\n onClick={() => handleNavigate('/targets')}\n />\n </MotionItem>\n <MotionItem variant=\"fadeScale\">\n <StatCard\n title={tr('overviewPage.stats.agents', 'Agents')}\n value={loading ? '-' : stats.agents.total}\n subtitle={\n loading\n ? ''\n : tr('overviewPage.stats.active', '{{count}} active', {\n count: stats.agents.active,\n })\n }\n icon={<Bot className=\"size-6\" />}\n variant={!loading && stats.agents.active > 0 ? 'success' : 'default'}\n onClick={() => handleNavigate('/agents')}\n />\n </MotionItem>\n <MotionItem variant=\"fadeScale\">\n <StatCard\n title={tr('overviewPage.stats.vibes', 'Vibes')}\n value={loading ? '-' : stats.vibes.total}\n subtitle={\n loading\n ? ''\n : tr('overviewPage.stats.active', '{{count}} active', {\n count: stats.vibes.active,\n })\n }\n icon={<Zap className=\"size-6\" />}\n onClick={() => handleNavigate('/vibes')}\n />\n </MotionItem>\n <MotionItem variant=\"fadeScale\">\n <StatCard\n title={tr('overviewPage.stats.sessions', 'Sessions')}\n value={loading ? '-' : stats.sessions.total}\n subtitle={\n loading\n ? ''\n : tr('overviewPage.stats.running', '{{count}} running', {\n count: stats.sessions.running,\n })\n }\n icon={<Terminal className=\"size-6\" />}\n variant={!loading && stats.sessions.running > 0 ? 'success' : 'default'}\n onClick={() => handleNavigate('/sessions')}\n />\n </MotionItem>\n </MotionList>\n\n {/* Main Content Grid */}\n <MotionList className=\"grid grid-cols-1 gap-6 xl:grid-cols-3\" stagger={0.08}>\n {/* Active Agents */}\n <MotionItem className=\"xl:col-span-2 h-full\">\n <Card className=\"flex h-full flex-col\">\n <div className=\"flex items-center justify-between mb-5\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary flex items-center gap-2.5\">\n <span className=\"inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-action-primary-bg\">\n <Bot className=\"size-5\" />\n </span>\n {tr('overviewPage.sections.activeAgents', 'Active Agents')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/agents')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n aria-label={tr('overviewPage.sections.viewAllAgents', 'View all agents')}\n >\n {tr('overviewPage.sections.viewAll', 'View all')}\n </button>\n </div>\n {activeAgents.length > 0 ? (\n <MotionList\n className=\"grid grid-cols-1 sm:grid-cols-2 gap-4 flex-1 content-start\"\n stagger={0.04}\n >\n {activeAgents.slice(0, 4).map((agent) => (\n <MotionItem key={agent.id}>\n <AgentCard agent={agent} onSelect={(a) => handleNavigate(`/agents/${a.id}`)} />\n </MotionItem>\n ))}\n </MotionList>\n ) : (\n <div className=\"flex flex-1 flex-col items-center justify-center text-center py-8 text-text-secondary\">\n <span className=\"inline-flex size-12 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-action-primary-bg mb-3\">\n <Bot className=\"size-6\" />\n </span>\n <p className=\"text-base font-semibold text-text-primary\">\n {tr('overviewPage.empty.noActiveAgents', 'No active agents')}\n </p>\n <p className=\"text-xs text-text-muted mt-1 mb-4\">\n {tr('overviewPage.empty.installCliHint', 'Install the agent CLI to get started')}\n </p>\n <div className=\"flex flex-wrap items-center justify-center gap-2\">\n <button\n type=\"button\"\n onClick={() => handleNavigate('/getting-started')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n >\n {tr('overviewPage.empty.setupGuide', 'Setup guide')}\n </button>\n <span className=\"text-text-muted\">&middot;</span>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/agents')}\n className=\"text-sm text-text-link hover:underline\"\n >\n {tr('overviewPage.empty.addAgent', 'Add agent')}\n </button>\n </div>\n </div>\n )}\n </Card>\n </MotionItem>\n\n {/* Recent Activity */}\n <MotionItem className=\"h-full\">\n <Card className=\"flex h-full flex-col\">\n <div className=\"flex items-center justify-between mb-5\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary flex items-center gap-2.5\">\n <span className=\"inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-action-primary-bg\">\n <Activity className=\"size-5\" />\n </span>\n {tr('overviewPage.sections.recentActivity', 'Recent Activity')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/audit')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n aria-label={tr('overviewPage.sections.viewAllActivity', 'View all activity')}\n >\n View all\n </button>\n </div>\n <MotionList className=\"space-y-3 flex-1\" stagger={0.04}>\n {recentActivity.length > 0 ? (\n recentActivity.map((activity) => (\n <MotionItem key={activity.id} variant=\"fadeRight\">\n <div className=\"flex items-start gap-3\">\n <div\n className={`flex-shrink-0 size-8 rounded-full flex items-center justify-center ${getActivityColor(activity.color)}`}\n >\n {getActivityIcon(activity.type)}\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">\n {activity.title}\n </p>\n <p className=\"text-xs text-text-secondary truncate\">\n {activity.description}\n </p>\n </div>\n <span className=\"text-xs text-text-secondary flex-shrink-0\">\n {formatTimestamp(activity.timestamp)}\n </span>\n </div>\n </MotionItem>\n ))\n ) : (\n <div className=\"flex h-full flex-col items-center justify-center text-center py-4 text-text-secondary text-sm\">\n <p>{tr('overviewPage.empty.noRecentActivity', 'No recent activity')}</p>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/audit')}\n className=\"mt-2 text-sm text-text-link hover:underline\"\n >\n {tr('overviewPage.empty.viewAuditLog', 'View audit log')}\n </button>\n </div>\n )}\n </MotionList>\n </Card>\n </MotionItem>\n </MotionList>\n\n {/* Running Sessions */}\n <MotionItem>\n <Card>\n <div className=\"flex items-center justify-between mb-5\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary flex items-center gap-2.5\">\n <span className=\"inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-action-primary-bg\">\n <Terminal className=\"size-5\" />\n </span>\n {tr('overviewPage.sections.runningSessions', 'Running Sessions')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/sessions')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n >\n {tr('overviewPage.sections.viewAll', 'View all')}\n </button>\n </div>\n {runningSessions.length > 0 ? (\n <MotionList\n className=\"grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-4\"\n stagger={0.04}\n >\n {runningSessions.slice(0, 6).map((session) => (\n <MotionItem key={session.id}>\n <SessionCard\n session={session}\n onOpen={(s) => handleNavigate(`/sessions/${s.id}`)}\n />\n </MotionItem>\n ))}\n </MotionList>\n ) : (\n <div className=\"flex flex-col items-center text-center py-10 text-text-secondary\">\n <span className=\"inline-flex size-12 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-action-primary-bg mb-3\">\n <Terminal className=\"size-6\" />\n </span>\n <p className=\"text-base font-semibold text-text-primary\">\n {tr('overviewPage.empty.noRunningSessions', 'No running sessions')}\n </p>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/sessions')}\n className=\"mt-3 text-sm font-medium text-text-link hover:underline\"\n >\n {tr('overviewPage.empty.startSession', 'Start a session')}\n </button>\n </div>\n )}\n </Card>\n </MotionItem>\n\n {/* Active Vibes */}\n <MotionItem>\n <Card>\n <div className=\"flex items-center justify-between mb-5\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary flex items-center gap-2.5\">\n <span className=\"inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-action-primary-bg\">\n <Zap className=\"size-5\" />\n </span>\n {tr('overviewPage.sections.activeVibes', 'Active Vibes')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/vibes')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n >\n {tr('overviewPage.sections.viewAll', 'View all')}\n </button>\n </div>\n {activeVibes.length > 0 ? (\n <MotionList\n className=\"grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-4\"\n stagger={0.04}\n >\n {activeVibes.slice(0, 6).map((vibe) => (\n <MotionItem key={vibe.id}>\n <VibeCard vibe={vibe} onOpen={(v) => handleNavigate(`/vibes/${v.id}`)} />\n </MotionItem>\n ))}\n </MotionList>\n ) : (\n <div className=\"flex flex-col items-center text-center py-10 text-text-secondary\">\n <span className=\"inline-flex size-12 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-action-primary-bg mb-3\">\n <Zap className=\"size-6\" />\n </span>\n <p className=\"text-base font-semibold text-text-primary\">\n {tr('overviewPage.empty.noActiveVibes', 'No active vibes')}\n </p>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/vibes')}\n className=\"mt-3 text-sm font-medium text-text-link hover:underline\"\n >\n {tr('overviewPage.empty.addVibe', 'Add a vibe')}\n </button>\n </div>\n )}\n </Card>\n </MotionItem>\n </MotionPage>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"OverviewPage.js","names":[],"sources":["../../src/pages/OverviewPage.tsx"],"sourcesContent":["import { useCallback, useMemo } from 'react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport {\n Bot,\n Zap,\n Terminal,\n FileText,\n Activity,\n Server,\n Play,\n GitBranch,\n RefreshCw,\n} from 'lucide-react';\nimport { MotionPage, MotionList, MotionItem } from '@burdenoff/fe-libs/shared/motion';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { AgentCard } from '@/components/agents';\nimport { SessionCard } from '@/components/sessions';\nimport { VibeCard } from '@/components/vibes';\nimport {\n PageHeader,\n StatCard,\n Card,\n AgentSetupBanner,\n ErrorState,\n LoadingState,\n} from '@/components/shared';\nimport { useVibeNavigate, useVibeControls } from '@/providers/VibeControlsProvider';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\nimport { useListTargetsQuery } from '@/generated/wspace-operations';\nimport type { Vibe } from '@/components/vibes/types';\nimport type { Session } from '@/components/sessions/types';\n\n/**\n * Overview page showing summary dashboard with stats, active resources, and recent activity\n *\n * This page now uses cached initial data from Apollo instead of independent queries,\n * reducing GraphQL calls from 5 to 0 for the initial render.\n * The refresh button triggers a refetch of the initial data.\n */\nexport function OverviewPage() {\n const handleNavigate = useVibeNavigate();\n const { t } = useI18n();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n\n const tr = (key: string, fallback: string, params?: Record<string, string | number>): string => {\n const translated = t(key, params);\n const template = translated === key ? fallback : translated;\n\n if (!params) return template;\n\n return Object.entries(params).reduce(\n (acc, [paramKey, paramValue]) => acc.replace(`{{${paramKey}}}`, String(paramValue)),\n template\n );\n };\n\n // Use cached initial data - reads from Apollo cache, no network request\n // Loading state reflects whether initial data has been loaded\n const {\n agents: cachedAgents,\n vibes: cachedVibes,\n sessions: cachedSessions,\n loading,\n error: dataError,\n totals,\n refetch,\n } = useCachedInitialData();\n\n // Targets is intentionally NOT part of VibeControlsInitialData (it caused a 25s\n // timeout there), so fetch the count with a lightweight standalone query — the\n // same pattern HealthPage uses.\n const { workspaceId } = useVibeControls();\n const targetsCountQuery = useListTargetsQuery({\n variables: { workspaceId: workspaceId || '', limit: 50 },\n skip: !workspaceId,\n fetchPolicy: 'cache-and-network',\n });\n\n const refetchTargets = targetsCountQuery.refetch;\n // The header Refresh button must refetch BOTH the cached initial data and the\n // standalone targets query — otherwise the Targets stat card stays stale after\n // a manual refresh.\n const handleRefresh = useCallback(() => {\n void refetch();\n void refetchTargets();\n }, [refetch, refetchTargets]);\n\n const targetItems: Array<{ status: string }> = targetsCountQuery.data?.targets.items ?? [];\n const targetsTotal = targetsCountQuery.data?.targets.total ?? 0;\n // `targetsConnected` is derived from `targetItems`, which is capped by the\n // query `limit`. When the workspace has more targets than the page size the\n // connected count would only reflect the first page and contradict the\n // server-side `targetsTotal`. Track truncation so we only surface the\n // connected detail when it is accurate for the full set.\n const targetsTruncated = targetsTotal > targetItems.length;\n const targetsConnected = targetItems.filter(\n (t) => t.status === 'connected' || t.status === 'active'\n ).length;\n\n if (dataError) {\n console.error('[overview] failed to load initial workspace data', dataError);\n }\n\n // Map cached data to component types\n // Using type assertion since we know the structure from the GraphQL query\n const agents = useMemo(() => {\n return cachedAgents.map((agent) => ({\n id: agent.id,\n workspaceId: '',\n name: agent.name,\n hostname: agent.hostname,\n platform: agent.platform,\n architecture: agent.architecture || '',\n version: agent.version || '',\n isActive: agent.isActive,\n status: agent.isActive ? ('ACTIVE' as const) : ('OFFLINE' as const),\n lastHeartbeat: agent.lastHeartbeat || null,\n tunnelUrl: agent.tunnelUrl ?? null,\n tunnelStatus: agent.tunnelStatus ?? null,\n agentApiKey: null,\n aiContext: null,\n configuration: {},\n capabilities: [],\n metadata: {},\n createdAt: agent.createdAt || '',\n updatedAt: '',\n }));\n }, [cachedAgents]);\n\n const vibes = useMemo(() => {\n return cachedVibes.map((vibe) => ({\n id: vibe.id,\n workspaceId: '',\n name: vibe.name,\n description: '',\n type: (vibe.type || 'PROJECT') as Vibe['type'],\n status: vibe.status as Vibe['status'],\n path: '',\n parentId: null,\n gitBranch: null,\n gitRemote: null,\n gitStatus: null,\n environmentVariables: {},\n tags: [],\n metadata: {},\n createdAt: '',\n updatedAt: '',\n archivedAt: null,\n // Multi-agent: surface attached agents so Overview cards can render a\n // count badge (\"+N agents\") or single name. Empty when none.\n agents: vibe.agents ?? [],\n }));\n }, [cachedVibes]);\n\n const sessions: Session[] = useMemo(() => {\n return cachedSessions.map((session) => ({\n id: session.id,\n workspaceId: '',\n agentId: session.agentId ?? null,\n vibeId: session.vibeId ?? null,\n name: session.name,\n type: (session.type || 'TERMINAL') as Session['type'],\n status: session.status as Session['status'],\n command: null,\n workingDirectory: null,\n environmentVariables: {},\n autoStart: false,\n pid: null,\n exitCode: null,\n lastOutput: null,\n metadata: {},\n createdAt: session.createdAt || '',\n updatedAt: '',\n agent: undefined,\n vibe: undefined,\n }));\n }, [cachedSessions]);\n\n // Calculate stats from cached totals\n const activeAgents = agents.filter((a) => a.isActive);\n const runningSessions = sessions.filter((s) => s.status === 'RUNNING');\n const activeVibes = vibes.filter((v) => v.status === 'ACTIVE');\n\n const stats = {\n agents: {\n total: totals.agents,\n active: activeAgents.length,\n offline: agents.filter((a) => !a.isActive).length,\n },\n vibes: {\n total: totals.vibes,\n active: activeVibes.length,\n archived: vibes.filter((v) => v.status === 'ARCHIVED').length,\n },\n sessions: {\n total: totals.sessions,\n running: runningSessions.length,\n stopped: sessions.filter((s) => s.status === 'STOPPED').length,\n },\n };\n\n // Recent activity - derive from session/agent data (simplified for now)\n const recentActivity = useMemo(() => {\n const activities: Array<{\n id: string;\n type: string;\n title: string;\n description: string;\n timestamp: string;\n color: string;\n }> = [];\n\n // Add recent sessions as activity\n sessions.slice(0, 3).forEach((session) => {\n activities.push({\n id: `session-${session.id}`,\n type: 'session_started',\n title:\n session.status === 'RUNNING'\n ? tr('overviewPage.activity.sessionRunning', 'Session Running')\n : tr('overviewPage.activity.sessionStatus', 'Session {{status}}', {\n status: session.status.toLowerCase(),\n }),\n description: `${session.name}`,\n timestamp: session.createdAt,\n color: session.status === 'RUNNING' ? 'green' : 'blue',\n });\n });\n\n // Add active agents as activity\n activeAgents.slice(0, 2).forEach((agent) => {\n activities.push({\n id: `agent-${agent.id}`,\n type: 'agent_connected',\n title: tr('overviewPage.activity.agentOnline', 'Agent Online'),\n description: tr('overviewPage.activity.agentOnlineDescription', '{{name}} is active', {\n name: agent.name,\n }),\n timestamp: agent.lastHeartbeat || agent.updatedAt,\n color: 'blue',\n });\n });\n\n // Sort by timestamp descending\n return activities\n .sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())\n .slice(0, 6);\n }, [sessions, activeAgents]);\n\n if (\n permissionsLoading ||\n (loading &&\n cachedAgents.length === 0 &&\n cachedVibes.length === 0 &&\n cachedSessions.length === 0)\n )\n return (\n <div className=\"flex items-center justify-center min-h-[400px]\">\n <LoadingState message={tr('overviewPage.loadingPermissions', 'Loading permissions...')} />\n </div>\n );\n if (!hasPermission(VIBE_PERMISSIONS.VIBE_LIST))\n return (\n <div className=\"flex items-center justify-center min-h-[400px] px-4\">\n <div className=\"text-center space-y-2 max-w-sm\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary\">\n {tr('common.accessDeniedTitle', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'overviewPage.accessDeniedDescription',\n \"You don't have permission to access this page.\"\n )}\n </p>\n </div>\n </div>\n );\n\n const formatTimestamp = (timestamp: string) => {\n if (!timestamp) return tr('overviewPage.time.unknown', 'Unknown');\n const diff = Date.now() - new Date(timestamp).getTime();\n if (diff < 60000) return tr('overviewPage.time.justNow', 'Just now');\n if (diff < 3600000) {\n return tr('overviewPage.time.minutesAgo', '{{count}}m ago', {\n count: Math.floor(diff / 60000),\n });\n }\n if (diff < 86400000) {\n return tr('overviewPage.time.hoursAgo', '{{count}}h ago', {\n count: Math.floor(diff / 3600000),\n });\n }\n return tr('overviewPage.time.daysAgo', '{{count}}d ago', {\n count: Math.floor(diff / 86400000),\n });\n };\n\n const getActivityIcon = (type: string) => {\n const icons: Record<string, typeof Activity> = {\n session_started: Play,\n agent_connected: Server,\n vibe_updated: GitBranch,\n note_created: FileText,\n module_installed: Activity,\n };\n const Icon = icons[type] || Activity;\n return <Icon className=\"size-4\" />;\n };\n\n const getActivityColor = (color: string) => {\n const colors: Record<string, string> = {\n green: 'bg-status-success-bg-subtle text-status-success-text',\n blue: 'bg-[var(--color-accent-soft)] text-text-primary',\n purple: 'bg-accent-purple-subtle text-text-primary',\n orange: 'bg-status-warning-bg-subtle text-status-warning-text',\n cyan: 'bg-accent-teal-subtle text-accent-teal',\n yellow: 'bg-status-warning-bg-subtle text-status-warning-text',\n pink: 'bg-accent-purple-subtle text-text-primary',\n };\n return colors[color] || 'bg-bg-sunken text-text-secondary';\n };\n\n return (\n <MotionPage className=\"space-y-6 px-6 lg:px-8 py-6 bg-bg-canvas min-h-screen\">\n <PageHeader\n title={tr('overviewPage.title', 'VibeControls Overview')}\n description={tr(\n 'overviewPage.description',\n 'Monitor and manage your development environments'\n )}\n actions={\n <button\n type=\"button\"\n onClick={handleRefresh}\n disabled={loading}\n className=\"inline-flex items-center gap-2 px-3 py-2 text-sm bg-bg-surface border border-border-subtle rounded-button text-text-primary hover:bg-bg-sunken hover:border-border-strong transition-all duration-200 disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus\"\n >\n <RefreshCw className={`size-4 ${loading ? 'animate-spin' : ''}`} aria-hidden=\"true\" />\n {tr('overviewPage.refresh', 'Refresh')}\n </button>\n }\n />\n\n {/* Friendly fallback when the initial workspace load fails — keeps the\n page header / refresh button rendered above so the user can recover\n without a hard reload. */}\n {dataError && !loading && (\n <ErrorState\n title={tr('overviewPage.loadFailed.title', 'Could not load workspace data')}\n message={tr(\n 'overviewPage.loadFailed.message',\n \"We couldn't load your VibeControls overview. Please try again in a moment.\"\n )}\n onRetry={handleRefresh}\n />\n )}\n\n {/* Agent CLI Setup Banner — shown when no agents exist */}\n {!dataError && agents.length === 0 && !loading && (\n <AgentSetupBanner variant=\"full\" dismissKey=\"vibecontrols-overview-setup-banner\" />\n )}\n\n {/* Stats Grid */}\n <MotionList\n data-tour=\"overview-stats\"\n className=\"grid grid-cols-2 sm:grid-cols-4 gap-4\"\n stagger={0.06}\n >\n <MotionItem variant=\"fadeScale\">\n <StatCard\n title={tr('overviewPage.stats.targets', 'Targets')}\n value={loading ? '-' : targetsTotal}\n subtitle={\n loading || targetsTruncated\n ? ''\n : tr('overviewPage.stats.connected', '{{count}} connected', {\n count: targetsConnected,\n })\n }\n icon={<Server className=\"size-6\" />}\n variant={!loading && targetsTotal > 0 ? 'success' : 'default'}\n onClick={() => handleNavigate('/targets')}\n />\n </MotionItem>\n <MotionItem variant=\"fadeScale\">\n <StatCard\n title={tr('overviewPage.stats.agents', 'Agents')}\n value={loading ? '-' : stats.agents.total}\n subtitle={\n loading\n ? ''\n : tr('overviewPage.stats.active', '{{count}} active', {\n count: stats.agents.active,\n })\n }\n icon={<Bot className=\"size-6\" />}\n variant={!loading && stats.agents.active > 0 ? 'success' : 'default'}\n onClick={() => handleNavigate('/agents')}\n />\n </MotionItem>\n <MotionItem variant=\"fadeScale\">\n <StatCard\n title={tr('overviewPage.stats.vibes', 'Vibes')}\n value={loading ? '-' : stats.vibes.total}\n subtitle={\n loading\n ? ''\n : tr('overviewPage.stats.active', '{{count}} active', {\n count: stats.vibes.active,\n })\n }\n icon={<Zap className=\"size-6\" />}\n onClick={() => handleNavigate('/vibes')}\n />\n </MotionItem>\n <MotionItem variant=\"fadeScale\">\n <StatCard\n title={tr('overviewPage.stats.sessions', 'Sessions')}\n value={loading ? '-' : stats.sessions.total}\n subtitle={\n loading\n ? ''\n : tr('overviewPage.stats.running', '{{count}} running', {\n count: stats.sessions.running,\n })\n }\n icon={<Terminal className=\"size-6\" />}\n variant={!loading && stats.sessions.running > 0 ? 'success' : 'default'}\n onClick={() => handleNavigate('/sessions')}\n />\n </MotionItem>\n </MotionList>\n\n {/* Main Content Grid */}\n <MotionList className=\"grid grid-cols-1 gap-6 xl:grid-cols-3\" stagger={0.08}>\n {/* Active Agents */}\n <MotionItem className=\"xl:col-span-2 h-full\">\n <Card className=\"flex h-full flex-col\">\n <div className=\"flex items-center justify-between mb-5\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary flex items-center gap-2.5\">\n <span className=\"inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n <Bot className=\"size-5\" />\n </span>\n {tr('overviewPage.sections.activeAgents', 'Active Agents')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/agents')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n aria-label={tr('overviewPage.sections.viewAllAgents', 'View all agents')}\n >\n {tr('overviewPage.sections.viewAll', 'View all')}\n </button>\n </div>\n {activeAgents.length > 0 ? (\n <MotionList\n className=\"grid grid-cols-1 sm:grid-cols-2 gap-4 flex-1 content-start\"\n stagger={0.04}\n >\n {activeAgents.slice(0, 4).map((agent) => (\n <MotionItem key={agent.id}>\n <AgentCard agent={agent} onSelect={(a) => handleNavigate(`/agents/${a.id}`)} />\n </MotionItem>\n ))}\n </MotionList>\n ) : (\n <div className=\"flex flex-1 flex-col items-center justify-center text-center py-8 text-text-secondary\">\n <span className=\"inline-flex size-12 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-text-primary mb-3\">\n <Bot className=\"size-6\" />\n </span>\n <p className=\"text-base font-semibold text-text-primary\">\n {tr('overviewPage.empty.noActiveAgents', 'No active agents')}\n </p>\n <p className=\"text-xs text-text-muted mt-1 mb-4\">\n {tr('overviewPage.empty.installCliHint', 'Install the agent CLI to get started')}\n </p>\n <div className=\"flex flex-wrap items-center justify-center gap-2\">\n <button\n type=\"button\"\n onClick={() => handleNavigate('/getting-started')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n >\n {tr('overviewPage.empty.setupGuide', 'Setup guide')}\n </button>\n <span className=\"text-text-muted\">&middot;</span>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/agents')}\n className=\"text-sm text-text-link hover:underline\"\n >\n {tr('overviewPage.empty.addAgent', 'Add agent')}\n </button>\n </div>\n </div>\n )}\n </Card>\n </MotionItem>\n\n {/* Recent Activity */}\n <MotionItem className=\"h-full\">\n <Card className=\"flex h-full flex-col\">\n <div className=\"flex items-center justify-between mb-5\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary flex items-center gap-2.5\">\n <span className=\"inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n <Activity className=\"size-5\" />\n </span>\n {tr('overviewPage.sections.recentActivity', 'Recent Activity')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/audit')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n aria-label={tr('overviewPage.sections.viewAllActivity', 'View all activity')}\n >\n View all\n </button>\n </div>\n <MotionList className=\"space-y-3 flex-1\" stagger={0.04}>\n {recentActivity.length > 0 ? (\n recentActivity.map((activity) => (\n <MotionItem key={activity.id} variant=\"fadeRight\">\n <div className=\"flex items-start gap-3\">\n <div\n className={`flex-shrink-0 size-8 rounded-full flex items-center justify-center ${getActivityColor(activity.color)}`}\n >\n {getActivityIcon(activity.type)}\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">\n {activity.title}\n </p>\n <p className=\"text-xs text-text-secondary truncate\">\n {activity.description}\n </p>\n </div>\n <span className=\"text-xs text-text-secondary flex-shrink-0\">\n {formatTimestamp(activity.timestamp)}\n </span>\n </div>\n </MotionItem>\n ))\n ) : (\n <div className=\"flex h-full flex-col items-center justify-center text-center py-4 text-text-secondary text-sm\">\n <p>{tr('overviewPage.empty.noRecentActivity', 'No recent activity')}</p>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/audit')}\n className=\"mt-2 text-sm text-text-link hover:underline\"\n >\n {tr('overviewPage.empty.viewAuditLog', 'View audit log')}\n </button>\n </div>\n )}\n </MotionList>\n </Card>\n </MotionItem>\n </MotionList>\n\n {/* Running Sessions */}\n <MotionItem>\n <Card>\n <div className=\"flex items-center justify-between mb-5\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary flex items-center gap-2.5\">\n <span className=\"inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n <Terminal className=\"size-5\" />\n </span>\n {tr('overviewPage.sections.runningSessions', 'Running Sessions')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/sessions')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n >\n {tr('overviewPage.sections.viewAll', 'View all')}\n </button>\n </div>\n {runningSessions.length > 0 ? (\n <MotionList\n className=\"grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-4\"\n stagger={0.04}\n >\n {runningSessions.slice(0, 6).map((session) => (\n <MotionItem key={session.id}>\n <SessionCard\n session={session}\n onOpen={(s) => handleNavigate(`/sessions/${s.id}`)}\n />\n </MotionItem>\n ))}\n </MotionList>\n ) : (\n <div className=\"flex flex-col items-center text-center py-10 text-text-secondary\">\n <span className=\"inline-flex size-12 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-text-primary mb-3\">\n <Terminal className=\"size-6\" />\n </span>\n <p className=\"text-base font-semibold text-text-primary\">\n {tr('overviewPage.empty.noRunningSessions', 'No running sessions')}\n </p>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/sessions')}\n className=\"mt-3 text-sm font-medium text-text-link hover:underline\"\n >\n {tr('overviewPage.empty.startSession', 'Start a session')}\n </button>\n </div>\n )}\n </Card>\n </MotionItem>\n\n {/* Active Vibes */}\n <MotionItem>\n <Card>\n <div className=\"flex items-center justify-between mb-5\">\n <h2 className=\"text-lg font-semibold tracking-tight text-text-primary flex items-center gap-2.5\">\n <span className=\"inline-flex size-8 items-center justify-center rounded-lg bg-[var(--color-accent-soft)] text-text-primary\">\n <Zap className=\"size-5\" />\n </span>\n {tr('overviewPage.sections.activeVibes', 'Active Vibes')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/vibes')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n >\n {tr('overviewPage.sections.viewAll', 'View all')}\n </button>\n </div>\n {activeVibes.length > 0 ? (\n <MotionList\n className=\"grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-3 gap-4\"\n stagger={0.04}\n >\n {activeVibes.slice(0, 6).map((vibe) => (\n <MotionItem key={vibe.id}>\n <VibeCard vibe={vibe} onOpen={(v) => handleNavigate(`/vibes/${v.id}`)} />\n </MotionItem>\n ))}\n </MotionList>\n ) : (\n <div className=\"flex flex-col items-center text-center py-10 text-text-secondary\">\n <span className=\"inline-flex size-12 items-center justify-center rounded-full bg-[var(--color-accent-soft)] text-text-primary mb-3\">\n <Zap className=\"size-6\" />\n </span>\n <p className=\"text-base font-semibold text-text-primary\">\n {tr('overviewPage.empty.noActiveVibes', 'No active vibes')}\n </p>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/vibes')}\n className=\"mt-3 text-sm font-medium text-text-link hover:underline\"\n >\n {tr('overviewPage.empty.addVibe', 'Add a vibe')}\n </button>\n </div>\n )}\n </Card>\n </MotionItem>\n </MotionPage>\n );\n}\n"],"mappings":"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"}
@@ -88,7 +88,7 @@ function v(e) {
88
88
  }
89
89
  function y(e) {
90
90
  switch (e) {
91
- case "Meta": return "bg-accent-purple-subtle text-accent-purple border-accent-purple/30";
91
+ case "Meta": return "bg-accent-purple-subtle text-text-primary border-accent-purple/30";
92
92
  case "Provider": return "bg-status-info-bg text-status-info-text border-status-info-border";
93
93
  default: return "bg-bg-sunken text-text-secondary border-border-default";
94
94
  }