mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
fix(ui): improve nodes performance
This commit is contained in:
parent
44a653925a
commit
4901911c1a
@ -49,7 +49,7 @@ export const AddNodeMenu = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Menu>
|
<Menu isLazy>
|
||||||
<MenuButton
|
<MenuButton
|
||||||
as={IAIIconButton}
|
as={IAIIconButton}
|
||||||
aria-label="Add Node"
|
aria-label="Add Node"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Tooltip } from '@chakra-ui/react';
|
import { Tooltip } from '@chakra-ui/react';
|
||||||
import { CSSProperties, useMemo } from 'react';
|
import { CSSProperties, memo, useMemo } from 'react';
|
||||||
import {
|
import {
|
||||||
Handle,
|
Handle,
|
||||||
Position,
|
Position,
|
||||||
@ -38,13 +38,14 @@ type FieldHandleProps = {
|
|||||||
styles?: CSSProperties;
|
styles?: CSSProperties;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FieldHandle = (props: FieldHandleProps) => {
|
const FieldHandle = (props: FieldHandleProps) => {
|
||||||
const { nodeId, field, isValidConnection, handleType, styles } = props;
|
const { nodeId, field, isValidConnection, handleType, styles } = props;
|
||||||
const { name, title, type, description } = field;
|
const { name, title, type, description } = field;
|
||||||
|
|
||||||
|
console.log(props);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
key={name}
|
|
||||||
label={type}
|
label={type}
|
||||||
placement={handleType === 'target' ? 'start' : 'end'}
|
placement={handleType === 'target' ? 'start' : 'end'}
|
||||||
hasArrow
|
hasArrow
|
||||||
@ -67,3 +68,5 @@ export const FieldHandle = (props: FieldHandleProps) => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default memo(FieldHandle);
|
||||||
|
@ -30,6 +30,10 @@ import { IAIIconButton } from 'exports';
|
|||||||
import { InfoIcon } from '@chakra-ui/icons';
|
import { InfoIcon } from '@chakra-ui/icons';
|
||||||
import { ViewportControls } from './ViewportControls';
|
import { ViewportControls } from './ViewportControls';
|
||||||
import NodeGraphOverlay from './NodeGraphOverlay';
|
import NodeGraphOverlay from './NodeGraphOverlay';
|
||||||
|
import TopLeftPanel from './panels/TopLeftPanel';
|
||||||
|
import TopRightPanel from './panels/TopRightPanel';
|
||||||
|
import TopCenterPanel from './panels/TopCenterPanel';
|
||||||
|
import BottomLeftPanel from './panels/BottomLeftPanel.tsx';
|
||||||
|
|
||||||
const nodeTypes = { invocation: InvocationComponent };
|
const nodeTypes = { invocation: InvocationComponent };
|
||||||
|
|
||||||
@ -37,9 +41,6 @@ export const Flow = () => {
|
|||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const nodes = useAppSelector((state: RootState) => state.nodes.nodes);
|
const nodes = useAppSelector((state: RootState) => state.nodes.nodes);
|
||||||
const edges = useAppSelector((state: RootState) => state.nodes.edges);
|
const edges = useAppSelector((state: RootState) => state.nodes.edges);
|
||||||
const shouldShowGraphOverlay = useAppSelector(
|
|
||||||
(state: RootState) => state.nodes.shouldShowGraphOverlay
|
|
||||||
);
|
|
||||||
|
|
||||||
const onNodesChange: OnNodesChange = useCallback(
|
const onNodesChange: OnNodesChange = useCallback(
|
||||||
(changes) => {
|
(changes) => {
|
||||||
@ -76,10 +77,6 @@ export const Flow = () => {
|
|||||||
[dispatch]
|
[dispatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleInvoke = useCallback(() => {
|
|
||||||
dispatch(nodesGraphBuilt());
|
|
||||||
}, [dispatch]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactFlow
|
<ReactFlow
|
||||||
nodeTypes={nodeTypes}
|
nodeTypes={nodeTypes}
|
||||||
@ -94,19 +91,10 @@ export const Flow = () => {
|
|||||||
style: { strokeWidth: 2 },
|
style: { strokeWidth: 2 },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Panel position="top-left">
|
<TopLeftPanel />
|
||||||
<AddNodeMenu />
|
<TopCenterPanel />
|
||||||
</Panel>
|
<TopRightPanel />
|
||||||
<Panel position="top-center">
|
<BottomLeftPanel />
|
||||||
<Button onClick={handleInvoke}>Will it blend?</Button>
|
|
||||||
</Panel>
|
|
||||||
<Panel position="top-right">
|
|
||||||
<FieldTypeLegend />
|
|
||||||
{shouldShowGraphOverlay && <NodeGraphOverlay />}
|
|
||||||
</Panel>
|
|
||||||
<Panel position="bottom-left">
|
|
||||||
<ViewportControls />
|
|
||||||
</Panel>
|
|
||||||
<Background />
|
<Background />
|
||||||
<MiniMap nodeStrokeWidth={3} zoomable pannable />
|
<MiniMap nodeStrokeWidth={3} zoomable pannable />
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
|
@ -5,7 +5,7 @@ import { FaInfoCircle } from 'react-icons/fa';
|
|||||||
|
|
||||||
interface IAINodeHeaderProps {
|
interface IAINodeHeaderProps {
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
template: MutableRefObject<InvocationTemplate | undefined>;
|
template: InvocationTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function IAINodeHeader(props: IAINodeHeaderProps) {
|
export default function IAINodeHeader(props: IAINodeHeaderProps) {
|
||||||
@ -21,11 +21,11 @@ export default function IAINodeHeader(props: IAINodeHeaderProps) {
|
|||||||
>
|
>
|
||||||
<Tooltip label={nodeId}>
|
<Tooltip label={nodeId}>
|
||||||
<Heading size="xs" fontWeight={600} color="base.100">
|
<Heading size="xs" fontWeight={600} color="base.100">
|
||||||
{template.current?.title}
|
{template.title}
|
||||||
</Heading>
|
</Heading>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
label={template.current?.description}
|
label={template.description}
|
||||||
placement="top"
|
placement="top"
|
||||||
hasArrow
|
hasArrow
|
||||||
shouldWrapChildren
|
shouldWrapChildren
|
||||||
|
@ -3,7 +3,7 @@ import {
|
|||||||
InputFieldValue,
|
InputFieldValue,
|
||||||
InvocationTemplate,
|
InvocationTemplate,
|
||||||
} from 'features/nodes/types/types';
|
} from 'features/nodes/types/types';
|
||||||
import { MutableRefObject, ReactNode } from 'react';
|
import { memo, MutableRefObject, ReactNode } from 'react';
|
||||||
import { map } from 'lodash';
|
import { map } from 'lodash';
|
||||||
import { useAppSelector } from 'app/storeHooks';
|
import { useAppSelector } from 'app/storeHooks';
|
||||||
import { RootState } from 'app/store';
|
import { RootState } from 'app/store';
|
||||||
@ -17,7 +17,7 @@ import {
|
|||||||
Icon,
|
Icon,
|
||||||
Divider,
|
Divider,
|
||||||
} from '@chakra-ui/react';
|
} from '@chakra-ui/react';
|
||||||
import { FieldHandle } from '../FieldHandle';
|
import FieldHandle from '../FieldHandle';
|
||||||
import { useIsValidConnection } from 'features/nodes/hooks/useIsValidConnection';
|
import { useIsValidConnection } from 'features/nodes/hooks/useIsValidConnection';
|
||||||
import { InputFieldComponent } from '../InputFieldComponent';
|
import { InputFieldComponent } from '../InputFieldComponent';
|
||||||
import { FaInfoCircle } from 'react-icons/fa';
|
import { FaInfoCircle } from 'react-icons/fa';
|
||||||
@ -37,7 +37,6 @@ function IAINodeInput(props: IAINodeInputProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
key={input.id}
|
|
||||||
position="relative"
|
position="relative"
|
||||||
borderColor={
|
borderColor={
|
||||||
!template
|
!template
|
||||||
@ -96,11 +95,11 @@ function IAINodeInput(props: IAINodeInputProps) {
|
|||||||
|
|
||||||
interface IAINodeInputsProps {
|
interface IAINodeInputsProps {
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
template: MutableRefObject<InvocationTemplate | undefined>;
|
template: InvocationTemplate;
|
||||||
inputs: Record<string, InputFieldValue>;
|
inputs: Record<string, InputFieldValue>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function IAINodeInputs(props: IAINodeInputsProps) {
|
const IAINodeInputs = (props: IAINodeInputsProps) => {
|
||||||
const { nodeId, template, inputs } = props;
|
const { nodeId, template, inputs } = props;
|
||||||
|
|
||||||
const connectedInputs = useAppSelector(
|
const connectedInputs = useAppSelector(
|
||||||
@ -112,7 +111,7 @@ export default function IAINodeInputs(props: IAINodeInputsProps) {
|
|||||||
const inputSockets = map(inputs);
|
const inputSockets = map(inputs);
|
||||||
|
|
||||||
inputSockets.forEach((inputSocket, index) => {
|
inputSockets.forEach((inputSocket, index) => {
|
||||||
const inputTemplate = template.current?.inputs[inputSocket.name];
|
const inputTemplate = template.inputs[inputSocket.name];
|
||||||
|
|
||||||
const isConnected = Boolean(
|
const isConnected = Boolean(
|
||||||
connectedInputs.filter((connectedInput) => {
|
connectedInputs.filter((connectedInput) => {
|
||||||
@ -129,6 +128,7 @@ export default function IAINodeInputs(props: IAINodeInputsProps) {
|
|||||||
|
|
||||||
IAINodeInputsToRender.push(
|
IAINodeInputsToRender.push(
|
||||||
<IAINodeInput
|
<IAINodeInput
|
||||||
|
key={inputSocket.id}
|
||||||
nodeId={nodeId}
|
nodeId={nodeId}
|
||||||
input={inputSocket}
|
input={inputSocket}
|
||||||
template={inputTemplate}
|
template={inputTemplate}
|
||||||
@ -145,4 +145,6 @@ export default function IAINodeInputs(props: IAINodeInputsProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return renderIAINodeInputs();
|
return renderIAINodeInputs();
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default memo(IAINodeInputs);
|
||||||
|
@ -3,12 +3,12 @@ import {
|
|||||||
OutputFieldTemplate,
|
OutputFieldTemplate,
|
||||||
OutputFieldValue,
|
OutputFieldValue,
|
||||||
} from 'features/nodes/types/types';
|
} from 'features/nodes/types/types';
|
||||||
import { MutableRefObject, ReactNode } from 'react';
|
import { memo, MutableRefObject, ReactNode } from 'react';
|
||||||
import { map } from 'lodash';
|
import { map } from 'lodash';
|
||||||
import { useAppSelector } from 'app/storeHooks';
|
import { useAppSelector } from 'app/storeHooks';
|
||||||
import { RootState } from 'app/store';
|
import { RootState } from 'app/store';
|
||||||
import { Box, Flex, FormControl, FormLabel, HStack } from '@chakra-ui/react';
|
import { Box, Flex, FormControl, FormLabel, HStack } from '@chakra-ui/react';
|
||||||
import { FieldHandle } from '../FieldHandle';
|
import FieldHandle from '../FieldHandle';
|
||||||
import { useIsValidConnection } from 'features/nodes/hooks/useIsValidConnection';
|
import { useIsValidConnection } from 'features/nodes/hooks/useIsValidConnection';
|
||||||
|
|
||||||
interface IAINodeOutputProps {
|
interface IAINodeOutputProps {
|
||||||
@ -23,7 +23,7 @@ function IAINodeOutput(props: IAINodeOutputProps) {
|
|||||||
const isValidConnection = useIsValidConnection();
|
const isValidConnection = useIsValidConnection();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box key={output.id} position="relative">
|
<Box position="relative">
|
||||||
<FormControl isDisabled={!template ? true : connected} paddingRight={3}>
|
<FormControl isDisabled={!template ? true : connected} paddingRight={3}>
|
||||||
{!template ? (
|
{!template ? (
|
||||||
<HStack justifyContent="space-between" alignItems="center">
|
<HStack justifyContent="space-between" alignItems="center">
|
||||||
@ -52,11 +52,11 @@ function IAINodeOutput(props: IAINodeOutputProps) {
|
|||||||
|
|
||||||
interface IAINodeOutputsProps {
|
interface IAINodeOutputsProps {
|
||||||
nodeId: string;
|
nodeId: string;
|
||||||
template: MutableRefObject<InvocationTemplate | undefined>;
|
template: InvocationTemplate;
|
||||||
outputs: Record<string, OutputFieldValue>;
|
outputs: Record<string, OutputFieldValue>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function IAINodeOutputs(props: IAINodeOutputsProps) {
|
const IAINodeOutputs = (props: IAINodeOutputsProps) => {
|
||||||
const { nodeId, template, outputs } = props;
|
const { nodeId, template, outputs } = props;
|
||||||
|
|
||||||
const connectedInputs = useAppSelector(
|
const connectedInputs = useAppSelector(
|
||||||
@ -68,7 +68,7 @@ export default function IAINodeOutputs(props: IAINodeOutputsProps) {
|
|||||||
const outputSockets = map(outputs);
|
const outputSockets = map(outputs);
|
||||||
|
|
||||||
outputSockets.forEach((outputSocket) => {
|
outputSockets.forEach((outputSocket) => {
|
||||||
const outputTemplate = template.current?.outputs[outputSocket.name];
|
const outputTemplate = template.outputs[outputSocket.name];
|
||||||
|
|
||||||
const isConnected = Boolean(
|
const isConnected = Boolean(
|
||||||
connectedInputs.filter((connectedInput) => {
|
connectedInputs.filter((connectedInput) => {
|
||||||
@ -81,6 +81,7 @@ export default function IAINodeOutputs(props: IAINodeOutputsProps) {
|
|||||||
|
|
||||||
IAINodeOutputsToRender.push(
|
IAINodeOutputsToRender.push(
|
||||||
<IAINodeOutput
|
<IAINodeOutput
|
||||||
|
key={outputSocket.id}
|
||||||
nodeId={nodeId}
|
nodeId={nodeId}
|
||||||
output={outputSocket}
|
output={outputSocket}
|
||||||
template={outputTemplate}
|
template={outputTemplate}
|
||||||
@ -93,4 +94,6 @@ export default function IAINodeOutputs(props: IAINodeOutputsProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return renderIAINodeOutputs();
|
return renderIAINodeOutputs();
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default memo(IAINodeOutputs);
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
import { NodeProps, NodeResizeControl } from 'reactflow';
|
import { NodeProps, NodeResizeControl } from 'reactflow';
|
||||||
import { Box, Flex, Icon, useToken } from '@chakra-ui/react';
|
import { Box, Flex, Icon, useToken } from '@chakra-ui/react';
|
||||||
import { FaExclamationCircle } from 'react-icons/fa';
|
import { FaExclamationCircle } from 'react-icons/fa';
|
||||||
import { InvocationValue } from '../types/types';
|
import { InvocationTemplate, InvocationValue } from '../types/types';
|
||||||
|
|
||||||
import { memo, PropsWithChildren, useRef } from 'react';
|
import { memo, PropsWithChildren, useMemo, useRef } from 'react';
|
||||||
import { useGetInvocationTemplate } from '../hooks/useInvocationTemplate';
|
import { useGetInvocationTemplate } from '../hooks/useInvocationTemplate';
|
||||||
import IAINodeOutputs from './IAINode/IAINodeOutputs';
|
import IAINodeOutputs from './IAINode/IAINodeOutputs';
|
||||||
import IAINodeInputs from './IAINode/IAINodeInputs';
|
import IAINodeInputs from './IAINode/IAINodeInputs';
|
||||||
import IAINodeHeader from './IAINode/IAINodeHeader';
|
import IAINodeHeader from './IAINode/IAINodeHeader';
|
||||||
import { IoResize } from 'react-icons/io5';
|
import { IoResize } from 'react-icons/io5';
|
||||||
import IAINodeResizer from './IAINode/IAINodeResizer';
|
import IAINodeResizer from './IAINode/IAINodeResizer';
|
||||||
|
import { RootState } from 'app/store';
|
||||||
|
import { AnyInvocationType } from 'services/events/types';
|
||||||
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
|
import { useAppSelector } from 'app/storeHooks';
|
||||||
|
|
||||||
type InvocationComponentWrapperProps = PropsWithChildren & {
|
type InvocationComponentWrapperProps = PropsWithChildren & {
|
||||||
selected: boolean;
|
selected: boolean;
|
||||||
@ -36,16 +40,35 @@ const InvocationComponentWrapper = (props: InvocationComponentWrapperProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const makeTemplateSelector = (type: AnyInvocationType) =>
|
||||||
|
createSelector(
|
||||||
|
[(state: RootState) => state.nodes],
|
||||||
|
(nodes) => {
|
||||||
|
const template = nodes.invocationTemplates[type];
|
||||||
|
if (!template) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return template;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
memoizeOptions: {
|
||||||
|
resultEqualityCheck: (
|
||||||
|
a: InvocationTemplate | undefined,
|
||||||
|
b: InvocationTemplate | undefined
|
||||||
|
) => a !== undefined && b !== undefined && a.type === b.type,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export const InvocationComponent = memo((props: NodeProps<InvocationValue>) => {
|
export const InvocationComponent = memo((props: NodeProps<InvocationValue>) => {
|
||||||
const { id: nodeId, data, selected } = props;
|
const { id: nodeId, data, selected } = props;
|
||||||
const { type, inputs, outputs } = data;
|
const { type, inputs, outputs } = data;
|
||||||
|
|
||||||
const getInvocationTemplate = useGetInvocationTemplate();
|
const templateSelector = useMemo(() => makeTemplateSelector(type), [type]);
|
||||||
// TODO: determine if a field/handle is connected and disable the input if so
|
|
||||||
|
|
||||||
const template = useRef(getInvocationTemplate(type));
|
const template = useAppSelector(templateSelector);
|
||||||
|
|
||||||
if (!template.current) {
|
if (!template) {
|
||||||
return (
|
return (
|
||||||
<InvocationComponentWrapper selected={selected}>
|
<InvocationComponentWrapper selected={selected}>
|
||||||
<Flex sx={{ alignItems: 'center', justifyContent: 'center' }}>
|
<Flex sx={{ alignItems: 'center', justifyContent: 'center' }}>
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
import { memo } from 'react';
|
||||||
|
import { Panel } from 'reactflow';
|
||||||
|
import { ViewportControls } from '../ViewportControls';
|
||||||
|
|
||||||
|
const BottomLeftPanel = () => (
|
||||||
|
<Panel position="bottom-left">
|
||||||
|
<ViewportControls />
|
||||||
|
</Panel>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default memo(BottomLeftPanel);
|
@ -0,0 +1,23 @@
|
|||||||
|
import { useAppDispatch } from 'app/storeHooks';
|
||||||
|
import IAIButton from 'common/components/IAIButton';
|
||||||
|
import { memo, useCallback } from 'react';
|
||||||
|
import { Panel } from 'reactflow';
|
||||||
|
import { nodesGraphBuilt } from 'services/thunks/session';
|
||||||
|
|
||||||
|
const TopCenterPanel = () => {
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
const handleInvoke = useCallback(() => {
|
||||||
|
dispatch(nodesGraphBuilt());
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Panel position="top-center">
|
||||||
|
<IAIButton colorScheme="accent" onClick={handleInvoke}>
|
||||||
|
Will it blend?
|
||||||
|
</IAIButton>
|
||||||
|
</Panel>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(TopCenterPanel);
|
@ -0,0 +1,11 @@
|
|||||||
|
import { memo } from 'react';
|
||||||
|
import { Panel } from 'reactflow';
|
||||||
|
import { AddNodeMenu } from '../AddNodeMenu';
|
||||||
|
|
||||||
|
const TopLeftPanel = () => (
|
||||||
|
<Panel position="top-left">
|
||||||
|
<AddNodeMenu />
|
||||||
|
</Panel>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default memo(TopLeftPanel);
|
@ -0,0 +1,21 @@
|
|||||||
|
import { RootState } from 'app/store';
|
||||||
|
import { useAppSelector } from 'app/storeHooks';
|
||||||
|
import { memo } from 'react';
|
||||||
|
import { Panel } from 'reactflow';
|
||||||
|
import { FieldTypeLegend } from '../FieldTypeLegend';
|
||||||
|
import NodeGraphOverlay from '../NodeGraphOverlay';
|
||||||
|
|
||||||
|
const TopRightPanel = () => {
|
||||||
|
const shouldShowGraphOverlay = useAppSelector(
|
||||||
|
(state: RootState) => state.nodes.shouldShowGraphOverlay
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Panel position="top-right">
|
||||||
|
<FieldTypeLegend />
|
||||||
|
{shouldShowGraphOverlay && <NodeGraphOverlay />}
|
||||||
|
</Panel>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(TopRightPanel);
|
@ -1,6 +1,8 @@
|
|||||||
|
import { createSelector } from '@reduxjs/toolkit';
|
||||||
import { RootState } from 'app/store';
|
import { RootState } from 'app/store';
|
||||||
import { useAppSelector } from 'app/storeHooks';
|
import { useAppSelector } from 'app/storeHooks';
|
||||||
import { reduce } from 'lodash';
|
import { reduce } from 'lodash';
|
||||||
|
import { useCallback } from 'react';
|
||||||
import { Node, useReactFlow } from 'reactflow';
|
import { Node, useReactFlow } from 'reactflow';
|
||||||
import { AnyInvocationType } from 'services/events/types';
|
import { AnyInvocationType } from 'services/events/types';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
@ -11,75 +13,82 @@ import {
|
|||||||
} from '../types/types';
|
} from '../types/types';
|
||||||
import { buildInputFieldValue } from '../util/fieldValueBuilders';
|
import { buildInputFieldValue } from '../util/fieldValueBuilders';
|
||||||
|
|
||||||
|
const templatesSelector = createSelector(
|
||||||
|
[(state: RootState) => state.nodes],
|
||||||
|
(nodes) => nodes.invocationTemplates,
|
||||||
|
{ memoizeOptions: { resultEqualityCheck: (a, b) => true } }
|
||||||
|
);
|
||||||
|
|
||||||
export const useBuildInvocation = () => {
|
export const useBuildInvocation = () => {
|
||||||
const invocationTemplates = useAppSelector(
|
const invocationTemplates = useAppSelector(templatesSelector);
|
||||||
(state: RootState) => state.nodes.invocationTemplates
|
|
||||||
);
|
|
||||||
|
|
||||||
const reactflow = useReactFlow();
|
const flow = useReactFlow();
|
||||||
|
|
||||||
return (type: AnyInvocationType) => {
|
return useCallback(
|
||||||
const template = invocationTemplates[type];
|
(type: AnyInvocationType) => {
|
||||||
|
const template = invocationTemplates[type];
|
||||||
|
|
||||||
if (template === undefined) {
|
if (template === undefined) {
|
||||||
console.error(`Unable to find template ${type}.`);
|
console.error(`Unable to find template ${type}.`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodeId = uuidv4();
|
const nodeId = uuidv4();
|
||||||
|
|
||||||
const inputs = reduce(
|
const inputs = reduce(
|
||||||
template.inputs,
|
template.inputs,
|
||||||
(inputsAccumulator, inputTemplate, inputName) => {
|
(inputsAccumulator, inputTemplate, inputName) => {
|
||||||
const fieldId = uuidv4();
|
const fieldId = uuidv4();
|
||||||
|
|
||||||
const inputFieldValue: InputFieldValue = buildInputFieldValue(
|
const inputFieldValue: InputFieldValue = buildInputFieldValue(
|
||||||
fieldId,
|
fieldId,
|
||||||
inputTemplate
|
inputTemplate
|
||||||
);
|
);
|
||||||
|
|
||||||
inputsAccumulator[inputName] = inputFieldValue;
|
inputsAccumulator[inputName] = inputFieldValue;
|
||||||
|
|
||||||
return inputsAccumulator;
|
return inputsAccumulator;
|
||||||
},
|
},
|
||||||
{} as Record<string, InputFieldValue>
|
{} as Record<string, InputFieldValue>
|
||||||
);
|
);
|
||||||
|
|
||||||
const outputs = reduce(
|
const outputs = reduce(
|
||||||
template.outputs,
|
template.outputs,
|
||||||
(outputsAccumulator, outputTemplate, outputName) => {
|
(outputsAccumulator, outputTemplate, outputName) => {
|
||||||
const fieldId = uuidv4();
|
const fieldId = uuidv4();
|
||||||
|
|
||||||
const outputFieldValue: OutputFieldValue = {
|
const outputFieldValue: OutputFieldValue = {
|
||||||
id: fieldId,
|
id: fieldId,
|
||||||
name: outputName,
|
name: outputName,
|
||||||
type: outputTemplate.type,
|
type: outputTemplate.type,
|
||||||
};
|
};
|
||||||
|
|
||||||
outputsAccumulator[outputName] = outputFieldValue;
|
outputsAccumulator[outputName] = outputFieldValue;
|
||||||
|
|
||||||
return outputsAccumulator;
|
return outputsAccumulator;
|
||||||
},
|
},
|
||||||
{} as Record<string, OutputFieldValue>
|
{} as Record<string, OutputFieldValue>
|
||||||
);
|
);
|
||||||
|
|
||||||
const { x, y } = reactflow.project({
|
const { x, y } = flow.project({
|
||||||
x: window.innerWidth / 2.5,
|
x: window.innerWidth / 2.5,
|
||||||
y: window.innerHeight / 8,
|
y: window.innerHeight / 8,
|
||||||
});
|
});
|
||||||
|
|
||||||
const invocation: Node<InvocationValue> = {
|
const invocation: Node<InvocationValue> = {
|
||||||
id: nodeId,
|
|
||||||
type: 'invocation',
|
|
||||||
position: { x: x, y: y },
|
|
||||||
data: {
|
|
||||||
id: nodeId,
|
id: nodeId,
|
||||||
type,
|
type: 'invocation',
|
||||||
inputs,
|
position: { x: x, y: y },
|
||||||
outputs,
|
data: {
|
||||||
},
|
id: nodeId,
|
||||||
};
|
type,
|
||||||
|
inputs,
|
||||||
|
outputs,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
return invocation;
|
return invocation;
|
||||||
};
|
},
|
||||||
|
[invocationTemplates, flow]
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
import { useAppSelector } from 'app/storeHooks';
|
|
||||||
import { invocationTemplatesSelector } from '../store/selectors/invocationTemplatesSelector';
|
|
||||||
|
|
||||||
export const useGetInvocationTemplate = () => {
|
|
||||||
const invocationTemplates = useAppSelector(invocationTemplatesSelector);
|
|
||||||
|
|
||||||
return (invocationType: string) => {
|
|
||||||
const template = invocationTemplates[invocationType];
|
|
||||||
|
|
||||||
if (!template) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return template;
|
|
||||||
};
|
|
||||||
};
|
|
Loading…
x
Reference in New Issue
Block a user