import { useRef, useState } from "react"; import styles from '../../VisProg.module.css'; import { GetActionValue, type Action, type ActionTypes, type Plan } from "../components/Plan"; import { defaultPlan } from "../components/Plan.default"; import { TextField } from "../../../../components/TextField"; type PlanEditorDialogProps = { plan?: Plan; onSave: (plan: Plan | undefined) => void; description? : string; }; /** * Adds an element to a React.JSX.Element that allows for the creation and editing of plans. * Renders a dialog in the current screen with buttons and text fields for names, actions and other configurability. * @param param0: Takes in a current plan, which can be undefined and a function which is called on saving with the potential plan. * @returns: JSX.Element * @example * ``` * // Within a Node's default JSX Element function * { * updateNodeData(props.id, { * ...data, * plan, * }); * }} * /> * ``` */ export default function PlanEditorDialog({ plan, onSave, description, }: PlanEditorDialogProps) { // UseStates and references const dialogRef = useRef(null); const [draftPlan, setDraftPlan] = useState(null); const [newActionType, setNewActionType] = useState("speech"); const [newActionValue, setNewActionValue] = useState(""); //Button Actions const openCreate = () => { setDraftPlan({...structuredClone(defaultPlan), id: crypto.randomUUID()}); dialogRef.current?.showModal(); }; const openCreateWithDescription = () => { setDraftPlan({...structuredClone(defaultPlan), id: crypto.randomUUID(), name: description!}); setNewActionType("llm") setNewActionValue(description!) dialogRef.current?.showModal(); } const openEdit = () => { if (!plan) return; setDraftPlan(structuredClone(plan)); dialogRef.current?.showModal(); }; const close = () => { dialogRef.current?.close(); setDraftPlan(null); }; const buildAction = (): Action => { const id = crypto.randomUUID(); switch (newActionType) { case "speech": return { id, text: newActionValue, type: "speech" }; case "gesture": return { id, gesture: newActionValue, type: "gesture" }; case "llm": return { id, goal: newActionValue, type: "llm" }; } }; return (<> {/* Create and edit buttons */} {!plan && ( )} {plan && ( )} {/* Start of dialog (plan editor) */} e.preventDefault()} >

{draftPlan?.id === plan?.id ? "Edit Plan" : "Create Plan"}

{/* Plan name text field */} {draftPlan && ( setDraftPlan({ ...draftPlan, name })} placeholder="Plan name" data-testid="name_text_field"/> )} {/* Entire "bottom" part (adder and steps) without cancel, confirm and reset */} {draftPlan && (
{/* Left Side (Action Adder) */}

Add Action

{(!plan && description && draftPlan.steps.length === 0) && (
)} {/* Action value editor */} {/* Adding steps */}
{/* Right Side (Steps shown) */}

Steps

{/* Show if there are no steps yet */} {draftPlan.steps.length === 0 && (
No steps yet
)} {/* Map over all steps, create a div for them that deletes them if clicked on and add the index, name and type. as spans */} {draftPlan.steps.map((step, index) => (
{ setDraftPlan({ ...draftPlan, steps: draftPlan.steps.filter((s) => s.id !== step.id),}); }}> {index + 1}. {step.type}: { step.type == "goal" ? ""/* TODO: Add support for goals */ : GetActionValue(step)}
))}
)} {/* End Action Editor and steps shower */} {/* Buttons */}
{/* Close button */} {/* Confirm/ Create button */} {/* Reset button */}
); }