@matthesketh/fleet 1.8.0 → 1.8.1

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.
@@ -46,7 +46,7 @@ export function Dashboard() {
46
46
  if (!status)
47
47
  return _jsx(Text, { color: colors.muted, children: "No data" });
48
48
  const listHeight = Math.max(5, availableHeight - 4);
49
- return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, gap: 2, children: [_jsxs(Text, { bold: true, children: [status.totalApps, " apps"] }), _jsxs(Text, { color: colors.success, children: [status.healthy, " healthy"] }), status.unhealthy > 0 && (_jsxs(Text, { color: colors.error, children: [status.unhealthy, " unhealthy"] })), loading && _jsx(Text, { color: colors.muted, children: _jsx(Spinner, { type: "dots" }) })] }), _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { bold: true, children: ['APP'.padEnd(24), 'SYSTEMD'.padEnd(14), 'CONTAINERS'.padEnd(14), 'HEALTH'.padEnd(12)] }) }), _jsx(ScrollableList, { items: items, selectedIndex: Math.min(state.dashboardIndex, items.length - 1), maxVisible: listHeight, renderItem: (item, selected) => {
49
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, gap: 2, children: [_jsxs(Text, { bold: true, children: [status.totalApps, " apps"] }), _jsxs(Text, { color: colors.success, children: [status.healthy, " healthy"] }), status.unhealthy > 0 && (_jsxs(Text, { color: colors.error, children: [status.unhealthy, " unhealthy"] }))] }), _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { bold: true, children: ['APP'.padEnd(24), 'SYSTEMD'.padEnd(14), 'CONTAINERS'.padEnd(14), 'HEALTH'.padEnd(12)] }) }), _jsx(ScrollableList, { items: items, selectedIndex: Math.min(state.dashboardIndex, items.length - 1), maxVisible: listHeight, renderItem: (item, selected) => {
50
50
  const app = status.apps.find(a => a.name === item.name);
51
51
  const displayName = redact(app.name);
52
52
  return (_jsxs(Box, { children: [_jsx(Text, { bold: true, color: selected ? colors.primary : colors.muted, children: selected ? '> ' : ' ' }), _jsx(Box, { width: 24, children: _jsx(Text, { bold: selected, color: selected ? colors.primary : colors.text, children: displayName.length > 22 ? displayName.slice(0, 19) + '...' : displayName }) }), _jsx(Box, { width: 14, children: _jsx(Text, { children: app.systemd.slice(0, 12) }) }), _jsx(Box, { width: 14, children: _jsx(Text, { children: app.containers }) }), _jsx(Box, { width: 12, children: _jsx(Text, { children: app.health.slice(0, 10) }) })] }));
@@ -13,6 +13,10 @@ export function HealthView() {
13
13
  const state = useAppState();
14
14
  const dispatch = useAppDispatch();
15
15
  const { results, loading, error } = useHealth();
16
+ // only show spinner during the very first load. background polls (every
17
+ // 15s) flip `loading` true/false too, but the data is already on screen —
18
+ // ticking a spinner there causes the whole table to redraw at frame rate.
19
+ const initialLoad = loading && results.length === 0;
16
20
  const redact = useRedact();
17
21
  const availableHeight = useAvailableHeight();
18
22
  const counts = useMemo(() => ({
@@ -34,14 +38,14 @@ export function HealthView() {
34
38
  return false;
35
39
  };
36
40
  useRegisterHandler(handler);
37
- if (loading && results.length === 0) {
41
+ if (initialLoad) {
38
42
  return (_jsx(Box, { padding: 1, children: _jsxs(Text, { children: [_jsx(Spinner, { type: "dots" }), " Running health checks..."] }) }));
39
43
  }
40
44
  if (error && results.length === 0) {
41
45
  return (_jsx(Box, { padding: 1, children: _jsxs(Text, { color: colors.error, children: ["Error: ", error] }) }));
42
46
  }
43
47
  const listHeight = Math.max(5, availableHeight - 4);
44
- return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, gap: 2, children: [_jsx(Text, { bold: true, children: "Health Monitor" }), _jsxs(Text, { color: colors.success, children: [counts.healthy, " healthy"] }), counts.degraded > 0 && _jsxs(Text, { color: colors.warning, children: [counts.degraded, " degraded"] }), counts.down > 0 && _jsxs(Text, { color: colors.error, children: [counts.down, " down"] }), loading && _jsx(Text, { color: colors.muted, children: _jsx(Spinner, { type: "dots" }) })] }), _jsxs(Text, { bold: true, children: [' APP'.padEnd(26), 'SYSTEMD'.padEnd(12), 'CONTAINERS'.padEnd(20), 'HTTP'.padEnd(10), "OVERALL"] }), _jsx(ScrollableList, { items: results, selectedIndex: Math.min(state.healthIndex, results.length - 1), maxVisible: listHeight, renderItem: (result, selected) => {
48
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsxs(Box, { marginBottom: 1, gap: 2, children: [_jsx(Text, { bold: true, children: "Health Monitor" }), _jsxs(Text, { color: colors.success, children: [counts.healthy, " healthy"] }), counts.degraded > 0 && _jsxs(Text, { color: colors.warning, children: [counts.degraded, " degraded"] }), counts.down > 0 && _jsxs(Text, { color: colors.error, children: [counts.down, " down"] })] }), _jsxs(Text, { bold: true, children: [' APP'.padEnd(26), 'SYSTEMD'.padEnd(12), 'CONTAINERS'.padEnd(20), 'HTTP'.padEnd(10), "OVERALL"] }), _jsx(ScrollableList, { items: results, selectedIndex: Math.min(state.healthIndex, results.length - 1), maxVisible: listHeight, renderItem: (result, selected) => {
45
49
  const runningCount = result.containers.filter(c => c.running).length;
46
50
  const containerStr = `${runningCount}/${result.containers.length}`;
47
51
  // 404 → "no /health" (app never implemented one — distinct from a real failure).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matthesketh/fleet",
3
- "version": "1.8.0",
3
+ "version": "1.8.1",
4
4
  "description": "Docker production management CLI + MCP server for Claude Code",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -59,7 +59,7 @@
59
59
  "@matthesketh/ink-modal": "^0.1.0",
60
60
  "@matthesketh/ink-pipeline": "^0.1.0",
61
61
  "@matthesketh/ink-rule": "^0.1.0",
62
- "@matthesketh/ink-scrollable-list": "^0.1.1",
62
+ "@matthesketh/ink-scrollable-list": "0.2.0",
63
63
  "@matthesketh/ink-split-pane": "^0.1.0",
64
64
  "@matthesketh/ink-stable-state": "^0.1.0",
65
65
  "@matthesketh/ink-status-bar": "^0.1.0",