// biome-ignore lint/style/useImportType: UMD global
import React, { useMemo } from "react";
import { Box, Text } from "ink";
import type { Capability } from "../../capability.ts";
import type { IPlan as AlchemyPlan, BindNode, CRUD } from "../../plan.ts";
export interface PlanProps {
plan: AlchemyPlan;
}
export function Plan({ plan }: PlanProps): React.JSX.Element {
const items = useMemo(
() =>
(
[
...Object.values(plan.resources),
...Object.values(plan.deletions),
] as CRUD[]
).sort((n1, n2) => n1.resource.id.localeCompare(n2.resource.id)),
[plan],
);
if (items.length === 0) {
return No changes planned;
}
const counts = items.reduce((acc, item) => (acc[item.action]++, acc), {
create: 0,
update: 0,
delete: 0,
noop: 0,
replace: 0,
});
const actions = (["create", "update", "delete", "replace"] as const).filter(
(action) => counts[action] > 0,
);
return (
Plan
:
{actions.flatMap((action, i) => {
const count = counts[action];
const color = actionColor(action);
if (count === 0) return [];
const box = (
{count} to {action}
);
return i === actions.length - 1
? [box]
: [box, | ];
})}
{items.map((item) => {
const color = actionColor(item.action);
const icon = actionIcon(item.action);
const hasBindings = item.bindings && item.bindings.length > 0;
return (
{icon}
{item.resource.id}
({item.resource.type})
{/*
{item.action}
*/}
{hasBindings && (
({item.bindings!.length} bindings)
)}
{/* Show bindings as sub-items */}
{hasBindings &&
item.bindings!.map((node) => {
const bindingColor = bindingActionColor(node.action);
const bindingIcon = bindingActionIcon(node.action);
return (
{bindingIcon}
{node.binding.capability.label}
);
})}
);
})}
);
}
type Color = Parameters[0]["color"];
const actionColor = (action: CRUD["action"]): Color =>
({
noop: "gray",
create: "green",
update: "yellow",
delete: "red",
replace: "orange",
})[action];
const actionIcon = (action: CRUD["action"]): string =>
({
create: "+",
update: "~",
delete: "-",
noop: "•",
replace: "!",
})[action];
const bindingActionColor = (
action: BindNode["action"],
): Parameters[0]["color"] =>
({
attach: "green",
detach: "red",
noop: "gray",
reattach: "orange",
})[action];
const bindingActionIcon = (action: BindNode["action"]): string =>
({
attach: "+",
detach: "-",
noop: "•",
reattach: "~",
})[action];