UNPKG

alnilam-cli

Version:

Git-native AI career coach that converts multi-year ambitions into weekly execution

89 lines (88 loc) 8.17 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Dashboard = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const ink_1 = require("ink"); const Layout_js_1 = require("../shared/Layout.js"); const Theme_js_1 = require("../shared/Theme.js"); const Loading_js_1 = require("../shared/Loading.js"); const MomentumGauge_js_1 = require("./MomentumGauge.js"); const GoalProgressGrid_js_1 = require("./GoalProgressGrid.js"); const ActivityFeed_js_1 = require("./ActivityFeed.js"); const api_js_1 = require("../../lib/api.js"); const Dashboard = ({ autoRefresh = false, refreshInterval = 30000 }) => { const [data, setData] = (0, react_1.useState)(null); const [loading, setLoading] = (0, react_1.useState)(true); const [error, setError] = (0, react_1.useState)(null); const [lastUpdated, setLastUpdated] = (0, react_1.useState)(new Date()); const { stdout } = (0, ink_1.useStdout)(); // Get terminal dimensions for responsive layout const terminalWidth = stdout?.columns || 100; const isSmallScreen = terminalWidth < 80; // Fetch dashboard data const fetchDashboardData = async () => { try { setLoading(true); setError(null); // Fetch all dashboard data in parallel const [goalsRes, evidenceRes, evaluationRes, summariesRes, nudgesRes] = await Promise.all([ api_js_1.restClient.get('/goals', { params: { select: '*', order: 'created_at.desc', limit: 10 } }), api_js_1.restClient.get('/evidence', { params: { select: '*', order: 'created_at.desc', limit: 20 } }), api_js_1.restClient.get('/evaluations', { params: { select: '*', order: 'week_start.desc', limit: 1 } }), api_js_1.restClient.get('/summaries', { params: { select: 'date,content,evidence_count', order: 'date.desc', limit: 7 } }), api_js_1.restClient.get('/nudges', { params: { select: '*', eq: 'requires_approval.true,approved.false', limit: 5 } }) ]); setData({ goals: goalsRes.data || [], recentEvidence: evidenceRes.data || [], latestEvaluation: evaluationRes.data?.[0] || null, recentSummaries: summariesRes.data || [], pendingNudges: nudgesRes.data || [] }); setLastUpdated(new Date()); } catch (err) { setError(err.message || 'Failed to load dashboard data'); } finally { setLoading(false); } }; // Initial data load (0, react_1.useEffect)(() => { fetchDashboardData(); }, []); // Auto-refresh functionality (0, react_1.useEffect)(() => { if (!autoRefresh) return; const interval = setInterval(fetchDashboardData, refreshInterval); return () => clearInterval(interval); }, [autoRefresh, refreshInterval]); // Keyboard shortcuts (0, ink_1.useInput)((input, key) => { if (input === 'r' || key.return) { fetchDashboardData(); } if (input === 'q' || key.escape) { process.exit(0); } }); // Calculate stats for overview const stats = data ? { totalGoals: data.goals.length, activeGoals: data.goals.filter(g => g.status === 'active').length, completedGoals: data.goals.filter(g => g.status === 'completed').length, weeklyEvidence: data.recentEvidence.filter(e => { const weekAgo = new Date(); weekAgo.setDate(weekAgo.getDate() - 7); return new Date(e.created_at) > weekAgo; }).length, currentMomentum: data.latestEvaluation?.momentum_score || 0, pendingApprovals: data.pendingNudges.length } : null; return ((0, jsx_runtime_1.jsx)(Layout_js_1.Layout, { title: "Alnilam Dashboard", subtitle: `Last updated: ${lastUpdated.toLocaleTimeString()}`, children: (0, jsx_runtime_1.jsx)(Loading_js_1.DataState, { loading: loading, error: error || undefined, empty: !data, children: data && stats && ((0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [(0, jsx_runtime_1.jsx)(Layout_js_1.Section, { title: "\uD83D\uDCCA Overview", children: (0, jsx_runtime_1.jsxs)(Layout_js_1.Grid, { columns: isSmallScreen ? 2 : 4, gap: 1, children: [(0, jsx_runtime_1.jsx)(Layout_js_1.Card, { compact: true, status: "info", children: (0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "row", justifyContent: "space-between", children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { children: "Goals" }), (0, jsx_runtime_1.jsxs)(Theme_js_1.ThemedText.bold, { color: "blue", children: [stats.activeGoals, "/", stats.totalGoals] })] }) }), (0, jsx_runtime_1.jsx)(Layout_js_1.Card, { compact: true, status: "success", children: (0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "row", justifyContent: "space-between", children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { children: "Completed" }), (0, jsx_runtime_1.jsx)(Theme_js_1.ThemedText.bold, { color: "green", children: stats.completedGoals })] }) }), (0, jsx_runtime_1.jsx)(Layout_js_1.Card, { compact: true, status: "warning", children: (0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "row", justifyContent: "space-between", children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { children: "Weekly Evidence" }), (0, jsx_runtime_1.jsx)(Theme_js_1.ThemedText.bold, { color: "yellow", children: stats.weeklyEvidence })] }) }), (0, jsx_runtime_1.jsx)(Layout_js_1.Card, { compact: true, status: "info", children: (0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "row", justifyContent: "space-between", children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { children: "Pending" }), (0, jsx_runtime_1.jsx)(Theme_js_1.ThemedText.bold, { color: "red", children: stats.pendingApprovals })] }) })] }) }), (0, jsx_runtime_1.jsxs)(Layout_js_1.Grid, { columns: isSmallScreen ? 1 : 2, gap: 2, children: [(0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [(0, jsx_runtime_1.jsx)(Layout_js_1.Section, { title: "\uD83C\uDFAF Momentum", children: (0, jsx_runtime_1.jsx)(MomentumGauge_js_1.MomentumGauge, { score: stats.currentMomentum, evaluation: data.latestEvaluation }) }), (0, jsx_runtime_1.jsx)(Layout_js_1.Section, { title: "\uD83D\uDCCB Goals Progress", children: (0, jsx_runtime_1.jsx)(GoalProgressGrid_js_1.GoalProgressGrid, { goals: data.goals, compact: isSmallScreen }) })] }), (0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [(0, jsx_runtime_1.jsx)(Layout_js_1.Section, { title: "\uD83D\uDD04 Recent Activity", children: (0, jsx_runtime_1.jsx)(ActivityFeed_js_1.ActivityFeed, { evidence: data.recentEvidence.slice(0, 5), summaries: data.recentSummaries.slice(0, 3), compact: isSmallScreen }) }), stats.pendingApprovals > 0 && ((0, jsx_runtime_1.jsx)(Layout_js_1.Section, { title: "\u23F3 Pending Approvals", children: (0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "column", children: [data.pendingNudges.slice(0, 3).map((nudge) => ((0, jsx_runtime_1.jsxs)(ink_1.Box, { marginBottom: 1, children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: "yellow", children: "\u2022 " }), (0, jsx_runtime_1.jsx)(ink_1.Text, { children: nudge.content }), nudge.type === 'weekly_plan' && ((0, jsx_runtime_1.jsx)(ink_1.Text, { color: "gray", dimColor: true, children: " (Plan)" }))] }, nudge.id))), data.pendingNudges.length > 3 && ((0, jsx_runtime_1.jsxs)(ink_1.Text, { color: "gray", dimColor: true, children: ["... and ", data.pendingNudges.length - 3, " more"] }))] }) }))] })] }), (0, jsx_runtime_1.jsx)(ink_1.Box, { marginTop: 2, borderStyle: "single", borderColor: "gray", paddingX: 2, paddingY: 1, children: (0, jsx_runtime_1.jsxs)(ink_1.Box, { flexDirection: "row", justifyContent: "space-between", children: [(0, jsx_runtime_1.jsx)(ink_1.Text, { color: "gray", children: "Press 'r' to refresh \u2022 'q' to quit" }), (0, jsx_runtime_1.jsx)(ink_1.Text, { color: "gray", children: autoRefresh ? `Auto-refresh: ${refreshInterval / 1000}s` : 'Manual refresh' })] }) })] })) }) })); }; exports.Dashboard = Dashboard; exports.default = exports.Dashboard;