mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): store node templates in separate slice
Flattens the `nodes` slice. May offer minor perf improvements in addition to just being cleaner.
This commit is contained in:
parent
7c548c5bf3
commit
5d4610d981
@ -1,6 +1,6 @@
|
||||
import type { UnknownAction } from '@reduxjs/toolkit';
|
||||
import { isAnyGraphBuilt } from 'features/nodes/store/actions';
|
||||
import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice';
|
||||
import { nodeTemplatesBuilt } from 'features/nodes/store/nodeTemplatesSlice';
|
||||
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
|
||||
import type { Graph } from 'services/api/types';
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { logger } from 'app/logging/logger';
|
||||
import { parseify } from 'common/util/serialize';
|
||||
import { nodeTemplatesBuilt } from 'features/nodes/store/nodesSlice';
|
||||
import { nodeTemplatesBuilt } from 'features/nodes/store/nodeTemplatesSlice';
|
||||
import { parseSchema } from 'features/nodes/util/schema/parseSchema';
|
||||
import { size } from 'lodash-es';
|
||||
import { receivedOpenAPISchema } from 'services/api/thunks/schema';
|
||||
|
@ -15,11 +15,11 @@ export const addSocketConnectedEventListener = () => {
|
||||
|
||||
log.debug('Connected');
|
||||
|
||||
const { nodes, config, system } = getState();
|
||||
const { nodeTemplates, config, system } = getState();
|
||||
|
||||
const { disabledTabs } = config;
|
||||
|
||||
if (!size(nodes.nodeTemplates) && !disabledTabs.includes('nodes')) {
|
||||
if (!size(nodeTemplates.templates) && !disabledTabs.includes('nodes')) {
|
||||
dispatch(receivedOpenAPISchema());
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ export const addUpdateAllNodesRequestedListener = () => {
|
||||
effect: (action, { dispatch, getState }) => {
|
||||
const log = logger('nodes');
|
||||
const nodes = getState().nodes.nodes;
|
||||
const templates = getState().nodes.nodeTemplates;
|
||||
const templates = getState().nodeTemplates.templates;
|
||||
|
||||
let unableToUpdateCount = 0;
|
||||
|
||||
|
@ -25,7 +25,7 @@ export const addWorkflowLoadRequestedListener = () => {
|
||||
effect: (action, { dispatch, getState }) => {
|
||||
const log = logger('nodes');
|
||||
const { workflow, asCopy } = action.payload;
|
||||
const nodeTemplates = getState().nodes.nodeTemplates;
|
||||
const nodeTemplates = getState().nodeTemplates.templates;
|
||||
|
||||
try {
|
||||
const { workflow: validatedWorkflow, warnings } = validateWorkflow(
|
||||
|
@ -14,6 +14,7 @@ import hrfReducer from 'features/hrf/store/hrfSlice';
|
||||
import loraReducer from 'features/lora/store/loraSlice';
|
||||
import modelmanagerReducer from 'features/modelManager/store/modelManagerSlice';
|
||||
import nodesReducer from 'features/nodes/store/nodesSlice';
|
||||
import nodeTemplatesReducer from 'features/nodes/store/nodeTemplatesSlice';
|
||||
import workflowReducer from 'features/nodes/store/workflowSlice';
|
||||
import generationReducer from 'features/parameters/store/generationSlice';
|
||||
import postprocessingReducer from 'features/parameters/store/postprocessingSlice';
|
||||
@ -42,6 +43,7 @@ const allReducers = {
|
||||
gallery: galleryReducer,
|
||||
generation: generationReducer,
|
||||
nodes: nodesReducer,
|
||||
nodeTemplates: nodeTemplatesReducer,
|
||||
postprocessing: postprocessingReducer,
|
||||
system: systemReducer,
|
||||
config: configReducer,
|
||||
|
@ -12,7 +12,14 @@ import { getConnectedEdges } from 'reactflow';
|
||||
const selector = createMemoizedSelector(
|
||||
[stateSelector, activeTabNameSelector],
|
||||
(
|
||||
{ controlAdapters, generation, system, nodes, dynamicPrompts },
|
||||
{
|
||||
controlAdapters,
|
||||
generation,
|
||||
system,
|
||||
nodes,
|
||||
nodeTemplates,
|
||||
dynamicPrompts,
|
||||
},
|
||||
activeTabName
|
||||
) => {
|
||||
const { initialImage, model } = generation;
|
||||
@ -41,7 +48,7 @@ const selector = createMemoizedSelector(
|
||||
return;
|
||||
}
|
||||
|
||||
const nodeTemplate = nodes.nodeTemplates[node.data.type];
|
||||
const nodeTemplate = nodeTemplates.templates[node.data.type];
|
||||
|
||||
if (!nodeTemplate) {
|
||||
// Node type not found
|
||||
|
@ -74,57 +74,60 @@ const AddNodePopover = () => {
|
||||
(state) => state.nodes.connectionStartParams?.handleType
|
||||
);
|
||||
|
||||
const selector = createMemoizedSelector([stateSelector], ({ nodes }) => {
|
||||
// If we have a connection in progress, we need to filter the node choices
|
||||
const filteredNodeTemplates = fieldFilter
|
||||
? filter(nodes.nodeTemplates, (template) => {
|
||||
const handles =
|
||||
handleFilter == 'source' ? template.inputs : template.outputs;
|
||||
const selector = createMemoizedSelector(
|
||||
[stateSelector],
|
||||
({ nodeTemplates }) => {
|
||||
// If we have a connection in progress, we need to filter the node choices
|
||||
const filteredNodeTemplates = fieldFilter
|
||||
? filter(nodeTemplates.templates, (template) => {
|
||||
const handles =
|
||||
handleFilter == 'source' ? template.inputs : template.outputs;
|
||||
|
||||
return some(handles, (handle) => {
|
||||
const sourceType =
|
||||
handleFilter == 'source' ? fieldFilter : handle.type;
|
||||
const targetType =
|
||||
handleFilter == 'target' ? fieldFilter : handle.type;
|
||||
return some(handles, (handle) => {
|
||||
const sourceType =
|
||||
handleFilter == 'source' ? fieldFilter : handle.type;
|
||||
const targetType =
|
||||
handleFilter == 'target' ? fieldFilter : handle.type;
|
||||
|
||||
return validateSourceAndTargetTypes(sourceType, targetType);
|
||||
});
|
||||
})
|
||||
: map(nodes.nodeTemplates);
|
||||
return validateSourceAndTargetTypes(sourceType, targetType);
|
||||
});
|
||||
})
|
||||
: map(nodeTemplates.templates);
|
||||
|
||||
const options: InvSelectOption[] = map(
|
||||
filteredNodeTemplates,
|
||||
(template) => {
|
||||
return {
|
||||
label: template.title,
|
||||
value: template.type,
|
||||
description: template.description,
|
||||
tags: template.tags,
|
||||
};
|
||||
const options: InvSelectOption[] = map(
|
||||
filteredNodeTemplates,
|
||||
(template) => {
|
||||
return {
|
||||
label: template.title,
|
||||
value: template.type,
|
||||
description: template.description,
|
||||
tags: template.tags,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
//We only want these nodes if we're not filtered
|
||||
if (fieldFilter === null) {
|
||||
options.push({
|
||||
label: t('nodes.currentImage'),
|
||||
value: 'current_image',
|
||||
description: t('nodes.currentImageDescription'),
|
||||
tags: ['progress'],
|
||||
});
|
||||
|
||||
options.push({
|
||||
label: t('nodes.notes'),
|
||||
value: 'notes',
|
||||
description: t('nodes.notesDescription'),
|
||||
tags: ['notes'],
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
//We only want these nodes if we're not filtered
|
||||
if (fieldFilter === null) {
|
||||
options.push({
|
||||
label: t('nodes.currentImage'),
|
||||
value: 'current_image',
|
||||
description: t('nodes.currentImageDescription'),
|
||||
tags: ['progress'],
|
||||
});
|
||||
options.sort((a, b) => a.label.localeCompare(b.label));
|
||||
|
||||
options.push({
|
||||
label: t('nodes.notes'),
|
||||
value: 'notes',
|
||||
description: t('nodes.notesDescription'),
|
||||
tags: ['notes'],
|
||||
});
|
||||
return { options };
|
||||
}
|
||||
|
||||
options.sort((a, b) => a.label.localeCompare(b.label));
|
||||
|
||||
return { options };
|
||||
});
|
||||
);
|
||||
|
||||
const { options } = useAppSelector(selector);
|
||||
const isOpen = useAppSelector((state) => state.nodes.isAddNodePopoverOpen);
|
||||
|
@ -14,8 +14,8 @@ const InvocationNodeWrapper = (props: NodeProps<InvocationNodeData>) => {
|
||||
|
||||
const hasTemplateSelector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) =>
|
||||
Boolean(nodes.nodeTemplates[type])
|
||||
createMemoizedSelector(stateSelector, ({ nodeTemplates }) =>
|
||||
Boolean(nodeTemplates.templates[type])
|
||||
),
|
||||
[type]
|
||||
);
|
||||
|
@ -14,28 +14,31 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
import EditableNodeTitle from './details/EditableNodeTitle';
|
||||
|
||||
const selector = createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const lastSelectedNodeId =
|
||||
nodes.selectedNodes[nodes.selectedNodes.length - 1];
|
||||
const selector = createMemoizedSelector(
|
||||
stateSelector,
|
||||
({ nodes, nodeTemplates }) => {
|
||||
const lastSelectedNodeId =
|
||||
nodes.selectedNodes[nodes.selectedNodes.length - 1];
|
||||
|
||||
const lastSelectedNode = nodes.nodes.find(
|
||||
(node) => node.id === lastSelectedNodeId
|
||||
);
|
||||
const lastSelectedNode = nodes.nodes.find(
|
||||
(node) => node.id === lastSelectedNodeId
|
||||
);
|
||||
|
||||
const lastSelectedNodeTemplate = lastSelectedNode
|
||||
? nodes.nodeTemplates[lastSelectedNode.data.type]
|
||||
: undefined;
|
||||
const lastSelectedNodeTemplate = lastSelectedNode
|
||||
? nodeTemplates.templates[lastSelectedNode.data.type]
|
||||
: undefined;
|
||||
|
||||
if (!isInvocationNode(lastSelectedNode) || !lastSelectedNodeTemplate) {
|
||||
return;
|
||||
if (!isInvocationNode(lastSelectedNode) || !lastSelectedNodeTemplate) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
nodeId: lastSelectedNode.data.id,
|
||||
nodeVersion: lastSelectedNode.data.version,
|
||||
templateTitle: lastSelectedNodeTemplate.title,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
nodeId: lastSelectedNode.data.id,
|
||||
nodeVersion: lastSelectedNode.data.version,
|
||||
templateTitle: lastSelectedNodeTemplate.title,
|
||||
};
|
||||
});
|
||||
);
|
||||
|
||||
const InspectorDetailsTab = () => {
|
||||
const data = useAppSelector(selector);
|
||||
|
@ -13,34 +13,37 @@ import type { AnyResult } from 'services/events/types';
|
||||
|
||||
import ImageOutputPreview from './outputs/ImageOutputPreview';
|
||||
|
||||
const selector = createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const lastSelectedNodeId =
|
||||
nodes.selectedNodes[nodes.selectedNodes.length - 1];
|
||||
const selector = createMemoizedSelector(
|
||||
stateSelector,
|
||||
({ nodes, nodeTemplates }) => {
|
||||
const lastSelectedNodeId =
|
||||
nodes.selectedNodes[nodes.selectedNodes.length - 1];
|
||||
|
||||
const lastSelectedNode = nodes.nodes.find(
|
||||
(node) => node.id === lastSelectedNodeId
|
||||
);
|
||||
const lastSelectedNode = nodes.nodes.find(
|
||||
(node) => node.id === lastSelectedNodeId
|
||||
);
|
||||
|
||||
const lastSelectedNodeTemplate = lastSelectedNode
|
||||
? nodes.nodeTemplates[lastSelectedNode.data.type]
|
||||
: undefined;
|
||||
const lastSelectedNodeTemplate = lastSelectedNode
|
||||
? nodeTemplates.templates[lastSelectedNode.data.type]
|
||||
: undefined;
|
||||
|
||||
const nes =
|
||||
nodes.nodeExecutionStates[lastSelectedNodeId ?? '__UNKNOWN_NODE__'];
|
||||
const nes =
|
||||
nodes.nodeExecutionStates[lastSelectedNodeId ?? '__UNKNOWN_NODE__'];
|
||||
|
||||
if (
|
||||
!isInvocationNode(lastSelectedNode) ||
|
||||
!nes ||
|
||||
!lastSelectedNodeTemplate
|
||||
) {
|
||||
return;
|
||||
if (
|
||||
!isInvocationNode(lastSelectedNode) ||
|
||||
!nes ||
|
||||
!lastSelectedNodeTemplate
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
outputs: nes.outputs,
|
||||
outputType: lastSelectedNodeTemplate.outputType,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
outputs: nes.outputs,
|
||||
outputType: lastSelectedNodeTemplate.outputType,
|
||||
};
|
||||
});
|
||||
);
|
||||
|
||||
const InspectorOutputsTab = () => {
|
||||
const data = useAppSelector(selector);
|
||||
|
@ -6,22 +6,25 @@ import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataView
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const selector = createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const lastSelectedNodeId =
|
||||
nodes.selectedNodes[nodes.selectedNodes.length - 1];
|
||||
const selector = createMemoizedSelector(
|
||||
stateSelector,
|
||||
({ nodes, nodeTemplates }) => {
|
||||
const lastSelectedNodeId =
|
||||
nodes.selectedNodes[nodes.selectedNodes.length - 1];
|
||||
|
||||
const lastSelectedNode = nodes.nodes.find(
|
||||
(node) => node.id === lastSelectedNodeId
|
||||
);
|
||||
const lastSelectedNode = nodes.nodes.find(
|
||||
(node) => node.id === lastSelectedNodeId
|
||||
);
|
||||
|
||||
const lastSelectedNodeTemplate = lastSelectedNode
|
||||
? nodes.nodeTemplates[lastSelectedNode.data.type]
|
||||
: undefined;
|
||||
const lastSelectedNodeTemplate = lastSelectedNode
|
||||
? nodeTemplates.templates[lastSelectedNode.data.type]
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
template: lastSelectedNodeTemplate,
|
||||
};
|
||||
});
|
||||
return {
|
||||
template: lastSelectedNodeTemplate,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const NodeTemplateInspector = () => {
|
||||
const { template } = useAppSelector(selector);
|
||||
|
@ -10,12 +10,12 @@ import { useMemo } from 'react';
|
||||
export const useAnyOrDirectInputFieldNames = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
createMemoizedSelector(stateSelector, ({ nodes, nodeTemplates }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return [];
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node.data.type];
|
||||
const nodeTemplate = nodeTemplates.templates[node.data.type];
|
||||
if (!nodeTemplate) {
|
||||
return [];
|
||||
}
|
||||
|
@ -1,5 +1,3 @@
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import type { RootState } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import {
|
||||
DRAG_HANDLE_CLASSNAME,
|
||||
@ -16,17 +14,14 @@ import { useCallback } from 'react';
|
||||
import type { Node } from 'reactflow';
|
||||
import { useReactFlow } from 'reactflow';
|
||||
|
||||
const templatesSelector = createMemoizedSelector(
|
||||
[(state: RootState) => state.nodes],
|
||||
(nodes) => nodes.nodeTemplates
|
||||
);
|
||||
|
||||
export const SHARED_NODE_PROPERTIES: Partial<Node> = {
|
||||
dragHandle: `.${DRAG_HANDLE_CLASSNAME}`,
|
||||
};
|
||||
|
||||
export const useBuildNode = () => {
|
||||
const nodeTemplates = useAppSelector(templatesSelector);
|
||||
const nodeTemplates = useAppSelector(
|
||||
(state) => state.nodeTemplates.templates
|
||||
);
|
||||
|
||||
const flow = useReactFlow();
|
||||
|
||||
|
@ -10,12 +10,12 @@ import { useMemo } from 'react';
|
||||
export const useConnectionInputFieldNames = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
createMemoizedSelector(stateSelector, ({ nodes, nodeTemplates }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return [];
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node.data.type];
|
||||
const nodeTemplate = nodeTemplates.templates[node.data.type];
|
||||
if (!nodeTemplate) {
|
||||
return [];
|
||||
}
|
||||
|
@ -8,12 +8,12 @@ import { useMemo } from 'react';
|
||||
export const useDoNodeVersionsMatch = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
createMemoizedSelector(stateSelector, ({ nodes, nodeTemplates }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
const nodeTemplate = nodeTemplates.templates[node?.data.type ?? ''];
|
||||
if (!nodeTemplate?.version || !node.data?.version) {
|
||||
return false;
|
||||
}
|
||||
|
@ -7,12 +7,12 @@ import { useMemo } from 'react';
|
||||
export const useFieldInputKind = (nodeId: string, fieldName: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
createMemoizedSelector(stateSelector, ({ nodes, nodeTemplates }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
const nodeTemplate = nodeTemplates.templates[node?.data.type ?? ''];
|
||||
const fieldTemplate = nodeTemplate?.inputs[fieldName];
|
||||
return fieldTemplate?.input;
|
||||
}),
|
||||
|
@ -7,12 +7,12 @@ import { useMemo } from 'react';
|
||||
export const useFieldInputTemplate = (nodeId: string, fieldName: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
createMemoizedSelector(stateSelector, ({ nodes, nodeTemplates }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
const nodeTemplate = nodeTemplates.templates[node?.data.type ?? ''];
|
||||
return nodeTemplate?.inputs[fieldName];
|
||||
}),
|
||||
[fieldName, nodeId]
|
||||
|
@ -7,12 +7,12 @@ import { useMemo } from 'react';
|
||||
export const useFieldOutputTemplate = (nodeId: string, fieldName: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
createMemoizedSelector(stateSelector, ({ nodes, nodeTemplates }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
const nodeTemplate = nodeTemplates.templates[node?.data.type ?? ''];
|
||||
return nodeTemplate?.outputs[fieldName];
|
||||
}),
|
||||
[fieldName, nodeId]
|
||||
|
@ -12,12 +12,12 @@ export const useFieldTemplate = (
|
||||
) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
createMemoizedSelector(stateSelector, ({ nodes, nodeTemplates }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
const nodeTemplate = nodeTemplates.templates[node?.data.type ?? ''];
|
||||
return nodeTemplate?.[KIND_MAP[kind]][fieldName];
|
||||
}),
|
||||
[fieldName, kind, nodeId]
|
||||
|
@ -12,12 +12,12 @@ export const useFieldTemplateTitle = (
|
||||
) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
createMemoizedSelector(stateSelector, ({ nodes, nodeTemplates }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
const nodeTemplate = nodeTemplates.templates[node?.data.type ?? ''];
|
||||
return nodeTemplate?.[KIND_MAP[kind]][fieldName]?.title;
|
||||
}),
|
||||
[fieldName, kind, nodeId]
|
||||
|
@ -4,19 +4,15 @@ import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { getNeedsUpdate } from 'features/nodes/util/node/nodeUpdate';
|
||||
|
||||
const selector = createMemoizedSelector(stateSelector, (state) => {
|
||||
const nodes = state.nodes.nodes;
|
||||
const templates = state.nodes.nodeTemplates;
|
||||
|
||||
const needsUpdate = nodes.filter(isInvocationNode).some((node) => {
|
||||
const template = templates[node.data.type];
|
||||
const selector = createMemoizedSelector(stateSelector, (state) =>
|
||||
state.nodes.nodes.filter(isInvocationNode).some((node) => {
|
||||
const template = state.nodeTemplates.templates[node.data.type];
|
||||
if (!template) {
|
||||
return false;
|
||||
}
|
||||
return getNeedsUpdate(node, template);
|
||||
});
|
||||
return needsUpdate;
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
export const useGetNodesNeedUpdate = () => {
|
||||
const getNeedsUpdate = useAppSelector(selector);
|
||||
|
@ -7,12 +7,12 @@ import { useMemo } from 'react';
|
||||
export const useNodeClassification = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
createMemoizedSelector(stateSelector, ({ nodes, nodeTemplates }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
const nodeTemplate = nodeTemplates.templates[node?.data.type ?? ''];
|
||||
return nodeTemplate?.classification;
|
||||
}),
|
||||
[nodeId]
|
||||
|
@ -8,9 +8,9 @@ import { useMemo } from 'react';
|
||||
export const useNodeNeedsUpdate = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
createMemoizedSelector(stateSelector, ({ nodes, nodeTemplates }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
const template = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
const template = nodeTemplates.templates[node?.data.type ?? ''];
|
||||
if (isInvocationNode(node) && template) {
|
||||
return getNeedsUpdate(node, template);
|
||||
}
|
||||
|
@ -6,9 +6,9 @@ import { useMemo } from 'react';
|
||||
export const useNodeTemplate = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
createMemoizedSelector(stateSelector, ({ nodes, nodeTemplates }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
const nodeTemplate = nodeTemplates.templates[node?.data.type ?? ''];
|
||||
return nodeTemplate;
|
||||
}),
|
||||
[nodeId]
|
||||
|
@ -9,9 +9,8 @@ export const useNodeTemplateByType = (type: string) => {
|
||||
() =>
|
||||
createMemoizedSelector(
|
||||
stateSelector,
|
||||
({ nodes }): InvocationTemplate | undefined => {
|
||||
const nodeTemplate = nodes.nodeTemplates[type];
|
||||
return nodeTemplate;
|
||||
({ nodeTemplates }): InvocationTemplate | undefined => {
|
||||
return nodeTemplates.templates[type];
|
||||
}
|
||||
),
|
||||
[type]
|
||||
|
@ -7,13 +7,13 @@ import { useMemo } from 'react';
|
||||
export const useNodeTemplateTitle = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
createMemoizedSelector(stateSelector, ({ nodes, nodeTemplates }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
const nodeTemplate = node
|
||||
? nodes.nodeTemplates[node.data.type]
|
||||
? nodeTemplates.templates[node.data.type]
|
||||
: undefined;
|
||||
|
||||
return nodeTemplate?.title;
|
||||
|
@ -9,12 +9,12 @@ import { useMemo } from 'react';
|
||||
export const useOutputFieldNames = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
createMemoizedSelector(stateSelector, ({ nodes, nodeTemplates }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return [];
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node.data.type];
|
||||
const nodeTemplate = nodeTemplates.templates[node.data.type];
|
||||
if (!nodeTemplate) {
|
||||
return [];
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import type { InvocationTemplate } from 'features/nodes/types/invocation';
|
||||
|
||||
import type { NodeTemplatesState } from './types';
|
||||
|
||||
export const initialNodeTemplatesState: NodeTemplatesState = {
|
||||
templates: {},
|
||||
};
|
||||
|
||||
const nodesTemplatesSlice = createSlice({
|
||||
name: 'nodeTemplates',
|
||||
initialState: initialNodeTemplatesState,
|
||||
reducers: {
|
||||
nodeTemplatesBuilt: (
|
||||
state,
|
||||
action: PayloadAction<Record<string, InvocationTemplate>>
|
||||
) => {
|
||||
state.templates = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { nodeTemplatesBuilt } = nodesTemplatesSlice.actions;
|
||||
|
||||
export default nodesTemplatesSlice.reducer;
|
@ -4,7 +4,6 @@ import type { NodesState } from './types';
|
||||
* Nodes slice persist denylist
|
||||
*/
|
||||
export const nodesPersistDenylist: (keyof NodesState)[] = [
|
||||
'nodeTemplates',
|
||||
'connectionStartParams',
|
||||
'connectionStartFieldType',
|
||||
'selectedNodes',
|
||||
|
@ -1,6 +1,7 @@
|
||||
import type { PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createSlice, isAnyOf } from '@reduxjs/toolkit';
|
||||
import { workflowLoaded } from 'features/nodes/store/actions';
|
||||
import { nodeTemplatesBuilt } from 'features/nodes/store/nodeTemplatesSlice';
|
||||
import { SHARED_NODE_PROPERTIES } from 'features/nodes/types/constants';
|
||||
import type {
|
||||
BoardFieldValue,
|
||||
@ -41,7 +42,6 @@ import {
|
||||
} from 'features/nodes/types/field';
|
||||
import type {
|
||||
AnyNode,
|
||||
InvocationTemplate,
|
||||
NodeExecutionState,
|
||||
} from 'features/nodes/types/invocation';
|
||||
import {
|
||||
@ -97,7 +97,6 @@ const initialNodeExecutionState: Omit<NodeExecutionState, 'nodeId'> = {
|
||||
export const initialNodesState: NodesState = {
|
||||
nodes: [],
|
||||
edges: [],
|
||||
nodeTemplates: {},
|
||||
isReady: false,
|
||||
connectionStartParams: null,
|
||||
connectionStartFieldType: null,
|
||||
@ -656,13 +655,6 @@ const nodesSlice = createSlice({
|
||||
shouldShowMinimapPanelChanged: (state, action: PayloadAction<boolean>) => {
|
||||
state.shouldShowMinimapPanel = action.payload;
|
||||
},
|
||||
nodeTemplatesBuilt: (
|
||||
state,
|
||||
action: PayloadAction<Record<string, InvocationTemplate>>
|
||||
) => {
|
||||
state.nodeTemplates = action.payload;
|
||||
state.isReady = true;
|
||||
},
|
||||
nodeEditorReset: (state) => {
|
||||
state.nodes = [];
|
||||
state.edges = [];
|
||||
@ -893,6 +885,9 @@ const nodesSlice = createSlice({
|
||||
});
|
||||
}
|
||||
});
|
||||
builder.addCase(nodeTemplatesBuilt, (state) => {
|
||||
state.isReady = true;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@ -935,7 +930,6 @@ export const {
|
||||
nodeOpacityChanged,
|
||||
nodesChanged,
|
||||
nodesDeleted,
|
||||
nodeTemplatesBuilt,
|
||||
nodeUseCacheChanged,
|
||||
notesNodeValueChanged,
|
||||
selectedAll,
|
||||
|
@ -16,7 +16,6 @@ import type {
|
||||
export type NodesState = {
|
||||
nodes: AnyNode[];
|
||||
edges: InvocationNodeEdge[];
|
||||
nodeTemplates: Record<string, InvocationTemplate>;
|
||||
connectionStartParams: OnConnectStartParams | null;
|
||||
connectionStartFieldType: FieldType | null;
|
||||
connectionMade: boolean;
|
||||
@ -42,3 +41,7 @@ export type NodesState = {
|
||||
export type WorkflowsState = Omit<WorkflowV2, 'nodes' | 'edges'> & {
|
||||
isTouched: boolean;
|
||||
};
|
||||
|
||||
export type NodeTemplatesState = {
|
||||
templates: Record<string, InvocationTemplate>;
|
||||
};
|
||||
|
@ -33,7 +33,7 @@ const zWorkflowMetaVersion = z.object({
|
||||
* - Workflow schema version bumped to 2.0.0
|
||||
*/
|
||||
const migrateV1toV2 = (workflowToMigrate: WorkflowV1): WorkflowV2 => {
|
||||
const invocationTemplates = $store.get()?.getState().nodes.nodeTemplates;
|
||||
const invocationTemplates = $store.get()?.getState().nodeTemplates.templates;
|
||||
|
||||
if (!invocationTemplates) {
|
||||
throw new Error(t('app.storeNotInitialized'));
|
||||
|
Loading…
Reference in New Issue
Block a user