// 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];