mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): upgrade redux and RTK
There are a few breaking changes, which I've addressed. The vast majority of changes are related to new handling of `reselect`'s `createSelector` options. For better or worse, we memoize just about all our selectors using lodash `isEqual` for `resultEqualityCheck`. The upgrade requires we explicitly set the `memoize` option to `lruMemoize` to continue using lodash here. Doing that required changing our `defaultSelectorOptions`. Instead of changing that and finding dozens of instances where we weren't using that and instead were defining selector options manually, I've created a pre-configured selector: `createMemoizedSelector`. This is now used everywhere instead of `createSelector`.
This commit is contained in:
@ -5,11 +5,10 @@ import {
|
||||
PopoverBody,
|
||||
PopoverContent,
|
||||
} from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppToaster } from 'app/components/Toaster';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
||||
import { useBuildNode } from 'features/nodes/hooks/useBuildNode';
|
||||
import {
|
||||
@ -62,58 +61,54 @@ const AddNodePopover = () => {
|
||||
(state) => state.nodes.connectionStartParams?.handleType
|
||||
);
|
||||
|
||||
const selector = createSelector(
|
||||
[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], ({ 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;
|
||||
|
||||
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(nodes.nodeTemplates);
|
||||
|
||||
const data: NodeTemplate[] = map(filteredNodeTemplates, (template) => {
|
||||
return {
|
||||
label: template.title,
|
||||
value: template.type,
|
||||
description: template.description,
|
||||
tags: template.tags,
|
||||
};
|
||||
const data: NodeTemplate[] = 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) {
|
||||
data.push({
|
||||
label: t('nodes.currentImage'),
|
||||
value: 'current_image',
|
||||
description: t('nodes.currentImageDescription'),
|
||||
tags: ['progress'],
|
||||
});
|
||||
|
||||
//We only want these nodes if we're not filtered
|
||||
if (fieldFilter === null) {
|
||||
data.push({
|
||||
label: t('nodes.currentImage'),
|
||||
value: 'current_image',
|
||||
description: t('nodes.currentImageDescription'),
|
||||
tags: ['progress'],
|
||||
});
|
||||
data.push({
|
||||
label: t('nodes.notes'),
|
||||
value: 'notes',
|
||||
description: t('nodes.notesDescription'),
|
||||
tags: ['notes'],
|
||||
});
|
||||
}
|
||||
|
||||
data.push({
|
||||
label: t('nodes.notes'),
|
||||
value: 'notes',
|
||||
description: t('nodes.notesDescription'),
|
||||
tags: ['notes'],
|
||||
});
|
||||
}
|
||||
data.sort((a, b) => a.label.localeCompare(b.label));
|
||||
|
||||
data.sort((a, b) => a.label.localeCompare(b.label));
|
||||
|
||||
return { data };
|
||||
},
|
||||
defaultSelectorOptions
|
||||
);
|
||||
return { data };
|
||||
});
|
||||
|
||||
const { data } = useAppSelector(selector);
|
||||
const isOpen = useAppSelector((state) => state.nodes.isAddNodePopoverOpen);
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { useToken } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useIsValidConnection } from 'features/nodes/hooks/useIsValidConnection';
|
||||
import {
|
||||
connectionEnded,
|
||||
@ -67,17 +66,13 @@ const nodeTypes = {
|
||||
// TODO: can we support reactflow? if not, we could style the attribution so it matches the app
|
||||
const proOptions: ProOptions = { hideAttribution: true };
|
||||
|
||||
const selector = createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const { shouldSnapToGrid, selectionMode } = nodes;
|
||||
return {
|
||||
shouldSnapToGrid,
|
||||
selectionMode,
|
||||
};
|
||||
},
|
||||
defaultSelectorOptions
|
||||
);
|
||||
const selector = createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const { shouldSnapToGrid, selectionMode } = nodes;
|
||||
return {
|
||||
shouldSnapToGrid,
|
||||
selectionMode,
|
||||
};
|
||||
});
|
||||
|
||||
export const Flow = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar';
|
||||
import { getFieldColor } from 'features/nodes/components/flow/edges/util/getEdgeColor';
|
||||
import { memo } from 'react';
|
||||
import { ConnectionLineComponentProps, getBezierPath } from 'reactflow';
|
||||
import { getFieldColor } from 'features/nodes/components/flow/edges/util/getEdgeColor';
|
||||
|
||||
const selector = createSelector(stateSelector, ({ nodes }) => {
|
||||
const selector = createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const { shouldAnimateEdges, connectionStartFieldType, shouldColorEdges } =
|
||||
nodes;
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { colorTokenToCssVar } from 'common/util/colorTokenToCssVar';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { getFieldColor } from './getEdgeColor';
|
||||
@ -12,31 +11,26 @@ export const makeEdgeSelector = (
|
||||
targetHandleId: string | null | undefined,
|
||||
selected?: boolean
|
||||
) =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const sourceNode = nodes.nodes.find((node) => node.id === source);
|
||||
const targetNode = nodes.nodes.find((node) => node.id === target);
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const sourceNode = nodes.nodes.find((node) => node.id === source);
|
||||
const targetNode = nodes.nodes.find((node) => node.id === target);
|
||||
|
||||
const isInvocationToInvocationEdge =
|
||||
isInvocationNode(sourceNode) && isInvocationNode(targetNode);
|
||||
const isInvocationToInvocationEdge =
|
||||
isInvocationNode(sourceNode) && isInvocationNode(targetNode);
|
||||
|
||||
const isSelected =
|
||||
sourceNode?.selected || targetNode?.selected || selected;
|
||||
const sourceType = isInvocationToInvocationEdge
|
||||
? sourceNode?.data?.outputs[sourceHandleId || '']?.type
|
||||
: undefined;
|
||||
const isSelected = sourceNode?.selected || targetNode?.selected || selected;
|
||||
const sourceType = isInvocationToInvocationEdge
|
||||
? sourceNode?.data?.outputs[sourceHandleId || '']?.type
|
||||
: undefined;
|
||||
|
||||
const stroke =
|
||||
sourceType && nodes.shouldColorEdges
|
||||
? getFieldColor(sourceType)
|
||||
: colorTokenToCssVar('base.500');
|
||||
const stroke =
|
||||
sourceType && nodes.shouldColorEdges
|
||||
? getFieldColor(sourceType)
|
||||
: colorTokenToCssVar('base.500');
|
||||
|
||||
return {
|
||||
isSelected,
|
||||
shouldAnimate: nodes.shouldAnimateEdges && isSelected,
|
||||
stroke,
|
||||
};
|
||||
},
|
||||
defaultSelectorOptions
|
||||
);
|
||||
return {
|
||||
isSelected,
|
||||
shouldAnimate: nodes.shouldAnimateEdges && isSelected,
|
||||
stroke,
|
||||
};
|
||||
});
|
||||
|
@ -1,25 +1,28 @@
|
||||
import { useState, PropsWithChildren, memo, useCallback } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { Flex, Image, Text } from '@chakra-ui/react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import NodeWrapper from 'features/nodes/components/flow/nodes/common/NodeWrapper';
|
||||
import NextPrevImageButtons from 'features/gallery/components/NextPrevImageButtons';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import IAIDndImage from 'common/components/IAIDndImage';
|
||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import NextPrevImageButtons from 'features/gallery/components/NextPrevImageButtons';
|
||||
import NodeWrapper from 'features/nodes/components/flow/nodes/common/NodeWrapper';
|
||||
import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { motion } from 'framer-motion';
|
||||
import { PropsWithChildren, memo, useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { NodeProps } from 'reactflow';
|
||||
|
||||
const selector = createSelector(stateSelector, ({ system, gallery }) => {
|
||||
const imageDTO = gallery.selection[gallery.selection.length - 1];
|
||||
const selector = createMemoizedSelector(
|
||||
stateSelector,
|
||||
({ system, gallery }) => {
|
||||
const imageDTO = gallery.selection[gallery.selection.length - 1];
|
||||
|
||||
return {
|
||||
imageDTO,
|
||||
progressImage: system.denoiseProgress?.progress_image,
|
||||
};
|
||||
});
|
||||
return {
|
||||
imageDTO,
|
||||
progressImage: system.denoiseProgress?.progress_image,
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const CurrentImageNode = (props: NodeProps) => {
|
||||
const { progressImage, imageDTO } = useSelector(selector);
|
||||
|
@ -7,7 +7,7 @@ import {
|
||||
Text,
|
||||
Tooltip,
|
||||
} from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants';
|
||||
@ -16,8 +16,8 @@ import {
|
||||
zNodeStatus,
|
||||
} from 'features/nodes/types/invocation';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { FaCheck, FaEllipsisH, FaExclamation } from 'react-icons/fa';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaCheck, FaEllipsisH, FaExclamation } from 'react-icons/fa';
|
||||
|
||||
type Props = {
|
||||
nodeId: string;
|
||||
@ -35,7 +35,7 @@ const circleStyles = {
|
||||
const InvocationNodeStatusIndicator = ({ nodeId }: Props) => {
|
||||
const selectNodeExecutionState = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
createMemoizedSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => nodes.nodeExecutionStates[nodeId]
|
||||
),
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import InvocationNode from 'features/nodes/components/flow/nodes/Invocation/InvocationNode';
|
||||
import { InvocationNodeData } from 'features/nodes/types/invocation';
|
||||
import { memo, useMemo } from 'react';
|
||||
import { NodeProps } from 'reactflow';
|
||||
import InvocationNode from 'features/nodes/components/flow/nodes/Invocation/InvocationNode';
|
||||
import InvocationNodeUnknownFallback from './InvocationNodeUnknownFallback';
|
||||
|
||||
const InvocationNodeWrapper = (props: NodeProps<InvocationNodeData>) => {
|
||||
@ -13,7 +13,7 @@ const InvocationNodeWrapper = (props: NodeProps<InvocationNodeData>) => {
|
||||
|
||||
const hasTemplateSelector = useMemo(
|
||||
() =>
|
||||
createSelector(stateSelector, ({ nodes }) =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) =>
|
||||
Boolean(nodes.nodeTemplates[type])
|
||||
),
|
||||
[type]
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { MenuGroup, MenuItem, MenuList } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import {
|
||||
IAIContextMenu,
|
||||
IAIContextMenuProps,
|
||||
@ -15,9 +14,9 @@ import {
|
||||
workflowExposedFieldRemoved,
|
||||
} from 'features/nodes/store/workflowSlice';
|
||||
import { MouseEvent, ReactNode, memo, useCallback, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaMinus, FaPlus } from 'react-icons/fa';
|
||||
import { menuListMotionProps } from 'theme/components/menu';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type Props = {
|
||||
nodeId: string;
|
||||
@ -39,19 +38,15 @@ const FieldContextMenu = ({ nodeId, fieldName, kind, children }: Props) => {
|
||||
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ workflow }) => {
|
||||
const isExposed = Boolean(
|
||||
workflow.exposedFields.find(
|
||||
(f) => f.nodeId === nodeId && f.fieldName === fieldName
|
||||
)
|
||||
);
|
||||
createMemoizedSelector(stateSelector, ({ workflow }) => {
|
||||
const isExposed = Boolean(
|
||||
workflow.exposedFields.find(
|
||||
(f) => f.nodeId === nodeId && f.fieldName === fieldName
|
||||
)
|
||||
);
|
||||
|
||||
return { isExposed };
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
return { isExposed };
|
||||
}),
|
||||
[fieldName, nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Flex, Text } from '@chakra-ui/react';
|
||||
import { skipToken } from '@reduxjs/toolkit/dist/query';
|
||||
import { skipToken } from '@reduxjs/toolkit/query';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import IAIDndImage from 'common/components/IAIDndImage';
|
||||
import IAIDndImageIcon from 'common/components/IAIDndImageIcon';
|
||||
|
@ -1,38 +1,33 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
|
||||
import { fieldSchedulerValueChanged } from 'features/nodes/store/nodesSlice';
|
||||
import {
|
||||
SchedulerFieldInputTemplate,
|
||||
SchedulerFieldInputInstance,
|
||||
SchedulerFieldInputTemplate,
|
||||
} from 'features/nodes/types/field';
|
||||
import { FieldComponentProps } from './types';
|
||||
import { ParameterScheduler } from 'features/parameters/types/parameterSchemas';
|
||||
import { SCHEDULER_LABEL_MAP } from 'features/parameters/types/constants';
|
||||
import { ParameterScheduler } from 'features/parameters/types/parameterSchemas';
|
||||
import { map } from 'lodash-es';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { FieldComponentProps } from './types';
|
||||
|
||||
const selector = createSelector(
|
||||
[stateSelector],
|
||||
({ ui }) => {
|
||||
const { favoriteSchedulers: enabledSchedulers } = ui;
|
||||
const selector = createMemoizedSelector([stateSelector], ({ ui }) => {
|
||||
const { favoriteSchedulers: enabledSchedulers } = ui;
|
||||
|
||||
const data = map(SCHEDULER_LABEL_MAP, (label, name) => ({
|
||||
value: name,
|
||||
label: label,
|
||||
group: enabledSchedulers.includes(name as ParameterScheduler)
|
||||
? 'Favorites'
|
||||
: undefined,
|
||||
})).sort((a, b) => a.label.localeCompare(b.label));
|
||||
const data = map(SCHEDULER_LABEL_MAP, (label, name) => ({
|
||||
value: name,
|
||||
label: label,
|
||||
group: enabledSchedulers.includes(name as ParameterScheduler)
|
||||
? 'Favorites'
|
||||
: undefined,
|
||||
})).sort((a, b) => a.label.localeCompare(b.label));
|
||||
|
||||
return {
|
||||
data,
|
||||
};
|
||||
},
|
||||
defaultSelectorOptions
|
||||
);
|
||||
return {
|
||||
data,
|
||||
};
|
||||
});
|
||||
|
||||
const SchedulerFieldInputComponent = (
|
||||
props: FieldComponentProps<
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
useColorModeValue,
|
||||
useToken,
|
||||
} from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import NodeSelectionOverlay from 'common/components/NodeSelectionOverlay';
|
||||
@ -37,7 +37,7 @@ const NodeWrapper = (props: NodeWrapperProps) => {
|
||||
|
||||
const selectIsInProgress = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
createMemoizedSelector(
|
||||
stateSelector,
|
||||
({ nodes }) =>
|
||||
nodes.nodeExecutionStates[nodeId]?.status ===
|
||||
|
@ -11,10 +11,9 @@ import {
|
||||
ModalOverlay,
|
||||
useDisclosure,
|
||||
} from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import IAISwitch from 'common/components/IAISwitch';
|
||||
import ReloadNodeTemplatesButton from 'features/nodes/components/flow/panels/TopCenterPanel/ReloadSchemaButton';
|
||||
import {
|
||||
@ -32,26 +31,22 @@ const formLabelProps: FormLabelProps = {
|
||||
fontWeight: 600,
|
||||
};
|
||||
|
||||
const selector = createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const {
|
||||
shouldAnimateEdges,
|
||||
shouldValidateGraph,
|
||||
shouldSnapToGrid,
|
||||
shouldColorEdges,
|
||||
selectionMode,
|
||||
} = nodes;
|
||||
return {
|
||||
shouldAnimateEdges,
|
||||
shouldValidateGraph,
|
||||
shouldSnapToGrid,
|
||||
shouldColorEdges,
|
||||
selectionModeIsChecked: selectionMode === SelectionMode.Full,
|
||||
};
|
||||
},
|
||||
defaultSelectorOptions
|
||||
);
|
||||
const selector = createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const {
|
||||
shouldAnimateEdges,
|
||||
shouldValidateGraph,
|
||||
shouldSnapToGrid,
|
||||
shouldColorEdges,
|
||||
selectionMode,
|
||||
} = nodes;
|
||||
return {
|
||||
shouldAnimateEdges,
|
||||
shouldValidateGraph,
|
||||
shouldSnapToGrid,
|
||||
shouldColorEdges,
|
||||
selectionModeIsChecked: selectionMode === SelectionMode.Full,
|
||||
};
|
||||
});
|
||||
|
||||
type Props = {
|
||||
children: (props: { onOpen: () => void }) => ReactNode;
|
||||
|
@ -1,27 +1,22 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer';
|
||||
import { memo } from 'react';
|
||||
|
||||
const selector = createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const lastSelectedNodeId =
|
||||
nodes.selectedNodes[nodes.selectedNodes.length - 1];
|
||||
const selector = createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
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
|
||||
);
|
||||
|
||||
return {
|
||||
data: lastSelectedNode?.data,
|
||||
};
|
||||
},
|
||||
defaultSelectorOptions
|
||||
);
|
||||
return {
|
||||
data: lastSelectedNode?.data,
|
||||
};
|
||||
});
|
||||
|
||||
const InspectorDataTab = () => {
|
||||
const { data } = useAppSelector(selector);
|
||||
|
@ -6,10 +6,9 @@ import {
|
||||
HStack,
|
||||
Text,
|
||||
} from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import NotesTextarea from 'features/nodes/components/flow/nodes/Invocation/NotesTextarea';
|
||||
import ScrollableContent from 'features/nodes/components/sidePanel/ScrollableContent';
|
||||
@ -23,27 +22,23 @@ import { memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import EditableNodeTitle from './details/EditableNodeTitle';
|
||||
|
||||
const selector = createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const lastSelectedNodeId =
|
||||
nodes.selectedNodes[nodes.selectedNodes.length - 1];
|
||||
const selector = createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
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
|
||||
? nodes.nodeTemplates[lastSelectedNode.data.type]
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
node: lastSelectedNode,
|
||||
template: lastSelectedNodeTemplate,
|
||||
};
|
||||
},
|
||||
defaultSelectorOptions
|
||||
);
|
||||
return {
|
||||
node: lastSelectedNode,
|
||||
template: lastSelectedNodeTemplate,
|
||||
};
|
||||
});
|
||||
|
||||
const InspectorDetailsTab = () => {
|
||||
const { node, template } = useAppSelector(selector);
|
||||
|
@ -1,43 +1,38 @@
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer';
|
||||
import ScrollableContent from 'features/nodes/components/sidePanel/ScrollableContent';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ImageOutput } from 'services/api/types';
|
||||
import { AnyResult } from 'services/events/types';
|
||||
import ScrollableContent from 'features/nodes/components/sidePanel/ScrollableContent';
|
||||
import ImageOutputPreview from './outputs/ImageOutputPreview';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const selector = createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const lastSelectedNodeId =
|
||||
nodes.selectedNodes[nodes.selectedNodes.length - 1];
|
||||
const selector = createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
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
|
||||
? nodes.nodeTemplates[lastSelectedNode.data.type]
|
||||
: undefined;
|
||||
|
||||
const nes =
|
||||
nodes.nodeExecutionStates[lastSelectedNodeId ?? '__UNKNOWN_NODE__'];
|
||||
const nes =
|
||||
nodes.nodeExecutionStates[lastSelectedNodeId ?? '__UNKNOWN_NODE__'];
|
||||
|
||||
return {
|
||||
node: lastSelectedNode,
|
||||
template: lastSelectedNodeTemplate,
|
||||
nes,
|
||||
};
|
||||
},
|
||||
defaultSelectorOptions
|
||||
);
|
||||
return {
|
||||
node: lastSelectedNode,
|
||||
template: lastSelectedNodeTemplate,
|
||||
nes,
|
||||
};
|
||||
});
|
||||
|
||||
const InspectorOutputsTab = () => {
|
||||
const { node, template, nes } = useAppSelector(selector);
|
||||
|
@ -1,32 +1,27 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import DataViewer from 'features/gallery/components/ImageMetadataViewer/DataViewer';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const selector = createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const lastSelectedNodeId =
|
||||
nodes.selectedNodes[nodes.selectedNodes.length - 1];
|
||||
const selector = createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
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
|
||||
? nodes.nodeTemplates[lastSelectedNode.data.type]
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
template: lastSelectedNodeTemplate,
|
||||
};
|
||||
},
|
||||
defaultSelectorOptions
|
||||
);
|
||||
return {
|
||||
template: lastSelectedNodeTemplate,
|
||||
};
|
||||
});
|
||||
|
||||
const NodeTemplateInspector = () => {
|
||||
const { template } = useAppSelector(selector);
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { Flex, FormControl, FormLabel } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import IAIInput from 'common/components/IAIInput';
|
||||
import IAITextarea from 'common/components/IAITextarea';
|
||||
import ScrollableContent from 'features/nodes/components/sidePanel/ScrollableContent';
|
||||
@ -18,24 +17,19 @@ import {
|
||||
import { ChangeEvent, memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const selector = createSelector(
|
||||
stateSelector,
|
||||
({ workflow }) => {
|
||||
const { author, name, description, tags, version, contact, notes } =
|
||||
workflow;
|
||||
const selector = createMemoizedSelector(stateSelector, ({ workflow }) => {
|
||||
const { author, name, description, tags, version, contact, notes } = workflow;
|
||||
|
||||
return {
|
||||
name,
|
||||
author,
|
||||
description,
|
||||
tags,
|
||||
version,
|
||||
contact,
|
||||
notes,
|
||||
};
|
||||
},
|
||||
defaultSelectorOptions
|
||||
);
|
||||
return {
|
||||
name,
|
||||
author,
|
||||
description,
|
||||
tags,
|
||||
version,
|
||||
contact,
|
||||
notes,
|
||||
};
|
||||
});
|
||||
|
||||
const WorkflowGeneralTab = () => {
|
||||
const { author, name, description, tags, version, contact, notes } =
|
||||
|
@ -1,23 +1,18 @@
|
||||
import { Box, Flex } from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import { memo } from 'react';
|
||||
import LinearViewField from 'features/nodes/components/flow/nodes/Invocation/fields/LinearViewField';
|
||||
import ScrollableContent from 'features/nodes/components/sidePanel/ScrollableContent';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const selector = createSelector(
|
||||
stateSelector,
|
||||
({ workflow }) => {
|
||||
return {
|
||||
fields: workflow.exposedFields,
|
||||
};
|
||||
},
|
||||
defaultSelectorOptions
|
||||
);
|
||||
const selector = createMemoizedSelector(stateSelector, ({ workflow }) => {
|
||||
return {
|
||||
fields: workflow.exposedFields,
|
||||
};
|
||||
});
|
||||
|
||||
const WorkflowLinearTab = () => {
|
||||
const { fields } = useAppSelector(selector);
|
||||
|
@ -1,37 +1,32 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { keys, map } from 'lodash-es';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { getSortedFilteredFieldNames } from 'features/nodes/util/node/getSortedFilteredFieldNames';
|
||||
import { TEMPLATE_BUILDER_MAP } from 'features/nodes/util/schema/buildFieldInputTemplate';
|
||||
import { keys, map } from 'lodash-es';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useAnyOrDirectInputFieldNames = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return [];
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node.data.type];
|
||||
if (!nodeTemplate) {
|
||||
return [];
|
||||
}
|
||||
const fields = map(nodeTemplate.inputs).filter(
|
||||
(field) =>
|
||||
(['any', 'direct'].includes(field.input) ||
|
||||
field.type.isCollectionOrScalar) &&
|
||||
keys(TEMPLATE_BUILDER_MAP).includes(field.type.name)
|
||||
);
|
||||
return getSortedFilteredFieldNames(fields);
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return [];
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node.data.type];
|
||||
if (!nodeTemplate) {
|
||||
return [];
|
||||
}
|
||||
const fields = map(nodeTemplate.inputs).filter(
|
||||
(field) =>
|
||||
(['any', 'direct'].includes(field.input) ||
|
||||
field.type.isCollectionOrScalar) &&
|
||||
keys(TEMPLATE_BUILDER_MAP).includes(field.type.name)
|
||||
);
|
||||
return getSortedFilteredFieldNames(fields);
|
||||
}),
|
||||
[nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { RootState } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { useCallback } from 'react';
|
||||
import { Node, useReactFlow } from 'reactflow';
|
||||
import {
|
||||
DRAG_HANDLE_CLASSNAME,
|
||||
NODE_WIDTH,
|
||||
@ -11,8 +9,10 @@ import { AnyNode, InvocationTemplate } from 'features/nodes/types/invocation';
|
||||
import { buildCurrentImageNode } from 'features/nodes/util/node/buildCurrentImageNode';
|
||||
import { buildInvocationNode } from 'features/nodes/util/node/buildInvocationNode';
|
||||
import { buildNotesNode } from 'features/nodes/util/node/buildNotesNode';
|
||||
import { useCallback } from 'react';
|
||||
import { Node, useReactFlow } from 'reactflow';
|
||||
|
||||
const templatesSelector = createSelector(
|
||||
const templatesSelector = createMemoizedSelector(
|
||||
[(state: RootState) => state.nodes],
|
||||
(nodes) => nodes.nodeTemplates
|
||||
);
|
||||
|
@ -1,40 +1,35 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { keys, map } from 'lodash-es';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { getSortedFilteredFieldNames } from 'features/nodes/util/node/getSortedFilteredFieldNames';
|
||||
import { TEMPLATE_BUILDER_MAP } from 'features/nodes/util/schema/buildFieldInputTemplate';
|
||||
import { keys, map } from 'lodash-es';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useConnectionInputFieldNames = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return [];
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node.data.type];
|
||||
if (!nodeTemplate) {
|
||||
return [];
|
||||
}
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return [];
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node.data.type];
|
||||
if (!nodeTemplate) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// get the visible fields
|
||||
const fields = map(nodeTemplate.inputs).filter(
|
||||
(field) =>
|
||||
(field.input === 'connection' &&
|
||||
!field.type.isCollectionOrScalar) ||
|
||||
!keys(TEMPLATE_BUILDER_MAP).includes(field.type.name)
|
||||
);
|
||||
// get the visible fields
|
||||
const fields = map(nodeTemplate.inputs).filter(
|
||||
(field) =>
|
||||
(field.input === 'connection' &&
|
||||
!field.type.isCollectionOrScalar) ||
|
||||
!keys(TEMPLATE_BUILDER_MAP).includes(field.type.name)
|
||||
);
|
||||
|
||||
return getSortedFilteredFieldNames(fields);
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
return getSortedFilteredFieldNames(fields);
|
||||
}),
|
||||
[nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { makeConnectionErrorSelector } from 'features/nodes/store/util/makeIsConnectionValidSelector';
|
||||
import { useMemo } from 'react';
|
||||
import { useFieldType } from './useFieldType.ts';
|
||||
|
||||
const selectIsConnectionInProgress = createSelector(
|
||||
const selectIsConnectionInProgress = createMemoizedSelector(
|
||||
stateSelector,
|
||||
({ nodes }) =>
|
||||
nodes.connectionStartFieldType !== null &&
|
||||
@ -27,7 +27,7 @@ export const useConnectionState = ({
|
||||
|
||||
const selectIsConnected = useMemo(
|
||||
() =>
|
||||
createSelector(stateSelector, ({ nodes }) =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) =>
|
||||
Boolean(
|
||||
nodes.edges.filter((edge) => {
|
||||
return (
|
||||
@ -54,7 +54,7 @@ export const useConnectionState = ({
|
||||
|
||||
const selectIsConnectionStartField = useMemo(
|
||||
() =>
|
||||
createSelector(stateSelector, ({ nodes }) =>
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) =>
|
||||
Boolean(
|
||||
nodes.connectionStartParams?.nodeId === nodeId &&
|
||||
nodes.connectionStartParams?.handleId === fieldName &&
|
||||
|
@ -1,29 +1,24 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { compareVersions } from 'compare-versions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useDoNodeVersionsMatch = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
if (!nodeTemplate?.version || !node.data?.version) {
|
||||
return false;
|
||||
}
|
||||
return compareVersions(nodeTemplate.version, node.data.version) === 0;
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
if (!nodeTemplate?.version || !node.data?.version) {
|
||||
return false;
|
||||
}
|
||||
return compareVersions(nodeTemplate.version, node.data.version) === 0;
|
||||
}),
|
||||
[nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,24 +1,19 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useDoesInputHaveValue = (nodeId: string, fieldName: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
return node?.data.inputs[fieldName]?.value !== undefined;
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
return node?.data.inputs[fieldName]?.value !== undefined;
|
||||
}),
|
||||
[fieldName, nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,24 +1,19 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useFieldInstance = (nodeId: string, fieldName: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
return node?.data.inputs[fieldName];
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
return node?.data.inputs[fieldName];
|
||||
}),
|
||||
[fieldName, nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,24 +1,19 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useFieldInputInstance = (nodeId: string, fieldName: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
return node.data.inputs[fieldName];
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
return node.data.inputs[fieldName];
|
||||
}),
|
||||
[fieldName, nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,26 +1,21 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useFieldInputKind = (nodeId: string, fieldName: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
const fieldTemplate = nodeTemplate?.inputs[fieldName];
|
||||
return fieldTemplate?.input;
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
const fieldTemplate = nodeTemplate?.inputs[fieldName];
|
||||
return fieldTemplate?.input;
|
||||
}),
|
||||
[fieldName, nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,25 +1,20 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useFieldInputTemplate = (nodeId: string, fieldName: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
return nodeTemplate?.inputs[fieldName];
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
return nodeTemplate?.inputs[fieldName];
|
||||
}),
|
||||
[fieldName, nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,24 +1,19 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useFieldLabel = (nodeId: string, fieldName: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
return node?.data.inputs[fieldName]?.label;
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
return node?.data.inputs[fieldName]?.label;
|
||||
}),
|
||||
[fieldName, nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,24 +1,19 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useFieldOutputInstance = (nodeId: string, fieldName: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
return node.data.outputs[fieldName];
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
return node.data.outputs[fieldName];
|
||||
}),
|
||||
[fieldName, nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,25 +1,20 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useFieldOutputTemplate = (nodeId: string, fieldName: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
return nodeTemplate?.outputs[fieldName];
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
return nodeTemplate?.outputs[fieldName];
|
||||
}),
|
||||
[fieldName, nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { KIND_MAP } from 'features/nodes/types/constants';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useFieldTemplate = (
|
||||
nodeId: string,
|
||||
@ -13,18 +12,14 @@ export const useFieldTemplate = (
|
||||
) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
return nodeTemplate?.[KIND_MAP[kind]][fieldName];
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
return nodeTemplate?.[KIND_MAP[kind]][fieldName];
|
||||
}),
|
||||
[fieldName, kind, nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { KIND_MAP } from 'features/nodes/types/constants';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useFieldTemplateTitle = (
|
||||
nodeId: string,
|
||||
@ -13,18 +12,14 @@ export const useFieldTemplateTitle = (
|
||||
) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
return nodeTemplate?.[KIND_MAP[kind]][fieldName]?.title;
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
return nodeTemplate?.[KIND_MAP[kind]][fieldName]?.title;
|
||||
}),
|
||||
[fieldName, kind, nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { KIND_MAP } from 'features/nodes/types/constants';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useFieldType = (
|
||||
nodeId: string,
|
||||
@ -13,18 +12,14 @@ export const useFieldType = (
|
||||
) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const field = node.data[KIND_MAP[kind]][fieldName];
|
||||
return field?.type;
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return;
|
||||
}
|
||||
const field = node.data[KIND_MAP[kind]][fieldName];
|
||||
return field?.type;
|
||||
}),
|
||||
[fieldName, kind, nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,27 +1,22 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { getNeedsUpdate } from 'features/nodes/util/node/nodeUpdate';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { getNeedsUpdate } from 'features/nodes/util/node/nodeUpdate';
|
||||
|
||||
const selector = createSelector(
|
||||
stateSelector,
|
||||
(state) => {
|
||||
const nodes = state.nodes.nodes;
|
||||
const templates = state.nodes.nodeTemplates;
|
||||
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];
|
||||
if (!template) {
|
||||
return false;
|
||||
}
|
||||
return getNeedsUpdate(node, template);
|
||||
});
|
||||
return needsUpdate;
|
||||
},
|
||||
defaultSelectorOptions
|
||||
);
|
||||
const needsUpdate = nodes.filter(isInvocationNode).some((node) => {
|
||||
const template = templates[node.data.type];
|
||||
if (!template) {
|
||||
return false;
|
||||
}
|
||||
return getNeedsUpdate(node, template);
|
||||
});
|
||||
return needsUpdate;
|
||||
});
|
||||
|
||||
export const useGetNodesNeedUpdate = () => {
|
||||
const getNeedsUpdate = useAppSelector(selector);
|
||||
|
@ -1,31 +1,26 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { some } from 'lodash-es';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
|
||||
export const useHasImageOutput = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
return some(
|
||||
node.data.outputs,
|
||||
(output) =>
|
||||
output.type.name === 'ImageField' &&
|
||||
// the image primitive node (node type "image") does not actually save the image, do not show the image-saving checkboxes
|
||||
node.data.type !== 'image'
|
||||
);
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
return some(
|
||||
node.data.outputs,
|
||||
(output) =>
|
||||
output.type.name === 'ImageField' &&
|
||||
// the image primitive node (node type "image") does not actually save the image, do not show the image-saving checkboxes
|
||||
node.data.type !== 'image'
|
||||
);
|
||||
}),
|
||||
[nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,24 +1,19 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useIsIntermediate = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
return node.data.isIntermediate;
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
return node.data.isIntermediate;
|
||||
}),
|
||||
[nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,20 +1,18 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { mouseOverFieldChanged } from 'features/nodes/store/nodesSlice';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
export const useIsMouseOverField = (nodeId: string, fieldName: string) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
createMemoizedSelector(
|
||||
stateSelector,
|
||||
({ nodes }) =>
|
||||
nodes.mouseOverField?.nodeId === nodeId &&
|
||||
nodes.mouseOverField?.fieldName === fieldName,
|
||||
defaultSelectorOptions
|
||||
nodes.mouseOverField?.fieldName === fieldName
|
||||
),
|
||||
[fieldName, nodeId]
|
||||
);
|
||||
|
@ -1,18 +1,16 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { mouseOverNodeChanged } from 'features/nodes/store/nodesSlice';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
export const useMouseOverNode = (nodeId: string) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
createMemoizedSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => nodes.mouseOverNode === nodeId,
|
||||
defaultSelectorOptions
|
||||
({ nodes }) => nodes.mouseOverNode === nodeId
|
||||
),
|
||||
[nodeId]
|
||||
);
|
||||
|
@ -1,20 +1,15 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useNodeData = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
return node?.data;
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
return node?.data;
|
||||
}),
|
||||
[nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,25 +1,20 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useNodeLabel = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return node.data.label;
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
return node.data.label;
|
||||
}),
|
||||
[nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,23 +1,18 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { getNeedsUpdate } from 'features/nodes/util/node/nodeUpdate';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useNodeNeedsUpdate = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
const template = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
return { node, template };
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
const template = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
return { node, template };
|
||||
}),
|
||||
[nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,24 +1,19 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useNodePack = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
return node.data.nodePack;
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
return node.data.nodePack;
|
||||
}),
|
||||
[nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,21 +1,16 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useNodeTemplate = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
return nodeTemplate;
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
const nodeTemplate = nodes.nodeTemplates[node?.data.type ?? ''];
|
||||
return nodeTemplate;
|
||||
}),
|
||||
[nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,20 +1,18 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { InvocationTemplate } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useNodeTemplateByType = (type: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
createMemoizedSelector(
|
||||
stateSelector,
|
||||
({ nodes }): InvocationTemplate | undefined => {
|
||||
const nodeTemplate = nodes.nodeTemplates[type];
|
||||
return nodeTemplate;
|
||||
},
|
||||
defaultSelectorOptions
|
||||
}
|
||||
),
|
||||
[type]
|
||||
);
|
||||
|
@ -1,28 +1,23 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useNodeTemplateTitle = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
const nodeTemplate = node
|
||||
? nodes.nodeTemplates[node.data.type]
|
||||
: undefined;
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
const nodeTemplate = node
|
||||
? nodes.nodeTemplates[node.data.type]
|
||||
: undefined;
|
||||
|
||||
return nodeTemplate?.title;
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
return nodeTemplate?.title;
|
||||
}),
|
||||
[nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,31 +1,26 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { map } from 'lodash-es';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { getSortedFilteredFieldNames } from 'features/nodes/util/node/getSortedFilteredFieldNames';
|
||||
import { map } from 'lodash-es';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useOutputFieldNames = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return [];
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node.data.type];
|
||||
if (!nodeTemplate) {
|
||||
return [];
|
||||
}
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return [];
|
||||
}
|
||||
const nodeTemplate = nodes.nodeTemplates[node.data.type];
|
||||
if (!nodeTemplate) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return getSortedFilteredFieldNames(map(nodeTemplate.outputs));
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
return getSortedFilteredFieldNames(map(nodeTemplate.outputs));
|
||||
}),
|
||||
[nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,26 +1,21 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppSelector } from 'app/store/storeHooks';
|
||||
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
|
||||
import { useMemo } from 'react';
|
||||
import { isInvocationNode } from 'features/nodes/types/invocation';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useUseCache = (nodeId: string) => {
|
||||
const selector = useMemo(
|
||||
() =>
|
||||
createSelector(
|
||||
stateSelector,
|
||||
({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
// cast to boolean to support older workflows that didn't have useCache
|
||||
// TODO: handle this better somehow
|
||||
return node.data.useCache;
|
||||
},
|
||||
defaultSelectorOptions
|
||||
),
|
||||
createMemoizedSelector(stateSelector, ({ nodes }) => {
|
||||
const node = nodes.nodes.find((node) => node.id === nodeId);
|
||||
if (!isInvocationNode(node)) {
|
||||
return false;
|
||||
}
|
||||
// cast to boolean to support older workflows that didn't have useCache
|
||||
// TODO: handle this better somehow
|
||||
return node.data.useCache;
|
||||
}),
|
||||
[nodeId]
|
||||
);
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Connection, Edge, HandleType, Node } from 'reactflow';
|
||||
|
||||
import {
|
||||
FieldInputInstance,
|
||||
FieldOutputInstance,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { createMemoizedSelector } from 'app/store/createMemoizedSelector';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { FieldType } from 'features/nodes/types/field';
|
||||
import i18n from 'i18next';
|
||||
@ -17,7 +17,7 @@ export const makeConnectionErrorSelector = (
|
||||
handleType: HandleType,
|
||||
fieldType?: FieldType
|
||||
) => {
|
||||
return createSelector(stateSelector, (state): string | undefined => {
|
||||
return createMemoizedSelector(stateSelector, (state): string | undefined => {
|
||||
if (!fieldType) {
|
||||
return i18n.t('nodes.noFieldType');
|
||||
}
|
||||
|
Reference in New Issue
Block a user