@burdenoff/microfe-vibecontrols 2026.528.6 → 2026.528.8

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 (42) hide show
  1. package/dist/VibeControlsRoot.js +90 -81
  2. package/dist/VibeControlsRoot.js.map +1 -1
  3. package/dist/VibeControlsRoutes.js +144 -140
  4. package/dist/VibeControlsRoutes.js.map +1 -1
  5. package/dist/components/audit/AuditLogFilters.js +71 -47
  6. package/dist/components/audit/AuditLogFilters.js.map +1 -1
  7. package/dist/components/shared/AgentSetupBanner.js +50 -45
  8. package/dist/components/shared/AgentSetupBanner.js.map +1 -1
  9. package/dist/components/shared/LinkToVibePanel.js +97 -0
  10. package/dist/components/shared/LinkToVibePanel.js.map +1 -0
  11. package/dist/components/shared/index.js +1 -0
  12. package/dist/components/templates/TemplateWizard.js +2 -2
  13. package/dist/components/templates/TemplateWizard.js.map +1 -1
  14. package/dist/components/vibe/VibeLinkedEntitiesPanel.js +60 -0
  15. package/dist/components/vibe/VibeLinkedEntitiesPanel.js.map +1 -0
  16. package/dist/components/vibedeck/VibeDeckButtonTile.js +25 -23
  17. package/dist/components/vibedeck/VibeDeckButtonTile.js.map +1 -1
  18. package/dist/components/vibedeck/VibeDeckGrid.js +2 -2
  19. package/dist/components/vibedeck/VibeDeckGrid.js.map +1 -1
  20. package/dist/constants/pluginCatalog.js +1 -1
  21. package/dist/microfe-vibecontrols.css +1 -1
  22. package/dist/pages/AgentDetailsPage.js +2 -2
  23. package/dist/pages/AgentDetailsPage.js.map +1 -1
  24. package/dist/pages/AnalyticsPage.js +255 -204
  25. package/dist/pages/AnalyticsPage.js.map +1 -1
  26. package/dist/pages/OverviewPage.js +1 -11
  27. package/dist/pages/OverviewPage.js.map +1 -1
  28. package/dist/pages/PluginsCatalogPage.js +287 -0
  29. package/dist/pages/PluginsCatalogPage.js.map +1 -0
  30. package/dist/pages/SessionsPage.js +825 -629
  31. package/dist/pages/SessionsPage.js.map +1 -1
  32. package/dist/pages/VibeAuditPage.js +184 -153
  33. package/dist/pages/VibeAuditPage.js.map +1 -1
  34. package/dist/pages/VibeCalendarPage.js +132 -107
  35. package/dist/pages/VibeCalendarPage.js.map +1 -1
  36. package/dist/pages/VibeDeckPage.js +416 -379
  37. package/dist/pages/VibeDeckPage.js.map +1 -1
  38. package/dist/pages/VibeDetailsPage.js +621 -557
  39. package/dist/pages/VibeDetailsPage.js.map +1 -1
  40. package/dist/pages/tunnels/TunnelsTab.js +115 -90
  41. package/dist/pages/tunnels/TunnelsTab.js.map +1 -1
  42. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"AnalyticsPage.js","names":[],"sources":["../../src/pages/AnalyticsPage.tsx"],"sourcesContent":["import { lazy, Suspense, useCallback, useMemo, useState } from 'react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { PageHeader } from '@/components/shared';\nimport { SkeletonLine } from '@/components/shared/PageSkeleton';\nimport {\n AnalyticsBreakdownTable,\n AnalyticsEntityTabs,\n AnalyticsFilterBar,\n AnalyticsKpiGrid,\n SandboxAnalyticsSection,\n getAnalyticsTabConfig,\n getDateRange,\n} from '@/components/analytics';\n\n// Recharts is ~150KB+ gzipped and only mounts on the Analytics page once\n// the user lands on it. Lazy-load both chart components so the recharts\n// bundle is excluded from the initial page-load chunk.\nconst AnalyticsTimeSeriesChart = lazy(() =>\n import('@/components/analytics/AnalyticsTimeSeriesChart').then((m) => ({\n default: m.AnalyticsTimeSeriesChart,\n }))\n);\nconst AnalyticsBreakdownChart = lazy(() =>\n import('@/components/analytics/AnalyticsBreakdownChart').then((m) => ({\n default: m.AnalyticsBreakdownChart,\n }))\n);\n\nconst ChartFallback = () => (\n <div className=\"bg-bg-surface border border-border-default rounded-lg p-4\">\n <SkeletonLine height=\"h-40\" />\n </div>\n);\nimport type { EntityTab, Granularity, TimeRange } from '@/components/analytics';\nimport { useVibecontrolsAnalyticsQuery } from '@/generated/wspace-operations';\nimport { useVibeControls, useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useQueryBackedTab } from '@/hooks/useQueryBackedTab';\n\nconst ANALYTICS_TABS: readonly EntityTab[] = [\n 'overview',\n 'agents',\n 'sessions',\n 'sandbox',\n 'vibes',\n 'actions',\n 'vibedecks',\n 'aievents',\n 'audit',\n 'docs',\n];\n\nconst ANALYTICS_SERIES_COLORS = {\n primary: 'var(--color-text-link)',\n success: 'var(--color-status-success-text)',\n accent: 'var(--color-accent-purple)',\n warning: 'var(--color-status-warning-text)',\n} as const;\n\nexport function AnalyticsPage() {\n const { workspaceId } = useVibeControls();\n const { t } = useI18n();\n const navigate = useVibeNavigate();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const [timeRange, setTimeRange] = useState<TimeRange>('LAST_7D');\n const [granularity, setGranularity] = useState<Granularity>('DAY');\n const [activeTab, setActiveTab] = useQueryBackedTab<EntityTab>(ANALYTICS_TABS, 'overview');\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 { startDate, endDate } = useMemo(() => getDateRange(timeRange), [timeRange]);\n const activeTabConfig = useMemo(() => getAnalyticsTabConfig(activeTab), [activeTab]);\n\n const { data, loading, error, refetch } = useVibecontrolsAnalyticsQuery({\n variables: {\n input: {\n startDate: startDate.toISOString(),\n endDate: endDate.toISOString(),\n granularity,\n entityTypes: activeTabConfig.entityTypes,\n },\n },\n fetchPolicy: 'cache-first',\n nextFetchPolicy: 'cache-first',\n notifyOnNetworkStatusChange: true,\n skip: !workspaceId,\n });\n\n const analytics = data?.vibecontrolsAnalytics;\n\n const handleRefresh = useCallback(() => {\n void refetch();\n }, [refetch]);\n\n const handleCardClick = useCallback(\n (href: string) => {\n navigate(href);\n },\n [navigate]\n );\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 (!hasPermission(VIBE_PERMISSIONS.ANALYTICS_READ))\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-foreground\">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 if (!workspaceId) {\n return (\n <MotionPage className=\"min-h-screen space-y-6 bg-bg-surface p-4 sm:p-6\">\n <PageHeader title={tr('nav.analytics', 'Analytics')} />\n <div className=\"text-sm text-text-secondary\">Waiting for workspace context…</div>\n </MotionPage>\n );\n }\n\n if (error && !analytics) {\n return (\n <MotionPage className=\"min-h-screen space-y-6 bg-bg-surface p-4 sm:p-6\">\n <PageHeader title={tr('nav.analytics', 'Analytics')} />\n <div className=\"space-y-3 rounded-lg border border-status-error-border bg-status-error-bg/10 p-4 text-sm text-status-error-text\">\n <p>Failed to load analytics: {error.message}</p>\n <button\n type=\"button\"\n onClick={handleRefresh}\n className=\"rounded-md bg-status-error-bg/20 px-3 py-1.5 text-xs font-medium transition-colors hover:bg-status-error-bg/30\"\n >\n Retry\n </button>\n </div>\n </MotionPage>\n );\n }\n\n return (\n <MotionPage className=\"min-h-screen space-y-4 bg-bg-surface p-4 sm:p-6\">\n <PageHeader title={tr('nav.analytics', 'Analytics')} />\n\n <AnalyticsFilterBar\n timeRange={timeRange}\n granularity={granularity}\n onTimeRangeChange={setTimeRange}\n onGranularityChange={setGranularity}\n onRefresh={handleRefresh}\n loading={loading}\n executionTimeMs={analytics?.executionTimeMs}\n cached={analytics?.cached}\n />\n\n <AnalyticsEntityTabs activeTab={activeTab} onTabChange={setActiveTab} />\n\n <Suspense fallback={<ChartFallback />}>\n <section\n id={`analytics-panel-${activeTab}`}\n role=\"tabpanel\"\n aria-labelledby={`analytics-tab-${activeTab}`}\n className=\"space-y-4\"\n >\n {activeTab === 'overview' ? (\n <div className=\"space-y-4\">\n <AnalyticsKpiGrid data={analytics} loading={loading} onCardClick={handleCardClick} />\n\n <AnalyticsTimeSeriesChart\n title=\"Activity Over Time\"\n datasets={[\n {\n label: 'Sessions',\n data: analytics?.sessions?.createdOverTime,\n color: ANALYTICS_SERIES_COLORS.primary,\n },\n {\n label: 'Executions',\n data: analytics?.actions?.executionsOverTime,\n color: ANALYTICS_SERIES_COLORS.success,\n },\n {\n label: 'AI Events',\n data: analytics?.aiEvents?.eventsOverTime,\n color: ANALYTICS_SERIES_COLORS.accent,\n },\n {\n label: 'Audit Logs',\n data: analytics?.audit?.eventsOverTime,\n color: ANALYTICS_SERIES_COLORS.warning,\n },\n ]}\n />\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownChart\n title=\"Sessions by Status\"\n data={analytics?.sessions?.byStatus}\n />\n <AnalyticsBreakdownChart\n title=\"Vibes by Status\"\n data={analytics?.vibes?.byStatus}\n />\n </div>\n </div>\n ) : null}\n\n {activeTab === 'agents' && analytics?.agents ? (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <KpiCard label=\"Total\" value={analytics.agents.total} />\n <KpiCard label=\"Active\" value={analytics.agents.active} variant=\"success\" />\n <KpiCard label=\"Inactive\" value={analytics.agents.inactive} variant=\"warning\" />\n <KpiCard\n label=\"Stale Heartbeat\"\n value={analytics.agents.staleHeartbeatCount}\n variant=\"error\"\n />\n </div>\n\n <AnalyticsTimeSeriesChart\n title=\"Agents Created Over Time\"\n datasets={[\n {\n label: 'Agents',\n data: analytics.agents.createdOverTime,\n color: ANALYTICS_SERIES_COLORS.primary,\n },\n ]}\n height={250}\n />\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownTable\n title=\"By Platform\"\n data={analytics.agents.byPlatform}\n keyLabel=\"Platform\"\n />\n <AnalyticsBreakdownTable\n title=\"By Architecture\"\n data={analytics.agents.byArchitecture}\n keyLabel=\"Architecture\"\n />\n </div>\n </div>\n ) : null}\n\n {activeTab === 'sessions' && analytics?.sessions ? (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <KpiCard label=\"Total\" value={analytics.sessions.total} />\n <KpiCard label=\"Running\" value={analytics.sessions.active} variant=\"success\" />\n <KpiCard label=\"Collaborators\" value={analytics.sessions.totalCollaborators} />\n <KpiCard\n label=\"Shares\"\n value={analytics.sessions.totalShares + analytics.sessions.totalShareLinks}\n />\n </div>\n\n {analytics.sessions.avgDurationMs != null ? (\n <div className=\"text-sm text-text-secondary\">\n Average duration:{' '}\n <span className=\"font-medium text-text-primary\">\n {formatDuration(analytics.sessions.avgDurationMs)}\n </span>\n </div>\n ) : null}\n\n <AnalyticsTimeSeriesChart\n title=\"Sessions Created Over Time\"\n datasets={[\n {\n label: 'Sessions',\n data: analytics.sessions.createdOverTime,\n color: ANALYTICS_SERIES_COLORS.primary,\n },\n ]}\n height={250}\n />\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownChart\n title=\"Sessions by Type\"\n data={analytics.sessions.byType}\n />\n <AnalyticsBreakdownTable\n title=\"Sessions by Status\"\n data={analytics.sessions.byStatus}\n keyLabel=\"Status\"\n />\n </div>\n </div>\n ) : null}\n\n {activeTab === 'sandbox' ? <SandboxAnalyticsSection /> : null}\n\n {activeTab === 'vibes' && analytics?.vibes ? (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <KpiCard label=\"Total\" value={analytics.vibes.total} />\n <KpiCard label=\"With Agent\" value={analytics.vibes.withAgent} variant=\"success\" />\n <KpiCard label=\"Without Agent\" value={analytics.vibes.withoutAgent} />\n </div>\n\n <AnalyticsTimeSeriesChart\n title=\"Vibes Created Over Time\"\n datasets={[\n {\n label: 'Vibes',\n data: analytics.vibes.createdOverTime,\n color: ANALYTICS_SERIES_COLORS.accent,\n },\n ]}\n height={250}\n />\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownChart title=\"Vibes by Type\" data={analytics.vibes.byType} />\n <AnalyticsBreakdownChart title=\"Vibes by Status\" data={analytics.vibes.byStatus} />\n </div>\n </div>\n ) : null}\n\n {activeTab === 'actions' && analytics?.actions ? (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <KpiCard label=\"Total Actions\" value={analytics.actions.total} />\n <KpiCard label=\"Executions\" value={analytics.actions.totalExecutions} />\n <KpiCard\n label=\"Success Rate\"\n value={\n analytics.actions.successRate != null\n ? `${analytics.actions.successRate.toFixed(1)}%`\n : 'N/A'\n }\n variant={\n analytics.actions.successRate != null && analytics.actions.successRate >= 90\n ? 'success'\n : 'warning'\n }\n />\n <KpiCard\n label=\"Avg Duration\"\n value={\n analytics.actions.avgDurationMs != null\n ? formatDuration(analytics.actions.avgDurationMs)\n : 'N/A'\n }\n />\n </div>\n\n <AnalyticsTimeSeriesChart\n title=\"Executions Over Time\"\n datasets={[\n {\n label: 'Executions',\n data: analytics.actions.executionsOverTime,\n color: ANALYTICS_SERIES_COLORS.success,\n },\n ]}\n height={250}\n />\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownChart\n title=\"By Action Type\"\n data={analytics.actions.byActionType}\n />\n <AnalyticsBreakdownChart\n title=\"Execution Status\"\n data={analytics.actions.executionsByStatus}\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownTable\n title=\"By Trigger Type\"\n data={analytics.actions.byTriggerType}\n keyLabel=\"Trigger\"\n />\n <AnalyticsBreakdownTable\n title=\"By Source Type\"\n data={analytics.actions.bySourceType}\n keyLabel=\"Source\"\n />\n </div>\n </div>\n ) : null}\n\n {activeTab === 'vibedecks' && analytics?.vibeDecks ? (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3\">\n <KpiCard label=\"Decks\" value={analytics.vibeDecks.totalDecks} />\n <KpiCard label=\"Buttons\" value={analytics.vibeDecks.totalButtons} />\n </div>\n\n <AnalyticsBreakdownChart\n title=\"Buttons by Action Type\"\n data={analytics.vibeDecks.buttonsByActionType}\n />\n </div>\n ) : null}\n\n {activeTab === 'aievents' && analytics?.aiEvents ? (\n <div className=\"space-y-4\">\n <KpiCard label=\"Total AI Events\" value={analytics.aiEvents.total} />\n\n <AnalyticsTimeSeriesChart\n title=\"AI Events Over Time\"\n datasets={[\n {\n label: 'Events',\n data: analytics.aiEvents.eventsOverTime,\n color: ANALYTICS_SERIES_COLORS.accent,\n },\n ]}\n height={250}\n />\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownChart title=\"By Source\" data={analytics.aiEvents.bySource} />\n <AnalyticsBreakdownTable\n title=\"By Event Type\"\n data={analytics.aiEvents.byEventType}\n keyLabel=\"Event Type\"\n />\n </div>\n </div>\n ) : null}\n\n {activeTab === 'audit' && analytics?.audit ? (\n <div className=\"space-y-4\">\n <KpiCard label=\"Total Audit Logs\" value={analytics.audit.total} />\n\n <AnalyticsTimeSeriesChart\n title=\"Audit Events Over Time\"\n datasets={[\n {\n label: 'Events',\n data: analytics.audit.eventsOverTime,\n color: ANALYTICS_SERIES_COLORS.warning,\n },\n ]}\n height={250}\n />\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownChart title=\"By Action\" data={analytics.audit.byAction} />\n <AnalyticsBreakdownChart title=\"By Status\" data={analytics.audit.byStatus} />\n </div>\n\n <AnalyticsBreakdownTable\n title=\"By Resource Type\"\n data={analytics.audit.byResourceType}\n keyLabel=\"Resource\"\n />\n </div>\n ) : null}\n\n {activeTab === 'docs' && analytics?.docs ? (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <KpiCard label=\"Sites\" value={analytics.docs.totalSites} />\n <KpiCard label=\"Pages\" value={analytics.docs.totalPages} />\n <KpiCard label=\"Revisions\" value={analytics.docs.totalRevisions} />\n <KpiCard\n label=\"Build Success\"\n value={\n analytics.docs.buildSuccessRate != null\n ? `${analytics.docs.buildSuccessRate.toFixed(1)}%`\n : 'N/A'\n }\n variant={\n analytics.docs.buildSuccessRate != null && analytics.docs.buildSuccessRate >= 90\n ? 'success'\n : 'warning'\n }\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownChart\n title=\"Pages by Status\"\n data={analytics.docs.pagesByStatus}\n />\n <AnalyticsBreakdownChart\n title=\"Revisions by Status\"\n data={analytics.docs.revisionsByStatus}\n />\n </div>\n </div>\n ) : null}\n </section>\n </Suspense>\n </MotionPage>\n );\n}\n\nfunction KpiCard({\n label,\n value,\n variant,\n}: {\n label: string;\n value: number | string;\n variant?: 'success' | 'warning' | 'error';\n}) {\n const surfaceClass =\n variant === 'success'\n ? 'bg-status-success-bg/10'\n : variant === 'warning'\n ? 'bg-status-warning-bg/10'\n : variant === 'error'\n ? 'bg-status-error-bg/10'\n : 'bg-bg-surface';\n\n return (\n <div className={`${surfaceClass} rounded-lg border border-border-default p-3`}>\n <p className=\"text-xs text-text-secondary\">{label}</p>\n <p className=\"mt-1 text-xl font-bold text-text-primary\">\n {typeof value === 'number' ? value.toLocaleString() : value}\n </p>\n </div>\n );\n}\n\nfunction formatDuration(milliseconds: number): string {\n if (milliseconds < 1000) {\n return `${Math.round(milliseconds)}ms`;\n }\n\n if (milliseconds < 60000) {\n return `${(milliseconds / 1000).toFixed(1)}s`;\n }\n\n const minutes = Math.floor(milliseconds / 60000);\n const seconds = Math.round((milliseconds % 60000) / 1000);\n return `${minutes}m ${seconds}s`;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AnalyticsPage.js","names":[],"sources":["../../src/pages/AnalyticsPage.tsx"],"sourcesContent":["import { lazy, Suspense, useCallback, useMemo, useState } from 'react';\nimport { Download, Printer } from 'lucide-react';\nimport { usePermissions } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { VIBE_PERMISSIONS } from '../constants/permissions';\nimport { MotionPage } from '@burdenoff/fe-libs/shared/motion';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { PageHeader } from '@/components/shared';\nimport { SkeletonLine } from '@/components/shared/PageSkeleton';\nimport {\n AnalyticsBreakdownTable,\n AnalyticsEntityTabs,\n AnalyticsFilterBar,\n AnalyticsKpiGrid,\n SandboxAnalyticsSection,\n getAnalyticsTabConfig,\n getDateRange,\n} from '@/components/analytics';\n\n// Recharts is ~150KB+ gzipped and only mounts on the Analytics page once\n// the user lands on it. Lazy-load both chart components so the recharts\n// bundle is excluded from the initial page-load chunk.\nconst AnalyticsTimeSeriesChart = lazy(() =>\n import('@/components/analytics/AnalyticsTimeSeriesChart').then((m) => ({\n default: m.AnalyticsTimeSeriesChart,\n }))\n);\nconst AnalyticsBreakdownChart = lazy(() =>\n import('@/components/analytics/AnalyticsBreakdownChart').then((m) => ({\n default: m.AnalyticsBreakdownChart,\n }))\n);\n\nconst ChartFallback = () => (\n <div className=\"bg-bg-surface border border-border-default rounded-lg p-4\">\n <SkeletonLine height=\"h-40\" />\n </div>\n);\nimport type { EntityTab, Granularity, TimeRange } from '@/components/analytics';\nimport { useVibecontrolsAnalyticsQuery } from '@/generated/wspace-operations';\nimport { useVibeControls, useVibeNavigate } from '@/providers/VibeControlsProvider';\nimport { useQueryBackedTab } from '@/hooks/useQueryBackedTab';\n\nconst ANALYTICS_TABS: readonly EntityTab[] = [\n 'overview',\n 'agents',\n 'sessions',\n 'sandbox',\n 'vibes',\n 'actions',\n 'vibedecks',\n 'aievents',\n 'audit',\n 'docs',\n];\n\nconst ANALYTICS_SERIES_COLORS = {\n primary: 'var(--color-text-link)',\n success: 'var(--color-status-success-text)',\n accent: 'var(--color-accent-purple)',\n warning: 'var(--color-status-warning-text)',\n} as const;\n\nexport function AnalyticsPage() {\n const { workspaceId } = useVibeControls();\n const { t } = useI18n();\n const navigate = useVibeNavigate();\n const { hasPermission, isLoading: permissionsLoading } = usePermissions();\n const [timeRange, setTimeRange] = useState<TimeRange>('LAST_7D');\n const [granularity, setGranularity] = useState<Granularity>('DAY');\n const [activeTab, setActiveTab] = useQueryBackedTab<EntityTab>(ANALYTICS_TABS, 'overview');\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 { startDate, endDate } = useMemo(() => getDateRange(timeRange), [timeRange]);\n const activeTabConfig = useMemo(() => getAnalyticsTabConfig(activeTab), [activeTab]);\n\n const { data, loading, error, refetch } = useVibecontrolsAnalyticsQuery({\n variables: {\n input: {\n startDate: startDate.toISOString(),\n endDate: endDate.toISOString(),\n granularity,\n entityTypes: activeTabConfig.entityTypes,\n },\n },\n fetchPolicy: 'cache-first',\n nextFetchPolicy: 'cache-first',\n notifyOnNetworkStatusChange: true,\n skip: !workspaceId,\n });\n\n const analytics = data?.vibecontrolsAnalytics;\n\n const handleRefresh = useCallback(() => {\n void refetch();\n }, [refetch]);\n\n const handlePrint = useCallback(() => {\n if (typeof window !== 'undefined') window.print();\n }, []);\n\n const handleExportCsv = useCallback(() => {\n if (!analytics) return;\n const rows = buildCsvRowsForTab(activeTab, analytics);\n if (rows.length === 0) return;\n const csv = rowsToCsv(rows);\n const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n const stamp = new Date().toISOString().slice(0, 10);\n a.download = `vibecontrols-analytics-${activeTab}-${stamp}.csv`;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n URL.revokeObjectURL(url);\n }, [analytics, activeTab]);\n\n const handleCardClick = useCallback(\n (href: string) => {\n navigate(href);\n },\n [navigate]\n );\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 (!hasPermission(VIBE_PERMISSIONS.ANALYTICS_READ))\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-foreground\">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 if (!workspaceId) {\n return (\n <MotionPage className=\"min-h-screen space-y-6 bg-bg-surface p-4 sm:p-6\">\n <PageHeader title={tr('nav.analytics', 'Analytics')} />\n <div className=\"text-sm text-text-secondary\">Waiting for workspace context…</div>\n </MotionPage>\n );\n }\n\n if (error && !analytics) {\n return (\n <MotionPage className=\"min-h-screen space-y-6 bg-bg-surface p-4 sm:p-6\">\n <PageHeader title={tr('nav.analytics', 'Analytics')} />\n <div className=\"space-y-3 rounded-lg border border-status-error-border bg-status-error-bg/10 p-4 text-sm text-status-error-text\">\n <p>Failed to load analytics: {error.message}</p>\n <button\n type=\"button\"\n onClick={handleRefresh}\n className=\"rounded-md bg-status-error-bg/20 px-3 py-1.5 text-xs font-medium transition-colors hover:bg-status-error-bg/30\"\n >\n Retry\n </button>\n </div>\n </MotionPage>\n );\n }\n\n return (\n <MotionPage className=\"min-h-screen space-y-4 bg-bg-surface p-4 sm:p-6 vc-printable\">\n <PageHeader title={tr('nav.analytics', 'Analytics')} />\n\n <AnalyticsFilterBar\n timeRange={timeRange}\n granularity={granularity}\n onTimeRangeChange={setTimeRange}\n onGranularityChange={setGranularity}\n onRefresh={handleRefresh}\n loading={loading}\n executionTimeMs={analytics?.executionTimeMs}\n cached={analytics?.cached}\n />\n\n <AnalyticsEntityTabs activeTab={activeTab} onTabChange={setActiveTab} />\n\n {/* F11: Per-tab export + print toolbar. Hidden in print output via the\n `vc-print-hide` class. */}\n <div className=\"flex flex-wrap items-center justify-end gap-2 vc-print-hide\">\n <button\n type=\"button\"\n onClick={handleExportCsv}\n disabled={loading || !analytics}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-default px-3 py-1.5 text-sm font-medium text-text-primary hover:bg-bg-sunken transition-colors disabled:opacity-50 disabled:cursor-not-allowed\"\n title={tr('analytics.exportCsvTitle', 'Export current tab as CSV')}\n >\n <Download size={14} />\n {tr('analytics.exportCsv', 'Export CSV')}\n </button>\n <button\n type=\"button\"\n onClick={handlePrint}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-default px-3 py-1.5 text-sm font-medium text-text-primary hover:bg-bg-sunken transition-colors\"\n title={tr('analytics.printTitle', 'Print this report')}\n >\n <Printer size={14} />\n {tr('analytics.print', 'Print')}\n </button>\n {/* TODO(boff-analytics-png): wire PNG export once html-to-image\n or recharts svg-to-image helper is added to deps. */}\n </div>\n\n <Suspense fallback={<ChartFallback />}>\n <section\n id={`analytics-panel-${activeTab}`}\n role=\"tabpanel\"\n aria-labelledby={`analytics-tab-${activeTab}`}\n className=\"space-y-4\"\n >\n {activeTab === 'overview' ? (\n <div className=\"space-y-4\">\n <AnalyticsKpiGrid data={analytics} loading={loading} onCardClick={handleCardClick} />\n\n <AnalyticsTimeSeriesChart\n title=\"Activity Over Time\"\n datasets={[\n {\n label: 'Sessions',\n data: analytics?.sessions?.createdOverTime,\n color: ANALYTICS_SERIES_COLORS.primary,\n },\n {\n label: 'Executions',\n data: analytics?.actions?.executionsOverTime,\n color: ANALYTICS_SERIES_COLORS.success,\n },\n {\n label: 'AI Events',\n data: analytics?.aiEvents?.eventsOverTime,\n color: ANALYTICS_SERIES_COLORS.accent,\n },\n {\n label: 'Audit Logs',\n data: analytics?.audit?.eventsOverTime,\n color: ANALYTICS_SERIES_COLORS.warning,\n },\n ]}\n />\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownChart\n title=\"Sessions by Status\"\n data={analytics?.sessions?.byStatus}\n />\n <AnalyticsBreakdownChart\n title=\"Vibes by Status\"\n data={analytics?.vibes?.byStatus}\n />\n </div>\n </div>\n ) : null}\n\n {activeTab === 'agents' && analytics?.agents ? (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <KpiCard label=\"Total\" value={analytics.agents.total} />\n <KpiCard label=\"Active\" value={analytics.agents.active} variant=\"success\" />\n <KpiCard label=\"Inactive\" value={analytics.agents.inactive} variant=\"warning\" />\n <KpiCard\n label=\"Stale Heartbeat\"\n value={analytics.agents.staleHeartbeatCount}\n variant=\"error\"\n />\n </div>\n\n <AnalyticsTimeSeriesChart\n title=\"Agents Created Over Time\"\n datasets={[\n {\n label: 'Agents',\n data: analytics.agents.createdOverTime,\n color: ANALYTICS_SERIES_COLORS.primary,\n },\n ]}\n height={250}\n />\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownTable\n title=\"By Platform\"\n data={analytics.agents.byPlatform}\n keyLabel=\"Platform\"\n />\n <AnalyticsBreakdownTable\n title=\"By Architecture\"\n data={analytics.agents.byArchitecture}\n keyLabel=\"Architecture\"\n />\n </div>\n </div>\n ) : null}\n\n {activeTab === 'sessions' && analytics?.sessions ? (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <KpiCard label=\"Total\" value={analytics.sessions.total} />\n <KpiCard label=\"Running\" value={analytics.sessions.active} variant=\"success\" />\n <KpiCard label=\"Collaborators\" value={analytics.sessions.totalCollaborators} />\n <KpiCard\n label=\"Shares\"\n value={analytics.sessions.totalShares + analytics.sessions.totalShareLinks}\n />\n </div>\n\n {analytics.sessions.avgDurationMs != null ? (\n <div className=\"text-sm text-text-secondary\">\n Average duration:{' '}\n <span className=\"font-medium text-text-primary\">\n {formatDuration(analytics.sessions.avgDurationMs)}\n </span>\n </div>\n ) : null}\n\n <AnalyticsTimeSeriesChart\n title=\"Sessions Created Over Time\"\n datasets={[\n {\n label: 'Sessions',\n data: analytics.sessions.createdOverTime,\n color: ANALYTICS_SERIES_COLORS.primary,\n },\n ]}\n height={250}\n />\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownChart\n title=\"Sessions by Type\"\n data={analytics.sessions.byType}\n />\n <AnalyticsBreakdownTable\n title=\"Sessions by Status\"\n data={analytics.sessions.byStatus}\n keyLabel=\"Status\"\n />\n </div>\n </div>\n ) : null}\n\n {activeTab === 'sandbox' ? <SandboxAnalyticsSection /> : null}\n\n {activeTab === 'vibes' && analytics?.vibes ? (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <KpiCard label=\"Total\" value={analytics.vibes.total} />\n <KpiCard label=\"With Agent\" value={analytics.vibes.withAgent} variant=\"success\" />\n <KpiCard label=\"Without Agent\" value={analytics.vibes.withoutAgent} />\n </div>\n\n <AnalyticsTimeSeriesChart\n title=\"Vibes Created Over Time\"\n datasets={[\n {\n label: 'Vibes',\n data: analytics.vibes.createdOverTime,\n color: ANALYTICS_SERIES_COLORS.accent,\n },\n ]}\n height={250}\n />\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownChart title=\"Vibes by Type\" data={analytics.vibes.byType} />\n <AnalyticsBreakdownChart title=\"Vibes by Status\" data={analytics.vibes.byStatus} />\n </div>\n </div>\n ) : null}\n\n {activeTab === 'actions' && analytics?.actions ? (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <KpiCard label=\"Total Actions\" value={analytics.actions.total} />\n <KpiCard label=\"Executions\" value={analytics.actions.totalExecutions} />\n <KpiCard\n label=\"Success Rate\"\n value={\n analytics.actions.successRate != null\n ? `${analytics.actions.successRate.toFixed(1)}%`\n : 'N/A'\n }\n variant={\n analytics.actions.successRate != null && analytics.actions.successRate >= 90\n ? 'success'\n : 'warning'\n }\n />\n <KpiCard\n label=\"Avg Duration\"\n value={\n analytics.actions.avgDurationMs != null\n ? formatDuration(analytics.actions.avgDurationMs)\n : 'N/A'\n }\n />\n </div>\n\n <AnalyticsTimeSeriesChart\n title=\"Executions Over Time\"\n datasets={[\n {\n label: 'Executions',\n data: analytics.actions.executionsOverTime,\n color: ANALYTICS_SERIES_COLORS.success,\n },\n ]}\n height={250}\n />\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownChart\n title=\"By Action Type\"\n data={analytics.actions.byActionType}\n />\n <AnalyticsBreakdownChart\n title=\"Execution Status\"\n data={analytics.actions.executionsByStatus}\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownTable\n title=\"By Trigger Type\"\n data={analytics.actions.byTriggerType}\n keyLabel=\"Trigger\"\n />\n <AnalyticsBreakdownTable\n title=\"By Source Type\"\n data={analytics.actions.bySourceType}\n keyLabel=\"Source\"\n />\n </div>\n </div>\n ) : null}\n\n {activeTab === 'vibedecks' && analytics?.vibeDecks ? (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-3\">\n <KpiCard label=\"Decks\" value={analytics.vibeDecks.totalDecks} />\n <KpiCard label=\"Buttons\" value={analytics.vibeDecks.totalButtons} />\n </div>\n\n <AnalyticsBreakdownChart\n title=\"Buttons by Action Type\"\n data={analytics.vibeDecks.buttonsByActionType}\n />\n </div>\n ) : null}\n\n {activeTab === 'aievents' && analytics?.aiEvents ? (\n <div className=\"space-y-4\">\n <KpiCard label=\"Total AI Events\" value={analytics.aiEvents.total} />\n\n <AnalyticsTimeSeriesChart\n title=\"AI Events Over Time\"\n datasets={[\n {\n label: 'Events',\n data: analytics.aiEvents.eventsOverTime,\n color: ANALYTICS_SERIES_COLORS.accent,\n },\n ]}\n height={250}\n />\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownChart title=\"By Source\" data={analytics.aiEvents.bySource} />\n <AnalyticsBreakdownTable\n title=\"By Event Type\"\n data={analytics.aiEvents.byEventType}\n keyLabel=\"Event Type\"\n />\n </div>\n </div>\n ) : null}\n\n {activeTab === 'audit' && analytics?.audit ? (\n <div className=\"space-y-4\">\n <KpiCard label=\"Total Audit Logs\" value={analytics.audit.total} />\n\n <AnalyticsTimeSeriesChart\n title=\"Audit Events Over Time\"\n datasets={[\n {\n label: 'Events',\n data: analytics.audit.eventsOverTime,\n color: ANALYTICS_SERIES_COLORS.warning,\n },\n ]}\n height={250}\n />\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownChart title=\"By Action\" data={analytics.audit.byAction} />\n <AnalyticsBreakdownChart title=\"By Status\" data={analytics.audit.byStatus} />\n </div>\n\n <AnalyticsBreakdownTable\n title=\"By Resource Type\"\n data={analytics.audit.byResourceType}\n keyLabel=\"Resource\"\n />\n </div>\n ) : null}\n\n {activeTab === 'docs' && analytics?.docs ? (\n <div className=\"space-y-4\">\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <KpiCard label=\"Sites\" value={analytics.docs.totalSites} />\n <KpiCard label=\"Pages\" value={analytics.docs.totalPages} />\n <KpiCard label=\"Revisions\" value={analytics.docs.totalRevisions} />\n <KpiCard\n label=\"Build Success\"\n value={\n analytics.docs.buildSuccessRate != null\n ? `${analytics.docs.buildSuccessRate.toFixed(1)}%`\n : 'N/A'\n }\n variant={\n analytics.docs.buildSuccessRate != null && analytics.docs.buildSuccessRate >= 90\n ? 'success'\n : 'warning'\n }\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-2\">\n <AnalyticsBreakdownChart\n title=\"Pages by Status\"\n data={analytics.docs.pagesByStatus}\n />\n <AnalyticsBreakdownChart\n title=\"Revisions by Status\"\n data={analytics.docs.revisionsByStatus}\n />\n </div>\n </div>\n ) : null}\n </section>\n </Suspense>\n </MotionPage>\n );\n}\n\nfunction KpiCard({\n label,\n value,\n variant,\n}: {\n label: string;\n value: number | string;\n variant?: 'success' | 'warning' | 'error';\n}) {\n const surfaceClass =\n variant === 'success'\n ? 'bg-status-success-bg/10'\n : variant === 'warning'\n ? 'bg-status-warning-bg/10'\n : variant === 'error'\n ? 'bg-status-error-bg/10'\n : 'bg-bg-surface';\n\n return (\n <div className={`${surfaceClass} rounded-lg border border-border-default p-3`}>\n <p className=\"text-xs text-text-secondary\">{label}</p>\n <p className=\"mt-1 text-xl font-bold text-text-primary\">\n {typeof value === 'number' ? value.toLocaleString() : value}\n </p>\n </div>\n );\n}\n\nfunction formatDuration(milliseconds: number): string {\n if (milliseconds < 1000) {\n return `${Math.round(milliseconds)}ms`;\n }\n\n if (milliseconds < 60000) {\n return `${(milliseconds / 1000).toFixed(1)}s`;\n }\n\n const minutes = Math.floor(milliseconds / 60000);\n const seconds = Math.round((milliseconds % 60000) / 1000);\n return `${minutes}m ${seconds}s`;\n}\n\n// ── F11: CSV serialization for the active analytics tab ──────────────────\n\ntype CsvRow = (string | number)[];\n\nfunction rowsToCsv(rows: CsvRow[]): string {\n return rows\n .map((row) =>\n row\n .map((cell) => {\n const s = cell == null ? '' : String(cell);\n // Escape per RFC4180 — wrap in quotes when the cell contains a\n // separator, quote, or newline; double any internal quotes.\n if (/[\",\\n\\r]/.test(s)) return `\"${s.replace(/\"/g, '\"\"')}\"`;\n return s;\n })\n .join(',')\n )\n .join('\\r\\n');\n}\n\n/**\n * Build the CSV row matrix for an analytics tab. Each tab serialises its\n * primary table data; chart-only tabs fall back to a sparse summary.\n * The first row is always headers.\n */\ntype AnalyticsBreakdownEntry = {\n key?: string | null;\n label?: string | null;\n count?: number | null;\n};\n\ninterface AnalyticsTabSlice {\n total?: number | null;\n active?: number | null;\n inactive?: number | null;\n staleHeartbeatCount?: number | null;\n withAgent?: number | null;\n withoutAgent?: number | null;\n totalExecutions?: number | null;\n successRate?: number | null;\n avgDurationMs?: number | null;\n totalDecks?: number | null;\n totalButtons?: number | null;\n totalSites?: number | null;\n totalPages?: number | null;\n totalRevisions?: number | null;\n buildSuccessRate?: number | null;\n byPlatform?: ReadonlyArray<AnalyticsBreakdownEntry>;\n byType?: ReadonlyArray<AnalyticsBreakdownEntry>;\n}\n\ninterface AnalyticsSnapshot {\n sessions?: AnalyticsTabSlice;\n agents?: AnalyticsTabSlice;\n vibes?: AnalyticsTabSlice;\n actions?: AnalyticsTabSlice;\n aiEvents?: AnalyticsTabSlice;\n audit?: AnalyticsTabSlice;\n docs?: AnalyticsTabSlice;\n vibeDecks?: AnalyticsTabSlice;\n}\n\nfunction buildCsvRowsForTab(tab: EntityTab, analytics: AnalyticsSnapshot): CsvRow[] {\n const rows: CsvRow[] = [];\n if (tab === 'overview') {\n rows.push(['metric', 'value']);\n if (analytics.sessions) rows.push(['sessions.total', analytics.sessions.total ?? 0]);\n if (analytics.agents) rows.push(['agents.total', analytics.agents.total ?? 0]);\n if (analytics.vibes) rows.push(['vibes.total', analytics.vibes.total ?? 0]);\n if (analytics.actions) rows.push(['actions.total', analytics.actions.total ?? 0]);\n return rows;\n }\n if (tab === 'agents' && analytics.agents) {\n rows.push(['metric', 'value']);\n rows.push(['total', analytics.agents.total ?? 0]);\n rows.push(['active', analytics.agents.active ?? 0]);\n rows.push(['inactive', analytics.agents.inactive ?? 0]);\n rows.push(['staleHeartbeat', analytics.agents.staleHeartbeatCount ?? 0]);\n if (Array.isArray(analytics.agents.byPlatform)) {\n rows.push([], ['platform', 'count']);\n for (const e of analytics.agents.byPlatform)\n rows.push([e.key ?? e.label ?? '', e.count ?? 0]);\n }\n return rows;\n }\n if (tab === 'sessions' && analytics.sessions) {\n rows.push(['metric', 'value']);\n rows.push(['total', analytics.sessions.total ?? 0]);\n rows.push(['running', analytics.sessions.active ?? 0]);\n rows.push(['avgDurationMs', analytics.sessions.avgDurationMs ?? '']);\n if (Array.isArray(analytics.sessions.byType)) {\n rows.push([], ['type', 'count']);\n for (const e of analytics.sessions.byType) rows.push([e.key ?? e.label ?? '', e.count ?? 0]);\n }\n return rows;\n }\n if (tab === 'actions' && analytics.actions) {\n rows.push(['metric', 'value']);\n rows.push(['total', analytics.actions.total ?? 0]);\n rows.push(['totalExecutions', analytics.actions.totalExecutions ?? 0]);\n rows.push(['successRate', analytics.actions.successRate ?? '']);\n rows.push(['avgDurationMs', analytics.actions.avgDurationMs ?? '']);\n return rows;\n }\n if (tab === 'vibes' && analytics.vibes) {\n rows.push(['metric', 'value']);\n rows.push(['total', analytics.vibes.total ?? 0]);\n rows.push(['withAgent', analytics.vibes.withAgent ?? 0]);\n rows.push(['withoutAgent', analytics.vibes.withoutAgent ?? 0]);\n return rows;\n }\n if (tab === 'vibedecks' && analytics.vibeDecks) {\n rows.push(['metric', 'value']);\n rows.push(['decks', analytics.vibeDecks.totalDecks ?? 0]);\n rows.push(['buttons', analytics.vibeDecks.totalButtons ?? 0]);\n return rows;\n }\n if (tab === 'aievents' && analytics.aiEvents) {\n rows.push(['metric', 'value']);\n rows.push(['total', analytics.aiEvents.total ?? 0]);\n return rows;\n }\n if (tab === 'audit' && analytics.audit) {\n rows.push(['metric', 'value']);\n rows.push(['total', analytics.audit.total ?? 0]);\n return rows;\n }\n if (tab === 'docs' && analytics.docs) {\n rows.push(['metric', 'value']);\n rows.push(['sites', analytics.docs.totalSites ?? 0]);\n rows.push(['pages', analytics.docs.totalPages ?? 0]);\n rows.push(['revisions', analytics.docs.totalRevisions ?? 0]);\n rows.push(['buildSuccessRate', analytics.docs.buildSuccessRate ?? '']);\n return rows;\n }\n // sandbox + others fall back to a sparse summary\n rows.push(['metric', 'value']);\n rows.push(['note', `No CSV serialiser for ${tab} tab yet`]);\n return rows;\n}\n"],"mappings":"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"}
@@ -283,21 +283,11 @@ function k() {
283
283
  /* @__PURE__ */ T("div", {
284
284
  className: "flex flex-wrap items-center justify-center gap-2",
285
285
  children: [
286
- /* @__PURE__ */ w("button", {
287
- type: "button",
288
- onClick: () => k("/getting-started"),
289
- className: "text-sm text-text-link hover:underline",
290
- children: N("overviewPage.empty.setupGuide", "Setup guide")
291
- }),
292
- /* @__PURE__ */ w("span", {
293
- className: "text-text-muted",
294
- children: "·"
295
- }),
296
286
  /* @__PURE__ */ w("button", {
297
287
  type: "button",
298
288
  onClick: () => k("/getting-started"),
299
289
  className: "text-sm font-medium text-text-link hover:underline",
300
- children: N("overviewPage.empty.fullSetupGuide", "View full setup guide")
290
+ children: N("overviewPage.empty.setupGuide", "Setup guide")
301
291
  }),
302
292
  /* @__PURE__ */ w("span", {
303
293
  className: "text-text-muted",
@@ -1 +1 @@
1
- {"version":3,"file":"OverviewPage.js","names":[],"sources":["../../src/pages/OverviewPage.tsx"],"sourcesContent":["import { 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 } from '@/providers/VibeControlsProvider';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\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 notes,\n targets,\n loading,\n error: dataError,\n totals,\n refetch,\n } = useCachedInitialData();\n\n if (dataError) {\n // eslint-disable-next-line no-console -- intentional debug breadcrumb for failed overview load\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 notes: {\n total: totals.notes,\n pinned: notes.filter((n) => n.isPinned).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]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold text-foreground\">\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 text-status-success-text',\n blue: 'bg-status-info-bg text-status-info-text',\n purple: 'bg-accent-purple-subtle text-accent-purple',\n orange: 'bg-status-warning-bg text-status-warning-text',\n cyan: 'bg-accent-teal-subtle text-accent-teal',\n yellow: 'bg-status-warning-bg 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 p-4 sm:p-6 bg-bg-surface 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={refetch}\n disabled={loading}\n className=\"flex items-center gap-2 px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary hover:bg-bg-sunken/80 transition-colors disabled:opacity-50\"\n >\n <RefreshCw className={`size-4 ${loading ? 'animate-spin' : ''}`} />\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={refetch}\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-5 gap-4\"\n stagger={0.06}\n >\n <MotionItem variant=\"fadeScale\">\n <StatCard\n title={tr('overviewPage.stats.targets', 'Targets')}\n value={loading ? '-' : targets.length}\n subtitle={\n loading\n ? ''\n : tr('overviewPage.stats.connected', '{{count}} connected', {\n count: targets.filter((t) => t.status === 'connected' || t.status === 'active')\n .length,\n })\n }\n icon={<Server className=\"size-6\" />}\n variant={!loading && targets.length > 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 <MotionItem variant=\"fadeScale\" className=\"col-span-2 sm:col-span-1\">\n <StatCard\n title={tr('overviewPage.stats.notes', 'Notes')}\n value={loading ? '-' : stats.notes.total}\n subtitle={\n loading\n ? ''\n : tr('overviewPage.stats.pinned', '{{count}} pinned', {\n count: stats.notes.pinned,\n })\n }\n icon={<FileText className=\"size-6\" />}\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\">\n <Card>\n <div className=\"flex items-center justify-between mb-4\">\n <h2 className=\"text-lg font-semibold text-text-primary flex items-center gap-2\">\n <Bot className=\"size-5\" />\n {tr('overviewPage.sections.activeAgents', 'Active Agents')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/agents')}\n className=\"text-sm 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 className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\" stagger={0.04}>\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=\"text-center py-6 text-text-secondary\">\n <Bot className=\"size-12 mx-auto mb-2 opacity-50\" />\n <p>{tr('overviewPage.empty.noActiveAgents', 'No active agents')}</p>\n <p className=\"text-xs text-text-muted mt-1 mb-3\">\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 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('/getting-started')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n >\n {tr('overviewPage.empty.fullSetupGuide', 'View full 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>\n <Card>\n <div className=\"flex items-center justify-between mb-4\">\n <h2 className=\"text-lg font-semibold text-text-primary flex items-center gap-2\">\n <Activity className=\"size-5\" />\n {tr('overviewPage.sections.recentActivity', 'Recent Activity')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/audit')}\n className=\"text-sm 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\" 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=\"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-4\">\n <h2 className=\"text-lg font-semibold text-text-primary flex items-center gap-2\">\n <Terminal className=\"size-5\" />\n {tr('overviewPage.sections.runningSessions', 'Running Sessions')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/sessions')}\n className=\"text-sm 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-3\"\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=\"text-center py-8 text-text-secondary\">\n <Terminal className=\"size-12 mx-auto mb-2 opacity-50\" />\n <p>{tr('overviewPage.empty.noRunningSessions', 'No running sessions')}</p>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/sessions')}\n className=\"mt-2 text-sm 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-4\">\n <h2 className=\"text-lg font-semibold text-text-primary flex items-center gap-2\">\n <Zap className=\"size-5\" />\n {tr('overviewPage.sections.activeVibes', 'Active Vibes')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/vibes')}\n className=\"text-sm 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-3\"\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=\"text-center py-8 text-text-secondary\">\n <Zap className=\"size-12 mx-auto mb-2 opacity-50\" />\n <p>{tr('overviewPage.empty.noActiveVibes', 'No active vibes')}</p>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/vibes')}\n className=\"mt-2 text-sm 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 { 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 } from '@/providers/VibeControlsProvider';\nimport { useCachedInitialData } from '@/hooks/useCachedInitialData';\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 notes,\n targets,\n loading,\n error: dataError,\n totals,\n refetch,\n } = useCachedInitialData();\n\n if (dataError) {\n // eslint-disable-next-line no-console -- intentional debug breadcrumb for failed overview load\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 notes: {\n total: totals.notes,\n pinned: notes.filter((n) => n.isPinned).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]\">\n <div className=\"text-center space-y-2\">\n <h2 className=\"text-lg font-semibold text-foreground\">\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 text-status-success-text',\n blue: 'bg-status-info-bg text-status-info-text',\n purple: 'bg-accent-purple-subtle text-accent-purple',\n orange: 'bg-status-warning-bg text-status-warning-text',\n cyan: 'bg-accent-teal-subtle text-accent-teal',\n yellow: 'bg-status-warning-bg 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 p-4 sm:p-6 bg-bg-surface 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={refetch}\n disabled={loading}\n className=\"flex items-center gap-2 px-3 py-2 text-sm bg-bg-sunken border border-border-default rounded-md text-text-primary hover:bg-bg-sunken/80 transition-colors disabled:opacity-50\"\n >\n <RefreshCw className={`size-4 ${loading ? 'animate-spin' : ''}`} />\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={refetch}\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-5 gap-4\"\n stagger={0.06}\n >\n <MotionItem variant=\"fadeScale\">\n <StatCard\n title={tr('overviewPage.stats.targets', 'Targets')}\n value={loading ? '-' : targets.length}\n subtitle={\n loading\n ? ''\n : tr('overviewPage.stats.connected', '{{count}} connected', {\n count: targets.filter((t) => t.status === 'connected' || t.status === 'active')\n .length,\n })\n }\n icon={<Server className=\"size-6\" />}\n variant={!loading && targets.length > 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 <MotionItem variant=\"fadeScale\" className=\"col-span-2 sm:col-span-1\">\n <StatCard\n title={tr('overviewPage.stats.notes', 'Notes')}\n value={loading ? '-' : stats.notes.total}\n subtitle={\n loading\n ? ''\n : tr('overviewPage.stats.pinned', '{{count}} pinned', {\n count: stats.notes.pinned,\n })\n }\n icon={<FileText className=\"size-6\" />}\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\">\n <Card>\n <div className=\"flex items-center justify-between mb-4\">\n <h2 className=\"text-lg font-semibold text-text-primary flex items-center gap-2\">\n <Bot className=\"size-5\" />\n {tr('overviewPage.sections.activeAgents', 'Active Agents')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/agents')}\n className=\"text-sm 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 className=\"grid grid-cols-1 sm:grid-cols-2 gap-3\" stagger={0.04}>\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=\"text-center py-6 text-text-secondary\">\n <Bot className=\"size-12 mx-auto mb-2 opacity-50\" />\n <p>{tr('overviewPage.empty.noActiveAgents', 'No active agents')}</p>\n <p className=\"text-xs text-text-muted mt-1 mb-3\">\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>\n <Card>\n <div className=\"flex items-center justify-between mb-4\">\n <h2 className=\"text-lg font-semibold text-text-primary flex items-center gap-2\">\n <Activity className=\"size-5\" />\n {tr('overviewPage.sections.recentActivity', 'Recent Activity')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/audit')}\n className=\"text-sm 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\" 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=\"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-4\">\n <h2 className=\"text-lg font-semibold text-text-primary flex items-center gap-2\">\n <Terminal className=\"size-5\" />\n {tr('overviewPage.sections.runningSessions', 'Running Sessions')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/sessions')}\n className=\"text-sm 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-3\"\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=\"text-center py-8 text-text-secondary\">\n <Terminal className=\"size-12 mx-auto mb-2 opacity-50\" />\n <p>{tr('overviewPage.empty.noRunningSessions', 'No running sessions')}</p>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/sessions')}\n className=\"mt-2 text-sm 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-4\">\n <h2 className=\"text-lg font-semibold text-text-primary flex items-center gap-2\">\n <Zap className=\"size-5\" />\n {tr('overviewPage.sections.activeVibes', 'Active Vibes')}\n </h2>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/vibes')}\n className=\"text-sm 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-3\"\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=\"text-center py-8 text-text-secondary\">\n <Zap className=\"size-12 mx-auto mb-2 opacity-50\" />\n <p>{tr('overviewPage.empty.noActiveVibes', 'No active vibes')}</p>\n <button\n type=\"button\"\n onClick={() => handleNavigate('/vibes')}\n className=\"mt-2 text-sm 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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"}