From 44e0328f362e3ec19fbc81168348d8b209364806 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Thu, 11 Apr 2024 13:43:36 -0300 Subject: [PATCH 01/60] Refactor: Use react-hotkeys-hook lib to handle shortcuts usability --- src/frontend/package-lock.json | 10 + src/frontend/package.json | 1 + .../components/nodeToolbarComponent/index.tsx | 195 ++++++++---------- 3 files changed, 99 insertions(+), 107 deletions(-) diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index 971c9eee11..4e3967f1be 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -50,6 +50,7 @@ "react-cookie": "^4.1.1", "react-dom": "^18.2.0", "react-error-boundary": "^4.0.11", + "react-hotkeys-hook": "^4.5.0", "react-icons": "^5.0.1", "react-laag": "^2.0.5", "react-markdown": "^8.0.7", @@ -10471,6 +10472,15 @@ "react": ">=16.13.1" } }, + "node_modules/react-hotkeys-hook": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-4.5.0.tgz", + "integrity": "sha512-Samb85GSgAWFQNvVt3PS90LPPGSf9mkH/r4au81ZP1yOIFayLC3QAvqTgGtJ8YEDMXtPmaVBs6NgipHO6h4Mug==", + "peerDependencies": { + "react": ">=16.8.1", + "react-dom": ">=16.8.1" + } + }, "node_modules/react-icons": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.0.1.tgz", diff --git a/src/frontend/package.json b/src/frontend/package.json index fd27d8bd6c..e298a84fb2 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -45,6 +45,7 @@ "react-cookie": "^4.1.1", "react-dom": "^18.2.0", "react-error-boundary": "^4.0.11", + "react-hotkeys-hook": "^4.5.0", "react-icons": "^5.0.1", "react-laag": "^2.0.5", "react-markdown": "^8.0.7", diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 8a134f48ad..9d097cb12d 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -31,6 +31,7 @@ import { } from "../../../../utils/reactflowUtils"; import { classNames } from "../../../../utils/utils"; import ToolbarSelectItem from "./toolbarSelectItem"; +import { useHotkeys } from "react-hotkeys-hook"; export default function NodeToolbarComponent({ data, @@ -65,6 +66,92 @@ export default function NodeToolbarComponent({ const hasApiKey = useStoreStore((state) => state.hasApiKey); const validApiKey = useStoreStore((state) => state.validApiKey); + function handleMinimizeWShortcut(e: KeyboardEvent) { + e.preventDefault() + if (isMinimal) { + setShowState((show) => !show); + setShowNode(data.showNode ?? true ? false : true); + return; + } + setNoticeData({ + title: + "Minimization are only available for nodes with one handle or fewer.", + }); + return; + } + + function handleUpdateWShortcut(e: KeyboardEvent) { + e.preventDefault() + if ((hasApiKey || hasStore)) { + handleSelectChange("update"); + } + } + + function handleGroupWShortcut(e: KeyboardEvent) { + e.preventDefault() + if (isGroup) { + handleSelectChange("ungroup"); + } + } + + function handleShareWShortcut(e: KeyboardEvent) { + e.preventDefault() + if (hasApiKey || hasStore) { + setShowconfirmShare((state) => !state); + } + } + + function handleCodeWShortcut(e: KeyboardEvent) { + e.preventDefault() + if (hasCode) return setOpenModal((state) => !state); + setNoticeData({ title: `You can not access ${data.id} code` }); + } + + function handleAdvancedWShortcut(e: KeyboardEvent) { + e.preventDefault() + if (!isGroup) { + setShowModalAdvanced((state) => !state); + } + } + + function handleSaveWShortcut(e: KeyboardEvent) { + e.preventDefault() + if (isSaved) { + setShowOverrideModal((state) => !state); + return; + } + if (hasCode) { + saveComponent(cloneDeep(data), false); + setSuccessData({ title: `${data.id} saved successfully` }); + return; + } + } + + function handleDocsWShortcut(e: KeyboardEvent) { + e.preventDefault(); + if (data.node?.documentation) { + return openInNewTab(data.node?.documentation); + } + setNoticeData({ + title: `${data.id} docs is not available at the moment.`, + }); + } + + function handleDownloadWShortcut(e: KeyboardEvent) { + e.preventDefault(); + downloadNode(flowComponent!); + } + + useHotkeys("ctrl+q", handleMinimizeWShortcut); + useHotkeys("ctrl+u", handleUpdateWShortcut); + useHotkeys("ctrl+g", handleGroupWShortcut); + useHotkeys("ctrl+shift+s", handleShareWShortcut); + useHotkeys("ctrl+shift+u", handleCodeWShortcut); + useHotkeys("ctrl+shift+a", handleAdvancedWShortcut); + useHotkeys("ctrl+s", handleSaveWShortcut); + useHotkeys("ctrl+shift+d", handleDocsWShortcut); + useHotkeys("ctrl+j", handleDownloadWShortcut); + const isMinimal = numberOfHandles <= 1; const isGroup = data.node?.flow ? true : false; @@ -265,112 +352,6 @@ export default function NodeToolbarComponent({ const [openModal, setOpenModal] = useState(false); const hasCode = Object.keys(data.node!.template).includes("code"); - useEffect(() => { - function onKeyDown(event: KeyboardEvent) { - if ( - selected && - (hasApiKey || hasStore) && - (event.ctrlKey || event.metaKey) && - event.key === "u" - ) { - event.preventDefault(); - handleSelectChange("update"); - } - if ( - selected && - isGroup && - (event.ctrlKey || event.metaKey) && - event.key === "g" - ) { - event.preventDefault(); - handleSelectChange("ungroup"); - } - if ( - selected && - (hasApiKey || hasStore) && - (event.ctrlKey || event.metaKey) && - event.shiftKey && - event.key === "S" - ) { - event.preventDefault(); - setShowconfirmShare((state) => !state); - } - - if ( - selected && - (event.ctrlKey || event.metaKey) && - event.shiftKey && - event.key === "Q" - ) { - event.preventDefault(); - if (isMinimal) { - setShowState((show) => !show); - setShowNode(data.showNode ?? true ? false : true); - return; - } - setNoticeData({ - title: - "Minimization are only available for nodes with one handle or fewer.", - }); - } - if ( - selected && - (event.ctrlKey || event.metaKey) && - event.shiftKey && - event.key === "U" - ) { - event.preventDefault(); - if (hasCode) return setOpenModal((state) => !state); - setNoticeData({ title: `You can not access ${data.id} code` }); - } - if ( - selected && - !isGroup && - (event.ctrlKey || event.metaKey) && - event.shiftKey && - event.key === "A" - ) { - event.preventDefault(); - setShowModalAdvanced((state) => !state); - } - if (selected && (event.ctrlKey || event.metaKey) && event.key === "s") { - if (isSaved) { - event.preventDefault(); - return setShowOverrideModal((state) => !state); - } - if (hasCode) { - event.preventDefault(); - saveComponent(cloneDeep(data), false); - setSuccessData({ title: `${data.id} saved successfully` }); - } - } - if ( - selected && - (event.ctrlKey || event.metaKey) && - event.shiftKey && - event.key === "D" - ) { - event.preventDefault(); - if (data.node?.documentation) { - return openInNewTab(data.node?.documentation); - } - setNoticeData({ - title: `${data.id} docs is not available at the moment.`, - }); - } - if (selected && (event.ctrlKey || event.metaKey) && event.key === "j") { - event.preventDefault(); - downloadNode(flowComponent!); - } - } - - document.addEventListener("keydown", onKeyDown); - - return () => { - document.removeEventListener("keydown", onKeyDown); - }; - }, [isSaved, showNode, data.showNode, isMinimal]); - return ( <>
@@ -567,7 +548,7 @@ export default function NodeToolbarComponent({ icon={showNode ? "Minimize2" : "Maximize2"} value={showNode ? "Minimize" : "Expand"} isMac={navigator.userAgent.toUpperCase().includes("MAC")} - shift={true} + shift={false} keyboardKey={"Q"} dataTestId={"minimize-button-nodeToolbar"} /> From 489fc0d64c72ef372d0cf388428ec494834e0779 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 12 Apr 2024 18:55:25 -0300 Subject: [PATCH 02/60] Refactor: Use mod key instead of ctrl key to enable shortcuts to mac users --- .../components/nodeToolbarComponent/index.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index f1f52b050b..8dcd851e72 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -142,15 +142,15 @@ export default function NodeToolbarComponent({ downloadNode(flowComponent!); } - useHotkeys("ctrl+q", handleMinimizeWShortcut); - useHotkeys("ctrl+u", handleUpdateWShortcut); - useHotkeys("ctrl+g", handleGroupWShortcut); - useHotkeys("ctrl+shift+s", handleShareWShortcut); - useHotkeys("ctrl+shift+u", handleCodeWShortcut); - useHotkeys("ctrl+shift+a", handleAdvancedWShortcut); - useHotkeys("ctrl+s", handleSaveWShortcut); - useHotkeys("ctrl+shift+d", handleDocsWShortcut); - useHotkeys("ctrl+j", handleDownloadWShortcut); + useHotkeys("mod+q", handleMinimizeWShortcut); + useHotkeys("mod+u", handleUpdateWShortcut); + useHotkeys("mod+g", handleGroupWShortcut); + useHotkeys("mod+shift+s", handleShareWShortcut); + useHotkeys("mod+shift+u", handleCodeWShortcut); + useHotkeys("mod+shift+a", handleAdvancedWShortcut); + useHotkeys("mod+s", handleSaveWShortcut); + useHotkeys("mod+shift+d", handleDocsWShortcut); + useHotkeys("mod+j", handleDownloadWShortcut); const isMinimal = numberOfHandles <= 1; const isGroup = data.node?.flow ? true : false; From 53f0388649705575f35cee89b807a82e9ea0e9b7 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Wed, 17 Apr 2024 19:56:21 -0300 Subject: [PATCH 03/60] Feat: add API Modal shortcut (ctrl+r) --- .../src/components/chatComponent/index.tsx | 36 +++++++++---------- src/frontend/src/modals/ApiModal/index.tsx | 9 ++++- .../components/nodeToolbarComponent/index.tsx | 2 +- 3 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 66ff2b609f..0eff32c8d8 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -9,32 +9,32 @@ import { useStoreStore } from "../../stores/storeStore"; import { classNames } from "../../utils/utils"; import ForwardedIconComponent from "../genericIconComponent"; import { Separator } from "../ui/separator"; +import { useHotkeys } from "react-hotkeys-hook"; export default function FlowToolbar(): JSX.Element { + function handleAPIWShortcut(e: KeyboardEvent) { + e.preventDefault(); + setOpenCodeModal((oldOpen) => !oldOpen) + } + + function handleChatWShortcut(e: KeyboardEvent) { + if (useFlowStore.getState().hasIO) { + e.preventDefault(); + setOpen((oldState) => !oldState); + } + } + + useHotkeys("mod+k", handleChatWShortcut); + useHotkeys("mod+r", handleAPIWShortcut); const [open, setOpen] = useState(false); + const [openCodeModal, setOpenCodeModal] = useState(false); + const hasIO = useFlowStore((state) => state.hasIO); const hasStore = useStoreStore((state) => state.hasStore); const validApiKey = useStoreStore((state) => state.validApiKey); const currentFlow = useFlowsManagerStore((state) => state.currentFlow); const hasApiKey = useStoreStore((state) => state.hasApiKey); - useEffect(() => { - const handleKeyDown = (event: KeyboardEvent) => { - if ( - (event.key === "K" || event.key === "k") && - (event.metaKey || event.ctrlKey) && - useFlowStore.getState().hasIO - ) { - event.preventDefault(); - setOpen((oldState) => !oldState); - } - }; - document.addEventListener("keydown", handleKeyDown); - return () => { - document.removeEventListener("keydown", handleKeyDown); - }; - }, []); - const prevNodesRef = useRef(); const ModalMemo = useMemo( @@ -117,7 +117,7 @@ export default function FlowToolbar(): JSX.Element {
{currentFlow && currentFlow.data && ( - +
{ const { autoLogin } = useContext(AuthContext); - const [open, setOpen] = useState(false); + const [open, setOpen] = + mySetOpen !== undefined && myOpen !== undefined + ? [myOpen, mySetOpen] + : useState(false); const [activeTab, setActiveTab] = useState("0"); const tweak = useRef([]); const tweaksList = useRef([]); diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 8dcd851e72..c862558486 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -95,8 +95,8 @@ export default function NodeToolbarComponent({ } function handleShareWShortcut(e: KeyboardEvent) { - e.preventDefault() if (hasApiKey || hasStore) { + e.preventDefault() setShowconfirmShare((state) => !state); } } From 58f78c3680d6cd11dc5fc6ef83e8277d2199924a Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 19 Apr 2024 13:33:11 -0300 Subject: [PATCH 04/60] Feat: make space open node code modal --- .../src/pages/FlowPage/components/nodeToolbarComponent/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index c862558486..fa7478b4a5 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -151,6 +151,7 @@ export default function NodeToolbarComponent({ useHotkeys("mod+s", handleSaveWShortcut); useHotkeys("mod+shift+d", handleDocsWShortcut); useHotkeys("mod+j", handleDownloadWShortcut); + useHotkeys("space", handleCodeWShortcut) const isMinimal = numberOfHandles <= 1; const isGroup = data.node?.flow ? true : false; From a0a01aef3fe166fcb7202fc6ecb117312f0eeb55 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 19 Apr 2024 16:57:57 -0300 Subject: [PATCH 05/60] Feat: make possible to open node advanced settings by double clicking the node --- .../src/CustomNodes/GenericNode/index.tsx | 7 ++++++ .../src/modals/EditNodeModal/index.tsx | 8 +++++++ .../components/nodeToolbarComponent/index.tsx | 23 ++++++++++++++----- src/frontend/src/types/components/index.ts | 11 ++------- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index 29673fdb89..bc0ff0fd85 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -339,6 +339,8 @@ export default function GenericNode({ ); }; + const [openWDoubleCLick, setOpenWDoubleCLick] = useState(false); + const getBaseBorderClass = (selected) => selected ? "border border-ring" : "border"; @@ -349,6 +351,8 @@ export default function GenericNode({ return ( { takeSnapshot(); @@ -382,12 +386,15 @@ export default function GenericNode({ updateNodeCode, isOutdated, selected, + openWDoubleCLick, + setOpenWDoubleCLick ]); return ( <> {memoizedNodeToolbarComponent}
setOpenWDoubleCLick(true)} className={getNodeBorderClassName( selected, showNode, diff --git a/src/frontend/src/modals/EditNodeModal/index.tsx b/src/frontend/src/modals/EditNodeModal/index.tsx index 17da8c73b3..1e90cacce9 100644 --- a/src/frontend/src/modals/EditNodeModal/index.tsx +++ b/src/frontend/src/modals/EditNodeModal/index.tsx @@ -46,11 +46,13 @@ const EditNodeModal = forwardRef( nodeLength, open, setOpen, + setOpenWDoubleClick, }: { data: NodeDataType; nodeLength: number; open: boolean; setOpen: (open: boolean) => void; + setOpenWDoubleClick: (open: boolean) => void; }, ref ) => { @@ -82,6 +84,12 @@ const EditNodeModal = forwardRef( } }, [open]); + useEffect(() => { + return () => { + setOpenWDoubleClick(false) + } + }, []) + const [errorDuplicateKey, setErrorDuplicateKey] = useState(false); return ( diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index fa7478b4a5..220b53ee02 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -45,6 +45,8 @@ export default function NodeToolbarComponent({ setShowState, onCloseAdvancedModal, isOutdated, + openWDoubleClick, + setOpenWDoubleClick, }: nodeToolbarPropsType): JSX.Element { const nodeLength = Object.keys(data.node!.template).filter( (templateField) => @@ -176,6 +178,12 @@ export default function NodeToolbarComponent({ createFlowComponent(cloneDeep(data), version) ); + useEffect(() => { + console.log(openWDoubleClick) + if (openWDoubleClick) setShowModalAdvanced(true) + }, [openWDoubleClick, setOpenWDoubleClick]); + + const openInNewTab = (url) => { window.open(url, "_blank", "noreferrer"); }; @@ -621,12 +629,15 @@ export default function NodeToolbarComponent({ - + {showModalAdvanced && ( + + )} {showconfirmShare && ( void; - setDb: (value: boolean) => void; - name: string; - data: NodeDataType; - editNode?: boolean; -}; - export type KeyPairListComponentType = { value: any; onChange: (value: Object[]) => void; @@ -511,6 +502,8 @@ export type fileCardPropsType = { }; export type nodeToolbarPropsType = { + openWDoubleClick: boolean; + setOpenWDoubleClick: (open: boolean) => void; data: NodeDataType; deleteNode: (idx: string) => void; setShowNode: (boolean: any) => void; From 2818909126f044198f72012c16d5e373b85211bc Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 19 Apr 2024 16:58:41 -0300 Subject: [PATCH 06/60] remove console.log --- .../src/pages/FlowPage/components/nodeToolbarComponent/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 220b53ee02..0636ec7e3e 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -179,7 +179,6 @@ export default function NodeToolbarComponent({ ); useEffect(() => { - console.log(openWDoubleClick) if (openWDoubleClick) setShowModalAdvanced(true) }, [openWDoubleClick, setOpenWDoubleClick]); From c550a1dd8ae92235e2b863afdc982b5b6a0fee70 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Mon, 22 Apr 2024 20:58:03 -0300 Subject: [PATCH 07/60] Refactor: Add all toolbar options into more --- .../components/nodeToolbarComponent/index.tsx | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 0636ec7e3e..858cc555af 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -215,6 +215,15 @@ export default function NodeToolbarComponent({ const handleSelectChange = (event) => { switch (event) { + case "save": + if (isSaved) { + return setShowOverrideModal(true); + } + saveComponent(cloneDeep(data), false); + break; + case "code": + setOpenModal(!openModal); + break; case "advanced": setShowModalAdvanced(true); break; @@ -461,6 +470,18 @@ export default function NodeToolbarComponent({ + {hasCode && ( + + + + )} {nodeLength > 0 && ( )} + + + + + + {/* Date: Mon, 22 Apr 2024 21:49:36 -0300 Subject: [PATCH 08/60] Feat: add shortcut to open flow share modal (ctrl+alt+s) --- src/frontend/src/modals/shareModal/index.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/frontend/src/modals/shareModal/index.tsx b/src/frontend/src/modals/shareModal/index.tsx index 8272bddbe3..2d23563f19 100644 --- a/src/frontend/src/modals/shareModal/index.tsx +++ b/src/frontend/src/modals/shareModal/index.tsx @@ -25,6 +25,7 @@ import { import { getTagsIds } from "../../utils/storeUtils"; import ConfirmationModal from "../ConfirmationModal"; import BaseModal from "../baseModal"; +import { useHotkeys } from "react-hotkeys-hook"; export default function ShareModal({ component, @@ -41,6 +42,10 @@ export default function ShareModal({ setOpen?: (open: boolean) => void; disabled?: boolean; }): JSX.Element { + function handleOpenWShortcut(e: KeyboardEvent) { + e.preventDefault() + internalSetOpen(state => !state); + } const version = useDarkStore((state) => state.version); const hasStore = useStoreStore((state) => state.hasStore); const hasApiKey = useStoreStore((state) => state.hasApiKey); @@ -51,6 +56,8 @@ export default function ShareModal({ const [openConfirmationModal, setOpenConfirmationModal] = useState(false); const nameComponent = is_component ? "component" : "workflow"; + useHotkeys("mod+alt+s", handleOpenWShortcut) + const [tags, setTags] = useState<{ id: string; name: string }[]>([]); const [loadingTags, setLoadingTags] = useState(false); const [sharePublic, setSharePublic] = useState(true); From 113b47804fe53d53621ec866fc508d0598a2e6dc Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Mon, 22 Apr 2024 22:23:47 -0300 Subject: [PATCH 09/60] Feat: Add validation to avoid error when user doesnt have access to the store --- src/frontend/src/modals/shareModal/index.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/modals/shareModal/index.tsx b/src/frontend/src/modals/shareModal/index.tsx index 2d23563f19..d40a5a3991 100644 --- a/src/frontend/src/modals/shareModal/index.tsx +++ b/src/frontend/src/modals/shareModal/index.tsx @@ -43,8 +43,10 @@ export default function ShareModal({ disabled?: boolean; }): JSX.Element { function handleOpenWShortcut(e: KeyboardEvent) { - e.preventDefault() - internalSetOpen(state => !state); + if (hasApiKey || hasStore) { + e.preventDefault() + internalSetOpen(state => !state); + } } const version = useDarkStore((state) => state.version); const hasStore = useStoreStore((state) => state.hasStore); From cfff4e3f1e834aaad6d1983657c1bcf139c86523 Mon Sep 17 00:00:00 2001 From: Lucas Oliveira Date: Mon, 29 Apr 2024 23:28:18 +0200 Subject: [PATCH 10/60] Fixed double click on description opening Settings modal --- .../src/CustomNodes/GenericNode/index.tsx | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index bc0ff0fd85..600f20d1fb 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -27,7 +27,13 @@ import { validationStatusType } from "../../types/components"; import { NodeDataType } from "../../types/flow"; import { handleKeyDown, scapedJSONStringfy } from "../../utils/reactflowUtils"; import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils"; -import { classNames, cn, getFieldTitle, sortFields } from "../../utils/utils"; +import { + classNames, + cn, + getFieldTitle, + isWrappedWithClass, + sortFields, +} from "../../utils/utils"; import ParameterComponent from "./components/parameterComponent"; export default function GenericNode({ @@ -387,14 +393,17 @@ export default function GenericNode({ isOutdated, selected, openWDoubleCLick, - setOpenWDoubleCLick + setOpenWDoubleCLick, ]); return ( <> {memoizedNodeToolbarComponent}
setOpenWDoubleCLick(true)} + onDoubleClick={(event) => { + if (!isWrappedWithClass(event, "nodoubleclick")) + setOpenWDoubleCLick(true); + }} className={getNodeBorderClassName( selected, showNode, @@ -467,7 +476,7 @@ export default function GenericNode({ event.preventDefault(); }} data-testid={"title-" + data.node?.display_name} - className="generic-node-tooltip-div cursor-text text-primary" + className="nodoubleclick generic-node-tooltip-div cursor-text text-primary" > {data.node?.display_name}
@@ -720,7 +729,7 @@ export default function GenericNode({ ) : (
Date: Mon, 29 Apr 2024 23:37:31 +0200 Subject: [PATCH 11/60] Fixed Code shortcut --- .../components/nodeToolbarComponent/index.tsx | 37 +++++++------------ .../toolbarSelectItem/index.tsx | 34 +++++++++-------- src/frontend/src/types/components/index.ts | 1 + 3 files changed, 32 insertions(+), 40 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 858cc555af..bf94458c74 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -1,5 +1,6 @@ import _, { cloneDeep } from "lodash"; import { useEffect, useState } from "react"; +import { useHotkeys } from "react-hotkeys-hook"; import { useUpdateNodeInternals } from "reactflow"; import ShadTooltip from "../../../../components/ShadTooltipComponent"; import CodeAreaComponent from "../../../../components/codeAreaComponent"; @@ -31,7 +32,6 @@ import { } from "../../../../utils/reactflowUtils"; import { classNames } from "../../../../utils/utils"; import ToolbarSelectItem from "./toolbarSelectItem"; -import { useHotkeys } from "react-hotkeys-hook"; export default function NodeToolbarComponent({ data, @@ -69,7 +69,7 @@ export default function NodeToolbarComponent({ const validApiKey = useStoreStore((state) => state.validApiKey); function handleMinimizeWShortcut(e: KeyboardEvent) { - e.preventDefault() + e.preventDefault(); if (isMinimal) { setShowState((show) => !show); setShowNode(data.showNode ?? true ? false : true); @@ -83,14 +83,14 @@ export default function NodeToolbarComponent({ } function handleUpdateWShortcut(e: KeyboardEvent) { - e.preventDefault() - if ((hasApiKey || hasStore)) { + e.preventDefault(); + if (hasApiKey || hasStore) { handleSelectChange("update"); } } function handleGroupWShortcut(e: KeyboardEvent) { - e.preventDefault() + e.preventDefault(); if (isGroup) { handleSelectChange("ungroup"); } @@ -98,26 +98,26 @@ export default function NodeToolbarComponent({ function handleShareWShortcut(e: KeyboardEvent) { if (hasApiKey || hasStore) { - e.preventDefault() + e.preventDefault(); setShowconfirmShare((state) => !state); } } function handleCodeWShortcut(e: KeyboardEvent) { - e.preventDefault() + e.preventDefault(); if (hasCode) return setOpenModal((state) => !state); setNoticeData({ title: `You can not access ${data.id} code` }); } function handleAdvancedWShortcut(e: KeyboardEvent) { - e.preventDefault() + e.preventDefault(); if (!isGroup) { setShowModalAdvanced((state) => !state); } } function handleSaveWShortcut(e: KeyboardEvent) { - e.preventDefault() + e.preventDefault(); if (isSaved) { setShowOverrideModal((state) => !state); return; @@ -153,7 +153,7 @@ export default function NodeToolbarComponent({ useHotkeys("mod+s", handleSaveWShortcut); useHotkeys("mod+shift+d", handleDocsWShortcut); useHotkeys("mod+j", handleDownloadWShortcut); - useHotkeys("space", handleCodeWShortcut) + useHotkeys("space", handleCodeWShortcut); const isMinimal = numberOfHandles <= 1; const isGroup = data.node?.flow ? true : false; @@ -165,7 +165,6 @@ export default function NodeToolbarComponent({ const setNodes = useFlowStore((state) => state.setNodes); const setEdges = useFlowStore((state) => state.setEdges); - const unselectAll = useFlowStore((state) => state.unselectAll); const saveComponent = useFlowsManagerStore((state) => state.saveComponent); const getNodePosition = useFlowStore((state) => state.getNodePosition); const flows = useFlowsManagerStore((state) => state.flows); @@ -179,10 +178,9 @@ export default function NodeToolbarComponent({ ); useEffect(() => { - if (openWDoubleClick) setShowModalAdvanced(true) + if (openWDoubleClick) setShowModalAdvanced(true); }, [openWDoubleClick, setOpenWDoubleClick]); - const openInNewTab = (url) => { window.open(url, "_blank", "noreferrer"); }; @@ -473,9 +471,10 @@ export default function NodeToolbarComponent({ {hasCode && ( - {/* - - */} {value} - {isMac ? ( - - ) : ( - - {shift ? "Ctrl" : "Ctrl +"} - - )} + {mod && + (isMac ? ( + + ) : ( + + {shift ? "Ctrl" : "Ctrl +"} + + ))} {shift && ( Date: Mon, 29 Apr 2024 23:51:11 +0200 Subject: [PATCH 12/60] Fixed PageComponent shortcuts not considering shift --- .../pages/FlowPage/components/PageComponent/index.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index e0b7af4f76..7883317ad8 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -145,6 +145,7 @@ export default function Page({ if ( selectionMenuVisible && (event.ctrlKey || event.metaKey) && + !event.shiftKey && event.key === "g" ) { event.preventDefault(); @@ -153,6 +154,7 @@ export default function Page({ if ( (event.ctrlKey || event.metaKey) && event.key === "p" && + !event.shiftKey && selectedNode.length > 0 ) { event.preventDefault(); @@ -169,6 +171,7 @@ export default function Page({ } if ( (event.ctrlKey || event.metaKey) && + !event.shiftKey && event.key === "d" && selectedNode.length > 0 ) { @@ -183,12 +186,12 @@ export default function Page({ } if (!isWrappedWithClass(event, "noundo")) { if ( - (event.key === "y" || (event.key === "z" && event.shiftKey)) && + ((event.key === "y" && !event.shiftKey) || (event.key === "z" && event.shiftKey)) && (event.ctrlKey || event.metaKey) ) { event.preventDefault(); // prevent the default action redo(); - } else if (event.key === "z" && (event.ctrlKey || event.metaKey)) { + } else if (event.key === "z" && (event.ctrlKey || event.metaKey) && !event.shiftKey) { event.preventDefault(); undo(); } @@ -199,6 +202,7 @@ export default function Page({ ) { if ( (event.ctrlKey || event.metaKey) && + !event.shiftKey && event.key === "c" && lastSelection ) { @@ -206,6 +210,7 @@ export default function Page({ setLastCopiedSelection(_.cloneDeep(lastSelection)); } else if ( (event.ctrlKey || event.metaKey) && + !event.shiftKey && event.key === "x" && lastSelection ) { @@ -213,6 +218,7 @@ export default function Page({ setLastCopiedSelection(_.cloneDeep(lastSelection), true); } else if ( (event.ctrlKey || event.metaKey) && + !event.shiftKey && event.key === "v" && lastCopiedSelection ) { @@ -224,6 +230,7 @@ export default function Page({ }); } else if ( (event.ctrlKey || event.metaKey) && + !event.shiftKey && event.key === "g" && lastSelection ) { From 604e579bed567a83c52f123fa54556f06fee755b Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 30 Apr 2024 19:56:35 -0300 Subject: [PATCH 13/60] Feat: User can edit his keys combination for each shortcut --- src/frontend/src/constants/constants.ts | 41 +++++++ .../EditShortcutButton/index.tsx | 113 ++++++++++++++++++ .../pages/ShortcutsPage/index.tsx | 50 +++++++- src/frontend/src/stores/shortcuts.ts | 14 +-- src/frontend/src/types/store/index.ts | 8 +- 5 files changed, 213 insertions(+), 13 deletions(-) create mode 100644 src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index c8d7626ca4..e862de5e9e 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -754,3 +754,44 @@ export const NATIVE_CATEGORIES = [ ]; export const SAVE_DEBOUNCE_TIME = 300; + +export const defaultShortcuts = [ + { + name: "Advanced Settings", + shortcut: "Ctrl + Shift + a" + }, + { + name: "Minimize", + shortcut: "Ctrl + Shift + q" + }, + { + name: "Code", + shortcut: "Ctrl + Shift + c" + }, + { + name: "Copy", + shortcut: "Ctrl + c" + }, + { + name: "Duplicate", + shortcut: "Ctrl + d" + }, + { + name: "Share", + shortcut: "Ctrl + Shift + s" + }, + { + name: "Docs", + shortcut: "Ctrl + Shift + d" + }, + { + name: "Save", + shortcut: "Ctrl + s" + }, + { + name: "Delete", + shortcut: "Backspace" + }, +]; + +export const unavailableShortcutss = ["Ctrl + Shift + a", "Ctrl + Shift + q", "Ctrl + Shift + c", "Ctrl + c", "Ctrl + d", "Ctrl + Shift + s", "Ctrl + Shift + d", "Ctrl + s", "Backspace"]; diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx new file mode 100644 index 0000000000..738eb18291 --- /dev/null +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx @@ -0,0 +1,113 @@ + + +//TODO IMPLEMENT FORM LOGIC + +import { useEffect, useState } from "react"; +import useAlertStore from "../../../../../stores/alertStore"; +import { useTypesStore } from "../../../../../stores/typesStore"; +import { useGlobalVariablesStore } from "../../../../../stores/globalVariables"; +import { registerGlobalVariable } from "../../../../../controllers/API"; +import { ResponseErrorDetailAPI } from "../../../../../types/api"; +import BaseModal from "../../../../../modals/baseModal"; +import { Label } from "@radix-ui/react-select"; +import { Input } from "../../../../../components/ui/input"; +import InputComponent from "../../../../../components/inputComponent"; +import { Textarea } from "../../../../../components/ui/textarea"; +import { Button } from "../../../../../components/ui/button"; +import ForwardedIconComponent from "../../../../../components/genericIconComponent"; +import { defaultShortcuts } from "../../../../../constants/constants"; +import { useShortcutsStore } from "../../../../../stores/shortcuts"; + +export default function EditShortcutButton({ children, shortcut, defaultShortcuts, defaultCombination, open, setOpen, }: {children: JSX.Element; shortcut: string[]; defaultShortcuts: Array<{name: string; shortcut: string;}>; defaultCombination: string; open: boolean; setOpen: (bool: boolean) => void;}): JSX.Element { + const setSuccessData = useAlertStore(state => state.setSuccessData) + const setShortcuts = useShortcutsStore(state => state.setShortcuts); + const unavaliableShortcuts = useShortcutsStore(state => state.unavailableShortcuts); + const isMac = navigator.userAgent.toUpperCase().includes("MAC"); + const [fields, setFields] = useState([]); + const setErrorData = useAlertStore((state) => state.setErrorData); + const componentFields = useTypesStore((state) => state.ComponentFields); + const unavaliableFields =new Set(Object.keys(useGlobalVariablesStore( + (state) => state.unavaliableFields + ))); + + const [key, setKey] = useState(isMac ? "Meta" : 'Ctrl'); + + const availableFields = Array.from(componentFields).filter( + (field) => !unavaliableFields.has(field) + ); + const addGlobalVariable = useGlobalVariablesStore( + (state) => state.addGlobalVariable + ); + + function canEditCombination(newCombination: string): boolean { + return !unavaliableShortcuts.includes(newCombination); + } + + function editCombination(): void { + if (canEditCombination(key)) { + const newCombination = defaultShortcuts.map((s) => { + if (s.name === shortcut[0]) { + return {name: s.name, shortcut: key} + } + return {name: s.name, shortcut: s.shortcut}; + }) + const unavailable = unavaliableShortcuts.map((s) => { + if (s === defaultCombination) return s = key; + return s; + }) + setShortcuts(newCombination, unavailable) + setOpen(false) + setSuccessData({title: `${shortcut[0]} shortcut successfully changed`}) + setKey(isMac ? "Meta" : 'Ctrl') + return; + } + setErrorData({title: "Error saving key combination", list: ["This combination already exists!"]}) + } + + useEffect(() => { + if (!open) setKey(isMac ? "Meta" : 'Ctrl') + }, [open, setOpen]) + + useEffect(() => { + function onKeyDown(e: KeyboardEvent) { + e.preventDefault() + console.log(e.key) + if (key.includes(e.key)) return; + setKey(oldKey => `${oldKey} + ${e.key}`) + } + + document.addEventListener("keydown", onKeyDown); + + return () => { + document.removeEventListener("keydown", onKeyDown) + } + }, [key, setKey]) + + return ( + + + Key Combination + + {children} + +
+
+ {key} +
+
+
+ + + +
+ ); +} diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx index adcfcefef3..a53f785db1 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx @@ -1,5 +1,5 @@ import { ColDef, ColGroupDef } from "ag-grid-community"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import ForwardedIconComponent from "../../../../components/genericIconComponent"; import TableComponent from "../../../../components/tableComponent"; import { @@ -9,6 +9,9 @@ import { CardHeader, CardTitle, } from "../../../../components/ui/card"; +import { Button } from "../../../../components/ui/button"; +import EditShortcutButton from "./EditShortcutButton"; +import { useShortcutsStore } from "../../../../stores/shortcuts"; export default function ShortcutsPage() { const advancedShortcut = "Ctrl + Shift + A"; @@ -24,9 +27,20 @@ export default function ShortcutsPage() { const undoShortcut = "Ctrl + Z"; const redoShortcut = "Ctrl + Y"; + const [selectedRows, setSelectedRows] = useState([]); + const shortcuts = useShortcutsStore(state => state.shortcuts) + // Column Definitions: Defines the columns to be displayed. const [colDefs, setColDefs] = useState<(ColDef | ColGroupDef)[]>([ - { headerName: "Functionality", field: "name", flex: 1, editable: false }, //This column will be twice as wide as the others + { + headerName: "Functionality", + field: "name", + flex: 1, + editable: false, + headerCheckboxSelection: true, + checkboxSelection: true, + showDisabledCheckboxes: true, + }, //This column will be twice as wide as the others { field: "shortcut", flex: 2, @@ -87,6 +101,14 @@ export default function ShortcutsPage() { shortcut: redoShortcut, }, ]); + + useEffect(() => { + setNodesRowData(shortcuts) + }, [shortcuts]) + + const combinationToEdit = shortcuts.filter((s) => s.name === selectedRows[0]) + const [open, setOpen] = useState(false); + return (
@@ -113,7 +135,27 @@ export default function ShortcutsPage() { +
+
+ + + +
+
{ + setSelectedRows(event.api.getSelectedRows().map((row) => row.name)); + }} + suppressRowClickSelection={true} domLayout="autoHeight" pagination={false} columnDefs={colDefs} @@ -128,6 +170,10 @@ export default function ShortcutsPage() { { + setSelectedRows(event.api.getSelectedRows().map((row) => row.name)); + }} + suppressRowClickSelection={true} domLayout="autoHeight" pagination={false} columnDefs={colDefs} diff --git a/src/frontend/src/stores/shortcuts.ts b/src/frontend/src/stores/shortcuts.ts index 7986137086..d54753fbc4 100644 --- a/src/frontend/src/stores/shortcuts.ts +++ b/src/frontend/src/stores/shortcuts.ts @@ -1,15 +1,11 @@ import { create } from "zustand"; import { shortcutsStoreType } from "../types/store"; +import { defaultShortcuts, unavailableShortcutss } from "../constants/constants"; export const useShortcutsStore = create((set, get) => ({ - openCodeModalWShortcut: false, - handleModalWShortcut: (modal) => { - switch (modal) { - case "code": - set({ - openCodeModalWShortcut: !get().openCodeModalWShortcut, - }); - break; - } + unavailableShortcuts: unavailableShortcutss, + shortcuts: defaultShortcuts, + setShortcuts: (newShortcuts, unavailable) => { + set({shortcuts: newShortcuts, unavailableShortcuts: unavailable} ); }, })); diff --git a/src/frontend/src/types/store/index.ts b/src/frontend/src/types/store/index.ts index b116bbc3d7..cfafe4f4e9 100644 --- a/src/frontend/src/types/store/index.ts +++ b/src/frontend/src/types/store/index.ts @@ -20,6 +20,10 @@ export type StoreComponentResponse = { }; export type shortcutsStoreType = { - openCodeModalWShortcut: boolean; - handleModalWShortcut: (str: string) => void; + shortcuts: Array<{ + name: string; + shortcut: string; + }> + unavailableShortcuts: string[]; + setShortcuts: (newShortcuts: Array<{name: string; shortcut: string;}>, unavailable: string[]) => void; }; From edb2ff4034fb194e3e52aa7244ae0cfe8ea58028 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 30 Apr 2024 20:00:54 -0300 Subject: [PATCH 14/60] Fix: resolve merge conflicts --- src/frontend/package.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/frontend/package.json b/src/frontend/package.json index 19c79b3edf..d9371f3854 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -26,10 +26,7 @@ "@tailwindcss/line-clamp": "^0.4.4", "@types/axios": "^0.14.0", "ace-builds": "^1.24.1", -<<<<<<< HEAD "ag-grid-community": "^31.2.1", -======= ->>>>>>> node-shortcuts-refactor "ag-grid-react": "^31.2.1", "ansi-to-html": "^0.7.2", "axios": "^1.5.0", From 86fe906626cfe1590796ac13915230e44cefc09d Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 30 Apr 2024 20:54:48 -0300 Subject: [PATCH 15/60] Feat: User can change the node shortcuts --- src/frontend/src/constants/constants.ts | 6 +++--- .../components/nodeToolbarComponent/index.tsx | 20 +++++++++++++------ .../EditShortcutButton/index.tsx | 7 +++++++ src/frontend/src/stores/shortcuts.ts | 14 +++++++++++++ src/frontend/src/types/store/index.ts | 10 ++++++++++ 5 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index 630008c407..06348105c5 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -791,11 +791,11 @@ export const defaultShortcuts = [ }, { name: "Minimize", - shortcut: "Ctrl + Shift + q" + shortcut: "Ctrl + q" }, { name: "Code", - shortcut: "Ctrl + Shift + c" + shortcut: "Ctrl + Shift + u" }, { name: "Copy", @@ -823,4 +823,4 @@ export const defaultShortcuts = [ }, ]; -export const unavailableShortcutss = ["Ctrl + Shift + a", "Ctrl + Shift + q", "Ctrl + Shift + c", "Ctrl + c", "Ctrl + d", "Ctrl + Shift + s", "Ctrl + Shift + d", "Ctrl + s", "Backspace"]; +export const unavailableShortcutss = ["Ctrl + Shift + a", "Ctrl + q", "Ctrl + Shift + u", "Ctrl + c", "Ctrl + d", "Ctrl + Shift + s", "Ctrl + Shift + d", "Ctrl + s", "Backspace"]; diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index bf94458c74..c907325415 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -32,6 +32,7 @@ import { } from "../../../../utils/reactflowUtils"; import { classNames } from "../../../../utils/utils"; import ToolbarSelectItem from "./toolbarSelectItem"; +import { useShortcutsStore } from "../../../../stores/shortcuts"; export default function NodeToolbarComponent({ data, @@ -144,14 +145,21 @@ export default function NodeToolbarComponent({ downloadNode(flowComponent!); } - useHotkeys("mod+q", handleMinimizeWShortcut); + const advanced = useShortcutsStore(state => state.advanced); + const minimize = useShortcutsStore(state => state.minimize); + const share = useShortcutsStore(state => state.share); + const save = useShortcutsStore(state => state.save); + const docs = useShortcutsStore(state => state.docs); + const code = useShortcutsStore(state => state.code); + + useHotkeys(minimize, handleMinimizeWShortcut); useHotkeys("mod+u", handleUpdateWShortcut); useHotkeys("mod+g", handleGroupWShortcut); - useHotkeys("mod+shift+s", handleShareWShortcut); - useHotkeys("mod+shift+u", handleCodeWShortcut); - useHotkeys("mod+shift+a", handleAdvancedWShortcut); - useHotkeys("mod+s", handleSaveWShortcut); - useHotkeys("mod+shift+d", handleDocsWShortcut); + useHotkeys(share, handleShareWShortcut); + useHotkeys(code, handleCodeWShortcut); + useHotkeys(advanced, handleAdvancedWShortcut); + useHotkeys(save, handleSaveWShortcut); + useHotkeys(docs, handleDocsWShortcut); useHotkeys("mod+j", handleDownloadWShortcut); useHotkeys("space", handleCodeWShortcut); diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx index 738eb18291..2140629355 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx @@ -43,6 +43,8 @@ export default function EditShortcutButton({ children, shortcut, defaultShortcut return !unavaliableShortcuts.includes(newCombination); } + const setUniqueShortcut = useShortcutsStore(state => state.updateUniqueShortcut); + function editCombination(): void { if (canEditCombination(key)) { const newCombination = defaultShortcuts.map((s) => { @@ -55,6 +57,11 @@ export default function EditShortcutButton({ children, shortcut, defaultShortcut if (s === defaultCombination) return s = key; return s; }) + const fixCombination = key.split(" ") + fixCombination[0] = "mod" + const shortcutName = shortcut[0].split(" ")[0].toLowerCase(); + console.log(shortcutName) + setUniqueShortcut(shortcutName, fixCombination.join("").toLowerCase()) setShortcuts(newCombination, unavailable) setOpen(false) setSuccessData({title: `${shortcut[0]} shortcut successfully changed`}) diff --git a/src/frontend/src/stores/shortcuts.ts b/src/frontend/src/stores/shortcuts.ts index d54753fbc4..66a21c1068 100644 --- a/src/frontend/src/stores/shortcuts.ts +++ b/src/frontend/src/stores/shortcuts.ts @@ -8,4 +8,18 @@ export const useShortcutsStore = create((set, get) => ({ setShortcuts: (newShortcuts, unavailable) => { set({shortcuts: newShortcuts, unavailableShortcuts: unavailable} ); }, + advanced: "mod+shift+a", + minimize: "mod+shift+q", + code: "mod+shift+u", + copy: "mod+c", + duplicate: "mod+d", + share: "mod+shift+s", + docs: "mod+shift+d", + save: "mod+s", + delete: "backspace", + updateUniqueShortcut: (name, combination) => { + set({ + [name]: combination + }) + } })); diff --git a/src/frontend/src/types/store/index.ts b/src/frontend/src/types/store/index.ts index cfafe4f4e9..fa193c5012 100644 --- a/src/frontend/src/types/store/index.ts +++ b/src/frontend/src/types/store/index.ts @@ -20,6 +20,16 @@ export type StoreComponentResponse = { }; export type shortcutsStoreType = { + updateUniqueShortcut: (name: string, combination: string) => void; + advanced: string; + minimize: string; + code: string; + copy: string; + duplicate: string; + share: string; + docs:string; + save:string; + delete: string; shortcuts: Array<{ name: string; shortcut: string; From c146a0c82847df6bdcee2534f21bb43b41acb175 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Wed, 1 May 2024 01:22:02 -0300 Subject: [PATCH 16/60] Fix merge --- src/frontend/src/constants/constants.ts | 8 +- .../components/PageComponent/index.tsx | 203 ++++++++---------- .../EditShortcutButton/index.tsx | 34 ++- .../pages/ShortcutsPage/index.tsx | 86 +------- src/frontend/src/stores/shortcuts.ts | 3 + src/frontend/src/types/store/index.ts | 3 + 6 files changed, 120 insertions(+), 217 deletions(-) diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index a14b124c7c..8e0d70f246 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -823,16 +823,16 @@ export const defaultShortcuts = [ }, { name: "Open playground", - shortcut: "Ctrl K" + shortcut: "Ctrl + k" }, { name: "Undo", - shortcut: "Ctrl Z" + shortcut: "Ctrl + z" }, { name: "Redo", - shortcut: "Ctrl Y" + shortcut: "Ctrl + y" } ]; -export const unavailableShortcutss = ["Ctrl + Shift + a", "Ctrl + q", "Ctrl + Shift + u", "Ctrl + c", "Ctrl + d", "Ctrl + Shift + s", "Ctrl + Shift + d", "Ctrl + s", "Backspace", "Ctrl + K", "Ctrl + Z", "Ctrl + Y"]; +export const unavailableShortcutss = ["CTRL + SHIFT + A", "CTRL + Q", "CTRL + SHIFT + U", "CTRL + C", "CTRL + D", "CTRL + SHIFT + S", "CTRL + SHIFT + D", "CTRL + S", "BACKSPACE", "CTRL + K", "CTRL + Z", "CTRL + Y"]; diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index 7883317ad8..8b10d577b9 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -1,5 +1,5 @@ import _, { cloneDeep } from "lodash"; -import { MouseEvent, useCallback, useEffect, useRef, useState } from "react"; +import { KeyboardEvent, MouseEvent, useCallback, useEffect, useRef, useState } from "react"; import ReactFlow, { Background, Connection, @@ -37,6 +37,8 @@ import { import { getRandomName, isWrappedWithClass } from "../../../../utils/utils"; import ConnectionLineComponent from "../ConnectionLineComponent"; import SelectionMenu from "../SelectionMenuComponent"; +import { useHotkeys } from "react-hotkeys-hook"; +import { useShortcutsStore } from "../../../../stores/shortcuts"; const nodeTypes = { genericNode: GenericNode, @@ -140,125 +142,13 @@ export default function Page({ const setNode = useFlowStore((state) => state.setNode); useEffect(() => { - const onKeyDown = (event: KeyboardEvent) => { - const selectedNode = nodes.filter((obj) => obj.selected); - if ( - selectionMenuVisible && - (event.ctrlKey || event.metaKey) && - !event.shiftKey && - event.key === "g" - ) { - event.preventDefault(); - handleGroupNode(); - } - if ( - (event.ctrlKey || event.metaKey) && - event.key === "p" && - !event.shiftKey && - selectedNode.length > 0 - ) { - event.preventDefault(); - setNode(selectedNode[0].id, (old) => ({ - ...old, - data: { - ...old.data, - node: { - ...old.data.node, - frozen: old.data?.node?.frozen ? false : true, - }, - }, - })); - } - if ( - (event.ctrlKey || event.metaKey) && - !event.shiftKey && - event.key === "d" && - selectedNode.length > 0 - ) { - event.preventDefault(); - paste( - { nodes: selectedNode, edges: [] }, - { - x: position.current.x, - y: position.current.y, - } - ); - } - if (!isWrappedWithClass(event, "noundo")) { - if ( - ((event.key === "y" && !event.shiftKey) || (event.key === "z" && event.shiftKey)) && - (event.ctrlKey || event.metaKey) - ) { - event.preventDefault(); // prevent the default action - redo(); - } else if (event.key === "z" && (event.ctrlKey || event.metaKey) && !event.shiftKey) { - event.preventDefault(); - undo(); - } - } - if ( - !isWrappedWithClass(event, "nocopy") && - window.getSelection()?.toString().length === 0 - ) { - if ( - (event.ctrlKey || event.metaKey) && - !event.shiftKey && - event.key === "c" && - lastSelection - ) { - event.preventDefault(); - setLastCopiedSelection(_.cloneDeep(lastSelection)); - } else if ( - (event.ctrlKey || event.metaKey) && - !event.shiftKey && - event.key === "x" && - lastSelection - ) { - event.preventDefault(); - setLastCopiedSelection(_.cloneDeep(lastSelection), true); - } else if ( - (event.ctrlKey || event.metaKey) && - !event.shiftKey && - event.key === "v" && - lastCopiedSelection - ) { - event.preventDefault(); - takeSnapshot(); - paste(lastCopiedSelection, { - x: position.current.x, - y: position.current.y, - }); - } else if ( - (event.ctrlKey || event.metaKey) && - !event.shiftKey && - event.key === "g" && - lastSelection - ) { - event.preventDefault(); - } - } - if (!isWrappedWithClass(event, "nodelete")) { - if ( - (event.key === "Delete" || event.key === "Backspace") && - lastSelection - ) { - event.preventDefault(); - takeSnapshot(); - deleteNode(lastSelection.nodes.map((node) => node.id)); - deleteEdge(lastSelection.edges.map((edge) => edge.id)); - } - } - }; - const handleMouseMove = (event) => { position.current = { x: event.clientX, y: event.clientY }; }; - document.addEventListener("keydown", onKeyDown); document.addEventListener("mousemove", handleMouseMove); return () => { - document.removeEventListener("keydown", onKeyDown); document.removeEventListener("mousemove", handleMouseMove); }; }, [lastCopiedSelection, lastSelection, takeSnapshot, selectionMenuVisible]); @@ -279,6 +169,93 @@ export default function Page({ }; }, []); + + function handleUndo(e: KeyboardEvent) { + e.preventDefault() + if (!isWrappedWithClass(e, "noundo")) { + undo(); + } + } + + function handleRedo(e: KeyboardEvent) { + e.preventDefault() + if (!isWrappedWithClass(e, "noundo")) { + redo(); + } + } + + function handleGroup(e: KeyboardEvent) { + e.preventDefault() + if (selectionMenuVisible) { + handleGroupNode() + } + } + + function handleDuplicate(e: KeyboardEvent) { + const selectedNode = nodes.filter((obj) => obj.selected); + e.preventDefault() + if (selectedNode.length > 0) { + paste( + { nodes: selectedNode, edges: [] }, + { + x: position.current.x, + y: position.current.y, + } + ); + } + } + + function handleCopy(e: KeyboardEvent) { + e.preventDefault() + if (!isWrappedWithClass(e, "nocopy") && + window.getSelection()?.toString().length === 0 && lastSelection) { + setLastCopiedSelection(_.cloneDeep(lastSelection)); + } + } + + function handleCut(e: KeyboardEvent) { + e.preventDefault() + if (!isWrappedWithClass(e, "nocopy") && + window.getSelection()?.toString().length === 0 && lastSelection) { + setLastCopiedSelection(_.cloneDeep(lastSelection), true); + } + } + + function handlePaste(e: KeyboardEvent) { + e.preventDefault() + if (!isWrappedWithClass(e, "nocopy") && + window.getSelection()?.toString().length === 0 && lastCopiedSelection) { + takeSnapshot(); + paste(lastCopiedSelection, { + x: position.current.x, + y: position.current.y, + }); + } + } + + function handleDelete(e: KeyboardEvent) { + e.preventDefault() + if (!isWrappedWithClass(event, "nodelete") && lastSelection) { + takeSnapshot(); + deleteNode(lastSelection.nodes.map((node) => node.id)); + deleteEdge(lastSelection.edges.map((edge) => edge.id)); + } + } + + const undoAction = useShortcutsStore(state => state.undo); + const redoAction = useShortcutsStore(state => state.redo); + const copyAction = useShortcutsStore(state => state.copy); + + useHotkeys(undoAction, handleUndo); + useHotkeys(redoAction, handleRedo); + useHotkeys("mod+g", handleGroup); + useHotkeys("mod+d", handleDuplicate); + useHotkeys(copyAction, handleCopy); + useHotkeys("mod+x", handleCut); + useHotkeys("mod+v", handlePaste); + useHotkeys("backspace", handleDelete); + useHotkeys("delete", handleDelete); + useEffect(() => { setSHowCanvas( Object.keys(templates).length > 0 && Object.keys(types).length > 0 diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx index 2140629355..64e9914fa9 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx @@ -32,20 +32,20 @@ export default function EditShortcutButton({ children, shortcut, defaultShortcut const [key, setKey] = useState(isMac ? "Meta" : 'Ctrl'); - const availableFields = Array.from(componentFields).filter( - (field) => !unavaliableFields.has(field) - ); - const addGlobalVariable = useGlobalVariablesStore( - (state) => state.addGlobalVariable - ); - function canEditCombination(newCombination: string): boolean { - return !unavaliableShortcuts.includes(newCombination); - } + let canSave = true; + unavaliableShortcuts.forEach((s) => { + if (s.toLowerCase() === newCombination.toLowerCase()) { + canSave = false + } + }) + return canSave; + } const setUniqueShortcut = useShortcutsStore(state => state.updateUniqueShortcut); function editCombination(): void { + console.log(canEditCombination(key)) if (canEditCombination(key)) { const newCombination = defaultShortcuts.map((s) => { if (s.name === shortcut[0]) { @@ -54,33 +54,31 @@ export default function EditShortcutButton({ children, shortcut, defaultShortcut return {name: s.name, shortcut: s.shortcut}; }) const unavailable = unavaliableShortcuts.map((s) => { - if (s === defaultCombination) return s = key; + if (s.toLowerCase() === defaultCombination.toLowerCase()) return s = key.toUpperCase(); return s; }) const fixCombination = key.split(" ") fixCombination[0] = "mod" const shortcutName = shortcut[0].split(" ")[0].toLowerCase(); - console.log(shortcutName) setUniqueShortcut(shortcutName, fixCombination.join("").toLowerCase()) setShortcuts(newCombination, unavailable) setOpen(false) setSuccessData({title: `${shortcut[0]} shortcut successfully changed`}) - setKey(isMac ? "Meta" : 'Ctrl') + setKey(isMac ? "META" : 'CTRL') return; } setErrorData({title: "Error saving key combination", list: ["This combination already exists!"]}) } useEffect(() => { - if (!open) setKey(isMac ? "Meta" : 'Ctrl') + if (!open) setKey(isMac ? "META" : 'CTRL') }, [open, setOpen]) useEffect(() => { function onKeyDown(e: KeyboardEvent) { e.preventDefault() - console.log(e.key) - if (key.includes(e.key)) return; - setKey(oldKey => `${oldKey} + ${e.key}`) + if (key.toUpperCase().includes(e.key.toUpperCase())) return; + setKey(oldKey => `${oldKey.toUpperCase()} + ${e.key.toUpperCase()}`) } document.addEventListener("keydown", onKeyDown); @@ -107,8 +105,8 @@ export default function EditShortcutButton({ children, shortcut, defaultShortcut {children}
-
- {key} +
+ {key.toUpperCase()}
diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx index e30ce10212..106a3e779c 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx @@ -14,19 +14,6 @@ import EditShortcutButton from "./EditShortcutButton"; import { useShortcutsStore } from "../../../../stores/shortcuts"; export default function ShortcutsPage() { - const advancedShortcut = "Ctrl + Shift + A"; - const minizmizeShortcut = "Ctrl + Shift + Q"; - const codeShortcut = "Ctrl + Shift + C"; - const copyShortcut = "Ctrl + C"; - const duplicateShortcut = "Ctrl + D"; - const shareShortcut = "Ctrl + Shift + S"; - const docsShortcut = "Ctrl + Shift + D"; - const saveShortcut = "Ctrl + S"; - const deleteShortcut = "Backspace"; - const interactionShortcut = "Ctrl + K"; - const undoShortcut = "Ctrl + Z"; - const redoShortcut = "Ctrl + Y"; - const [selectedRows, setSelectedRows] = useState([]); const shortcuts = useShortcutsStore(state => state.shortcuts) @@ -48,56 +35,7 @@ export default function ShortcutsPage() { }, ]); - const [nodesRowData, setNodesRowData] = useState([ - { - name: "Advanced Settings Component", - shortcut: advancedShortcut, - }, - { - name: "Minimize Component", - shortcut: minizmizeShortcut, - }, - { - name: "Code Component", - shortcut: codeShortcut, - }, - { - name: "Copy Component", - shortcut: copyShortcut, - }, - { - name: "Duplicate Component", - shortcut: duplicateShortcut, - }, - { - name: "Share Component", - shortcut: shareShortcut, - }, - { - name: "Docs Component", - shortcut: docsShortcut, - }, - { - name: "Save Component", - shortcut: saveShortcut, - }, - { - name: "Delete Component", - shortcut: deleteShortcut, - }, - { - name: "Open Playground", - shortcut: interactionShortcut, - }, - { - name: "Undo", - shortcut: undoShortcut, - }, - { - name: "Redo", - shortcut: redoShortcut, - }, - ]); + const [nodesRowData, setNodesRowData] = useState>([]); useEffect(() => { setNodesRowData(shortcuts) @@ -107,6 +45,8 @@ export default function ShortcutsPage() { const [open, setOpen] = useState(false); return ( + +
@@ -125,7 +65,7 @@ export default function ShortcutsPage() {
- +
- - - Flow - Shortcuts relating to the flow. - - - { - setSelectedRows(event.api.getSelectedRows().map((row) => row.name)); - }} - suppressRowClickSelection={true} - domLayout="autoHeight" - pagination={false} - columnDefs={colDefs} - rowData={nodesRowData} - /> - -
); diff --git a/src/frontend/src/stores/shortcuts.ts b/src/frontend/src/stores/shortcuts.ts index 66a21c1068..18a3f1f181 100644 --- a/src/frontend/src/stores/shortcuts.ts +++ b/src/frontend/src/stores/shortcuts.ts @@ -8,6 +8,9 @@ export const useShortcutsStore = create((set, get) => ({ setShortcuts: (newShortcuts, unavailable) => { set({shortcuts: newShortcuts, unavailableShortcuts: unavailable} ); }, + undo: "mod+z", + redo: "mod+y", + open: "mod+k", advanced: "mod+shift+a", minimize: "mod+shift+q", code: "mod+shift+u", diff --git a/src/frontend/src/types/store/index.ts b/src/frontend/src/types/store/index.ts index fa193c5012..c009e14bc5 100644 --- a/src/frontend/src/types/store/index.ts +++ b/src/frontend/src/types/store/index.ts @@ -21,6 +21,9 @@ export type StoreComponentResponse = { export type shortcutsStoreType = { updateUniqueShortcut: (name: string, combination: string) => void; + open: string; + undo: string; + redo: string; advanced: string; minimize: string; code: string; From 76f3b824128af70409d07446c3de057e367d5a70 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Wed, 1 May 2024 01:38:28 -0300 Subject: [PATCH 17/60] Feat: User can customize all shortcuts --- .../src/components/chatComponent/index.tsx | 8 ++++++-- src/frontend/src/constants/constants.ts | 20 +++++++++++++++++-- .../components/PageComponent/index.tsx | 17 ++++++++++------ src/frontend/src/stores/shortcuts.ts | 4 ++++ src/frontend/src/types/store/index.ts | 4 ++++ 5 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 0eff32c8d8..5bec5b1fd5 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -10,6 +10,7 @@ import { classNames } from "../../utils/utils"; import ForwardedIconComponent from "../genericIconComponent"; import { Separator } from "../ui/separator"; import { useHotkeys } from "react-hotkeys-hook"; +import { useShortcutsStore } from "../../stores/shortcuts"; export default function FlowToolbar(): JSX.Element { function handleAPIWShortcut(e: KeyboardEvent) { @@ -24,8 +25,11 @@ export default function FlowToolbar(): JSX.Element { } } - useHotkeys("mod+k", handleChatWShortcut); - useHotkeys("mod+r", handleAPIWShortcut); + const openPlayground = useShortcutsStore(state => state.open); + const api = useShortcutsStore(state => state.api); + + useHotkeys(openPlayground, handleChatWShortcut); + useHotkeys(api, handleAPIWShortcut); const [open, setOpen] = useState(false); const [openCodeModal, setOpenCodeModal] = useState(false); diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index 8e0d70f246..992f5f8978 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -832,7 +832,23 @@ export const defaultShortcuts = [ { name: "Redo", shortcut: "Ctrl + y" - } + }, + { + name: "Group", + shortcut: "Ctrl + g" + }, + { + name: "Cut", + shortcut: "Ctrl + x" + }, + { + name: "Paste", + shortcut: "Ctrl + v" + }, + { + name: "API", + shortcut: "Ctrl + r" + }, ]; -export const unavailableShortcutss = ["CTRL + SHIFT + A", "CTRL + Q", "CTRL + SHIFT + U", "CTRL + C", "CTRL + D", "CTRL + SHIFT + S", "CTRL + SHIFT + D", "CTRL + S", "BACKSPACE", "CTRL + K", "CTRL + Z", "CTRL + Y"]; +export const unavailableShortcutss = ["CTRL + R","CTRL + V", "CTRL + X", "CTRL + G", "CTRL + SHIFT + A", "CTRL + Q", "CTRL + SHIFT + U", "CTRL + C", "CTRL + D", "CTRL + SHIFT + S", "CTRL + SHIFT + D", "CTRL + S", "BACKSPACE", "CTRL + K", "CTRL + Z", "CTRL + Y"]; diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index 8b10d577b9..c5eb8bca96 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -235,7 +235,7 @@ export default function Page({ function handleDelete(e: KeyboardEvent) { e.preventDefault() - if (!isWrappedWithClass(event, "nodelete") && lastSelection) { + if (!isWrappedWithClass(e, "nodelete") && lastSelection) { takeSnapshot(); deleteNode(lastSelection.nodes.map((node) => node.id)); deleteEdge(lastSelection.edges.map((edge) => edge.id)); @@ -245,15 +245,20 @@ export default function Page({ const undoAction = useShortcutsStore(state => state.undo); const redoAction = useShortcutsStore(state => state.redo); const copyAction = useShortcutsStore(state => state.copy); + const duplicate = useShortcutsStore(state => state.duplicate); + const deleteAction = useShortcutsStore(state => state.delete); + const groupAction = useShortcutsStore(state => state.group); + const cutAction = useShortcutsStore(state => state.cut); + const pasteAction = useShortcutsStore(state => state.paste); useHotkeys(undoAction, handleUndo); useHotkeys(redoAction, handleRedo); - useHotkeys("mod+g", handleGroup); - useHotkeys("mod+d", handleDuplicate); + useHotkeys(groupAction, handleGroup); + useHotkeys(duplicate, handleDuplicate); useHotkeys(copyAction, handleCopy); - useHotkeys("mod+x", handleCut); - useHotkeys("mod+v", handlePaste); - useHotkeys("backspace", handleDelete); + useHotkeys(cutAction, handleCut); + useHotkeys(pasteAction, handlePaste); + useHotkeys(deleteAction, handleDelete); useHotkeys("delete", handleDelete); useEffect(() => { diff --git a/src/frontend/src/stores/shortcuts.ts b/src/frontend/src/stores/shortcuts.ts index 18a3f1f181..f2389359d7 100644 --- a/src/frontend/src/stores/shortcuts.ts +++ b/src/frontend/src/stores/shortcuts.ts @@ -20,6 +20,10 @@ export const useShortcutsStore = create((set, get) => ({ docs: "mod+shift+d", save: "mod+s", delete: "backspace", + group: "mod+g", + cut: "mod+x", + paste: "mod+v", + api: "mod+r", updateUniqueShortcut: (name, combination) => { set({ [name]: combination diff --git a/src/frontend/src/types/store/index.ts b/src/frontend/src/types/store/index.ts index c009e14bc5..676d927b7a 100644 --- a/src/frontend/src/types/store/index.ts +++ b/src/frontend/src/types/store/index.ts @@ -21,6 +21,10 @@ export type StoreComponentResponse = { export type shortcutsStoreType = { updateUniqueShortcut: (name: string, combination: string) => void; + group: string; + cut: string; + paste: string; + api: string; open: string; undo: string; redo: string; From 5bd9aba92278d8aa7655acdaf5731621247b07f8 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Thu, 2 May 2024 18:15:34 -0300 Subject: [PATCH 18/60] Feat: Save user config in localStorage --- .../EditShortcutButton/index.tsx | 54 +++++++++---------- .../pages/ShortcutsPage/index.tsx | 16 ++++-- 2 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx index 64e9914fa9..0e0df2a66e 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx @@ -1,36 +1,32 @@ - - -//TODO IMPLEMENT FORM LOGIC - import { useEffect, useState } from "react"; import useAlertStore from "../../../../../stores/alertStore"; -import { useTypesStore } from "../../../../../stores/typesStore"; -import { useGlobalVariablesStore } from "../../../../../stores/globalVariables"; -import { registerGlobalVariable } from "../../../../../controllers/API"; -import { ResponseErrorDetailAPI } from "../../../../../types/api"; + import BaseModal from "../../../../../modals/baseModal"; -import { Label } from "@radix-ui/react-select"; -import { Input } from "../../../../../components/ui/input"; -import InputComponent from "../../../../../components/inputComponent"; -import { Textarea } from "../../../../../components/ui/textarea"; import { Button } from "../../../../../components/ui/button"; import ForwardedIconComponent from "../../../../../components/genericIconComponent"; -import { defaultShortcuts } from "../../../../../constants/constants"; import { useShortcutsStore } from "../../../../../stores/shortcuts"; -export default function EditShortcutButton({ children, shortcut, defaultShortcuts, defaultCombination, open, setOpen, }: {children: JSX.Element; shortcut: string[]; defaultShortcuts: Array<{name: string; shortcut: string;}>; defaultCombination: string; open: boolean; setOpen: (bool: boolean) => void;}): JSX.Element { +export default function EditShortcutButton({ + children, + shortcut, + defaultShortcuts, + defaultCombination, + open, + setOpen +}: { + children: JSX.Element; + shortcut: string[]; + defaultShortcuts: Array<{name: string; shortcut: string;}>; + defaultCombination: string; + open: boolean; + setOpen: (bool: boolean) => void; +}): JSX.Element { + const isMac = navigator.userAgent.toUpperCase().includes("MAC"); + const [key, setKey] = useState(isMac ? "Meta" : 'Ctrl'); const setSuccessData = useAlertStore(state => state.setSuccessData) const setShortcuts = useShortcutsStore(state => state.setShortcuts); const unavaliableShortcuts = useShortcutsStore(state => state.unavailableShortcuts); - const isMac = navigator.userAgent.toUpperCase().includes("MAC"); - const [fields, setFields] = useState([]); const setErrorData = useAlertStore((state) => state.setErrorData); - const componentFields = useTypesStore((state) => state.ComponentFields); - const unavaliableFields =new Set(Object.keys(useGlobalVariablesStore( - (state) => state.unavaliableFields - ))); - - const [key, setKey] = useState(isMac ? "Meta" : 'Ctrl'); function canEditCombination(newCombination: string): boolean { let canSave = true; @@ -64,7 +60,9 @@ export default function EditShortcutButton({ children, shortcut, defaultShortcut setShortcuts(newCombination, unavailable) setOpen(false) setSuccessData({title: `${shortcut[0]} shortcut successfully changed`}) - setKey(isMac ? "META" : 'CTRL') + setKey(isMac ? "META" : 'CTRL'); + localStorage.setItem("langflow-shortcuts", JSON.stringify(newCombination)); + localStorage.setItem("langflow-UShortcuts", JSON.stringify(unavailable)); return; } setErrorData({title: "Error saving key combination", list: ["This combination already exists!"]}) @@ -72,7 +70,8 @@ export default function EditShortcutButton({ children, shortcut, defaultShortcut useEffect(() => { if (!open) setKey(isMac ? "META" : 'CTRL') - }, [open, setOpen]) + console.log(key) + }, [open, setOpen, key]) useEffect(() => { function onKeyDown(e: KeyboardEvent) { @@ -89,7 +88,7 @@ export default function EditShortcutButton({ children, shortcut, defaultShortcut }, [key, setKey]) return ( - + {children}
-
+
{key.toUpperCase()}
- + + ); diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx index 106a3e779c..5bea21d18e 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx @@ -15,7 +15,8 @@ import { useShortcutsStore } from "../../../../stores/shortcuts"; export default function ShortcutsPage() { const [selectedRows, setSelectedRows] = useState([]); - const shortcuts = useShortcutsStore(state => state.shortcuts) + const shortcuts = useShortcutsStore(state => state.shortcuts); + const setShortcuts = useShortcutsStore(state => state.setShortcuts); // Column Definitions: Defines the columns to be displayed. const [colDefs, setColDefs] = useState<(ColDef | ColGroupDef)[]>([ @@ -44,10 +45,17 @@ export default function ShortcutsPage() { const combinationToEdit = shortcuts.filter((s) => s.name === selectedRows[0]) const [open, setOpen] = useState(false); - return ( - + const unavaliableShortcuts = useShortcutsStore(state => state.unavailableShortcuts); + useEffect(() => { + if (localStorage.getItem("langflow-shortcuts")) { + const savedShortcuts = localStorage.getItem("langflow-shortcuts"); + const savedUShortcuts = localStorage.getItem("langflow-UShortcuts"); + setShortcuts(JSON.parse(savedShortcuts!), JSON.parse(savedUShortcuts!)); + } + }, []) -
+ return ( +

From 61b894c2e8faf799b59497e9b34a3eaa79409255 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Thu, 2 May 2024 20:53:39 -0300 Subject: [PATCH 19/60] Feat: Add restore button to shortcuts settings --- .../EditShortcutButton/index.tsx | 8 ++- .../pages/ShortcutsPage/index.tsx | 72 +++++++++++-------- src/frontend/src/utils/styleUtils.ts | 2 + 3 files changed, 49 insertions(+), 33 deletions(-) diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx index 0e0df2a66e..44e18ab7f1 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx @@ -12,7 +12,8 @@ export default function EditShortcutButton({ defaultShortcuts, defaultCombination, open, - setOpen + setOpen, + disable, }: { children: JSX.Element; shortcut: string[]; @@ -20,6 +21,7 @@ export default function EditShortcutButton({ defaultCombination: string; open: boolean; setOpen: (bool: boolean) => void; + disable?: boolean; }): JSX.Element { const isMac = navigator.userAgent.toUpperCase().includes("MAC"); const [key, setKey] = useState(isMac ? "Meta" : 'Ctrl'); @@ -88,10 +90,10 @@ export default function EditShortcutButton({ }, [key, setKey]) return ( - + Key Combination diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx index 5bea21d18e..77e2936721 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx @@ -12,6 +12,7 @@ import { import { Button } from "../../../../components/ui/button"; import EditShortcutButton from "./EditShortcutButton"; import { useShortcutsStore } from "../../../../stores/shortcuts"; +import { defaultShortcuts, unavailableShortcutss } from "../../../../constants/constants"; export default function ShortcutsPage() { const [selectedRows, setSelectedRows] = useState([]); @@ -54,6 +55,12 @@ export default function ShortcutsPage() { } }, []) + function handleRestore() { + setShortcuts(defaultShortcuts, unavailableShortcutss); + localStorage.removeItem("langflow-shortcuts"); + localStorage.removeItem("langflow-UShortcuts"); + } + return (
@@ -70,38 +77,43 @@ export default function ShortcutsPage() { frequently used actions.

+
+
+
+ + + + +
+
+
- - -
-
- - - -
-
- { - setSelectedRows(event.api.getSelectedRows().map((row) => row.name)); - }} - suppressRowClickSelection={true} - domLayout="autoHeight" - pagination={false} - columnDefs={colDefs} - rowData={nodesRowData} - /> -
-
+
+ { + setSelectedRows(event.api.getSelectedRows().map((row) => row.name)); + }} + suppressRowClickSelection={true} + domLayout="autoHeight" + pagination={false} + columnDefs={colDefs} + rowData={nodesRowData} + /> +

); diff --git a/src/frontend/src/utils/styleUtils.ts b/src/frontend/src/utils/styleUtils.ts index 25e5ec4fb2..8437c802b7 100644 --- a/src/frontend/src/utils/styleUtils.ts +++ b/src/frontend/src/utils/styleUtils.ts @@ -140,6 +140,7 @@ import { X, XCircle, Zap, + RotateCcw, } from "lucide-react"; import { FaApple, FaGithub } from "react-icons/fa"; import { AWSIcon } from "../icons/AWS"; @@ -514,4 +515,5 @@ export const nodeIconsLucide: iconsType = { Command, ArrowBigUp, Dot, + RotateCcw }; From 8967a2694ee9d413938ea6f6d1f3f6db8d495fb6 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Thu, 2 May 2024 20:54:25 -0300 Subject: [PATCH 20/60] Format code --- .../base/langflow/base/memory/memory.py | 2 - .../interface/initialize/vector_store.py | 1 - src/backend/base/langflow/schema/schema.py | 1 - .../src/components/ImageViewer/index.tsx | 277 ++++++++++-------- .../addNewVariableButton.tsx | 6 +- .../src/components/chatComponent/index.tsx | 18 +- .../helpers/convert-data-function.ts | 1 - .../components/inputGlobalComponent/index.tsx | 5 +- .../src/components/pdfViewer/Error/index.tsx | 34 +-- src/frontend/src/constants/constants.ts | 51 ++-- src/frontend/src/modals/ApiModal/index.tsx | 6 +- .../src/modals/EditNodeModal/index.tsx | 6 +- src/frontend/src/modals/shareModal/index.tsx | 50 ++-- .../components/PageComponent/index.tsx | 83 +++--- .../components/nodeToolbarComponent/index.tsx | 14 +- .../EditShortcutButton/index.tsx | 99 ++++--- .../pages/ShortcutsPage/index.tsx | 51 ++-- src/frontend/src/stores/shortcuts.ts | 13 +- src/frontend/src/types/components/index.ts | 2 +- src/frontend/src/types/store/index.ts | 11 +- .../types/zustand/globalVariables/index.ts | 4 +- src/frontend/src/utils/styleUtils.ts | 4 +- src/frontend/src/utils/utils.ts | 4 +- 23 files changed, 410 insertions(+), 333 deletions(-) diff --git a/src/backend/base/langflow/base/memory/memory.py b/src/backend/base/langflow/base/memory/memory.py index 8367525092..1bb2e22fff 100644 --- a/src/backend/base/langflow/base/memory/memory.py +++ b/src/backend/base/langflow/base/memory/memory.py @@ -1,7 +1,5 @@ from typing import Optional -from langflow.field_typing import Text -from langflow.helpers.record import records_to_text from langflow.interface.custom.custom_component import CustomComponent from langflow.schema.schema import Record diff --git a/src/backend/base/langflow/interface/initialize/vector_store.py b/src/backend/base/langflow/interface/initialize/vector_store.py index 619baa3f03..8e596298c7 100644 --- a/src/backend/base/langflow/interface/initialize/vector_store.py +++ b/src/backend/base/langflow/interface/initialize/vector_store.py @@ -5,7 +5,6 @@ from langchain_community.vectorstores import ( FAISS, Chroma, - ElasticsearchStore, MongoDBAtlasVectorSearch, Pinecone, Qdrant, diff --git a/src/backend/base/langflow/schema/schema.py b/src/backend/base/langflow/schema/schema.py index 29ab15ede1..1474c24eed 100644 --- a/src/backend/base/langflow/schema/schema.py +++ b/src/backend/base/langflow/schema/schema.py @@ -4,7 +4,6 @@ from langchain_core.documents import Document from langchain_core.messages import AIMessage, BaseMessage, HumanMessage from pydantic import BaseModel, model_validator -from langchain_core.messages import HumanMessage, AIMessage class Record(BaseModel): diff --git a/src/frontend/src/components/ImageViewer/index.tsx b/src/frontend/src/components/ImageViewer/index.tsx index 6adda4e3ea..dc7f41ad7e 100644 --- a/src/frontend/src/components/ImageViewer/index.tsx +++ b/src/frontend/src/components/ImageViewer/index.tsx @@ -1,141 +1,162 @@ +import { saveAs } from "file-saver"; +import OpenSeadragon from "openseadragon"; import { useEffect, useRef, useState } from "react"; +import { IMGViewErrorMSG, IMGViewErrorTitle } from "../../constants/constants"; +import useAlertStore from "../../stores/alertStore"; import ForwardedIconComponent from "../genericIconComponent"; -import useFlowStore from "../../stores/flowStore"; -import OpenSeadragon from 'openseadragon'; import { Separator } from "../ui/separator"; -import { saveAs } from 'file-saver' -import useAlertStore from "../../stores/alertStore"; -import { IMGViewErrorMSG, IMGViewErrorTitle } from "../../constants/constants"; -export default function ImageViewer({image }) { +export default function ImageViewer({ image }) { const viewerRef = useRef(null); - const [errorDownloading, setErrordownloading] = useState(false) - const setErrorList = useAlertStore(state => state.setErrorData); + const [errorDownloading, setErrordownloading] = useState(false); + const setErrorList = useAlertStore((state) => state.setErrorData); const [initialMsg, setInicialMsg] = useState("Please build your flow"); + useEffect(() => { + try { + if (viewerRef.current) { + // Initialize OpenSeadragon viewer + const viewer = OpenSeadragon({ + element: viewerRef.current, + prefixUrl: + "https://cdnjs.cloudflare.com/ajax/libs/openseadragon/2.4.2/images/", // Optional: Set the path to OpenSeadragon images + tileSources: { type: "image", url: image }, + defaultZoomLevel: 1, + maxZoomPixelRatio: 4, + showNavigationControl: false, + }); + const zoomInButton = document.getElementById("zoom-in-button"); + const zoomOutButton = document.getElementById("zoom-out-button"); + const homeButton = document.getElementById("home-button"); + const fullPageButton = document.getElementById("full-page-button"); + + zoomInButton!.addEventListener("click", () => + viewer.viewport.zoomBy(1.2) + ); + zoomOutButton!.addEventListener("click", () => + viewer.viewport.zoomBy(0.8) + ); + homeButton!.addEventListener("click", () => viewer.viewport.goHome()); + fullPageButton!.addEventListener("click", () => + viewer.setFullScreen(true) + ); - useEffect(() => { - try { - if (viewerRef.current) { - // Initialize OpenSeadragon viewer - const viewer = OpenSeadragon({ - element: viewerRef.current, - prefixUrl: 'https://cdnjs.cloudflare.com/ajax/libs/openseadragon/2.4.2/images/', // Optional: Set the path to OpenSeadragon images - tileSources: {type: 'image', url: image}, - defaultZoomLevel: 1, - maxZoomPixelRatio: 4, - showNavigationControl: false, - }); - const zoomInButton = document.getElementById('zoom-in-button'); - const zoomOutButton = document.getElementById('zoom-out-button'); - const homeButton = document.getElementById('home-button'); - const fullPageButton = document.getElementById('full-page-button'); - - zoomInButton!.addEventListener('click', () => viewer.viewport.zoomBy(1.2)); - zoomOutButton!.addEventListener('click', () => viewer.viewport.zoomBy(0.8)); - homeButton!.addEventListener('click', () => viewer.viewport.goHome()); - fullPageButton!.addEventListener('click', () => viewer.setFullScreen(true)); - - // Optionally, you can set additional viewer options here - - // Cleanup function - return () => { - viewer.destroy(); - zoomInButton!.removeEventListener('click', () => viewer.viewport.zoomBy(1.2)); - zoomOutButton!.removeEventListener('click', () => viewer.viewport.zoomBy(0.8)); - homeButton!.removeEventListener('click', () => viewer.viewport.goHome()); - fullPageButton!.removeEventListener('click', () => viewer.setFullScreen(true)); - }; - } - } catch (error) { - console.error('Error initializing OpenSeadragon:', error); - } - }, [image]); + // Optionally, you can set additional viewer options here - function download() { - const imageUrl = image; - // Fetch the image data - fetch(imageUrl) - .then(response => response.blob()) - .then(blob => { - // Save the image using FileSaver.js - saveAs(blob, 'image.jpg'); - }) - .catch(error => { - setErrorList({title: "There was an error downloading your image"}) - console.error('Error downloading image:', error) - }); + // Cleanup function + return () => { + viewer.destroy(); + zoomInButton!.removeEventListener("click", () => + viewer.viewport.zoomBy(1.2) + ); + zoomOutButton!.removeEventListener("click", () => + viewer.viewport.zoomBy(0.8) + ); + homeButton!.removeEventListener("click", () => + viewer.viewport.goHome() + ); + fullPageButton!.removeEventListener("click", () => + viewer.setFullScreen(true) + ); + }; } + } catch (error) { + console.error("Error initializing OpenSeadragon:", error); + } + }, [image]); - return ( - image === "" ? ( -
-
- - {IMGViewErrorTitle} -
-
-
-
- {IMGViewErrorMSG} -
-
-
+ function download() { + const imageUrl = image; + // Fetch the image data + fetch(imageUrl) + .then((response) => response.blob()) + .then((blob) => { + // Save the image using FileSaver.js + saveAs(blob, "image.jpg"); + }) + .catch((error) => { + setErrorList({ title: "There was an error downloading your image" }); + console.error("Error downloading image:", error); + }); + } + + return image === "" ? ( +
+
+ + {IMGViewErrorTitle} +
+
+
+
{IMGViewErrorMSG}
+
+
+
+ ) : ( + <> +
+
+ +
+ +
+ +
+
- ) : ( - <> -
-
- -
- -
- -
- -
- -
- -
- -
- -
- - - -
+ +
+
-
- - ) - ); -} \ No newline at end of file + +
+ +
+ + +
+
+
+ + ); +} diff --git a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx index e5e8dd4882..2e738cd6bd 100644 --- a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx +++ b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx @@ -22,9 +22,9 @@ export default function AddNewVariableButton({ children }): JSX.Element { const [open, setOpen] = useState(false); const setErrorData = useAlertStore((state) => state.setErrorData); const componentFields = useTypesStore((state) => state.ComponentFields); - const unavaliableFields =new Set(Object.keys(useGlobalVariablesStore( - (state) => state.unavaliableFields - ))); + const unavaliableFields = new Set( + Object.keys(useGlobalVariablesStore((state) => state.unavaliableFields)) + ); const availableFields = Array.from(componentFields).filter( (field) => !unavaliableFields.has(field) diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 5bec5b1fd5..bd92220d44 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -1,21 +1,21 @@ import { Transition } from "@headlessui/react"; -import { useEffect, useMemo, useRef, useState } from "react"; +import { useMemo, useRef, useState } from "react"; +import { useHotkeys } from "react-hotkeys-hook"; import ApiModal from "../../modals/ApiModal"; import IOModal from "../../modals/IOModal"; import ShareModal from "../../modals/shareModal"; import useFlowStore from "../../stores/flowStore"; import useFlowsManagerStore from "../../stores/flowsManagerStore"; +import { useShortcutsStore } from "../../stores/shortcuts"; import { useStoreStore } from "../../stores/storeStore"; import { classNames } from "../../utils/utils"; import ForwardedIconComponent from "../genericIconComponent"; import { Separator } from "../ui/separator"; -import { useHotkeys } from "react-hotkeys-hook"; -import { useShortcutsStore } from "../../stores/shortcuts"; export default function FlowToolbar(): JSX.Element { function handleAPIWShortcut(e: KeyboardEvent) { e.preventDefault(); - setOpenCodeModal((oldOpen) => !oldOpen) + setOpenCodeModal((oldOpen) => !oldOpen); } function handleChatWShortcut(e: KeyboardEvent) { @@ -25,8 +25,8 @@ export default function FlowToolbar(): JSX.Element { } } - const openPlayground = useShortcutsStore(state => state.open); - const api = useShortcutsStore(state => state.api); + const openPlayground = useShortcutsStore((state) => state.open); + const api = useShortcutsStore((state) => state.api); useHotkeys(openPlayground, handleChatWShortcut); useHotkeys(api, handleAPIWShortcut); @@ -121,7 +121,11 @@ export default function FlowToolbar(): JSX.Element {
{currentFlow && currentFlow.data && ( - +
{ const lines = csvFile.data.trim().split("\n"); const headers = lines[0].trim().split(csvSeparator); - const initialRowData: any = []; const initialColDefs = headers.map((header) => ({ diff --git a/src/frontend/src/components/inputGlobalComponent/index.tsx b/src/frontend/src/components/inputGlobalComponent/index.tsx index f3b5b3b29c..1b0d2d8043 100644 --- a/src/frontend/src/components/inputGlobalComponent/index.tsx +++ b/src/frontend/src/components/inputGlobalComponent/index.tsx @@ -49,7 +49,10 @@ export default function InputGlobalComponent({ !data.node?.template[name].value && data.node?.template[name].display_name ) { - if (unavaliableFields[data.node?.template[name].display_name!] && !disabled) { + if ( + unavaliableFields[data.node?.template[name].display_name!] && + !disabled + ) { setTimeout(() => { setDb(true); onChange(unavaliableFields[data.node?.template[name].display_name!]); diff --git a/src/frontend/src/components/pdfViewer/Error/index.tsx b/src/frontend/src/components/pdfViewer/Error/index.tsx index 76c35bcd00..c0a6216646 100644 --- a/src/frontend/src/components/pdfViewer/Error/index.tsx +++ b/src/frontend/src/components/pdfViewer/Error/index.tsx @@ -1,23 +1,19 @@ -import { CHAT_FIRST_INITIAL_TEXT, CHAT_SECOND_INITIAL_TEXT, PDFCheckFlow, PDFLoadErrorTitle } from "../../../constants/constants"; +import { PDFCheckFlow, PDFLoadErrorTitle } from "../../../constants/constants"; import IconComponent from "../../genericIconComponent"; - export default function Error(): JSX.Element { - return ( -
-
- - - {PDFLoadErrorTitle} - -
-
- - {PDFCheckFlow}{" "} - -
-
- + return ( +
+
+ + + {PDFLoadErrorTitle} + +
+
+ {PDFCheckFlow}
- ); -} \ No newline at end of file +
+
+ ); +} diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index 992f5f8978..a2ab5a43eb 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -787,68 +787,85 @@ export const SAVE_DEBOUNCE_TIME = 300; export const defaultShortcuts = [ { name: "Advanced Settings", - shortcut: "Ctrl + Shift + a" + shortcut: "Ctrl + Shift + a", }, { name: "Minimize", - shortcut: "Ctrl + q" + shortcut: "Ctrl + q", }, { name: "Code", - shortcut: "Ctrl + Shift + u" + shortcut: "Ctrl + Shift + u", }, { name: "Copy", - shortcut: "Ctrl + c" + shortcut: "Ctrl + c", }, { name: "Duplicate", - shortcut: "Ctrl + d" + shortcut: "Ctrl + d", }, { name: "Share", - shortcut: "Ctrl + Shift + s" + shortcut: "Ctrl + Shift + s", }, { name: "Docs", - shortcut: "Ctrl + Shift + d" + shortcut: "Ctrl + Shift + d", }, { name: "Save", - shortcut: "Ctrl + s" + shortcut: "Ctrl + s", }, { name: "Delete", - shortcut: "Backspace" + shortcut: "Backspace", }, { name: "Open playground", - shortcut: "Ctrl + k" + shortcut: "Ctrl + k", }, { name: "Undo", - shortcut: "Ctrl + z" + shortcut: "Ctrl + z", }, { name: "Redo", - shortcut: "Ctrl + y" + shortcut: "Ctrl + y", }, { name: "Group", - shortcut: "Ctrl + g" + shortcut: "Ctrl + g", }, { name: "Cut", - shortcut: "Ctrl + x" + shortcut: "Ctrl + x", }, { name: "Paste", - shortcut: "Ctrl + v" + shortcut: "Ctrl + v", }, { name: "API", - shortcut: "Ctrl + r" + shortcut: "Ctrl + r", }, ]; -export const unavailableShortcutss = ["CTRL + R","CTRL + V", "CTRL + X", "CTRL + G", "CTRL + SHIFT + A", "CTRL + Q", "CTRL + SHIFT + U", "CTRL + C", "CTRL + D", "CTRL + SHIFT + S", "CTRL + SHIFT + D", "CTRL + S", "BACKSPACE", "CTRL + K", "CTRL + Z", "CTRL + Y"]; +export const unavailableShortcutss = [ + "CTRL + R", + "CTRL + V", + "CTRL + X", + "CTRL + G", + "CTRL + SHIFT + A", + "CTRL + Q", + "CTRL + SHIFT + U", + "CTRL + C", + "CTRL + D", + "CTRL + SHIFT + S", + "CTRL + SHIFT + D", + "CTRL + S", + "BACKSPACE", + "CTRL + K", + "CTRL + Z", + "CTRL + Y", +]; diff --git a/src/frontend/src/modals/ApiModal/index.tsx b/src/frontend/src/modals/ApiModal/index.tsx index c80e5ce52a..874e93f5b5 100644 --- a/src/frontend/src/modals/ApiModal/index.tsx +++ b/src/frontend/src/modals/ApiModal/index.tsx @@ -49,9 +49,9 @@ const ApiModal = forwardRef( ) => { const { autoLogin } = useContext(AuthContext); const [open, setOpen] = - mySetOpen !== undefined && myOpen !== undefined - ? [myOpen, mySetOpen] - : useState(false); + mySetOpen !== undefined && myOpen !== undefined + ? [myOpen, mySetOpen] + : useState(false); const [activeTab, setActiveTab] = useState("0"); const tweak = useRef([]); const tweaksList = useRef([]); diff --git a/src/frontend/src/modals/EditNodeModal/index.tsx b/src/frontend/src/modals/EditNodeModal/index.tsx index 1e90cacce9..cda819c86b 100644 --- a/src/frontend/src/modals/EditNodeModal/index.tsx +++ b/src/frontend/src/modals/EditNodeModal/index.tsx @@ -86,9 +86,9 @@ const EditNodeModal = forwardRef( useEffect(() => { return () => { - setOpenWDoubleClick(false) - } - }, []) + setOpenWDoubleClick(false); + }; + }, []); const [errorDuplicateKey, setErrorDuplicateKey] = useState(false); diff --git a/src/frontend/src/modals/shareModal/index.tsx b/src/frontend/src/modals/shareModal/index.tsx index 89f1f25691..0614b25049 100644 --- a/src/frontend/src/modals/shareModal/index.tsx +++ b/src/frontend/src/modals/shareModal/index.tsx @@ -1,5 +1,6 @@ import { Loader2 } from "lucide-react"; import { ReactNode, useEffect, useMemo, useState } from "react"; +import { useHotkeys } from "react-hotkeys-hook"; import EditFlowSettings from "../../components/EditFlowSettingsComponent"; import IconComponent from "../../components/genericIconComponent"; import { TagsSelector } from "../../components/tagsSelectorComponent"; @@ -25,7 +26,6 @@ import { import { getTagsIds } from "../../utils/storeUtils"; import ConfirmationModal from "../ConfirmationModal"; import BaseModal from "../baseModal"; -import { useHotkeys } from "react-hotkeys-hook"; import ExportModal from "../exportModal"; export default function ShareModal({ @@ -45,8 +45,8 @@ export default function ShareModal({ }): JSX.Element { function handleOpenWShortcut(e: KeyboardEvent) { if (hasApiKey || hasStore) { - e.preventDefault() - internalSetOpen(state => !state); + e.preventDefault(); + internalSetOpen((state) => !state); } } const version = useDarkStore((state) => state.version); @@ -59,7 +59,7 @@ export default function ShareModal({ const [openConfirmationModal, setOpenConfirmationModal] = useState(false); const nameComponent = is_component ? "component" : "workflow"; - useHotkeys("mod+alt+s", handleOpenWShortcut) + useHotkeys("mod+alt+s", handleOpenWShortcut); const [tags, setTags] = useState<{ id: string; name: string }[]>([]); const [loadingTags, setLoadingTags] = useState(false); @@ -216,8 +216,9 @@ export default function ShareModal({ {children ? children : <>} Share
- {!is_component && + {!is_component && ( + + + + )} + {is_component && ( - - } - {is_component && - - } + )} - + + ); diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx index 77e2936721..768f92e6cb 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx @@ -2,22 +2,18 @@ import { ColDef, ColGroupDef } from "ag-grid-community"; import { useEffect, useState } from "react"; import ForwardedIconComponent from "../../../../components/genericIconComponent"; import TableComponent from "../../../../components/tableComponent"; -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "../../../../components/ui/card"; import { Button } from "../../../../components/ui/button"; -import EditShortcutButton from "./EditShortcutButton"; +import { + defaultShortcuts, + unavailableShortcutss, +} from "../../../../constants/constants"; import { useShortcutsStore } from "../../../../stores/shortcuts"; -import { defaultShortcuts, unavailableShortcutss } from "../../../../constants/constants"; +import EditShortcutButton from "./EditShortcutButton"; export default function ShortcutsPage() { const [selectedRows, setSelectedRows] = useState([]); - const shortcuts = useShortcutsStore(state => state.shortcuts); - const setShortcuts = useShortcutsStore(state => state.setShortcuts); + const shortcuts = useShortcutsStore((state) => state.shortcuts); + const setShortcuts = useShortcutsStore((state) => state.setShortcuts); // Column Definitions: Defines the columns to be displayed. const [colDefs, setColDefs] = useState<(ColDef | ColGroupDef)[]>([ @@ -37,23 +33,27 @@ export default function ShortcutsPage() { }, ]); - const [nodesRowData, setNodesRowData] = useState>([]); + const [nodesRowData, setNodesRowData] = useState< + Array<{ name: string; shortcut: string }> + >([]); useEffect(() => { - setNodesRowData(shortcuts) - }, [shortcuts]) + setNodesRowData(shortcuts); + }, [shortcuts]); - const combinationToEdit = shortcuts.filter((s) => s.name === selectedRows[0]) + const combinationToEdit = shortcuts.filter((s) => s.name === selectedRows[0]); const [open, setOpen] = useState(false); - const unavaliableShortcuts = useShortcutsStore(state => state.unavailableShortcuts); + const unavaliableShortcuts = useShortcutsStore( + (state) => state.unavailableShortcuts + ); useEffect(() => { if (localStorage.getItem("langflow-shortcuts")) { const savedShortcuts = localStorage.getItem("langflow-shortcuts"); const savedUShortcuts = localStorage.getItem("langflow-UShortcuts"); setShortcuts(JSON.parse(savedShortcuts!), JSON.parse(savedUShortcuts!)); } - }, []) + }, []); function handleRestore() { setShortcuts(defaultShortcuts, unavailableShortcutss); @@ -73,13 +73,12 @@ export default function ShortcutsPage() { />

- Manage Shortcuts for quick access to - frequently used actions. + Manage Shortcuts for quick access to frequently used actions.

-
-
+
+
- @@ -105,7 +108,9 @@ export default function ShortcutsPage() {
{ - setSelectedRows(event.api.getSelectedRows().map((row) => row.name)); + setSelectedRows( + event.api.getSelectedRows().map((row) => row.name) + ); }} suppressRowClickSelection={true} domLayout="autoHeight" diff --git a/src/frontend/src/stores/shortcuts.ts b/src/frontend/src/stores/shortcuts.ts index f2389359d7..7b817c3f3b 100644 --- a/src/frontend/src/stores/shortcuts.ts +++ b/src/frontend/src/stores/shortcuts.ts @@ -1,12 +1,15 @@ import { create } from "zustand"; +import { + defaultShortcuts, + unavailableShortcutss, +} from "../constants/constants"; import { shortcutsStoreType } from "../types/store"; -import { defaultShortcuts, unavailableShortcutss } from "../constants/constants"; export const useShortcutsStore = create((set, get) => ({ unavailableShortcuts: unavailableShortcutss, shortcuts: defaultShortcuts, setShortcuts: (newShortcuts, unavailable) => { - set({shortcuts: newShortcuts, unavailableShortcuts: unavailable} ); + set({ shortcuts: newShortcuts, unavailableShortcuts: unavailable }); }, undo: "mod+z", redo: "mod+y", @@ -26,7 +29,7 @@ export const useShortcutsStore = create((set, get) => ({ api: "mod+r", updateUniqueShortcut: (name, combination) => { set({ - [name]: combination - }) - } + [name]: combination, + }); + }, })); diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts index 9c58121c6b..2b973ccd71 100644 --- a/src/frontend/src/types/components/index.ts +++ b/src/frontend/src/types/components/index.ts @@ -735,7 +735,7 @@ export type toolbarSelectItemProps = { isMac: boolean; shift: boolean; keyboardKey: string; - mod?:boolean; + mod?: boolean; value: string; icon: string; styleObj?: { diff --git a/src/frontend/src/types/store/index.ts b/src/frontend/src/types/store/index.ts index 676d927b7a..fd847c165e 100644 --- a/src/frontend/src/types/store/index.ts +++ b/src/frontend/src/types/store/index.ts @@ -34,13 +34,16 @@ export type shortcutsStoreType = { copy: string; duplicate: string; share: string; - docs:string; - save:string; + docs: string; + save: string; delete: string; shortcuts: Array<{ name: string; shortcut: string; - }> + }>; unavailableShortcuts: string[]; - setShortcuts: (newShortcuts: Array<{name: string; shortcut: string;}>, unavailable: string[]) => void; + setShortcuts: ( + newShortcuts: Array<{ name: string; shortcut: string }>, + unavailable: string[] + ) => void; }; diff --git a/src/frontend/src/types/zustand/globalVariables/index.ts b/src/frontend/src/types/zustand/globalVariables/index.ts index 752336c19b..de7c5543e6 100644 --- a/src/frontend/src/types/zustand/globalVariables/index.ts +++ b/src/frontend/src/types/zustand/globalVariables/index.ts @@ -25,7 +25,7 @@ export type GlobalVariablesStore = { ) => void; removeGlobalVariable: (name: string) => Promise; getVariableId: (name: string) => string | undefined; - unavaliableFields: {[name: string]: string}; - setUnavaliableFields: (fields: {[name: string]: string}) => void; + unavaliableFields: { [name: string]: string }; + setUnavaliableFields: (fields: { [name: string]: string }) => void; removeUnavaliableField: (field: string) => void; }; diff --git a/src/frontend/src/utils/styleUtils.ts b/src/frontend/src/utils/styleUtils.ts index 8437c802b7..aeb1e66ae5 100644 --- a/src/frontend/src/utils/styleUtils.ts +++ b/src/frontend/src/utils/styleUtils.ts @@ -101,6 +101,7 @@ import { Redo, RefreshCcw, Repeat, + RotateCcw, Save, SaveAll, Scissors, @@ -140,7 +141,6 @@ import { X, XCircle, Zap, - RotateCcw, } from "lucide-react"; import { FaApple, FaGithub } from "react-icons/fa"; import { AWSIcon } from "../icons/AWS"; @@ -515,5 +515,5 @@ export const nodeIconsLucide: iconsType = { Command, ArrowBigUp, Dot, - RotateCcw + RotateCcw, }; diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 1c580fa4b4..47324133d3 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -93,8 +93,8 @@ export function toTitleCase( export function getUnavailableFields(variables: { [key: string]: { default_fields?: string[] }; -}): {[name: string]: string} { - const unVariables:{[name: string]: string} = {}; +}): { [name: string]: string } { + const unVariables: { [name: string]: string } = {}; Object.keys(variables).forEach((key) => { if (variables[key].default_fields) { variables[key].default_fields!.forEach((field) => { From c6869c2eb5096e1af82b40c89f3525dde7e6e9c7 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 3 May 2024 19:39:27 -0300 Subject: [PATCH 21/60] Refactor: Visual shortcut update with the settings configuration --- .../src/components/ui/select-custom.tsx | 8 +- src/frontend/src/constants/constants.ts | 39 ++++++---- .../components/nodeToolbarComponent/index.tsx | 74 +++++++++++-------- .../toolbarSelectItem/index.tsx | 62 ++++++++-------- .../EditShortcutButton/index.tsx | 16 ++-- src/frontend/src/types/components/index.ts | 12 ++- 6 files changed, 118 insertions(+), 93 deletions(-) diff --git a/src/frontend/src/components/ui/select-custom.tsx b/src/frontend/src/components/ui/select-custom.tsx index 8c5223231e..82ba540fe5 100644 --- a/src/frontend/src/components/ui/select-custom.tsx +++ b/src/frontend/src/components/ui/select-custom.tsx @@ -33,10 +33,10 @@ const SelectContent = React.forwardRef< {children} @@ -75,7 +75,7 @@ const SelectItem = React.forwardRef< ref={ref} className={cn( "relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-3 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", - className + className, )} {...props} > diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index d2ceb530db..4279c71d29 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -796,35 +796,35 @@ export const SAVE_DEBOUNCE_TIME = 300; export const defaultShortcuts = [ { name: "Advanced Settings", - shortcut: "Ctrl + Shift + a", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Shift + A`, }, { name: "Minimize", - shortcut: "Ctrl + q", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Q`, }, { name: "Code", - shortcut: "Ctrl + Shift + u", + shortcut: `Space`, }, { name: "Copy", - shortcut: "Ctrl + c", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + C`, }, { name: "Duplicate", - shortcut: "Ctrl + d", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + D`, }, { name: "Share", - shortcut: "Ctrl + Shift + s", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Shift + S`, }, { name: "Docs", - shortcut: "Ctrl + Shift + d", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Shift + D`, }, { name: "Save", - shortcut: "Ctrl + s", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + S`, }, { name: "Delete", @@ -832,31 +832,39 @@ export const defaultShortcuts = [ }, { name: "Open playground", - shortcut: "Ctrl + k", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + K`, }, { name: "Undo", - shortcut: "Ctrl + z", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Z`, }, { name: "Redo", - shortcut: "Ctrl + y", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Y`, }, { name: "Group", - shortcut: "Ctrl + g", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + G`, }, { name: "Cut", - shortcut: "Ctrl + x", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + X`, }, { name: "Paste", - shortcut: "Ctrl + v", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + V`, }, { name: "API", - shortcut: "Ctrl + r", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + R`, + }, + { + name: "Download", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + J`, + }, + { + name: "Update", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + U`, }, ]; @@ -877,4 +885,5 @@ export const unavailableShortcutss = [ "CTRL + K", "CTRL + Z", "CTRL + Y", + "CTRL + J", ]; diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index fcabc130da..c91f22049f 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -64,10 +64,12 @@ export default function NodeToolbarComponent({ data.node.template[templateField].type === "dict" || data.node.template[templateField].type === "NestedDict"), ).length; + const templates = useTypesStore((state) => state.templates); const hasStore = useStoreStore((state) => state.hasStore); const hasApiKey = useStoreStore((state) => state.hasApiKey); const validApiKey = useStoreStore((state) => state.validApiKey); + const shortcuts = useShortcutsStore((state) => state.shortcuts); function handleMinimizeWShortcut(e: KeyboardEvent) { e.preventDefault(); @@ -479,10 +481,10 @@ export default function NodeToolbarComponent({ {hasCode && ( obj.name === "Code")?.shortcut! + } isMac={navigator.userAgent.toUpperCase().includes("MAC")} - shift={false} - mod={false} value={"Code"} icon={"Code"} dataTestId="code-button-modal" @@ -492,9 +494,11 @@ export default function NodeToolbarComponent({ {nodeLength > 0 && ( obj.name === "Advanced Settings") + ?.shortcut! + } isMac={navigator.userAgent.toUpperCase().includes("MAC")} - shift={true} value={"Advanced"} icon={"Settings2"} dataTestId="edit-button-modal" @@ -503,9 +507,10 @@ export default function NodeToolbarComponent({ )} obj.name === "Save")?.shortcut! + } isMac={navigator.userAgent.toUpperCase().includes("MAC")} - shift={false} value={"Save"} icon={"SaveAll"} dataTestId="save-button-modal" @@ -513,19 +518,21 @@ export default function NodeToolbarComponent({ obj.name === "Duplicate")?.shortcut! + } isMac={navigator.userAgent.toUpperCase().includes("MAC")} - shift={false} value={"Duplicate"} icon={"Copy"} - dataTestId="duplicate-button-modal" + dataTestId="copy-button-modal" /> obj.name === "Copy")?.shortcut! + } isMac={navigator.userAgent.toUpperCase().includes("MAC")} - shift={false} value={"Copy"} icon={"Clipboard"} dataTestId="copy-button-modal" @@ -534,9 +541,10 @@ export default function NodeToolbarComponent({ {isOutdated && ( obj.name === "Update")?.shortcut! + } isMac={navigator.userAgent.toUpperCase().includes("MAC")} - shift={false} value={"Update"} icon={"Code"} dataTestId="update-button-modal" @@ -550,14 +558,12 @@ export default function NodeToolbarComponent({ disabled={!hasApiKey || !validApiKey} > obj.name === "Share")?.shortcut! + } isMac={navigator.userAgent.toUpperCase().includes("MAC")} - shift={true} value={"Share"} icon={"Share3"} - styleObj={{ - iconClasses: "relative top-0.5 -m-1 mr-[0.25rem] h-6 w-6", - }} dataTestId="share-button-modal" /> @@ -565,13 +571,14 @@ export default function NodeToolbarComponent({ {(!hasStore || !hasApiKey || !validApiKey) && ( obj.name === "Download") + ?.shortcut! + } isMac={navigator.userAgent.toUpperCase().includes("MAC")} - icon="Download" - styleObj={{ iconClasses: "relative top-0.5 mr-2 h-4 w-4" }} - keyboardKey={"J"} - dataTestId={"Dowload-button-nodeToolbar"} + value={"Download"} + icon={"Download"} + dataTestId="Download-button-modal" /> )} @@ -580,9 +587,10 @@ export default function NodeToolbarComponent({ disabled={data.node?.documentation === ""} > obj.name === "Docs")?.shortcut! + } isMac={navigator.userAgent.toUpperCase().includes("MAC")} - shift={true} value={"Docs"} icon={"FileText"} dataTestId="docs-button-modal" @@ -591,12 +599,14 @@ export default function NodeToolbarComponent({ {isMinimal && ( obj.name === "Minimize") + ?.shortcut! + } isMac={navigator.userAgent.toUpperCase().includes("MAC")} - shift={false} - keyboardKey={"Q"} - dataTestId={"minimize-button-nodeToolbar"} + value={showNode ? "Minimize" : "Expand"} + icon={showNode ? "Minimize2" : "Maximize2"} + dataTestId="minimize-button-modal" /> )} diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx index 031bd41a73..fc10b74c49 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx @@ -2,16 +2,27 @@ import ForwardedIconComponent from "../../../../../components/genericIconCompone import { toolbarSelectItemProps } from "../../../../../types/components"; export default function ToolbarSelectItem({ - shift, - isMac, - mod = true, - keyboardKey, value, icon, styleObj, dataTestId, ping, + shortcut, + isMac, }: toolbarSelectItemProps) { + let hasShift = false; + const fixedShortcut = shortcut?.split("+"); + fixedShortcut.forEach((key) => { + if (key.toLowerCase().includes("shift")) { + hasShift = true; + } + }); + const filteredShortcut = fixedShortcut.filter( + (key) => !key.toLowerCase().includes("shift"), + ); + let shortcutWPlus = ""; + if (!hasShift) shortcutWPlus = filteredShortcut.join("+"); + return (
{value} - - {mod && - (isMac ? ( - + + {hasShift ? ( + <> + {filteredShortcut[0]} + + {filteredShortcut.map((key, idx) => { + if (idx > 0) { + return {key.toUpperCase()} ; + } + })} + ) : ( - - {shift ? "Ctrl" : "Ctrl +"} - - ))} - {shift && ( - - )} - - {keyboardKey} + shortcutWPlus + )}
); diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx index 50e2c8e5fa..51e3aa144c 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx @@ -5,6 +5,7 @@ import ForwardedIconComponent from "../../../../../components/genericIconCompone import { Button } from "../../../../../components/ui/button"; import BaseModal from "../../../../../modals/baseModal"; import { useShortcutsStore } from "../../../../../stores/shortcuts"; +import { toTitleCase } from "../../../../../utils/utils"; export default function EditShortcutButton({ children, @@ -24,11 +25,11 @@ export default function EditShortcutButton({ disable?: boolean; }): JSX.Element { const isMac = navigator.userAgent.toUpperCase().includes("MAC"); - const [key, setKey] = useState(isMac ? "Meta" : "Ctrl"); + const [key, setKey] = useState(isMac ? "Cmd" : "Ctrl"); const setSuccessData = useAlertStore((state) => state.setSuccessData); const setShortcuts = useShortcutsStore((state) => state.setShortcuts); const unavaliableShortcuts = useShortcutsStore( - (state) => state.unavailableShortcuts + (state) => state.unavailableShortcuts, ); const setErrorData = useAlertStore((state) => state.setErrorData); @@ -43,7 +44,7 @@ export default function EditShortcutButton({ } const setUniqueShortcut = useShortcutsStore( - (state) => state.updateUniqueShortcut + (state) => state.updateUniqueShortcut, ); function editCombination(): void { @@ -70,7 +71,7 @@ export default function EditShortcutButton({ setKey(isMac ? "META" : "CTRL"); localStorage.setItem( "langflow-shortcuts", - JSON.stringify(newCombination) + JSON.stringify(newCombination), ); localStorage.setItem("langflow-UShortcuts", JSON.stringify(unavailable)); return; @@ -82,7 +83,7 @@ export default function EditShortcutButton({ } useEffect(() => { - if (!open) setKey(isMac ? "META" : "CTRL"); + if (!open) setKey(isMac ? "Cmd" : "Ctrl"); console.log(key); }, [open, setOpen, key]); @@ -90,7 +91,10 @@ export default function EditShortcutButton({ function onKeyDown(e: KeyboardEvent) { e.preventDefault(); if (key.toUpperCase().includes(e.key.toUpperCase())) return; - setKey((oldKey) => `${oldKey.toUpperCase()} + ${e.key.toUpperCase()}`); + setKey( + (oldKey) => + `${oldKey.length > 0 ? toTitleCase(oldKey) : oldKey.toUpperCase()} + ${e.key.length > 0 ? toTitleCase(e.key) : e.key.toUpperCase()}`, + ); } document.addEventListener("keydown", onKeyDown); diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts index 5ee1a0fc93..f46bf385fc 100644 --- a/src/frontend/src/types/components/index.ts +++ b/src/frontend/src/types/components/index.ts @@ -513,7 +513,7 @@ export type nodeToolbarPropsType = { updateNodeCode?: ( newNodeClass: APIClassType, code: string, - name: string + name: string, ) => void; setShowState: (show: boolean | SetStateAction) => void; isOutdated?: boolean; @@ -563,7 +563,7 @@ export type chatMessagePropsType = { updateChat: ( chat: ChatMessageType, message: string, - stream_url?: string + stream_url?: string, ) => void; }; @@ -654,12 +654,12 @@ export type codeTabsPropsType = { getValue?: ( value: string, node: NodeType, - template: TemplateVariableType + template: TemplateVariableType, ) => string; buildTweakObject?: ( tw: string, changes: string | string[] | boolean | number | Object[] | Object, - template: TemplateVariableType + template: TemplateVariableType, ) => string | void; }; }; @@ -729,9 +729,6 @@ export type IOFileInputProps = { export type toolbarSelectItemProps = { isMac: boolean; - shift: boolean; - keyboardKey: string; - mod?: boolean; value: string; icon: string; styleObj?: { @@ -744,4 +741,5 @@ export type toolbarSelectItemProps = { }; dataTestId: string; ping?: boolean; + shortcut: string; }; From c2ae5e88319b18f335fbf56f13da24cd478b8480 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Mon, 6 May 2024 18:37:53 -0300 Subject: [PATCH 22/60] Refactor: Add the possibility to don't use ctrl/cmd --- .../EditShortcutButton/index.tsx | 95 ++++++++++++------- 1 file changed, 59 insertions(+), 36 deletions(-) diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx index 51e3aa144c..ffaaf63c16 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx @@ -25,7 +25,7 @@ export default function EditShortcutButton({ disable?: boolean; }): JSX.Element { const isMac = navigator.userAgent.toUpperCase().includes("MAC"); - const [key, setKey] = useState(isMac ? "Cmd" : "Ctrl"); + const [key, setKey] = useState(""); const setSuccessData = useAlertStore((state) => state.setSuccessData); const setShortcuts = useShortcutsStore((state) => state.setShortcuts); const unavaliableShortcuts = useShortcutsStore( @@ -48,33 +48,45 @@ export default function EditShortcutButton({ ); function editCombination(): void { - console.log(canEditCombination(key)); - if (canEditCombination(key)) { - const newCombination = defaultShortcuts.map((s) => { - if (s.name === shortcut[0]) { - return { name: s.name, shortcut: key }; + if (key) { + if (canEditCombination(key)) { + const newCombination = defaultShortcuts.map((s) => { + if (s.name === shortcut[0]) { + return { name: s.name, shortcut: key }; + } + return { name: s.name, shortcut: s.shortcut }; + }); + const unavailable = unavaliableShortcuts.map((s) => { + if (s.toLowerCase() === defaultCombination.toLowerCase()) + return (s = key.toUpperCase()); + return s; + }); + const fixCombination = key.split(" "); + if ( + fixCombination[0].toLowerCase().includes("ctrl") || + fixCombination[0].toLowerCase().includes("cmd") + ) { + fixCombination[0] = "mod"; } - return { name: s.name, shortcut: s.shortcut }; - }); - const unavailable = unavaliableShortcuts.map((s) => { - if (s.toLowerCase() === defaultCombination.toLowerCase()) - return (s = key.toUpperCase()); - return s; - }); - const fixCombination = key.split(" "); - fixCombination[0] = "mod"; - const shortcutName = shortcut[0].split(" ")[0].toLowerCase(); - setUniqueShortcut(shortcutName, fixCombination.join("").toLowerCase()); - setShortcuts(newCombination, unavailable); - setOpen(false); - setSuccessData({ title: `${shortcut[0]} shortcut successfully changed` }); - setKey(isMac ? "META" : "CTRL"); - localStorage.setItem( - "langflow-shortcuts", - JSON.stringify(newCombination), - ); - localStorage.setItem("langflow-UShortcuts", JSON.stringify(unavailable)); - return; + const shortcutName = shortcut[0].split(" ")[0].toLowerCase(); + setUniqueShortcut(shortcutName, fixCombination.join("").toLowerCase()); + console.log(newCombination); + setShortcuts(newCombination, unavailable); + setOpen(false); + setSuccessData({ + title: `${shortcut[0]} shortcut successfully changed`, + }); + setKey(null); + localStorage.setItem( + "langflow-shortcuts", + JSON.stringify(newCombination), + ); + localStorage.setItem( + "langflow-UShortcuts", + JSON.stringify(unavailable), + ); + return; + } } setErrorData({ title: "Error saving key combination", @@ -83,18 +95,29 @@ export default function EditShortcutButton({ } useEffect(() => { - if (!open) setKey(isMac ? "Cmd" : "Ctrl"); - console.log(key); + if (!open) setKey(null); }, [open, setOpen, key]); + function getFixedCombination({ + oldKey, + key, + }: { + oldKey: string; + key: string; + }): string { + if (oldKey === null) { + return `${key.length > 0 ? toTitleCase(key) : toTitleCase(key)}`; + } + return `${oldKey.length > 0 ? toTitleCase(oldKey) : oldKey.toUpperCase()} + ${key.length > 0 ? toTitleCase(key) : key.toUpperCase()}`; + } + useEffect(() => { function onKeyDown(e: KeyboardEvent) { e.preventDefault(); - if (key.toUpperCase().includes(e.key.toUpperCase())) return; - setKey( - (oldKey) => - `${oldKey.length > 0 ? toTitleCase(oldKey) : oldKey.toUpperCase()} + ${e.key.length > 0 ? toTitleCase(e.key) : e.key.toUpperCase()}`, - ); + if (key) { + if (key.toUpperCase().includes(e.key.toUpperCase())) return; + } + setKey((oldKey) => getFixedCombination({ oldKey: oldKey!, key: e.key })); } document.addEventListener("keydown", onKeyDown); @@ -118,7 +141,7 @@ export default function EditShortcutButton({
- {key.toUpperCase()} + {key && key.toUpperCase()}
@@ -127,7 +150,7 @@ export default function EditShortcutButton({ From 60dba48703e82639a2283c3e42c0ecfcfb7ed347 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Mon, 6 May 2024 19:03:01 -0300 Subject: [PATCH 23/60] Feat: make possible to change all nodes shortcuts --- src/frontend/src/constants/constants.ts | 1 + .../components/nodeToolbarComponent/index.tsx | 36 ++++++++----------- .../pages/ShortcutsPage/index.tsx | 2 ++ src/frontend/src/stores/shortcuts.ts | 2 ++ src/frontend/src/types/store/index.ts | 4 ++- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index 4279c71d29..da2ad92bed 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -886,4 +886,5 @@ export const unavailableShortcutss = [ "CTRL + Z", "CTRL + Y", "CTRL + J", + "CTRL + U", ]; diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index c91f22049f..7d737b0457 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -153,16 +153,19 @@ export default function NodeToolbarComponent({ const save = useShortcutsStore((state) => state.save); const docs = useShortcutsStore((state) => state.docs); const code = useShortcutsStore((state) => state.code); + const group = useShortcutsStore((state) => state.group); + const update = useShortcutsStore((state) => state.update); + const download = useShortcutsStore((state) => state.download); useHotkeys(minimize, handleMinimizeWShortcut); - useHotkeys("mod+u", handleUpdateWShortcut); - useHotkeys("mod+g", handleGroupWShortcut); + useHotkeys(update, handleUpdateWShortcut); + useHotkeys(group, handleGroupWShortcut); useHotkeys(share, handleShareWShortcut); useHotkeys(code, handleCodeWShortcut); useHotkeys(advanced, handleAdvancedWShortcut); useHotkeys(save, handleSaveWShortcut); useHotkeys(docs, handleDocsWShortcut); - useHotkeys("mod+j", handleDownloadWShortcut); + useHotkeys(download, handleDownloadWShortcut); useHotkeys("space", handleCodeWShortcut); const isMinimal = numberOfHandles <= 1; @@ -612,24 +615,15 @@ export default function NodeToolbarComponent({ )} {isGroup && ( -
- {" "} - Ungroup{" "} - {navigator.userAgent.toUpperCase().includes("MAC") ? ( - - ) : ( - - Ctrl +{" "} - - )} - G -
+ obj.name === "Group")?.shortcut! + } + isMac={navigator.userAgent.toUpperCase().includes("MAC")} + value={"Ungroup"} + icon={"Ungroup"} + dataTestId="group-button-modal" + />
)} diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx index 9e6580741a..2f84b37382 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx @@ -25,11 +25,13 @@ export default function ShortcutsPage() { headerCheckboxSelection: true, checkboxSelection: true, showDisabledCheckboxes: true, + resizable: false, }, //This column will be twice as wide as the others { field: "shortcut", flex: 2, editable: false, + resizable: false, }, ]); diff --git a/src/frontend/src/stores/shortcuts.ts b/src/frontend/src/stores/shortcuts.ts index 7b817c3f3b..2c23914175 100644 --- a/src/frontend/src/stores/shortcuts.ts +++ b/src/frontend/src/stores/shortcuts.ts @@ -27,6 +27,8 @@ export const useShortcutsStore = create((set, get) => ({ cut: "mod+x", paste: "mod+v", api: "mod+r", + update: "mod+u", + download: "mod+j", updateUniqueShortcut: (name, combination) => { set({ [name]: combination, diff --git a/src/frontend/src/types/store/index.ts b/src/frontend/src/types/store/index.ts index fd847c165e..5cf866db7f 100644 --- a/src/frontend/src/types/store/index.ts +++ b/src/frontend/src/types/store/index.ts @@ -37,6 +37,8 @@ export type shortcutsStoreType = { docs: string; save: string; delete: string; + update: string; + download: string; shortcuts: Array<{ name: string; shortcut: string; @@ -44,6 +46,6 @@ export type shortcutsStoreType = { unavailableShortcuts: string[]; setShortcuts: ( newShortcuts: Array<{ name: string; shortcut: string }>, - unavailable: string[] + unavailable: string[], ) => void; }; From 9466e061be9da8a79f3ba3dc67e3afa295c17657 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Mon, 6 May 2024 19:54:28 -0300 Subject: [PATCH 24/60] Fix: Ctrl displaying as Control --- .../SettingsPage/pages/GlobalVariablesPage/index.tsx | 1 + .../pages/ShortcutsPage/EditShortcutButton/index.tsx | 10 +++++++++- .../pages/SettingsPage/pages/ShortcutsPage/index.tsx | 2 +- src/frontend/src/utils/styleUtils.ts | 6 ++++-- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx index 2ca48050b6..0350a18276 100644 --- a/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx @@ -178,6 +178,7 @@ export default function GlobalVariablesPage() { pagination={false} columnDefs={colDefs} rowData={rowData} + containerStyle={{ overflow: "auto", maxWidth: "80vh" }} />
diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx index ffaaf63c16..b5d530c11f 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx @@ -114,10 +114,18 @@ export default function EditShortcutButton({ useEffect(() => { function onKeyDown(e: KeyboardEvent) { e.preventDefault(); + let fixedKey = e.key; if (key) { if (key.toUpperCase().includes(e.key.toUpperCase())) return; } - setKey((oldKey) => getFixedCombination({ oldKey: oldKey!, key: e.key })); + if (e.key?.toLowerCase() === "control") { + console.log("oi"); + fixedKey = "Ctrl"; + console.log(fixedKey); + } + setKey((oldKey) => + getFixedCombination({ oldKey: oldKey!, key: fixedKey }), + ); } document.addEventListener("keydown", onKeyDown); diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx index 2f84b37382..a1ef2f688f 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx @@ -86,7 +86,7 @@ export default function ShortcutsPage() { setOpen={setOpen} > diff --git a/src/frontend/src/utils/styleUtils.ts b/src/frontend/src/utils/styleUtils.ts index 281278e2f8..1ffe95b52d 100644 --- a/src/frontend/src/utils/styleUtils.ts +++ b/src/frontend/src/utils/styleUtils.ts @@ -141,7 +141,8 @@ import { X, XCircle, Zap, - PlaySquare + PlaySquare, + Wrench, } from "lucide-react"; import { FaApple, FaGithub } from "react-icons/fa"; import { AWSIcon } from "../icons/AWS"; @@ -150,7 +151,7 @@ import { AnthropicIcon } from "../icons/Anthropic"; import { AstraDBIcon } from "../icons/AstraDB"; import { AzureIcon } from "../icons/Azure"; import { BingIcon } from "../icons/Bing"; -import { BotMessageSquareIcon} from "../icons/BotMessageSquare"; +import { BotMessageSquareIcon } from "../icons/BotMessageSquare"; import { ChromaIcon } from "../icons/ChromaIcon"; import { CohereIcon } from "../icons/Cohere"; import { ElasticsearchIcon } from "../icons/ElasticsearchStore"; @@ -518,4 +519,5 @@ export const nodeIconsLucide: iconsType = { ArrowBigUp, Dot, RotateCcw, + Wrench, }; From ca30b114b20b0c189a9829fa1d593f0ae9fae568 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Thu, 23 May 2024 15:10:27 -0300 Subject: [PATCH 25/60] Install react-hotkeys-hook --- src/frontend/package.json | 265 +++++++++++++++++++------------------- 1 file changed, 133 insertions(+), 132 deletions(-) diff --git a/src/frontend/package.json b/src/frontend/package.json index d755b70b96..78f0f61325 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -1,134 +1,135 @@ { - "name": "langflow", - "version": "0.1.2", - "private": true, - "dependencies": { - "@headlessui/react": "^1.7.17", - "@million/lint": "^0.0.73", - "@radix-ui/react-accordion": "^1.1.2", - "@radix-ui/react-checkbox": "^1.0.4", - "@radix-ui/react-dialog": "^1.0.4", - "@radix-ui/react-dropdown-menu": "^2.0.5", - "@radix-ui/react-form": "^0.0.3", - "@radix-ui/react-icons": "^1.3.0", - "@radix-ui/react-label": "^2.0.2", - "@radix-ui/react-menubar": "^1.0.3", - "@radix-ui/react-popover": "^1.0.6", - "@radix-ui/react-progress": "^1.0.3", - "@radix-ui/react-select": "^2.0.0", - "@radix-ui/react-separator": "^1.0.3", - "@radix-ui/react-slot": "^1.0.2", - "@radix-ui/react-switch": "^1.0.3", - "@radix-ui/react-tabs": "^1.0.4", - "@radix-ui/react-tooltip": "^1.0.6", - "@tabler/icons-react": "^2.32.0", - "@tailwindcss/forms": "^0.5.6", - "@tailwindcss/line-clamp": "^0.4.4", - "@types/axios": "^0.14.0", - "ace-builds": "^1.24.1", - "ag-grid-community": "^31.2.1", - "ag-grid-react": "^31.2.1", - "ansi-to-html": "^0.7.2", - "axios": "^1.5.0", - "base64-js": "^1.5.1", - "class-variance-authority": "^0.6.1", - "clsx": "^1.2.1", - "cmdk": "^1.0.0", - "dompurify": "^3.0.5", - "dotenv": "^16.4.5", - "esbuild": "^0.17.19", - "file-saver": "^2.0.5", - "framer-motion": "^11.0.6", - "lodash": "^4.17.21", - "lucide-react": "^0.331.0", - "million": "^3.0.6", - "moment": "^2.29.4", - "openseadragon": "^4.1.1", - "playwright": "^1.42.0", - "react": "^18.2.21", - "react-ace": "^10.1.0", - "react-cookie": "^4.1.1", - "react-dom": "^18.2.21", - "react-error-boundary": "^4.0.11", - "react-icons": "^5.0.1", - "react-laag": "^2.0.5", - "react-markdown": "^8.0.7", - "react-pdf": "^7.7.1", - "react-router-dom": "^6.15.0", - "react-syntax-highlighter": "^15.5.0", - "react18-json-view": "^0.2.3", - "reactflow": "^11.9.2", - "rehype-mathjax": "^4.0.3", - "remark-gfm": "^3.0.1", - "remark-math": "^5.1.1", - "shadcn-ui": "^0.2.3", - "short-unique-id": "^4.4.4", - "tailwind-merge": "^1.14.0", - "tailwindcss-animate": "^1.0.7", - "uuid": "^9.0.0", - "vite-plugin-svgr": "^3.2.0", - "web-vitals": "^2.1.4", - "zustand": "^4.4.7" - }, - "scripts": { - "dev:docker": "vite --host 0.0.0.0", - "start": "vite", - "build": "vite build", - "serve": "vite preview", - "format": "npx prettier --write \"{docs,src}/**/*.{js,jsx,ts,tsx,json,md}\" --ignore-path .prettierignore", - "type-check": "tsc --noEmit --pretty --project tsconfig.json && vite" - }, - "simple-git-hooks": { - "pre-commit": "npx pretty-quick --staged" - }, - "eslintConfig": { - "extends": [ - "react-app", - "react-app/jest" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - }, - "proxy": "http://127.0.0.1:7860", - "devDependencies": { - "@playwright/test": "^1.43.1", - "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.80", - "@tailwindcss/typography": "^0.5.9", - "@testing-library/jest-dom": "^5.17.0", - "@testing-library/react": "^13.4.0", - "@testing-library/user-event": "^13.5.0", - "@types/jest": "^27.5.2", - "@types/lodash": "^4.14.197", - "@types/node": "^16.18.46", - "@types/react": "^18.2.21", - "@types/react-dom": "^18.2.7", - "@types/uuid": "^9.0.2", - "@vitejs/plugin-react-swc": "^3.3.2", - "autoprefixer": "^10.4.15", - "daisyui": "^4.0.4", - "eslint": "^8.57.0", - "eslint-plugin-node": "^11.1.0", - "postcss": "^8.4.29", - "prettier": "^2.8.8", - "prettier-plugin-organize-imports": "^3.2.3", - "prettier-plugin-tailwindcss": "^0.3.0", - "pretty-quick": "^3.1.3", - "simple-git-hooks": "^2.11.1", - "tailwindcss": "^3.3.3", - "tailwindcss-dotted-background": "^1.1.0", - "typescript": "^5.2.2", - "ua-parser-js": "^1.0.37", - "vite": "^4.5.2" - } + "name": "langflow", + "version": "0.1.2", + "private": true, + "dependencies": { + "@headlessui/react": "^1.7.17", + "@million/lint": "^0.0.73", + "@radix-ui/react-accordion": "^1.1.2", + "@radix-ui/react-checkbox": "^1.0.4", + "@radix-ui/react-dialog": "^1.0.4", + "@radix-ui/react-dropdown-menu": "^2.0.5", + "@radix-ui/react-form": "^0.0.3", + "@radix-ui/react-icons": "^1.3.0", + "@radix-ui/react-label": "^2.0.2", + "@radix-ui/react-menubar": "^1.0.3", + "@radix-ui/react-popover": "^1.0.6", + "@radix-ui/react-progress": "^1.0.3", + "@radix-ui/react-select": "^2.0.0", + "@radix-ui/react-separator": "^1.0.3", + "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-switch": "^1.0.3", + "@radix-ui/react-tabs": "^1.0.4", + "@radix-ui/react-tooltip": "^1.0.6", + "@tabler/icons-react": "^2.32.0", + "@tailwindcss/forms": "^0.5.6", + "@tailwindcss/line-clamp": "^0.4.4", + "@types/axios": "^0.14.0", + "ace-builds": "^1.24.1", + "ag-grid-community": "^31.2.1", + "ag-grid-react": "^31.2.1", + "ansi-to-html": "^0.7.2", + "axios": "^1.5.0", + "base64-js": "^1.5.1", + "class-variance-authority": "^0.6.1", + "clsx": "^1.2.1", + "cmdk": "^1.0.0", + "dompurify": "^3.0.5", + "dotenv": "^16.4.5", + "esbuild": "^0.17.19", + "file-saver": "^2.0.5", + "framer-motion": "^11.0.6", + "lodash": "^4.17.21", + "lucide-react": "^0.331.0", + "million": "^3.0.6", + "moment": "^2.29.4", + "openseadragon": "^4.1.1", + "playwright": "^1.42.0", + "react": "^18.2.21", + "react-ace": "^10.1.0", + "react-cookie": "^4.1.1", + "react-dom": "^18.2.21", + "react-error-boundary": "^4.0.11", + "react-hotkeys-hook": "^4.5.0", + "react-icons": "^5.0.1", + "react-laag": "^2.0.5", + "react-markdown": "^8.0.7", + "react-pdf": "^7.7.1", + "react-router-dom": "^6.15.0", + "react-syntax-highlighter": "^15.5.0", + "react18-json-view": "^0.2.3", + "reactflow": "^11.9.2", + "rehype-mathjax": "^4.0.3", + "remark-gfm": "^3.0.1", + "remark-math": "^5.1.1", + "shadcn-ui": "^0.2.3", + "short-unique-id": "^4.4.4", + "tailwind-merge": "^1.14.0", + "tailwindcss-animate": "^1.0.7", + "uuid": "^9.0.0", + "vite-plugin-svgr": "^3.2.0", + "web-vitals": "^2.1.4", + "zustand": "^4.4.7" + }, + "scripts": { + "dev:docker": "vite --host 0.0.0.0", + "start": "vite", + "build": "vite build", + "serve": "vite preview", + "format": "npx prettier --write \"{docs,src}/**/*.{js,jsx,ts,tsx,json,md}\" --ignore-path .prettierignore", + "type-check": "tsc --noEmit --pretty --project tsconfig.json && vite" + }, + "simple-git-hooks": { + "pre-commit": "npx pretty-quick --staged" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + }, + "proxy": "http://127.0.0.1:7860", + "devDependencies": { + "@playwright/test": "^1.43.1", + "@swc/cli": "^0.1.62", + "@swc/core": "^1.3.80", + "@tailwindcss/typography": "^0.5.9", + "@testing-library/jest-dom": "^5.17.0", + "@testing-library/react": "^13.4.0", + "@testing-library/user-event": "^13.5.0", + "@types/jest": "^27.5.2", + "@types/lodash": "^4.14.197", + "@types/node": "^16.18.46", + "@types/react": "^18.2.21", + "@types/react-dom": "^18.2.7", + "@types/uuid": "^9.0.2", + "@vitejs/plugin-react-swc": "^3.3.2", + "autoprefixer": "^10.4.15", + "daisyui": "^4.0.4", + "eslint": "^8.57.0", + "eslint-plugin-node": "^11.1.0", + "postcss": "^8.4.29", + "prettier": "^2.8.8", + "prettier-plugin-organize-imports": "^3.2.3", + "prettier-plugin-tailwindcss": "^0.3.0", + "pretty-quick": "^3.1.3", + "simple-git-hooks": "^2.11.1", + "tailwindcss": "^3.3.3", + "tailwindcss-dotted-background": "^1.1.0", + "typescript": "^5.2.2", + "ua-parser-js": "^1.0.37", + "vite": "^4.5.2" + } } From 5218e92945fac0730386e2f9512b0d4357444aff Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 7 Jun 2024 19:34:07 -0300 Subject: [PATCH 26/60] Refactor: add max page size --- .../src/pages/SettingsPage/pages/ShortcutsPage/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx index 8c11d0567d..1b68c05176 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx @@ -115,6 +115,7 @@ export default function ShortcutsPage() { pagination={false} columnDefs={colDefs} rowData={nodesRowData} + paginationPageSize={8} />
From 0d09ca236e19b2396dde93a379e8c9a8a26a1371 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 7 Jun 2024 19:35:21 -0300 Subject: [PATCH 27/60] Remove consolelog --- .../pages/ShortcutsPage/EditShortcutButton/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx index b5d530c11f..e8c4ba3e73 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx @@ -119,9 +119,7 @@ export default function EditShortcutButton({ if (key.toUpperCase().includes(e.key.toUpperCase())) return; } if (e.key?.toLowerCase() === "control") { - console.log("oi"); fixedKey = "Ctrl"; - console.log(fixedKey); } setKey((oldKey) => getFixedCombination({ oldKey: oldKey!, key: fixedKey }), From 1cfc3f403346be85a1554641f214175e951c83d8 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Fri, 7 Jun 2024 19:43:27 -0300 Subject: [PATCH 28/60] Fix: Change Meta key to command for mac users --- .../pages/ShortcutsPage/EditShortcutButton/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx index e8c4ba3e73..3d01b4ac0f 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx @@ -121,6 +121,9 @@ export default function EditShortcutButton({ if (e.key?.toLowerCase() === "control") { fixedKey = "Ctrl"; } + if (e.key?.toLowerCase() === "meta") { + fixedKey = "Command"; + } setKey((oldKey) => getFixedCombination({ oldKey: oldKey!, key: fixedKey }), ); @@ -152,7 +155,9 @@ export default function EditShortcutButton({
- + diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx index e79d59c1ec..151101de2b 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx @@ -22,12 +22,10 @@ export default function ShortcutsPage() { field: "name", flex: 1, editable: false, - headerCheckboxSelection: true, - checkboxSelection: true, - showDisabledCheckboxes: true, resizable: false, }, //This column will be twice as wide as the others { + headerName: "Functionality", field: "shortcut", flex: 2, editable: false, @@ -77,11 +75,9 @@ export default function ShortcutsPage() { defaultShortcuts={shortcuts} open={open} setOpen={setOpen} + setSelected={setSelectedRows} > - +
diff --git a/src/frontend/src/style/classes.css b/src/frontend/src/style/classes.css index b25da3dfb5..b375d166e3 100644 --- a/src/frontend/src/style/classes.css +++ b/src/frontend/src/style/classes.css @@ -19,6 +19,10 @@ pre { display: none; } +.ag-row { + cursor: pointer; +} + .react-flow__pane { cursor: default; } From 4b090d6229bbb38a5f6134252a3ee4e701446877 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Sat, 8 Jun 2024 18:08:45 -0300 Subject: [PATCH 32/60] Refactor: add a name to shortcuts column --- .../src/pages/SettingsPage/pages/ShortcutsPage/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx index 151101de2b..1438fe5d83 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx @@ -25,7 +25,7 @@ export default function ShortcutsPage() { resizable: false, }, //This column will be twice as wide as the others { - headerName: "Functionality", + headerName: "Keyboard Shortcut", field: "shortcut", flex: 2, editable: false, From f5f5147397bf2f35e2053fe9461481e0f9b0d605 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Sat, 8 Jun 2024 18:12:53 -0300 Subject: [PATCH 33/60] Refactor: Remove checkbox and pagination --- .../src/pages/SettingsPage/pages/ShortcutsPage/index.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx index 1438fe5d83..d22b7d41b9 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx @@ -94,17 +94,11 @@ export default function ShortcutsPage() {
{ - setSelectedRows( - event.api.getSelectedRows().map((row) => row.name), - ); - }} suppressRowClickSelection={true} domLayout="autoHeight" pagination={false} columnDefs={colDefs} rowData={nodesRowData} - paginationPageSize={8} onCellDoubleClicked={(e) => { setSelectedRows([e.data.name]); setOpen(true); From 6b108794ef97c89237a330e4a3a57a73338bfd79 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Sat, 8 Jun 2024 18:35:14 -0300 Subject: [PATCH 34/60] Refactor: change command for cmd --- .../pages/ShortcutsPage/EditShortcutButton/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx index 3f596da57c..2596b32c13 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx @@ -141,7 +141,7 @@ export default function EditShortcutButton({ fixedKey = "Ctrl"; } if (e.key?.toLowerCase() === "meta") { - fixedKey = "Command"; + fixedKey = "Cmd"; } setKey((oldKey) => getFixedCombination({ oldKey: oldKey!, key: fixedKey }), @@ -156,7 +156,7 @@ export default function EditShortcutButton({ }, [key, setKey]); return ( - + Key Combination {children} -
+
{key === null ? shortcutInitialValue?.toUpperCase() From f4a8b310128895797b61e3c3c292659b33fdb2c3 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Sat, 8 Jun 2024 18:38:16 -0300 Subject: [PATCH 35/60] Remove console.log --- .../pages/ShortcutsPage/EditShortcutButton/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx index 2596b32c13..3388c5de03 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx @@ -113,8 +113,6 @@ export default function EditShortcutButton({ setKey(null); setSelected([]); } - console.log(key); - console.log(shortcutInitialValue); }, [open, setOpen, key]); function getFixedCombination({ From ce4550d2cea6b1ddd83b3b26daa5bd0238ed52d8 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Sat, 8 Jun 2024 19:20:32 -0300 Subject: [PATCH 36/60] Refactor: put freeze inside more --- src/frontend/src/constants/constants.ts | 5 ++ .../components/nodeToolbarComponent/index.tsx | 72 ++++++++++--------- .../toolbarSelectItem/index.tsx | 12 ++-- .../EditShortcutButton/index.tsx | 3 - src/frontend/src/stores/shortcuts.ts | 3 +- src/frontend/src/types/components/index.ts | 9 +-- src/frontend/src/types/store/index.ts | 1 + 7 files changed, 54 insertions(+), 51 deletions(-) diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index c0e258a714..312915eb55 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -804,6 +804,10 @@ export const defaultShortcuts = [ name: "Update", shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + U`, }, + { + name: "Freeze", + shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + F`, + }, ]; export const unavailableShortcutss = [ @@ -825,6 +829,7 @@ export const unavailableShortcutss = [ "CTRL + Y", "CTRL + J", "CTRL + U", + "CTRL + F", ]; export const DEFAULT_TABLE_ALERT_MSG = `Oops! It seems there's no data to display right now. Please check back later.`; diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index a7bed6cadd..02c9d9da92 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -148,6 +148,20 @@ export default function NodeToolbarComponent({ downloadNode(flowComponent!); } + function handleFreeze(e: KeyboardEvent) { + e.preventDefault(); + setNode(data.id, (old) => ({ + ...old, + data: { + ...old.data, + node: { + ...old.data.node, + frozen: old.data?.node?.frozen ? false : true, + }, + }, + })); + } + const advanced = useShortcutsStore((state) => state.advanced); const minimize = useShortcutsStore((state) => state.minimize); const share = useShortcutsStore((state) => state.share); @@ -157,6 +171,7 @@ export default function NodeToolbarComponent({ const group = useShortcutsStore((state) => state.group); const update = useShortcutsStore((state) => state.update); const download = useShortcutsStore((state) => state.download); + const freeze = useShortcutsStore((state) => state.freeze); useHotkeys(minimize, handleMinimizeWShortcut); useHotkeys(update, handleUpdateWShortcut); @@ -167,7 +182,7 @@ export default function NodeToolbarComponent({ useHotkeys(save, handleSaveWShortcut); useHotkeys(docs, handleDocsWShortcut); useHotkeys(download, handleDownloadWShortcut); - useHotkeys("space", handleCodeWShortcut); + useHotkeys(freeze, handleFreeze); const isMinimal = numberOfHandles <= 1; const isGroup = data.node?.flow ? true : false; @@ -233,6 +248,18 @@ export default function NodeToolbarComponent({ } saveComponent(cloneDeep(data), false); break; + case "freeze": + setNode(data.id, (old) => ({ + ...old, + data: { + ...old.data, + node: { + ...old.data.node, + frozen: old.data?.node?.frozen ? false : true, + }, + }, + })); + break; case "code": setOpenModal(!openModal); break; @@ -436,36 +463,6 @@ export default function NodeToolbarComponent({ - - - - From 40e977cc3c223a3087915f01287f4a3350965210 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Sat, 8 Jun 2024 23:41:40 -0300 Subject: [PATCH 42/60] Refactor: Improve code check to prevent bugs --- .../ShortcutsPage/EditShortcutButton/index.tsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx index 4780238cb9..976df035ae 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx @@ -123,13 +123,18 @@ export default function EditShortcutButton({ return `${oldKey.length > 0 ? toTitleCase(oldKey) : oldKey.toUpperCase()} + ${key.length > 0 ? toTitleCase(key) : key.toUpperCase()}`; } + function checkForKeys(keys: string, keyToCompare: string): boolean { + const keysArr = keys.split(" "); + let hasNewKey = false; + return keysArr.some( + (k) => k.toLowerCase().trim() === keyToCompare.toLowerCase().trim(), + ); + } + useEffect(() => { function onKeyDown(e: KeyboardEvent) { e.preventDefault(); let fixedKey = e.key; - if (key) { - if (key.toUpperCase().includes(e.key.toUpperCase())) return; - } if (e.key?.toLowerCase() === "control") { fixedKey = "Ctrl"; } @@ -139,8 +144,9 @@ export default function EditShortcutButton({ if (e.key?.toLowerCase() === " ") { fixedKey = "Space"; } - if (shortcutInitialValue?.toUpperCase().includes(fixedKey.toUpperCase())) - return; + if (key) { + if (checkForKeys(key, fixedKey)) return; + } setKey((oldKey) => getFixedCombination({ oldKey: oldKey!, key: fixedKey }), ); From e6147871eeb66c507cf9364bc6db9f1c8a6b4e08 Mon Sep 17 00:00:00 2001 From: ogabrielluiz Date: Sun, 9 Jun 2024 11:26:42 -0300 Subject: [PATCH 43/60] Refactor: Remove unnecessary isMac prop from toolbarSelectItem component and add IS_MAC constant --- .../components/menuBar/index.tsx | 10 +- src/frontend/src/constants/constants.ts | 36 +++--- .../components/nodeToolbarComponent/index.tsx | 34 ++---- .../toolbarSelectItem/index.tsx | 3 +- src/frontend/src/types/components/index.ts | 9 +- src/frontend/src/utils/reactflowUtils.ts | 109 +++++++++--------- 6 files changed, 93 insertions(+), 108 deletions(-) diff --git a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx index 35542ca2a8..9a0d54213f 100644 --- a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx +++ b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx @@ -9,7 +9,7 @@ import { import { useNavigate } from "react-router-dom"; import { UPLOAD_ERROR_ALERT } from "../../../../constants/alerts_constants"; -import { SAVED_HOVER } from "../../../../constants/constants"; +import { IS_MAC, SAVED_HOVER } from "../../../../constants/constants"; import ExportModal from "../../../../modals/exportModal"; import FlowLogsModal from "../../../../modals/flowLogsModal"; import FlowSettingsModal from "../../../../modals/flowSettingsModal"; @@ -113,7 +113,7 @@ export const MenuBar = ({}: {}): JSX.Element => { title: UPLOAD_ERROR_ALERT, list: [error], }); - }, + } ); }} > @@ -137,7 +137,7 @@ export const MenuBar = ({}: {}): JSX.Element => { > Undo - {navigator.userAgent.toUpperCase().includes("MAC") ? ( + {IS_MAC ? ( { > Redo - {navigator.userAgent.toUpperCase().includes("MAC") ? ( + {IS_MAC ? ( { name={isBuilding || saveLoading ? "Loader2" : "CheckCircle2"} className={cn( "h-4 w-4", - isBuilding || saveLoading ? "animate-spin" : "animate-wiggle", + isBuilding || saveLoading ? "animate-spin" : "animate-wiggle" )} /> {printByBuildStatus()} diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index bfbc93e18a..e13f1105ee 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -734,14 +734,16 @@ export const AUTHORIZED_DUPLICATE_REQUESTS = [ export const SAVE_DEBOUNCE_TIME = 300; +export const IS_MAC = navigator.userAgent.toUpperCase().includes("MAC"); + export const defaultShortcuts = [ { name: "Advanced Settings", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Shift + A`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Shift + A`, }, { name: "Minimize", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Q`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Q`, }, { name: "Code", @@ -749,23 +751,23 @@ export const defaultShortcuts = [ }, { name: "Copy", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + C`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + C`, }, { name: "Duplicate", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + D`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + D`, }, { name: "Share", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Shift + S`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Shift + S`, }, { name: "Docs", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Shift + D`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Shift + D`, }, { name: "Save", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + S`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + S`, }, { name: "Delete", @@ -773,43 +775,43 @@ export const defaultShortcuts = [ }, { name: "Open playground", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + K`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + K`, }, { name: "Undo", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Z`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Z`, }, { name: "Redo", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Y`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Y`, }, { name: "Group", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + G`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + G`, }, { name: "Cut", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + X`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + X`, }, { name: "Paste", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + V`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + V`, }, { name: "API", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + R`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + R`, }, { name: "Download", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + J`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + J`, }, { name: "Update", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + U`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + U`, }, { name: "Freeze", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + F`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + F`, }, ]; diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 013fa5e223..40dfa0066d 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -11,7 +11,6 @@ import { SelectItem, SelectTrigger, } from "../../../../components/ui/select-custom"; -import { postCustomComponent } from "../../../../controllers/API"; import ConfirmationModal from "../../../../modals/confirmationModal"; import EditNodeModal from "../../../../modals/editNodeModal"; import ShareModal from "../../../../modals/shareModal"; @@ -58,16 +57,14 @@ export default function NodeToolbarComponent({ data.node.template[templateField].type === "Any" || data.node.template[templateField].type === "int" || data.node.template[templateField].type === "dict" || - data.node.template[templateField].type === "NestedDict"), + data.node.template[templateField].type === "NestedDict") ).length; - const templates = useTypesStore((state) => state.templates); const hasStore = useStoreStore((state) => state.hasStore); const hasApiKey = useStoreStore((state) => state.hasApiKey); const validApiKey = useStoreStore((state) => state.validApiKey); const shortcuts = useShortcutsStore((state) => state.shortcuts); const unselectAll = useFlowStore((state) => state.unselectAll); - function handleMinimizeWShortcut(e: KeyboardEvent) { e.preventDefault(); if (isMinimal) { @@ -199,7 +196,7 @@ export default function NodeToolbarComponent({ const [showconfirmShare, setShowconfirmShare] = useState(false); const [showOverrideModal, setShowOverrideModal] = useState(false); const [flowComponent, setFlowComponent] = useState( - createFlowComponent(cloneDeep(data), version), + createFlowComponent(cloneDeep(data), version) ); // useEffect(() => { @@ -218,7 +215,7 @@ export default function NodeToolbarComponent({ const updateNodeInternals = useUpdateNodeInternals(); const setLastCopiedSelection = useFlowStore( - (state) => state.setLastCopiedSelection, + (state) => state.setLastCopiedSelection ); const setSuccessData = useAlertStore((state) => state.setSuccessData); @@ -292,7 +289,7 @@ export default function NodeToolbarComponent({ nodes, edges, setNodes, - setEdges, + setEdges ); break; case "override": @@ -316,20 +313,20 @@ export default function NodeToolbarComponent({ y: 10, paneX: nodes.find((node) => node.id === data.id)?.position.x, paneY: nodes.find((node) => node.id === data.id)?.position.y, - }, + } ); break; } }; const isSaved = flows.some((flow) => - Object.values(flow).includes(data.node?.display_name!), + Object.values(flow).includes(data.node?.display_name!) ); const setNode = useFlowStore((state) => state.setNode); const handleOnNewValue = ( - newValue: string | string[] | boolean | Object[], + newValue: string | string[] | boolean | Object[] ): void => { if (data.node!.template[name].value !== newValue) { takeSnapshot(); @@ -428,7 +425,7 @@ export default function NodeToolbarComponent({ @@ -477,7 +474,7 @@ export default function NodeToolbarComponent({
obj.name === "Code")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Code"} icon={"Code"} dataTestId="code-button-modal" @@ -509,7 +505,6 @@ export default function NodeToolbarComponent({ shortcuts.find((obj) => obj.name === "Advanced Settings") ?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Advanced"} icon={"Settings2"} dataTestId="edit-button-modal" @@ -521,7 +516,6 @@ export default function NodeToolbarComponent({ shortcut={ shortcuts.find((obj) => obj.name === "Save")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Save"} icon={"SaveAll"} dataTestId="save-button-modal" @@ -532,7 +526,6 @@ export default function NodeToolbarComponent({ shortcut={ shortcuts.find((obj) => obj.name === "Duplicate")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Duplicate"} icon={"Copy"} dataTestId="copy-button-modal" @@ -543,7 +536,6 @@ export default function NodeToolbarComponent({ shortcut={ shortcuts.find((obj) => obj.name === "Copy")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Copy"} icon={"Clipboard"} dataTestId="copy-button-modal" @@ -558,7 +550,6 @@ export default function NodeToolbarComponent({ shortcut={ shortcuts.find((obj) => obj.name === "Share")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Share"} icon={"Share3"} dataTestId="share-button-modal" @@ -572,7 +563,6 @@ export default function NodeToolbarComponent({ shortcuts.find((obj) => obj.name === "Download") ?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Download"} icon={"Download"} dataTestId="Download-button-modal" @@ -587,7 +577,6 @@ export default function NodeToolbarComponent({ shortcut={ shortcuts.find((obj) => obj.name === "Docs")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Docs"} icon={"FileText"} dataTestId="docs-button-modal" @@ -600,7 +589,6 @@ export default function NodeToolbarComponent({ shortcuts.find((obj) => obj.name === "Minimize") ?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={showNode ? "Minimize" : "Expand"} icon={showNode ? "Minimize2" : "Maximize2"} dataTestId="minimize-button-modal" @@ -613,7 +601,6 @@ export default function NodeToolbarComponent({ shortcut={ shortcuts.find((obj) => obj.name === "Group")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Ungroup"} icon={"Ungroup"} dataTestId="group-button-modal" @@ -625,7 +612,6 @@ export default function NodeToolbarComponent({ shortcut={ shortcuts.find((obj) => obj.name === "Freeze")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Freeze"} icon={"Snowflake"} dataTestId="group-button-modal" diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx index 1037824aed..38f56a7d5c 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx @@ -8,7 +8,6 @@ export default function ToolbarSelectItem({ dataTestId, ping, shortcut, - isMac, }: toolbarSelectItemProps) { let hasShift = false; const fixedShortcut = shortcut?.split("+"); @@ -18,7 +17,7 @@ export default function ToolbarSelectItem({ } }); const filteredShortcut = fixedShortcut.filter( - (key) => !key.toLowerCase().includes("shift"), + (key) => !key.toLowerCase().includes("shift") ); let shortcutWPlus = ""; if (!hasShift) shortcutWPlus = filteredShortcut.join("+"); diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts index dffa5b035a..8d1fef5d17 100644 --- a/src/frontend/src/types/components/index.ts +++ b/src/frontend/src/types/components/index.ts @@ -491,7 +491,7 @@ export type ChatInputType = { isDragging: boolean; files: FilePreviewType[]; setFiles: ( - files: FilePreviewType[] | ((prev: FilePreviewType[]) => FilePreviewType[]), + files: FilePreviewType[] | ((prev: FilePreviewType[]) => FilePreviewType[]) ) => void; chatValue: string; inputRef: { @@ -593,7 +593,7 @@ export type chatMessagePropsType = { updateChat: ( chat: ChatMessageType, message: string, - stream_url?: string, + stream_url?: string ) => void; }; @@ -685,12 +685,12 @@ export type codeTabsPropsType = { value: string, node: NodeType, template: TemplateVariableType, - tweak: tweakType, + tweak: tweakType ) => string; buildTweakObject?: ( tw: string, changes: string | string[] | boolean | number | Object[] | Object, - template: TemplateVariableType, + template: TemplateVariableType ) => Promise; }; activeTweaks?: boolean; @@ -772,7 +772,6 @@ export type IOFileInputProps = { }; export type toolbarSelectItemProps = { - isMac: boolean; value: string; icon: string; style?: string; diff --git a/src/frontend/src/utils/reactflowUtils.ts b/src/frontend/src/utils/reactflowUtils.ts index 161f7c70bc..4c267dc329 100644 --- a/src/frontend/src/utils/reactflowUtils.ts +++ b/src/frontend/src/utils/reactflowUtils.ts @@ -11,6 +11,7 @@ import ShortUniqueId from "short-unique-id"; import getFieldTitle from "../CustomNodes/utils/get-field-title"; import { INPUT_TYPES, + IS_MAC, LANGFLOW_SUPPORTED_TYPES, OUTPUT_TYPES, SUCCESS_BUILD, @@ -99,18 +100,18 @@ export function unselectAllNodes({ updateNodes, data }: unselectAllNodesType) { export function isValidConnection( { source, target, sourceHandle, targetHandle }: Connection, nodes: Node[], - edges: Edge[], + edges: Edge[] ) { const targetHandleObject: targetHandleType = scapeJSONParse(targetHandle!); const sourceHandleObject: sourceHandleType = scapeJSONParse(sourceHandle!); if ( targetHandleObject.inputTypes?.some( - (n) => n === sourceHandleObject.dataType, + (n) => n === sourceHandleObject.dataType ) || sourceHandleObject.baseClasses.some( (t) => targetHandleObject.inputTypes?.some((n) => n === t) || - t === targetHandleObject.type, + t === targetHandleObject.type ) ) { let targetNode = nodes.find((node) => node.id === target!)?.data?.node; @@ -143,7 +144,7 @@ export function removeApiKeys(flow: FlowType): FlowType { export function updateTemplate( reference: APITemplateType, - objectToUpdate: APITemplateType, + objectToUpdate: APITemplateType ): APITemplateType { let clonedObject: APITemplateType = cloneDeep(reference); @@ -203,7 +204,7 @@ export const processDataFromFlow = (flow: FlowType, refreshIds = true) => { export function updateIds( { edges, nodes }: { edges: Edge[]; nodes: Node[] }, - selection?: { edges: Edge[]; nodes: Node[] }, + selection?: { edges: Edge[]; nodes: Node[] } ) { let idsMap = {}; const selectionIds = selection?.nodes.map((n) => n.id); @@ -231,7 +232,7 @@ export function updateIds( edge.source = idsMap[edge.source]; edge.target = idsMap[edge.target]; const sourceHandleObject: sourceHandleType = scapeJSONParse( - edge.sourceHandle!, + edge.sourceHandle! ); edge.sourceHandle = scapedJSONStringfy({ ...sourceHandleObject, @@ -241,7 +242,7 @@ export function updateIds( edge.data.sourceHandle.id = edge.source; } const targetHandleObject: targetHandleType = scapeJSONParse( - edge.targetHandle!, + edge.targetHandle! ); edge.targetHandle = scapedJSONStringfy({ ...targetHandleObject, @@ -287,11 +288,11 @@ export function validateNode(node: NodeType, edges: Edge[]): Array { (scapeJSONParse(edge.targetHandle!) as targetHandleType).fieldName === t && (scapeJSONParse(edge.targetHandle!) as targetHandleType).id === - node.id, + node.id ) ) { errors.push( - `${displayName || type} is missing ${getFieldTitle(template, t)}.`, + `${displayName || type} is missing ${getFieldTitle(template, t)}.` ); } else if ( template[t].type === "dict" && @@ -305,15 +306,15 @@ export function validateNode(node: NodeType, edges: Edge[]): Array { errors.push( `${displayName || type} (${getFieldTitle( template, - t, - )}) contains duplicate keys with the same values.`, + t + )}) contains duplicate keys with the same values.` ); if (hasEmptyKey(template[t].value)) errors.push( `${displayName || type} (${getFieldTitle( template, - t, - )}) field must not be empty.`, + t + )}) field must not be empty.` ); } return errors; @@ -322,7 +323,7 @@ export function validateNode(node: NodeType, edges: Edge[]): Array { export function validateNodes( nodes: Node[], - edges: Edge[], + edges: Edge[] ): // this returns an array of tuples with the node id and the errors Array<{ id: string; errors: Array }> { if (nodes.length === 0) { @@ -343,7 +344,7 @@ export function updateEdges(edges: Edge[]) { if (edges) edges.forEach((edge) => { const targetHandleObject: targetHandleType = scapeJSONParse( - edge.targetHandle!, + edge.targetHandle! ); edge.className = ""; }); @@ -410,7 +411,7 @@ export function handleKeyDown( | React.KeyboardEvent | React.KeyboardEvent, inputValue: string | string[] | null, - block: string, + block: string ) { //condition to fix bug control+backspace on Windows/Linux if ( @@ -420,9 +421,7 @@ export function handleKeyDown( (inputValue === block || inputValue?.charAt(inputValue?.length - 1) === " " || specialCharsRegex.test(inputValue?.charAt(inputValue?.length - 1)))) || - (navigator.userAgent.toUpperCase().includes("MAC") && - e.ctrlKey === true && - e.key === "Backspace") + (IS_MAC && e.ctrlKey === true && e.key === "Backspace") ) { e.preventDefault(); e.stopPropagation(); @@ -435,7 +434,7 @@ export function handleKeyDown( } export function handleOnlyIntegerInput( - event: React.KeyboardEvent, + event: React.KeyboardEvent ) { if ( event.key === "." || @@ -451,7 +450,7 @@ export function handleOnlyIntegerInput( export function getConnectedNodes( edge: Edge, - nodes: Array, + nodes: Array ): Array { const sourceId = edge.source; const targetId = edge.target; @@ -552,7 +551,7 @@ export function checkOldEdgesHandles(edges: Edge[]): boolean { !edge.sourceHandle || !edge.targetHandle || !edge.sourceHandle.includes("{") || - !edge.targetHandle.includes("{"), + !edge.targetHandle.includes("{") ); } @@ -575,7 +574,7 @@ export function customStringify(obj: any): string { const keys = Object.keys(obj).sort(); const keyValuePairs = keys.map( - (key) => `"${key}":${customStringify(obj[key])}`, + (key) => `"${key}":${customStringify(obj[key])}` ); return `{${keyValuePairs.join(",")}}`; } @@ -604,7 +603,7 @@ export function getHandleId( source: string, sourceHandle: string, target: string, - targetHandle: string, + targetHandle: string ) { return ( "reactflow__edge-" + source + sourceHandle + "-" + target + targetHandle @@ -615,7 +614,7 @@ export function generateFlow( selection: OnSelectionChangeParams, nodes: Node[], edges: Edge[], - name: string, + name: string ): generateFlowType { const newFlowData = { nodes, edges, viewport: { zoom: 1, x: 0, y: 0 } }; const uid = new ShortUniqueId({ length: 5 }); @@ -624,7 +623,7 @@ export function generateFlow( newFlowData.edges = selection.edges.filter( (edge) => selection.nodes.some((node) => node.id === edge.target) && - selection.nodes.some((node) => node.id === edge.source), + selection.nodes.some((node) => node.id === edge.source) ); newFlowData.nodes = selection.nodes; @@ -645,7 +644,7 @@ export function generateFlow( (edge) => (selection.nodes.some((node) => node.id === edge.target) || selection.nodes.some((node) => node.id === edge.source)) && - newFlowData.edges.every((e) => e.id !== edge.id), + newFlowData.edges.every((e) => e.id !== edge.id) ), }; } @@ -656,13 +655,13 @@ export function reconnectEdges(groupNode: NodeType, excludedEdges: Edge[]) { const { nodes, edges } = groupNode.data.node!.flow!.data!; const lastNode = findLastNode(groupNode.data.node!.flow!.data!); newEdges = newEdges.filter( - (e) => !(nodes.some((n) => n.id === e.source) && e.source !== lastNode?.id), + (e) => !(nodes.some((n) => n.id === e.source) && e.source !== lastNode?.id) ); newEdges.forEach((edge) => { if (lastNode && edge.source === lastNode.id) { edge.source = groupNode.id; let newSourceHandle: sourceHandleType = scapeJSONParse( - edge.sourceHandle!, + edge.sourceHandle! ); newSourceHandle.id = groupNode.id; edge.sourceHandle = scapedJSONStringfy(newSourceHandle); @@ -689,7 +688,7 @@ export function reconnectEdges(groupNode: NodeType, excludedEdges: Edge[]) { export function filterFlow( selection: OnSelectionChangeParams, setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void, - setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void, + setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void ) { setNodes((nodes) => nodes.filter((node) => !selection.nodes.includes(node))); setEdges((edges) => edges.filter((edge) => !selection.edges.includes(edge))); @@ -727,7 +726,7 @@ export function updateFlowPosition(NewPosition: XYPosition, flow: FlowType) { export function concatFlows( flow: FlowType, setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void, - setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void, + setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void ) { const { nodes, edges } = flow.data!; setNodes((old) => [...old, ...nodes]); @@ -736,7 +735,7 @@ export function concatFlows( export function validateSelection( selection: OnSelectionChangeParams, - edges: Edge[], + edges: Edge[] ): Array { const clonedSelection = cloneDeep(selection); const clonedEdges = cloneDeep(edges); @@ -750,7 +749,7 @@ export function validateSelection( let nodesSet = new Set(clonedSelection.nodes.map((n) => n.id)); // then filter the edges that are connected to the nodes in the set let connectedEdges = clonedSelection.edges.filter( - (e) => nodesSet.has(e.source) && nodesSet.has(e.target), + (e) => nodesSet.has(e.source) && nodesSet.has(e.target) ); // add the edges to the selection clonedSelection.edges = connectedEdges; @@ -764,17 +763,17 @@ export function validateSelection( clonedSelection.nodes.some( (node) => isInputNode(node.data as NodeDataType) || - isOutputNode(node.data as NodeDataType), + isOutputNode(node.data as NodeDataType) ) ) { errorsArray.push( - "Please select only nodes that are not input or output nodes", + "Please select only nodes that are not input or output nodes" ); } //check if there are two or more nodes with free outputs if ( clonedSelection.nodes.filter( - (n) => !clonedSelection.edges.some((e) => e.source === n.id), + (n) => !clonedSelection.edges.some((e) => e.source === n.id) ).length > 1 ) { errorsArray.push("Please select only one node with free outputs"); @@ -785,7 +784,7 @@ export function validateSelection( clonedSelection.nodes.some( (node) => !clonedSelection.edges.some((edge) => edge.target === node.id) && - !clonedSelection.edges.some((edge) => edge.source === node.id), + !clonedSelection.edges.some((edge) => edge.source === node.id) ) ) { errorsArray.push("Please select only nodes that are connected"); @@ -842,8 +841,8 @@ export function mergeNodeTemplates({ nodeTemplate[key].display_name ? nodeTemplate[key].display_name : nodeTemplate[key].name - ? toTitleCase(nodeTemplate[key].name) - : toTitleCase(key); + ? toTitleCase(nodeTemplate[key].name) + : toTitleCase(key); } } }); @@ -854,7 +853,7 @@ function isHandleConnected( edges: Edge[], key: string, field: TemplateVariableType, - nodeId: string, + nodeId: string ) { /* this function receives a flow and a handleId and check if there is a connection with this handle @@ -870,7 +869,7 @@ function isHandleConnected( id: nodeId, proxy: { id: field.proxy!.id, field: field.proxy!.field }, inputTypes: field.input_types, - } as targetHandleType), + } as targetHandleType) ) ) { return true; @@ -885,7 +884,7 @@ function isHandleConnected( fieldName: key, id: nodeId, inputTypes: field.input_types, - } as targetHandleType), + } as targetHandleType) ) ) { return true; @@ -908,7 +907,7 @@ export function generateNodeTemplate(Flow: FlowType) { export function generateNodeFromFlow( flow: FlowType, - getNodeId: (type: string) => string, + getNodeId: (type: string) => string ): NodeType { const { nodes } = flow.data!; const outputNode = cloneDeep(findLastNode(flow.data!)); @@ -939,7 +938,7 @@ export function generateNodeFromFlow( export function connectedInputNodesOnHandle( nodeId: string, handleId: string, - { nodes, edges }: { nodes: NodeType[]; edges: Edge[] }, + { nodes, edges }: { nodes: NodeType[]; edges: Edge[] } ) { const connectedNodes: Array<{ name: string; id: string; isGroup: boolean }> = []; @@ -976,7 +975,7 @@ export function connectedInputNodesOnHandle( export function updateProxyIdsOnTemplate( template: APITemplateType, - idsMap: { [key: string]: string }, + idsMap: { [key: string]: string } ) { Object.keys(template).forEach((key) => { if (template[key].proxy && idsMap[template[key].proxy!.id]) { @@ -987,7 +986,7 @@ export function updateProxyIdsOnTemplate( export function updateEdgesIds( edges: Edge[], - idsMap: { [key: string]: string }, + idsMap: { [key: string]: string } ) { edges.forEach((edge) => { let targetHandle: targetHandleType = edge.data.targetHandle; @@ -1014,7 +1013,7 @@ export function expandGroupNode( nodes: Node[], edges: Edge[], setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void, - setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void, + setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void ) { const idsMap = updateIds(flow!.data!); updateProxyIdsOnTemplate(template, idsMap); @@ -1057,7 +1056,7 @@ export function expandGroupNode( const lastNode = cloneDeep(findLastNode(flow!.data!)); newEdge.source = lastNode!.id; let newSourceHandle: sourceHandleType = scapeJSONParse( - newEdge.sourceHandle!, + newEdge.sourceHandle! ); newSourceHandle.id = lastNode!.id; newEdge.data.sourceHandle = newSourceHandle; @@ -1114,7 +1113,7 @@ export function expandGroupNode( export function getGroupStatus( flow: FlowType, - ssData: { [key: string]: { valid: boolean; params: string } }, + ssData: { [key: string]: { valid: boolean; params: string } } ) { let status = { valid: true, params: SUCCESS_BUILD }; const { nodes } = flow.data!; @@ -1133,7 +1132,7 @@ export function getGroupStatus( export function createFlowComponent( nodeData: NodeDataType, - version: string, + version: string ): FlowType { const flowNode: FlowType = { data: { @@ -1169,7 +1168,7 @@ export function downloadNode(NodeFLow: FlowType) { export function updateComponentNameAndType( data: any, - component: NodeDataType, + component: NodeDataType ) {} export function removeFileNameFromComponents(flow: FlowType) { @@ -1243,7 +1242,7 @@ export function extractFieldsFromComponenents(data: APIObjectType) { export function downloadFlow( flow: FlowType, flowName: string, - flowDescription?: string, + flowDescription?: string ) { let clonedFlow = cloneDeep(flow); removeFileNameFromComponents(clonedFlow); @@ -1253,7 +1252,7 @@ export function downloadFlow( ...clonedFlow, name: flowName, description: flowDescription, - }), + }) )}`; // create a link element and set its properties @@ -1268,7 +1267,7 @@ export function downloadFlow( export function downloadFlows() { downloadFlowsFromDatabase().then((flows) => { const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent( - JSON.stringify(flows), + JSON.stringify(flows) )}`; // create a link element and set its properties @@ -1292,7 +1291,7 @@ export function getRandomDescription(): string { export const createNewFlow = ( flowData: ReactFlowJsonObject, flow: FlowType, - folderId: string, + folderId: string ) => { return { description: flow?.description ?? getRandomDescription(), From b99a82e81f9935722df66e66e38e7fcfb12d300f Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Sun, 9 Jun 2024 12:27:08 -0300 Subject: [PATCH 44/60] Fix: shortcuts not saving properly --- .../headerComponent/components/menuBar/index.tsx | 14 ++++++++++---- .../toolbarSelectItem/index.tsx | 6 ++++-- src/frontend/src/stores/shortcuts.ts | 7 +++++++ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx index 35542ca2a8..6babcf5fdd 100644 --- a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx +++ b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx @@ -20,8 +20,10 @@ import { cn } from "../../../../utils/utils"; import IconComponent from "../../../genericIconComponent"; import ShadTooltip from "../../../shadTooltipComponent"; import { Button } from "../../../ui/button"; +import { useShortcutsStore } from "../../../../stores/shortcuts"; export const MenuBar = ({}: {}): JSX.Element => { + const shortcuts = useShortcutsStore((state) => state.shortcuts); const addFlow = useFlowsManagerStore((state) => state.addFlow); const currentFlow = useFlowsManagerStore((state) => state.currentFlow); const setErrorData = useAlertStore((state) => state.setErrorData); @@ -144,10 +146,12 @@ export const MenuBar = ({}: {}): JSX.Element => { /> ) : ( - Ctrl +{" "} + { + shortcuts.find((s) => s.name.toLowerCase() === "undo") + ?.shortcut + } )} - Z { @@ -164,10 +168,12 @@ export const MenuBar = ({}: {}): JSX.Element => { /> ) : ( - Ctrl +{" "} + { + shortcuts.find((s) => s.name.toLowerCase() === "redo") + ?.shortcut + } )} - Y diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx index 1037824aed..1db08834fd 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx @@ -27,11 +27,13 @@ export default function ToolbarSelectItem({
- {value} + + {value} + {hasShift ? ( <> diff --git a/src/frontend/src/stores/shortcuts.ts b/src/frontend/src/stores/shortcuts.ts index 8b60fc50b1..87dc21453c 100644 --- a/src/frontend/src/stores/shortcuts.ts +++ b/src/frontend/src/stores/shortcuts.ts @@ -39,6 +39,13 @@ export const useShortcutsStore = create((set, get) => ({ if (localStorage.getItem("langflow-shortcuts")) { const savedShortcuts = localStorage.getItem("langflow-shortcuts"); const savedUShortcuts = localStorage.getItem("langflow-UShortcuts"); + const savedArr = JSON.parse(savedShortcuts!); + savedArr.forEach(({ name, shortcut }) => { + let shortcutName = name.split(" ")[0].toLowerCase(); + set({ + [shortcutName]: shortcut, + }); + }); get().setShortcuts( JSON.parse(savedShortcuts!), JSON.parse(savedUShortcuts!), From d372a8eb932dd26af93717d5a05175ccad9c66e7 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Sun, 9 Jun 2024 13:23:44 -0300 Subject: [PATCH 45/60] Fix: add panActivationKeyCode to reactFLow to prevent pan bugs --- .../src/pages/FlowPage/components/PageComponent/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index b0aa8749ad..daec3f29a8 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -484,6 +484,7 @@ export default function Page({ zoomOnScroll={!view} zoomOnPinch={!view} panOnDrag={!view} + panActivationKeyCode={""} proOptions={{ hideAttribution: true }} onPaneClick={onPaneClick} > From 9d73489ea9799d5d1c57c2c500d598cf31b939aa Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Sun, 9 Jun 2024 13:40:00 -0300 Subject: [PATCH 46/60] Refactor: remove cache before saving shortcuts --- .../pages/ShortcutsPage/EditShortcutButton/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx index 976df035ae..99dd435546 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx @@ -86,6 +86,8 @@ export default function EditShortcutButton({ title: `${shortcut[0]} shortcut successfully changed`, }); setKey(null); + localStorage.removeItem("langflow-shortcuts"); + localStorage.removeItem("langflow-UShortcuts"); localStorage.setItem( "langflow-shortcuts", JSON.stringify(newCombination), From 3541101047a7aa4bc49f395b3ef8418cf503a235 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Sun, 9 Jun 2024 14:49:06 -0300 Subject: [PATCH 47/60] Refactor: Use a single array of shortcuts to prevent bugs on MACOS --- src/frontend/src/constants/constants.ts | 21 ------------- .../EditShortcutButton/index.tsx | 31 +++++-------------- .../pages/ShortcutsPage/index.tsx | 8 ++--- src/frontend/src/stores/shortcuts.ts | 16 +++------- src/frontend/src/types/store/index.ts | 2 -- src/frontend/src/utils/styleUtils.ts | 1 - 6 files changed, 14 insertions(+), 65 deletions(-) diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index e13f1105ee..6bb0656f5b 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -815,27 +815,6 @@ export const defaultShortcuts = [ }, ]; -export const unavailableShortcutss = [ - "CTRL + R", - "CTRL + V", - "CTRL + X", - "CTRL + G", - "CTRL + SHIFT + A", - "CTRL + Q", - "CTRL + SHIFT + U", - "CTRL + C", - "CTRL + D", - "CTRL + SHIFT + S", - "CTRL + SHIFT + D", - "CTRL + S", - "BACKSPACE", - "CTRL + K", - "CTRL + Z", - "CTRL + Y", - "CTRL + J", - "CTRL + U", - "CTRL + F", -]; export const DEFAULT_TABLE_ALERT_MSG = `Oops! It seems there's no data to display right now. Please check back later.`; export const DEFAULT_TABLE_ALERT_TITLE = "No Data Available"; diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx index 99dd435546..652a3c8db3 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/EditShortcutButton/index.tsx @@ -37,15 +37,12 @@ export default function EditShortcutButton({ const [key, setKey] = useState(null); const setSuccessData = useAlertStore((state) => state.setSuccessData); const setShortcuts = useShortcutsStore((state) => state.setShortcuts); - const unavaliableShortcuts = useShortcutsStore( - (state) => state.unavailableShortcuts, - ); const setErrorData = useAlertStore((state) => state.setErrorData); function canEditCombination(newCombination: string): boolean { let canSave = true; - unavaliableShortcuts.forEach((s) => { - if (s.toLowerCase() === newCombination.toLowerCase()) { + defaultShortcuts.forEach(({ shortcut }) => { + if (shortcut.toLowerCase() === newCombination.toLowerCase()) { canSave = false; } }); @@ -65,11 +62,6 @@ export default function EditShortcutButton({ } return { name: s.name, shortcut: s.shortcut }; }); - const unavailable = unavaliableShortcuts.map((s) => { - if (s.toLowerCase() === defaultCombination.toLowerCase()) - return (s = key.toUpperCase()); - return s; - }); const fixCombination = key.split(" "); if ( fixCombination[0].toLowerCase().includes("ctrl") || @@ -79,23 +71,16 @@ export default function EditShortcutButton({ } const shortcutName = shortcut[0].split(" ")[0].toLowerCase(); setUniqueShortcut(shortcutName, fixCombination.join("").toLowerCase()); - console.log(newCombination); - setShortcuts(newCombination, unavailable); - setOpen(false); - setSuccessData({ - title: `${shortcut[0]} shortcut successfully changed`, - }); - setKey(null); - localStorage.removeItem("langflow-shortcuts"); - localStorage.removeItem("langflow-UShortcuts"); + setShortcuts(newCombination); localStorage.setItem( "langflow-shortcuts", JSON.stringify(newCombination), ); - localStorage.setItem( - "langflow-UShortcuts", - JSON.stringify(unavailable), - ); + setKey(null); + setOpen(false); + setSuccessData({ + title: `${shortcut[0]} shortcut successfully changed`, + }); return; } } diff --git a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx index d26c13c180..83d51ee53a 100644 --- a/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/ShortcutsPage/index.tsx @@ -3,10 +3,7 @@ import { useEffect, useState } from "react"; import ForwardedIconComponent from "../../../../components/genericIconComponent"; import TableComponent from "../../../../components/tableComponent"; import { Button } from "../../../../components/ui/button"; -import { - defaultShortcuts, - unavailableShortcutss, -} from "../../../../constants/constants"; +import { defaultShortcuts } from "../../../../constants/constants"; import { useShortcutsStore } from "../../../../stores/shortcuts"; import EditShortcutButton from "./EditShortcutButton"; @@ -45,9 +42,8 @@ export default function ShortcutsPage() { const [open, setOpen] = useState(false); function handleRestore() { - setShortcuts(defaultShortcuts, unavailableShortcutss); + setShortcuts(defaultShortcuts); localStorage.removeItem("langflow-shortcuts"); - localStorage.removeItem("langflow-UShortcuts"); } return ( diff --git a/src/frontend/src/stores/shortcuts.ts b/src/frontend/src/stores/shortcuts.ts index 87dc21453c..09970b42e9 100644 --- a/src/frontend/src/stores/shortcuts.ts +++ b/src/frontend/src/stores/shortcuts.ts @@ -1,15 +1,11 @@ import { create } from "zustand"; -import { - defaultShortcuts, - unavailableShortcutss, -} from "../constants/constants"; +import { defaultShortcuts } from "../constants/constants"; import { shortcutsStoreType } from "../types/store"; export const useShortcutsStore = create((set, get) => ({ - unavailableShortcuts: unavailableShortcutss, shortcuts: defaultShortcuts, - setShortcuts: (newShortcuts, unavailable) => { - set({ shortcuts: newShortcuts, unavailableShortcuts: unavailable }); + setShortcuts: (newShortcuts) => { + set({ shortcuts: newShortcuts }); }, undo: "mod+z", redo: "mod+y", @@ -38,7 +34,6 @@ export const useShortcutsStore = create((set, get) => ({ getShortcutsFromStorage: () => { if (localStorage.getItem("langflow-shortcuts")) { const savedShortcuts = localStorage.getItem("langflow-shortcuts"); - const savedUShortcuts = localStorage.getItem("langflow-UShortcuts"); const savedArr = JSON.parse(savedShortcuts!); savedArr.forEach(({ name, shortcut }) => { let shortcutName = name.split(" ")[0].toLowerCase(); @@ -46,10 +41,7 @@ export const useShortcutsStore = create((set, get) => ({ [shortcutName]: shortcut, }); }); - get().setShortcuts( - JSON.parse(savedShortcuts!), - JSON.parse(savedUShortcuts!), - ); + get().setShortcuts(JSON.parse(savedShortcuts!)); } }, })); diff --git a/src/frontend/src/types/store/index.ts b/src/frontend/src/types/store/index.ts index 8426654798..143e1b26bc 100644 --- a/src/frontend/src/types/store/index.ts +++ b/src/frontend/src/types/store/index.ts @@ -44,10 +44,8 @@ export type shortcutsStoreType = { name: string; shortcut: string; }>; - unavailableShortcuts: string[]; setShortcuts: ( newShortcuts: Array<{ name: string; shortcut: string }>, - unavailable: string[], ) => void; getShortcutsFromStorage: () => void; }; diff --git a/src/frontend/src/utils/styleUtils.ts b/src/frontend/src/utils/styleUtils.ts index b7e5995c67..123702b608 100644 --- a/src/frontend/src/utils/styleUtils.ts +++ b/src/frontend/src/utils/styleUtils.ts @@ -541,7 +541,6 @@ export const nodeIconsLucide: iconsType = { FolderIcon, Discord: FaDiscord, PaperclipIcon, - RotateCcw, Settings, Streamlit, }; From 81a29da787e1ff56e02202675e739d167fcf3f50 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Sun, 9 Jun 2024 15:36:57 -0300 Subject: [PATCH 48/60] Fix: API modal not opening with shortcut --- src/frontend/src/components/chatComponent/index.tsx | 2 ++ src/frontend/src/modals/apiModal/views/index.tsx | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 4ef0c1cf25..20c6868113 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -15,6 +15,8 @@ import { Separator } from "../ui/separator"; export default function FlowToolbar(): JSX.Element { function handleAPIWShortcut(e: KeyboardEvent) { e.preventDefault(); + console.log("oi"); + console.log(openCodeModal); setOpenCodeModal((oldOpen) => !oldOpen); } diff --git a/src/frontend/src/modals/apiModal/views/index.tsx b/src/frontend/src/modals/apiModal/views/index.tsx index 59b3c13ee6..0a9c32ee69 100644 --- a/src/frontend/src/modals/apiModal/views/index.tsx +++ b/src/frontend/src/modals/apiModal/views/index.tsx @@ -31,9 +31,13 @@ const ApiModal = forwardRef( { flow, children, + open: myOpen, + setOpen: mySetOpen, }: { flow: FlowType; children: ReactNode; + open: boolean; + setOpen: (a: boolean | ((o?: boolean) => boolean)) => void; }, ref, ) => { @@ -44,7 +48,10 @@ const ApiModal = forwardRef( const [activeTweaks, setActiveTweaks] = useState(false); const { autoLogin } = useContext(AuthContext); - const [open, setOpen] = useState(false); + const [open, setOpen] = + mySetOpen !== undefined && myOpen !== undefined + ? [myOpen, mySetOpen] + : useState(false); const [activeTab, setActiveTab] = useState("0"); const pythonApiCode = getPythonApiCode( flow?.id, From 71525cfe475488444116ce042c9a66e09ec3c3b6 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Sun, 9 Jun 2024 16:00:36 -0300 Subject: [PATCH 49/60] Remove console.log --- src/frontend/src/components/chatComponent/index.tsx | 2 -- src/frontend/src/modals/apiModal/views/index.tsx | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 20c6868113..4ef0c1cf25 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -15,8 +15,6 @@ import { Separator } from "../ui/separator"; export default function FlowToolbar(): JSX.Element { function handleAPIWShortcut(e: KeyboardEvent) { e.preventDefault(); - console.log("oi"); - console.log(openCodeModal); setOpenCodeModal((oldOpen) => !oldOpen); } diff --git a/src/frontend/src/modals/apiModal/views/index.tsx b/src/frontend/src/modals/apiModal/views/index.tsx index 0a9c32ee69..3b41103f93 100644 --- a/src/frontend/src/modals/apiModal/views/index.tsx +++ b/src/frontend/src/modals/apiModal/views/index.tsx @@ -36,8 +36,8 @@ const ApiModal = forwardRef( }: { flow: FlowType; children: ReactNode; - open: boolean; - setOpen: (a: boolean | ((o?: boolean) => boolean)) => void; + open?: boolean; + setOpen?: (a: boolean | ((o?: boolean) => boolean)) => void; }, ref, ) => { From 4fd9677fb6b6150c5da806cccee8f8e056c18e14 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Sun, 9 Jun 2024 16:50:57 -0300 Subject: [PATCH 50/60] Feat: add shortcut to open flow Share modal --- .../src/components/chatComponent/index.tsx | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/frontend/src/components/chatComponent/index.tsx b/src/frontend/src/components/chatComponent/index.tsx index 4ef0c1cf25..6fc0da4b95 100644 --- a/src/frontend/src/components/chatComponent/index.tsx +++ b/src/frontend/src/components/chatComponent/index.tsx @@ -13,25 +13,32 @@ import ForwardedIconComponent from "../genericIconComponent"; import { Separator } from "../ui/separator"; export default function FlowToolbar(): JSX.Element { + const preventDefault = true; function handleAPIWShortcut(e: KeyboardEvent) { - e.preventDefault(); setOpenCodeModal((oldOpen) => !oldOpen); } function handleChatWShortcut(e: KeyboardEvent) { if (useFlowStore.getState().hasIO) { - e.preventDefault(); setOpen((oldState) => !oldState); } } + function handleShareWShortcut(e: KeyboardEvent) { + setOpenShareModal((oldState) => !oldState); + } + const openPlayground = useShortcutsStore((state) => state.open); const api = useShortcutsStore((state) => state.api); + const share = useShortcutsStore((state) => state.share); + + useHotkeys(openPlayground, handleChatWShortcut, { preventDefault }); + useHotkeys(api, handleAPIWShortcut, { preventDefault }); + useHotkeys(share, handleShareWShortcut, { preventDefault }); - useHotkeys(openPlayground, handleChatWShortcut); - useHotkeys(api, handleAPIWShortcut); - const [open, setOpen] = useState(false); + const [open, setOpen] = useState(false); const [openCodeModal, setOpenCodeModal] = useState(false); + const [openShareModal, setOpenShareModal] = useState(false); const hasIO = useFlowStore((state) => state.hasIO); const hasStore = useStoreStore((state) => state.hasStore); @@ -47,6 +54,8 @@ export default function FlowToolbar(): JSX.Element { is_component={false} component={currentFlow!} disabled={!hasApiKey || !validApiKey || !hasStore} + open={openShareModal} + setOpen={setOpen} > */} - + name.split(" ")[0].toLowerCase() === "freeze", + )!, + )} + side="top" + > @@ -468,13 +529,13 @@ export default function NodeToolbarComponent({ */}