feat(ui): organise nodes files

- also remove old `.gitignore` of `inputs/` which wasn't used and was ignoring a frontend folder
This commit is contained in:
psychedelicious
2023-08-19 14:19:32 +10:00
parent 0b9ae74192
commit 211e8203f8
101 changed files with 856 additions and 855 deletions

4
.gitignore vendored
View File

@ -15,9 +15,6 @@ invokeai.init
# ignore the Anaconda/Miniconda installer used while building Docker image # ignore the Anaconda/Miniconda installer used while building Docker image
anaconda.sh anaconda.sh
# ignore a directory which serves as a place for initial images
inputs/
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/
*.py[cod] *.py[cod]
@ -213,7 +210,6 @@ invokeai/frontend/node_modules
gfpgan/ gfpgan/
models/ldm/stable-diffusion-v1/*.sha256 models/ldm/stable-diffusion-v1/*.sha256
# GFPGAN model files # GFPGAN model files
gfpgan/ gfpgan/

View File

@ -1,199 +0,0 @@
import { Badge, Flex } from '@chakra-ui/react';
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { useChakraThemeTokens } from 'common/hooks/useChakraThemeTokens';
import { memo, useMemo } from 'react';
import {
BaseEdge,
EdgeLabelRenderer,
EdgeProps,
getBezierPath,
} from 'reactflow';
import { FIELDS, colorTokenToCssVar } from '../types/constants';
import { isInvocationNode } from '../types/types';
const makeEdgeSelector = (
source: string,
sourceHandleId: string | null | undefined,
target: string,
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);
const isInvocationToInvocationEdge =
isInvocationNode(sourceNode) && isInvocationNode(targetNode);
const isSelected =
sourceNode?.selected || targetNode?.selected || selected;
const sourceType = isInvocationToInvocationEdge
? sourceNode?.data?.outputs[sourceHandleId || '']?.type
: undefined;
const stroke =
sourceType && nodes.shouldColorEdges
? colorTokenToCssVar(FIELDS[sourceType].color)
: colorTokenToCssVar('base.500');
return {
isSelected,
shouldAnimate: nodes.shouldAnimateEdges && isSelected,
stroke,
};
},
defaultSelectorOptions
);
const CollapsedEdge = memo(
({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
markerEnd,
data,
selected,
source,
target,
sourceHandleId,
targetHandleId,
}: EdgeProps<{ count: number }>) => {
const selector = useMemo(
() =>
makeEdgeSelector(
source,
sourceHandleId,
target,
targetHandleId,
selected
),
[selected, source, sourceHandleId, target, targetHandleId]
);
const { isSelected, shouldAnimate } = useAppSelector(selector);
const [edgePath, labelX, labelY] = getBezierPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
});
const { base500 } = useChakraThemeTokens();
return (
<>
<BaseEdge
path={edgePath}
markerEnd={markerEnd}
style={{
strokeWidth: isSelected ? 3 : 2,
stroke: base500,
opacity: isSelected ? 0.8 : 0.5,
animation: shouldAnimate
? 'dashdraw 0.5s linear infinite'
: undefined,
strokeDasharray: shouldAnimate ? 5 : 'none',
}}
/>
{data?.count && data.count > 1 && (
<EdgeLabelRenderer>
<Flex
sx={{
position: 'absolute',
transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
}}
className="nodrag nopan"
>
<Badge
variant="solid"
sx={{
bg: 'base.500',
opacity: isSelected ? 0.8 : 0.5,
boxShadow: 'base',
}}
>
{data.count}
</Badge>
</Flex>
</EdgeLabelRenderer>
)}
</>
);
}
);
CollapsedEdge.displayName = 'CollapsedEdge';
const DefaultEdge = memo(
({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
markerEnd,
selected,
source,
target,
sourceHandleId,
targetHandleId,
}: EdgeProps) => {
const selector = useMemo(
() =>
makeEdgeSelector(
source,
sourceHandleId,
target,
targetHandleId,
selected
),
[source, sourceHandleId, target, targetHandleId, selected]
);
const { isSelected, shouldAnimate, stroke } = useAppSelector(selector);
const [edgePath] = getBezierPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
});
return (
<BaseEdge
path={edgePath}
markerEnd={markerEnd}
style={{
strokeWidth: isSelected ? 3 : 2,
stroke,
opacity: isSelected ? 0.8 : 0.5,
animation: shouldAnimate
? 'dashdraw 0.5s linear infinite'
: undefined,
strokeDasharray: shouldAnimate ? 5 : 'none',
}}
/>
);
}
);
DefaultEdge.displayName = 'DefaultEdge';
export const edgeTypes = {
collapsed: CollapsedEdge,
default: DefaultEdge,
};

View File

@ -1,9 +0,0 @@
import CurrentImageNode from './nodes/CurrentImageNode';
import InvocationNodeWrapper from './nodes/InvocationNodeWrapper';
import NotesNode from './nodes/NotesNode';
export const nodeTypes = {
invocation: InvocationNodeWrapper,
current_image: CurrentImageNode,
notes: NotesNode,
};

View File

@ -6,8 +6,8 @@ import { memo, useState } from 'react';
import { MdDeviceHub } from 'react-icons/md'; import { MdDeviceHub } from 'react-icons/md';
import { Panel, PanelGroup } from 'react-resizable-panels'; import { Panel, PanelGroup } from 'react-resizable-panels';
import 'reactflow/dist/style.css'; import 'reactflow/dist/style.css';
import NodeEditorPanelGroup from './panel/NodeEditorPanelGroup'; import NodeEditorPanelGroup from './sidePanel/NodeEditorPanelGroup';
import { Flow } from './Flow'; import { Flow } from './flow/Flow';
import { AnimatePresence, motion } from 'framer-motion'; import { AnimatePresence, motion } from 'framer-motion';
const NodeEditor = () => { const NodeEditor = () => {

View File

@ -1,26 +0,0 @@
import { RootState } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import ImageMetadataJSON from 'features/gallery/components/ImageMetadataViewer/ImageMetadataJSON';
import { omit } from 'lodash-es';
import { useMemo } from 'react';
import { useDebounce } from 'use-debounce';
import { buildNodesGraph } from '../util/graphBuilders/buildNodesGraph';
const useNodesGraph = () => {
const nodes = useAppSelector((state: RootState) => state.nodes);
const [debouncedNodes] = useDebounce(nodes, 300);
const graph = useMemo(
() => omit(buildNodesGraph(debouncedNodes), 'id'),
[debouncedNodes]
);
return graph;
};
const NodeGraph = () => {
const graph = useNodesGraph();
return <ImageMetadataJSON jsonObject={graph} label="Graph" />;
};
export default NodeGraph;

View File

@ -1,13 +0,0 @@
import {
InputFieldTemplate,
InputFieldValue,
} from 'features/nodes/types/types';
export type FieldComponentProps<
V extends InputFieldValue,
T extends InputFieldTemplate
> = {
nodeId: string;
field: V;
fieldTemplate: T;
};

View File

@ -17,7 +17,7 @@ import {
ProOptions, ProOptions,
ReactFlow, ReactFlow,
} from 'reactflow'; } from 'reactflow';
import { useIsValidConnection } from '../hooks/useIsValidConnection'; import { useIsValidConnection } from '../../hooks/useIsValidConnection';
import { import {
connectionEnded, connectionEnded,
connectionMade, connectionMade,
@ -32,18 +32,32 @@ import {
selectionCopied, selectionCopied,
selectionPasted, selectionPasted,
viewportChanged, viewportChanged,
} from '../store/nodesSlice'; } from '../../store/nodesSlice';
import { CustomConnectionLine } from './CustomConnectionLine'; import CustomConnectionLine from './connectionLines/CustomConnectionLine';
import { edgeTypes } from './CustomEdges'; import InvocationCollapsedEdge from './edges/InvocationCollapsedEdge';
import { nodeTypes } from './CustomNodes'; import InvocationDefaultEdge from './edges/InvocationDefaultEdge';
import BottomLeftPanel from './editorPanels/BottomLeftPanel'; import CurrentImageNode from './nodes/CurrentImage/CurrentImageNode';
import MinimapPanel from './editorPanels/MinimapPanel'; import InvocationNodeWrapper from './nodes/Invocation/InvocationNodeWrapper';
import TopCenterPanel from './editorPanels/TopCenterPanel'; import NotesNode from './nodes/Notes/NotesNode';
import TopLeftPanel from './editorPanels/TopLeftPanel'; import BottomLeftPanel from './panels/BottomLeftPanel/BottomLeftPanel';
import TopRightPanel from './editorPanels/TopRightPanel'; import MinimapPanel from './panels/MinimapPanel/MinimapPanel';
import TopCenterPanel from './panels/TopCenterPanel/TopCenterPanel';
import TopLeftPanel from './panels/TopLeftPanel/TopLeftPanel';
import TopRightPanel from './panels/TopRightPanel/TopRightPanel';
const DELETE_KEYS = ['Delete', 'Backspace']; const DELETE_KEYS = ['Delete', 'Backspace'];
const edgeTypes = {
collapsed: InvocationCollapsedEdge,
default: InvocationDefaultEdge,
};
const nodeTypes = {
invocation: InvocationNodeWrapper,
current_image: CurrentImageNode,
notes: NotesNode,
};
// TODO: can we support reactflow? if not, we could style the attribution so it matches the app // TODO: can we support reactflow? if not, we could style the attribution so it matches the app
const proOptions: ProOptions = { hideAttribution: true }; const proOptions: ProOptions = { hideAttribution: true };

View File

@ -2,7 +2,8 @@ import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store'; import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { ConnectionLineComponentProps, getBezierPath } from 'reactflow'; import { ConnectionLineComponentProps, getBezierPath } from 'reactflow';
import { FIELDS, colorTokenToCssVar } from '../types/constants'; import { FIELDS, colorTokenToCssVar } from '../../../types/constants';
import { memo } from 'react';
const selector = createSelector(stateSelector, ({ nodes }) => { const selector = createSelector(stateSelector, ({ nodes }) => {
const { shouldAnimateEdges, currentConnectionFieldType, shouldColorEdges } = const { shouldAnimateEdges, currentConnectionFieldType, shouldColorEdges } =
@ -25,7 +26,7 @@ const selector = createSelector(stateSelector, ({ nodes }) => {
}; };
}); });
export const CustomConnectionLine = ({ const CustomConnectionLine = ({
fromX, fromX,
fromY, fromY,
fromPosition, fromPosition,
@ -59,3 +60,5 @@ export const CustomConnectionLine = ({
</g> </g>
); );
}; };
export default memo(CustomConnectionLine);

View File

@ -0,0 +1,94 @@
import { Badge, Flex } from '@chakra-ui/react';
import { useAppSelector } from 'app/store/storeHooks';
import { useChakraThemeTokens } from 'common/hooks/useChakraThemeTokens';
import { memo, useMemo } from 'react';
import {
BaseEdge,
EdgeLabelRenderer,
EdgeProps,
getBezierPath,
} from 'reactflow';
import { makeEdgeSelector } from './util/makeEdgeSelector';
const InvocationCollapsedEdge = ({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
markerEnd,
data,
selected,
source,
target,
sourceHandleId,
targetHandleId,
}: EdgeProps<{ count: number }>) => {
const selector = useMemo(
() =>
makeEdgeSelector(
source,
sourceHandleId,
target,
targetHandleId,
selected
),
[selected, source, sourceHandleId, target, targetHandleId]
);
const { isSelected, shouldAnimate } = useAppSelector(selector);
const [edgePath, labelX, labelY] = getBezierPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
});
const { base500 } = useChakraThemeTokens();
return (
<>
<BaseEdge
path={edgePath}
markerEnd={markerEnd}
style={{
strokeWidth: isSelected ? 3 : 2,
stroke: base500,
opacity: isSelected ? 0.8 : 0.5,
animation: shouldAnimate
? 'dashdraw 0.5s linear infinite'
: undefined,
strokeDasharray: shouldAnimate ? 5 : 'none',
}}
/>
{data?.count && data.count > 1 && (
<EdgeLabelRenderer>
<Flex
sx={{
position: 'absolute',
transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
}}
className="nodrag nopan"
>
<Badge
variant="solid"
sx={{
bg: 'base.500',
opacity: isSelected ? 0.8 : 0.5,
boxShadow: 'base',
}}
>
{data.count}
</Badge>
</Flex>
</EdgeLabelRenderer>
)}
</>
);
};
export default memo(InvocationCollapsedEdge);

View File

@ -0,0 +1,58 @@
import { useAppSelector } from 'app/store/storeHooks';
import { memo, useMemo } from 'react';
import { BaseEdge, EdgeProps, getBezierPath } from 'reactflow';
import { makeEdgeSelector } from './util/makeEdgeSelector';
const InvocationDefaultEdge = ({
sourceX,
sourceY,
targetX,
targetY,
sourcePosition,
targetPosition,
markerEnd,
selected,
source,
target,
sourceHandleId,
targetHandleId,
}: EdgeProps) => {
const selector = useMemo(
() =>
makeEdgeSelector(
source,
sourceHandleId,
target,
targetHandleId,
selected
),
[source, sourceHandleId, target, targetHandleId, selected]
);
const { isSelected, shouldAnimate, stroke } = useAppSelector(selector);
const [edgePath] = getBezierPath({
sourceX,
sourceY,
sourcePosition,
targetX,
targetY,
targetPosition,
});
return (
<BaseEdge
path={edgePath}
markerEnd={markerEnd}
style={{
strokeWidth: isSelected ? 3 : 2,
stroke,
opacity: isSelected ? 0.8 : 0.5,
animation: shouldAnimate ? 'dashdraw 0.5s linear infinite' : undefined,
strokeDasharray: shouldAnimate ? 5 : 'none',
}}
/>
);
};
export default memo(InvocationDefaultEdge);

View File

@ -0,0 +1,41 @@
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { FIELDS, colorTokenToCssVar } from 'features/nodes/types/constants';
import { isInvocationNode } from 'features/nodes/types/types';
export const makeEdgeSelector = (
source: string,
sourceHandleId: string | null | undefined,
target: string,
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);
const isInvocationToInvocationEdge =
isInvocationNode(sourceNode) && isInvocationNode(targetNode);
const isSelected =
sourceNode?.selected || targetNode?.selected || selected;
const sourceType = isInvocationToInvocationEdge
? sourceNode?.data?.outputs[sourceHandleId || '']?.type
: undefined;
const stroke =
sourceType && nodes.shouldColorEdges
? colorTokenToCssVar(FIELDS[sourceType].color)
: colorTokenToCssVar('base.500');
return {
isSelected,
shouldAnimate: nodes.shouldAnimateEdges && isSelected,
stroke,
};
},
defaultSelectorOptions
);

View File

@ -7,7 +7,7 @@ import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants';
import { PropsWithChildren, memo } from 'react'; import { PropsWithChildren, memo } from 'react';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import NodeWrapper from '../Invocation/NodeWrapper'; import NodeWrapper from '../common/NodeWrapper';
const selector = createSelector(stateSelector, ({ system, gallery }) => { const selector = createSelector(stateSelector, ({ system, gallery }) => {
const imageDTO = gallery.selection[gallery.selection.length - 1]; const imageDTO = gallery.selection[gallery.selection.length - 1];

View File

@ -1,11 +1,12 @@
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { useFieldNames, useWithFooter } from 'features/nodes/hooks/useNodeData';
import { memo } from 'react'; import { memo } from 'react';
import InputField from '../fields/InputField'; import InvocationNodeFooter from './InvocationNodeFooter';
import OutputField from '../fields/OutputField'; import InvocationNodeHeader from './InvocationNodeHeader';
import NodeFooter from './NodeFooter'; import NodeWrapper from '../common/NodeWrapper';
import NodeHeader from './NodeHeader'; import OutputField from './fields/OutputField';
import NodeWrapper from './NodeWrapper'; import InputField from './fields/InputField';
import { useFieldNames } from 'features/nodes/hooks/useFieldNames';
import { useWithFooter } from 'features/nodes/hooks/useWithFooter';
type Props = { type Props = {
nodeId: string; nodeId: string;
@ -22,7 +23,7 @@ const InvocationNode = ({ nodeId, isOpen, label, type, selected }: Props) => {
return ( return (
<NodeWrapper nodeId={nodeId} selected={selected}> <NodeWrapper nodeId={nodeId} selected={selected}>
<NodeHeader <InvocationNodeHeader
nodeId={nodeId} nodeId={nodeId}
isOpen={isOpen} isOpen={isOpen}
label={label} label={label}
@ -59,7 +60,7 @@ const InvocationNode = ({ nodeId, isOpen, label, type, selected }: Props) => {
))} ))}
</Flex> </Flex>
</Flex> </Flex>
{withFooter && <NodeFooter nodeId={nodeId} />} {withFooter && <InvocationNodeFooter nodeId={nodeId} />}
</> </>
)} )}
</NodeWrapper> </NodeWrapper>

View File

@ -10,7 +10,7 @@ interface Props {
nodeId: string; nodeId: string;
} }
const NodeCollapsedHandles = ({ nodeId }: Props) => { const InvocationNodeCollapsedHandles = ({ nodeId }: Props) => {
const data = useNodeData(nodeId); const data = useNodeData(nodeId);
const { base400, base600 } = useChakraThemeTokens(); const { base400, base600 } = useChakraThemeTokens();
const backgroundColor = useColorModeValue(base400, base600); const backgroundColor = useColorModeValue(base400, base600);
@ -71,4 +71,4 @@ const NodeCollapsedHandles = ({ nodeId }: Props) => {
); );
}; };
export default memo(NodeCollapsedHandles); export default memo(InvocationNodeCollapsedHandles);

View File

@ -6,10 +6,8 @@ import {
Spacer, Spacer,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks'; import { useAppDispatch } from 'app/store/storeHooks';
import { import { useHasImageOutput } from 'features/nodes/hooks/useHasImageOutput';
useHasImageOutput, import { useIsIntermediate } from 'features/nodes/hooks/useIsIntermediate';
useIsIntermediate,
} from 'features/nodes/hooks/useNodeData';
import { fieldBooleanValueChanged } from 'features/nodes/store/nodesSlice'; import { fieldBooleanValueChanged } from 'features/nodes/store/nodesSlice';
import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants'; import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants';
import { ChangeEvent, memo, useCallback } from 'react'; import { ChangeEvent, memo, useCallback } from 'react';
@ -18,7 +16,7 @@ type Props = {
nodeId: string; nodeId: string;
}; };
const NodeFooter = ({ nodeId }: Props) => { const InvocationNodeFooter = ({ nodeId }: Props) => {
return ( return (
<Flex <Flex
className={DRAG_HANDLE_CLASSNAME} className={DRAG_HANDLE_CLASSNAME}
@ -37,7 +35,7 @@ const NodeFooter = ({ nodeId }: Props) => {
); );
}; };
export default memo(NodeFooter); export default memo(InvocationNodeFooter);
const SaveImageCheckbox = memo(({ nodeId }: { nodeId: string }) => { const SaveImageCheckbox = memo(({ nodeId }: { nodeId: string }) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();

View File

@ -1,10 +1,10 @@
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
import { memo } from 'react'; import { memo } from 'react';
import NodeCollapseButton from '../Invocation/NodeCollapseButton'; import NodeCollapseButton from '../common/NodeCollapseButton';
import NodeCollapsedHandles from '../Invocation/NodeCollapsedHandles'; import NodeTitle from '../common/NodeTitle';
import NodeNotesEdit from '../Invocation/NodeNotesEdit'; import InvocationNodeCollapsedHandles from './InvocationNodeCollapsedHandles';
import NodeStatusIndicator from '../Invocation/NodeStatusIndicator'; import InvocationNodeNotes from './InvocationNodeNotes';
import NodeTitle from '../Invocation/NodeTitle'; import InvocationNodeStatusIndicator from './InvocationNodeStatusIndicator';
type Props = { type Props = {
nodeId: string; nodeId: string;
@ -14,7 +14,7 @@ type Props = {
selected: boolean; selected: boolean;
}; };
const NodeHeader = ({ nodeId, isOpen }: Props) => { const InvocationNodeHeader = ({ nodeId, isOpen }: Props) => {
return ( return (
<Flex <Flex
layerStyle="nodeHeader" layerStyle="nodeHeader"
@ -33,12 +33,12 @@ const NodeHeader = ({ nodeId, isOpen }: Props) => {
<NodeCollapseButton nodeId={nodeId} isOpen={isOpen} /> <NodeCollapseButton nodeId={nodeId} isOpen={isOpen} />
<NodeTitle nodeId={nodeId} /> <NodeTitle nodeId={nodeId} />
<Flex alignItems="center"> <Flex alignItems="center">
<NodeStatusIndicator nodeId={nodeId} /> <InvocationNodeStatusIndicator nodeId={nodeId} />
<NodeNotesEdit nodeId={nodeId} /> <InvocationNodeNotes nodeId={nodeId} />
</Flex> </Flex>
{!isOpen && <NodeCollapsedHandles nodeId={nodeId} />} {!isOpen && <InvocationNodeCollapsedHandles nodeId={nodeId} />}
</Flex> </Flex>
); );
}; };
export default memo(NodeHeader); export default memo(InvocationNodeHeader);

View File

@ -16,12 +16,10 @@ import {
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks'; import { useAppDispatch } from 'app/store/storeHooks';
import IAITextarea from 'common/components/IAITextarea'; import IAITextarea from 'common/components/IAITextarea';
import { import { useNodeData } from 'features/nodes/hooks/useNodeData';
useNodeData, import { useNodeLabel } from 'features/nodes/hooks/useNodeLabel';
useNodeLabel, import { useNodeTemplate } from 'features/nodes/hooks/useNodeTemplate';
useNodeTemplate, import { useNodeTemplateTitle } from 'features/nodes/hooks/useNodeTemplateTitle';
useNodeTemplateTitle,
} from 'features/nodes/hooks/useNodeData';
import { nodeNotesChanged } from 'features/nodes/store/nodesSlice'; import { nodeNotesChanged } from 'features/nodes/store/nodesSlice';
import { isInvocationNodeData } from 'features/nodes/types/types'; import { isInvocationNodeData } from 'features/nodes/types/types';
import { ChangeEvent, memo, useCallback } from 'react'; import { ChangeEvent, memo, useCallback } from 'react';
@ -31,7 +29,7 @@ interface Props {
nodeId: string; nodeId: string;
} }
const NodeNotesEdit = ({ nodeId }: Props) => { const InvocationNodeNotes = ({ nodeId }: Props) => {
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
const label = useNodeLabel(nodeId); const label = useNodeLabel(nodeId);
const title = useNodeTemplateTitle(nodeId); const title = useNodeTemplateTitle(nodeId);
@ -76,7 +74,7 @@ const NodeNotesEdit = ({ nodeId }: Props) => {
); );
}; };
export default memo(NodeNotesEdit); export default memo(InvocationNodeNotes);
const TooltipContent = memo(({ nodeId }: { nodeId: string }) => { const TooltipContent = memo(({ nodeId }: { nodeId: string }) => {
const data = useNodeData(nodeId); const data = useNodeData(nodeId);

View File

@ -28,7 +28,7 @@ const circleStyles = {
'.chakra-progress__track': { stroke: 'transparent' }, '.chakra-progress__track': { stroke: 'transparent' },
}; };
const NodeStatusIndicator = ({ nodeId }: Props) => { const InvocationNodeStatusIndicator = ({ nodeId }: Props) => {
const selectNodeExecutionState = useMemo( const selectNodeExecutionState = useMemo(
() => () =>
createSelector( createSelector(
@ -64,7 +64,7 @@ const NodeStatusIndicator = ({ nodeId }: Props) => {
); );
}; };
export default memo(NodeStatusIndicator); export default memo(InvocationNodeStatusIndicator);
type TooltipLabelProps = { type TooltipLabelProps = {
nodeExecutionState: NodeExecutionState; nodeExecutionState: NodeExecutionState;

View File

@ -1,8 +1,8 @@
import { Box, Flex, Text } from '@chakra-ui/react'; import { Box, Flex, Text } from '@chakra-ui/react';
import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants'; import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants';
import { memo } from 'react'; import { memo } from 'react';
import NodeCollapseButton from '../Invocation/NodeCollapseButton'; import NodeCollapseButton from '../common/NodeCollapseButton';
import NodeWrapper from '../Invocation/NodeWrapper'; import NodeWrapper from '../common/NodeWrapper';
type Props = { type Props = {
nodeId: string; nodeId: string;
@ -12,7 +12,7 @@ type Props = {
selected: boolean; selected: boolean;
}; };
const UnknownNodeFallback = ({ const InvocationNodeUnknownFallback = ({
nodeId, nodeId,
isOpen, isOpen,
label, label,
@ -72,4 +72,4 @@ const UnknownNodeFallback = ({
); );
}; };
export default memo(UnknownNodeFallback); export default memo(InvocationNodeUnknownFallback);

View File

@ -5,7 +5,7 @@ import { InvocationNodeData } from 'features/nodes/types/types';
import { memo, useMemo } from 'react'; import { memo, useMemo } from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import InvocationNode from '../Invocation/InvocationNode'; import InvocationNode from '../Invocation/InvocationNode';
import UnknownNodeFallback from '../Invocation/UnknownNodeFallback'; import InvocationNodeUnknownFallback from './InvocationNodeUnknownFallback';
const InvocationNodeWrapper = (props: NodeProps<InvocationNodeData>) => { const InvocationNodeWrapper = (props: NodeProps<InvocationNodeData>) => {
const { data, selected } = props; const { data, selected } = props;
@ -23,7 +23,7 @@ const InvocationNodeWrapper = (props: NodeProps<InvocationNodeData>) => {
if (!nodeTemplate) { if (!nodeTemplate) {
return ( return (
<UnknownNodeFallback <InvocationNodeUnknownFallback
nodeId={nodeId} nodeId={nodeId}
isOpen={isOpen} isOpen={isOpen}
label={label} label={label}

View File

@ -7,11 +7,9 @@ import {
IAIContextMenu, IAIContextMenu,
IAIContextMenuProps, IAIContextMenuProps,
} from 'common/components/IAIContextMenu'; } from 'common/components/IAIContextMenu';
import { import { useFieldInputKind } from 'features/nodes/hooks/useFieldInputKind';
useFieldInputKind, import { useFieldLabel } from 'features/nodes/hooks/useFieldLabel';
useFieldLabel, import { useFieldTemplateTitle } from 'features/nodes/hooks/useFieldTemplateTitle';
useFieldTemplateTitle,
} from 'features/nodes/hooks/useNodeData';
import { import {
workflowExposedFieldAdded, workflowExposedFieldAdded,
workflowExposedFieldRemoved, workflowExposedFieldRemoved,
@ -31,6 +29,7 @@ const FieldContextMenu = ({ nodeId, fieldName, kind, children }: Props) => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const label = useFieldLabel(nodeId, fieldName); const label = useFieldLabel(nodeId, fieldName);
const fieldTemplateTitle = useFieldTemplateTitle(nodeId, fieldName, kind); const fieldTemplateTitle = useFieldTemplateTitle(nodeId, fieldName, kind);
const input = useFieldInputKind(nodeId, fieldName);
const skipEvent = useCallback((e: MouseEvent<HTMLDivElement>) => { const skipEvent = useCallback((e: MouseEvent<HTMLDivElement>) => {
e.preventDefault(); e.preventDefault();
@ -54,7 +53,6 @@ const FieldContextMenu = ({ nodeId, fieldName, kind, children }: Props) => {
[fieldName, nodeId] [fieldName, nodeId]
); );
const input = useFieldInputKind(nodeId, fieldName);
const mayExpose = useMemo( const mayExpose = useMemo(
() => ['any', 'direct'].includes(input ?? '__UNKNOWN_INPUT__'), () => ['any', 'direct'].includes(input ?? '__UNKNOWN_INPUT__'),
[input] [input]

View File

@ -5,8 +5,11 @@ import {
FIELDS, FIELDS,
HANDLE_TOOLTIP_OPEN_DELAY, HANDLE_TOOLTIP_OPEN_DELAY,
colorTokenToCssVar, colorTokenToCssVar,
} from '../../types/constants'; } from '../../../../../types/constants';
import { InputFieldTemplate, OutputFieldTemplate } from '../../types/types'; import {
InputFieldTemplate,
OutputFieldTemplate,
} from '../../../../../types/types';
export const handleBaseStyles: CSSProperties = { export const handleBaseStyles: CSSProperties = {
position: 'absolute', position: 'absolute',

View File

@ -7,10 +7,8 @@ import {
useEditableControls, useEditableControls,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks'; import { useAppDispatch } from 'app/store/storeHooks';
import { import { useFieldLabel } from 'features/nodes/hooks/useFieldLabel';
useFieldLabel, import { useFieldTemplateTitle } from 'features/nodes/hooks/useFieldTemplateTitle';
useFieldTemplateTitle,
} from 'features/nodes/hooks/useNodeData';
import { fieldLabelChanged } from 'features/nodes/store/nodesSlice'; import { fieldLabelChanged } from 'features/nodes/store/nodesSlice';
import { MouseEvent, memo, useCallback, useEffect, useState } from 'react'; import { MouseEvent, memo, useCallback, useEffect, useState } from 'react';

View File

@ -1,8 +1,6 @@
import { Flex, Text } from '@chakra-ui/react'; import { Flex, Text } from '@chakra-ui/react';
import { import { useFieldData } from 'features/nodes/hooks/useFieldData';
useFieldData, import { useFieldTemplate } from 'features/nodes/hooks/useFieldTemplate';
useFieldTemplate,
} from 'features/nodes/hooks/useNodeData';
import { FIELDS } from 'features/nodes/types/constants'; import { FIELDS } from 'features/nodes/types/constants';
import { import {
isInputFieldTemplate, isInputFieldTemplate,

View File

@ -1,14 +1,12 @@
import { Box, Flex, FormControl, FormLabel, Tooltip } from '@chakra-ui/react'; import { Box, Flex, FormControl, FormLabel, Tooltip } from '@chakra-ui/react';
import SelectionOverlay from 'common/components/SelectionOverlay'; import SelectionOverlay from 'common/components/SelectionOverlay';
import { useConnectionState } from 'features/nodes/hooks/useConnectionState'; import { useConnectionState } from 'features/nodes/hooks/useConnectionState';
import { import { useDoesInputHaveValue } from 'features/nodes/hooks/useDoesInputHaveValue';
useDoesInputHaveValue, import { useFieldInputKind } from 'features/nodes/hooks/useFieldInputKind';
useFieldInputKind, import { useFieldTemplate } from 'features/nodes/hooks/useFieldTemplate';
useFieldTemplate, import { useIsMouseOverField } from 'features/nodes/hooks/useIsMouseOverField';
useIsMouseOverField,
} from 'features/nodes/hooks/useNodeData';
import { HANDLE_TOOLTIP_OPEN_DELAY } from 'features/nodes/types/constants'; import { HANDLE_TOOLTIP_OPEN_DELAY } from 'features/nodes/types/constants';
import { PropsWithChildren, memo, useCallback, useMemo, useState } from 'react'; import { PropsWithChildren, memo, useMemo } from 'react';
import FieldContextMenu from './FieldContextMenu'; import FieldContextMenu from './FieldContextMenu';
import FieldHandle from './FieldHandle'; import FieldHandle from './FieldHandle';
import FieldTitle from './FieldTitle'; import FieldTitle from './FieldTitle';
@ -24,15 +22,6 @@ const InputField = ({ nodeId, fieldName }: Props) => {
const fieldTemplate = useFieldTemplate(nodeId, fieldName, 'input'); const fieldTemplate = useFieldTemplate(nodeId, fieldName, 'input');
const doesFieldHaveValue = useDoesInputHaveValue(nodeId, fieldName); const doesFieldHaveValue = useDoesInputHaveValue(nodeId, fieldName);
const input = useFieldInputKind(nodeId, fieldName); const input = useFieldInputKind(nodeId, fieldName);
const [isHovered, setIsHovered] = useState(false);
const handleMouseOver = useCallback(() => {
setIsHovered(true);
}, []);
const handleMouseOut = useCallback(() => {
setIsHovered(false);
}, []);
const { const {
isConnected, isConnected,

View File

@ -1,31 +1,29 @@
import { Box, Text } from '@chakra-ui/react'; import { Box, Text } from '@chakra-ui/react';
import { import { useFieldData } from 'features/nodes/hooks/useFieldData';
useFieldData, import { useFieldTemplate } from 'features/nodes/hooks/useFieldTemplate';
useFieldTemplate,
} from 'features/nodes/hooks/useNodeData';
import { memo } from 'react'; import { memo } from 'react';
import BooleanInputField from './fieldTypes/BooleanInputField'; import BooleanInputField from './inputs/BooleanInputField';
import ClipInputField from './fieldTypes/ClipInputField'; import ClipInputField from './inputs/ClipInputField';
import CollectionInputField from './fieldTypes/CollectionInputField'; import CollectionInputField from './inputs/CollectionInputField';
import CollectionItemInputField from './fieldTypes/CollectionItemInputField'; import CollectionItemInputField from './inputs/CollectionItemInputField';
import ColorInputField from './fieldTypes/ColorInputField'; import ColorInputField from './inputs/ColorInputField';
import ConditioningInputField from './fieldTypes/ConditioningInputField'; import ConditioningInputField from './inputs/ConditioningInputField';
import ControlInputField from './fieldTypes/ControlInputField'; import ControlInputField from './inputs/ControlInputField';
import ControlNetModelInputField from './fieldTypes/ControlNetModelInputField'; import ControlNetModelInputField from './inputs/ControlNetModelInputField';
import EnumInputField from './fieldTypes/EnumInputField'; import EnumInputField from './inputs/EnumInputField';
import ImageCollectionInputField from './fieldTypes/ImageCollectionInputField'; import ImageCollectionInputField from './inputs/ImageCollectionInputField';
import ImageInputField from './fieldTypes/ImageInputField'; import ImageInputField from './inputs/ImageInputField';
import LatentsInputField from './fieldTypes/LatentsInputField'; import LatentsInputField from './inputs/LatentsInputField';
import LoRAModelInputField from './fieldTypes/LoRAModelInputField'; import LoRAModelInputField from './inputs/LoRAModelInputField';
import MainModelInputField from './fieldTypes/MainModelInputField'; import MainModelInputField from './inputs/MainModelInputField';
import NumberInputField from './fieldTypes/NumberInputField'; import NumberInputField from './inputs/NumberInputField';
import RefinerModelInputField from './fieldTypes/RefinerModelInputField'; import RefinerModelInputField from './inputs/RefinerModelInputField';
import SDXLMainModelInputField from './fieldTypes/SDXLMainModelInputField'; import SDXLMainModelInputField from './inputs/SDXLMainModelInputField';
import SchedulerInputField from './fieldTypes/SchedulerInputField'; import SchedulerInputField from './inputs/SchedulerInputField';
import StringInputField from './fieldTypes/StringInputField'; import StringInputField from './inputs/StringInputField';
import UnetInputField from './fieldTypes/UnetInputField'; import UnetInputField from './inputs/UnetInputField';
import VaeInputField from './fieldTypes/VaeInputField'; import VaeInputField from './inputs/VaeInputField';
import VaeModelInputField from './fieldTypes/VaeModelInputField'; import VaeModelInputField from './inputs/VaeModelInputField';
type InputFieldProps = { type InputFieldProps = {
nodeId: string; nodeId: string;

View File

@ -2,7 +2,7 @@ import { Flex, FormControl, FormLabel, Icon, Tooltip } from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks'; import { useAppDispatch } from 'app/store/storeHooks';
import IAIIconButton from 'common/components/IAIIconButton'; import IAIIconButton from 'common/components/IAIIconButton';
import SelectionOverlay from 'common/components/SelectionOverlay'; import SelectionOverlay from 'common/components/SelectionOverlay';
import { useIsMouseOverField } from 'features/nodes/hooks/useNodeData'; import { useIsMouseOverField } from 'features/nodes/hooks/useIsMouseOverField';
import { workflowExposedFieldRemoved } from 'features/nodes/store/nodesSlice'; import { workflowExposedFieldRemoved } from 'features/nodes/store/nodesSlice';
import { HANDLE_TOOLTIP_OPEN_DELAY } from 'features/nodes/types/constants'; import { HANDLE_TOOLTIP_OPEN_DELAY } from 'features/nodes/types/constants';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';

View File

@ -6,7 +6,7 @@ import {
Tooltip, Tooltip,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useConnectionState } from 'features/nodes/hooks/useConnectionState'; import { useConnectionState } from 'features/nodes/hooks/useConnectionState';
import { useFieldTemplate } from 'features/nodes/hooks/useNodeData'; import { useFieldTemplate } from 'features/nodes/hooks/useFieldTemplate';
import { HANDLE_TOOLTIP_OPEN_DELAY } from 'features/nodes/types/constants'; import { HANDLE_TOOLTIP_OPEN_DELAY } from 'features/nodes/types/constants';
import { PropsWithChildren, memo } from 'react'; import { PropsWithChildren, memo } from 'react';
import FieldHandle from './FieldHandle'; import FieldHandle from './FieldHandle';

View File

@ -4,9 +4,9 @@ import { fieldBooleanValueChanged } from 'features/nodes/store/nodesSlice';
import { import {
BooleanInputFieldTemplate, BooleanInputFieldTemplate,
BooleanInputFieldValue, BooleanInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { ChangeEvent, memo, useCallback } from 'react'; import { ChangeEvent, memo, useCallback } from 'react';
import { FieldComponentProps } from './types';
const BooleanInputFieldComponent = ( const BooleanInputFieldComponent = (
props: FieldComponentProps<BooleanInputFieldValue, BooleanInputFieldTemplate> props: FieldComponentProps<BooleanInputFieldValue, BooleanInputFieldTemplate>

View File

@ -1,9 +1,9 @@
import { import {
ClipInputFieldTemplate, ClipInputFieldTemplate,
ClipInputFieldValue, ClipInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { memo } from 'react'; import { memo } from 'react';
import { FieldComponentProps } from './types';
const ClipInputFieldComponent = ( const ClipInputFieldComponent = (
_props: FieldComponentProps<ClipInputFieldValue, ClipInputFieldTemplate> _props: FieldComponentProps<ClipInputFieldValue, ClipInputFieldTemplate>

View File

@ -1,9 +1,9 @@
import { import {
CollectionInputFieldTemplate, CollectionInputFieldTemplate,
CollectionInputFieldValue, CollectionInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { memo } from 'react'; import { memo } from 'react';
import { FieldComponentProps } from './types';
const CollectionInputFieldComponent = ( const CollectionInputFieldComponent = (
_props: FieldComponentProps< _props: FieldComponentProps<

View File

@ -1,9 +1,9 @@
import { import {
CollectionItemInputFieldTemplate, CollectionItemInputFieldTemplate,
CollectionItemInputFieldValue, CollectionItemInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { memo } from 'react'; import { memo } from 'react';
import { FieldComponentProps } from './types';
const CollectionItemInputFieldComponent = ( const CollectionItemInputFieldComponent = (
_props: FieldComponentProps< _props: FieldComponentProps<

View File

@ -3,10 +3,10 @@ import { fieldColorValueChanged } from 'features/nodes/store/nodesSlice';
import { import {
ColorInputFieldTemplate, ColorInputFieldTemplate,
ColorInputFieldValue, ColorInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
import { RgbaColor, RgbaColorPicker } from 'react-colorful'; import { RgbaColor, RgbaColorPicker } from 'react-colorful';
import { FieldComponentProps } from './types';
const ColorInputFieldComponent = ( const ColorInputFieldComponent = (
props: FieldComponentProps<ColorInputFieldValue, ColorInputFieldTemplate> props: FieldComponentProps<ColorInputFieldValue, ColorInputFieldTemplate>

View File

@ -1,9 +1,9 @@
import { import {
ConditioningInputFieldTemplate, ConditioningInputFieldTemplate,
ConditioningInputFieldValue, ConditioningInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { memo } from 'react'; import { memo } from 'react';
import { FieldComponentProps } from './types';
const ConditioningInputFieldComponent = ( const ConditioningInputFieldComponent = (
_props: FieldComponentProps< _props: FieldComponentProps<

View File

@ -1,9 +1,9 @@
import { import {
ControlInputFieldTemplate, ControlInputFieldTemplate,
ControlInputFieldValue, ControlInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { memo } from 'react'; import { memo } from 'react';
import { FieldComponentProps } from './types';
const ControlInputFieldComponent = ( const ControlInputFieldComponent = (
_props: FieldComponentProps<ControlInputFieldValue, ControlInputFieldTemplate> _props: FieldComponentProps<ControlInputFieldValue, ControlInputFieldTemplate>

View File

@ -5,13 +5,13 @@ import { fieldControlNetModelValueChanged } from 'features/nodes/store/nodesSlic
import { import {
ControlNetModelInputFieldTemplate, ControlNetModelInputFieldTemplate,
ControlNetModelInputFieldValue, ControlNetModelInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants'; import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
import { modelIdToControlNetModelParam } from 'features/parameters/util/modelIdToControlNetModelParam'; import { modelIdToControlNetModelParam } from 'features/parameters/util/modelIdToControlNetModelParam';
import { forEach } from 'lodash-es'; import { forEach } from 'lodash-es';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { useGetControlNetModelsQuery } from 'services/api/endpoints/models'; import { useGetControlNetModelsQuery } from 'services/api/endpoints/models';
import { FieldComponentProps } from './types';
const ControlNetModelInputFieldComponent = ( const ControlNetModelInputFieldComponent = (
props: FieldComponentProps< props: FieldComponentProps<

View File

@ -4,9 +4,9 @@ import { fieldEnumModelValueChanged } from 'features/nodes/store/nodesSlice';
import { import {
EnumInputFieldTemplate, EnumInputFieldTemplate,
EnumInputFieldValue, EnumInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { ChangeEvent, memo, useCallback } from 'react'; import { ChangeEvent, memo, useCallback } from 'react';
import { FieldComponentProps } from './types';
const EnumInputFieldComponent = ( const EnumInputFieldComponent = (
props: FieldComponentProps<EnumInputFieldValue, EnumInputFieldTemplate> props: FieldComponentProps<EnumInputFieldValue, EnumInputFieldTemplate>

View File

@ -1,6 +1,7 @@
import { import {
ImageCollectionInputFieldTemplate, ImageCollectionInputFieldTemplate,
ImageCollectionInputFieldValue, ImageCollectionInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { memo } from 'react'; import { memo } from 'react';
@ -11,7 +12,6 @@ import { useDroppableTypesafe } from 'features/dnd/hooks/typesafeHooks';
import { NodesMultiImageDropData } from 'features/dnd/types'; import { NodesMultiImageDropData } from 'features/dnd/types';
import { isValidDrop } from 'features/dnd/util/isValidDrop'; import { isValidDrop } from 'features/dnd/util/isValidDrop';
import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import { FieldComponentProps } from './types';
const ImageCollectionInputFieldComponent = ( const ImageCollectionInputFieldComponent = (
props: FieldComponentProps< props: FieldComponentProps<

View File

@ -11,12 +11,12 @@ import { fieldImageValueChanged } from 'features/nodes/store/nodesSlice';
import { import {
ImageInputFieldTemplate, ImageInputFieldTemplate,
ImageInputFieldValue, ImageInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { FaUndo } from 'react-icons/fa'; import { FaUndo } from 'react-icons/fa';
import { useGetImageDTOQuery } from 'services/api/endpoints/images'; import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import { PostUploadAction } from 'services/api/types'; import { PostUploadAction } from 'services/api/types';
import { FieldComponentProps } from './types';
const ImageInputFieldComponent = ( const ImageInputFieldComponent = (
props: FieldComponentProps<ImageInputFieldValue, ImageInputFieldTemplate> props: FieldComponentProps<ImageInputFieldValue, ImageInputFieldTemplate>

View File

@ -1,9 +1,9 @@
import { import {
LatentsInputFieldTemplate, LatentsInputFieldTemplate,
LatentsInputFieldValue, LatentsInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { memo } from 'react'; import { memo } from 'react';
import { FieldComponentProps } from './types';
const LatentsInputFieldComponent = ( const LatentsInputFieldComponent = (
_props: FieldComponentProps<LatentsInputFieldValue, LatentsInputFieldTemplate> _props: FieldComponentProps<LatentsInputFieldValue, LatentsInputFieldTemplate>

View File

@ -7,13 +7,13 @@ import { fieldLoRAModelValueChanged } from 'features/nodes/store/nodesSlice';
import { import {
LoRAModelInputFieldTemplate, LoRAModelInputFieldTemplate,
LoRAModelInputFieldValue, LoRAModelInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants'; import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
import { modelIdToLoRAModelParam } from 'features/parameters/util/modelIdToLoRAModelParam'; import { modelIdToLoRAModelParam } from 'features/parameters/util/modelIdToLoRAModelParam';
import { forEach } from 'lodash-es'; import { forEach } from 'lodash-es';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { useGetLoRAModelsQuery } from 'services/api/endpoints/models'; import { useGetLoRAModelsQuery } from 'services/api/endpoints/models';
import { FieldComponentProps } from './types';
const LoRAModelInputFieldComponent = ( const LoRAModelInputFieldComponent = (
props: FieldComponentProps< props: FieldComponentProps<

View File

@ -6,6 +6,7 @@ import { fieldMainModelValueChanged } from 'features/nodes/store/nodesSlice';
import { import {
MainModelInputFieldTemplate, MainModelInputFieldTemplate,
MainModelInputFieldValue, MainModelInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants'; import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
import { modelIdToMainModelParam } from 'features/parameters/util/modelIdToMainModelParam'; import { modelIdToMainModelParam } from 'features/parameters/util/modelIdToMainModelParam';
@ -18,7 +19,6 @@ import {
useGetMainModelsQuery, useGetMainModelsQuery,
useGetOnnxModelsQuery, useGetOnnxModelsQuery,
} from 'services/api/endpoints/models'; } from 'services/api/endpoints/models';
import { FieldComponentProps } from './types';
const MainModelInputFieldComponent = ( const MainModelInputFieldComponent = (
props: FieldComponentProps< props: FieldComponentProps<

View File

@ -13,9 +13,9 @@ import {
FloatInputFieldValue, FloatInputFieldValue,
IntegerInputFieldTemplate, IntegerInputFieldTemplate,
IntegerInputFieldValue, IntegerInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { memo, useEffect, useMemo, useState } from 'react'; import { memo, useEffect, useMemo, useState } from 'react';
import { FieldComponentProps } from './types';
const NumberInputFieldComponent = ( const NumberInputFieldComponent = (
props: FieldComponentProps< props: FieldComponentProps<

View File

@ -6,6 +6,7 @@ import { fieldRefinerModelValueChanged } from 'features/nodes/store/nodesSlice';
import { import {
SDXLRefinerModelInputFieldTemplate, SDXLRefinerModelInputFieldTemplate,
SDXLRefinerModelInputFieldValue, SDXLRefinerModelInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants'; import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
import { modelIdToMainModelParam } from 'features/parameters/util/modelIdToMainModelParam'; import { modelIdToMainModelParam } from 'features/parameters/util/modelIdToMainModelParam';
@ -16,7 +17,6 @@ import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { REFINER_BASE_MODELS } from 'services/api/constants'; import { REFINER_BASE_MODELS } from 'services/api/constants';
import { useGetMainModelsQuery } from 'services/api/endpoints/models'; import { useGetMainModelsQuery } from 'services/api/endpoints/models';
import { FieldComponentProps } from './types';
const RefinerModelInputFieldComponent = ( const RefinerModelInputFieldComponent = (
props: FieldComponentProps< props: FieldComponentProps<

View File

@ -6,6 +6,7 @@ import { fieldMainModelValueChanged } from 'features/nodes/store/nodesSlice';
import { import {
SDXLMainModelInputFieldTemplate, SDXLMainModelInputFieldTemplate,
SDXLMainModelInputFieldValue, SDXLMainModelInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants'; import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
import { modelIdToMainModelParam } from 'features/parameters/util/modelIdToMainModelParam'; import { modelIdToMainModelParam } from 'features/parameters/util/modelIdToMainModelParam';
@ -19,7 +20,6 @@ import {
useGetMainModelsQuery, useGetMainModelsQuery,
useGetOnnxModelsQuery, useGetOnnxModelsQuery,
} from 'services/api/endpoints/models'; } from 'services/api/endpoints/models';
import { FieldComponentProps } from './types';
const ModelInputFieldComponent = ( const ModelInputFieldComponent = (
props: FieldComponentProps< props: FieldComponentProps<

View File

@ -7,6 +7,7 @@ import { fieldSchedulerValueChanged } from 'features/nodes/store/nodesSlice';
import { import {
SchedulerInputFieldTemplate, SchedulerInputFieldTemplate,
SchedulerInputFieldValue, SchedulerInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { import {
SCHEDULER_LABEL_MAP, SCHEDULER_LABEL_MAP,
@ -14,7 +15,6 @@ import {
} from 'features/parameters/types/parameterSchemas'; } from 'features/parameters/types/parameterSchemas';
import { map } from 'lodash-es'; import { map } from 'lodash-es';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
import { FieldComponentProps } from './types';
const selector = createSelector( const selector = createSelector(
[stateSelector], [stateSelector],

View File

@ -5,9 +5,9 @@ import { fieldStringValueChanged } from 'features/nodes/store/nodesSlice';
import { import {
StringInputFieldTemplate, StringInputFieldTemplate,
StringInputFieldValue, StringInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { ChangeEvent, memo, useCallback } from 'react'; import { ChangeEvent, memo, useCallback } from 'react';
import { FieldComponentProps } from './types';
const StringInputFieldComponent = ( const StringInputFieldComponent = (
props: FieldComponentProps<StringInputFieldValue, StringInputFieldTemplate> props: FieldComponentProps<StringInputFieldValue, StringInputFieldTemplate>

View File

@ -1,9 +1,9 @@
import { import {
UNetInputFieldTemplate, UNetInputFieldTemplate,
UNetInputFieldValue, UNetInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { memo } from 'react'; import { memo } from 'react';
import { FieldComponentProps } from './types';
const UNetInputFieldComponent = ( const UNetInputFieldComponent = (
_props: FieldComponentProps<UNetInputFieldValue, UNetInputFieldTemplate> _props: FieldComponentProps<UNetInputFieldValue, UNetInputFieldTemplate>

View File

@ -1,9 +1,9 @@
import { import {
VaeInputFieldTemplate, VaeInputFieldTemplate,
VaeInputFieldValue, VaeInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { memo } from 'react'; import { memo } from 'react';
import { FieldComponentProps } from './types';
const VaeInputFieldComponent = ( const VaeInputFieldComponent = (
_props: FieldComponentProps<VaeInputFieldValue, VaeInputFieldTemplate> _props: FieldComponentProps<VaeInputFieldValue, VaeInputFieldTemplate>

View File

@ -6,13 +6,13 @@ import { fieldVaeModelValueChanged } from 'features/nodes/store/nodesSlice';
import { import {
VaeModelInputFieldTemplate, VaeModelInputFieldTemplate,
VaeModelInputFieldValue, VaeModelInputFieldValue,
FieldComponentProps,
} from 'features/nodes/types/types'; } from 'features/nodes/types/types';
import { MODEL_TYPE_MAP } from 'features/parameters/types/constants'; import { MODEL_TYPE_MAP } from 'features/parameters/types/constants';
import { modelIdToVAEModelParam } from 'features/parameters/util/modelIdToVAEModelParam'; import { modelIdToVAEModelParam } from 'features/parameters/util/modelIdToVAEModelParam';
import { forEach } from 'lodash-es'; import { forEach } from 'lodash-es';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { useGetVaeModelsQuery } from 'services/api/endpoints/models'; import { useGetVaeModelsQuery } from 'services/api/endpoints/models';
import { FieldComponentProps } from './types';
const VaeModelInputFieldComponent = ( const VaeModelInputFieldComponent = (
props: FieldComponentProps< props: FieldComponentProps<

View File

@ -5,9 +5,9 @@ import { notesNodeValueChanged } from 'features/nodes/store/nodesSlice';
import { NotesNodeData } from 'features/nodes/types/types'; import { NotesNodeData } from 'features/nodes/types/types';
import { ChangeEvent, memo, useCallback } from 'react'; import { ChangeEvent, memo, useCallback } from 'react';
import { NodeProps } from 'reactflow'; import { NodeProps } from 'reactflow';
import NodeCollapseButton from '../Invocation/NodeCollapseButton'; import NodeWrapper from '../common/NodeWrapper';
import NodeTitle from '../Invocation/NodeTitle'; import NodeCollapseButton from '../common/NodeCollapseButton';
import NodeWrapper from '../Invocation/NodeWrapper'; import NodeTitle from '../common/NodeTitle';
const NotesNode = (props: NodeProps<NotesNodeData>) => { const NotesNode = (props: NodeProps<NotesNodeData>) => {
const { id: nodeId, data, selected } = props; const { id: nodeId, data, selected } = props;

View File

@ -7,10 +7,8 @@ import {
useEditableControls, useEditableControls,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useAppDispatch } from 'app/store/storeHooks'; import { useAppDispatch } from 'app/store/storeHooks';
import { import { useNodeLabel } from 'features/nodes/hooks/useNodeLabel';
useNodeLabel, import { useNodeTemplateTitle } from 'features/nodes/hooks/useNodeTemplateTitle';
useNodeTemplateTitle,
} from 'features/nodes/hooks/useNodeData';
import { nodeLabelChanged } from 'features/nodes/store/nodesSlice'; import { nodeLabelChanged } from 'features/nodes/store/nodesSlice';
import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants'; import { DRAG_HANDLE_CLASSNAME } from 'features/nodes/types/constants';
import { MouseEvent, memo, useCallback, useEffect, useState } from 'react'; import { MouseEvent, memo, useCallback, useEffect, useState } from 'react';

View File

@ -5,9 +5,12 @@ import {
useToken, useToken,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import {
DRAG_HANDLE_CLASSNAME,
NODE_WIDTH,
} from 'features/nodes/types/constants';
import { contextMenusClosed } from 'features/ui/store/uiSlice'; import { contextMenusClosed } from 'features/ui/store/uiSlice';
import { PropsWithChildren, memo, useCallback } from 'react'; import { PropsWithChildren, memo, useCallback } from 'react';
import { DRAG_HANDLE_CLASSNAME, NODE_WIDTH } from '../../types/constants';
type NodeWrapperProps = PropsWithChildren & { type NodeWrapperProps = PropsWithChildren & {
nodeId: string; nodeId: string;

View File

@ -1,7 +1,7 @@
import { memo } from 'react'; import { memo } from 'react';
import { Panel } from 'reactflow'; import { Panel } from 'reactflow';
import ViewportControls from '../ViewportControls'; import ViewportControls from './ViewportControls';
import NodeOpacitySlider from '../NodeOpacitySlider'; import NodeOpacitySlider from './NodeOpacitySlider';
import { Flex } from '@chakra-ui/react'; import { Flex } from '@chakra-ui/react';
const BottomLeftPanel = () => ( const BottomLeftPanel = () => (

View File

@ -7,7 +7,7 @@ import {
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { nodeOpacityChanged } from '../store/nodesSlice'; import { nodeOpacityChanged } from 'features/nodes/store/nodesSlice';
export default function NodeOpacitySlider() { export default function NodeOpacitySlider() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();

View File

@ -14,7 +14,7 @@ import { useReactFlow } from 'reactflow';
import { import {
shouldShowFieldTypeLegendChanged, shouldShowFieldTypeLegendChanged,
shouldShowMinimapPanelChanged, shouldShowMinimapPanelChanged,
} from '../store/nodesSlice'; } from 'features/nodes/store/nodesSlice';
const ViewportControls = () => { const ViewportControls = () => {
const { t } = useTranslation(); const { t } = useTranslation();

View File

@ -22,7 +22,7 @@ import {
shouldColorEdgesChanged, shouldColorEdgesChanged,
shouldSnapToGridChanged, shouldSnapToGridChanged,
shouldValidateGraphChanged, shouldValidateGraphChanged,
} from '../store/nodesSlice'; } from 'features/nodes/store/nodesSlice';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
const selector = createSelector( const selector = createSelector(

View File

@ -2,10 +2,10 @@ import { HStack } from '@chakra-ui/react';
import CancelButton from 'features/parameters/components/ProcessButtons/CancelButton'; import CancelButton from 'features/parameters/components/ProcessButtons/CancelButton';
import { memo } from 'react'; import { memo } from 'react';
import { Panel } from 'reactflow'; import { Panel } from 'reactflow';
import NodeEditorSettings from '../NodeEditorSettings'; import NodeEditorSettings from './NodeEditorSettings';
import ClearGraphButton from '../ui/ClearGraphButton'; import ClearGraphButton from './ClearGraphButton';
import NodeInvokeButton from '../ui/NodeInvokeButton'; import NodeInvokeButton from './NodeInvokeButton';
import ReloadSchemaButton from '../ui/ReloadSchemaButton'; import ReloadSchemaButton from './ReloadSchemaButton';
const TopCenterPanel = () => { const TopCenterPanel = () => {
return ( return (

View File

@ -5,12 +5,12 @@ import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect'; import IAIMantineSearchableSelect from 'common/components/IAIMantineSearchableSelect';
import { useBuildNodeData } from 'features/nodes/hooks/useBuildNodeData';
import { nodeAdded } from 'features/nodes/store/nodesSlice';
import { map } from 'lodash-es'; import { map } from 'lodash-es';
import { forwardRef, useCallback } from 'react'; import { forwardRef, useCallback } from 'react';
import 'reactflow/dist/style.css'; import 'reactflow/dist/style.css';
import { AnyInvocationType } from 'services/events/types'; import { AnyInvocationType } from 'services/events/types';
import { useBuildNodeData } from '../hooks/useBuildNodeData';
import { nodeAdded } from '../store/nodesSlice';
type NodeTemplate = { type NodeTemplate = {
label: string; label: string;

View File

@ -1,6 +1,6 @@
import { memo } from 'react'; import { memo } from 'react';
import { Panel } from 'reactflow'; import { Panel } from 'reactflow';
import AddNodeMenu from '../AddNodeMenu'; import AddNodeMenu from './AddNodeMenu';
const TopLeftPanel = () => ( const TopLeftPanel = () => (
<Panel position="top-left"> <Panel position="top-left">

View File

@ -1,8 +1,8 @@
import { Badge, Flex, Tooltip } from '@chakra-ui/react'; import { Badge, Flex, Tooltip } from '@chakra-ui/react';
import { FIELDS } from 'features/nodes/types/constants';
import { map } from 'lodash-es'; import { map } from 'lodash-es';
import { memo } from 'react'; import { memo } from 'react';
import 'reactflow/dist/style.css'; import 'reactflow/dist/style.css';
import { FIELDS } from '../types/constants';
const FieldTypeLegend = () => { const FieldTypeLegend = () => {
return ( return (

View File

@ -1,7 +1,7 @@
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { memo } from 'react'; import { memo } from 'react';
import { Panel } from 'reactflow'; import { Panel } from 'reactflow';
import FieldTypeLegend from '../FieldTypeLegend'; import FieldTypeLegend from './FieldTypeLegend';
const TopRightPanel = () => { const TopRightPanel = () => {
const shouldShowFieldTypeLegend = useAppSelector( const shouldShowFieldTypeLegend = useAppSelector(

View File

@ -1,17 +0,0 @@
import IAIDndImage from 'common/components/IAIDndImage';
import { memo } from 'react';
import { useGetImageDTOQuery } from 'services/api/endpoints/images';
import { ImageOutput } from 'services/api/types';
type Props = {
output: ImageOutput;
};
const ImageOutputPreview = ({ output }: Props) => {
const { image, width, height } = output;
const { data: imageDTO } = useGetImageDTOQuery(image.image_name);
return <IAIDndImage imageDTO={imageDTO} />;
};
export default memo(ImageOutputPreview);

View File

@ -1,13 +0,0 @@
import { Text } from '@chakra-ui/react';
import { memo } from 'react';
import { FloatOutput, IntegerOutput } from 'services/api/types';
type Props = {
output: IntegerOutput | FloatOutput;
};
const NumberOutputPreview = ({ output }: Props) => {
return <Text>{output.value}</Text>;
};
export default memo(NumberOutputPreview);

View File

@ -1,13 +0,0 @@
import { Text } from '@chakra-ui/react';
import { memo } from 'react';
import { StringOutput } from 'services/api/types';
type Props = {
output: StringOutput;
};
const StringOutputPreview = ({ output }: Props) => {
return <Text>{output.value}</Text>;
};
export default memo(StringOutputPreview);

View File

@ -1,9 +1,9 @@
import InspectorPanel from 'features/nodes/components/panel/InspectorPanel';
import ResizeHandle from 'features/ui/components/tabs/ResizeHandle'; import ResizeHandle from 'features/ui/components/tabs/ResizeHandle';
import { memo, useState } from 'react'; import { memo, useState } from 'react';
import { Panel, PanelGroup } from 'react-resizable-panels'; import { Panel, PanelGroup } from 'react-resizable-panels';
import 'reactflow/dist/style.css'; import 'reactflow/dist/style.css';
import WorkflowPanel from './WorkflowPanel'; import WorkflowPanel from './workflow/WorkflowPanel';
import InspectorPanel from './inspector/InspectorPanel';
const NodeEditorPanelGroup = () => { const NodeEditorPanelGroup = () => {
const [isTopPanelCollapsed, setIsTopPanelCollapsed] = useState(false); const [isTopPanelCollapsed, setIsTopPanelCollapsed] = useState(false);

View File

@ -23,7 +23,7 @@ const selector = createSelector(
defaultSelectorOptions defaultSelectorOptions
); );
const NodeDataInspector = () => { const InspectorDataTab = () => {
const { data } = useAppSelector(selector); const { data } = useAppSelector(selector);
if (!data) { if (!data) {
@ -33,4 +33,4 @@ const NodeDataInspector = () => {
return <ImageMetadataJSON jsonObject={data} label="Node Data" />; return <ImageMetadataJSON jsonObject={data} label="Node Data" />;
}; };
export default memo(NodeDataInspector); export default memo(InspectorDataTab);

View File

@ -5,11 +5,11 @@ import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { IAINoContentFallback } from 'common/components/IAIImageFallback'; import { IAINoContentFallback } from 'common/components/IAIImageFallback';
import { memo } from 'react'; import { memo } from 'react';
import ImageOutputPreview from './ImageOutputPreview'; import ImageOutputPreview from './outputs/ImageOutputPreview';
import NumberOutputPreview from './NumberOutputPreview'; import ScrollableContent from '../ScrollableContent';
import ScrollableContent from './ScrollableContent';
import StringOutputPreview from './StringOutputPreview';
import { AnyResult } from 'services/events/types'; import { AnyResult } from 'services/events/types';
import StringOutputPreview from './outputs/StringOutputPreview';
import NumberOutputPreview from './outputs/NumberOutputPreview';
const selector = createSelector( const selector = createSelector(
stateSelector, stateSelector,
@ -32,7 +32,7 @@ const selector = createSelector(
defaultSelectorOptions defaultSelectorOptions
); );
const NodeResultsInspector = () => { const InspectorOutputsTab = () => {
const { node, nes } = useAppSelector(selector); const { node, nes } = useAppSelector(selector);
if (!node || !nes) { if (!node || !nes) {
@ -96,6 +96,6 @@ const NodeResultsInspector = () => {
); );
}; };
export default memo(NodeResultsInspector); export default memo(InspectorOutputsTab);
const getKey = (result: AnyResult, i: number) => `${result.type}-${i}`; const getKey = (result: AnyResult, i: number) => `${result.type}-${i}`;

View File

@ -7,9 +7,9 @@ import {
Tabs, Tabs,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { memo } from 'react'; import { memo } from 'react';
import NodeDataInspector from './NodeDataInspector'; import InspectorDataTab from './InspectorDataTab';
import NodeResultsInspector from './NodeResultsInspector'; import InspectorOutputsTab from './InspectorOutputsTab';
import NodeTemplateInspector from './NodeTemplateInspector'; import InspectorTemplateTab from './InspectorTemplateTab';
const InspectorPanel = () => { const InspectorPanel = () => {
return ( return (
@ -29,20 +29,20 @@ const InspectorPanel = () => {
sx={{ display: 'flex', flexDir: 'column', w: 'full', h: 'full' }} sx={{ display: 'flex', flexDir: 'column', w: 'full', h: 'full' }}
> >
<TabList> <TabList>
<Tab>Node Outputs</Tab> <Tab>Outputs</Tab>
<Tab>Node Data</Tab> <Tab>Data</Tab>
<Tab>Node Template</Tab> <Tab>Template</Tab>
</TabList> </TabList>
<TabPanels> <TabPanels>
<TabPanel> <TabPanel>
<NodeResultsInspector /> <InspectorOutputsTab />
</TabPanel> </TabPanel>
<TabPanel> <TabPanel>
<NodeDataInspector /> <InspectorDataTab />
</TabPanel> </TabPanel>
<TabPanel> <TabPanel>
<NodeTemplateInspector /> <InspectorTemplateTab />
</TabPanel> </TabPanel>
</TabPanels> </TabPanels>
</Tabs> </Tabs>

View File

@ -36,7 +36,7 @@ const selector = createSelector(
defaultSelectorOptions defaultSelectorOptions
); );
const WorkflowPanel = () => { const WorkflowGeneralTab = () => {
const { author, name, description, tags, version, contact, notes } = const { author, name, description, tags, version, contact, notes } =
useAppSelector(selector); useAppSelector(selector);
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
@ -139,4 +139,4 @@ const WorkflowPanel = () => {
); );
}; };
export default memo(WorkflowPanel); export default memo(WorkflowGeneralTab);

View File

@ -19,7 +19,7 @@ const useWatchWorkflow = () => {
}; };
}; };
const WorkflowWorkflowTab = () => { const WorkflowJSONTab = () => {
const { workflow } = useWatchWorkflow(); const { workflow } = useWatchWorkflow();
return ( return (
@ -40,4 +40,4 @@ const WorkflowWorkflowTab = () => {
); );
}; };
export default memo(WorkflowWorkflowTab); export default memo(WorkflowJSONTab);

View File

@ -5,7 +5,7 @@ import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { IAINoContentFallback } from 'common/components/IAIImageFallback'; import { IAINoContentFallback } from 'common/components/IAIImageFallback';
import { memo } from 'react'; import { memo } from 'react';
import LinearViewField from '../../fields/LinearViewField'; import LinearViewField from '../../flow/nodes/Invocation/fields/LinearViewField';
import ScrollableContent from '../ScrollableContent'; import ScrollableContent from '../ScrollableContent';
const selector = createSelector( const selector = createSelector(
@ -18,7 +18,7 @@ const selector = createSelector(
defaultSelectorOptions defaultSelectorOptions
); );
const LinearTabContent = () => { const WorkflowLinearTab = () => {
const { fields } = useAppSelector(selector); const { fields } = useAppSelector(selector);
return ( return (
@ -61,4 +61,4 @@ const LinearTabContent = () => {
); );
}; };
export default memo(LinearTabContent); export default memo(WorkflowLinearTab);

View File

@ -14,7 +14,7 @@ const selector = createSelector(stateSelector, ({ nodes }) => {
}; };
}); });
const WorkflowPanel = () => { const WorkflowNotesTab = () => {
const { notes } = useAppSelector(selector); const { notes } = useAppSelector(selector);
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
@ -48,4 +48,4 @@ const WorkflowPanel = () => {
); );
}; };
export default memo(WorkflowPanel); export default memo(WorkflowNotesTab);

View File

@ -7,9 +7,9 @@ import {
Tabs, Tabs,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { memo } from 'react'; import { memo } from 'react';
import GeneralTab from './workflow/GeneralTab'; import WorkflowGeneralTab from './WorkflowGeneralTab';
import LinearTab from './workflow/LinearTab'; import WorkflowLinearTab from './WorkflowLinearTab';
import WorkflowTab from './workflow/WorkflowTab'; import WorkflowJSONTab from './WorkflowJSONTab';
const WorkflowPanel = () => { const WorkflowPanel = () => {
return ( return (
@ -35,13 +35,13 @@ const WorkflowPanel = () => {
<TabPanels> <TabPanels>
<TabPanel> <TabPanel>
<LinearTab /> <WorkflowLinearTab />
</TabPanel> </TabPanel>
<TabPanel> <TabPanel>
<GeneralTab /> <WorkflowGeneralTab />
</TabPanel> </TabPanel>
<TabPanel> <TabPanel>
<WorkflowTab /> <WorkflowJSONTab />
</TabPanel> </TabPanel>
</TabPanels> </TabPanels>
</Tabs> </Tabs>

View File

@ -3,7 +3,7 @@ import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { makeConnectionErrorSelector } from 'features/nodes/store/util/makeIsConnectionValidSelector'; import { makeConnectionErrorSelector } from 'features/nodes/store/util/makeIsConnectionValidSelector';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useFieldType } from './useNodeData'; import { useFieldType } from './useFieldType.ts';
const selectIsConnectionInProgress = createSelector( const selectIsConnectionInProgress = createSelector(
stateSelector, stateSelector,

View File

@ -0,0 +1,28 @@
import { createSelector } from '@reduxjs/toolkit';
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 '../types/types';
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 Boolean(node?.data.inputs[fieldName]?.value);
},
defaultSelectorOptions
),
[fieldName, nodeId]
);
const doesFieldHaveValue = useAppSelector(selector);
return doesFieldHaveValue;
};

View File

@ -0,0 +1,28 @@
import { createSelector } from '@reduxjs/toolkit';
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 '../types/types';
export const useFieldData = (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
),
[fieldName, nodeId]
);
const fieldData = useAppSelector(selector);
return fieldData;
};

View File

@ -0,0 +1,30 @@
import { createSelector } from '@reduxjs/toolkit';
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 '../types/types';
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
),
[fieldName, nodeId]
);
const inputKind = useAppSelector(selector);
return inputKind;
};

View File

@ -0,0 +1,28 @@
import { createSelector } from '@reduxjs/toolkit';
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 '../types/types';
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
),
[fieldName, nodeId]
);
const label = useAppSelector(selector);
return label;
};

View File

@ -0,0 +1,31 @@
import { createSelector } from '@reduxjs/toolkit';
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 { KIND_MAP } from '../types/constants';
import { isInvocationNode } from '../types/types';
export const useFieldNames = (nodeId: string, kind: 'input' | 'output') => {
const selector = useMemo(
() =>
createSelector(
stateSelector,
({ nodes }) => {
const node = nodes.nodes.find((node) => node.id === nodeId);
if (!isInvocationNode(node)) {
return [];
}
return map(node.data[KIND_MAP[kind]], (field) => field.name).filter(
(fieldName) => fieldName !== 'is_intermediate'
);
},
defaultSelectorOptions
),
[kind, nodeId]
);
const fieldNames = useAppSelector(selector);
return fieldNames;
};

View File

@ -0,0 +1,34 @@
import { createSelector } from '@reduxjs/toolkit';
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 '../types/constants';
import { isInvocationNode } from '../types/types';
export const useFieldTemplate = (
nodeId: string,
fieldName: string,
kind: 'input' | 'output'
) => {
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
),
[fieldName, kind, nodeId]
);
const fieldTemplate = useAppSelector(selector);
return fieldTemplate;
};

View File

@ -0,0 +1,34 @@
import { createSelector } from '@reduxjs/toolkit';
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 '../types/types';
import { KIND_MAP } from '../types/constants';
export const useFieldTemplateTitle = (
nodeId: string,
fieldName: string,
kind: 'input' | 'output'
) => {
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
),
[fieldName, kind, nodeId]
);
const fieldTemplate = useAppSelector(selector);
return fieldTemplate;
};

View File

@ -0,0 +1,33 @@
import { createSelector } from '@reduxjs/toolkit';
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 '../types/constants';
import { isInvocationNode } from '../types/types';
export const useFieldType = (
nodeId: string,
fieldName: string,
kind: 'input' | 'output'
) => {
const selector = useMemo(
() =>
createSelector(
stateSelector,
({ nodes }) => {
const node = nodes.nodes.find((node) => node.id === nodeId);
if (!isInvocationNode(node)) {
return;
}
return node?.data[KIND_MAP[kind]][fieldName]?.type;
},
defaultSelectorOptions
),
[fieldName, kind, nodeId]
);
const fieldType = useAppSelector(selector);
return fieldType;
};

View File

@ -0,0 +1,31 @@
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { some } from 'lodash-es';
import { useMemo } from 'react';
import { IMAGE_FIELDS } from '../types/constants';
import { isInvocationNode } from '../types/types';
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) =>
IMAGE_FIELDS.includes(output.type)
);
},
defaultSelectorOptions
),
[nodeId]
);
const hasImageOutput = useAppSelector(selector);
return hasImageOutput;
};

View File

@ -0,0 +1,27 @@
import { createSelector } from '@reduxjs/toolkit';
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 '../types/types';
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 Boolean(node.data.inputs.is_intermediate?.value);
},
defaultSelectorOptions
),
[nodeId]
);
const is_intermediate = useAppSelector(selector);
return is_intermediate;
};

View File

@ -0,0 +1,33 @@
import { createSelector } from '@reduxjs/toolkit';
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 '../store/nodesSlice';
export const useIsMouseOverField = (nodeId: string, fieldName: string) => {
const dispatch = useAppDispatch();
const selector = useMemo(
() =>
createSelector(
stateSelector,
({ nodes }) =>
nodes.mouseOverField?.nodeId === nodeId &&
nodes.mouseOverField?.fieldName === fieldName,
defaultSelectorOptions
),
[fieldName, nodeId]
);
const isMouseOverField = useAppSelector(selector);
const handleMouseOver = useCallback(() => {
dispatch(mouseOverFieldChanged({ nodeId, fieldName }));
}, [dispatch, fieldName, nodeId]);
const handleMouseOut = useCallback(() => {
dispatch(mouseOverFieldChanged(null));
}, [dispatch]);
return { isMouseOverField, handleMouseOver, handleMouseOut };
};

View File

@ -1,37 +1,8 @@
import { createSelector } from '@reduxjs/toolkit'; import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store'; import { stateSelector } from 'app/store/store';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks'; import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions'; import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { map, some } from 'lodash-es'; import { useMemo } from 'react';
import { useCallback, useMemo } from 'react';
import { mouseOverFieldChanged } from '../store/nodesSlice';
import { FOOTER_FIELDS, IMAGE_FIELDS } from '../types/constants';
import { isInvocationNode } from '../types/types';
const KIND_MAP = {
input: 'inputs' as const,
output: 'outputs' as const,
};
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
),
[nodeId]
);
const nodeTemplate = useAppSelector(selector);
return nodeTemplate;
};
export const useNodeData = (nodeId: string) => { export const useNodeData = (nodeId: string) => {
const selector = useMemo( const selector = useMemo(
@ -51,337 +22,3 @@ export const useNodeData = (nodeId: string) => {
return nodeData; return nodeData;
}; };
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
),
[fieldName, nodeId]
);
const label = useAppSelector(selector);
return label;
};
export const useFieldData = (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
),
[fieldName, nodeId]
);
const fieldData = useAppSelector(selector);
return fieldData;
};
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
),
[fieldName, nodeId]
);
const inputKind = useAppSelector(selector);
return inputKind;
};
export const useFieldType = (
nodeId: string,
fieldName: string,
kind: 'input' | 'output'
) => {
const selector = useMemo(
() =>
createSelector(
stateSelector,
({ nodes }) => {
const node = nodes.nodes.find((node) => node.id === nodeId);
if (!isInvocationNode(node)) {
return;
}
return node?.data[KIND_MAP[kind]][fieldName]?.type;
},
defaultSelectorOptions
),
[fieldName, kind, nodeId]
);
const fieldType = useAppSelector(selector);
return fieldType;
};
export const useFieldNames = (nodeId: string, kind: 'input' | 'output') => {
const selector = useMemo(
() =>
createSelector(
stateSelector,
({ nodes }) => {
const node = nodes.nodes.find((node) => node.id === nodeId);
if (!isInvocationNode(node)) {
return [];
}
return map(node.data[KIND_MAP[kind]], (field) => field.name).filter(
(fieldName) => fieldName !== 'is_intermediate'
);
},
defaultSelectorOptions
),
[kind, nodeId]
);
const fieldNames = useAppSelector(selector);
return fieldNames;
};
export const useWithFooter = (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) =>
FOOTER_FIELDS.includes(output.type)
);
},
defaultSelectorOptions
),
[nodeId]
);
const withFooter = useAppSelector(selector);
return withFooter;
};
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) =>
IMAGE_FIELDS.includes(output.type)
);
},
defaultSelectorOptions
),
[nodeId]
);
const hasImageOutput = useAppSelector(selector);
return hasImageOutput;
};
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 Boolean(node.data.inputs.is_intermediate?.value);
},
defaultSelectorOptions
),
[nodeId]
);
const is_intermediate = useAppSelector(selector);
return is_intermediate;
};
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;
}
return node.data.label;
},
defaultSelectorOptions
),
[nodeId]
);
const label = useAppSelector(selector);
return label;
};
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;
return nodeTemplate?.title;
},
defaultSelectorOptions
),
[nodeId]
);
const title = useAppSelector(selector);
return title;
};
export const useFieldTemplateTitle = (
nodeId: string,
fieldName: string,
kind: 'input' | 'output'
) => {
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
),
[fieldName, kind, nodeId]
);
const fieldTemplate = useAppSelector(selector);
return fieldTemplate;
};
export const useFieldTemplate = (
nodeId: string,
fieldName: string,
kind: 'input' | 'output'
) => {
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
),
[fieldName, kind, nodeId]
);
const fieldTemplate = useAppSelector(selector);
return fieldTemplate;
};
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 Boolean(node?.data.inputs[fieldName]?.value);
},
defaultSelectorOptions
),
[fieldName, nodeId]
);
const doesFieldHaveValue = useAppSelector(selector);
return doesFieldHaveValue;
};
export const useIsMouseOverField = (nodeId: string, fieldName: string) => {
const dispatch = useAppDispatch();
const selector = useMemo(
() =>
createSelector(
stateSelector,
({ nodes }) =>
nodes.mouseOverField?.nodeId === nodeId &&
nodes.mouseOverField?.fieldName === fieldName,
defaultSelectorOptions
),
[fieldName, nodeId]
);
const isMouseOverField = useAppSelector(selector);
const handleMouseOver = useCallback(() => {
dispatch(mouseOverFieldChanged({ nodeId, fieldName }));
}, [dispatch, fieldName, nodeId]);
const handleMouseOut = useCallback(() => {
dispatch(mouseOverFieldChanged(null));
}, [dispatch]);
return { isMouseOverField, handleMouseOver, handleMouseOut };
};

View File

@ -0,0 +1,28 @@
import { createSelector } from '@reduxjs/toolkit';
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 '../types/types';
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;
}
return node.data.label;
},
defaultSelectorOptions
),
[nodeId]
);
const label = useAppSelector(selector);
return label;
};

View File

@ -0,0 +1,25 @@
import { createSelector } from '@reduxjs/toolkit';
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
),
[nodeId]
);
const nodeTemplate = useAppSelector(selector);
return nodeTemplate;
};

View File

@ -0,0 +1,31 @@
import { createSelector } from '@reduxjs/toolkit';
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 '../types/types';
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;
return nodeTemplate?.title;
},
defaultSelectorOptions
),
[nodeId]
);
const title = useAppSelector(selector);
return title;
};

View File

@ -0,0 +1,31 @@
import { createSelector } from '@reduxjs/toolkit';
import { stateSelector } from 'app/store/store';
import { useAppSelector } from 'app/store/storeHooks';
import { defaultSelectorOptions } from 'app/store/util/defaultMemoizeOptions';
import { some } from 'lodash-es';
import { useMemo } from 'react';
import { FOOTER_FIELDS } from '../types/constants';
import { isInvocationNode } from '../types/types';
export const useWithFooter = (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) =>
FOOTER_FIELDS.includes(output.type)
);
},
defaultSelectorOptions
),
[nodeId]
);
const withFooter = useAppSelector(selector);
return withFooter;
};

View File

@ -9,6 +9,11 @@ export const DRAG_HANDLE_CLASSNAME = 'node-drag-handle';
export const IMAGE_FIELDS = ['ImageField', 'ImageCollection']; export const IMAGE_FIELDS = ['ImageField', 'ImageCollection'];
export const FOOTER_FIELDS = IMAGE_FIELDS; export const FOOTER_FIELDS = IMAGE_FIELDS;
export const KIND_MAP = {
input: 'inputs' as const,
output: 'outputs' as const,
};
export const COLLECTION_TYPES: FieldType[] = [ export const COLLECTION_TYPES: FieldType[] = [
'Collection', 'Collection',
'IntegerCollection', 'IntegerCollection',

Some files were not shown because too many files have changed in this diff Show More