Skip to content

Commit be3b97a

Browse files
feat: [WIP] nodes ls --verbose rework
1 parent 2ac4c0b commit be3b97a

1 file changed

Lines changed: 57 additions & 20 deletions

File tree

src/lib/nodes/list.tsx

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import advanced from "dayjs/plugin/advancedFormat";
99
import timezone from "dayjs/plugin/timezone";
1010
import { Box, render, Text } from "ink";
1111
import type { SFCNodes } from "@sfcompute/nodes-sdk-alpha";
12+
import { formatDuration, intervalToDuration } from "date-fns";
1213

1314
import { getAuthToken } from "../../helpers/config.ts";
1415
import { logAndQuit } from "../../helpers/errors.ts";
@@ -27,6 +28,7 @@ import {
2728
jsonOption,
2829
pluralizeNodes,
2930
printNodeType,
31+
printVMStatus,
3032
} from "./utils.ts";
3133

3234
dayjs.extend(utc);
@@ -63,7 +65,7 @@ function VMTable({ vms }: { vms: NonNullable<SFCNodes.Node["vms"]>["data"] }) {
6365
borderColor="gray"
6466
>
6567
<Box width={25} padding={0}>
66-
<Text bold color="cyan">Virtual Machines</Text>
68+
<Text bold color="cyan">Previous VMs</Text>
6769
</Box>
6870
<Box width={15} padding={0}>
6971
<Text bold color="cyan">Status</Text>
@@ -268,12 +270,24 @@ function getActionsForNode(node: SFCNodes.Node) {
268270
// Component for displaying a single node in verbose format
269271
function NodeVerboseDisplay({ node }: { node: SFCNodes.Node }) {
270272
// Convert Unix timestamps to dates and calculate duration
271-
const startDate = node.start_at && dayjs.unix(node.start_at);
272-
const endDate = node.end_at && dayjs.unix(node.end_at);
273+
const startDate = node.start_at ? dayjs.unix(node.start_at) : null;
274+
const endDate = node.end_at ? dayjs.unix(node.end_at) : null;
273275
let duration = endDate && startDate && endDate.diff(startDate, "hours");
274276
if (typeof duration === "number" && duration < 1) {
275277
duration = 1;
276278
}
279+
const durationLabel = duration
280+
? formatDuration(
281+
intervalToDuration({
282+
start: 0,
283+
end: duration * 60 * 60 * 1000,
284+
}),
285+
{
286+
delimiter: ", ",
287+
format: ["years", "months", "weeks", "days", "hours"],
288+
},
289+
)
290+
: null;
277291
// Convert max_price_per_node_hour from cents to dollars
278292
const pricePerHour = node.max_price_per_node_hour
279293
? (node.max_price_per_node_hour / 100)
@@ -285,6 +299,8 @@ function NodeVerboseDisplay({ node }: { node: SFCNodes.Node }) {
285299
// Get available actions for this node
286300
const nodeActions = getActionsForNode(node);
287301

302+
const lastVM = getLastVM(node);
303+
288304
return (
289305
<Box
290306
borderStyle="single"
@@ -320,8 +336,41 @@ function NodeVerboseDisplay({ node }: { node: SFCNodes.Node }) {
320336
<Row head="Owner: " value={node.owner} />
321337
</Box>
322338

339+
{lastVM && (
340+
<>
341+
<Box marginTop={1} paddingX={1}>
342+
<Text bold color="cyan">Active VM:</Text>
343+
</Box>
344+
<Box marginLeft={3} flexDirection="column" paddingX={1}>
345+
<Row head="ID: " value={lastVM.id} />
346+
<Row head="Status: " value={getVMStatusColor(lastVM.status)} />
347+
<Row
348+
head="Start: "
349+
value={lastVM.start_at
350+
? dayjs.unix(lastVM.start_at).format("YYYY-MM-DDTHH:mm:ssZ")
351+
: "Not specified"}
352+
/>
353+
<Row
354+
head="End: "
355+
value={lastVM.end_at
356+
? dayjs.unix(lastVM.end_at).format("YYYY-MM-DDTHH:mm:ssZ")
357+
: "Not specified"}
358+
/>
359+
<Row head="Image: " value={lastVM.image_id ?? "Not specified"} />
360+
</Box>
361+
</>
362+
)}
363+
364+
{node.vms?.data && node.vms.data.length > 1 && (
365+
<Box flexDirection="column" gap={0} marginLeft={1} marginRight={2}>
366+
<Box marginTop={1} paddingX={1}>
367+
</Box>
368+
<VMTable vms={node.vms.data.slice(1)} />
369+
</Box>
370+
)}
371+
323372
<Box marginTop={1} paddingX={1}>
324-
<Text>📅 Schedule:</Text>
373+
<Text bold color="cyan">Schedule:</Text>
325374
</Box>
326375

327376
<Box marginLeft={3} flexDirection="column" paddingX={1}>
@@ -354,15 +403,15 @@ function NodeVerboseDisplay({ node }: { node: SFCNodes.Node }) {
354403
{duration && (
355404
<Row
356405
head="Duration: "
357-
value={`${duration} hours`}
406+
value={durationLabel}
358407
/>
359408
)}
360409
</Box>
361410

362411
{node.max_price_per_node_hour && (
363412
<>
364413
<Box marginTop={1} paddingX={1}>
365-
<Text>💰 Pricing:</Text>
414+
<Text bold color="cyan">Pricing:</Text>
366415
</Box>
367416
<Box marginLeft={3} flexDirection="column" paddingX={1}>
368417
{node.node_type === "autoreserved" && (
@@ -392,22 +441,10 @@ function NodeVerboseDisplay({ node }: { node: SFCNodes.Node }) {
392441
</>
393442
)}
394443

395-
{/* VMs Section - Show if node has VMs */}
396-
{node.vms?.data && node.vms.data.length > 0 && (
397-
<Box flexDirection="row" gap={0}>
398-
<Box marginTop={1} paddingX={1}>
399-
<Text color="cyan" bold>💿</Text>
400-
</Box>
401-
<Box marginTop={1}>
402-
<VMTable vms={node.vms.data} />
403-
</Box>
404-
</Box>
405-
)}
406-
407444
{node.vms?.data?.[0]?.image_id && (
408445
<>
409446
<Box marginTop={1} paddingX={1}>
410-
<Text>💾 Current VM Image:</Text>
447+
<Text bold color="cyan">Current VM Image:</Text>
411448
</Box>
412449
<Box marginLeft={3} flexDirection="column" paddingX={1}>
413450
<Row
@@ -422,7 +459,7 @@ function NodeVerboseDisplay({ node }: { node: SFCNodes.Node }) {
422459
{nodeActions.length > 0 && (
423460
<>
424461
<Box marginTop={1} paddingX={1}>
425-
<Text>🎯 Actions:</Text>
462+
<Text bold color="cyan">Actions:</Text>
426463
</Box>
427464
<Box marginLeft={3} flexDirection="column" paddingX={1}>
428465
{nodeActions.map((action, index) => (

0 commit comments

Comments
 (0)