Add experiment logs to the monitoring page #48

Merged
0950726 merged 122 commits from feat/experiment-logs into dev 2026-01-28 10:16:00 +00:00
5 changed files with 87 additions and 20 deletions
Showing only changes of commit a00fd02634 - Show all commits

View File

@@ -238,12 +238,15 @@ function VisProgPage() {
const [programValidity, setProgramValidity] = useState<boolean>(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 (
<>
<VisualProgrammingUI/>

View File

@@ -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,

View File

@@ -1,4 +1,6 @@
.warnings-sidebar {
min-width: 320px;
max-width: 320px;
width: 320px;
height: 100%;
background: canvas;

View File

@@ -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<TriggerNodeData>
*/
export default function TriggerNode(props: NodeProps<TriggerNode>) {
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 <>
<Toolbar nodeId={props.id} allowDelete={true}/>

View File

@@ -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);
});
});