chore: replace plan editor functionality into own folder with own files.

This commit is contained in:
Björn Otgaar
2026-01-28 12:26:57 +01:00
parent 1876138fe2
commit dcf4f01e68
16 changed files with 365 additions and 301 deletions

View File

@@ -1,279 +0,0 @@
// This program has been developed by students from the bachelor Computer Science at Utrecht
// University within the Software Project course.
// © Copyright Utrecht University (Department of Information and Computing Sciences)
import {useRef, useState} from "react";
import useFlowStore from "../VisProgStores.tsx";
import styles from './PlanEditor.module.css';
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";
type PlanEditorDialogProps = {
plan?: Plan;
onSave: (plan: Plan | undefined) => void;
description? : string;
};
/**
* Creates an action, as a step for a plan.
* @param type the type of action to build
* @param value the value of this action to build
* @param isGestureTag whether or not this action, restricted to gestures, is a tag.
* @returns An action
*/
function createAction(
type: ActionTypes,
value: string,
isGestureTag: boolean
): Action {
const id = crypto.randomUUID();
switch (type) {
case "speech":
return { id, text: value, type: "speech" };
case "gesture":
return { id, gesture: value, isTag: isGestureTag, type: "gesture" };
case "llm":
return { id, goal: value, type: "llm" };
}
}
export default function PlanEditorDialog({
plan,
onSave,
description,
}: PlanEditorDialogProps) {
// UseStates and references
const dialogRef = useRef<HTMLDialogElement | null>(null);
const [draftPlan, setDraftPlan] = useState<Plan | null>(null);
const [newActionType, setNewActionType] = useState<ActionTypes>("speech");
const [newActionGestureType, setNewActionGestureType] = useState<boolean>(true);
const [newActionValue, setNewActionValue] = useState("");
const [hasInteractedWithPlan, setHasInteractedWithPlan] = useState<boolean>(false)
const { setScrollable } = useFlowStore();
const nodes = useFlowStore().nodes;
//Button Actions
const openCreate = () => {
setScrollable(false);
setDraftPlan({...structuredClone(defaultPlan), id: crypto.randomUUID()});
dialogRef.current?.showModal();
};
const openCreateWithDescription = () => {
setScrollable(false);
setDraftPlan({...structuredClone(defaultPlan), id: crypto.randomUUID(), name: description!});
setNewActionType("llm")
setNewActionValue(description!)
dialogRef.current?.showModal();
}
const openEdit = () => {
setScrollable(false);
if (!plan) return;
setDraftPlan(structuredClone(plan));
dialogRef.current?.showModal();
};
const close = () => {
setScrollable(true);
dialogRef.current?.close();
setDraftPlan(null);
};
const buildAction = (): Action => {
const id = crypto.randomUUID();
setHasInteractedWithPlan(true)
switch (newActionType) {
case "speech":
return { id, text: newActionValue, type: "speech" };
case "gesture":
return { id, gesture: newActionValue, isTag: newActionGestureType, type: "gesture" };
case "llm":
return { id, goal: newActionValue, type: "llm" };
}
};
return (<>
{/* Create and edit buttons */}
{!plan && (
<button className={styles.nodeButton} onClick={description ? openCreateWithDescription : openCreate}>
Create Plan
</button>
)}
{plan && (
<button className={styles.nodeButton} onClick={openEdit}>
Edit Plan
</button>
)}
{/* Start of dialog (plan editor) */}
<dialog
ref={dialogRef}
className={`${styles.planDialog}`}
//onWheel={(e) => e.stopPropagation()}
data-testid={"PlanEditorDialogTestID"}
>
<form method="dialog" className="flex-col gap-md">
<h3> {draftPlan?.id === plan?.id ? "Edit Plan" : "Create Plan"} </h3>
{/* Plan name text field */}
{draftPlan && (
<TextField
value={draftPlan.name}
setValue={(name) =>
setDraftPlan({ ...draftPlan, name })}
placeholder="Plan name"
data-testid="name_text_field"/>
)}
{/* Entire "bottom" part (adder and steps) without cancel, confirm and reset */}
{draftPlan && (<div className={styles.planEditor}>
<div className={styles.planEditorLeft}>
{/* Left Side (Action Adder) */}
<h4>Add Action</h4>
{(!plan && description && draftPlan.steps.length === 0 && !hasInteractedWithPlan) && (<div className={styles.stepSuggestion}>
<label> Filled in as a suggestion! </label>
<label> Feel free to change! </label>
</div>)}
<label>
Action Type <wbr />
{/* Type selection */}
<select
value={newActionType}
onChange={(e) => {
setNewActionType(e.target.value as ActionTypes);
// Reset value when action type changes
setNewActionValue("");
}}>
<option value="speech">Speech Action</option>
<option value="gesture">Gesture Action</option>
<option value="llm">LLM Action</option>
</select>
</label>
{/* Action value editor*/}
{newActionType === "gesture" ? (
// Gesture get their own editor component
<GestureValueEditor
value={newActionValue}
setValue={setNewActionValue}
setType={setNewActionGestureType}
placeholder="Gesture name"
/>
) : (
<TextField
value={newActionValue}
setValue={setNewActionValue}
placeholder={
newActionType === "speech" ? "Speech text"
: "LLM goal"
}
/>
)}
{/* Adding steps */}
<button
type="button"
disabled={!newActionValue}
onClick={() => {
if (!draftPlan) return;
// Add action to steps
const action = buildAction();
setDraftPlan({
...draftPlan,
steps: [...draftPlan.steps, action],});
// Reset current action building
setNewActionValue("");
setNewActionType("speech");
}}>
Add Step
</button>
</div>
{/* Right Side (Steps shown) */}
<div className={styles.planEditorRight}>
<h4>Steps</h4>
{/* Show if there are no steps yet */}
{draftPlan.steps.length === 0 && (
<div className={styles.emptySteps}>
No steps yet
</div>
)}
{/* Map over all steps */}
{draftPlan.steps.map((step, index) => (
<div
role="button"
tabIndex={0}
key={step.id}
className={styles.planStep}
// Extra logic for screen readers to access using keyboard
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
setDraftPlan({
...draftPlan,
steps: draftPlan.steps.filter((s) => s.id !== step.id),});
}}}
onClick={() => {
setDraftPlan({
...draftPlan,
steps: draftPlan.steps.filter((s) => s.id !== step.id),});
}}>
<span className={styles.stepIndex}>{index + 1}.</span>
<span className={styles.stepType}>{step.type}:</span>
<span className={styles.stepName}>
{
// This just tries to find the goals name, i know it looks ugly:(
step.type === "goal"
? ((nodes.find(x => x.id === step.id)?.data.name as string) == "" ?
"unnamed goal": (nodes.find(x => x.id === step.id)?.data.name as string))
: (GetActionValue(step) ?? "")}
</span>
</div>
))}
</div>
</div>
)}
{/* Buttons */}
<div className="flex-row gap-md">
{/* Close button */}
<button type="button" onClick={close}>
Cancel
</button>
{/* Confirm/ Create button */}
<button
type="button"
disabled={!draftPlan}
onClick={() => {
if (!draftPlan) return;
onSave(draftPlan);
close();
}}>
{draftPlan?.id === plan?.id ? "Confirm" : "Create"}
</button>
{/* Reset button */}
<button
type="button"
disabled={!draftPlan}
onClick={() => {
onSave(undefined);
close();
}}>
Reset
</button>
</div>
</form>
</dialog>
</>
);
}

View File

@@ -0,0 +1,72 @@
import { TextField } from "../../../../../components/TextField";
import GestureValueEditor from "./GestureValueEditor";
import type { ActionTypes } from "./Plan";
import styles from './PlanEditor.module.css';
type ActionAdderProps = {
newActionType: ActionTypes;
setNewActionType: (t: ActionTypes) => void;
newActionValue: string;
setNewActionValue: (v: string) => void;
setNewActionGestureType: (b: boolean) => void;
onAdd: () => void;
showSuggestion: boolean;
};
export function ActionAdder({
newActionType,
setNewActionType,
newActionValue,
setNewActionValue,
setNewActionGestureType,
onAdd,
showSuggestion,
}: ActionAdderProps) {
return (
<div className={styles.planEditorLeft}>
<h4>Add Action</h4>
{showSuggestion && (
<div className={styles.stepSuggestion}>
<label>Filled in as a suggestion!</label>
<label>Feel free to change!</label>
</div>
)}
<label>
Action Type <wbr />
<select
value={newActionType}
onChange={(e) => {
setNewActionType(e.target.value as ActionTypes);
setNewActionValue("");
}}
>
<option value="speech">Speech Action</option>
<option value="gesture">Gesture Action</option>
<option value="llm">LLM Action</option>
</select>
</label>
{newActionType === "gesture" ? (
<GestureValueEditor
value={newActionValue}
setValue={setNewActionValue}
setType={setNewActionGestureType}
placeholder="Gesture name"
/>
) : (
<TextField
value={newActionValue}
setValue={setNewActionValue}
placeholder={newActionType === "speech" ? "Speech text" : "LLM goal"}
/>
)}
<button type="button" disabled={!newActionValue} onClick={onAdd}>
Add Step
</button>
</div>
);
}

View File

@@ -1,8 +1,8 @@
{/* /*
This program has been developed by students from the bachelor Computer Science at Utrecht This program has been developed by students from the bachelor Computer Science at Utrecht
University within the Software Project course. University within the Software Project course.
© Copyright Utrecht University (Department of Information and Computing Sciences) © Copyright Utrecht University (Department of Information and Computing Sciences)
*/} */
.gestureEditor { .gestureEditor {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@@ -2,7 +2,7 @@
// University within the Software Project course. // University within the Software Project course.
// © Copyright Utrecht University (Department of Information and Computing Sciences) // © Copyright Utrecht University (Department of Information and Computing Sciences)
import { type Node } from "@xyflow/react" import { type Node } from "@xyflow/react"
import { GoalReduce } from "../nodes/GoalNode" import { GoalReduce } from "../../nodes/GoalNode"
export type Plan = { export type Plan = {
@@ -124,4 +124,6 @@ export function GetActionValue(action: Action) {
return returnAction.goal; return returnAction.goal;
default: default:
} }
} }

View File

@@ -2,7 +2,7 @@
// University within the Software Project course. // University within the Software Project course.
// © Copyright Utrecht University (Department of Information and Computing Sciences) // © Copyright Utrecht University (Department of Information and Computing Sciences)
// This file is to avoid sharing both functions and components which eslint dislikes. :) // This file is to avoid sharing both functions and components which eslint dislikes. :)
import type { GoalNode } from "../nodes/GoalNode" import type { GoalNode } from "../../nodes/GoalNode"
import type { Goal, Plan } from "./Plan" import type { Goal, Plan } from "./Plan"
/** /**
@@ -35,4 +35,5 @@ export function deleteGoalInPlanByID(plan: Plan, goalID: string) {
steps: plan.steps.filter((x) => x.id !== goalID) steps: plan.steps.filter((x) => x.id !== goalID)
} }
return updatedPlan.steps.length == 0 ? undefined : updatedPlan return updatedPlan.steps.length == 0 ? undefined : updatedPlan
} }

View File

@@ -1,8 +1,8 @@
{/* /*
This program has been developed by students from the bachelor Computer Science at Utrecht This program has been developed by students from the bachelor Computer Science at Utrecht
University within the Software Project course. University within the Software Project course.
© Copyright Utrecht University (Department of Information and Computing Sciences) © Copyright Utrecht University (Department of Information and Computing Sciences)
*/} */
.planDialog { .planDialog {
overflow:visible; overflow:visible;
width: 80vw; width: 80vw;

View File

@@ -0,0 +1,214 @@
// This program has been developed by students from the bachelor Computer Science at Utrecht
// University within the Software Project course.
// © Copyright Utrecht University (Department of Information and Computing Sciences)
import {useRef, useState} from "react";
import useFlowStore from "../../VisProgStores.tsx";
import styles from './PlanEditor.module.css';
import { type Action, type ActionTypes, type Plan } from "./Plan.tsx";
import { defaultPlan } from "./Plan.default.ts";
import { TextField } from "../../../../../components/TextField.tsx";
import { StepsList } from "./StepList.tsx";
import { ActionAdder } from "./ActionAdder.tsx";
type PlanEditorDialogProps = {
plan?: Plan;
onSave: (plan: Plan | undefined) => void;
description? : string;
};
/**
* Creates an action, as a step for a plan.
* @param type the type of action to build
* @param value the value of this action to build
* @param isGestureTag whether or not this action, restricted to gestures, is a tag.
* @returns An action
*/
function buildAction(
type: ActionTypes,
value: string,
isGestureTag: boolean
): Action {
const id = crypto.randomUUID();
switch (type) {
case "speech":
return { id, text: value, type: "speech" };
case "gesture":
return { id, gesture: value, isTag: isGestureTag, type: "gesture" };
case "llm":
return { id, goal: value, type: "llm" };
}
}
export default function PlanEditorDialog({
plan,
onSave,
description,
}: PlanEditorDialogProps) {
// UseStates and references
const dialogRef = useRef<HTMLDialogElement | null>(null);
const [draftPlan, setDraftPlan] = useState<Plan | null>(null);
const [newActionType, setNewActionType] = useState<ActionTypes>("speech");
const [newActionGestureType, setNewActionGestureType] = useState<boolean>(true);
const [newActionValue, setNewActionValue] = useState("");
const [hasInteractedWithPlan, setHasInteractedWithPlan] = useState<boolean>(false)
const { setScrollable } = useFlowStore();
const nodes = useFlowStore().nodes;
//Button Actions
const openCreate = () => {
setScrollable(false);
setDraftPlan({...structuredClone(defaultPlan), id: crypto.randomUUID()});
dialogRef.current?.showModal();
};
const openCreateWithDescription = () => {
setScrollable(false);
setDraftPlan({...structuredClone(defaultPlan), id: crypto.randomUUID(), name: description!});
setNewActionType("llm")
setNewActionValue(description!)
dialogRef.current?.showModal();
}
const openEdit = () => {
setScrollable(false);
if (!plan) return;
setDraftPlan(structuredClone(plan));
dialogRef.current?.showModal();
};
const close = () => {
setScrollable(true);
dialogRef.current?.close();
setDraftPlan(null);
};
const addAction = () => {
if (!draftPlan) return;
// Add action to steps
const action = buildAction(newActionType, newActionValue, newActionGestureType);
setDraftPlan({
...draftPlan,
steps: [...draftPlan.steps, action],});
// Reset current action building
setNewActionValue("");
setNewActionType("speech");
setHasInteractedWithPlan(true);
}
const showSuggestion : boolean = (
!plan &&
!!description &&
draftPlan !== null &&
draftPlan.steps.length === 0 &&
!hasInteractedWithPlan)
return (<>
{/* Create and edit buttons */}
{!plan && (
<button className={styles.nodeButton} onClick={description ? openCreateWithDescription : openCreate}>
Create Plan
</button>
)}
{plan && (
<button className={styles.nodeButton} onClick={openEdit}>
Edit Plan
</button>
)}
{/* Start of dialog (plan editor) */}
<dialog
ref={dialogRef}
className={`${styles.planDialog}`}
//onWheel={(e) => e.stopPropagation()}
data-testid={"PlanEditorDialogTestID"}
>
<form method="dialog" className="flex-col gap-md">
<h3> {draftPlan?.id === plan?.id ? "Edit Plan" : "Create Plan"} </h3>
{/* Plan name text field */}
{draftPlan && (
<TextField
value={draftPlan.name}
setValue={(name) =>
setDraftPlan({ ...draftPlan, name })}
placeholder="Plan name"
data-testid="name_text_field"/>
)}
{/* Entire "bottom" part (adder and steps) without cancel, confirm and reset */}
{draftPlan && (<div className={styles.planEditor}>
<div className={styles.planEditorLeft}>
{/* Left Side (Action Adder) */}
<ActionAdder
newActionType={newActionType}
setNewActionType={setNewActionType}
newActionValue={newActionValue}
setNewActionValue={setNewActionValue}
setNewActionGestureType={setNewActionGestureType}
onAdd={addAction}
showSuggestion={showSuggestion}
/>
</div>
{/* Right Side (Steps shown) */}
<div className={styles.planEditorRight}>
<h4>Steps</h4>
{/* Map over all steps */}
<StepsList
steps={draftPlan.steps}
nodes={nodes}
onRemove={(id) =>
setDraftPlan({
...draftPlan,
steps: draftPlan.steps.filter(s => s.id !== id),
})
}
/>
</div>
</div>
)}
{/* Buttons */}
<div className="flex-row gap-md">
{/* Close button */}
<button type="button" onClick={close}>
Cancel
</button>
{/* Confirm/ Create button */}
<button
type="button"
disabled={!draftPlan}
onClick={() => {
if (!draftPlan) return;
onSave(draftPlan);
close();
}}>
{draftPlan?.id === plan?.id ? "Confirm" : "Create"}
</button>
{/* Reset button */}
<button
type="button"
disabled={!draftPlan}
onClick={() => {
onSave(undefined);
close();
}}>
Reset
</button>
</div>
</form>
</dialog>
</>
);
}

View File

@@ -0,0 +1,54 @@
import { GetActionValue, type PlanElement } from "./Plan";
import styles from './PlanEditor.module.css';
import { type Node} from "@xyflow/react"
type StepsListProps = {
steps: PlanElement[];
onRemove: (id: string) => void;
nodes: Node[];
};
function getStepLabel(
step: PlanElement,
nodes: Node[],
): string {
if (step.type === "goal") {
// For goals, we lookup the value through the nodes in the diagram
const node = nodes.find(n => n.id === step.id);
return (node?.data?.name as string)?.trim() || "unnamed goal";
}
// Not a goal, we lookup the correct action value of the action
return GetActionValue(step) ?? "";
}
export function StepsList({ steps, onRemove, nodes }: StepsListProps) {
if (steps.length === 0) {
return <div className={styles.emptySteps}>No steps yet</div>;
}
return (
<>
{steps.map((step, index) => (
<div
key={step.id}
role="button"
tabIndex={0}
className={styles.planStep}
onClick={() => onRemove(step.id)}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
onRemove(step.id);
}
}}
>
<span className={styles.stepIndex}>{index + 1}.</span>
<span className={styles.stepType}>{step.type}:</span>
<span className={styles.stepName}>
{getStepLabel(step, nodes)}
</span>
</div>
))}
</>
);
}

View File

@@ -14,11 +14,11 @@ import { TextField } from '../../../../components/TextField';
import {MultiConnectionHandle} from "../components/RuleBasedHandle.tsx"; import {MultiConnectionHandle} from "../components/RuleBasedHandle.tsx";
import {allowOnlyConnectionsFromHandle, allowOnlyConnectionsFromType} from "../HandleRules.ts"; import {allowOnlyConnectionsFromHandle, allowOnlyConnectionsFromType} from "../HandleRules.ts";
import useFlowStore from '../VisProgStores'; import useFlowStore from '../VisProgStores';
import {DoesPlanIterate, HasCheckingSubGoal, PlanReduce, type Plan } from '../components/Plan'; import {DoesPlanIterate, HasCheckingSubGoal, PlanReduce, type Plan } from '../components/PlanEditor/Plan.tsx';
import PlanEditorDialog from '../components/PlanEditor'; import PlanEditorDialog from '../components/PlanEditor/PlanEditor.tsx';
import { MultilineTextField } from '../../../../components/MultilineTextField'; import { MultilineTextField } from '../../../../components/MultilineTextField';
import { defaultPlan } from '../components/Plan.default.ts'; import { defaultPlan } from '../components/PlanEditor/Plan.default.ts';
import { deleteGoalInPlanByID, insertGoalInPlan } from '../components/PlanEditingFunctions.tsx'; import { deleteGoalInPlanByID, insertGoalInPlan } from '../components/PlanEditor/PlanEditingFunctions.tsx';
/** /**
* The default data dot a phase node * The default data dot a phase node

View File

@@ -13,12 +13,12 @@ import styles from '../../VisProg.module.css';
import {MultiConnectionHandle, SingleConnectionHandle} from "../components/RuleBasedHandle.tsx"; import {MultiConnectionHandle, SingleConnectionHandle} from "../components/RuleBasedHandle.tsx";
import {allowOnlyConnectionsFromHandle, allowOnlyConnectionsFromType} from "../HandleRules.ts"; import {allowOnlyConnectionsFromHandle, allowOnlyConnectionsFromType} from "../HandleRules.ts";
import useFlowStore from '../VisProgStores'; import useFlowStore from '../VisProgStores';
import {PlanReduce, type Plan } from '../components/Plan'; import {PlanReduce, type Plan } from '../components/PlanEditor/Plan.tsx';
import PlanEditorDialog from '../components/PlanEditor'; import PlanEditorDialog from '../components/PlanEditor/PlanEditor.tsx';
import {BeliefGlobalReduce} from "./BeliefGlobals.ts"; import {BeliefGlobalReduce} from "./BeliefGlobals.ts";
import type { GoalNode } from './GoalNode.tsx'; import type { GoalNode } from './GoalNode.tsx';
import { defaultPlan } from '../components/Plan.default.ts'; import { defaultPlan } from '../components/PlanEditor/Plan.default.ts';
import { deleteGoalInPlanByID, insertGoalInPlan } from '../components/PlanEditingFunctions.tsx'; import { deleteGoalInPlanByID, insertGoalInPlan } from '../components/PlanEditor/PlanEditingFunctions.tsx';
import { TextField } from '../../../../components/TextField.tsx'; import { TextField } from '../../../../components/TextField.tsx';
/** /**

View File

@@ -4,7 +4,7 @@
import { useState } from 'react'; import { useState } from 'react';
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
import { renderWithProviders, screen } from '../../../../test-utils/test-utils.tsx'; import { renderWithProviders, screen } from '../../../../test-utils/test-utils.tsx';
import GestureValueEditor from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/GestureValueEditor'; import GestureValueEditor from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor/GestureValueEditor.tsx';
function TestHarness({ initialValue = '', initialType=true, placeholder = 'Gesture name' } : { initialValue?: string, initialType?: boolean, placeholder?: string }) { function TestHarness({ initialValue = '', initialType=true, placeholder = 'Gesture name' } : { initialValue?: string, initialType?: boolean, placeholder?: string }) {
const [value, setValue] = useState(initialValue); const [value, setValue] = useState(initialValue);

View File

@@ -6,12 +6,12 @@ import { screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
import type { Node } from '@xyflow/react'; import type { Node } from '@xyflow/react';
import { renderWithProviders } from '../../../../test-utils/test-utils.tsx'; import { renderWithProviders } from '../../../../test-utils/test-utils.tsx';
import PlanEditorDialog from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor'; import PlanEditorDialog from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor/PlanEditor.tsx';
import { PlanReduce, type Plan } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/Plan'; import { PlanReduce, type Plan } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor/Plan.tsx';
import '@testing-library/jest-dom'; import '@testing-library/jest-dom';
import { GoalReduce, type GoalNodeData } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/GoalNode.tsx'; import { GoalReduce, type GoalNodeData } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/GoalNode.tsx';
import { GoalNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/GoalNode.default.ts'; import { GoalNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/GoalNode.default.ts';
import { insertGoalInPlan } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/PlanEditingFunctions.tsx'; import { insertGoalInPlan } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor/PlanEditingFunctions.tsx';
// Mock structuredClone // Mock structuredClone

View File

@@ -10,7 +10,7 @@ import useFlowStore from '../../../../../src/pages/VisProgPage/visualProgramming
import type { Node } from '@xyflow/react'; import type { Node } from '@xyflow/react';
import '@testing-library/jest-dom'; import '@testing-library/jest-dom';
import { GoalNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/GoalNode.default.ts'; import { GoalNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/GoalNode.default.ts';
import { defaultPlan } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/Plan.default.ts'; import { defaultPlan } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor/Plan.default.ts';
describe('GoalNode', () => { describe('GoalNode', () => {
let user: ReturnType<typeof userEvent.setup>; let user: ReturnType<typeof userEvent.setup>;

View File

@@ -14,7 +14,7 @@ import type { Node } from '@xyflow/react';
import '@testing-library/jest-dom'; import '@testing-library/jest-dom';
import { TriggerNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/TriggerNode.default.ts'; import { TriggerNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/TriggerNode.default.ts';
import { BasicBeliefNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/BasicBeliefNode.default.ts'; import { BasicBeliefNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/BasicBeliefNode.default.ts';
import { defaultPlan } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/Plan.default.ts'; import { defaultPlan } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/components/PlanEditor/Plan.default.ts';
import { NormNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/NormNode.default.ts'; import { NormNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/NormNode.default.ts';
import { GoalNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/GoalNode.default.ts'; import { GoalNodeDefaults } from '../../../../../src/pages/VisProgPage/visualProgrammingUI/nodes/GoalNode.default.ts';
import { act } from '@testing-library/react'; import { act } from '@testing-library/react';