mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
perf(ui): fix issue w/ add node cmdk component (more fixed)
This commit is contained in:
@@ -19,13 +19,13 @@ import { IAINoContentFallback } from 'common/components/IAIImageFallback';
|
||||
import ScrollableContent from 'common/components/OverlayScrollbars/ScrollableContent';
|
||||
import { useBuildNode } from 'features/nodes/hooks/useBuildNode';
|
||||
import {
|
||||
$addNodeCmdk,
|
||||
$cursorPos,
|
||||
$edgePendingUpdate,
|
||||
$pendingConnection,
|
||||
$templates,
|
||||
edgesChanged,
|
||||
nodesChanged,
|
||||
useAddNodeCmdk,
|
||||
} from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { findUnoccupiedPosition } from 'features/nodes/store/util/findUnoccupiedPosition';
|
||||
@@ -142,19 +142,25 @@ const cmdkRootSx: SystemStyleObject = {
|
||||
|
||||
export const AddNodeCmdk = memo(() => {
|
||||
const { t } = useTranslation();
|
||||
const addNodeCmdk = useAddNodeCmdk();
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const addNode = useAddNode();
|
||||
const tab = useAppSelector(selectActiveTab);
|
||||
const [debouncedSearchTerm] = useDebounce(searchTerm, 300);
|
||||
const isOpen = useStore($addNodeCmdk);
|
||||
const open = useCallback(() => {
|
||||
$addNodeCmdk.set(true);
|
||||
}, []);
|
||||
const close = useCallback(() => {
|
||||
$addNodeCmdk.set(false);
|
||||
}, []);
|
||||
|
||||
useRegisteredHotkeys({
|
||||
id: 'addNode',
|
||||
category: 'workflows',
|
||||
callback: addNodeCmdk.setTrue,
|
||||
callback: open,
|
||||
options: { enabled: tab === 'workflows', preventDefault: true },
|
||||
dependencies: [addNodeCmdk.setTrue, tab],
|
||||
dependencies: [open, tab],
|
||||
});
|
||||
|
||||
const onChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
|
||||
@@ -162,10 +168,10 @@ export const AddNodeCmdk = memo(() => {
|
||||
}, []);
|
||||
|
||||
const onClose = useCallback(() => {
|
||||
addNodeCmdk.setFalse();
|
||||
close();
|
||||
setSearchTerm('');
|
||||
$pendingConnection.set(null);
|
||||
}, [addNodeCmdk]);
|
||||
}, [close]);
|
||||
|
||||
const onSelect = useCallback(
|
||||
(value: string) => {
|
||||
@@ -176,14 +182,7 @@ export const AddNodeCmdk = memo(() => {
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={addNodeCmdk.isTrue}
|
||||
onClose={onClose}
|
||||
useInert={false}
|
||||
initialFocusRef={inputRef}
|
||||
size="xl"
|
||||
isCentered
|
||||
>
|
||||
<Modal isOpen={isOpen} onClose={onClose} useInert={false} initialFocusRef={inputRef} size="xl" isCentered>
|
||||
<ModalOverlay />
|
||||
<ModalContent h="512" maxH="70%">
|
||||
<ModalBody p={2} h="full" sx={cmdkRootSx}>
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
import { IconButton } from '@invoke-ai/ui-library';
|
||||
import { useAddNodeCmdk } from 'features/nodes/store/nodesSlice';
|
||||
import { memo } from 'react';
|
||||
import { $addNodeCmdk } from 'features/nodes/store/nodesSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { PiPlusBold } from 'react-icons/pi';
|
||||
|
||||
const AddNodeButton = () => {
|
||||
const addNodeCmdk = useAddNodeCmdk();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
$addNodeCmdk.set(true);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
tooltip={t('nodes.addNodeToolTip')}
|
||||
aria-label={t('nodes.addNode')}
|
||||
icon={<PiPlusBold />}
|
||||
onClick={addNodeCmdk.setTrue}
|
||||
onClick={onClick}
|
||||
pointerEvents="auto"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
import { useStore } from '@nanostores/react';
|
||||
import { useReactFlow } from '@xyflow/react';
|
||||
import { $templates } from 'features/nodes/store/nodesSlice';
|
||||
import { $flow } from 'features/nodes/store/reactFlowInstance';
|
||||
import { NODE_WIDTH } from 'features/nodes/types/constants';
|
||||
import type { AnyNode, InvocationTemplate } from 'features/nodes/types/invocation';
|
||||
import { buildCurrentImageNode } from 'features/nodes/util/node/buildCurrentImageNode';
|
||||
import { buildInvocationNode } from 'features/nodes/util/node/buildInvocationNode';
|
||||
import { buildNotesNode } from 'features/nodes/util/node/buildNotesNode';
|
||||
import { useCallback } from 'react';
|
||||
import { assert } from 'tsafe';
|
||||
|
||||
export const useBuildNode = () => {
|
||||
const templates = useStore($templates);
|
||||
const { screenToFlowPosition } = useReactFlow();
|
||||
|
||||
return useCallback(
|
||||
// string here is "any invocation type"
|
||||
(type: string | 'current_image' | 'notes'): AnyNode => {
|
||||
const flow = $flow.get();
|
||||
assert(flow !== null);
|
||||
|
||||
let _x = window.innerWidth / 2;
|
||||
let _y = window.innerHeight / 2;
|
||||
|
||||
@@ -26,7 +29,7 @@ export const useBuildNode = () => {
|
||||
_y = rect.height / 2 - NODE_WIDTH / 2 + rect.top;
|
||||
}
|
||||
|
||||
const position = screenToFlowPosition({
|
||||
const position = flow.screenToFlowPosition({
|
||||
x: _x,
|
||||
y: _y,
|
||||
});
|
||||
@@ -45,6 +48,6 @@ export const useBuildNode = () => {
|
||||
|
||||
return buildInvocationNode(position, template);
|
||||
},
|
||||
[screenToFlowPosition, templates]
|
||||
[templates]
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,12 +4,12 @@ import { useUpdateNodeInternals } from '@xyflow/react';
|
||||
import { useAppStore } from 'app/store/storeHooks';
|
||||
import { $mouseOverNode } from 'features/nodes/hooks/useMouseOverNode';
|
||||
import {
|
||||
$addNodeCmdk,
|
||||
$didUpdateEdge,
|
||||
$edgePendingUpdate,
|
||||
$pendingConnection,
|
||||
$templates,
|
||||
edgesChanged,
|
||||
useAddNodeCmdk,
|
||||
} from 'features/nodes/store/nodesSlice';
|
||||
import { selectNodes, selectNodesSlice } from 'features/nodes/store/selectors';
|
||||
import { getFirstValidConnection } from 'features/nodes/store/util/getFirstValidConnection';
|
||||
@@ -22,7 +22,6 @@ export const useConnection = () => {
|
||||
const store = useAppStore();
|
||||
const templates = useStore($templates);
|
||||
const updateNodeInternals = useUpdateNodeInternals();
|
||||
const addNodeCmdk = useAddNodeCmdk();
|
||||
|
||||
const onConnectStart = useCallback<OnConnectStart>(
|
||||
(event, { nodeId, handleId, handleType }) => {
|
||||
@@ -109,9 +108,9 @@ export const useConnection = () => {
|
||||
$pendingConnection.set(null);
|
||||
} else {
|
||||
// The mouse is not over a node - we should open the add node popover
|
||||
addNodeCmdk.setTrue();
|
||||
$addNodeCmdk.set(true);
|
||||
}
|
||||
}, [addNodeCmdk, store, templates, updateNodeInternals]);
|
||||
}, [store, templates, updateNodeInternals]);
|
||||
|
||||
const api = useMemo(() => ({ onConnectStart, onConnect, onConnectEnd }), [onConnectStart, onConnect, onConnectEnd]);
|
||||
return api;
|
||||
|
||||
@@ -3,7 +3,6 @@ import { createSlice, isAnyOf } from '@reduxjs/toolkit';
|
||||
import type { EdgeChange, NodeChange, Viewport, XYPosition } from '@xyflow/react';
|
||||
import { applyEdgeChanges, applyNodeChanges, getConnectedEdges, getIncomers, getOutgoers } from '@xyflow/react';
|
||||
import type { PersistConfig } from 'app/store/store';
|
||||
import { buildUseBoolean } from 'common/hooks/useBoolean';
|
||||
import { workflowLoaded } from 'features/nodes/store/actions';
|
||||
import { SHARED_NODE_PROPERTIES } from 'features/nodes/types/constants';
|
||||
import type {
|
||||
@@ -541,7 +540,7 @@ export const $didUpdateEdge = atom(false);
|
||||
export const $lastEdgeUpdateMouseEvent = atom<MouseEvent | null>(null);
|
||||
|
||||
export const $viewport = atom<Viewport>({ x: 0, y: 0, zoom: 1 });
|
||||
export const [useAddNodeCmdk, $addNodeCmdk] = buildUseBoolean(false);
|
||||
export const $addNodeCmdk = atom(false);
|
||||
|
||||
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
||||
const migrateNodesState = (state: any): any => {
|
||||
|
||||
Reference in New Issue
Block a user