@burdenoff/microfe-vibecontrols 2026.625.2 → 2026.625.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.
- package/dist/components/agents/AgentStatusBadge.js +11 -4
- package/dist/components/agents/AgentStatusBadge.js.map +1 -1
- package/dist/components/sessions/SessionStatusBadge.js +11 -8
- package/dist/components/sessions/SessionStatusBadge.js.map +1 -1
- package/dist/components/shared/EmptyState.js +14 -8
- package/dist/components/shared/EmptyState.js.map +1 -1
- package/dist/components/shared/PageHeader.js.map +1 -1
- package/dist/components/shared/PageSkeleton.js +4 -1
- package/dist/components/shared/PageSkeleton.js.map +1 -1
- package/dist/components/shared/SessionNotificationBanner.js +12 -5
- package/dist/components/shared/SessionNotificationBanner.js.map +1 -1
- package/dist/components/shared/StatusBadge.js +2 -2
- package/dist/components/shared/StatusBadge.js.map +1 -1
- package/dist/pages/AgentsPage.js +1 -0
- package/dist/pages/AgentsPage.js.map +1 -1
- package/dist/pages/OverviewPage.js +220 -240
- package/dist/pages/OverviewPage.js.map +1 -1
- package/dist/pages/SessionsPage.js +1 -0
- package/dist/pages/SessionsPage.js.map +1 -1
- package/dist/pages/TargetsPage.js +176 -175
- package/dist/pages/TargetsPage.js.map +1 -1
- package/dist/pages/VibesPage.js +1 -0
- package/dist/pages/VibesPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -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 { EmphasisPanel } from '@burdenoff/fe-libs/ui';\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 — the single emphasised \"primary insight\" zone */}\n <MotionItem className=\"xl:col-span-2 h-full\">\n <EmphasisPanel 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\">·</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 </EmphasisPanel>\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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"}
|
|
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 {\n EmphasisPanel,\n AuroraBackground,\n GradientText,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\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 {/* Hero header — the ONE aurora backdrop for this MFE. Sits at -z-10\n behind the header; never moves content; static under reduced motion. */}\n <div className=\"relative overflow-hidden rounded-card -mx-2 px-2 pt-1\">\n <AuroraBackground intensity=\"subtle\" />\n <PageHeader\n title={\n <>\n <GradientText>{tr('overviewPage.titleNoun', 'VibeControls')}</GradientText>{' '}\n {tr('overviewPage.titleSuffix', 'Overview')}\n </>\n }\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 </div>\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 — the single emphasised \"primary insight\" zone */}\n <MotionItem className=\"xl:col-span-2 h-full\">\n <EmphasisPanel className=\"flex h-full flex-col border-[color-mix(in_oklab,var(--color-action-primary-bg)_34%,transparent)] shadow-[var(--shadow-glow)]\">\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 <IllustratedEmptyState\n className=\"flex-1 py-8\"\n illustration=\"empty-agents\"\n title={tr('overviewPage.empty.noActiveAgents', 'No active agents')}\n description={tr(\n 'overviewPage.empty.installCliHint',\n 'Install the agent CLI to get started'\n )}\n action={\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\">·</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 }\n />\n )}\n </EmphasisPanel>\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 <IllustratedEmptyState\n className=\"h-full py-6\"\n illustration=\"empty-notifications\"\n title={tr('overviewPage.empty.noRecentActivity', 'No recent activity')}\n action={\n <button\n type=\"button\"\n onClick={() => handleNavigate('/audit')}\n className=\"text-sm text-text-link hover:underline\"\n >\n {tr('overviewPage.empty.viewAuditLog', 'View audit log')}\n </button>\n }\n />\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 <IllustratedEmptyState\n illustration=\"empty-sessions\"\n title={tr('overviewPage.empty.noRunningSessions', 'No running sessions')}\n action={\n <button\n type=\"button\"\n onClick={() => handleNavigate('/sessions')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n >\n {tr('overviewPage.empty.startSession', 'Start a session')}\n </button>\n }\n />\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 <IllustratedEmptyState\n illustration=\"empty-vibes\"\n title={tr('overviewPage.empty.noActiveVibes', 'No active vibes')}\n action={\n <button\n type=\"button\"\n onClick={() => handleNavigate('/vibes')}\n className=\"text-sm font-medium text-text-link hover:underline\"\n >\n {tr('overviewPage.empty.addVibe', 'Add a vibe')}\n </button>\n }\n />\n )}\n </Card>\n </MotionItem>\n </MotionPage>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1948,6 +1948,7 @@ function jt() {
|
|
|
1948
1948
|
dismissKey: "vibecontrols-sessions-setup-banner"
|
|
1949
1949
|
}), /* @__PURE__ */ h(Te, {
|
|
1950
1950
|
icon: /* @__PURE__ */ h(pt, { className: "size-8 text-text-secondary" }),
|
|
1951
|
+
illustration: x || S !== "all" || C !== "all" || w !== "all" || T !== "all" || E !== "all" ? "empty-search" : "empty-sessions",
|
|
1951
1952
|
title: x || S !== "all" || C !== "all" || w !== "all" || T !== "all" || E !== "all" ? b("sessions.emptyFound", "No sessions found") : b("sessions.emptyConfigured", "No sessions configured"),
|
|
1952
1953
|
description: x || S !== "all" || C !== "all" || w !== "all" || T !== "all" || E !== "all" ? b("sessions.emptyAdjustSearch", "Try adjusting your search or filters") : b("sessions.emptyDescription", "Sessions require an active agent. Install the CLI agent first, then start a session."),
|
|
1953
1954
|
action: !x && S === "all" && C === "all" && w === "all" && T === "all" && E === "all" ? /* @__PURE__ */ g("div", {
|