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
6 changed files with 61 additions and 12 deletions
Showing only changes of commit 8b40001038 - Show all commits

View File

@@ -119,7 +119,7 @@ const VisProgUI = () => {
<SaveLoadPanel></SaveLoadPanel> <SaveLoadPanel></SaveLoadPanel>
</Panel> </Panel>
<Panel position="bottom-center"> <Panel position="bottom-center">
<button onClick={() => undo()}>undo</button> <button onClick={() => undo()}>Undo</button>
<button onClick={() => redo()}>Redo</button> <button onClick={() => redo()}>Redo</button>
</Panel> </Panel>
<Controls/> <Controls/>
@@ -175,7 +175,7 @@ function VisProgPage() {
return ( return (
<> <>
<VisualProgrammingUI/> <VisualProgrammingUI/>
<button onClick={runProgram}>run program</button> <button onClick={runProgram}>Run Program</button>
</> </>
) )
} }

View File

@@ -108,3 +108,15 @@ export function useHandleRules(
return evaluateRules(targetRules, connection, context); return evaluateRules(targetRules, connection, context);
}; };
} }
export function validateConnectionWithRules(
connection: Connection,
context: ConnectionContext
): RuleResult {
const rules = useFlowStore.getState().getTargetRules(
connection.target!,
connection.targetHandle!
);
return evaluateRules(rules,connection, context);
}

View File

@@ -9,6 +9,7 @@ import {
type XYPosition, type XYPosition,
} from '@xyflow/react'; } from '@xyflow/react';
import '@xyflow/react/dist/style.css'; import '@xyflow/react/dist/style.css';
import {type ConnectionContext, validateConnectionWithRules} from "./HandleRuleLogic.ts";
import type { FlowState } from './VisProgTypes'; import type { FlowState } from './VisProgTypes';
import { import {
NodeDefaults, NodeDefaults,
@@ -129,7 +130,41 @@ const useFlowStore = create<FlowState>(UndoRedo((set, get) => ({
* Handles reconnecting an edge between nodes. * Handles reconnecting an edge between nodes.
*/ */
onReconnect: (oldEdge, newConnection) => { onReconnect: (oldEdge, newConnection) => {
get().edgeReconnectSuccessful = true;
function createContext(
source: {id: string, handleId: string},
target: {id: string, handleId: string}
) : ConnectionContext {
const edges = get().edges;
const targetConnections = edges.filter(edge => edge.target === target.id && edge.targetHandle === target.handleId).length
return {
connectionCount: targetConnections,
source: source,
target: target
}
}
// connection validation
const context: ConnectionContext = oldEdge.source === newConnection.source
? createContext({id: newConnection.source, handleId: newConnection.sourceHandle!}, {id: newConnection.target, handleId: newConnection.targetHandle!})
: createContext({id: newConnection.target, handleId: newConnection.targetHandle!}, {id: newConnection.source, handleId: newConnection.sourceHandle!});
const result = validateConnectionWithRules(
newConnection,
context
);
if (!result.isSatisfied) {
set({
edges: get().edges.map(e =>
e.id === oldEdge.id ? oldEdge : e
),
});
return;
}
// further reconnect logic
set({ edgeReconnectSuccessful: true });
set({ edges: reconnectEdge(oldEdge, newConnection, get().edges) }); set({ edges: reconnectEdge(oldEdge, newConnection, get().edges) });
// We make sure to perform any required data updates on the newly reconnected nodes // We make sure to perform any required data updates on the newly reconnected nodes

View File

@@ -10,6 +10,7 @@ import {allowOnlyConnectionsFromHandle} from "../HandleRules.ts";
import useFlowStore from '../VisProgStores.tsx'; import useFlowStore from '../VisProgStores.tsx';
import { TextField } from '../../../../components/TextField.tsx'; import { TextField } from '../../../../components/TextField.tsx';
import { MultilineTextField } from '../../../../components/MultilineTextField.tsx'; import { MultilineTextField } from '../../../../components/MultilineTextField.tsx';
import {noMatchingLeftRightBelief} from "./BeliefGlobals.ts";
/** /**
* The default data structure for a BasicBelief node * The default data structure for a BasicBelief node
@@ -189,6 +190,7 @@ export default function BasicBeliefNode(props: NodeProps<BasicBeliefNode>) {
</div> </div>
)} )}
<MultiConnectionHandle type="source" position={Position.Right} id="source" rules={[ <MultiConnectionHandle type="source" position={Position.Right} id="source" rules={[
noMatchingLeftRightBelief,
allowOnlyConnectionsFromHandle([{nodeType:"trigger",handleId:"TriggerBeliefs"}, {nodeType:"norm",handleId:"NormBeliefs"},{nodeType:"InferredBelief",handleId:"inferred_belief"}]), allowOnlyConnectionsFromHandle([{nodeType:"trigger",handleId:"TriggerBeliefs"}, {nodeType:"norm",handleId:"NormBeliefs"},{nodeType:"InferredBelief",handleId:"inferred_belief"}]),
]}/> ]}/>
</div> </div>

View File

@@ -5,7 +5,7 @@ import type { InferredBeliefNodeData } from "./InferredBeliefNode.tsx";
* Default data for this node * Default data for this node
*/ */
export const InferredBeliefNodeDefaults: InferredBeliefNodeData = { export const InferredBeliefNodeDefaults: InferredBeliefNodeData = {
label: "Inferred Belief", label: "AND/OR",
droppable: true, droppable: true,
inferredBelief: { inferredBelief: {
left: undefined, left: undefined,

View File

@@ -72,7 +72,7 @@ export default function TriggerNode(props: NodeProps<TriggerNode>) {
id="TriggerBeliefs" id="TriggerBeliefs"
style={{ left: '40%' }} style={{ left: '40%' }}
rules={[ rules={[
allowOnlyConnectionsFromType(['basic_belief', "inferred_belief"]), allowOnlyConnectionsFromType(['basic_belief']),
]} ]}
/> />
@@ -136,7 +136,7 @@ export function TriggerConnectionTarget(_thisNode: Node, _sourceNodeId: string)
const otherNode = nodes.find((x) => x.id === _sourceNodeId) const otherNode = nodes.find((x) => x.id === _sourceNodeId)
if (!otherNode) return; if (!otherNode) return;
if (otherNode.type === 'basic_belief'|| otherNode.type ==='inferred_belief') { if (otherNode.type === 'basic_belief' /* TODO: Add the option for an inferred belief */) {
data.condition = _sourceNodeId; data.condition = _sourceNodeId;
} }