Repository URL to install this package:
|
Version:
0.4.41 ▾
|
import React, { useCallback, useEffect, useState } from "react";
import { Box, Text, useInput } from "ink";
import { api } from "../rpc.js";
import { Panel } from "../components/Panel.js";
import { StatusBar } from "../components/StatusBar.js";
import { HelpOverlay } from "../components/HelpOverlay.js";
import { ConfirmDialog } from "../components/ConfirmDialog.js";
function clamp(value, max) {
if (max <= 0)
return 0;
return Math.max(0, Math.min(value, max - 1));
}
function stateColor(state) {
if (state === "running")
return "green";
if (state === "exited")
return "red";
if (state === "created")
return "yellow";
if (state === "paused")
return "blue";
return "gray";
}
const HELP_HINTS = [
{ key: "j/k", label: "navigate containers" },
{ key: "s", label: "start container" },
{ key: "x", label: "stop container" },
{ key: "R", label: "rebuild (remove) container" },
{ key: "r", label: "refresh" },
{ key: "?", label: "help" },
{ key: "q", label: "quit" },
];
const BAR_HINTS = [
{ key: "j/k", label: "navigate" },
{ key: "s", label: "start" },
{ key: "x", label: "stop" },
{ key: "R", label: "remove" },
{ key: "r", label: "refresh" },
{ key: "?", label: "help" },
{ key: "esc/q", label: "back" },
];
export function Containers({ onQuit }) {
const [containers, setContainers] = useState([]);
const [selected, setSelected] = useState(0);
const [status, setStatus] = useState(null);
const [loading, setLoading] = useState(true);
const [showHelp, setShowHelp] = useState(false);
const [confirmAction, setConfirmAction] = useState(null);
const refresh = useCallback(async () => {
try {
const result = await api.listContainers();
setContainers(result);
setLoading(false);
}
catch (err) {
setStatus(`Error: ${err instanceof Error ? err.message : String(err)}`);
setLoading(false);
}
}, []);
useEffect(() => {
refresh();
const interval = setInterval(refresh, 5000);
return () => clearInterval(interval);
}, [refresh]);
useEffect(() => {
if (!status)
return;
const timer = setTimeout(() => setStatus(null), 4000);
return () => clearTimeout(timer);
}, [status]);
const current = containers[selected] ?? null;
useInput((input, key) => {
if (showHelp || confirmAction)
return;
if (input === "?") {
setShowHelp(true);
return;
}
if (input === "q" || key.escape) {
onQuit();
return;
}
if (input === "r") {
refresh();
setStatus("Refreshed");
return;
}
if (key.upArrow || input === "k") {
setSelected((v) => clamp(v - 1, containers.length));
return;
}
if (key.downArrow || input === "j") {
setSelected((v) => clamp(v + 1, containers.length));
return;
}
if (input === "s" && current) {
setStatus(`Starting ${current.name}...`);
api.startContainer(current.name)
.then(() => { setStatus(`Started ${current.name}`); refresh(); })
.catch((err) => setStatus(`Error: ${err instanceof Error ? err.message : String(err)}`));
return;
}
if (input === "x" && current) {
const c = current;
setConfirmAction({
message: `Stop container "${c.name}"?`,
action: () => {
setStatus(`Stopping ${c.name}...`);
api.stopContainer(c.name)
.then(() => { setStatus(`Stopped ${c.name}`); refresh(); })
.catch((err) => setStatus(`Error: ${err instanceof Error ? err.message : String(err)}`));
},
});
return;
}
if (input === "R" && current) {
const c = current;
setConfirmAction({
message: `Remove container "${c.name}"?`,
action: () => {
setStatus(`Removing ${c.name}...`);
api.rebuildContainer(c.name)
.then(() => { setStatus(`Removed ${c.name}`); refresh(); })
.catch((err) => setStatus(`Error: ${err instanceof Error ? err.message : String(err)}`));
},
});
return;
}
});
if (showHelp) {
return (React.createElement(Box, { flexDirection: "column", flexGrow: 1 },
React.createElement(HelpOverlay, { title: "Containers", hints: HELP_HINTS, onClose: () => setShowHelp(false) })));
}
return (React.createElement(Box, { flexDirection: "column", flexGrow: 1 },
React.createElement(Box, { flexDirection: "row", flexGrow: 1 },
React.createElement(Panel, { title: `Containers (${containers.length})`, focused: true, flexGrow: 1 },
React.createElement(Box, { flexDirection: "column", paddingX: 1 }, loading ? (React.createElement(Text, { color: "gray" }, "Loading containers...")) : containers.length === 0 ? (React.createElement(Text, { color: "gray" }, "No omni containers found.")) : (containers.map((c, i) => {
const isSelected = i === selected;
return (React.createElement(Text, { key: c.name, color: isSelected ? "cyan" : undefined, wrap: "truncate" },
isSelected ? "\u25B8 " : " ",
React.createElement(Text, { color: stateColor(c.state), bold: true }, c.state.padEnd(8)),
" ",
c.name));
})))),
current && !loading ? (React.createElement(Panel, { title: "Detail", flexGrow: 1 },
React.createElement(Box, { flexDirection: "column", paddingX: 1 },
React.createElement(Box, null,
React.createElement(Text, { color: "gray" }, "Name "),
React.createElement(Text, null, current.name)),
React.createElement(Box, null,
React.createElement(Text, { color: "gray" }, "Image "),
React.createElement(Text, null, current.image)),
React.createElement(Box, null,
React.createElement(Text, { color: "gray" }, "Status "),
React.createElement(Text, null, current.status)),
React.createElement(Box, null,
React.createElement(Text, { color: "gray" }, "Created "),
React.createElement(Text, null, current.created)),
current.ports ? React.createElement(Box, null,
React.createElement(Text, { color: "gray" }, "Ports "),
React.createElement(Text, null, current.ports)) : null))) : null),
confirmAction ? (React.createElement(Box, { paddingX: 1 },
React.createElement(ConfirmDialog, { message: confirmAction.message, onConfirm: () => { confirmAction.action(); setConfirmAction(null); }, onCancel: () => setConfirmAction(null) }))) : null,
React.createElement(StatusBar, { hints: BAR_HINTS, status: status })));
}
//# sourceMappingURL=Containers.js.map