diff --git a/src/pages/VisProgPage/VisProg.tsx b/src/pages/VisProgPage/VisProg.tsx index 99a4a38..011c1ec 100644 --- a/src/pages/VisProgPage/VisProg.tsx +++ b/src/pages/VisProgPage/VisProg.tsx @@ -238,12 +238,15 @@ function VisProgPage() { const [programValidity, setProgramValidity] = useState(true); const {isProgramValid, severityIndex} = useFlowStore(); + const validity = () => {return isProgramValid();} + useEffect(() => { - setProgramValidity(isProgramValid); + setProgramValidity(validity); // the following eslint disable is required as it wants us to use all possible dependencies for the useEffect statement, // however this would cause unneeded updates // eslint-disable-next-line react-hooks/exhaustive-deps }, [severityIndex]); + console.log(programValidity); return ( <> diff --git a/src/pages/VisProgPage/visualProgrammingUI/components/EditorWarnings.tsx b/src/pages/VisProgPage/visualProgrammingUI/components/EditorWarnings.tsx index e394502..12438e6 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/components/EditorWarnings.tsx +++ b/src/pages/VisProgPage/visualProgrammingUI/components/EditorWarnings.tsx @@ -106,8 +106,8 @@ export function editorWarningRegistry(get: ZustandGet, set: ZustandSet) : Editor ]), getWarningsBySeverity: (warningSeverity) => { - const wRegistry = get().editorWarningRegistry; - const sIndex = get().severityIndex; + const wRegistry = new Map([...get().editorWarningRegistry].map(([k, v]) => [k, new Map(v)])); + const sIndex = new Map(get().severityIndex); const warningKeys = sIndex.get(warningSeverity); const warnings: EditorWarning[] = []; @@ -138,8 +138,8 @@ export function editorWarningRegistry(get: ZustandGet, set: ZustandSet) : Editor const { scope: {id, handleId}, type, severity } = warning; const warningKey = handleId ? `${type}:${handleId}` : type; const compositeKey = `${id}|${warningKey}`; - const wRegistry = get().editorWarningRegistry; - const sIndex = get().severityIndex; + const wRegistry = new Map([...get().editorWarningRegistry].map(([k, v]) => [k, new Map(v)])); + const sIndex = new Map(get().severityIndex); // add to warning registry if (!wRegistry.has(id)) { wRegistry.set(id, new Map()); @@ -159,8 +159,8 @@ export function editorWarningRegistry(get: ZustandGet, set: ZustandSet) : Editor }, unregisterWarning: (id, warningKey) => { - const wRegistry = get().editorWarningRegistry; - const sIndex = get().severityIndex; + const wRegistry = new Map([...get().editorWarningRegistry].map(([k, v]) => [k, new Map(v)])); + const sIndex = new Map(get().severityIndex); // verify if the warning was created already const warning = wRegistry.get(id)?.get(warningKey); if (!warning) return; @@ -179,8 +179,8 @@ export function editorWarningRegistry(get: ZustandGet, set: ZustandSet) : Editor }, unregisterWarningsForId: (id) => { - const wRegistry = get().editorWarningRegistry; - const sIndex = get().severityIndex; + const wRegistry = new Map([...get().editorWarningRegistry].map(([k, v]) => [k, new Map(v)])); + const sIndex = new Map(get().severityIndex); const nodeWarnings = wRegistry.get(id); @@ -196,7 +196,6 @@ export function editorWarningRegistry(get: ZustandGet, set: ZustandSet) : Editor // remove from warning registry wRegistry.delete(id); - console.log(wRegistry.get(id)); set({ editorWarningRegistry: wRegistry, diff --git a/src/pages/VisProgPage/visualProgrammingUI/components/WarningSidebar.module.css b/src/pages/VisProgPage/visualProgrammingUI/components/WarningSidebar.module.css index 05c89bd..c0d0c24 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/components/WarningSidebar.module.css +++ b/src/pages/VisProgPage/visualProgrammingUI/components/WarningSidebar.module.css @@ -1,4 +1,6 @@ .warnings-sidebar { + min-width: 320px; + max-width: 320px; width: 320px; height: 100%; background: canvas; diff --git a/src/pages/VisProgPage/visualProgrammingUI/nodes/TriggerNode.tsx b/src/pages/VisProgPage/visualProgrammingUI/nodes/TriggerNode.tsx index 7a32da2..61f299b 100644 --- a/src/pages/VisProgPage/visualProgrammingUI/nodes/TriggerNode.tsx +++ b/src/pages/VisProgPage/visualProgrammingUI/nodes/TriggerNode.tsx @@ -1,8 +1,10 @@ import { type NodeProps, Position, - type Node, + type Node, useNodeConnections } from '@xyflow/react'; +import {useEffect} from "react"; +import type {EditorWarning} from "../components/EditorWarnings.tsx"; import { Toolbar } from '../components/NodeComponents'; import styles from '../../VisProg.module.css'; import {MultiConnectionHandle, SingleConnectionHandle} from "../components/RuleBasedHandle.tsx"; @@ -45,12 +47,77 @@ export type TriggerNode = Node */ export default function TriggerNode(props: NodeProps) { const data = props.data; - const {updateNodeData} = useFlowStore(); + const {updateNodeData, registerWarning, unregisterWarning} = useFlowStore(); const setName= (value: string) => { updateNodeData(props.id, {...data, name: value}) } - + + const beliefInput = useNodeConnections({ + id: props.id, + handleType: "target", + handleId: "TriggerBeliefs" + }) + + const outputCons = useNodeConnections({ + id: props.id, + handleType: "source", + handleId: "TriggerSource" + }) + + useEffect(() => { + const noPhaseConnectionWarning : EditorWarning = { + scope: { + id: props.id, + handleId: 'TriggerSource' + }, + type: 'MISSING_OUTPUT', + severity: 'INFO', + description: "This triggerNode is missing a condition/belief, please make sure to connect a belief node to " + }; + + if (outputCons.length === 0){ + registerWarning(noPhaseConnectionWarning); + return; + } + unregisterWarning(props.id, `${noPhaseConnectionWarning.type}:${noPhaseConnectionWarning.scope.handleId}`); + },[outputCons.length, props.id, registerWarning, unregisterWarning]) + + useEffect(() => { + const noBeliefWarning : EditorWarning = { + scope: { + id: props.id, + handleId: 'TriggerBeliefs' + }, + type: 'MISSING_INPUT', + severity: 'ERROR', + description: "This triggerNode is missing a condition/belief, please make sure to connect a belief node to " + }; + + if (beliefInput.length === 0 && outputCons.length !== 0){ + registerWarning(noBeliefWarning); + return; + } + unregisterWarning(props.id, `${noBeliefWarning.type}:${noBeliefWarning.scope.handleId}`); + },[beliefInput.length, outputCons.length, props.id, registerWarning, unregisterWarning]) + + useEffect(() => { + const noPlanWarning : EditorWarning = { + scope: { + id: props.id, + handleId: undefined + }, + type: 'PLAN_IS_UNDEFINED', + severity: 'ERROR', + description: "This triggerNode is missing a plan, please make sure to create a plan by using the create plan button" + }; + + if (!data.plan && outputCons.length !== 0){ + registerWarning(noPlanWarning); + return; + } + unregisterWarning(props.id, noPlanWarning.type); + },[data.plan, outputCons.length, props.id, registerWarning, unregisterWarning]) return <> diff --git a/test/pages/visProgPage/visualProgrammingUI/components/EditorWarnings.test.tsx b/test/pages/visProgPage/visualProgrammingUI/components/EditorWarnings.test.tsx index a3c2935..8351c8d 100644 --- a/test/pages/visProgPage/visualProgrammingUI/components/EditorWarnings.test.tsx +++ b/test/pages/visProgPage/visualProgrammingUI/components/EditorWarnings.test.tsx @@ -33,19 +33,15 @@ describe("editorWarnings", () => { const warning = makeWarning({ scope: { id: 'node-1', handleId: 'input-1' }, }); - const {registerWarning, editorWarningRegistry} = useFlowStore.getState() + const {registerWarning} = useFlowStore.getState() registerWarning(warning); - - const nodeWarnings = editorWarningRegistry.get('node-1'); - - expect(nodeWarnings?.has('MISSING_INPUT:input-1')).toBe(true); + const nodeWarnings = useFlowStore.getState().editorWarningRegistry.get('node-1'); + expect(nodeWarnings?.has('MISSING_INPUT:input-1') === true).toBe(true); }); it('updates severityIndex correctly', () => { const {registerWarning, severityIndex} = useFlowStore.getState() registerWarning(makeWarning()); - - console.log(severityIndex); expect(severityIndex.get('ERROR')!.size).toBe(1); }); });