diff --git a/src/pages/VisProgPage/VisProg.module.css b/src/pages/VisProgPage/VisProg.module.css index 429e740..11db5cc 100644 --- a/src/pages/VisProgPage/VisProg.module.css +++ b/src/pages/VisProgPage/VisProg.module.css @@ -144,4 +144,12 @@ opacity: 0.5; font-style: italic; text-decoration: line-through; +} + +.bottomLeftHandle { + left: 40% !important; +} + +.bottomRightHandle { + left: 60% !important; } \ No newline at end of file diff --git a/src/pages/VisProgPage/visualProgrammingUI/components/Plan.default.ts b/src/pages/VisProgPage/visualProgrammingUI/components/Plan.default.ts index b2ea31b..87d7d94 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/components/Plan.default.ts +++ b/src/pages/VisProgPage/visualProgrammingUI/components/Plan.default.ts @@ -1,7 +1,7 @@ -import type { Plan } from "./Plan"; +import type { Plan, PlanElement } from "./Plan"; export const defaultPlan: Plan = { name: "Default Plan", id: "-1", - steps: [], + steps: [] as PlanElement[], } \ No newline at end of file diff --git a/src/pages/VisProgPage/visualProgrammingUI/components/Plan.tsx b/src/pages/VisProgPage/visualProgrammingUI/components/Plan.tsx index dbf38be..e8161c1 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/components/Plan.tsx +++ b/src/pages/VisProgPage/visualProgrammingUI/components/Plan.tsx @@ -1,3 +1,6 @@ +import { GoalReduce, type GoalNode } from "../nodes/GoalNode" +import { type Node } from "@xyflow/react" + export type Plan = { name: string, id: string, @@ -5,13 +8,9 @@ export type Plan = { } export type PlanElement = Goal | Action -export type PlanElementTypes = ActionTypes | "goal" export type Goal = { - id: string, - name: string, - plan: Plan, - can_fail: boolean, + id: string // we let the reducer figure out the rest dynamically type: "goal" } @@ -20,22 +19,21 @@ export type Action = SpeechAction | GestureAction | LLMAction export type SpeechAction = { id: string, text: string, type:"speech" } export type GestureAction = { id: string, gesture: string, isTag: boolean, type:"gesture" } export type LLMAction = { id: string, goal: string, type:"llm" } - -export type ActionTypes = "speech" | "gesture" | "llm" +export type ActionTypes = "speech" | "gesture" | "llm"; // Extract the wanted information from a plan within the reducing of nodes -export function PlanReduce(plan?: Plan) { +export function PlanReduce(_nodes: Node[], plan?: Plan, ) { if (!plan) return "" return { id: plan.id, - steps: plan.steps.map((x) => StepReduce(x)) + steps: plan.steps.map((x) => StepReduce(x, _nodes)) } } // Extract the wanted information from a plan element. -function StepReduce(planElement: PlanElement) { +function StepReduce(planElement: PlanElement, _nodes: Node[]) : Record { // We have different types of plan elements, requiring differnt types of output switch (planElement.type) { case ("speech"): @@ -57,12 +55,9 @@ function StepReduce(planElement: PlanElement) { goal: planElement.goal, } case ("goal"): - return { - id: planElement.id, - plan: planElement.plan, - can_fail: planElement.can_fail, - }; - default: + const nodes = _nodes + const thisNode = _nodes.find((x) => x.id === planElement.id) + return thisNode ? GoalReduce(thisNode, nodes) : {} } } @@ -75,7 +70,7 @@ function StepReduce(planElement: PlanElement) { export function DoesPlanIterate(plan?: Plan) : boolean { // TODO: should recursively check plans that have goals (and thus more plans) in them. if (!plan) return false - return plan.steps.filter((step) => step.type == "llm").length > 0 || (plan.steps.filter((x) => x.type == "goal").map((x) => DoesPlanIterate(x.plan))).includes(true); + return plan.steps.filter((step) => step.type == "llm").length > 0; } /** @@ -99,4 +94,28 @@ export function GetActionValue(action: Action) { return returnAction.goal; default: } +} + +/** + * Inserts a goal into a plan + * @param plan: plan to insert goal into + * @param goalNode: the goal node to insert into the plan. + * @returns: a new plan with the goal inside. + */ +export function insertGoalInPlan(plan: Plan, goalNode: GoalNode): Plan { + const planElement : Goal = { + id: goalNode.id, + type: "goal", + } + + return { + ...plan, + steps: [...plan.steps, planElement], + } +} + +export function deleteGoalInPlanByID(plan: Plan, goalID: string): Plan { + return {...plan, + steps: plan.steps.filter((x) => x.id !== goalID) + } } \ No newline at end of file diff --git a/src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor.tsx b/src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor.tsx index f303900..10ce06d 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor.tsx +++ b/src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor.tsx @@ -1,7 +1,7 @@ import {useRef, useState} from "react"; import useFlowStore from "../VisProgStores.tsx"; import styles from './PlanEditor.module.css'; -import { GetActionValue, type Action, type ActionTypes, type Goal, type Plan, type PlanElement, type PlanElementTypes } from "../components/Plan"; +import { GetActionValue, type Action, type ActionTypes, type Plan } from "../components/Plan"; import { defaultPlan } from "../components/Plan.default"; import { TextField } from "../../../../components/TextField"; import GestureValueEditor from "./GestureValueEditor"; @@ -21,10 +21,10 @@ export default function PlanEditorDialog({ const dialogRef = useRef(null); const [draftPlan, setDraftPlan] = useState(null); const [newActionType, setNewActionType] = useState("speech"); - const [newPlanElementType, setNewPlanElementType] = useState("speech") const [newActionGestureType, setNewActionGestureType] = useState(true); const [newActionValue, setNewActionValue] = useState(""); const { setScrollable } = useFlowStore(); + const nodes = useFlowStore().nodes; //Button Actions const openCreate = () => { @@ -58,24 +58,14 @@ export default function PlanEditorDialog({ const id = crypto.randomUUID(); switch (newActionType) { case "speech": - return { id, text: newPlanElementType, type: "speech" }; + return { id, text: newActionValue, type: "speech" }; case "gesture": - return { id, gesture: newPlanElementType, isTag: newActionGestureType, type: "gesture" }; + return { id, gesture: newActionValue, isTag: newActionGestureType, type: "gesture" }; case "llm": - return { id, goal: newPlanElementType, type: "llm" }; + return { id, goal: newActionValue, type: "llm" }; } }; - const buildGoal = (): Goal => { - return { - id: "", - name: "", - plan: defaultPlan, - can_fail: false, - type: "goal" - } - } - return (<> {/* Create and edit buttons */} {!plan && ( @@ -121,21 +111,20 @@ export default function PlanEditorDialog({ Action Type {/* Type selection */} {/* Action value editor*/} - {newPlanElementType === "gesture" ? ( + {newActionType === "gesture" ? ( // Gesture get their own editor component - ) - : (newPlanElementType === "goal" ? ( -
- - -
- ) - : - // Only used for the Speech and LLM elements - ( + ) : ( - ))} + )} {/* Adding steps */}