alnilam-cli
Version:
Git-native AI career coach that converts multi-year ambitions into weekly execution
89 lines (88 loc) • 8.17 kB
JavaScript
"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;