From 5e8cec40c9b5bbf62577c6f158046611c89f58c3 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Wed, 15 May 2024 21:51:32 -0300 Subject: [PATCH 01/12] Refactor utils file --- src/frontend/src/App.tsx | 14 +- .../addNewVariableButton.tsx | 2 +- .../components/inputGlobalComponent/index.tsx | 2 +- .../components/parameterComponent/index.tsx | 3 +- .../utils/group-by-family.tsx | 119 +++++++++++++++ .../src/modals/genericModal/index.tsx | 9 +- .../genericModal/utils/var-highlight-html.tsx | 6 + .../components/PageComponent/index.tsx | 3 +- .../utils/is-wrapped-with-class.tsx | 4 + .../pages/GlobalVariablesPage/index.tsx | 2 +- .../globalVariables.ts | 6 +- .../utils/get-unavailable-fields.tsx | 13 ++ src/frontend/src/utils/reactflowUtils.ts | 16 +- src/frontend/src/utils/utils.ts | 138 +----------------- 14 files changed, 175 insertions(+), 162 deletions(-) create mode 100644 src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx create mode 100644 src/frontend/src/modals/genericModal/utils/var-highlight-html.tsx create mode 100644 src/frontend/src/pages/FlowPage/components/PageComponent/utils/is-wrapped-with-class.tsx rename src/frontend/src/stores/{ => globalVariablesStore}/globalVariables.ts (91%) create mode 100644 src/frontend/src/stores/globalVariablesStore/utils/get-unavailable-fields.tsx diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index 2d8fc3caa..88d990c93 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -19,15 +19,15 @@ import Router from "./routes"; import useAlertStore from "./stores/alertStore"; import { useDarkStore } from "./stores/darkStore"; import useFlowsManagerStore from "./stores/flowsManagerStore"; -import { useGlobalVariablesStore } from "./stores/globalVariables"; +import { useGlobalVariablesStore } from "./stores/globalVariablesStore/globalVariables"; import { useStoreStore } from "./stores/storeStore"; import { useTypesStore } from "./stores/typesStore"; export default function App() { const removeFromTempNotificationList = useAlertStore( - (state) => state.removeFromTempNotificationList + (state) => state.removeFromTempNotificationList, ); const tempNotificationList = useAlertStore( - (state) => state.tempNotificationList + (state) => state.tempNotificationList, ); const [fetchError, setFetchError] = useState(false); const isLoading = useFlowsManagerStore((state) => state.isLoading); @@ -45,10 +45,10 @@ export default function App() { const refreshVersion = useDarkStore((state) => state.refreshVersion); const refreshStars = useDarkStore((state) => state.refreshStars); const setGlobalVariables = useGlobalVariablesStore( - (state) => state.setGlobalVariables + (state) => state.setGlobalVariables, ); const setUnavailableFields = useGlobalVariablesStore( - (state) => state.setUnavaliableFields + (state) => state.setUnavaliableFields, ); const checkHasStore = useStoreStore((state) => state.checkHasStore); const navigate = useNavigate(); @@ -92,8 +92,8 @@ export default function App() { } }); - /* - Abort the request as it isn't needed anymore, the component being + /* + Abort the request as it isn't needed anymore, the component being unmounted. It helps avoid, among other things, the well-known "can't perform a React state update on an unmounted component" warning. */ diff --git a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx index 2745ba1bf..1ea7142ab 100644 --- a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx +++ b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx @@ -2,7 +2,7 @@ import { useState } from "react"; import { registerGlobalVariable } from "../../controllers/API"; import BaseModal from "../../modals/baseModal"; import useAlertStore from "../../stores/alertStore"; -import { useGlobalVariablesStore } from "../../stores/globalVariables"; +import { useGlobalVariablesStore } from "../../stores/globalVariablesStore/globalVariables"; import { useTypesStore } from "../../stores/typesStore"; import { ResponseErrorDetailAPI } from "../../types/api"; import { sortByName } from "../../utils/utils"; diff --git a/src/frontend/src/components/inputGlobalComponent/index.tsx b/src/frontend/src/components/inputGlobalComponent/index.tsx index 2ca1aed22..7ab3cae33 100644 --- a/src/frontend/src/components/inputGlobalComponent/index.tsx +++ b/src/frontend/src/components/inputGlobalComponent/index.tsx @@ -2,7 +2,7 @@ import { useEffect } from "react"; import { deleteGlobalVariable } from "../../controllers/API"; import DeleteConfirmationModal from "../../modals/deleteConfirmationModal"; import useAlertStore from "../../stores/alertStore"; -import { useGlobalVariablesStore } from "../../stores/globalVariables"; +import { useGlobalVariablesStore } from "../../stores/globalVariablesStore/globalVariables"; import { InputGlobalComponentType } from "../../types/components"; import { cn } from "../../utils/utils"; import AddNewVariableButton from "../addNewVariableButtonComponent/addNewVariableButton"; diff --git a/src/frontend/src/customNodes/genericNode/components/parameterComponent/index.tsx b/src/frontend/src/customNodes/genericNode/components/parameterComponent/index.tsx index dbcb1e3dc..c77d7308c 100644 --- a/src/frontend/src/customNodes/genericNode/components/parameterComponent/index.tsx +++ b/src/frontend/src/customNodes/genericNode/components/parameterComponent/index.tsx @@ -49,7 +49,8 @@ import { nodeIconsLucide, nodeNames, } from "../../../../utils/styleUtils"; -import { classNames, groupByFamily } from "../../../../utils/utils"; +import { classNames } from "../../../../utils/utils"; +import groupByFamily from "./utils/group-by-family"; export default function ParameterComponent({ left, diff --git a/src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx b/src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx new file mode 100644 index 000000000..a38a31b59 --- /dev/null +++ b/src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx @@ -0,0 +1,119 @@ +import { APIDataType, TemplateVariableType } from "../../../../../types/api"; +import { + groupedObjType, + nodeGroupedObjType, +} from "../../../../../types/components"; +import { NodeType } from "../../../../../types/flow"; + +export default function groupByFamily( + data: APIDataType, + baseClasses: string, + left: boolean, + flow?: NodeType[], +): groupedObjType[] { + const baseClassesSet = new Set(baseClasses.split("\n")); + let arrOfPossibleInputs: Array<{ + category: string; + nodes: nodeGroupedObjType[]; + full: boolean; + display_name?: string; + }> = []; + let arrOfPossibleOutputs: Array<{ + category: string; + nodes: nodeGroupedObjType[]; + full: boolean; + display_name?: string; + }> = []; + let checkedNodes = new Map(); + const excludeTypes = new Set(["bool", "float", "code", "file", "int"]); + + const checkBaseClass = (template: TemplateVariableType) => { + return ( + template.type && + template.show && + ((!excludeTypes.has(template.type) && + baseClassesSet.has(template.type)) || + (template.input_types && + template.input_types.some((inputType) => + baseClassesSet.has(inputType), + ))) + ); + }; + + if (flow) { + // se existir o flow + for (const node of flow) { + // para cada node do flow + if (node!.data!.node!.flow || !node!.data!.node!.template) break; // não faz nada se o node for um group + const nodeData = node.data; + + const foundNode = checkedNodes.get(nodeData.type); // verifica se o tipo do node já foi checado + checkedNodes.set(nodeData.type, { + hasBaseClassInTemplate: + foundNode?.hasBaseClassInTemplate || + Object.values(nodeData.node!.template).some(checkBaseClass), + hasBaseClassInBaseClasses: + foundNode?.hasBaseClassInBaseClasses || + nodeData.node!.base_classes.some((baseClass) => + baseClassesSet.has(baseClass), + ), //seta como anterior ou verifica se o node tem base class + displayName: nodeData.node?.display_name, + }); + } + } + + for (const [d, nodes] of Object.entries(data)) { + let tempInputs: nodeGroupedObjType[] = [], + tempOutputs: nodeGroupedObjType[] = []; + + for (const [n, node] of Object.entries(nodes!)) { + let foundNode = checkedNodes.get(n); + + if (!foundNode) { + foundNode = { + hasBaseClassInTemplate: Object.values(node!.template).some( + checkBaseClass, + ), + hasBaseClassInBaseClasses: node!.base_classes.some((baseClass) => + baseClassesSet.has(baseClass), + ), + displayName: node?.display_name, + }; + } + + if (foundNode.hasBaseClassInTemplate) + tempInputs.push({ node: n, displayName: foundNode.displayName }); + if (foundNode.hasBaseClassInBaseClasses) + tempOutputs.push({ node: n, displayName: foundNode.displayName }); + } + + const totalNodes = Object.keys(nodes!).length; + + if (tempInputs.length) + arrOfPossibleInputs.push({ + category: d, + nodes: tempInputs, + full: tempInputs.length === totalNodes, + }); + if (tempOutputs.length) + arrOfPossibleOutputs.push({ + category: d, + nodes: tempOutputs, + full: tempOutputs.length === totalNodes, + }); + } + + return left + ? arrOfPossibleOutputs.map((output) => ({ + family: output.category, + type: output.full + ? "" + : output.nodes.map((item) => item.node).join(", "), + display_name: "", + })) + : arrOfPossibleInputs.map((input) => ({ + family: input.category, + type: input.full ? "" : input.nodes.map((item) => item.node).join(", "), + display_name: input.nodes.map((item) => item.displayName).join(", "), + })); +} diff --git a/src/frontend/src/modals/genericModal/index.tsx b/src/frontend/src/modals/genericModal/index.tsx index 02000df4d..0e111c548 100644 --- a/src/frontend/src/modals/genericModal/index.tsx +++ b/src/frontend/src/modals/genericModal/index.tsx @@ -24,8 +24,9 @@ import { postValidatePrompt } from "../../controllers/API"; import useAlertStore from "../../stores/alertStore"; import { genericModalPropsType } from "../../types/components"; import { handleKeyDown } from "../../utils/reactflowUtils"; -import { classNames, varHighlightHTML } from "../../utils/utils"; +import { classNames } from "../../utils/utils"; import BaseModal from "../baseModal"; +import varHighlightHTML from "./utils/var-highlight-html"; export default function GenericModal({ field_name = "", @@ -82,7 +83,7 @@ export default function GenericModal({ } const filteredWordsHighlight = matches.filter( - (word) => !invalid_chars.includes(word) + (word) => !invalid_chars.includes(word), ); setWordsHighlight(filteredWordsHighlight); @@ -133,7 +134,7 @@ export default function GenericModal({ // to the first key of the custom_fields object if (field_name === "") { field_name = Array.isArray( - apiReturn.data?.frontend_node?.custom_fields?.[""] + apiReturn.data?.frontend_node?.custom_fields?.[""], ) ? apiReturn.data?.frontend_node?.custom_fields?.[""][0] ?? "" : apiReturn.data?.frontend_node?.custom_fields?.[""] ?? ""; @@ -209,7 +210,7 @@ export default function GenericModal({
{type === TypeModal.PROMPT && isEdit && !readonly ? ( diff --git a/src/frontend/src/modals/genericModal/utils/var-highlight-html.tsx b/src/frontend/src/modals/genericModal/utils/var-highlight-html.tsx new file mode 100644 index 000000000..d88be4965 --- /dev/null +++ b/src/frontend/src/modals/genericModal/utils/var-highlight-html.tsx @@ -0,0 +1,6 @@ +import { IVarHighlightType } from "../../../types/components"; + +export default function varHighlightHTML({ name }: IVarHighlightType): string { + const html = `{${name}}`; + return html; +} diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index bc0a0e362..3a456f540 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -34,9 +34,10 @@ import { updateIds, validateSelection, } from "../../../../utils/reactflowUtils"; -import { getRandomName, isWrappedWithClass } from "../../../../utils/utils"; +import { getRandomName } from "../../../../utils/utils"; import ConnectionLineComponent from "../ConnectionLineComponent"; import SelectionMenu from "../SelectionMenuComponent"; +import isWrappedWithClass from "./utils/is-wrapped-with-class"; const nodeTypes = { genericNode: GenericNode, diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/utils/is-wrapped-with-class.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/utils/is-wrapped-with-class.tsx new file mode 100644 index 000000000..eff34d330 --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/utils/is-wrapped-with-class.tsx @@ -0,0 +1,4 @@ +const isWrappedWithClass = (event: any, className: string | undefined) => + event.target.closest(`.${className}`); + +export default isWrappedWithClass; diff --git a/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx index 0ecdd588b..148f4359f 100644 --- a/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx @@ -11,7 +11,7 @@ import { Badge } from "../../../../components/ui/badge"; import { Card, CardContent } from "../../../../components/ui/card"; import { deleteGlobalVariable } from "../../../../controllers/API"; import useAlertStore from "../../../../stores/alertStore"; -import { useGlobalVariablesStore } from "../../../../stores/globalVariables"; +import { useGlobalVariablesStore } from "../../../../stores/globalVariablesStore/globalVariables"; import { cn } from "../../../../utils/utils"; export default function GlobalVariablesPage() { diff --git a/src/frontend/src/stores/globalVariables.ts b/src/frontend/src/stores/globalVariablesStore/globalVariables.ts similarity index 91% rename from src/frontend/src/stores/globalVariables.ts rename to src/frontend/src/stores/globalVariablesStore/globalVariables.ts index 3adf8cbf8..873e6e899 100644 --- a/src/frontend/src/stores/globalVariables.ts +++ b/src/frontend/src/stores/globalVariablesStore/globalVariables.ts @@ -1,6 +1,6 @@ import { create } from "zustand"; -import { GlobalVariablesStore } from "../types/zustand/globalVariables"; -import { getUnavailableFields } from "../utils/utils"; +import { GlobalVariablesStore } from "../../types/zustand/globalVariables"; +import getUnavailableFields from "./utils/get-unavailable-fields"; export const useGlobalVariablesStore = create( (set, get) => ({ @@ -45,5 +45,5 @@ export const useGlobalVariablesStore = create( getVariableId: (name) => { return get().globalVariables[name]?.id; }, - }) + }), ); diff --git a/src/frontend/src/stores/globalVariablesStore/utils/get-unavailable-fields.tsx b/src/frontend/src/stores/globalVariablesStore/utils/get-unavailable-fields.tsx new file mode 100644 index 000000000..63da1dbe2 --- /dev/null +++ b/src/frontend/src/stores/globalVariablesStore/utils/get-unavailable-fields.tsx @@ -0,0 +1,13 @@ +export default function getUnavailableFields(variables: { + [key: string]: { default_fields?: 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) => { + unVariables[field] = key; + }); + } + }); + return unVariables; +} diff --git a/src/frontend/src/utils/reactflowUtils.ts b/src/frontend/src/utils/reactflowUtils.ts index 65a85960b..64008aa68 100644 --- a/src/frontend/src/utils/reactflowUtils.ts +++ b/src/frontend/src/utils/reactflowUtils.ts @@ -36,12 +36,8 @@ import { unselectAllNodesType, updateEdgesHandleIdsType, } from "../types/utils/reactflowUtils"; -import { - createRandomKey, - getFieldTitle, - getRandomDescription, - toTitleCase, -} from "./utils"; +import { createRandomKey, getFieldTitle, toTitleCase } from "./utils"; +import { DESCRIPTIONS } from "../flow_constants"; const uid = new ShortUniqueId({ length: 5 }); export function checkChatInput(nodes: Node[]) { @@ -1286,6 +1282,14 @@ export function downloadFlows() { }); } +export function getRandomElement(array: T[]): T { + return array[Math.floor(Math.random() * array.length)]; +} + +export function getRandomDescription(): string { + return getRandomElement(DESCRIPTIONS); +} + export const createNewFlow = ( flowData: ReactFlowJsonObject, flow: FlowType, diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 5e1786404..23bd275ea 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -15,6 +15,7 @@ import { } from "../types/components"; import { NodeType } from "../types/flow"; import { FlowState } from "../types/tabs"; +import { getRandomElement } from "./reactflowUtils"; export function classNames(...classes: Array): string { return classes.filter(Boolean).join(" "); @@ -90,20 +91,6 @@ export function toTitleCase( .join(" "); } -export function getUnavailableFields(variables: { - [key: string]: { default_fields?: 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) => { - unVariables[field] = key; - }); - } - }); - return unVariables; -} - export const upperCaseWords: string[] = ["llm", "uri"]; export function checkUpperWords(str: string): string { const words = str.split(" ").map((word) => { @@ -115,133 +102,10 @@ export function checkUpperWords(str: string): string { return words.join(" "); } -export const isWrappedWithClass = (event: any, className: string | undefined) => - event.target.closest(`.${className}`); - -export function groupByFamily( - data: APIDataType, - baseClasses: string, - left: boolean, - flow?: NodeType[], -): groupedObjType[] { - const baseClassesSet = new Set(baseClasses.split("\n")); - let arrOfPossibleInputs: Array<{ - category: string; - nodes: nodeGroupedObjType[]; - full: boolean; - display_name?: string; - }> = []; - let arrOfPossibleOutputs: Array<{ - category: string; - nodes: nodeGroupedObjType[]; - full: boolean; - display_name?: string; - }> = []; - let checkedNodes = new Map(); - const excludeTypes = new Set(["bool", "float", "code", "file", "int"]); - - const checkBaseClass = (template: TemplateVariableType) => { - return ( - template.type && - template.show && - ((!excludeTypes.has(template.type) && - baseClassesSet.has(template.type)) || - (template.input_types && - template.input_types.some((inputType) => - baseClassesSet.has(inputType), - ))) - ); - }; - - if (flow) { - // se existir o flow - for (const node of flow) { - // para cada node do flow - if (node!.data!.node!.flow || !node!.data!.node!.template) break; // não faz nada se o node for um group - const nodeData = node.data; - - const foundNode = checkedNodes.get(nodeData.type); // verifica se o tipo do node já foi checado - checkedNodes.set(nodeData.type, { - hasBaseClassInTemplate: - foundNode?.hasBaseClassInTemplate || - Object.values(nodeData.node!.template).some(checkBaseClass), - hasBaseClassInBaseClasses: - foundNode?.hasBaseClassInBaseClasses || - nodeData.node!.base_classes.some((baseClass) => - baseClassesSet.has(baseClass), - ), //seta como anterior ou verifica se o node tem base class - displayName: nodeData.node?.display_name, - }); - } - } - - for (const [d, nodes] of Object.entries(data)) { - let tempInputs: nodeGroupedObjType[] = [], - tempOutputs: nodeGroupedObjType[] = []; - - for (const [n, node] of Object.entries(nodes!)) { - let foundNode = checkedNodes.get(n); - - if (!foundNode) { - foundNode = { - hasBaseClassInTemplate: Object.values(node!.template).some( - checkBaseClass, - ), - hasBaseClassInBaseClasses: node!.base_classes.some((baseClass) => - baseClassesSet.has(baseClass), - ), - displayName: node?.display_name, - }; - } - - if (foundNode.hasBaseClassInTemplate) - tempInputs.push({ node: n, displayName: foundNode.displayName }); - if (foundNode.hasBaseClassInBaseClasses) - tempOutputs.push({ node: n, displayName: foundNode.displayName }); - } - - const totalNodes = Object.keys(nodes!).length; - - if (tempInputs.length) - arrOfPossibleInputs.push({ - category: d, - nodes: tempInputs, - full: tempInputs.length === totalNodes, - }); - if (tempOutputs.length) - arrOfPossibleOutputs.push({ - category: d, - nodes: tempOutputs, - full: tempOutputs.length === totalNodes, - }); - } - - return left - ? arrOfPossibleOutputs.map((output) => ({ - family: output.category, - type: output.full - ? "" - : output.nodes.map((item) => item.node).join(", "), - display_name: "", - })) - : arrOfPossibleInputs.map((input) => ({ - family: input.category, - type: input.full ? "" : input.nodes.map((item) => item.node).join(", "), - display_name: input.nodes.map((item) => item.displayName).join(", "), - })); -} - export function buildInputs(): string { return '{"input_value": "message"}'; } -export function getRandomElement(array: T[]): T { - return array[Math.floor(Math.random() * array.length)]; -} -export function getRandomDescription(): string { - return getRandomElement(DESCRIPTIONS); -} - export function getRandomName( retry: number = 0, noSpace: boolean = false, From 245eb3c102c2ee549cb51ada389d54ef796a3199 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 19:37:07 -0300 Subject: [PATCH 02/12] Refactor: move sensitiveSort to extrasidebar folder --- .../extraSidebarComponent/index.tsx | 2 +- .../utils/sensitive-sort.tsx | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/frontend/src/pages/FlowPage/components/extraSidebarComponent/utils/sensitive-sort.tsx diff --git a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx index fbd0c12d1..9ec1031c2 100644 --- a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx @@ -22,12 +22,12 @@ import { import { classNames, removeCountFromString, - sensitiveSort, } from "../../../../utils/utils"; import DisclosureComponent from "../DisclosureComponent"; import ParentDisclosureComponent from "../ParentDisclosureComponent"; import SidebarDraggableComponent from "./sideBarDraggableComponent"; import { sortKeys } from "./utils"; +import sensitiveSort from "./utils/sensitive-sort"; export default function ExtraSidebar(): JSX.Element { const data = useTypesStore((state) => state.data); diff --git a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/utils/sensitive-sort.tsx b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/utils/sensitive-sort.tsx new file mode 100644 index 000000000..c0e7bd265 --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/utils/sensitive-sort.tsx @@ -0,0 +1,25 @@ +export default function sensitiveSort(a: string, b: string): number { + // Extract the name and number from each string using regular expressions + const regex = /(.+) \((\w+)\)/; + const matchA = a.match(regex); + const matchB = b.match(regex); + + if (matchA && matchB) { + // Compare the names alphabetically + const nameA = matchA[1]; + const nameB = matchB[1]; + if (nameA !== nameB) { + return nameA.localeCompare(nameB); + } + + // If the names are the same, compare the numbers numerically + const numberA = parseInt(matchA[2]); + const numberB = parseInt(matchB[2]); + return numberA - numberB; + } else { + // Handle cases where one or both strings do not match the expected pattern + // Simple strings are treated as pure alphabetical comparisons + return a.localeCompare(b); + } +} + \ No newline at end of file From 78fe9f53b22473cfccdad97b254a049f02e47fa7 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 19:41:30 -0300 Subject: [PATCH 03/12] Refactor: move getRandomName to pageComponent folder --- .../components/PageComponent/index.tsx | 2 +- .../PageComponent/utils/get-random-name.tsx | 35 ++++++++++++ src/frontend/src/utils/utils.ts | 57 ------------------- 3 files changed, 36 insertions(+), 58 deletions(-) create mode 100644 src/frontend/src/pages/FlowPage/components/PageComponent/utils/get-random-name.tsx diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx index 3a456f540..c902ec2d5 100644 --- a/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/index.tsx @@ -34,10 +34,10 @@ import { updateIds, validateSelection, } from "../../../../utils/reactflowUtils"; -import { getRandomName } from "../../../../utils/utils"; import ConnectionLineComponent from "../ConnectionLineComponent"; import SelectionMenu from "../SelectionMenuComponent"; import isWrappedWithClass from "./utils/is-wrapped-with-class"; +import getRandomName from "./utils/get-random-name"; const nodeTypes = { genericNode: GenericNode, diff --git a/src/frontend/src/pages/FlowPage/components/PageComponent/utils/get-random-name.tsx b/src/frontend/src/pages/FlowPage/components/PageComponent/utils/get-random-name.tsx new file mode 100644 index 000000000..d6213bcc0 --- /dev/null +++ b/src/frontend/src/pages/FlowPage/components/PageComponent/utils/get-random-name.tsx @@ -0,0 +1,35 @@ +import { ADJECTIVES, NOUNS } from "../../../../../flow_constants"; +import { getRandomElement } from "../../../../../utils/reactflowUtils"; +import { toTitleCase } from "../../../../../utils/utils"; + +export default function getRandomName( + retry: number = 0, + noSpace: boolean = false, + maxRetries: number = 3, + ): string { + const left: string[] = ADJECTIVES; + const right: string[] = NOUNS; + + const lv = getRandomElement(left); + const rv = getRandomElement(right); + + // Condition to avoid "boring wozniak" + if (lv === "boring" && rv === "wozniak") { + if (retry < maxRetries) { + return getRandomName(retry + 1, noSpace, maxRetries); + } else { + console.warn("Max retries reached, returning as is"); + } + } + + // Append a suffix if retrying and noSpace is true + if (retry > 0 && noSpace) { + const retrySuffix = Math.floor(Math.random() * 10); + return `${lv}_${rv}${retrySuffix}`; + } + + // Construct the final name + let final_name = noSpace ? `${lv}_${rv}` : `${lv} ${rv}`; + // Return title case final name + return toTitleCase(final_name); + } \ No newline at end of file diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index c1ae07039..6868113fa 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -106,38 +106,6 @@ export function buildInputs(): string { return '{"input_value": "message"}'; } -export function getRandomName( - retry: number = 0, - noSpace: boolean = false, - maxRetries: number = 3, -): string { - const left: string[] = ADJECTIVES; - const right: string[] = NOUNS; - - const lv = getRandomElement(left); - const rv = getRandomElement(right); - - // Condition to avoid "boring wozniak" - if (lv === "boring" && rv === "wozniak") { - if (retry < maxRetries) { - return getRandomName(retry + 1, noSpace, maxRetries); - } else { - console.warn("Max retries reached, returning as is"); - } - } - - // Append a suffix if retrying and noSpace is true - if (retry > 0 && noSpace) { - const retrySuffix = Math.floor(Math.random() * 10); - return `${lv}_${rv}${retrySuffix}`; - } - - // Construct the final name - let final_name = noSpace ? `${lv}_${rv}` : `${lv} ${rv}`; - // Return title case final name - return toTitleCase(final_name); -} - export function getRandomKeyByssmm(): string { const now = new Date(); const seconds = String(now.getSeconds()).padStart(2, "0"); @@ -463,31 +431,6 @@ export function createRandomKey(key: string, uid: string): string { return removeCountFromString(key) + ` (${uid})`; } -export function sensitiveSort(a: string, b: string): number { - // Extract the name and number from each string using regular expressions - const regex = /(.+) \((\w+)\)/; - const matchA = a.match(regex); - const matchB = b.match(regex); - - if (matchA && matchB) { - // Compare the names alphabetically - const nameA = matchA[1]; - const nameB = matchB[1]; - if (nameA !== nameB) { - return nameA.localeCompare(nameB); - } - - // If the names are the same, compare the numbers numerically - const numberA = parseInt(matchA[2]); - const numberB = parseInt(matchB[2]); - return numberA - numberB; - } else { - // Handle cases where one or both strings do not match the expected pattern - // Simple strings are treated as pure alphabetical comparisons - return a.localeCompare(b); - } -} - export function groupByFamily( data: APIDataType, baseClasses: string, From a480021a54a592e14af900e3761b0777d3b09886 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 19:50:49 -0300 Subject: [PATCH 04/12] Refactor: move getPythonApiCode to apiModal folder --- .../apiModal/utils/get-python-api-code.tsx | 58 +++++++++++++++++ .../src/modals/apiModal/views/index.tsx | 2 +- src/frontend/src/utils/utils.ts | 64 ------------------- 3 files changed, 59 insertions(+), 65 deletions(-) create mode 100644 src/frontend/src/modals/apiModal/utils/get-python-api-code.tsx diff --git a/src/frontend/src/modals/apiModal/utils/get-python-api-code.tsx b/src/frontend/src/modals/apiModal/utils/get-python-api-code.tsx new file mode 100644 index 000000000..207ae2d48 --- /dev/null +++ b/src/frontend/src/modals/apiModal/utils/get-python-api-code.tsx @@ -0,0 +1,58 @@ +/** + * Function to get the python code for the API + * @param {string} flowId - The id of the flow + * @param {boolean} isAuth - If the API is authenticated + * @param {any[]} tweak - The tweaks + * @returns {string} - The python code + */ +export default function getPythonApiCode( + flowId: string, + isAuth: boolean, + tweaksBuildedObject, + ): string { + const tweaksObject = tweaksBuildedObject[0]; + return `import requests + from typing import Optional + + BASE_API_URL = "${window.location.protocol}//${window.location.host}/api/v1/run" + FLOW_ID = "${flowId}" + # You can tweak the flow by adding a tweaks dictionary + # e.g {"OpenAI-XXXXX": {"model_name": "gpt-4"}} + TWEAKS = ${JSON.stringify(tweaksObject, null, 2)} + + def run_flow(message: str, + flow_id: str, + output_type: str = "chat", + input_type: str = "chat", + tweaks: Optional[dict] = None, + api_key: Optional[str] = None) -> dict: + """ + Run a flow with a given message and optional tweaks. + + :param message: The message to send to the flow + :param flow_id: The ID of the flow to run + :param tweaks: Optional tweaks to customize the flow + :return: The JSON response from the flow + """ + api_url = f"{BASE_API_URL}/{flow_id}" + + payload = { + "input_value": message, + "output_type": output_type, + "input_type": input_type, + } + headers = None + if tweaks: + payload["tweaks"] = tweaks + if api_key: + headers = {"x-api-key": api_key} + response = requests.post(api_url, json=payload, headers=headers) + return response.json() + + # Setup any tweaks you want to apply to the flow + message = "message" + ${!isAuth ? `api_key = ""` : ""} + print(run_flow(message=message, flow_id=FLOW_ID, tweaks=TWEAKS${ + !isAuth ? `, api_key=api_key` : "" + }))`; + } \ No newline at end of file diff --git a/src/frontend/src/modals/apiModal/views/index.tsx b/src/frontend/src/modals/apiModal/views/index.tsx index a5cc47721..5165949ea 100644 --- a/src/frontend/src/modals/apiModal/views/index.tsx +++ b/src/frontend/src/modals/apiModal/views/index.tsx @@ -15,7 +15,6 @@ import { uniqueTweakType } from "../../../types/components"; import { FlowType } from "../../../types/flow/index"; import { getCurlCode, - getPythonApiCode, getPythonCode, getWidgetCode, tabsArray, @@ -27,6 +26,7 @@ import { checkCanBuildTweakObject } from "../utils/check-can-build-tweak-object" import { getChangesType } from "../utils/get-changes-types"; import { getNodesWithDefaultValue } from "../utils/get-nodes-with-default-value"; import { getValue } from "../utils/get-value"; +import getPythonApiCode from "../utils/get-python-api-code"; const ApiModal = forwardRef( ( diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 6868113fa..276585b18 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -113,11 +113,6 @@ export function getRandomKeyByssmm(): string { return seconds + milliseconds + Math.abs(Math.floor(Math.random() * 10001)); } -export function varHighlightHTML({ name }: IVarHighlightType): string { - const html = `{${name}}`; - return html; -} - export function buildTweakObject(tweak: tweakType) { tweak.forEach((el) => { Object.keys(el).forEach((key) => { @@ -146,65 +141,6 @@ export function getChatInputField(flowState?: FlowState) { return chat_input_field; } -/** - * Function to get the python code for the API - * @param {string} flowId - The id of the flow - * @param {boolean} isAuth - If the API is authenticated - * @param {any[]} tweak - The tweaks - * @returns {string} - The python code - */ -export function getPythonApiCode( - flowId: string, - isAuth: boolean, - tweaksBuildedObject, -): string { - const tweaksObject = tweaksBuildedObject[0]; - return `import requests -from typing import Optional - -BASE_API_URL = "${window.location.protocol}//${window.location.host}/api/v1/run" -FLOW_ID = "${flowId}" -# You can tweak the flow by adding a tweaks dictionary -# e.g {"OpenAI-XXXXX": {"model_name": "gpt-4"}} -TWEAKS = ${JSON.stringify(tweaksObject, null, 2)} - -def run_flow(message: str, - flow_id: str, - output_type: str = "chat", - input_type: str = "chat", - tweaks: Optional[dict] = None, - api_key: Optional[str] = None) -> dict: - """ - Run a flow with a given message and optional tweaks. - - :param message: The message to send to the flow - :param flow_id: The ID of the flow to run - :param tweaks: Optional tweaks to customize the flow - :return: The JSON response from the flow - """ - api_url = f"{BASE_API_URL}/{flow_id}" - - payload = { - "input_value": message, - "output_type": output_type, - "input_type": input_type, - } - headers = None - if tweaks: - payload["tweaks"] = tweaks - if api_key: - headers = {"x-api-key": api_key} - response = requests.post(api_url, json=payload, headers=headers) - return response.json() - -# Setup any tweaks you want to apply to the flow -message = "message" -${!isAuth ? `api_key = ""` : ""} -print(run_flow(message=message, flow_id=FLOW_ID, tweaks=TWEAKS${ - !isAuth ? `, api_key=api_key` : "" - }))`; -} - /** * Function to get the curl code for the API * @param {string} flowId - The id of the flow From 9bd70b2616fc362bd6bbe530f269f7cd38b63fe4 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 19:54:01 -0300 Subject: [PATCH 05/12] Refactor: move getCurlCode to apiModal folder --- .../modals/apiModal/utils/get-curl-code.tsx | 26 ++++++++++++++++++ .../src/modals/apiModal/views/index.tsx | 2 +- src/frontend/src/utils/utils.ts | 27 ------------------- 3 files changed, 27 insertions(+), 28 deletions(-) create mode 100644 src/frontend/src/modals/apiModal/utils/get-curl-code.tsx diff --git a/src/frontend/src/modals/apiModal/utils/get-curl-code.tsx b/src/frontend/src/modals/apiModal/utils/get-curl-code.tsx new file mode 100644 index 000000000..9ae8ec48f --- /dev/null +++ b/src/frontend/src/modals/apiModal/utils/get-curl-code.tsx @@ -0,0 +1,26 @@ +/** + * Function to get the curl code for the API + * @param {string} flowId - The id of the flow + * @param {boolean} isAuth - If the API is authenticated + * @returns {string} - The curl code + */ +export default function getCurlCode( + flowId: string, + isAuth: boolean, + tweaksBuildedObject, + ): string { + const tweaksObject = tweaksBuildedObject[0]; + + return `curl -X POST \\ + ${window.location.protocol}//${ + window.location.host + }/api/v1/run/${flowId}?stream=false \\ + -H 'Content-Type: application/json'\\${ + !isAuth ? `\n -H 'x-api-key: '\\` : "" + } + -d '{"input_value": "message", + "output_type": "chat", + "input_type": "chat", + "tweaks": ${JSON.stringify(tweaksObject, null, 2)}' + `; + } diff --git a/src/frontend/src/modals/apiModal/views/index.tsx b/src/frontend/src/modals/apiModal/views/index.tsx index 5165949ea..26b9d765f 100644 --- a/src/frontend/src/modals/apiModal/views/index.tsx +++ b/src/frontend/src/modals/apiModal/views/index.tsx @@ -14,7 +14,6 @@ import { TemplateVariableType } from "../../../types/api"; import { uniqueTweakType } from "../../../types/components"; import { FlowType } from "../../../types/flow/index"; import { - getCurlCode, getPythonCode, getWidgetCode, tabsArray, @@ -27,6 +26,7 @@ import { getChangesType } from "../utils/get-changes-types"; import { getNodesWithDefaultValue } from "../utils/get-nodes-with-default-value"; import { getValue } from "../utils/get-value"; import getPythonApiCode from "../utils/get-python-api-code"; +import getCurlCode from "../utils/get-curl-code"; const ApiModal = forwardRef( ( diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 276585b18..7bd08208d 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -141,33 +141,6 @@ export function getChatInputField(flowState?: FlowState) { return chat_input_field; } -/** - * Function to get the curl code for the API - * @param {string} flowId - The id of the flow - * @param {boolean} isAuth - If the API is authenticated - * @returns {string} - The curl code - */ -export function getCurlCode( - flowId: string, - isAuth: boolean, - tweaksBuildedObject, -): string { - const tweaksObject = tweaksBuildedObject[0]; - - return `curl -X POST \\ - ${window.location.protocol}//${ - window.location.host - }/api/v1/run/${flowId}?stream=false \\ - -H 'Content-Type: application/json'\\${ - !isAuth ? `\n -H 'x-api-key: '\\` : "" - } - -d '{"input_value": "message", - "output_type": "chat", - "input_type": "chat", - "tweaks": ${JSON.stringify(tweaksObject, null, 2)}' - `; -} - export function getOutputIds(flow) { const nodes = flow.data!.nodes; From 69f3b16fb73231c07728c721a7e1d5b2194b6d65 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 19:56:02 -0300 Subject: [PATCH 06/12] Refactor: move getPythonCode to apiModal folder --- .../modals/apiModal/utils/get-python-code.tsx | 17 +++++++++++++++++ .../src/modals/apiModal/views/index.tsx | 2 +- src/frontend/src/utils/utils.ts | 18 ------------------ 3 files changed, 18 insertions(+), 19 deletions(-) create mode 100644 src/frontend/src/modals/apiModal/utils/get-python-code.tsx diff --git a/src/frontend/src/modals/apiModal/utils/get-python-code.tsx b/src/frontend/src/modals/apiModal/utils/get-python-code.tsx new file mode 100644 index 000000000..d5327c3e7 --- /dev/null +++ b/src/frontend/src/modals/apiModal/utils/get-python-code.tsx @@ -0,0 +1,17 @@ +/** + * Function to get the python code for the API + * @param {string} flow - The current flow + * @param {any[]} tweak - The tweaks + * @returns {string} - The python code + */ +export default function getPythonCode(flowName: string, tweaksBuildedObject): string { + const tweaksObject = tweaksBuildedObject[0]; + + return `from langflow.load import run_flow_from_json + TWEAKS = ${JSON.stringify(tweaksObject, null, 2)} + + result = run_flow_from_json(flow="${flowName}.json", + input_value="message", + fallback_to_env_vars=True, # False by default + tweaks=TWEAKS)`; + } diff --git a/src/frontend/src/modals/apiModal/views/index.tsx b/src/frontend/src/modals/apiModal/views/index.tsx index 26b9d765f..bf45d9eae 100644 --- a/src/frontend/src/modals/apiModal/views/index.tsx +++ b/src/frontend/src/modals/apiModal/views/index.tsx @@ -14,7 +14,6 @@ import { TemplateVariableType } from "../../../types/api"; import { uniqueTweakType } from "../../../types/components"; import { FlowType } from "../../../types/flow/index"; import { - getPythonCode, getWidgetCode, tabsArray, } from "../../../utils/utils"; @@ -27,6 +26,7 @@ import { getNodesWithDefaultValue } from "../utils/get-nodes-with-default-value" import { getValue } from "../utils/get-value"; import getPythonApiCode from "../utils/get-python-api-code"; import getCurlCode from "../utils/get-curl-code"; +import getPythonCode from "../utils/get-python-code"; const ApiModal = forwardRef( ( diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 7bd08208d..4e15fc4ad 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -158,24 +158,6 @@ export function getOutputIds(flow) { return arrayOfOutputsJoin; } -/** - * Function to get the python code for the API - * @param {string} flow - The current flow - * @param {any[]} tweak - The tweaks - * @returns {string} - The python code - */ -export function getPythonCode(flowName: string, tweaksBuildedObject): string { - const tweaksObject = tweaksBuildedObject[0]; - - return `from langflow.load import run_flow_from_json -TWEAKS = ${JSON.stringify(tweaksObject, null, 2)} - -result = run_flow_from_json(flow="${flowName}.json", - input_value="message", - fallback_to_env_vars=True, # False by default - tweaks=TWEAKS)`; -} - /** * Function to get the widget code for the API * @param {string} flow - The current flow. From 5850634c04fd425d5fe09fef86a80676e1549610 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 19:57:34 -0300 Subject: [PATCH 07/12] Refactor: move getWidgetCode to apiModal folder --- .../modals/apiModal/utils/get-widget-code.tsx | 24 ++++++++++++++++++ .../src/modals/apiModal/views/index.tsx | 2 +- src/frontend/src/utils/utils.ts | 25 ------------------- 3 files changed, 25 insertions(+), 26 deletions(-) create mode 100644 src/frontend/src/modals/apiModal/utils/get-widget-code.tsx diff --git a/src/frontend/src/modals/apiModal/utils/get-widget-code.tsx b/src/frontend/src/modals/apiModal/utils/get-widget-code.tsx new file mode 100644 index 000000000..a44cba757 --- /dev/null +++ b/src/frontend/src/modals/apiModal/utils/get-widget-code.tsx @@ -0,0 +1,24 @@ +/** + * Function to get the widget code for the API + * @param {string} flow - The current flow. + * @returns {string} - The widget code + */ +export default function getWidgetCode( + flowId: string, + flowName: string, + isAuth: boolean, + ): string { + return ` + + `; + } diff --git a/src/frontend/src/modals/apiModal/views/index.tsx b/src/frontend/src/modals/apiModal/views/index.tsx index bf45d9eae..625261bfd 100644 --- a/src/frontend/src/modals/apiModal/views/index.tsx +++ b/src/frontend/src/modals/apiModal/views/index.tsx @@ -14,7 +14,6 @@ import { TemplateVariableType } from "../../../types/api"; import { uniqueTweakType } from "../../../types/components"; import { FlowType } from "../../../types/flow/index"; import { - getWidgetCode, tabsArray, } from "../../../utils/utils"; import BaseModal from "../../baseModal"; @@ -27,6 +26,7 @@ import { getValue } from "../utils/get-value"; import getPythonApiCode from "../utils/get-python-api-code"; import getCurlCode from "../utils/get-curl-code"; import getPythonCode from "../utils/get-python-code"; +import getWidgetCode from "../utils/get-widget-code"; const ApiModal = forwardRef( ( diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 4e15fc4ad..244a17963 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -158,31 +158,6 @@ export function getOutputIds(flow) { return arrayOfOutputsJoin; } -/** - * Function to get the widget code for the API - * @param {string} flow - The current flow. - * @returns {string} - The widget code - */ -export function getWidgetCode( - flowId: string, - flowName: string, - isAuth: boolean, -): string { - return ` - -`; -} - export function truncateLongId(id: string): string { let [componentName, newId] = id.split("-"); if (componentName.length > 15) { From 7547f0a17825a061084037211ef435fb89a759cb Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 20:00:39 -0300 Subject: [PATCH 08/12] Refactor: move tabsArray to apiModal folder --- .../src/modals/apiModal/utils/tabs-array.tsx | 78 ++++++++++++++++++ .../src/modals/apiModal/views/index.tsx | 4 +- src/frontend/src/utils/utils.ts | 79 ------------------- 3 files changed, 79 insertions(+), 82 deletions(-) create mode 100644 src/frontend/src/modals/apiModal/utils/tabs-array.tsx diff --git a/src/frontend/src/modals/apiModal/utils/tabs-array.tsx b/src/frontend/src/modals/apiModal/utils/tabs-array.tsx new file mode 100644 index 000000000..434086b88 --- /dev/null +++ b/src/frontend/src/modals/apiModal/utils/tabs-array.tsx @@ -0,0 +1,78 @@ +export default function tabsArray(codes: string[], method: number) { + if (!method) return; + if (method === 0) { + return [ + { + name: "cURL", + mode: "bash", + image: "https://curl.se/logo/curl-symbol-transparent.png", + language: "sh", + code: codes[0], + }, + { + name: "Python API", + mode: "python", + image: + "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", + language: "py", + code: codes[1], + }, + { + name: "Python Code", + mode: "python", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[2], + }, + { + name: "Chat Widget HTML", + description: + "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", + mode: "html", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[3], + }, + ]; + } + return [ + { + name: "cURL", + mode: "bash", + image: "https://curl.se/logo/curl-symbol-transparent.png", + language: "sh", + code: codes[0], + }, + { + name: "Python API", + mode: "python", + image: + "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", + language: "py", + code: codes[1], + }, + { + name: "Python Code", + mode: "python", + language: "py", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + code: codes[2], + }, + { + name: "Chat Widget HTML", + description: + "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", + mode: "html", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[3], + }, + { + name: "Tweaks", + mode: "python", + image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", + language: "py", + code: codes[4], + }, + ]; + } diff --git a/src/frontend/src/modals/apiModal/views/index.tsx b/src/frontend/src/modals/apiModal/views/index.tsx index 625261bfd..6e614e03f 100644 --- a/src/frontend/src/modals/apiModal/views/index.tsx +++ b/src/frontend/src/modals/apiModal/views/index.tsx @@ -13,9 +13,6 @@ import { useTweaksStore } from "../../../stores/tweaksStore"; import { TemplateVariableType } from "../../../types/api"; import { uniqueTweakType } from "../../../types/components"; import { FlowType } from "../../../types/flow/index"; -import { - tabsArray, -} from "../../../utils/utils"; import BaseModal from "../../baseModal"; import { buildContent } from "../utils/build-content"; import { buildTweaks } from "../utils/build-tweaks"; @@ -27,6 +24,7 @@ import getPythonApiCode from "../utils/get-python-api-code"; import getCurlCode from "../utils/get-curl-code"; import getPythonCode from "../utils/get-python-code"; import getWidgetCode from "../utils/get-widget-code"; +import tabsArray from "../utils/tabs-array"; const ApiModal = forwardRef( ( diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 244a17963..3cd67b2a8 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -181,85 +181,6 @@ export function truncateDisplayName(name: string): string { return name; } -export function tabsArray(codes: string[], method: number) { - if (!method) return; - if (method === 0) { - return [ - { - name: "cURL", - mode: "bash", - image: "https://curl.se/logo/curl-symbol-transparent.png", - language: "sh", - code: codes[0], - }, - { - name: "Python API", - mode: "python", - image: - "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", - language: "py", - code: codes[1], - }, - { - name: "Python Code", - mode: "python", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[2], - }, - { - name: "Chat Widget HTML", - description: - "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", - mode: "html", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[3], - }, - ]; - } - return [ - { - name: "cURL", - mode: "bash", - image: "https://curl.se/logo/curl-symbol-transparent.png", - language: "sh", - code: codes[0], - }, - { - name: "Python API", - mode: "python", - image: - "https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w", - language: "py", - code: codes[1], - }, - { - name: "Python Code", - mode: "python", - language: "py", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - code: codes[2], - }, - { - name: "Chat Widget HTML", - description: - "Insert this code anywhere in your <body> tag. To use with react and other libs, check our documentation.", - mode: "html", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[3], - }, - { - name: "Tweaks", - mode: "python", - image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png", - language: "py", - code: codes[4], - }, - ]; -} - export function checkLocalStorageKey(key: string): boolean { return localStorage.getItem(key) !== null; } From 05859becd4bd0356108217e2c9dd34728b973ad1 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 20:20:27 -0300 Subject: [PATCH 09/12] Refactor: move get-field-title and sort-fields to customNodes folder --- .../utils/group-by-family.tsx | 119 ------------------ .../src/customNodes/genericNode/index.tsx | 4 +- .../src/customNodes/utils/get-field-title.tsx | 10 ++ .../src/customNodes/utils/sort-fields.tsx | 40 ++++++ src/frontend/src/utils/reactflowUtils.ts | 3 +- src/frontend/src/utils/utils.ts | 48 ------- 6 files changed, 55 insertions(+), 169 deletions(-) delete mode 100644 src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx create mode 100644 src/frontend/src/customNodes/utils/get-field-title.tsx create mode 100644 src/frontend/src/customNodes/utils/sort-fields.tsx diff --git a/src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx b/src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx deleted file mode 100644 index a38a31b59..000000000 --- a/src/frontend/src/customNodes/genericNode/components/parameterComponent/utils/group-by-family.tsx +++ /dev/null @@ -1,119 +0,0 @@ -import { APIDataType, TemplateVariableType } from "../../../../../types/api"; -import { - groupedObjType, - nodeGroupedObjType, -} from "../../../../../types/components"; -import { NodeType } from "../../../../../types/flow"; - -export default function groupByFamily( - data: APIDataType, - baseClasses: string, - left: boolean, - flow?: NodeType[], -): groupedObjType[] { - const baseClassesSet = new Set(baseClasses.split("\n")); - let arrOfPossibleInputs: Array<{ - category: string; - nodes: nodeGroupedObjType[]; - full: boolean; - display_name?: string; - }> = []; - let arrOfPossibleOutputs: Array<{ - category: string; - nodes: nodeGroupedObjType[]; - full: boolean; - display_name?: string; - }> = []; - let checkedNodes = new Map(); - const excludeTypes = new Set(["bool", "float", "code", "file", "int"]); - - const checkBaseClass = (template: TemplateVariableType) => { - return ( - template.type && - template.show && - ((!excludeTypes.has(template.type) && - baseClassesSet.has(template.type)) || - (template.input_types && - template.input_types.some((inputType) => - baseClassesSet.has(inputType), - ))) - ); - }; - - if (flow) { - // se existir o flow - for (const node of flow) { - // para cada node do flow - if (node!.data!.node!.flow || !node!.data!.node!.template) break; // não faz nada se o node for um group - const nodeData = node.data; - - const foundNode = checkedNodes.get(nodeData.type); // verifica se o tipo do node já foi checado - checkedNodes.set(nodeData.type, { - hasBaseClassInTemplate: - foundNode?.hasBaseClassInTemplate || - Object.values(nodeData.node!.template).some(checkBaseClass), - hasBaseClassInBaseClasses: - foundNode?.hasBaseClassInBaseClasses || - nodeData.node!.base_classes.some((baseClass) => - baseClassesSet.has(baseClass), - ), //seta como anterior ou verifica se o node tem base class - displayName: nodeData.node?.display_name, - }); - } - } - - for (const [d, nodes] of Object.entries(data)) { - let tempInputs: nodeGroupedObjType[] = [], - tempOutputs: nodeGroupedObjType[] = []; - - for (const [n, node] of Object.entries(nodes!)) { - let foundNode = checkedNodes.get(n); - - if (!foundNode) { - foundNode = { - hasBaseClassInTemplate: Object.values(node!.template).some( - checkBaseClass, - ), - hasBaseClassInBaseClasses: node!.base_classes.some((baseClass) => - baseClassesSet.has(baseClass), - ), - displayName: node?.display_name, - }; - } - - if (foundNode.hasBaseClassInTemplate) - tempInputs.push({ node: n, displayName: foundNode.displayName }); - if (foundNode.hasBaseClassInBaseClasses) - tempOutputs.push({ node: n, displayName: foundNode.displayName }); - } - - const totalNodes = Object.keys(nodes!).length; - - if (tempInputs.length) - arrOfPossibleInputs.push({ - category: d, - nodes: tempInputs, - full: tempInputs.length === totalNodes, - }); - if (tempOutputs.length) - arrOfPossibleOutputs.push({ - category: d, - nodes: tempOutputs, - full: tempOutputs.length === totalNodes, - }); - } - - return left - ? arrOfPossibleOutputs.map((output) => ({ - family: output.category, - type: output.full - ? "" - : output.nodes.map((item) => item.node).join(", "), - display_name: "", - })) - : arrOfPossibleInputs.map((input) => ({ - family: input.category, - type: input.full ? "" : input.nodes.map((item) => item.node).join(", "), - display_name: input.nodes.map((item) => item.displayName).join(", "), - })); -} diff --git a/src/frontend/src/customNodes/genericNode/index.tsx b/src/frontend/src/customNodes/genericNode/index.tsx index 811e812a6..26dc0f764 100644 --- a/src/frontend/src/customNodes/genericNode/index.tsx +++ b/src/frontend/src/customNodes/genericNode/index.tsx @@ -27,8 +27,10 @@ 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 } from "../../utils/utils"; import ParameterComponent from "./components/parameterComponent"; +import getFieldTitle from "../utils/get-field-title"; +import sortFields from "../utils/sort-fields"; export default function GenericNode({ data, diff --git a/src/frontend/src/customNodes/utils/get-field-title.tsx b/src/frontend/src/customNodes/utils/get-field-title.tsx new file mode 100644 index 000000000..93db719df --- /dev/null +++ b/src/frontend/src/customNodes/utils/get-field-title.tsx @@ -0,0 +1,10 @@ +import { APITemplateType } from "../../types/api"; + +export default function getFieldTitle( + template: APITemplateType, + templateField: string, + ): string { + return template[templateField].display_name + ? template[templateField].display_name! + : template[templateField].name ?? templateField; + } diff --git a/src/frontend/src/customNodes/utils/sort-fields.tsx b/src/frontend/src/customNodes/utils/sort-fields.tsx new file mode 100644 index 000000000..d4dc473e5 --- /dev/null +++ b/src/frontend/src/customNodes/utils/sort-fields.tsx @@ -0,0 +1,40 @@ +import { priorityFields } from "../../constants/constants"; + +export default function sortFields(a, b, fieldOrder) { + // Early return for empty fields + if (!a && !b) return 0; + if (!a) return 1; + if (!b) return -1; + + // Normalize the case to ensure case-insensitive comparison + const normalizedFieldA = a.toLowerCase(); + const normalizedFieldB = b.toLowerCase(); + + const aIsPriority = priorityFields.has(normalizedFieldA); + const bIsPriority = priorityFields.has(normalizedFieldB); + + // Sort by priority + if (aIsPriority && !bIsPriority) return -1; + if (!aIsPriority && bIsPriority) return 1; + + // Check if either field is in the fieldOrder array + const indexOfA = fieldOrder.indexOf(normalizedFieldA); + const indexOfB = fieldOrder.indexOf(normalizedFieldB); + + // If both fields are in fieldOrder, sort by their order in the array + if (indexOfA !== -1 && indexOfB !== -1) { + return indexOfA - indexOfB; + } + + // If only one of the fields is in fieldOrder, that field comes first + if (indexOfA !== -1) { + return -1; + } + if (indexOfB !== -1) { + return 1; + } + + // Default case for fields not in priorityFields and not found in fieldOrder + // You might want to sort them alphabetically or in another specific manner + return a.localeCompare(b); + } diff --git a/src/frontend/src/utils/reactflowUtils.ts b/src/frontend/src/utils/reactflowUtils.ts index 1e67fdf93..d47ba4981 100644 --- a/src/frontend/src/utils/reactflowUtils.ts +++ b/src/frontend/src/utils/reactflowUtils.ts @@ -36,8 +36,9 @@ import { unselectAllNodesType, updateEdgesHandleIdsType, } from "../types/utils/reactflowUtils"; -import { createRandomKey, getFieldTitle, toTitleCase } from "./utils"; +import { createRandomKey, toTitleCase } from "./utils"; import { DESCRIPTIONS } from "../flow_constants"; +import getFieldTitle from "../customNodes/utils/get-field-title"; const uid = new ShortUniqueId({ length: 5 }); export function checkChatInput(nodes: Node[]) { diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 3cd67b2a8..cb8451299 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -346,54 +346,6 @@ export function getSetFromObject(obj: object, key?: string): Set { return set; } -export function getFieldTitle( - template: APITemplateType, - templateField: string, -): string { - return template[templateField].display_name - ? template[templateField].display_name! - : template[templateField].name ?? templateField; -} - -export function sortFields(a, b, fieldOrder) { - // Early return for empty fields - if (!a && !b) return 0; - if (!a) return 1; - if (!b) return -1; - - // Normalize the case to ensure case-insensitive comparison - const normalizedFieldA = a.toLowerCase(); - const normalizedFieldB = b.toLowerCase(); - - const aIsPriority = priorityFields.has(normalizedFieldA); - const bIsPriority = priorityFields.has(normalizedFieldB); - - // Sort by priority - if (aIsPriority && !bIsPriority) return -1; - if (!aIsPriority && bIsPriority) return 1; - - // Check if either field is in the fieldOrder array - const indexOfA = fieldOrder.indexOf(normalizedFieldA); - const indexOfB = fieldOrder.indexOf(normalizedFieldB); - - // If both fields are in fieldOrder, sort by their order in the array - if (indexOfA !== -1 && indexOfB !== -1) { - return indexOfA - indexOfB; - } - - // If only one of the fields is in fieldOrder, that field comes first - if (indexOfA !== -1) { - return -1; - } - if (indexOfB !== -1) { - return 1; - } - - // Default case for fields not in priorityFields and not found in fieldOrder - // You might want to sort them alphabetically or in another specific manner - return a.localeCompare(b); -} - export function freezeObject(obj: any) { if (!obj) return obj; return JSON.parse(JSON.stringify(obj)); From aef52637f67b3387bb553b107cfd6f575ab4770c Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 20:27:22 -0300 Subject: [PATCH 10/12] Refactor: move convert-test-name to cardComponent folder --- src/frontend/src/components/cardComponent/index.tsx | 3 ++- .../src/components/cardComponent/utils/convert-test-name.tsx | 3 +++ src/frontend/src/utils/utils.ts | 4 ---- 3 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 src/frontend/src/components/cardComponent/utils/convert-test-name.tsx diff --git a/src/frontend/src/components/cardComponent/index.tsx b/src/frontend/src/components/cardComponent/index.tsx index 0698edd73..9b2ecdbe3 100644 --- a/src/frontend/src/components/cardComponent/index.tsx +++ b/src/frontend/src/components/cardComponent/index.tsx @@ -11,7 +11,7 @@ import { storeComponent } from "../../types/store"; import cloneFLowWithParent, { getInputsAndOutputs, } from "../../utils/storeUtils"; -import { cn, convertTestName } from "../../utils/utils"; +import { cn } from "../../utils/utils"; import IconComponent from "../genericIconComponent"; import ShadTooltip from "../shadTooltipComponent"; import { Button } from "../ui/button"; @@ -23,6 +23,7 @@ import { CardTitle, } from "../ui/card"; import Loading from "../ui/loading"; +import { convertTestName } from "./utils/convert-test-name"; export default function CollectionCardComponent({ data, diff --git a/src/frontend/src/components/cardComponent/utils/convert-test-name.tsx b/src/frontend/src/components/cardComponent/utils/convert-test-name.tsx new file mode 100644 index 000000000..ac8800540 --- /dev/null +++ b/src/frontend/src/components/cardComponent/utils/convert-test-name.tsx @@ -0,0 +1,3 @@ +export function convertTestName(name: string): string { + return name.replace(/ /g, "-").toLowerCase(); +} diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index cb8451299..46495c942 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -351,10 +351,6 @@ export function freezeObject(obj: any) { return JSON.parse(JSON.stringify(obj)); } -export function convertTestName(name: string): string { - return name.replace(/ /g, "-").toLowerCase(); -} - export function sortByName(stringList: string[]): string[] { return stringList.sort((a, b) => a.localeCompare(b)); } From e2ca4b79f82f937687b3fbd629e1b960cf089a9e Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 20:30:10 -0300 Subject: [PATCH 11/12] Refactor: move sort-by-name to addNewVariableButton folder --- .../addNewVariableButton.tsx | 2 +- .../addNewVariableButtonComponent/utils/sort-by-name.tsx | 3 +++ src/frontend/src/utils/utils.ts | 9 --------- 3 files changed, 4 insertions(+), 10 deletions(-) create mode 100644 src/frontend/src/components/addNewVariableButtonComponent/utils/sort-by-name.tsx diff --git a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx index 1ea7142ab..f80755a46 100644 --- a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx +++ b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx @@ -5,13 +5,13 @@ import useAlertStore from "../../stores/alertStore"; import { useGlobalVariablesStore } from "../../stores/globalVariablesStore/globalVariables"; import { useTypesStore } from "../../stores/typesStore"; import { ResponseErrorDetailAPI } from "../../types/api"; -import { sortByName } from "../../utils/utils"; import ForwardedIconComponent from "../genericIconComponent"; import InputComponent from "../inputComponent"; import { Button } from "../ui/button"; import { Input } from "../ui/input"; import { Label } from "../ui/label"; import { Textarea } from "../ui/textarea"; +import sortByName from "./utils/sort-by-name"; //TODO IMPLEMENT FORM LOGIC diff --git a/src/frontend/src/components/addNewVariableButtonComponent/utils/sort-by-name.tsx b/src/frontend/src/components/addNewVariableButtonComponent/utils/sort-by-name.tsx new file mode 100644 index 000000000..96a1b6b68 --- /dev/null +++ b/src/frontend/src/components/addNewVariableButtonComponent/utils/sort-by-name.tsx @@ -0,0 +1,3 @@ +export default function sortByName(stringList: string[]): string[] { + return stringList.sort((a, b) => a.localeCompare(b)); +} \ No newline at end of file diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index 46495c942..487448665 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -1,21 +1,16 @@ import clsx, { ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; -import { priorityFields } from "../constants/constants"; -import { ADJECTIVES, DESCRIPTIONS, NOUNS } from "../flow_constants"; import { APIDataType, - APITemplateType, TemplateVariableType, } from "../types/api"; import { - IVarHighlightType, groupedObjType, nodeGroupedObjType, tweakType, } from "../types/components"; import { NodeType } from "../types/flow"; import { FlowState } from "../types/tabs"; -import { getRandomElement } from "./reactflowUtils"; export function classNames(...classes: Array): string { return classes.filter(Boolean).join(" "); @@ -350,7 +345,3 @@ export function freezeObject(obj: any) { if (!obj) return obj; return JSON.parse(JSON.stringify(obj)); } - -export function sortByName(stringList: string[]): string[] { - return stringList.sort((a, b) => a.localeCompare(b)); -} From c795a3646885ef36333efa0608b2e2515299c934 Mon Sep 17 00:00:00 2001 From: igorrCarvalho Date: Tue, 21 May 2024 20:34:00 -0300 Subject: [PATCH 12/12] Refactor: move get-tags-ids to shareModal folder --- src/frontend/src/modals/shareModal/index.tsx | 2 +- .../src/modals/shareModal/utils/get-tags-ids.tsx | 8 ++++++++ src/frontend/src/utils/storeUtils.ts | 9 --------- 3 files changed, 9 insertions(+), 10 deletions(-) create mode 100644 src/frontend/src/modals/shareModal/utils/get-tags-ids.tsx diff --git a/src/frontend/src/modals/shareModal/index.tsx b/src/frontend/src/modals/shareModal/index.tsx index 75c3c1382..b6c5a2aed 100644 --- a/src/frontend/src/modals/shareModal/index.tsx +++ b/src/frontend/src/modals/shareModal/index.tsx @@ -22,10 +22,10 @@ import { removeFileNameFromComponents, removeGlobalVariableFromComponents, } from "../../utils/reactflowUtils"; -import { getTagsIds } from "../../utils/storeUtils"; import BaseModal from "../baseModal"; import ConfirmationModal from "../confirmationModal"; import ExportModal from "../exportModal"; +import getTagsIds from "./utils/get-tags-ids"; export default function ShareModal({ component, diff --git a/src/frontend/src/modals/shareModal/utils/get-tags-ids.tsx b/src/frontend/src/modals/shareModal/utils/get-tags-ids.tsx new file mode 100644 index 000000000..9bb71e20e --- /dev/null +++ b/src/frontend/src/modals/shareModal/utils/get-tags-ids.tsx @@ -0,0 +1,8 @@ +export default function getTagsIds( + tags: string[], + tagListId: { name: string; id: string }[], + ) { + return tags + .map((tag) => tagListId.find((tagObj) => tagObj.name === tag))! + .map((tag) => tag!.id); +} diff --git a/src/frontend/src/utils/storeUtils.ts b/src/frontend/src/utils/storeUtils.ts index c0a0fc440..9c2735a35 100644 --- a/src/frontend/src/utils/storeUtils.ts +++ b/src/frontend/src/utils/storeUtils.ts @@ -20,15 +20,6 @@ export default function cloneFLowWithParent( return childFLow; } -export function getTagsIds( - tags: string[], - tagListId: { name: string; id: string }[], -) { - return tags - .map((tag) => tagListId.find((tagObj) => tagObj.name === tag))! - .map((tag) => tag!.id); -} - export function getInputsAndOutputs(nodes: Node[]) { let inputs: { type: string; id: string; displayName: string }[] = []; let outputs: { type: string; id: string; displayName: string }[] = [];