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
4 changed files with 38 additions and 19 deletions
Showing only changes of commit e86c06c3e5 - Show all commits

View File

@@ -44,6 +44,7 @@ const selector = (state: FlowState) => ({
nodes: state.nodes, nodes: state.nodes,
edges: state.edges, edges: state.edges,
onNodesChange: state.onNodesChange, onNodesChange: state.onNodesChange,
onNodesDelete: state.onNodesDelete,
onEdgesDelete: state.onEdgesDelete, onEdgesDelete: state.onEdgesDelete,
onEdgesChange: state.onEdgesChange, onEdgesChange: state.onEdgesChange,
onConnect: state.onConnect, onConnect: state.onConnect,
@@ -69,6 +70,7 @@ const VisProgUI = () => {
const { const {
nodes, edges, nodes, edges,
onNodesChange, onNodesChange,
onNodesDelete,
onEdgesDelete, onEdgesDelete,
onEdgesChange, onEdgesChange,
onConnect, onConnect,
@@ -122,6 +124,7 @@ const VisProgUI = () => {
defaultEdgeOptions={DEFAULT_EDGE_OPTIONS} defaultEdgeOptions={DEFAULT_EDGE_OPTIONS}
nodeTypes={NodeTypes} nodeTypes={NodeTypes}
onNodesChange={onNodesChange} onNodesChange={onNodesChange}
onNodesDelete={onNodesDelete}
onEdgesDelete={onEdgesDelete} onEdgesDelete={onEdgesDelete}
onEdgesChange={onEdgesChange} onEdgesChange={onEdgesChange}
onReconnect={onReconnect} onReconnect={onReconnect}

View File

@@ -44,19 +44,18 @@ function createNode(id: string, type: string, position: XYPosition, data: Record
} }
} }
//* Initial nodes, created by using createNode. */ //* Initial nodes, created by using createNode. */
// Start and End don't need to apply the UUID, since they are technically never compiled into a program. // Start and End don't need to apply the UUID, since they are technically never compiled into a program.
const startNode = createNode('start', 'start', {x: 110, y: 100}, {label: "Start"}, false) const startNode = createNode('start', 'start', {x: 110, y: 100}, {label: "Start"}, false)
const endNode = createNode('end', 'end', {x: 590, y: 100}, {label: "End"}, false) const endNode = createNode('end', 'end', {x: 590, y: 100}, {label: "End"}, false)
const initialPhaseNode = createNode(crypto.randomUUID(), 'phase', {x:235, y:100}, {label: "Phase 1", children : [], isFirstPhase: false, nextPhaseId: null}) const initialPhaseNode = createNode(crypto.randomUUID(), 'phase', {x:235, y:100}, {label: "Phase 1", children : [], isFirstPhase: false, nextPhaseId: null})
const initialNodes : Node[] = [startNode, endNode, initialPhaseNode]; const initialNodes : Node[] = [startNode, endNode, initialPhaseNode];
// Initial edges, leave empty as setting initial edges... // Initial edges, leave empty as setting initial edges...
// ...breaks logic that is dependent on connection events // ...breaks logic that is dependent on connection events
const initialEdges: Edge[] = []; const initialEdges: Edge[] = [];
/** /**
* useFlowStore contains the implementation for all editor functionality * useFlowStore contains the implementation for all editor functionality
* and stores the current state of the visual programming editor * and stores the current state of the visual programming editor
@@ -87,7 +86,9 @@ const useFlowStore = create<FlowState>(UndoRedo((set, get) => ({
*/ */
onNodesChange: (changes) => set({nodes: applyNodeChanges(changes, get().nodes)}), onNodesChange: (changes) => set({nodes: applyNodeChanges(changes, get().nodes)}),
onNodesDelete: (nodes) => nodes.forEach(node => get().unregisterNodeRules(node.id)), onNodesDelete: (nodes) => nodes.forEach((_node) => {
return;
}),
onEdgesDelete: (edges) => { onEdgesDelete: (edges) => {
// we make sure any affected nodes get updated to reflect removal of edges // we make sure any affected nodes get updated to reflect removal of edges
@@ -183,19 +184,30 @@ const useFlowStore = create<FlowState>(UndoRedo((set, get) => ({
* Deletes a node by ID, respecting NodeDeletes rules. * Deletes a node by ID, respecting NodeDeletes rules.
* Also removes all edges connected to that node. * Also removes all edges connected to that node.
*/ */
deleteNode: (nodeId) => { deleteNode: (nodeId, deleteElements) => {
get().pushSnapshot(); get().pushSnapshot();
// Let's find our node to check if they have a special deletion function // Let's find our node to check if they have a special deletion function
const ourNode = get().nodes.find((n)=>n.id==nodeId); const ourNode = get().nodes.find((n)=>n.id==nodeId);
const ourFunction = Object.entries(NodeDeletes).find(([t])=>t==ourNode?.type)?.[1] const ourFunction = Object.entries(NodeDeletes).find(([t])=>t==ourNode?.type)?.[1]
// If there's no function, OR, our function tells us we can delete it, let's do so... // If there's no function, OR, our function tells us we can delete it, let's do so...
if (ourFunction == undefined || ourFunction()) { if (ourFunction == undefined || ourFunction()) {
set({ deleteElements({
nodes: get().nodes.filter((n) => n.id !== nodeId), nodes: get().nodes.filter((n) => n.id === nodeId),
edges: get().edges.filter((e) => e.source !== nodeId && e.target !== nodeId), edges: get().edges.filter((e) => e.source !== nodeId && e.target === nodeId)}
})} ).then(() => {
get().unregisterNodeRules(nodeId);
get().unregisterWarningsForId(nodeId);
});
// set({
// nodes: get().nodes.filter((n) => n.id !== nodeId),
// edges: get().edges.filter((e) => e.source !== nodeId && e.target !== nodeId),
// })
}
}, },
/** /**

View File

@@ -7,7 +7,7 @@ import type {
OnReconnect, OnReconnect,
Node, Node,
OnEdgesDelete, OnEdgesDelete,
OnNodesDelete OnNodesDelete, DeleteElementsOptions
} from '@xyflow/react'; } from '@xyflow/react';
import type {EditorWarningRegistry} from "./components/EditorWarnings.tsx"; import type {EditorWarningRegistry} from "./components/EditorWarnings.tsx";
import type {HandleRule} from "./HandleRuleLogic.ts"; import type {HandleRule} from "./HandleRuleLogic.ts";
@@ -69,7 +69,10 @@ export type FlowState = {
* Deletes a node and any connected edges. * Deletes a node and any connected edges.
* @param nodeId - the ID of the node to delete * @param nodeId - the ID of the node to delete
*/ */
deleteNode: (nodeId: string) => void; deleteNode: (nodeId: string, deleteElements: (params: DeleteElementsOptions) => Promise<{
deletedNodes: Node[]
deletedEdges: Edge[]
}>) => void;
/** /**
* Replaces the current nodes array in the store. * Replaces the current nodes array in the store.

View File

@@ -1,4 +1,4 @@
import {NodeToolbar} from '@xyflow/react'; import {NodeToolbar, useReactFlow} from '@xyflow/react';
import '@xyflow/react/dist/style.css'; import '@xyflow/react/dist/style.css';
import {type JSX, useState} from "react"; import {type JSX, useState} from "react";
import {createPortal} from "react-dom"; import {createPortal} from "react-dom";
@@ -30,10 +30,11 @@ type ToolbarProps = {
*/ */
export function Toolbar({nodeId, allowDelete}: ToolbarProps) { export function Toolbar({nodeId, allowDelete}: ToolbarProps) {
const {nodes, deleteNode} = useFlowStore(); const {nodes, deleteNode} = useFlowStore();
const { deleteElements } = useReactFlow();
const deleteParentNode = () => { const deleteParentNode = () => {
deleteNode(nodeId);
deleteNode(nodeId, deleteElements);
}; };
const nodeType = nodes.find((node) => node.id === nodeId)?.type as keyof typeof NodeTooltips; const nodeType = nodes.find((node) => node.id === nodeId)?.type as keyof typeof NodeTooltips;