fix(ui): fix workflow loading

- Different handling for loading from library vs external
- Fix bug where only nodes and edges loaded
This commit is contained in:
psychedelicious 2023-12-03 20:13:44 +11:00
parent 4b2e3aa54d
commit 3863bd9da3
8 changed files with 50 additions and 36 deletions

View File

@ -1,7 +1,7 @@
import { logger } from 'app/logging/logger';
import { parseify } from 'common/util/serialize';
import { workflowLoadRequested } from 'features/nodes/store/actions';
import { workflowLoaded } from 'features/nodes/store/nodesSlice';
import { workflowLoaded } from 'features/nodes/store/workflowSlice';
import { $flow } from 'features/nodes/store/reactFlowInstance';
import {
WorkflowMigrationError,
@ -21,7 +21,7 @@ export const addWorkflowLoadRequestedListener = () => {
actionCreator: workflowLoadRequested,
effect: (action, { dispatch, getState }) => {
const log = logger('nodes');
const workflow = action.payload;
const { workflow, asCopy } = action.payload;
const nodeTemplates = getState().nodes.nodeTemplates;
try {
@ -29,6 +29,12 @@ export const addWorkflowLoadRequestedListener = () => {
workflow,
nodeTemplates
);
if (asCopy) {
// If we're loading a copy, we need to remove the ID so that the backend will create a new workflow
delete validatedWorkflow.id;
}
dispatch(workflowLoaded(validatedWorkflow));
if (!warnings.length) {
dispatch(

View File

@ -17,9 +17,10 @@ export const isAnyGraphBuilt = isAnyOf(
nodesGraphBuilt
);
export const workflowLoadRequested = createAction<unknown>(
'nodes/workflowLoadRequested'
);
export const workflowLoadRequested = createAction<{
workflow: unknown;
asCopy: boolean;
}>('nodes/workflowLoadRequested');
export const updateAllNodesRequested = createAction(
'nodes/updateAllNodesRequested'

View File

@ -1,4 +1,5 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { workflowLoaded } from 'features/nodes/store/workflowSlice';
import { SHARED_NODE_PROPERTIES } from 'features/nodes/types/constants';
import {
BoardFieldValue,
@ -28,7 +29,6 @@ import {
NodeExecutionState,
zNodeStatus,
} from 'features/nodes/types/invocation';
import { WorkflowV2 } from 'features/nodes/types/workflow';
import { cloneDeep, forEach } from 'lodash-es';
import {
addEdge,
@ -654,30 +654,6 @@ const nodesSlice = createSlice({
nodeOpacityChanged: (state, action: PayloadAction<number>) => {
state.nodeOpacity = action.payload;
},
workflowLoaded: (state, action: PayloadAction<WorkflowV2>) => {
const { nodes, edges } = action.payload;
state.nodes = applyNodeChanges(
nodes.map((node) => ({
item: { ...node, ...SHARED_NODE_PROPERTIES },
type: 'add',
})),
[]
);
state.edges = applyEdgeChanges(
edges.map((edge) => ({ item: edge, type: 'add' })),
[]
);
state.nodeExecutionStates = nodes.reduce<
Record<string, NodeExecutionState>
>((acc, node) => {
acc[node.id] = {
nodeId: node.id,
...initialNodeExecutionState,
};
return acc;
}, {});
},
viewportChanged: (state, action: PayloadAction<Viewport>) => {
state.viewport = action.payload;
},
@ -823,6 +799,32 @@ const nodesSlice = createSlice({
builder.addCase(receivedOpenAPISchema.pending, (state) => {
state.isReady = false;
});
builder.addCase(workflowLoaded, (state, action) => {
const { nodes, edges } = action.payload;
state.nodes = applyNodeChanges(
nodes.map((node) => ({
item: { ...node, ...SHARED_NODE_PROPERTIES },
type: 'add',
})),
[]
);
state.edges = applyEdgeChanges(
edges.map((edge) => ({ item: edge, type: 'add' })),
[]
);
state.nodeExecutionStates = nodes.reduce<
Record<string, NodeExecutionState>
>((acc, node) => {
acc[node.id] = {
nodeId: node.id,
...initialNodeExecutionState,
};
return acc;
}, {});
});
builder.addCase(appSocketInvocationStarted, (state, action) => {
const { source_node_id } = action.payload.data;
const node = state.nodeExecutionStates[source_node_id];
@ -931,7 +933,6 @@ export const {
shouldSnapToGridChanged,
shouldValidateGraphChanged,
viewportChanged,
workflowLoaded,
edgeAdded,
} = nodesSlice.actions;

View File

@ -34,7 +34,9 @@ export const useGetAndLoadEmbeddedWorkflow: UseGetAndLoadEmbeddedWorkflow = ({
async (imageName: string) => {
try {
const workflow = await _getAndLoadEmbeddedWorkflow(imageName);
dispatch(workflowLoadRequested(workflow.data));
dispatch(
workflowLoadRequested({ workflow: workflow.data, asCopy: true })
);
// No toast - the listener for this action does that after the workflow is loaded
onSuccess && onSuccess();
} catch {

View File

@ -32,7 +32,9 @@ export const useGetAndLoadLibraryWorkflow: UseGetAndLoadLibraryWorkflow = ({
async (workflow_id: string) => {
try {
const data = await _getAndLoadWorkflow(workflow_id).unwrap();
dispatch(workflowLoadRequested(data.workflow));
dispatch(
workflowLoadRequested({ workflow: data.workflow, asCopy: false })
);
// No toast - the listener for this action does that after the workflow is loaded
onSuccess && onSuccess();
} catch {

View File

@ -31,7 +31,9 @@ export const useLoadWorkflowFromFile: UseLoadWorkflowFromFile = ({
try {
const parsedJSON = JSON.parse(String(rawJSON));
dispatch(workflowLoadRequested(parsedJSON));
dispatch(
workflowLoadRequested({ workflow: parsedJSON, asCopy: true })
);
} catch (e) {
// There was a problem reading the file
logger.error(t('nodes.unableToLoadWorkflow'));

View File

@ -1,7 +1,7 @@
import { useAppToaster } from 'app/components/Toaster';
import { useAppDispatch } from 'app/store/storeHooks';
import { useWorkflow } from 'features/nodes/hooks/useWorkflow';
import { workflowLoaded } from 'features/nodes/store/nodesSlice';
import { workflowLoaded } from 'features/nodes/store/workflowSlice';
import { zWorkflowV2 } from 'features/nodes/types/workflow';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';

View File

@ -1,7 +1,7 @@
import { useAppToaster } from 'app/components/Toaster';
import { useAppDispatch } from 'app/store/storeHooks';
import { useWorkflow } from 'features/nodes/hooks/useWorkflow';
import { workflowLoaded } from 'features/nodes/store/nodesSlice';
import { workflowLoaded } from 'features/nodes/store/workflowSlice';
import { zWorkflowV2 } from 'features/nodes/types/workflow';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';