refactor: parameter component, edit node modal and api modal (#2928)
* changed column defs to receive handleOnNewValue and use it to change Advanced variable * Exported function isTargetHandleConnected * Refactored types of setNodeClass * Exported type of handleOnNewValue * Refactored useHandleNodeClass to only handle changes to node data * Refactored toggleCellRender to handle advanced values by itself with the handleOnNewValue * changed setNodeClass types and disabled hook * changed handleNodeClass on parametercomponent * changed handleNodeClass on the two components that used it * refactor: Update handleNodeClass to accept newNodeClass and type only * Refactor EditNodeModal component to use new handleNodeClass and columnDefs * Changed columnDefs to receive new handleNodeClass and not receive useless parameters * changed cellTypeStr to strRender * Refactored inputFileComponent to use the new handleOnNewValue * Refactored keypairList to convert values on the fly * added parameterRenderComponent that renders all parameters in one place * Exported parameterRenderComponent * Changed tableNodeCellRender to use ParameterRenderComponent * changed parameterredercomponent to receive name * changed strrendercomponent to receive name * changed nodecellrender to pass name and to check if value is undefined before assigning on templateData * chore: Refactor use-handle-new-value to handle undefined values in changes * Used ParameterRenderComponent at parameterComponent * Refactored parameterRenderComponent to include refresh button * Created refresh parameter component * Added nodeId to parameterrendercomponent call * Removed unused variable * Refactored refreshButton * Fixed parameters not showing when they dont have a value * Created a tweakComplnent that renders the tweak individually, with the same table as the EditNode * Created tweaks component, that renders all tweaks * Changed tableNodeCellRender to pass setNode as well * changed handleOnNewValue to use custom setNode if specified * added editNodeComponent that handles the table and rowData and columnDefs * changed editNodeModal to use editNodeComponent instead of table * changed columndefs type to handle setNode and hideVisibility optional parameters * changed useRowData to not use myData, and just use nodeClass * Changed codeTabsPropsType tweaks property to include only the ncessary * changed codeTabsComponent to use TweaksComponent and handle an internal nodes state * changed apiModal to handle the tweaks build by finding the differences between old and current node * fix bug on API modal that refresh tweaks table all the time * Created new tweaks store type * Added tweaks store with all of the logic needed to get the tweaks on the API page * refactored TweakComponent to hold an temporary state to prevent the table from rerendering * Added TweakComponent into TweaksComponent * Removed external state on tableAdvancedToggle, making every state come from the Stores * Removed external state from TableNodeCellRender and added isTweaks to choose which store to use * Added SetNode type on HandleOnNewValue * Added custom setNode to handleNodeClass * Removed unused logic from apiModal * removed unused old code * Changed type of getChangesTypes * Transformed string into object on get codes * Changed getNodesWithDefaultValue to return nodes that will appear on Tweaks, as well as just the allowed parameters * added hasTweaks to tabs * added check of template keys to update the local nodeClass state, allowing the table to be updated just when the number of parameters changes * passed isTweaks to columnDefs * removed unused state and passed isTweaks to value getters * Removed unused state * updated tabsArrayType with hasTweaks and removed unused types * Added local nodes tweaks state to the codetabscomponent and refactored conditions of display * removed unused console.log * changed advanced toggle to use parameterid given by the value * changed nodecellrender to use parameter id given by the value * passed parameter id by value to the renderers * removed nodeClass from columnDefs definition * Fixed isTargetHandleConnected returning error if field is undefined * Fix performance issues on edit node modal * Fixed scroll overflow issues on tweaksComponent * Revert "Revert "refactor: update template api, handleonnewvalue and handlenodeclass hooks (#2628)"" This reverts commit 236ae82cabba2fa1128f498d781099facd222b57. * 📝 (tweaksTest.spec.ts): remove redundant code and improve readability by simplifying the interaction with elements in the test case * added custom id for tests * ✨ (frontend): Add unique id prop to input components for better testability and accessibility. ✨ (Hierarchical Tasks Agent.spec.ts): Update dropdown element IDs to improve clarity and consistency ✨ (Memory Chatbot.spec.ts): Update dropdown element IDs to improve clarity and consistency ✨ (Sequential Tasks Agent.spec.ts): Update dropdown element IDs to improve clarity and consistency ✨ (chatInputOutputUser-shard-0.spec.ts): Update dropdown element IDs to improve clarity and consistency ✨ (chatInputOutputUser-shard-1.spec.ts): Update dropdown element IDs to improve clarity and consistency ✨ (chatInputOutputUser-shard-2.spec.ts): Update dropdown element IDs to improve clarity and consistency ✨ (decisionFlow.spec.ts): Update input list element IDs to improve clarity and consistency ✨ (decisionFlow.spec.ts): Update prompt area element IDs to improve clarity and consistency ✨ (decisionFlow.spec.ts): Update dropdown element IDs to improve clarity and consistency ✨ (freeze-path.spec.ts): Update dropdown element IDs to improve clarity and consistency ✨ (generalBugs-shard-0.spec.ts): Update dropdown element IDs to improve clarity and consistency ✨ (generalBugs-shard-1.spec.ts): Update dropdown element IDs to improve clarity and consistency ✨ (generalBugs-shard-3.spec.ts): Update dropdown element IDs to improve clarity and consistency 🔧 (logs.spec.ts, textInputOutput.spec.ts): update dropdown test selectors to match changes in the frontend codebase * Fixed prompt not holding the value when validating * Fixed range spec on int component * Fixed OpenAI Model max tokens range spec * ✨ (dropdownComponent.spec.ts): Update dropdown test cases to use more descriptive test IDs for better clarity and maintainability 📝 (fileUploadComponent.spec.ts): Add explicit wait for "Run Flow" button to ensure it is loaded before clicking 📝 (folders.spec.ts): Update file path in readFileSync function to use an absolute path for better reliability 📝 (freeze-path.spec.ts): Refactor test code to remove commented out code and improve readability by using more descriptive test IDs and removing unnecessary code snippets ✨ (inputListComponent.spec.ts): Update test file to use consistent naming convention for input elements in the InputListComponent 📝 (intComponent.spec.ts): Refactor test file to use consistent naming convention for input elements in the IntComponent ✨ (nestedComponent.spec.ts): Update test steps and interactions for nestedComponent to improve test coverage and accuracy. 📝 (promptModalComponent.spec.ts): Update test selectors for prompt modal component to improve consistency and readability 📝 (textAreaModalComponent.spec.ts): Update test selectors for text area modal component to improve consistency and readability 📝 (toggleComponent.spec.ts): Update test selectors for toggle component to improve consistency and readability * 🐛 (intComponent.spec.ts): fix incorrect value comparison in test for IntComponent 🐛 (intComponent.spec.ts): fix missing test step for clicking on a specific element in IntComponent test * 📝 (Vector Store.spec.ts): increase timeout for waiting for "built successfully" text to improve test reliability and prevent false negatives * Fixed folders test --------- Co-authored-by: anovazzi1 <otavio2204@gmail.com> Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org> Co-authored-by: cristhianzl <cristhian.lousa@gmail.com>
This commit is contained in:
parent
83910866e9
commit
a9863a050e
80 changed files with 2026 additions and 2923 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
import operator
|
import operator
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
|
from langflow.field_typing.range_spec import RangeSpec
|
||||||
from langchain_openai import ChatOpenAI
|
from langchain_openai import ChatOpenAI
|
||||||
from pydantic.v1 import SecretStr
|
from pydantic.v1 import SecretStr
|
||||||
|
|
||||||
|
|
@ -30,6 +31,7 @@ class OpenAIModelComponent(LCModelComponent):
|
||||||
display_name="Max Tokens",
|
display_name="Max Tokens",
|
||||||
advanced=True,
|
advanced=True,
|
||||||
info="The maximum number of tokens to generate. Set to 0 for unlimited tokens.",
|
info="The maximum number of tokens to generate. Set to 0 for unlimited tokens.",
|
||||||
|
range_spec=RangeSpec(min=0, max=128000),
|
||||||
),
|
),
|
||||||
DictInput(name="model_kwargs", display_name="Model Kwargs", advanced=True),
|
DictInput(name="model_kwargs", display_name="Model Kwargs", advanced=True),
|
||||||
BoolInput(
|
BoolInput(
|
||||||
|
|
|
||||||
602
src/frontend/package-lock.json
generated
602
src/frontend/package-lock.json
generated
|
|
@ -8,6 +8,7 @@
|
||||||
"name": "langflow",
|
"name": "langflow",
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@chakra-ui/number-input": "^2.1.2",
|
||||||
"@headlessui/react": "^2.0.4",
|
"@headlessui/react": "^2.0.4",
|
||||||
"@hookform/resolvers": "^3.6.0",
|
"@hookform/resolvers": "^3.6.0",
|
||||||
"@million/lint": "^1.0.0-rc.26",
|
"@million/lint": "^1.0.0-rc.26",
|
||||||
|
|
@ -765,6 +766,293 @@
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@chakra-ui/anatomy": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/anatomy/-/anatomy-2.2.2.tgz",
|
||||||
|
"integrity": "sha512-MV6D4VLRIHr4PkW4zMyqfrNS1mPlCTiCXwvYGtDFQYr+xHFfonhAuf9WjsSc0nyp2m0OdkSLnzmVKkZFLo25Tg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/color-mode": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/color-mode/-/color-mode-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-niTEA8PALtMWRI9wJ4LL0CSBDo8NBfLNp4GD6/0hstcm3IlbBHTVKxN6HwSaoNYfphDQLxCjT4yG+0BJA5tFpg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/react-use-safe-layout-effect": "2.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/counter": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/counter/-/counter-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-s6hZAEcWT5zzjNz2JIWUBzRubo9la/oof1W7EKZVVfPYHERnl5e16FmBC79Yfq8p09LQ+aqFKm/etYoJMMgghw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/number-utils": "2.0.7",
|
||||||
|
"@chakra-ui/react-use-callback-ref": "2.1.0",
|
||||||
|
"@chakra-ui/shared-utils": "2.0.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/form-control": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/form-control/-/form-control-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-wehLC1t4fafCVJ2RvJQT2jyqsAwX7KymmiGqBu7nQoQz8ApTkGABWpo/QwDh3F/dBLrouHDoOvGmYTqft3Mirw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/icon": "3.2.0",
|
||||||
|
"@chakra-ui/react-context": "2.1.0",
|
||||||
|
"@chakra-ui/react-types": "2.0.7",
|
||||||
|
"@chakra-ui/react-use-merge-refs": "2.1.0",
|
||||||
|
"@chakra-ui/shared-utils": "2.0.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@chakra-ui/system": ">=2.0.0",
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/icon": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/icon/-/icon-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-xxjGLvlX2Ys4H0iHrI16t74rG9EBcpFvJ3Y3B7KMQTrnW34Kf7Da/UC8J67Gtx85mTHW020ml85SVPKORWNNKQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/shared-utils": "2.0.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@chakra-ui/system": ">=2.0.0",
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/number-input": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/number-input/-/number-input-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-pfOdX02sqUN0qC2ysuvgVDiws7xZ20XDIlcNhva55Jgm095xjm8eVdIBfNm3SFbSUNxyXvLTW/YQanX74tKmuA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/counter": "2.1.0",
|
||||||
|
"@chakra-ui/form-control": "2.2.0",
|
||||||
|
"@chakra-ui/icon": "3.2.0",
|
||||||
|
"@chakra-ui/react-context": "2.1.0",
|
||||||
|
"@chakra-ui/react-types": "2.0.7",
|
||||||
|
"@chakra-ui/react-use-callback-ref": "2.1.0",
|
||||||
|
"@chakra-ui/react-use-event-listener": "2.1.0",
|
||||||
|
"@chakra-ui/react-use-interval": "2.1.0",
|
||||||
|
"@chakra-ui/react-use-merge-refs": "2.1.0",
|
||||||
|
"@chakra-ui/react-use-safe-layout-effect": "2.1.0",
|
||||||
|
"@chakra-ui/react-use-update-effect": "2.1.0",
|
||||||
|
"@chakra-ui/shared-utils": "2.0.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@chakra-ui/system": ">=2.0.0",
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/number-utils": {
|
||||||
|
"version": "2.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/number-utils/-/number-utils-2.0.7.tgz",
|
||||||
|
"integrity": "sha512-yOGxBjXNvLTBvQyhMDqGU0Oj26s91mbAlqKHiuw737AXHt0aPllOthVUqQMeaYLwLCjGMg0jtI7JReRzyi94Dg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/object-utils": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/object-utils/-/object-utils-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-tgIZOgLHaoti5PYGPTwK3t/cqtcycW0owaiOXoZOcpwwX/vlVb+H1jFsQyWiiwQVPt9RkoSLtxzXamx+aHH+bQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/react-context": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/react-context/-/react-context-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-iahyStvzQ4AOwKwdPReLGfDesGG+vWJfEsn0X/NoGph/SkN+HXtv2sCfYFFR9k7bb+Kvc6YfpLlSuLvKMHi2+w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/react-types": {
|
||||||
|
"version": "2.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/react-types/-/react-types-2.0.7.tgz",
|
||||||
|
"integrity": "sha512-12zv2qIZ8EHwiytggtGvo4iLT0APris7T0qaAWqzpUGS0cdUtR8W+V1BJ5Ocq+7tA6dzQ/7+w5hmXih61TuhWQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/react-use-callback-ref": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/react-use-callback-ref/-/react-use-callback-ref-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-efnJrBtGDa4YaxDzDE90EnKD3Vkh5a1t3w7PhnRQmsphLy3g2UieasoKTlT2Hn118TwDjIv5ZjHJW6HbzXA9wQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/react-use-event-listener": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/react-use-event-listener/-/react-use-event-listener-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-U5greryDLS8ISP69DKDsYcsXRtAdnTQT+jjIlRYZ49K/XhUR/AqVZCK5BkR1spTDmO9H8SPhgeNKI70ODuDU/Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/react-use-callback-ref": "2.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/react-use-interval": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/react-use-interval/-/react-use-interval-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-8iWj+I/+A0J08pgEXP1J1flcvhLBHkk0ln7ZvGIyXiEyM6XagOTJpwNhiu+Bmk59t3HoV/VyvyJTa+44sEApuw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/react-use-callback-ref": "2.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/react-use-merge-refs": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/react-use-merge-refs/-/react-use-merge-refs-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-lERa6AWF1cjEtWSGjxWTaSMvneccnAVH4V4ozh8SYiN9fSPZLlSG3kNxfNzdFvMEhM7dnP60vynF7WjGdTgQbQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/react-use-safe-layout-effect": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/react-use-safe-layout-effect/-/react-use-safe-layout-effect-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-Knbrrx/bcPwVS1TorFdzrK/zWA8yuU/eaXDkNj24IrKoRlQrSBFarcgAEzlCHtzuhufP3OULPkELTzz91b0tCw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/react-use-update-effect": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/react-use-update-effect/-/react-use-update-effect-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-ND4Q23tETaR2Qd3zwCKYOOS1dfssojPLJMLvUtUbW5M9uW1ejYWgGUobeAiOVfSplownG8QYMmHTP86p/v0lbA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/react-utils": {
|
||||||
|
"version": "2.0.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/react-utils/-/react-utils-2.0.12.tgz",
|
||||||
|
"integrity": "sha512-GbSfVb283+YA3kA8w8xWmzbjNWk14uhNpntnipHCftBibl0lxtQ9YqMFQLwuFOO0U2gYVocszqqDWX+XNKq9hw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/utils": "2.0.15"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/shared-utils": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/shared-utils/-/shared-utils-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-4/Wur0FqDov7Y0nCXl7HbHzCg4aq86h+SXdoUeuCMD3dSj7dpsVnStLYhng1vxvlbUnLpdF4oz5Myt3i/a7N3Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/styled-system": {
|
||||||
|
"version": "2.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/styled-system/-/styled-system-2.9.2.tgz",
|
||||||
|
"integrity": "sha512-To/Z92oHpIE+4nk11uVMWqo2GGRS86coeMmjxtpnErmWRdLcp1WVCVRAvn+ZwpLiNR+reWFr2FFqJRsREuZdAg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/shared-utils": "2.0.5",
|
||||||
|
"csstype": "^3.1.2",
|
||||||
|
"lodash.mergewith": "4.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/system": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/system/-/system-2.6.2.tgz",
|
||||||
|
"integrity": "sha512-EGtpoEjLrUu4W1fHD+a62XR+hzC5YfsWm+6lO0Kybcga3yYEij9beegO0jZgug27V+Rf7vns95VPVP6mFd/DEQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/color-mode": "2.2.0",
|
||||||
|
"@chakra-ui/object-utils": "2.1.0",
|
||||||
|
"@chakra-ui/react-utils": "2.0.12",
|
||||||
|
"@chakra-ui/styled-system": "2.9.2",
|
||||||
|
"@chakra-ui/theme-utils": "2.0.21",
|
||||||
|
"@chakra-ui/utils": "2.0.15",
|
||||||
|
"react-fast-compare": "3.2.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@emotion/react": "^11.0.0",
|
||||||
|
"@emotion/styled": "^11.0.0",
|
||||||
|
"react": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/theme": {
|
||||||
|
"version": "3.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/theme/-/theme-3.3.1.tgz",
|
||||||
|
"integrity": "sha512-Hft/VaT8GYnItGCBbgWd75ICrIrIFrR7lVOhV/dQnqtfGqsVDlrztbSErvMkoPKt0UgAkd9/o44jmZ6X4U2nZQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/anatomy": "2.2.2",
|
||||||
|
"@chakra-ui/shared-utils": "2.0.5",
|
||||||
|
"@chakra-ui/theme-tools": "2.1.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@chakra-ui/styled-system": ">=2.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/theme-tools": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/theme-tools/-/theme-tools-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-Qdj8ajF9kxY4gLrq7gA+Azp8CtFHGO9tWMN2wfF9aQNgG9AuMhPrUzMq9AMQ0MXiYcgNq/FD3eegB43nHVmXVA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/anatomy": "2.2.2",
|
||||||
|
"@chakra-ui/shared-utils": "2.0.5",
|
||||||
|
"color2k": "^2.0.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@chakra-ui/styled-system": ">=2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/theme-utils": {
|
||||||
|
"version": "2.0.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/theme-utils/-/theme-utils-2.0.21.tgz",
|
||||||
|
"integrity": "sha512-FjH5LJbT794r0+VSCXB3lT4aubI24bLLRWB+CuRKHijRvsOg717bRdUN/N1fEmEpFnRVrbewttWh/OQs0EWpWw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@chakra-ui/shared-utils": "2.0.5",
|
||||||
|
"@chakra-ui/styled-system": "2.9.2",
|
||||||
|
"@chakra-ui/theme": "3.3.1",
|
||||||
|
"lodash.mergewith": "4.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@chakra-ui/utils": {
|
||||||
|
"version": "2.0.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@chakra-ui/utils/-/utils-2.0.15.tgz",
|
||||||
|
"integrity": "sha512-El4+jL0WSaYYs+rJbuYFDbjmfCcfGDmRY95GO4xwzit6YAPZBLcR65rOEwLps+XWluZTy1xdMrusg/hW0c1aAA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/lodash.mergewith": "4.6.7",
|
||||||
|
"css-box-model": "1.2.1",
|
||||||
|
"framesync": "6.1.2",
|
||||||
|
"lodash.mergewith": "4.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@clack/core": {
|
"node_modules/@clack/core": {
|
||||||
"version": "0.3.4",
|
"version": "0.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/@clack/core/-/core-0.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@clack/core/-/core-0.3.4.tgz",
|
||||||
|
|
@ -799,6 +1087,195 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@emotion/babel-plugin": {
|
||||||
|
"version": "11.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz",
|
||||||
|
"integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/helper-module-imports": "^7.16.7",
|
||||||
|
"@babel/runtime": "^7.18.3",
|
||||||
|
"@emotion/hash": "^0.9.1",
|
||||||
|
"@emotion/memoize": "^0.8.1",
|
||||||
|
"@emotion/serialize": "^1.1.2",
|
||||||
|
"babel-plugin-macros": "^3.1.0",
|
||||||
|
"convert-source-map": "^1.5.0",
|
||||||
|
"escape-string-regexp": "^4.0.0",
|
||||||
|
"find-root": "^1.1.0",
|
||||||
|
"source-map": "^0.5.7",
|
||||||
|
"stylis": "4.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/babel-plugin/node_modules/convert-source-map": {
|
||||||
|
"version": "1.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
|
||||||
|
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/babel-plugin/node_modules/source-map": {
|
||||||
|
"version": "0.5.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||||
|
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/cache": {
|
||||||
|
"version": "11.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz",
|
||||||
|
"integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/memoize": "^0.8.1",
|
||||||
|
"@emotion/sheet": "^1.2.2",
|
||||||
|
"@emotion/utils": "^1.2.1",
|
||||||
|
"@emotion/weak-memoize": "^0.3.1",
|
||||||
|
"stylis": "4.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/hash": {
|
||||||
|
"version": "0.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz",
|
||||||
|
"integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/is-prop-valid": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/memoize": "^0.8.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/memoize": {
|
||||||
|
"version": "0.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz",
|
||||||
|
"integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/react": {
|
||||||
|
"version": "11.11.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz",
|
||||||
|
"integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.18.3",
|
||||||
|
"@emotion/babel-plugin": "^11.11.0",
|
||||||
|
"@emotion/cache": "^11.11.0",
|
||||||
|
"@emotion/serialize": "^1.1.3",
|
||||||
|
"@emotion/use-insertion-effect-with-fallbacks": "^1.0.1",
|
||||||
|
"@emotion/utils": "^1.2.1",
|
||||||
|
"@emotion/weak-memoize": "^0.3.1",
|
||||||
|
"hoist-non-react-statics": "^3.3.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/serialize": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@emotion/hash": "^0.9.1",
|
||||||
|
"@emotion/memoize": "^0.8.1",
|
||||||
|
"@emotion/unitless": "^0.8.1",
|
||||||
|
"@emotion/utils": "^1.2.1",
|
||||||
|
"csstype": "^3.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/sheet": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/styled": {
|
||||||
|
"version": "11.11.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.5.tgz",
|
||||||
|
"integrity": "sha512-/ZjjnaNKvuMPxcIiUkf/9SHoG4Q196DRl1w82hQ3WCsjo1IUR8uaGWrC6a87CrYAW0Kb/pK7hk8BnLgLRi9KoQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.18.3",
|
||||||
|
"@emotion/babel-plugin": "^11.11.0",
|
||||||
|
"@emotion/is-prop-valid": "^1.2.2",
|
||||||
|
"@emotion/serialize": "^1.1.4",
|
||||||
|
"@emotion/use-insertion-effect-with-fallbacks": "^1.0.1",
|
||||||
|
"@emotion/utils": "^1.2.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@emotion/react": "^11.0.0-rc.0",
|
||||||
|
"react": ">=16.8.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/unitless": {
|
||||||
|
"version": "0.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz",
|
||||||
|
"integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/use-insertion-effect-with-fallbacks": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/utils": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
|
"node_modules/@emotion/weak-memoize": {
|
||||||
|
"version": "0.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz",
|
||||||
|
"integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
"node_modules/@esbuild/aix-ppc64": {
|
||||||
"version": "0.21.5",
|
"version": "0.21.5",
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
|
||||||
|
|
@ -4998,8 +5475,17 @@
|
||||||
"node_modules/@types/lodash": {
|
"node_modules/@types/lodash": {
|
||||||
"version": "4.17.5",
|
"version": "4.17.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz",
|
||||||
"integrity": "sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==",
|
"integrity": "sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw=="
|
||||||
"dev": true
|
},
|
||||||
|
"node_modules/@types/lodash.mergewith": {
|
||||||
|
"version": "4.6.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/lodash.mergewith/-/lodash.mergewith-4.6.7.tgz",
|
||||||
|
"integrity": "sha512-3m+lkO5CLRRYU0fhGRp7zbsGi6+BZj0uTVSwvcKU+nSlhjA9/QRNfuSGnD2mX6hQA7ZbmcCkzk5h4ZYGOtk14A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/lodash": "*"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/mathjax": {
|
"node_modules/@types/mathjax": {
|
||||||
"version": "0.0.37",
|
"version": "0.0.37",
|
||||||
|
|
@ -5028,6 +5514,13 @@
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~5.26.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/parse-json": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/@types/prop-types": {
|
"node_modules/@types/prop-types": {
|
||||||
"version": "15.7.12",
|
"version": "15.7.12",
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
|
||||||
|
|
@ -5402,6 +5895,49 @@
|
||||||
"proxy-from-env": "^1.1.0"
|
"proxy-from-env": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/babel-plugin-macros": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.12.5",
|
||||||
|
"cosmiconfig": "^7.0.0",
|
||||||
|
"resolve": "^1.19.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10",
|
||||||
|
"npm": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/babel-plugin-macros/node_modules/cosmiconfig": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/parse-json": "^4.0.0",
|
||||||
|
"import-fresh": "^3.2.1",
|
||||||
|
"parse-json": "^5.0.0",
|
||||||
|
"path-type": "^4.0.0",
|
||||||
|
"yaml": "^1.10.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/babel-plugin-macros/node_modules/yaml": {
|
||||||
|
"version": "1.10.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||||
|
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/babel-plugin-syntax-hermes-parser": {
|
"node_modules/babel-plugin-syntax-hermes-parser": {
|
||||||
"version": "0.21.1",
|
"version": "0.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.21.1.tgz",
|
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.21.1.tgz",
|
||||||
|
|
@ -6358,6 +6894,13 @@
|
||||||
"color-support": "bin.js"
|
"color-support": "bin.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/color2k": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/color2k/-/color2k-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-zW190nQTIoXcGCaU08DvVNFTmQhUpnJfVuAKfWqUQkflXKpaDdpaYoM0iluLS9lgJNHyBF58KKA2FBEwkD7wog==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/combined-stream": {
|
"node_modules/combined-stream": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
|
@ -6461,6 +7004,16 @@
|
||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/css-box-model": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tiny-invariant": "^1.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/css.escape": {
|
"node_modules/css.escape": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
|
||||||
|
|
@ -7571,6 +8124,13 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/find-root": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/find-up": {
|
"node_modules/find-up": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
|
||||||
|
|
@ -7735,6 +8295,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/framesync": {
|
||||||
|
"version": "6.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/framesync/-/framesync-6.1.2.tgz",
|
||||||
|
"integrity": "sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/framesync/node_modules/tslib": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
|
||||||
|
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
|
||||||
|
"license": "0BSD",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/fs-extra": {
|
"node_modules/fs-extra": {
|
||||||
"version": "11.2.0",
|
"version": "11.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
|
||||||
|
|
@ -9249,6 +9826,13 @@
|
||||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.mergewith": {
|
||||||
|
"version": "4.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
|
||||||
|
"integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/lodash.template": {
|
"node_modules/lodash.template": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
|
||||||
|
|
@ -12228,6 +12812,13 @@
|
||||||
"react": ">=16.13.1"
|
"react": ">=16.13.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-fast-compare": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/react-hook-form": {
|
"node_modules/react-hook-form": {
|
||||||
"version": "7.52.0",
|
"version": "7.52.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.52.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.52.0.tgz",
|
||||||
|
|
@ -13637,6 +14228,13 @@
|
||||||
"inline-style-parser": "0.1.1"
|
"inline-style-parser": "0.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/stylis": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/sucrase": {
|
"node_modules/sucrase": {
|
||||||
"version": "3.35.0",
|
"version": "3.35.0",
|
||||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
|
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@chakra-ui/number-input": "^2.1.2",
|
||||||
"@headlessui/react": "^2.0.4",
|
"@headlessui/react": "^2.0.4",
|
||||||
"@hookform/resolvers": "^3.6.0",
|
"@hookform/resolvers": "^3.6.0",
|
||||||
"@million/lint": "^1.0.0-rc.26",
|
"@million/lint": "^1.0.0-rc.26",
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,22 @@
|
||||||
import TableNodeComponent from "@/components/TableNodeComponent";
|
import useHandleNodeClass from "@/CustomNodes/hooks/use-handle-node-class";
|
||||||
|
import { ParameterRenderComponent } from "@/components/parameterRenderComponent";
|
||||||
|
import { usePostTemplateValue } from "@/controllers/API/queries/nodes/use-post-template-value";
|
||||||
|
import useAlertStore from "@/stores/alertStore";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import { ReactNode, useEffect, useRef, useState } from "react";
|
import { ReactNode, useEffect, useRef, useState } from "react";
|
||||||
import { useHotkeys } from "react-hotkeys-hook";
|
import { useHotkeys } from "react-hotkeys-hook";
|
||||||
import { useUpdateNodeInternals } from "reactflow";
|
import { useUpdateNodeInternals } from "reactflow";
|
||||||
import CodeAreaComponent from "../../../../components/codeAreaComponent";
|
|
||||||
import DictComponent from "../../../../components/dictComponent";
|
|
||||||
import Dropdown from "../../../../components/dropdownComponent";
|
|
||||||
import FloatComponent from "../../../../components/floatComponent";
|
|
||||||
import { default as IconComponent } from "../../../../components/genericIconComponent";
|
import { default as IconComponent } from "../../../../components/genericIconComponent";
|
||||||
import InputFileComponent from "../../../../components/inputFileComponent";
|
|
||||||
import InputGlobalComponent from "../../../../components/inputGlobalComponent";
|
|
||||||
import InputListComponent from "../../../../components/inputListComponent";
|
|
||||||
import IntComponent from "../../../../components/intComponent";
|
|
||||||
import KeypairListComponent from "../../../../components/keypairListComponent";
|
|
||||||
import { Multiselect } from "../../../../components/multiselectComponent";
|
|
||||||
import PromptAreaComponent from "../../../../components/promptComponent";
|
|
||||||
import ShadTooltip from "../../../../components/shadTooltipComponent";
|
import ShadTooltip from "../../../../components/shadTooltipComponent";
|
||||||
import TextAreaComponent from "../../../../components/textAreaComponent";
|
|
||||||
import ToggleShadComponent from "../../../../components/toggleShadComponent";
|
|
||||||
import { Button } from "../../../../components/ui/button";
|
import { Button } from "../../../../components/ui/button";
|
||||||
import { RefreshButton } from "../../../../components/ui/refreshButton";
|
|
||||||
import { LANGFLOW_SUPPORTED_TYPES } from "../../../../constants/constants";
|
import { LANGFLOW_SUPPORTED_TYPES } from "../../../../constants/constants";
|
||||||
import { Case } from "../../../../shared/components/caseComponent";
|
import { Case } from "../../../../shared/components/caseComponent";
|
||||||
import useFlowStore from "../../../../stores/flowStore";
|
import useFlowStore from "../../../../stores/flowStore";
|
||||||
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
|
|
||||||
import { useShortcutsStore } from "../../../../stores/shortcuts";
|
import { useShortcutsStore } from "../../../../stores/shortcuts";
|
||||||
import { useTypesStore } from "../../../../stores/typesStore";
|
import { useTypesStore } from "../../../../stores/typesStore";
|
||||||
import { APIClassType } from "../../../../types/api";
|
|
||||||
import { ParameterComponentType } from "../../../../types/components";
|
import { ParameterComponentType } from "../../../../types/components";
|
||||||
import {
|
import {
|
||||||
debouncedHandleUpdateValues,
|
|
||||||
handleUpdateValues,
|
|
||||||
} from "../../../../utils/parameterUtils";
|
|
||||||
import {
|
|
||||||
convertObjToArray,
|
|
||||||
convertValuesToNumbers,
|
|
||||||
getGroupOutputNodeId,
|
getGroupOutputNodeId,
|
||||||
hasDuplicateKeys,
|
|
||||||
scapedJSONStringfy,
|
scapedJSONStringfy,
|
||||||
} from "../../../../utils/reactflowUtils";
|
} from "../../../../utils/reactflowUtils";
|
||||||
import {
|
import {
|
||||||
|
|
@ -49,12 +29,9 @@ import {
|
||||||
} from "../../../../utils/utils";
|
} from "../../../../utils/utils";
|
||||||
import useFetchDataOnMount from "../../../hooks/use-fetch-data-on-mount";
|
import useFetchDataOnMount from "../../../hooks/use-fetch-data-on-mount";
|
||||||
import useHandleOnNewValue from "../../../hooks/use-handle-new-value";
|
import useHandleOnNewValue from "../../../hooks/use-handle-new-value";
|
||||||
import useHandleNodeClass from "../../../hooks/use-handle-node-class";
|
|
||||||
import useHandleRefreshButtonPress from "../../../hooks/use-handle-refresh-buttons";
|
|
||||||
import OutputComponent from "../OutputComponent";
|
import OutputComponent from "../OutputComponent";
|
||||||
import HandleRenderComponent from "../handleRenderComponent";
|
import HandleRenderComponent from "../handleRenderComponent";
|
||||||
import OutputModal from "../outputModal";
|
import OutputModal from "../outputModal";
|
||||||
import { TEXT_FIELD_TYPES } from "./constants";
|
|
||||||
|
|
||||||
export default function ParameterComponent({
|
export default function ParameterComponent({
|
||||||
left,
|
left,
|
||||||
|
|
@ -81,10 +58,12 @@ export default function ParameterComponent({
|
||||||
const edges = useFlowStore((state) => state.edges);
|
const edges = useFlowStore((state) => state.edges);
|
||||||
const setNode = useFlowStore((state) => state.setNode);
|
const setNode = useFlowStore((state) => state.setNode);
|
||||||
const myData = useTypesStore((state) => state.data);
|
const myData = useTypesStore((state) => state.data);
|
||||||
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
|
const postTemplateValue = usePostTemplateValue({
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
node: data.node!,
|
||||||
|
nodeId: data.id,
|
||||||
|
parameterId: name,
|
||||||
|
});
|
||||||
const updateNodeInternals = useUpdateNodeInternals();
|
const updateNodeInternals = useUpdateNodeInternals();
|
||||||
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
|
|
||||||
const setFilterEdge = useFlowStore((state) => state.setFilterEdge);
|
const setFilterEdge = useFlowStore((state) => state.setFilterEdge);
|
||||||
const [openOutputModal, setOpenOutputModal] = useState(false);
|
const [openOutputModal, setOpenOutputModal] = useState(false);
|
||||||
const flowPool = useFlowStore((state) => state.flowPool);
|
const flowPool = useFlowStore((state) => state.flowPool);
|
||||||
|
|
@ -132,29 +111,12 @@ export default function ParameterComponent({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
|
|
||||||
const output = useShortcutsStore((state) => state.output);
|
const output = useShortcutsStore((state) => state.output);
|
||||||
useHotkeys(output, handleOutputWShortcut, { preventDefault });
|
useHotkeys(output, handleOutputWShortcut, { preventDefault });
|
||||||
|
|
||||||
const { handleOnNewValue: handleOnNewValueHook } = useHandleOnNewValue(
|
const { handleNodeClass } = useHandleNodeClass(data.id);
|
||||||
data,
|
|
||||||
name,
|
|
||||||
takeSnapshot,
|
|
||||||
handleUpdateValues,
|
|
||||||
debouncedHandleUpdateValues,
|
|
||||||
setNode,
|
|
||||||
setIsLoading,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { handleNodeClass: handleNodeClassHook } = useHandleNodeClass(
|
|
||||||
data,
|
|
||||||
name,
|
|
||||||
takeSnapshot,
|
|
||||||
setNode,
|
|
||||||
updateNodeInternals,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { handleRefreshButtonPress: handleRefreshButtonPressHook } =
|
|
||||||
useHandleRefreshButtonPress(setIsLoading, setNode);
|
|
||||||
|
|
||||||
let disabled =
|
let disabled =
|
||||||
edges.some(
|
edges.some(
|
||||||
|
|
@ -168,27 +130,13 @@ export default function ParameterComponent({
|
||||||
edge.sourceHandle === scapedJSONStringfy(proxy ? { ...id, proxy } : id),
|
edge.sourceHandle === scapedJSONStringfy(proxy ? { ...id, proxy } : id),
|
||||||
) ?? false;
|
) ?? false;
|
||||||
|
|
||||||
const handleRefreshButtonPress = async (name, data) => {
|
const { handleOnNewValue } = useHandleOnNewValue({
|
||||||
handleRefreshButtonPressHook(name, data);
|
node: data.node!,
|
||||||
};
|
nodeId: data.id,
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
|
||||||
useFetchDataOnMount(data, name, handleUpdateValues, setNode, setIsLoading);
|
useFetchDataOnMount(data.node!, handleNodeClass, name, postTemplateValue);
|
||||||
|
|
||||||
const handleOnNewValue = async (
|
|
||||||
newValue: string | string[] | boolean | Object[],
|
|
||||||
dbValue?: boolean,
|
|
||||||
skipSnapshot: boolean | undefined = false,
|
|
||||||
): Promise<void> => {
|
|
||||||
handleOnNewValueHook(newValue, dbValue, skipSnapshot);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleNodeClass = (
|
|
||||||
newNodeClass: APIClassType,
|
|
||||||
code?: string,
|
|
||||||
type?: string,
|
|
||||||
): void => {
|
|
||||||
handleNodeClassHook(newNodeClass, code, type);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|
@ -401,301 +349,21 @@ export default function ParameterComponent({
|
||||||
testIdComplement={`${data?.type?.toLowerCase()}-shownode`}
|
testIdComplement={`${data?.type?.toLowerCase()}-shownode`}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
<div className="mt-2 w-full">
|
||||||
<Case
|
{data.node?.template[name] !== undefined && (
|
||||||
condition={
|
<ParameterRenderComponent
|
||||||
left === true &&
|
handleOnNewValue={handleOnNewValue}
|
||||||
TEXT_FIELD_TYPES.includes(type ?? "") &&
|
name={name}
|
||||||
!data.node?.template[name]?.options
|
nodeId={data.id}
|
||||||
}
|
templateData={data.node?.template[name]!}
|
||||||
>
|
templateValue={data.node?.template[name].value ?? ""}
|
||||||
<div className="w-full">
|
|
||||||
<Case condition={data.node?.template[name]?.list}>
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
// Commenting this out until we have a better
|
|
||||||
// way to display
|
|
||||||
// (data.node?.template[name]?.refresh ? "w-5/6 " : "") +
|
|
||||||
"mt-2 flex-grow"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<InputListComponent
|
|
||||||
componentName={name}
|
|
||||||
disabled={disabled}
|
|
||||||
value={
|
|
||||||
!data.node!.template[name]?.value ||
|
|
||||||
data.node!.template[name]?.value === ""
|
|
||||||
? [""]
|
|
||||||
: data.node!.template[name]?.value
|
|
||||||
}
|
|
||||||
onChange={handleOnNewValue}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
<Case condition={data.node?.template[name]?.multiline}>
|
|
||||||
<div className="mt-2 flex w-full flex-col">
|
|
||||||
<div className="flex-grow">
|
|
||||||
<TextAreaComponent
|
|
||||||
disabled={disabled}
|
|
||||||
value={data.node!.template[name]?.value ?? ""}
|
|
||||||
onChange={handleOnNewValue}
|
|
||||||
id={"textarea-" + data.node!.template[name]?.name}
|
|
||||||
data-testid={"textarea-" + data.node!.template[name]?.name}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{data.node?.template[name]?.refresh_button && (
|
|
||||||
<div className="flex-grow">
|
|
||||||
<RefreshButton
|
|
||||||
isLoading={isLoading}
|
|
||||||
disabled={disabled}
|
|
||||||
name={name}
|
|
||||||
data={data}
|
|
||||||
button_text={
|
|
||||||
data.node?.template[name].refresh_button_text
|
|
||||||
}
|
|
||||||
className="extra-side-bar-buttons mt-1"
|
|
||||||
handleUpdateValues={handleRefreshButtonPress}
|
|
||||||
id={"refresh-button-" + name}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
!data.node?.template[name]?.multiline &&
|
|
||||||
!data.node?.template[name]?.list
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="mt-2 flex w-full items-center">
|
|
||||||
<div
|
|
||||||
className={
|
|
||||||
"flex-grow " +
|
|
||||||
(data.node?.template[name]?.refresh_button ? "w-5/6" : "")
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<InputGlobalComponent
|
|
||||||
disabled={disabled}
|
|
||||||
onChange={handleOnNewValue}
|
|
||||||
name={name}
|
|
||||||
data={data.node?.template[name]!}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{data.node?.template[name]?.refresh_button && (
|
|
||||||
<div className="w-1/6">
|
|
||||||
<RefreshButton
|
|
||||||
isLoading={isLoading}
|
|
||||||
disabled={disabled}
|
|
||||||
name={name}
|
|
||||||
data={data}
|
|
||||||
button_text={
|
|
||||||
data.node?.template[name].refresh_button_text
|
|
||||||
}
|
|
||||||
className="extra-side-bar-buttons ml-2 mt-1"
|
|
||||||
handleUpdateValues={handleRefreshButtonPress}
|
|
||||||
id={"refresh-button-" + name}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case condition={left === true && type === "bool"}>
|
|
||||||
<div className="mt-2 w-full">
|
|
||||||
<ToggleShadComponent
|
|
||||||
id={"toggle-" + name}
|
|
||||||
disabled={disabled}
|
|
||||||
enabled={data.node?.template[name]?.value ?? false}
|
|
||||||
setEnabled={handleOnNewValue}
|
|
||||||
size="large"
|
|
||||||
editNode={false}
|
editNode={false}
|
||||||
/>
|
handleNodeClass={handleNodeClass}
|
||||||
</div>
|
nodeClass={data.node!}
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case condition={left === true && type === "float"}>
|
|
||||||
<div className="mt-2 w-full">
|
|
||||||
<FloatComponent
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
value={data.node?.template[name]?.value ?? ""}
|
|
||||||
rangeSpec={data.node?.template[name]?.rangeSpec}
|
|
||||||
onChange={handleOnNewValue}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
)}
|
||||||
</Case>
|
</div>
|
||||||
<Case condition={left === true && type === "table"}>
|
|
||||||
<div className="mt-2 w-full">
|
|
||||||
<TableNodeComponent
|
|
||||||
description={info || "Add or edit data"}
|
|
||||||
columns={data.node?.template[name]?.table_schema?.columns}
|
|
||||||
onChange={handleOnNewValue}
|
|
||||||
tableTitle={data.node?.template[name]?.display_name ?? "Table"}
|
|
||||||
value={data.node?.template[name]?.value}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
left === true &&
|
|
||||||
type === "str" &&
|
|
||||||
!data.node?.template[name]?.list &&
|
|
||||||
(data.node?.template[name]?.options ||
|
|
||||||
data.node?.template[name]?.real_time_refresh)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="mt-2 flex w-full items-center gap-2">
|
|
||||||
<div className="flex-1">
|
|
||||||
<Dropdown
|
|
||||||
disabled={disabled}
|
|
||||||
isLoading={isLoading}
|
|
||||||
options={data.node!.template[name]?.options}
|
|
||||||
onSelect={handleOnNewValue}
|
|
||||||
value={data.node!.template[name]?.value}
|
|
||||||
id={"dropdown-" + name}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{data.node?.template[name]?.refresh_button && (
|
|
||||||
<div className="w-1/6">
|
|
||||||
<RefreshButton
|
|
||||||
isLoading={isLoading}
|
|
||||||
disabled={disabled}
|
|
||||||
name={name}
|
|
||||||
data={data}
|
|
||||||
button_text={data.node?.template[name]?.refresh_button_text}
|
|
||||||
handleUpdateValues={handleRefreshButtonPress}
|
|
||||||
id={"refresh-button-" + name}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
type === "str" &&
|
|
||||||
!!data.node?.template[name]?.options &&
|
|
||||||
!!data.node?.template[name]?.list
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="mt-2 flex w-full items-center">
|
|
||||||
<Multiselect
|
|
||||||
disabled={disabled}
|
|
||||||
options={data?.node?.template?.[name]?.options || []}
|
|
||||||
values={data?.node?.template?.[name]?.value || []}
|
|
||||||
id={"multiselect-" + name}
|
|
||||||
onValueChange={handleOnNewValue}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case condition={left === true && type === "code"}>
|
|
||||||
<div className="mt-2 w-full">
|
|
||||||
<CodeAreaComponent
|
|
||||||
readonly={
|
|
||||||
data.node?.flow && data.node.template[name]?.dynamic
|
|
||||||
? true
|
|
||||||
: false
|
|
||||||
}
|
|
||||||
dynamic={data.node?.template[name]?.dynamic ?? false}
|
|
||||||
setNodeClass={handleNodeClass}
|
|
||||||
nodeClass={data.node}
|
|
||||||
disabled={disabled}
|
|
||||||
value={data.node?.template[name]?.value ?? ""}
|
|
||||||
onChange={handleOnNewValue}
|
|
||||||
id={"code-input-" + name}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case condition={left === true && type === "file"}>
|
|
||||||
<div className="mt-2 w-full">
|
|
||||||
<InputFileComponent
|
|
||||||
disabled={disabled}
|
|
||||||
value={data.node?.template[name]?.value ?? ""}
|
|
||||||
onChange={handleOnNewValue}
|
|
||||||
fileTypes={data.node?.template[name]?.fileTypes}
|
|
||||||
onFileChange={(filePath: string) => {
|
|
||||||
data.node!.template[name].file_path = filePath;
|
|
||||||
}}
|
|
||||||
></InputFileComponent>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case condition={left === true && type === "int"}>
|
|
||||||
<div className="mt-2 w-full">
|
|
||||||
<IntComponent
|
|
||||||
rangeSpec={data.node?.template[name]?.rangeSpec}
|
|
||||||
disabled={disabled}
|
|
||||||
value={data.node?.template[name]?.value ?? ""}
|
|
||||||
onChange={handleOnNewValue}
|
|
||||||
id={"int-input-" + name}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case condition={left === true && type === "prompt"}>
|
|
||||||
<div className="mt-2 w-full">
|
|
||||||
<PromptAreaComponent
|
|
||||||
readonly={data.node?.flow ? true : false}
|
|
||||||
field_name={name}
|
|
||||||
setNodeClass={handleNodeClass}
|
|
||||||
nodeClass={data.node}
|
|
||||||
disabled={disabled}
|
|
||||||
value={data.node?.template[name]?.value ?? ""}
|
|
||||||
onChange={handleOnNewValue}
|
|
||||||
id={"prompt-input-" + name}
|
|
||||||
data-testid={"prompt-input-" + name}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case condition={left === true && type === "NestedDict"}>
|
|
||||||
<div
|
|
||||||
className={"mt-2 w-full" + (disabled ? " cursor-not-allowed" : "")}
|
|
||||||
>
|
|
||||||
<DictComponent
|
|
||||||
disabled={disabled}
|
|
||||||
editNode={false}
|
|
||||||
value={
|
|
||||||
!data.node!.template[name]?.value ||
|
|
||||||
!Object.keys(data.node!.template[name]?.value || {}).length
|
|
||||||
? {}
|
|
||||||
: data.node!.template[name]?.value
|
|
||||||
}
|
|
||||||
onChange={handleOnNewValue}
|
|
||||||
id="div-dict-input"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case condition={left === true && type === "dict"}>
|
|
||||||
<div className="mt-2 w-full">
|
|
||||||
<KeypairListComponent
|
|
||||||
disabled={disabled}
|
|
||||||
editNode={false}
|
|
||||||
value={
|
|
||||||
!data.node!.template[name]?.value ||
|
|
||||||
!Object.keys(data.node!.template[name]?.value || {}).length
|
|
||||||
? [{ "": "" }]
|
|
||||||
: convertObjToArray(data.node!.template[name]?.value, type!)
|
|
||||||
}
|
|
||||||
duplicateKey={errorDuplicateKey}
|
|
||||||
onChange={(newValue) => {
|
|
||||||
const valueToNumbers = convertValuesToNumbers(newValue);
|
|
||||||
setErrorDuplicateKey(hasDuplicateKeys(valueToNumbers));
|
|
||||||
// if data.node?.template[name]?.list is true, then the value is an array of objects
|
|
||||||
// else we need to get the first object of the array
|
|
||||||
|
|
||||||
if (data.node?.template[name]?.list) {
|
|
||||||
handleOnNewValue(valueToNumbers);
|
|
||||||
} else handleOnNewValue(valueToNumbers[0]);
|
|
||||||
}}
|
|
||||||
isList={data.node?.template[name]?.list ?? false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
{openOutputModal && (
|
{openOutputModal && (
|
||||||
<OutputModal
|
<OutputModal
|
||||||
open={openOutputModal}
|
open={openOutputModal}
|
||||||
|
|
|
||||||
44
src/frontend/src/CustomNodes/helpers/mutate-template.ts
Normal file
44
src/frontend/src/CustomNodes/helpers/mutate-template.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import {
|
||||||
|
ERROR_UPDATING_COMPONENT,
|
||||||
|
SAVE_DEBOUNCE_TIME,
|
||||||
|
TITLE_ERROR_UPDATING_COMPONENT,
|
||||||
|
} from "@/constants/constants";
|
||||||
|
import {
|
||||||
|
APIClassType,
|
||||||
|
APITemplateType,
|
||||||
|
ResponseErrorDetailAPI,
|
||||||
|
} from "@/types/api";
|
||||||
|
import { UseMutationResult } from "@tanstack/react-query";
|
||||||
|
import { cloneDeep, debounce } from "lodash";
|
||||||
|
|
||||||
|
export const mutateTemplate = debounce(
|
||||||
|
async (
|
||||||
|
newValue,
|
||||||
|
node: APIClassType,
|
||||||
|
setNodeClass,
|
||||||
|
postTemplateValue: UseMutationResult<
|
||||||
|
APITemplateType | undefined,
|
||||||
|
ResponseErrorDetailAPI,
|
||||||
|
any
|
||||||
|
>,
|
||||||
|
setErrorData,
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const newNode = cloneDeep(node);
|
||||||
|
const newTemplate = await postTemplateValue.mutateAsync({
|
||||||
|
value: newValue,
|
||||||
|
});
|
||||||
|
if (newTemplate) {
|
||||||
|
newNode.template = newTemplate;
|
||||||
|
}
|
||||||
|
setNodeClass(newNode);
|
||||||
|
} catch (e) {
|
||||||
|
const error = e as ResponseErrorDetailAPI;
|
||||||
|
setErrorData({
|
||||||
|
title: TITLE_ERROR_UPDATING_COMPONENT,
|
||||||
|
list: [error.response?.data?.detail || ERROR_UPDATING_COMPONENT],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SAVE_DEBOUNCE_TIME,
|
||||||
|
);
|
||||||
|
|
@ -1,55 +1,40 @@
|
||||||
import { cloneDeep } from "lodash";
|
|
||||||
import { useEffect } from "react";
|
|
||||||
import {
|
import {
|
||||||
ERROR_UPDATING_COMPONENT,
|
APIClassType,
|
||||||
TITLE_ERROR_UPDATING_COMPONENT,
|
APITemplateType,
|
||||||
} from "../../constants/constants";
|
ResponseErrorDetailAPI,
|
||||||
|
} from "@/types/api";
|
||||||
|
import { UseMutationResult } from "@tanstack/react-query";
|
||||||
|
import { useEffect } from "react";
|
||||||
import useAlertStore from "../../stores/alertStore";
|
import useAlertStore from "../../stores/alertStore";
|
||||||
import { ResponseErrorDetailAPI } from "../../types/api";
|
import { mutateTemplate } from "../helpers/mutate-template";
|
||||||
import { NodeDataType } from "../../types/flow";
|
|
||||||
|
|
||||||
const useFetchDataOnMount = (
|
const useFetchDataOnMount = (
|
||||||
data: NodeDataType,
|
node: APIClassType,
|
||||||
|
setNodeClass: (node: APIClassType) => void,
|
||||||
name: string,
|
name: string,
|
||||||
handleUpdateValues: (name: string, data: NodeDataType) => Promise<any>,
|
postTemplateValue: UseMutationResult<
|
||||||
setNode: (id: string, callback: (oldNode: any) => any) => void,
|
APITemplateType | undefined,
|
||||||
setIsLoading: (value: boolean) => void,
|
ResponseErrorDetailAPI,
|
||||||
|
any
|
||||||
|
>,
|
||||||
) => {
|
) => {
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
|
const template = node.template[name];
|
||||||
if (
|
if (
|
||||||
(data.node?.template[name]?.real_time_refresh ||
|
(template?.real_time_refresh || template?.refresh_button) &&
|
||||||
data.node?.template[name]?.refresh_button) &&
|
|
||||||
// options can be undefined but not an empty array
|
// options can be undefined but not an empty array
|
||||||
(data.node?.template[name]?.options?.length ?? 0) === 0
|
(template?.options?.length ?? 0) === 0
|
||||||
) {
|
) {
|
||||||
setIsLoading(true);
|
mutateTemplate(
|
||||||
try {
|
template?.value,
|
||||||
let newTemplate = await handleUpdateValues(name, data);
|
node,
|
||||||
|
setNodeClass,
|
||||||
if (newTemplate) {
|
postTemplateValue,
|
||||||
setNode(data.id, (oldNode) => {
|
setErrorData,
|
||||||
let newNode = cloneDeep(oldNode);
|
);
|
||||||
newNode.data = {
|
|
||||||
...newNode.data,
|
|
||||||
};
|
|
||||||
newNode.data.node.template = newTemplate;
|
|
||||||
return newNode;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
let responseError = error as ResponseErrorDetailAPI;
|
|
||||||
|
|
||||||
setErrorData({
|
|
||||||
title: TITLE_ERROR_UPDATING_COMPONENT,
|
|
||||||
list: [
|
|
||||||
responseError?.response?.data?.detail ?? ERROR_UPDATING_COMPONENT,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fetchData();
|
fetchData();
|
||||||
|
|
|
||||||
|
|
@ -1,79 +1,100 @@
|
||||||
|
import { usePostTemplateValue } from "@/controllers/API/queries/nodes/use-post-template-value";
|
||||||
|
import useAlertStore from "@/stores/alertStore";
|
||||||
|
import useFlowStore from "@/stores/flowStore";
|
||||||
|
import useFlowsManagerStore from "@/stores/flowsManagerStore";
|
||||||
|
import { APIClassType, InputFieldType } from "@/types/api";
|
||||||
|
import { NodeType } from "@/types/flow";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import {
|
import { mutateTemplate } from "../helpers/mutate-template";
|
||||||
ERROR_UPDATING_COMPONENT,
|
|
||||||
TITLE_ERROR_UPDATING_COMPONENT,
|
export type handleOnNewValueType = (
|
||||||
} from "../../constants/constants";
|
changes: Partial<InputFieldType>,
|
||||||
import useAlertStore from "../../stores/alertStore";
|
options?: {
|
||||||
import { ResponseErrorTypeAPI } from "../../types/api";
|
skipSnapshot?: boolean;
|
||||||
import { NodeDataType } from "../../types/flow";
|
setNodeClass?: (node: APIClassType) => void;
|
||||||
|
},
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
const useHandleOnNewValue = ({
|
||||||
|
node,
|
||||||
|
nodeId,
|
||||||
|
name,
|
||||||
|
setNode: setNodeExternal,
|
||||||
|
}: {
|
||||||
|
node: APIClassType;
|
||||||
|
nodeId: string;
|
||||||
|
name: string;
|
||||||
|
setNode?: (
|
||||||
|
id: string,
|
||||||
|
update: NodeType | ((oldState: NodeType) => NodeType),
|
||||||
|
) => void;
|
||||||
|
}) => {
|
||||||
|
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
|
||||||
|
|
||||||
|
const setNode = setNodeExternal ?? useFlowStore((state) => state.setNode);
|
||||||
|
|
||||||
const useHandleOnNewValue = (
|
|
||||||
data: NodeDataType,
|
|
||||||
name: string,
|
|
||||||
takeSnapshot: () => void,
|
|
||||||
handleUpdateValues: (name: string, data: NodeDataType) => Promise<any>,
|
|
||||||
debouncedHandleUpdateValues: any,
|
|
||||||
setNode: (id: string, callback: (oldNode: any) => any) => void,
|
|
||||||
setIsLoading: (value: boolean) => void,
|
|
||||||
) => {
|
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
|
|
||||||
const handleOnNewValue = async (newValue, dbValue, skipSnapshot = false) => {
|
const postTemplateValue = usePostTemplateValue({
|
||||||
const nodeTemplate = data.node!.template[name];
|
parameterId: name,
|
||||||
const currentValue = nodeTemplate.value;
|
nodeId: nodeId,
|
||||||
|
node: node,
|
||||||
|
});
|
||||||
|
|
||||||
if (currentValue !== newValue && !skipSnapshot) {
|
const handleOnNewValue: handleOnNewValueType = async (changes, options?) => {
|
||||||
takeSnapshot();
|
const newNode = cloneDeep(node);
|
||||||
|
const template = newNode.template;
|
||||||
|
|
||||||
|
if (!template) {
|
||||||
|
setErrorData({ title: "Template not found in the component" });
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const parameter = template[name];
|
||||||
|
|
||||||
|
if (!parameter) {
|
||||||
|
setErrorData({ title: "Parameter not found in the template" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options?.skipSnapshot) takeSnapshot();
|
||||||
|
|
||||||
|
Object.entries(changes).forEach(([key, value]) => {
|
||||||
|
if (value !== undefined) parameter[key] = value;
|
||||||
|
});
|
||||||
|
|
||||||
const shouldUpdate =
|
const shouldUpdate =
|
||||||
data.node?.template[name].real_time_refresh &&
|
parameter.real_time_refresh && !parameter.refresh_button;
|
||||||
!data.node?.template[name].refresh_button &&
|
|
||||||
currentValue !== newValue;
|
|
||||||
|
|
||||||
const typeToDebounce = nodeTemplate.type;
|
const setNodeClass = (newNodeClass: APIClassType) => {
|
||||||
|
options?.setNodeClass && options.setNodeClass(newNodeClass);
|
||||||
|
setNode(nodeId, (oldNode) => {
|
||||||
|
const newData = cloneDeep(oldNode.data);
|
||||||
|
newData.node = newNodeClass;
|
||||||
|
return {
|
||||||
|
...oldNode,
|
||||||
|
data: newData,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
nodeTemplate.value = newValue;
|
if (shouldUpdate && changes.value) {
|
||||||
|
mutateTemplate(
|
||||||
let newTemplate;
|
changes.value,
|
||||||
if (shouldUpdate) {
|
newNode,
|
||||||
setIsLoading(true);
|
setNodeClass,
|
||||||
try {
|
postTemplateValue,
|
||||||
if (["int"].includes(typeToDebounce)) {
|
setErrorData,
|
||||||
newTemplate = await handleUpdateValues(name, data);
|
);
|
||||||
} else {
|
|
||||||
newTemplate = await debouncedHandleUpdateValues(name, data);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
let responseError = error as ResponseErrorTypeAPI;
|
|
||||||
setErrorData({
|
|
||||||
title: TITLE_ERROR_UPDATING_COMPONENT,
|
|
||||||
list: [
|
|
||||||
responseError?.response?.data?.detail.error ??
|
|
||||||
ERROR_UPDATING_COMPONENT,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setNode(data.id, (oldNode) => {
|
setNode(nodeId, (oldNode) => {
|
||||||
const newNode = cloneDeep(oldNode);
|
const newData = cloneDeep(oldNode.data);
|
||||||
newNode.data = {
|
newData.node = newNode;
|
||||||
...newNode.data,
|
return {
|
||||||
|
...oldNode,
|
||||||
|
data: newData,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (dbValue !== undefined) {
|
|
||||||
newNode.data.node.template[name].load_from_db = dbValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.node?.template[name].real_time_refresh && newTemplate) {
|
|
||||||
newNode.data.node.template = newTemplate;
|
|
||||||
} else {
|
|
||||||
newNode.data.node.template[name].value = newValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return newNode;
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,30 @@
|
||||||
|
import useFlowStore from "@/stores/flowStore";
|
||||||
|
import { NodeType } from "@/types/flow";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import { NodeDataType } from "../../types/flow";
|
|
||||||
|
|
||||||
const useHandleNodeClass = (
|
const useHandleNodeClass = (
|
||||||
data: NodeDataType,
|
nodeId: string,
|
||||||
name: string,
|
setMyNode?: (
|
||||||
takeSnapshot: () => void,
|
id: string,
|
||||||
setNode: (id: string, callback: (oldNode: any) => any) => void,
|
update: NodeType | ((oldState: NodeType) => NodeType),
|
||||||
updateNodeInternals: (id: string) => void,
|
) => void,
|
||||||
) => {
|
) => {
|
||||||
const handleNodeClass = (newNodeClass, code, type?: string) => {
|
const setNode = setMyNode ?? useFlowStore((state) => state.setNode);
|
||||||
if (!data.node) return;
|
|
||||||
if (data.node!.template[name].value !== code) {
|
|
||||||
takeSnapshot();
|
|
||||||
}
|
|
||||||
|
|
||||||
setNode(data.id, (oldNode) => {
|
const handleNodeClass = (newNodeClass, type?: string) => {
|
||||||
|
setNode(nodeId, (oldNode) => {
|
||||||
let newNode = cloneDeep(oldNode);
|
let newNode = cloneDeep(oldNode);
|
||||||
|
|
||||||
newNode.data = {
|
newNode.data = {
|
||||||
...newNode.data,
|
...newNode.data,
|
||||||
node: newNodeClass,
|
node: cloneDeep(newNodeClass),
|
||||||
description: newNodeClass.description ?? data.node!.description,
|
|
||||||
display_name: newNodeClass.display_name ?? data.node!.display_name,
|
|
||||||
};
|
};
|
||||||
if (type) {
|
if (type) {
|
||||||
newNode.data.type = type;
|
newNode.data.type = type;
|
||||||
}
|
}
|
||||||
newNode.data.node.template[name].value = code;
|
|
||||||
|
|
||||||
return newNode;
|
return newNode;
|
||||||
});
|
});
|
||||||
|
|
||||||
updateNodeInternals(data.id);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return { handleNodeClass };
|
return { handleNodeClass };
|
||||||
|
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
import { cloneDeep } from "lodash";
|
|
||||||
import {
|
|
||||||
ERROR_UPDATING_COMPONENT,
|
|
||||||
TITLE_ERROR_UPDATING_COMPONENT,
|
|
||||||
} from "../../constants/constants";
|
|
||||||
import useAlertStore from "../../stores/alertStore";
|
|
||||||
import { ResponseErrorDetailAPI } from "../../types/api";
|
|
||||||
import { handleUpdateValues } from "../../utils/parameterUtils";
|
|
||||||
|
|
||||||
const useHandleRefreshButtonPress = (
|
|
||||||
setIsLoading: (value: boolean) => void,
|
|
||||||
setNode: (id: string, callback: (oldNode: any) => any) => void,
|
|
||||||
) => {
|
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
|
||||||
|
|
||||||
const handleRefreshButtonPress = async (name, data) => {
|
|
||||||
setIsLoading(true);
|
|
||||||
try {
|
|
||||||
let newTemplate = await handleUpdateValues(name, data);
|
|
||||||
|
|
||||||
if (newTemplate) {
|
|
||||||
setNode(data.id, (oldNode) => {
|
|
||||||
let newNode = cloneDeep(oldNode);
|
|
||||||
newNode.data = {
|
|
||||||
...newNode.data,
|
|
||||||
};
|
|
||||||
newNode.data.node.template = newTemplate;
|
|
||||||
return newNode;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
let responseError = error as ResponseErrorDetailAPI;
|
|
||||||
|
|
||||||
setErrorData({
|
|
||||||
title: TITLE_ERROR_UPDATING_COMPONENT,
|
|
||||||
list: [
|
|
||||||
responseError?.response?.data?.detail ?? ERROR_UPDATING_COMPONENT,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setIsLoading(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return { handleRefreshButtonPress };
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useHandleRefreshButtonPress;
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
import AccordionComponent from "@/components/accordionComponent";
|
||||||
|
import ShadTooltip from "@/components/shadTooltipComponent";
|
||||||
|
import { EditNodeComponent } from "@/modals/editNodeModal/components/editNodeComponent";
|
||||||
|
import { APIClassType } from "@/types/api";
|
||||||
|
import { NodeType } from "@/types/flow";
|
||||||
|
import { customStringify } from "@/utils/reactflowUtils";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export function TweakComponent({
|
||||||
|
open,
|
||||||
|
node,
|
||||||
|
}: {
|
||||||
|
open: boolean;
|
||||||
|
node: NodeType;
|
||||||
|
}) {
|
||||||
|
const [nodeClass, setNodeClass] = useState<APIClassType | undefined>(
|
||||||
|
node.data?.node,
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
customStringify(Object.keys(node.data?.node?.template ?? {})) ===
|
||||||
|
customStringify(Object.keys(nodeClass?.template ?? {}))
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
setNodeClass(node.data?.node);
|
||||||
|
}, [node.data?.node]);
|
||||||
|
return node && node.data && nodeClass ? (
|
||||||
|
<AccordionComponent
|
||||||
|
trigger={
|
||||||
|
<ShadTooltip side="top" styleClasses="z-50" content={node.data.id}>
|
||||||
|
<div>{node.data.node?.display_name}</div>
|
||||||
|
</ShadTooltip>
|
||||||
|
}
|
||||||
|
keyValue={node.data.id}
|
||||||
|
>
|
||||||
|
<EditNodeComponent
|
||||||
|
open={open}
|
||||||
|
autoHeight
|
||||||
|
hideVisibility
|
||||||
|
nodeClass={nodeClass}
|
||||||
|
isTweaks
|
||||||
|
nodeId={node.data.id}
|
||||||
|
/>
|
||||||
|
</AccordionComponent>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { useTweaksStore } from "@/stores/tweaksStore";
|
||||||
|
import { NodeType } from "@/types/flow";
|
||||||
|
import { TweakComponent } from "../tweakComponent";
|
||||||
|
|
||||||
|
export function TweaksComponent({ open }: { open: boolean }) {
|
||||||
|
const nodes = useTweaksStore((state) => state.nodes);
|
||||||
|
return (
|
||||||
|
<div className="h-full w-full overflow-y-auto overflow-x-hidden rounded-lg bg-muted custom-scroll">
|
||||||
|
{nodes?.map((node: NodeType, i) => (
|
||||||
|
<div className="px-3" key={i}>
|
||||||
|
<TweakComponent open={open} node={node} />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,82 +1,34 @@
|
||||||
import { cloneDeep } from "lodash";
|
import { useTweaksStore } from "@/stores/tweaksStore";
|
||||||
import { useEffect, useState } from "react";
|
import { useState } from "react";
|
||||||
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
||||||
import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
|
import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
|
||||||
import CodeAreaComponent from "../../components/codeAreaComponent";
|
|
||||||
import Dropdown from "../../components/dropdownComponent";
|
|
||||||
import FloatComponent from "../../components/floatComponent";
|
|
||||||
import InputFileComponent from "../../components/inputFileComponent";
|
|
||||||
import InputListComponent from "../../components/inputListComponent";
|
|
||||||
import IntComponent from "../../components/intComponent";
|
|
||||||
import PromptAreaComponent from "../../components/promptComponent";
|
|
||||||
import TextAreaComponent from "../../components/textAreaComponent";
|
|
||||||
import ToggleShadComponent from "../../components/toggleShadComponent";
|
|
||||||
import {
|
|
||||||
Table,
|
|
||||||
TableBody,
|
|
||||||
TableCell,
|
|
||||||
TableHead,
|
|
||||||
TableHeader,
|
|
||||||
TableRow,
|
|
||||||
} from "../../components/ui/table";
|
|
||||||
import {
|
import {
|
||||||
Tabs,
|
Tabs,
|
||||||
TabsContent,
|
TabsContent,
|
||||||
TabsList,
|
TabsList,
|
||||||
TabsTrigger,
|
TabsTrigger,
|
||||||
} from "../../components/ui/tabs";
|
} from "../../components/ui/tabs";
|
||||||
import { LANGFLOW_SUPPORTED_TYPES } from "../../constants/constants";
|
|
||||||
import getTabsOrder from "../../modals/apiModal/utils/get-tabs-order";
|
|
||||||
import { Case } from "../../shared/components/caseComponent";
|
|
||||||
import { useDarkStore } from "../../stores/darkStore";
|
import { useDarkStore } from "../../stores/darkStore";
|
||||||
import useFlowStore from "../../stores/flowStore";
|
|
||||||
import { codeTabsPropsType } from "../../types/components";
|
import { codeTabsPropsType } from "../../types/components";
|
||||||
import {
|
import { cn } from "../../utils/utils";
|
||||||
convertObjToArray,
|
|
||||||
convertValuesToNumbers,
|
|
||||||
hasDuplicateKeys,
|
|
||||||
} from "../../utils/reactflowUtils";
|
|
||||||
import { classNames, cn } from "../../utils/utils";
|
|
||||||
import AccordionComponent from "../accordionComponent";
|
|
||||||
import DictComponent from "../dictComponent";
|
|
||||||
import IconComponent from "../genericIconComponent";
|
import IconComponent from "../genericIconComponent";
|
||||||
import InputComponent from "../inputComponent";
|
|
||||||
import KeypairListComponent from "../keypairListComponent";
|
|
||||||
import ShadTooltip from "../shadTooltipComponent";
|
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
import { Label } from "../ui/label";
|
import { Label } from "../ui/label";
|
||||||
import { Switch } from "../ui/switch";
|
import { Switch } from "../ui/switch";
|
||||||
|
import { TweaksComponent } from "./components/tweaksComponent";
|
||||||
|
|
||||||
export default function CodeTabsComponent({
|
export default function CodeTabsComponent({
|
||||||
flow,
|
open,
|
||||||
tabs,
|
tabs,
|
||||||
activeTab,
|
activeTab,
|
||||||
setActiveTab,
|
setActiveTab,
|
||||||
isMessage,
|
isMessage,
|
||||||
tweaks,
|
|
||||||
setActiveTweaks,
|
setActiveTweaks,
|
||||||
activeTweaks,
|
activeTweaks,
|
||||||
allowExport = false,
|
|
||||||
isThereTweaks = false,
|
|
||||||
isThereWH = false,
|
|
||||||
}: codeTabsPropsType) {
|
}: codeTabsPropsType) {
|
||||||
const [isCopied, setIsCopied] = useState<Boolean>(false);
|
const [isCopied, setIsCopied] = useState<Boolean>(false);
|
||||||
const [data, setData] = useState(flow ? flow["data"]!["nodes"] : null);
|
|
||||||
const dark = useDarkStore((state) => state.dark);
|
const dark = useDarkStore((state) => state.dark);
|
||||||
const unselectAll = useFlowStore((state) => state.unselectAll);
|
const nodes = useTweaksStore((state) => state.nodes);
|
||||||
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (flow && flow["data"]!["nodes"]) {
|
|
||||||
setData(flow["data"]!["nodes"]);
|
|
||||||
}
|
|
||||||
}, [flow]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (tweaks && data) {
|
|
||||||
unselectAll();
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const copyToClipboard = () => {
|
const copyToClipboard = () => {
|
||||||
if (!navigator.clipboard || !navigator.clipboard.writeText) {
|
if (!navigator.clipboard || !navigator.clipboard.writeText) {
|
||||||
|
|
@ -92,12 +44,6 @@ export default function CodeTabsComponent({
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const type = (node, templateParam) => {
|
|
||||||
return node.data.node.template[templateParam].type;
|
|
||||||
};
|
|
||||||
|
|
||||||
const tabsOrder = getTabsOrder(isThereWH, isThereTweaks);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs
|
||||||
value={activeTab}
|
value={activeTab}
|
||||||
|
|
@ -130,29 +76,31 @@ export default function CodeTabsComponent({
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="float-right mx-2 mb-1 mt-2 flex items-center gap-4">
|
<div className="float-right mx-2 mb-1 mt-2 flex items-center gap-4">
|
||||||
{tweaks && (
|
{nodes.length > 0 &&
|
||||||
<div className={Number(activeTab) > 2 ? "hidden" : "flex gap-2"}>
|
tabs.find((tab) => tab.name.toLowerCase() === "tweaks") &&
|
||||||
<Switch
|
tabs[activeTab].hasTweaks && (
|
||||||
style={{
|
<div className="flex gap-2">
|
||||||
transform: `scaleX(${0.7}) scaleY(${0.7})`,
|
<Switch
|
||||||
}}
|
style={{
|
||||||
id="tweaks-switch"
|
transform: `scaleX(${0.7}) scaleY(${0.7})`,
|
||||||
onCheckedChange={setActiveTweaks}
|
}}
|
||||||
autoFocus={false}
|
id="tweaks-switch"
|
||||||
/>
|
onCheckedChange={setActiveTweaks}
|
||||||
<Label
|
autoFocus={false}
|
||||||
className={cn(
|
/>
|
||||||
"relative right-1 top-[4px] text-xs font-medium text-muted-foreground",
|
<Label
|
||||||
activeTweaks ? "text-primary" : "",
|
className={cn(
|
||||||
)}
|
"relative right-1 top-[4px] text-xs font-medium text-muted-foreground",
|
||||||
htmlFor="tweaks-switch"
|
activeTweaks ? "text-primary" : "",
|
||||||
>
|
)}
|
||||||
Tweaks
|
htmlFor="tweaks-switch"
|
||||||
</Label>
|
>
|
||||||
</div>
|
Tweaks
|
||||||
)}
|
</Label>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{Number(activeTab) < 5 && (
|
{tabs[activeTab].name.toLowerCase !== "tweaks" && (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
|
@ -177,7 +125,7 @@ export default function CodeTabsComponent({
|
||||||
className="api-modal-tabs-content overflow-hidden"
|
className="api-modal-tabs-content overflow-hidden"
|
||||||
key={idx} // Remember to add a unique key prop
|
key={idx} // Remember to add a unique key prop
|
||||||
>
|
>
|
||||||
{tabsOrder[idx].toLowerCase() !== "tweaks" ? (
|
{tab.name.toLowerCase() !== "tweaks" ? (
|
||||||
<div className="flex h-full w-full flex-col">
|
<div className="flex h-full w-full flex-col">
|
||||||
{tab.description && (
|
{tab.description && (
|
||||||
<div
|
<div
|
||||||
|
|
@ -193,675 +141,9 @@ export default function CodeTabsComponent({
|
||||||
{tab.code}
|
{tab.code}
|
||||||
</SyntaxHighlighter>
|
</SyntaxHighlighter>
|
||||||
</div>
|
</div>
|
||||||
) : tabsOrder[idx].toLowerCase() === "tweaks" ? (
|
) : tab.name.toLowerCase() === "tweaks" ? (
|
||||||
<>
|
<>
|
||||||
<div className="api-modal-according-display">
|
<TweaksComponent open={open} />
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
"h-[70vh] w-full overflow-y-auto overflow-x-hidden rounded-lg bg-muted custom-scroll",
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{data?.map((node: any, i) => (
|
|
||||||
<div className="px-3" key={i}>
|
|
||||||
{tweaks?.tweaksList!.includes(node["data"]["id"]) && (
|
|
||||||
<AccordionComponent
|
|
||||||
trigger={
|
|
||||||
<ShadTooltip
|
|
||||||
side="top"
|
|
||||||
styleClasses="z-50"
|
|
||||||
content={node["data"]["id"]}
|
|
||||||
>
|
|
||||||
<div>{node["data"]["node"]["display_name"]}</div>
|
|
||||||
</ShadTooltip>
|
|
||||||
}
|
|
||||||
keyValue={node["data"]["id"]}
|
|
||||||
>
|
|
||||||
<div className="api-modal-table-arrangement">
|
|
||||||
<Table className="table-fixed bg-muted outline-1">
|
|
||||||
<TableHeader className="h-10 border-input text-xs font-medium text-ring">
|
|
||||||
<TableRow className="">
|
|
||||||
<TableHead className="h-7 text-center">
|
|
||||||
PARAM
|
|
||||||
</TableHead>
|
|
||||||
<TableHead className="h-7 p-0 text-center">
|
|
||||||
VALUE
|
|
||||||
</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody className="p-0">
|
|
||||||
{Object.keys(node["data"]["node"]["template"])
|
|
||||||
.filter(
|
|
||||||
(templateField) =>
|
|
||||||
templateField.charAt(0) !== "_" &&
|
|
||||||
node.data.node.template[templateField]
|
|
||||||
.show &&
|
|
||||||
LANGFLOW_SUPPORTED_TYPES.has(
|
|
||||||
node.data.node.template[templateField]
|
|
||||||
.type,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.map((templateField, indx) => {
|
|
||||||
return (
|
|
||||||
<TableRow key={indx} className="h-10">
|
|
||||||
<TableCell className="p-0 text-center text-sm text-foreground">
|
|
||||||
{templateField}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="p-0 text-xs text-foreground">
|
|
||||||
<div className="m-auto w-[250px]">
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
type(node, templateField) ===
|
|
||||||
"str" &&
|
|
||||||
!node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].options
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
]?.list
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<InputListComponent
|
|
||||||
componentName={templateField}
|
|
||||||
editNode={true}
|
|
||||||
disabled={false}
|
|
||||||
value={
|
|
||||||
!node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value ||
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value === ""
|
|
||||||
? [""]
|
|
||||||
: node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value
|
|
||||||
}
|
|
||||||
onChange={(target) => {
|
|
||||||
setData((old) => {
|
|
||||||
let newInputList =
|
|
||||||
cloneDeep(old);
|
|
||||||
newInputList![
|
|
||||||
i
|
|
||||||
].data.node.template[
|
|
||||||
templateField
|
|
||||||
].value = target;
|
|
||||||
return newInputList;
|
|
||||||
});
|
|
||||||
tweaks?.buildTweakObject!(
|
|
||||||
node["data"]["id"],
|
|
||||||
target,
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].multiline
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<TextAreaComponent
|
|
||||||
disabled={false}
|
|
||||||
editNode={true}
|
|
||||||
value={
|
|
||||||
!node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value ||
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value === ""
|
|
||||||
? ""
|
|
||||||
: node.data.node
|
|
||||||
.template[
|
|
||||||
templateField
|
|
||||||
].value
|
|
||||||
}
|
|
||||||
onChange={(target) => {
|
|
||||||
setData((old) => {
|
|
||||||
let newInputList =
|
|
||||||
cloneDeep(old);
|
|
||||||
newInputList![
|
|
||||||
i
|
|
||||||
].data.node.template[
|
|
||||||
templateField
|
|
||||||
].value = target;
|
|
||||||
return newInputList;
|
|
||||||
});
|
|
||||||
tweaks?.buildTweakObject!(
|
|
||||||
node["data"]["id"],
|
|
||||||
target,
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
!node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].multiline &&
|
|
||||||
!node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].list
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<InputComponent
|
|
||||||
editNode={true}
|
|
||||||
disabled={false}
|
|
||||||
password={
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].password ?? false
|
|
||||||
}
|
|
||||||
value={
|
|
||||||
!node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value ||
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value === ""
|
|
||||||
? ""
|
|
||||||
: node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value
|
|
||||||
}
|
|
||||||
onChange={(target) => {
|
|
||||||
setData((old) => {
|
|
||||||
let newInputList =
|
|
||||||
cloneDeep(old);
|
|
||||||
newInputList![
|
|
||||||
i
|
|
||||||
].data.node.template[
|
|
||||||
templateField
|
|
||||||
].value = target;
|
|
||||||
return newInputList;
|
|
||||||
});
|
|
||||||
tweaks?.buildTweakObject!(
|
|
||||||
node["data"]["id"],
|
|
||||||
target,
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Case>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
type(node, templateField) ===
|
|
||||||
"bool"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="ml-auto">
|
|
||||||
{" "}
|
|
||||||
<ToggleShadComponent
|
|
||||||
enabled={
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value
|
|
||||||
}
|
|
||||||
setEnabled={(e) => {
|
|
||||||
setData((old) => {
|
|
||||||
let newInputList =
|
|
||||||
cloneDeep(old);
|
|
||||||
newInputList![
|
|
||||||
i
|
|
||||||
].data.node.template[
|
|
||||||
templateField
|
|
||||||
].value = e;
|
|
||||||
return newInputList;
|
|
||||||
});
|
|
||||||
tweaks?.buildTweakObject!(
|
|
||||||
node["data"]["id"],
|
|
||||||
e,
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
size="small"
|
|
||||||
disabled={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
type(node, templateField) ===
|
|
||||||
"file"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="mx-auto">
|
|
||||||
<InputFileComponent
|
|
||||||
editNode={true}
|
|
||||||
disabled={false}
|
|
||||||
value={
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value ?? ""
|
|
||||||
}
|
|
||||||
onChange={(target: any) => {}}
|
|
||||||
fileTypes={
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].fileTypes
|
|
||||||
}
|
|
||||||
onFileChange={(
|
|
||||||
value: any,
|
|
||||||
) => {
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].file_path = value;
|
|
||||||
}}
|
|
||||||
></InputFileComponent>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
type(node, templateField) ===
|
|
||||||
"float"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="mx-auto">
|
|
||||||
<FloatComponent
|
|
||||||
disabled={false}
|
|
||||||
editNode={true}
|
|
||||||
value={
|
|
||||||
!node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value ||
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value === ""
|
|
||||||
? ""
|
|
||||||
: node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value
|
|
||||||
}
|
|
||||||
rangeSpec={
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].rangeSpec
|
|
||||||
}
|
|
||||||
onChange={(target) => {
|
|
||||||
setData((old) => {
|
|
||||||
let newInputList =
|
|
||||||
cloneDeep(old);
|
|
||||||
newInputList![
|
|
||||||
i
|
|
||||||
].data.node.template[
|
|
||||||
templateField
|
|
||||||
].value = target;
|
|
||||||
return newInputList;
|
|
||||||
});
|
|
||||||
tweaks?.buildTweakObject!(
|
|
||||||
node["data"]["id"],
|
|
||||||
target,
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
type(node, templateField) ===
|
|
||||||
"str" &&
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].options
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="mx-auto">
|
|
||||||
<Dropdown
|
|
||||||
editNode={true}
|
|
||||||
options={
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].options
|
|
||||||
}
|
|
||||||
onSelect={(target) => {
|
|
||||||
setData((old) => {
|
|
||||||
let newInputList =
|
|
||||||
cloneDeep(old);
|
|
||||||
newInputList![
|
|
||||||
i
|
|
||||||
].data.node.template[
|
|
||||||
templateField
|
|
||||||
].value = target;
|
|
||||||
return newInputList;
|
|
||||||
});
|
|
||||||
tweaks?.buildTweakObject!(
|
|
||||||
node["data"]["id"],
|
|
||||||
target,
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
value={
|
|
||||||
!node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value ||
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value === ""
|
|
||||||
? ""
|
|
||||||
: node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value
|
|
||||||
}
|
|
||||||
></Dropdown>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
type(node, templateField) ===
|
|
||||||
"int"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="mx-auto">
|
|
||||||
<IntComponent
|
|
||||||
disabled={false}
|
|
||||||
editNode={true}
|
|
||||||
rangeSpec={
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].rangeSpec
|
|
||||||
}
|
|
||||||
value={
|
|
||||||
!node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value ||
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value === ""
|
|
||||||
? ""
|
|
||||||
: node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value
|
|
||||||
}
|
|
||||||
onChange={(target) => {
|
|
||||||
setData((old) => {
|
|
||||||
let newInputList =
|
|
||||||
cloneDeep(old);
|
|
||||||
newInputList![
|
|
||||||
i
|
|
||||||
].data.node.template[
|
|
||||||
templateField
|
|
||||||
].value = target;
|
|
||||||
return newInputList;
|
|
||||||
});
|
|
||||||
tweaks?.buildTweakObject!(
|
|
||||||
node["data"]["id"],
|
|
||||||
target,
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
type(node, templateField) ===
|
|
||||||
"prompt"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="mx-auto">
|
|
||||||
<PromptAreaComponent
|
|
||||||
readonly={true}
|
|
||||||
editNode={true}
|
|
||||||
disabled={false}
|
|
||||||
value={
|
|
||||||
!node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value ||
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value === ""
|
|
||||||
? ""
|
|
||||||
: node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value
|
|
||||||
}
|
|
||||||
onChange={(target) => {
|
|
||||||
setData((old) => {
|
|
||||||
let newInputList =
|
|
||||||
cloneDeep(old);
|
|
||||||
newInputList![
|
|
||||||
i
|
|
||||||
].data.node.template[
|
|
||||||
templateField
|
|
||||||
].value = target;
|
|
||||||
return newInputList;
|
|
||||||
});
|
|
||||||
tweaks?.buildTweakObject!(
|
|
||||||
node["data"]["id"],
|
|
||||||
target,
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
type(node, templateField) ===
|
|
||||||
"code"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="mx-auto">
|
|
||||||
<CodeAreaComponent
|
|
||||||
disabled={false}
|
|
||||||
editNode={true}
|
|
||||||
readonly={true}
|
|
||||||
value={
|
|
||||||
!node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value ||
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value === ""
|
|
||||||
? ""
|
|
||||||
: node.data.node.template[
|
|
||||||
templateField
|
|
||||||
].value
|
|
||||||
}
|
|
||||||
onChange={(target) => {
|
|
||||||
setData((old) => {
|
|
||||||
let newInputList =
|
|
||||||
cloneDeep(old);
|
|
||||||
newInputList![
|
|
||||||
i
|
|
||||||
].data.node.template[
|
|
||||||
templateField
|
|
||||||
].value = target;
|
|
||||||
return newInputList;
|
|
||||||
});
|
|
||||||
tweaks?.buildTweakObject!(
|
|
||||||
node["data"]["id"],
|
|
||||||
target,
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
type(node, templateField) ===
|
|
||||||
"dict"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="mx-auto overflow-auto custom-scroll">
|
|
||||||
<KeypairListComponent
|
|
||||||
disabled={false}
|
|
||||||
editNode={true}
|
|
||||||
value={
|
|
||||||
node.data.node!.template[
|
|
||||||
templateField
|
|
||||||
].value?.length === 0 ||
|
|
||||||
!node.data.node!.template[
|
|
||||||
templateField
|
|
||||||
].value
|
|
||||||
? [{ "": "" }]
|
|
||||||
: convertObjToArray(
|
|
||||||
node.data.node!
|
|
||||||
.template[
|
|
||||||
templateField
|
|
||||||
].value,
|
|
||||||
type(
|
|
||||||
node,
|
|
||||||
templateField,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
duplicateKey={
|
|
||||||
errorDuplicateKey
|
|
||||||
}
|
|
||||||
onChange={(target) => {
|
|
||||||
const valueToNumbers =
|
|
||||||
convertValuesToNumbers(
|
|
||||||
target,
|
|
||||||
);
|
|
||||||
node.data.node!.template[
|
|
||||||
templateField
|
|
||||||
].value = valueToNumbers;
|
|
||||||
setErrorDuplicateKey(
|
|
||||||
hasDuplicateKeys(
|
|
||||||
valueToNumbers,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
setData((old) => {
|
|
||||||
let newInputList =
|
|
||||||
cloneDeep(old);
|
|
||||||
newInputList![
|
|
||||||
i
|
|
||||||
].data.node.template[
|
|
||||||
templateField
|
|
||||||
].value = target;
|
|
||||||
return newInputList;
|
|
||||||
});
|
|
||||||
tweaks?.buildTweakObject!(
|
|
||||||
node["data"]["id"],
|
|
||||||
target,
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
isList={
|
|
||||||
node.data.node!.template[
|
|
||||||
templateField
|
|
||||||
]?.list ?? false
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
type(node, templateField) ===
|
|
||||||
"NestedDict"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="mx-auto">
|
|
||||||
<DictComponent
|
|
||||||
disabled={false}
|
|
||||||
editNode={true}
|
|
||||||
value={
|
|
||||||
node.data.node!.template[
|
|
||||||
templateField
|
|
||||||
].value?.toString() === "{}"
|
|
||||||
? {}
|
|
||||||
: node.data.node!
|
|
||||||
.template[
|
|
||||||
templateField
|
|
||||||
].value
|
|
||||||
}
|
|
||||||
onChange={(target) => {
|
|
||||||
setData((old) => {
|
|
||||||
let newInputList =
|
|
||||||
cloneDeep(old);
|
|
||||||
newInputList![
|
|
||||||
i
|
|
||||||
].data.node.template[
|
|
||||||
templateField
|
|
||||||
].value = target;
|
|
||||||
return newInputList;
|
|
||||||
});
|
|
||||||
tweaks?.buildTweakObject!(
|
|
||||||
node["data"]["id"],
|
|
||||||
target,
|
|
||||||
node.data.node.template[
|
|
||||||
templateField
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Case>
|
|
||||||
|
|
||||||
<Case
|
|
||||||
condition={
|
|
||||||
type(node, templateField) ===
|
|
||||||
"Any"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<>-</>
|
|
||||||
</Case>
|
|
||||||
</div>
|
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
</div>
|
|
||||||
</AccordionComponent>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{tweaks?.tweaksList!.length === 0 && (
|
|
||||||
<>
|
|
||||||
<div className="pt-3">
|
|
||||||
No tweaks are available for this flow.
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import {
|
||||||
CONSOLE_ERROR_MSG,
|
CONSOLE_ERROR_MSG,
|
||||||
INVALID_FILE_ALERT,
|
INVALID_FILE_ALERT,
|
||||||
} from "../../constants/alerts_constants";
|
} from "../../constants/alerts_constants";
|
||||||
import { uploadFile } from "../../controllers/API";
|
|
||||||
import useAlertStore from "../../stores/alertStore";
|
import useAlertStore from "../../stores/alertStore";
|
||||||
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
||||||
import { FileComponentType } from "../../types/components";
|
import { FileComponentType } from "../../types/components";
|
||||||
|
|
@ -13,25 +12,22 @@ import { Button } from "../ui/button";
|
||||||
|
|
||||||
export default function InputFileComponent({
|
export default function InputFileComponent({
|
||||||
value,
|
value,
|
||||||
onChange,
|
handleOnNewValue,
|
||||||
disabled,
|
disabled,
|
||||||
fileTypes,
|
fileTypes,
|
||||||
onFileChange,
|
|
||||||
editNode = false,
|
editNode = false,
|
||||||
|
id,
|
||||||
}: FileComponentType): JSX.Element {
|
}: FileComponentType): JSX.Element {
|
||||||
const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId);
|
const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId);
|
||||||
const [myValue, setMyValue] = useState(value);
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
|
|
||||||
// Clear component state
|
// Clear component state
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (disabled && value !== "") {
|
if (disabled && value !== "") {
|
||||||
setMyValue("");
|
handleOnNewValue({ value: "", file_path: "" }, { skipSnapshot: true });
|
||||||
onChange("", undefined, true);
|
|
||||||
onFileChange("");
|
|
||||||
}
|
}
|
||||||
}, [disabled, onChange]);
|
}, [disabled, handleOnNewValue]);
|
||||||
|
|
||||||
function checkFileType(fileName: string): boolean {
|
function checkFileType(fileName: string): boolean {
|
||||||
if (fileTypes === undefined) return true;
|
if (fileTypes === undefined) return true;
|
||||||
|
|
@ -43,10 +39,6 @@ export default function InputFileComponent({
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setMyValue(value);
|
|
||||||
}, [value]);
|
|
||||||
|
|
||||||
const { mutate } = usePostUploadFile();
|
const { mutate } = usePostUploadFile();
|
||||||
|
|
||||||
const handleButtonClick = (): void => {
|
const handleButtonClick = (): void => {
|
||||||
|
|
@ -74,11 +66,9 @@ export default function InputFileComponent({
|
||||||
const { file_path } = data;
|
const { file_path } = data;
|
||||||
|
|
||||||
// sets the value that goes to the backend
|
// sets the value that goes to the backend
|
||||||
onFileChange(file_path);
|
|
||||||
// Update the state and on with the name of the file
|
// Update the state and on with the name of the file
|
||||||
// sets the value to the user
|
// sets the value to the user
|
||||||
setMyValue(file.name);
|
handleOnNewValue({ value: file.name, file_path });
|
||||||
onChange(file.name);
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
},
|
},
|
||||||
onError: () => {
|
onError: () => {
|
||||||
|
|
@ -107,6 +97,7 @@ export default function InputFileComponent({
|
||||||
<div className={disabled ? "input-component-div" : "w-full"}>
|
<div className={disabled ? "input-component-div" : "w-full"}>
|
||||||
<div className="input-file-component gap-3">
|
<div className="input-file-component gap-3">
|
||||||
<span
|
<span
|
||||||
|
data-testid={id}
|
||||||
onClick={handleButtonClick}
|
onClick={handleButtonClick}
|
||||||
className={
|
className={
|
||||||
editNode
|
editNode
|
||||||
|
|
@ -116,7 +107,7 @@ export default function InputFileComponent({
|
||||||
: "input-dialog primary-input text-muted-foreground"
|
: "input-dialog primary-input text-muted-foreground"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{myValue !== "" ? myValue : "No file"}
|
{value !== "" ? value : "No file"}
|
||||||
</span>
|
</span>
|
||||||
{!editNode && (
|
{!editNode && (
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ export default function InputListComponent({
|
||||||
editNode = false,
|
editNode = false,
|
||||||
componentName,
|
componentName,
|
||||||
playgroundDisabled,
|
playgroundDisabled,
|
||||||
|
id,
|
||||||
}: InputListComponentType): JSX.Element {
|
}: InputListComponentType): JSX.Element {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (disabled && value.length > 0 && value[0] !== "") {
|
if (disabled && value.length > 0 && value[0] !== "") {
|
||||||
|
|
@ -49,10 +50,7 @@ export default function InputListComponent({
|
||||||
newInputList[idx] = event.target.value;
|
newInputList[idx] = event.target.value;
|
||||||
onChange(newInputList);
|
onChange(newInputList);
|
||||||
}}
|
}}
|
||||||
data-testid={
|
data-testid={`${id}_` + idx}
|
||||||
`input-list-input${editNode ? "-edit" : ""}_${componentName}-` +
|
|
||||||
idx
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
{idx === 0 ? (
|
{idx === 0 ? (
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
import { useEffect } from "react";
|
import { cn } from "@/utils/utils";
|
||||||
import { IntComponentType } from "../../types/components";
|
|
||||||
import {
|
import {
|
||||||
handleKeyDown,
|
NumberDecrementStepper,
|
||||||
handleOnlyIntegerInput,
|
NumberIncrementStepper,
|
||||||
} from "../../utils/reactflowUtils";
|
NumberInput,
|
||||||
import { Input } from "../ui/input";
|
NumberInputField,
|
||||||
|
NumberInputStepper,
|
||||||
|
} from "@chakra-ui/number-input";
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import { IntComponentType } from "../../types/components";
|
||||||
|
import { handleKeyDown } from "../../utils/reactflowUtils";
|
||||||
|
|
||||||
export default function IntComponent({
|
export default function IntComponent({
|
||||||
value,
|
value,
|
||||||
|
|
@ -15,7 +19,6 @@ export default function IntComponent({
|
||||||
id = "",
|
id = "",
|
||||||
}: IntComponentType): JSX.Element {
|
}: IntComponentType): JSX.Element {
|
||||||
const min = -Infinity;
|
const min = -Infinity;
|
||||||
|
|
||||||
// Clear component state
|
// Clear component state
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (disabled && value !== "") {
|
if (disabled && value !== "") {
|
||||||
|
|
@ -23,32 +26,54 @@ export default function IntComponent({
|
||||||
}
|
}
|
||||||
}, [disabled, onChange]);
|
}, [disabled, onChange]);
|
||||||
|
|
||||||
|
const [cursor, setCursor] = useState<number | null>(null);
|
||||||
|
const ref = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
ref.current?.setSelectionRange(cursor, cursor);
|
||||||
|
}, [ref, cursor, value]);
|
||||||
|
|
||||||
|
const handleChangeInput = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setCursor(e.target.selectionStart);
|
||||||
|
onChange(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<Input
|
<NumberInput
|
||||||
id={id}
|
id={id}
|
||||||
onKeyDown={(event) => {
|
step={(Number.isInteger(rangeSpec?.step) ? rangeSpec?.step : 1) ?? 1}
|
||||||
handleOnlyIntegerInput(event);
|
|
||||||
handleKeyDown(event, value, "");
|
|
||||||
}}
|
|
||||||
type="number"
|
|
||||||
step={rangeSpec?.step ?? 1}
|
|
||||||
min={rangeSpec?.min ?? min}
|
min={rangeSpec?.min ?? min}
|
||||||
max={rangeSpec?.max ?? undefined}
|
max={rangeSpec?.max ?? undefined}
|
||||||
onInput={(event: React.ChangeEvent<HTMLInputElement>) => {
|
onChange={(value) => {
|
||||||
if (Number(event.target.value) < min) {
|
onChange(value);
|
||||||
event.target.value = min.toString();
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
value={value ?? ""}
|
value={value ?? ""}
|
||||||
className={editNode ? "input-edit-node" : ""}
|
>
|
||||||
disabled={disabled}
|
<NumberInputField
|
||||||
placeholder={editNode ? "Integer number" : "Type an integer number"}
|
className={cn(
|
||||||
onChange={(event) => {
|
editNode ? "input-edit-node" : "",
|
||||||
onChange(event.target.value);
|
"nopan nodelete nodrag noflow primary-input",
|
||||||
}}
|
)}
|
||||||
data-testid={id}
|
onChange={handleChangeInput}
|
||||||
/>
|
onKeyDown={(event) => {
|
||||||
|
handleKeyDown(event, value, "");
|
||||||
|
}}
|
||||||
|
onInput={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
if (Number(event.target.value) < min) {
|
||||||
|
event.target.value = min.toString();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={disabled}
|
||||||
|
placeholder={editNode ? "Integer number" : "Type an integer number"}
|
||||||
|
data-testid={id}
|
||||||
|
ref={ref}
|
||||||
|
/>
|
||||||
|
<NumberInputStepper paddingRight={10}>
|
||||||
|
<NumberIncrementStepper fontSize={8} marginTop={6} />
|
||||||
|
<NumberDecrementStepper fontSize={8} marginBottom={6} />
|
||||||
|
</NumberInputStepper>
|
||||||
|
</NumberInput>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { KeyPairListComponentType } from "../../types/components";
|
import { KeyPairListComponentType } from "../../types/components";
|
||||||
|
|
||||||
|
import {
|
||||||
|
convertObjToArray,
|
||||||
|
convertValuesToNumbers,
|
||||||
|
hasDuplicateKeys,
|
||||||
|
} from "@/utils/reactflowUtils";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import { classNames } from "../../utils/utils";
|
import { classNames } from "../../utils/utils";
|
||||||
import IconComponent from "../genericIconComponent";
|
import IconComponent from "../genericIconComponent";
|
||||||
|
|
@ -11,8 +16,8 @@ export default function KeypairListComponent({
|
||||||
onChange,
|
onChange,
|
||||||
disabled,
|
disabled,
|
||||||
editNode = false,
|
editNode = false,
|
||||||
duplicateKey,
|
|
||||||
isList = true,
|
isList = true,
|
||||||
|
id,
|
||||||
}: KeyPairListComponentType): JSX.Element {
|
}: KeyPairListComponentType): JSX.Element {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (disabled && value.length > 0 && value[0] !== "") {
|
if (disabled && value.length > 0 && value[0] !== "") {
|
||||||
|
|
@ -20,7 +25,22 @@ export default function KeypairListComponent({
|
||||||
}
|
}
|
||||||
}, [disabled]);
|
}, [disabled]);
|
||||||
|
|
||||||
const myValue = Array.isArray(value) ? value : [value];
|
const [duplicateKey, setDuplicateKey] = useState(false);
|
||||||
|
|
||||||
|
const myValue =
|
||||||
|
Object.keys(value || {})?.length === 0 || !value
|
||||||
|
? [{ "": "" }]
|
||||||
|
: convertObjToArray(value, "dict");
|
||||||
|
|
||||||
|
Array.isArray(value) ? value : [value];
|
||||||
|
|
||||||
|
const handleNewValue = (newValue: any) => {
|
||||||
|
const valueToNumbers = convertValuesToNumbers(newValue);
|
||||||
|
setDuplicateKey(hasDuplicateKeys(valueToNumbers));
|
||||||
|
if (isList) {
|
||||||
|
onChange(valueToNumbers);
|
||||||
|
} else onChange(valueToNumbers[0]);
|
||||||
|
};
|
||||||
|
|
||||||
const handleChangeKey = (event, idx) => {
|
const handleChangeKey = (event, idx) => {
|
||||||
const oldKey = Object.keys(myValue[idx])[0];
|
const oldKey = Object.keys(myValue[idx])[0];
|
||||||
|
|
@ -29,7 +49,7 @@ export default function KeypairListComponent({
|
||||||
const newValue = cloneDeep(myValue);
|
const newValue = cloneDeep(myValue);
|
||||||
newValue[idx] = updatedObj;
|
newValue[idx] = updatedObj;
|
||||||
|
|
||||||
onChange(newValue);
|
handleNewValue(newValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChangeValue = (event, idx) => {
|
const handleChangeValue = (event, idx) => {
|
||||||
|
|
@ -39,7 +59,7 @@ export default function KeypairListComponent({
|
||||||
const newValue = cloneDeep(myValue);
|
const newValue = cloneDeep(myValue);
|
||||||
newValue[idx] = updatedObj;
|
newValue[idx] = updatedObj;
|
||||||
|
|
||||||
onChange(newValue);
|
handleNewValue(newValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -100,11 +120,7 @@ export default function KeypairListComponent({
|
||||||
? "editNodeplusbtn" + index.toString()
|
? "editNodeplusbtn" + index.toString()
|
||||||
: "plusbtn" + index.toString()
|
: "plusbtn" + index.toString()
|
||||||
}
|
}
|
||||||
data-testid={
|
data-testid={id}
|
||||||
editNode
|
|
||||||
? "editNodeplusbtn" + index.toString()
|
|
||||||
: "plusbtn" + index.toString()
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="Plus"
|
name="Plus"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { RefreshButton } from "@/components/ui/refreshButton";
|
||||||
|
import { usePostTemplateValue } from "@/controllers/API/queries/nodes/use-post-template-value";
|
||||||
|
import { mutateTemplate } from "@/CustomNodes/helpers/mutate-template";
|
||||||
|
import useAlertStore from "@/stores/alertStore";
|
||||||
|
|
||||||
|
export function RefreshParameterComponent({
|
||||||
|
children,
|
||||||
|
templateData,
|
||||||
|
disabled,
|
||||||
|
nodeClass,
|
||||||
|
handleNodeClass,
|
||||||
|
nodeId,
|
||||||
|
name,
|
||||||
|
}) {
|
||||||
|
const postTemplateValue = usePostTemplateValue({
|
||||||
|
parameterId: name,
|
||||||
|
nodeId: nodeId,
|
||||||
|
node: nodeClass,
|
||||||
|
});
|
||||||
|
|
||||||
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
|
const handleRefreshButtonPress = () =>
|
||||||
|
mutateTemplate(
|
||||||
|
templateData.value,
|
||||||
|
nodeClass,
|
||||||
|
handleNodeClass,
|
||||||
|
postTemplateValue,
|
||||||
|
setErrorData,
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<div className="flex w-full items-center gap-2">
|
||||||
|
<div className="w-full">{children}</div>
|
||||||
|
{templateData.refresh_button && (
|
||||||
|
<div className="w-1/6">
|
||||||
|
<RefreshButton
|
||||||
|
isLoading={postTemplateValue.isPending}
|
||||||
|
disabled={disabled}
|
||||||
|
button_text={templateData.refresh_button_text}
|
||||||
|
handleUpdateValues={handleRefreshButtonPress}
|
||||||
|
id={"refresh-button-" + name}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
import Dropdown from "../../../dropdownComponent";
|
||||||
|
import InputGlobalComponent from "../../../inputGlobalComponent";
|
||||||
|
import InputListComponent from "../../../inputListComponent";
|
||||||
|
import { Multiselect } from "../../../multiselectComponent";
|
||||||
|
import TextAreaComponent from "../../../textAreaComponent";
|
||||||
|
|
||||||
|
export function StrRenderComponent({
|
||||||
|
templateData,
|
||||||
|
value,
|
||||||
|
name,
|
||||||
|
disabled,
|
||||||
|
handleOnNewValue,
|
||||||
|
editNode,
|
||||||
|
id,
|
||||||
|
}) {
|
||||||
|
const onChange = (value: any, dbValue?: boolean, skipSnapshot?: boolean) => {
|
||||||
|
handleOnNewValue({ value, load_from_db: dbValue }, { skipSnapshot });
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!templateData.options) {
|
||||||
|
return templateData?.list ? (
|
||||||
|
<InputListComponent
|
||||||
|
componentName={name ?? undefined}
|
||||||
|
editNode={editNode}
|
||||||
|
disabled={disabled}
|
||||||
|
value={!value || value === "" ? [""] : value}
|
||||||
|
onChange={onChange}
|
||||||
|
id={`inputlist_${id}`}
|
||||||
|
/>
|
||||||
|
) : templateData.multiline ? (
|
||||||
|
<TextAreaComponent
|
||||||
|
id={`textarea_${id}`}
|
||||||
|
disabled={disabled}
|
||||||
|
editNode={editNode}
|
||||||
|
value={value ?? ""}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<InputGlobalComponent
|
||||||
|
disabled={disabled}
|
||||||
|
editNode={editNode}
|
||||||
|
onChange={onChange}
|
||||||
|
name={name}
|
||||||
|
data={templateData}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!templateData.options && !!templateData?.list) {
|
||||||
|
return (
|
||||||
|
<Multiselect
|
||||||
|
editNode={editNode}
|
||||||
|
disabled={disabled}
|
||||||
|
options={templateData.options || []}
|
||||||
|
values={[value ?? "Choose an option"]}
|
||||||
|
id={`multiselect_${id}`}
|
||||||
|
onValueChange={onChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!templateData.options) {
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
editNode={editNode}
|
||||||
|
options={templateData.options}
|
||||||
|
onSelect={onChange}
|
||||||
|
value={value ?? "Choose an option"}
|
||||||
|
id={`dropdown_${id}`}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
149
src/frontend/src/components/parameterRenderComponent/index.tsx
Normal file
149
src/frontend/src/components/parameterRenderComponent/index.tsx
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
import { TEXT_FIELD_TYPES } from "@/CustomNodes/GenericNode/components/parameterComponent/constants";
|
||||||
|
import { handleOnNewValueType } from "@/CustomNodes/hooks/use-handle-new-value";
|
||||||
|
import { APIClassType, InputFieldType } from "@/types/api";
|
||||||
|
import CodeAreaComponent from "../codeAreaComponent";
|
||||||
|
import DictComponent from "../dictComponent";
|
||||||
|
import FloatComponent from "../floatComponent";
|
||||||
|
import InputFileComponent from "../inputFileComponent";
|
||||||
|
import IntComponent from "../intComponent";
|
||||||
|
import KeypairListComponent from "../keypairListComponent";
|
||||||
|
import PromptAreaComponent from "../promptComponent";
|
||||||
|
import ToggleShadComponent from "../toggleShadComponent";
|
||||||
|
import { RefreshParameterComponent } from "./component/refreshParameterComponent";
|
||||||
|
import { StrRenderComponent } from "./component/strRenderComponent";
|
||||||
|
|
||||||
|
export function ParameterRenderComponent({
|
||||||
|
handleOnNewValue,
|
||||||
|
name,
|
||||||
|
nodeId,
|
||||||
|
templateData,
|
||||||
|
templateValue,
|
||||||
|
editNode,
|
||||||
|
handleNodeClass,
|
||||||
|
nodeClass,
|
||||||
|
disabled,
|
||||||
|
}: {
|
||||||
|
handleOnNewValue: handleOnNewValueType;
|
||||||
|
name: string;
|
||||||
|
nodeId: string;
|
||||||
|
templateData: Partial<InputFieldType>;
|
||||||
|
templateValue: any;
|
||||||
|
editNode: boolean;
|
||||||
|
handleNodeClass: (value: any, code?: string, type?: string) => void;
|
||||||
|
nodeClass: APIClassType;
|
||||||
|
disabled: boolean;
|
||||||
|
}) {
|
||||||
|
const onChange = (value: any) => {
|
||||||
|
handleOnNewValue({ value });
|
||||||
|
};
|
||||||
|
|
||||||
|
const id = (
|
||||||
|
templateData.type +
|
||||||
|
"_" +
|
||||||
|
(editNode ? "edit_" : "") +
|
||||||
|
templateData.name
|
||||||
|
).toLowerCase();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RefreshParameterComponent
|
||||||
|
templateData={templateData}
|
||||||
|
disabled={disabled}
|
||||||
|
nodeId={nodeId}
|
||||||
|
nodeClass={nodeClass}
|
||||||
|
handleNodeClass={handleNodeClass}
|
||||||
|
name={name}
|
||||||
|
>
|
||||||
|
{TEXT_FIELD_TYPES.includes(templateData.type ?? "") ? (
|
||||||
|
<StrRenderComponent
|
||||||
|
templateData={templateData}
|
||||||
|
value={templateValue}
|
||||||
|
name={name}
|
||||||
|
disabled={disabled}
|
||||||
|
handleOnNewValue={handleOnNewValue}
|
||||||
|
id={id}
|
||||||
|
editNode={editNode}
|
||||||
|
/>
|
||||||
|
) : templateData.type === "NestedDict" ? (
|
||||||
|
<DictComponent
|
||||||
|
disabled={disabled}
|
||||||
|
editNode={editNode}
|
||||||
|
value={(templateValue || "").toString() === "{}" ? {} : templateValue}
|
||||||
|
onChange={onChange}
|
||||||
|
id={`dict_${id}`}
|
||||||
|
/>
|
||||||
|
) : templateData.type === "dict" ? (
|
||||||
|
<KeypairListComponent
|
||||||
|
disabled={disabled}
|
||||||
|
editNode={editNode}
|
||||||
|
value={templateValue}
|
||||||
|
onChange={onChange}
|
||||||
|
isList={templateData.list ?? false}
|
||||||
|
id={`keypair_${id}`}
|
||||||
|
/>
|
||||||
|
) : templateData.type === "bool" ? (
|
||||||
|
<ToggleShadComponent
|
||||||
|
id={`toggle_${id}`}
|
||||||
|
disabled={disabled}
|
||||||
|
enabled={templateValue}
|
||||||
|
setEnabled={onChange}
|
||||||
|
size={editNode ? "small" : "large"}
|
||||||
|
/>
|
||||||
|
) : templateData.type === "float" ? (
|
||||||
|
<FloatComponent
|
||||||
|
disabled={disabled}
|
||||||
|
editNode={editNode}
|
||||||
|
rangeSpec={templateData.range_spec}
|
||||||
|
value={templateValue ?? ""}
|
||||||
|
onChange={onChange}
|
||||||
|
id={`float_${id}`}
|
||||||
|
/>
|
||||||
|
) : templateData.type === "int" ? (
|
||||||
|
<IntComponent
|
||||||
|
rangeSpec={templateData.range_spec}
|
||||||
|
id={`int_${id}`}
|
||||||
|
disabled={disabled}
|
||||||
|
editNode={editNode}
|
||||||
|
value={templateValue ?? ""}
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
) : templateData.type === "file" ? (
|
||||||
|
<InputFileComponent
|
||||||
|
editNode={editNode}
|
||||||
|
disabled={disabled}
|
||||||
|
value={templateValue ?? ""}
|
||||||
|
handleOnNewValue={handleOnNewValue}
|
||||||
|
fileTypes={templateData.fileTypes}
|
||||||
|
id={`inputfile_${id}`}
|
||||||
|
/>
|
||||||
|
) : templateData.type === "prompt" ? (
|
||||||
|
<PromptAreaComponent
|
||||||
|
readonly={nodeClass.flow ? true : false}
|
||||||
|
field_name={name}
|
||||||
|
editNode={editNode}
|
||||||
|
disabled={disabled}
|
||||||
|
nodeClass={nodeClass}
|
||||||
|
setNodeClass={handleNodeClass}
|
||||||
|
value={templateValue ?? ""}
|
||||||
|
onChange={onChange}
|
||||||
|
id={`promptarea_${id}`}
|
||||||
|
/>
|
||||||
|
) : templateData.type === "code" ? (
|
||||||
|
<CodeAreaComponent
|
||||||
|
readonly={nodeClass.flow && templateData.dynamic ? true : false}
|
||||||
|
dynamic={templateData.dynamic ?? false}
|
||||||
|
setNodeClass={handleNodeClass}
|
||||||
|
nodeClass={nodeClass}
|
||||||
|
disabled={disabled}
|
||||||
|
editNode={editNode}
|
||||||
|
value={templateValue ?? ""}
|
||||||
|
onChange={onChange}
|
||||||
|
id={`codearea_${id}`}
|
||||||
|
/>
|
||||||
|
) : templateData.type === "Any" ? (
|
||||||
|
<>-</>
|
||||||
|
) : (
|
||||||
|
String(templateValue)
|
||||||
|
)}
|
||||||
|
</RefreshParameterComponent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
import useHandleOnNewValue from "@/CustomNodes/hooks/use-handle-new-value";
|
||||||
|
import ShadTooltip from "@/components/shadTooltipComponent";
|
||||||
|
import useFlowStore from "@/stores/flowStore";
|
||||||
|
import { isTargetHandleConnected } from "@/utils/reactflowUtils";
|
||||||
|
import { CustomCellRendererProps } from "ag-grid-react";
|
||||||
|
import ToggleShadComponent from "../../../toggleShadComponent";
|
||||||
|
|
||||||
|
export default function TableAdvancedToggleCellRender({
|
||||||
|
value: { nodeId, parameterId },
|
||||||
|
}: CustomCellRendererProps) {
|
||||||
|
const edges = useFlowStore((state) => state.edges);
|
||||||
|
const node = useFlowStore((state) => state.getNode(nodeId));
|
||||||
|
const parameter = node?.data?.node?.template?.[parameterId];
|
||||||
|
|
||||||
|
const disabled = isTargetHandleConnected(
|
||||||
|
edges,
|
||||||
|
parameterId,
|
||||||
|
parameter,
|
||||||
|
nodeId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { handleOnNewValue } = useHandleOnNewValue({
|
||||||
|
node: node?.data.node,
|
||||||
|
nodeId,
|
||||||
|
name: parameterId,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
parameter && (
|
||||||
|
<ShadTooltip
|
||||||
|
content={
|
||||||
|
disabled
|
||||||
|
? "Cannot change visibility of connected handles"
|
||||||
|
: "Change visibility of the field"
|
||||||
|
}
|
||||||
|
styleClasses="z-50"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div className="flex h-full items-center">
|
||||||
|
<ToggleShadComponent
|
||||||
|
id={"show" + parameterId}
|
||||||
|
disabled={disabled}
|
||||||
|
enabled={!parameter?.advanced ?? true}
|
||||||
|
setEnabled={(e) => {
|
||||||
|
console.log(e, parameter);
|
||||||
|
handleOnNewValue({ advanced: !e });
|
||||||
|
}}
|
||||||
|
size="small"
|
||||||
|
editNode={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ShadTooltip>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
import Dropdown from "../../../dropdownComponent";
|
|
||||||
import InputGlobalComponent from "../../../inputGlobalComponent";
|
|
||||||
import InputListComponent from "../../../inputListComponent";
|
|
||||||
import { Multiselect } from "../../../multiselectComponent";
|
|
||||||
import TextAreaComponent from "../../../textAreaComponent";
|
|
||||||
|
|
||||||
export function renderStrType({
|
|
||||||
templateData,
|
|
||||||
templateValue,
|
|
||||||
disabled,
|
|
||||||
handleOnNewValue,
|
|
||||||
}) {
|
|
||||||
if (!templateData.options) {
|
|
||||||
return templateData?.list ? (
|
|
||||||
<InputListComponent
|
|
||||||
componentName={templateData.key ?? undefined}
|
|
||||||
editNode={true}
|
|
||||||
disabled={disabled}
|
|
||||||
value={!templateValue || templateValue === "" ? [""] : templateValue}
|
|
||||||
onChange={(value: string[]) => {
|
|
||||||
handleOnNewValue(value, templateData.key);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : templateData.multiline ? (
|
|
||||||
<TextAreaComponent
|
|
||||||
id={"textarea-edit-" + templateData.name}
|
|
||||||
data-testid={"textarea-edit-" + templateData.name}
|
|
||||||
disabled={disabled}
|
|
||||||
editNode={true}
|
|
||||||
value={templateValue ?? ""}
|
|
||||||
onChange={(value: string | string[]) => {
|
|
||||||
handleOnNewValue(value, templateData.key);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<InputGlobalComponent
|
|
||||||
disabled={disabled}
|
|
||||||
editNode={true}
|
|
||||||
onChange={(value, dbValue, snapshot) =>
|
|
||||||
handleOnNewValue(value, templateData.key, dbValue)
|
|
||||||
}
|
|
||||||
name={templateData.key}
|
|
||||||
data={templateData}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!!templateData.options && !!templateData?.list) {
|
|
||||||
return (
|
|
||||||
<Multiselect
|
|
||||||
editNode={true}
|
|
||||||
disabled={disabled}
|
|
||||||
options={templateData.options || []}
|
|
||||||
value={templateValue ?? "Choose an option"}
|
|
||||||
id={"multiselect-" + templateData.name}
|
|
||||||
onValueChange={(value) => handleOnNewValue(value, templateData.key)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!!templateData.options) {
|
|
||||||
return (
|
|
||||||
<Dropdown
|
|
||||||
editNode={true}
|
|
||||||
options={templateData.options}
|
|
||||||
onSelect={(value) => handleOnNewValue(value, templateData.key)}
|
|
||||||
value={templateValue ?? "Choose an option"}
|
|
||||||
id={"dropdown-edit-" + templateData.name}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,244 +1,56 @@
|
||||||
import TableNodeComponent from "@/components/TableNodeComponent";
|
import useHandleOnNewValue from "@/CustomNodes/hooks/use-handle-new-value";
|
||||||
|
import useHandleNodeClass from "@/CustomNodes/hooks/use-handle-node-class";
|
||||||
|
import { ParameterRenderComponent } from "@/components/parameterRenderComponent";
|
||||||
|
import { useTweaksStore } from "@/stores/tweaksStore";
|
||||||
import { CustomCellRendererProps } from "ag-grid-react";
|
import { CustomCellRendererProps } from "ag-grid-react";
|
||||||
import { cloneDeep } from "lodash";
|
|
||||||
import { useState } from "react";
|
|
||||||
import useFlowStore from "../../../../stores/flowStore";
|
import useFlowStore from "../../../../stores/flowStore";
|
||||||
import { APIClassType } from "../../../../types/api";
|
import { isTargetHandleConnected } from "../../../../utils/reactflowUtils";
|
||||||
import {
|
|
||||||
convertObjToArray,
|
|
||||||
convertValuesToNumbers,
|
|
||||||
hasDuplicateKeys,
|
|
||||||
scapedJSONStringfy,
|
|
||||||
} from "../../../../utils/reactflowUtils";
|
|
||||||
import { classNames } from "../../../../utils/utils";
|
|
||||||
import CodeAreaComponent from "../../../codeAreaComponent";
|
|
||||||
import DictComponent from "../../../dictComponent";
|
|
||||||
import Dropdown from "../../../dropdownComponent";
|
|
||||||
import FloatComponent from "../../../floatComponent";
|
|
||||||
import InputFileComponent from "../../../inputFileComponent";
|
|
||||||
import InputGlobalComponent from "../../../inputGlobalComponent";
|
|
||||||
import InputListComponent from "../../../inputListComponent";
|
|
||||||
import IntComponent from "../../../intComponent";
|
|
||||||
import KeypairListComponent from "../../../keypairListComponent";
|
|
||||||
import PromptAreaComponent from "../../../promptComponent";
|
|
||||||
import TextAreaComponent from "../../../textAreaComponent";
|
|
||||||
import ToggleShadComponent from "../../../toggleShadComponent";
|
|
||||||
import { renderStrType } from "./cellTypeStr";
|
|
||||||
|
|
||||||
export default function TableNodeCellRender({
|
export default function TableNodeCellRender({
|
||||||
node: { data },
|
value: { nodeId, parameterId, isTweaks },
|
||||||
value: {
|
|
||||||
value,
|
|
||||||
nodeClass,
|
|
||||||
handleOnNewValue: handleOnNewValueNode,
|
|
||||||
handleNodeClass,
|
|
||||||
},
|
|
||||||
}: CustomCellRendererProps) {
|
}: CustomCellRendererProps) {
|
||||||
const handleOnNewValue = (newValue: any, name: string, dbValue?: boolean) => {
|
|
||||||
handleOnNewValueNode(newValue, name, dbValue);
|
|
||||||
setTemplateData((old) => {
|
|
||||||
let newData = cloneDeep(old);
|
|
||||||
newData.value = newValue;
|
|
||||||
if (dbValue !== undefined) {
|
|
||||||
newData.load_from_db = newValue;
|
|
||||||
}
|
|
||||||
return newData;
|
|
||||||
});
|
|
||||||
setTemplateValue(newValue);
|
|
||||||
};
|
|
||||||
const setNodeClass = (value: APIClassType, code?: string, type?: string) => {
|
|
||||||
handleNodeClass(value, templateData.key, code, type);
|
|
||||||
};
|
|
||||||
|
|
||||||
const [templateValue, setTemplateValue] = useState(value);
|
|
||||||
const [templateData, setTemplateData] = useState(data);
|
|
||||||
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
|
|
||||||
const edges = useFlowStore((state) => state.edges);
|
const edges = useFlowStore((state) => state.edges);
|
||||||
|
const node = isTweaks
|
||||||
|
? useTweaksStore((state) => state.getNode(nodeId))
|
||||||
|
: useFlowStore((state) => state.getNode(nodeId));
|
||||||
|
const parameter = node?.data?.node?.template?.[parameterId];
|
||||||
|
|
||||||
const id = {
|
const setNode = useTweaksStore((state) => state.setNode);
|
||||||
inputTypes: templateData.input_types,
|
|
||||||
type: templateData.type,
|
|
||||||
id: nodeClass.id,
|
|
||||||
fieldName: templateData.key,
|
|
||||||
};
|
|
||||||
const disabled =
|
|
||||||
edges.some(
|
|
||||||
(edge) =>
|
|
||||||
edge.targetHandle ===
|
|
||||||
scapedJSONStringfy(
|
|
||||||
templateData.proxy
|
|
||||||
? {
|
|
||||||
...id,
|
|
||||||
proxy: templateData.proxy,
|
|
||||||
}
|
|
||||||
: id,
|
|
||||||
),
|
|
||||||
) ?? false;
|
|
||||||
function getCellType() {
|
|
||||||
switch (templateData.type) {
|
|
||||||
case "str":
|
|
||||||
return renderStrType({
|
|
||||||
templateData,
|
|
||||||
templateValue,
|
|
||||||
disabled,
|
|
||||||
handleOnNewValue,
|
|
||||||
});
|
|
||||||
|
|
||||||
case "NestedDict":
|
const disabled = isTargetHandleConnected(
|
||||||
return (
|
edges,
|
||||||
<DictComponent
|
parameterId,
|
||||||
disabled={disabled}
|
parameter,
|
||||||
editNode={true}
|
nodeId,
|
||||||
value={
|
);
|
||||||
(templateValue || "").toString() === "{}" ? {} : templateValue
|
|
||||||
}
|
|
||||||
onChange={(newValue) => {
|
|
||||||
handleOnNewValue(newValue, templateData.key);
|
|
||||||
}}
|
|
||||||
id="editnode-div-dict-input"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
case "dict":
|
const { handleOnNewValue } = useHandleOnNewValue({
|
||||||
return (
|
node: node?.data.node,
|
||||||
<div
|
nodeId,
|
||||||
className={classNames(
|
name: parameterId,
|
||||||
"max-h-48 w-full overflow-auto custom-scroll",
|
setNode: isTweaks ? setNode : undefined,
|
||||||
templateValue?.length > 1 ? "my-3" : "",
|
});
|
||||||
)}
|
|
||||||
>
|
|
||||||
<KeypairListComponent
|
|
||||||
disabled={disabled}
|
|
||||||
editNode={true}
|
|
||||||
value={
|
|
||||||
Object.keys(templateValue || {})?.length === 0 || !templateValue
|
|
||||||
? [{ "": "" }]
|
|
||||||
: convertObjToArray(templateValue, templateData.type)
|
|
||||||
}
|
|
||||||
duplicateKey={errorDuplicateKey}
|
|
||||||
onChange={(newValue) => {
|
|
||||||
const valueToNumbers = convertValuesToNumbers(newValue);
|
|
||||||
setErrorDuplicateKey(hasDuplicateKeys(valueToNumbers));
|
|
||||||
handleOnNewValue(valueToNumbers, templateData.key);
|
|
||||||
}}
|
|
||||||
isList={templateData.list ?? false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
case "bool":
|
const { handleNodeClass } = useHandleNodeClass(
|
||||||
return (
|
nodeId,
|
||||||
<ToggleShadComponent
|
isTweaks ? setNode : undefined,
|
||||||
id={"toggle-edit-" + templateData.name}
|
);
|
||||||
disabled={disabled}
|
|
||||||
enabled={templateValue}
|
|
||||||
setEnabled={(isEnabled) => {
|
|
||||||
handleOnNewValue(isEnabled, templateData.key);
|
|
||||||
}}
|
|
||||||
size="small"
|
|
||||||
editNode={true}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case "table":
|
|
||||||
return (
|
|
||||||
<TableNodeComponent
|
|
||||||
description={templateData.info || "Add or edit data"}
|
|
||||||
columns={templateData.table_schema?.columns}
|
|
||||||
onChange={(value) => {
|
|
||||||
handleOnNewValue(value, templateData.key);
|
|
||||||
}}
|
|
||||||
editNode
|
|
||||||
tableTitle={templateData.display_name ?? "Table"}
|
|
||||||
value={templateValue}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
case "float":
|
|
||||||
return (
|
|
||||||
<FloatComponent
|
|
||||||
disabled={disabled}
|
|
||||||
editNode={true}
|
|
||||||
rangeSpec={templateData.rangeSpec}
|
|
||||||
value={templateValue ?? ""}
|
|
||||||
onChange={(value) => {
|
|
||||||
handleOnNewValue(value, templateData.key);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case "int":
|
|
||||||
return (
|
|
||||||
<IntComponent
|
|
||||||
rangeSpec={templateData.rangeSpec}
|
|
||||||
id={"edit-int-input-" + templateData.name}
|
|
||||||
disabled={disabled}
|
|
||||||
editNode={true}
|
|
||||||
value={templateValue ?? ""}
|
|
||||||
onChange={(value) => {
|
|
||||||
handleOnNewValue(value, templateData.key);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
case "file":
|
|
||||||
return (
|
|
||||||
<InputFileComponent
|
|
||||||
editNode={true}
|
|
||||||
disabled={disabled}
|
|
||||||
value={templateValue ?? ""}
|
|
||||||
onChange={(value: string | string[]) => {
|
|
||||||
handleOnNewValue(value, templateData.key);
|
|
||||||
}}
|
|
||||||
fileTypes={templateData.fileTypes}
|
|
||||||
onFileChange={(filePath: string) => {
|
|
||||||
templateData.file_path = filePath;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
case "prompt":
|
|
||||||
return (
|
|
||||||
<PromptAreaComponent
|
|
||||||
readonly={nodeClass.flow ? true : false}
|
|
||||||
field_name={templateData.key}
|
|
||||||
editNode={true}
|
|
||||||
disabled={disabled}
|
|
||||||
nodeClass={nodeClass}
|
|
||||||
setNodeClass={setNodeClass}
|
|
||||||
value={templateValue ?? ""}
|
|
||||||
onChange={(value: string | string[]) => {
|
|
||||||
handleOnNewValue(value, templateData.key);
|
|
||||||
}}
|
|
||||||
id={"prompt-area-edit-" + templateData.name}
|
|
||||||
data-testid={"modal-prompt-input-" + templateData.name}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
case "code":
|
|
||||||
return (
|
|
||||||
<CodeAreaComponent
|
|
||||||
readonly={nodeClass.flow && templateData.dynamic ? true : false}
|
|
||||||
dynamic={templateData.dynamic ?? false}
|
|
||||||
setNodeClass={setNodeClass}
|
|
||||||
nodeClass={nodeClass}
|
|
||||||
disabled={disabled}
|
|
||||||
editNode={true}
|
|
||||||
value={templateValue ?? ""}
|
|
||||||
onChange={(value: string | string[]) => {
|
|
||||||
handleOnNewValue(value, templateData.key);
|
|
||||||
}}
|
|
||||||
id={"code-area-edit" + templateData.name}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
case "Any":
|
|
||||||
return <>-</>;
|
|
||||||
default:
|
|
||||||
return String(templateValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="group mx-auto flex h-full w-[300px] items-center justify-center py-2.5">
|
parameter && (
|
||||||
{getCellType()}
|
<div className="group mx-auto flex h-full max-h-48 w-[300px] items-center justify-center overflow-auto py-2.5 custom-scroll">
|
||||||
</div>
|
<ParameterRenderComponent
|
||||||
|
nodeId={nodeId}
|
||||||
|
handleOnNewValue={handleOnNewValue}
|
||||||
|
templateData={parameter}
|
||||||
|
name={parameterId}
|
||||||
|
templateValue={parameter.value}
|
||||||
|
editNode={true}
|
||||||
|
handleNodeClass={handleNodeClass}
|
||||||
|
nodeClass={node?.data.node}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
import { CustomCellRendererProps } from "ag-grid-react";
|
|
||||||
import { useState } from "react";
|
|
||||||
import ToggleShadComponent from "../../../toggleShadComponent";
|
|
||||||
|
|
||||||
export default function TableToggleCellRender({
|
|
||||||
value: { name, enabled, setEnabled },
|
|
||||||
}: CustomCellRendererProps) {
|
|
||||||
const [value, setValue] = useState(enabled);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex h-full items-center">
|
|
||||||
<ToggleShadComponent
|
|
||||||
id={"show" + name}
|
|
||||||
enabled={value}
|
|
||||||
setEnabled={(e) => {
|
|
||||||
setValue(e);
|
|
||||||
setEnabled(e);
|
|
||||||
}}
|
|
||||||
size="small"
|
|
||||||
editNode={true}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -7,7 +7,6 @@ export default function ToggleShadComponent({
|
||||||
disabled,
|
disabled,
|
||||||
size,
|
size,
|
||||||
id = "",
|
id = "",
|
||||||
editNode = false,
|
|
||||||
}: ToggleComponentType): JSX.Element {
|
}: ToggleComponentType): JSX.Element {
|
||||||
let scaleX, scaleY;
|
let scaleX, scaleY;
|
||||||
switch (size) {
|
switch (size) {
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,27 @@
|
||||||
import IconComponent from "../../components/genericIconComponent";
|
import IconComponent from "../../components/genericIconComponent";
|
||||||
import { NodeDataType } from "../../types/flow";
|
|
||||||
import { cn } from "../../utils/utils";
|
import { cn } from "../../utils/utils";
|
||||||
import { Button } from "./button";
|
import { Button } from "./button";
|
||||||
|
|
||||||
function RefreshButton({
|
function RefreshButton({
|
||||||
isLoading,
|
isLoading,
|
||||||
disabled,
|
disabled,
|
||||||
name,
|
|
||||||
button_text,
|
button_text,
|
||||||
data,
|
|
||||||
handleUpdateValues,
|
handleUpdateValues,
|
||||||
className,
|
className,
|
||||||
|
editNode,
|
||||||
id,
|
id,
|
||||||
}: {
|
}: {
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
name: string;
|
|
||||||
button_text?: string;
|
button_text?: string;
|
||||||
data: NodeDataType;
|
editNode?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
handleUpdateValues: (name: string, data: NodeDataType) => void;
|
handleUpdateValues: () => void;
|
||||||
id: string;
|
id: string;
|
||||||
}) {
|
}) {
|
||||||
const handleClick = async () => {
|
const handleClick = async () => {
|
||||||
if (disabled) return;
|
if (disabled) return;
|
||||||
handleUpdateValues(name, data);
|
handleUpdateValues();
|
||||||
};
|
};
|
||||||
|
|
||||||
const classNames = cn(className, disabled ? "cursor-not-allowed" : "");
|
const classNames = cn(className, disabled ? "cursor-not-allowed" : "");
|
||||||
|
|
@ -40,6 +37,7 @@ function RefreshButton({
|
||||||
className={classNames}
|
className={classNames}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
id={id}
|
id={id}
|
||||||
|
size={editNode ? "sm" : "default"}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
>
|
>
|
||||||
{button_text && <span className="mr-1">{button_text}</span>}
|
{button_text && <span className="mr-1">{button_text}</span>}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
import {
|
||||||
|
APIClassType,
|
||||||
|
APITemplateType,
|
||||||
|
ResponseErrorDetailAPI,
|
||||||
|
useMutationFunctionType,
|
||||||
|
} from "@/types/api";
|
||||||
|
import { UseMutationResult } from "@tanstack/react-query";
|
||||||
|
import { api } from "../../api";
|
||||||
|
import { getURL } from "../../helpers/constants";
|
||||||
|
import { UseRequestProcessor } from "../../services/request-processor";
|
||||||
|
|
||||||
|
interface IPostTemplateValue {
|
||||||
|
value: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IPostTemplateValueParams {
|
||||||
|
node: APIClassType;
|
||||||
|
nodeId: string;
|
||||||
|
parameterId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const usePostTemplateValue: useMutationFunctionType<
|
||||||
|
IPostTemplateValueParams,
|
||||||
|
IPostTemplateValue,
|
||||||
|
APITemplateType | undefined,
|
||||||
|
ResponseErrorDetailAPI
|
||||||
|
> = ({ parameterId, nodeId, node }, options?) => {
|
||||||
|
const { mutate } = UseRequestProcessor();
|
||||||
|
|
||||||
|
const postTemplateValueFn = async (
|
||||||
|
payload: IPostTemplateValue,
|
||||||
|
): Promise<APITemplateType | undefined> => {
|
||||||
|
const template = node.template;
|
||||||
|
|
||||||
|
if (!template) return;
|
||||||
|
|
||||||
|
const response = await api.post<APIClassType>(
|
||||||
|
getURL("CUSTOM_COMPONENT", { update: "update" }),
|
||||||
|
{
|
||||||
|
code: template.code.value,
|
||||||
|
template: template,
|
||||||
|
field: parameterId,
|
||||||
|
field_value: payload.value,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return response.data.template;
|
||||||
|
};
|
||||||
|
|
||||||
|
const mutation: UseMutationResult<
|
||||||
|
APITemplateType | undefined,
|
||||||
|
ResponseErrorDetailAPI,
|
||||||
|
IPostTemplateValue
|
||||||
|
> = mutate(
|
||||||
|
["usePostTemplateValue", { parameterId, nodeId }],
|
||||||
|
postTemplateValueFn,
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
|
||||||
|
return mutation;
|
||||||
|
};
|
||||||
|
|
@ -1,278 +1,67 @@
|
||||||
|
import useAuthStore from "@/stores/authStore";
|
||||||
import "ace-builds/src-noconflict/ext-language_tools";
|
import "ace-builds/src-noconflict/ext-language_tools";
|
||||||
import "ace-builds/src-noconflict/mode-python";
|
import "ace-builds/src-noconflict/mode-python";
|
||||||
import "ace-builds/src-noconflict/theme-github";
|
import "ace-builds/src-noconflict/theme-github";
|
||||||
import "ace-builds/src-noconflict/theme-twilight";
|
import "ace-builds/src-noconflict/theme-twilight";
|
||||||
import { ReactNode, forwardRef, useContext, useEffect, useState } from "react";
|
import { ReactNode, useEffect, useState } from "react";
|
||||||
// import "ace-builds/webpack-resolver";
|
|
||||||
import useAuthStore from "@/stores/authStore";
|
|
||||||
import { cloneDeep } from "lodash";
|
|
||||||
import CodeTabsComponent from "../../components/codeTabsComponent";
|
import CodeTabsComponent from "../../components/codeTabsComponent";
|
||||||
import IconComponent from "../../components/genericIconComponent";
|
import IconComponent from "../../components/genericIconComponent";
|
||||||
import { EXPORT_CODE_DIALOG } from "../../constants/constants";
|
import { EXPORT_CODE_DIALOG } from "../../constants/constants";
|
||||||
import { AuthContext } from "../../contexts/authContext";
|
|
||||||
import { useTweaksStore } from "../../stores/tweaksStore";
|
import { useTweaksStore } from "../../stores/tweaksStore";
|
||||||
import { InputFieldType } from "../../types/api";
|
|
||||||
import { uniqueTweakType } from "../../types/components";
|
|
||||||
import { FlowType } from "../../types/flow/index";
|
import { FlowType } from "../../types/flow/index";
|
||||||
import BaseModal from "../baseModal";
|
import BaseModal from "../baseModal";
|
||||||
import { buildContent } from "./utils/build-content";
|
|
||||||
import { buildTweaks } from "./utils/build-tweaks";
|
|
||||||
import { checkCanBuildTweakObject } from "./utils/check-can-build-tweak-object";
|
|
||||||
import { getChangesType } from "./utils/get-changes-types";
|
|
||||||
import getCodesObj from "./utils/get-codes-obj";
|
|
||||||
import { getCurlRunCode, getCurlWebhookCode } from "./utils/get-curl-code";
|
|
||||||
import getJsApiCode from "./utils/get-js-api-code";
|
|
||||||
import { getNodesWithDefaultValue } from "./utils/get-nodes-with-default-value";
|
|
||||||
import getPythonApiCode from "./utils/get-python-api-code";
|
|
||||||
import getPythonCode from "./utils/get-python-code";
|
|
||||||
import getTabsOrder from "./utils/get-tabs-order";
|
|
||||||
import { getValue } from "./utils/get-value";
|
|
||||||
import getWidgetCode from "./utils/get-widget-code";
|
|
||||||
import { createTabsArray } from "./utils/tabs-array";
|
|
||||||
|
|
||||||
const ApiModal = forwardRef(
|
export default function ApiModal({
|
||||||
(
|
flow,
|
||||||
{
|
children,
|
||||||
flow,
|
open: myOpen,
|
||||||
children,
|
setOpen: mySetOpen,
|
||||||
open: myOpen,
|
}: {
|
||||||
setOpen: mySetOpen,
|
flow: FlowType;
|
||||||
}: {
|
children: ReactNode;
|
||||||
flow: FlowType;
|
open?: boolean;
|
||||||
children: ReactNode;
|
setOpen?: (a: boolean | ((o?: boolean) => boolean)) => void;
|
||||||
open?: boolean;
|
}) {
|
||||||
setOpen?: (a: boolean | ((o?: boolean) => boolean)) => void;
|
const autoLogin = useAuthStore((state) => state.autoLogin);
|
||||||
},
|
const [open, setOpen] =
|
||||||
ref,
|
mySetOpen !== undefined && myOpen !== undefined
|
||||||
) => {
|
? [myOpen, mySetOpen]
|
||||||
const tweaksCode = buildTweaks(flow);
|
: useState(false);
|
||||||
const tweak = useTweaksStore((state) => state.tweak);
|
const [activeTab, setActiveTab] = useState("0");
|
||||||
const addTweaks = useTweaksStore((state) => state.setTweak);
|
const activeTweaks = useTweaksStore((state) => state.activeTweaks);
|
||||||
const setTweaksList = useTweaksStore((state) => state.setTweaksList);
|
const setActiveTweaks = useTweaksStore((state) => state.setActiveTweaks);
|
||||||
const tweaksList = useTweaksStore((state) => state.tweaksList);
|
const tabs = useTweaksStore((state) => state.tabs);
|
||||||
const isThereTweaks = Object.keys(tweaksCode).length > 0;
|
const initialSetup = useTweaksStore((state) => state.initialSetup);
|
||||||
const [activeTweaks, setActiveTweaks] = useState(false);
|
|
||||||
const autoLogin = useAuthStore((state) => state.autoLogin);
|
|
||||||
|
|
||||||
const [open, setOpen] =
|
useEffect(() => {
|
||||||
mySetOpen !== undefined && myOpen !== undefined
|
if (open) initialSetup(autoLogin, flow);
|
||||||
? [myOpen, mySetOpen]
|
}, [open, flow?.data?.nodes]);
|
||||||
: useState(false);
|
|
||||||
const [activeTab, setActiveTab] = useState("0");
|
|
||||||
const pythonApiCode = getPythonApiCode(
|
|
||||||
flow?.id,
|
|
||||||
autoLogin,
|
|
||||||
tweak,
|
|
||||||
flow?.endpoint_name,
|
|
||||||
);
|
|
||||||
const jsApiCode = getJsApiCode(
|
|
||||||
flow?.id,
|
|
||||||
autoLogin,
|
|
||||||
tweak,
|
|
||||||
flow?.endpoint_name,
|
|
||||||
);
|
|
||||||
const runCurlCode = getCurlRunCode(
|
|
||||||
flow?.id,
|
|
||||||
autoLogin,
|
|
||||||
tweak,
|
|
||||||
flow?.endpoint_name,
|
|
||||||
);
|
|
||||||
const webhookCurlCode = getCurlWebhookCode(
|
|
||||||
flow?.id,
|
|
||||||
autoLogin,
|
|
||||||
flow?.endpoint_name,
|
|
||||||
);
|
|
||||||
const pythonCode = getPythonCode(flow?.name, tweak);
|
|
||||||
const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin);
|
|
||||||
const includeWebhook = flow.webhook;
|
|
||||||
const codesArray = [
|
|
||||||
runCurlCode,
|
|
||||||
webhookCurlCode,
|
|
||||||
pythonApiCode,
|
|
||||||
jsApiCode,
|
|
||||||
pythonCode,
|
|
||||||
widgetCode,
|
|
||||||
];
|
|
||||||
const [tabs, setTabs] = useState(
|
|
||||||
createTabsArray(codesArray, includeWebhook),
|
|
||||||
);
|
|
||||||
|
|
||||||
const canShowTweaks =
|
useEffect(() => {
|
||||||
flow &&
|
setActiveTab("0");
|
||||||
flow["data"] &&
|
}, [open]);
|
||||||
flow["data"]!["nodes"] &&
|
|
||||||
tweak &&
|
|
||||||
tweak?.length > 0 &&
|
|
||||||
activeTweaks === true;
|
|
||||||
|
|
||||||
const buildTweaksInitialState = () => {
|
return (
|
||||||
const newTweak: any = [];
|
<BaseModal open={open} setOpen={setOpen}>
|
||||||
const t = buildTweaks(flow);
|
<BaseModal.Trigger asChild>{children}</BaseModal.Trigger>
|
||||||
newTweak.push(t);
|
<BaseModal.Header description={EXPORT_CODE_DIALOG}>
|
||||||
addTweaks(newTweak);
|
<span className="pr-2">API</span>
|
||||||
addCodes(newTweak);
|
<IconComponent
|
||||||
};
|
name="Code2"
|
||||||
|
className="h-6 w-6 pl-1 text-gray-800 dark:text-white"
|
||||||
useEffect(() => {
|
aria-hidden="true"
|
||||||
if (flow["data"]!["nodes"].length == 0) {
|
/>
|
||||||
addTweaks([]);
|
</BaseModal.Header>
|
||||||
setTweaksList([]);
|
<BaseModal.Content overflowHidden>
|
||||||
} else {
|
<CodeTabsComponent
|
||||||
buildTweaksInitialState();
|
open={open}
|
||||||
}
|
tabs={tabs!}
|
||||||
|
activeTab={activeTab}
|
||||||
filterNodes();
|
setActiveTab={setActiveTab}
|
||||||
|
activeTweaks={activeTweaks}
|
||||||
if (isThereTweaks) {
|
setActiveTweaks={setActiveTweaks}
|
||||||
setActiveTab("0");
|
/>
|
||||||
setTabs(createTabsArray(codesArray, includeWebhook, true));
|
</BaseModal.Content>
|
||||||
} else {
|
</BaseModal>
|
||||||
setTabs(createTabsArray(codesArray, includeWebhook, false));
|
);
|
||||||
}
|
}
|
||||||
}, [flow["data"]!["nodes"], open]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (canShowTweaks) {
|
|
||||||
const nodes = flow["data"]!["nodes"];
|
|
||||||
nodes.forEach((element) => {
|
|
||||||
const nodeId = element["id"];
|
|
||||||
const template = element["data"]["node"]["template"];
|
|
||||||
|
|
||||||
Object.keys(template).forEach((templateField) => {
|
|
||||||
if (checkCanBuildTweakObject(element, templateField)) {
|
|
||||||
buildTweakObject(
|
|
||||||
nodeId,
|
|
||||||
element.data.node.template[templateField].value,
|
|
||||||
element.data.node.template[templateField],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
buildTweaksInitialState();
|
|
||||||
}
|
|
||||||
}, [activeTweaks]);
|
|
||||||
|
|
||||||
const filterNodes = () => {
|
|
||||||
setTweaksList(getNodesWithDefaultValue(flow));
|
|
||||||
};
|
|
||||||
|
|
||||||
async function buildTweakObject(
|
|
||||||
tw: string,
|
|
||||||
changes: string | string[] | boolean | number | Object[] | Object,
|
|
||||||
template: InputFieldType,
|
|
||||||
) {
|
|
||||||
changes = getChangesType(changes, template);
|
|
||||||
|
|
||||||
const existingTweak = tweak.find((element) => element.hasOwnProperty(tw));
|
|
||||||
|
|
||||||
if (existingTweak) {
|
|
||||||
existingTweak[tw][template["name"]!] = changes as string;
|
|
||||||
|
|
||||||
if (existingTweak[tw][template["name"]!] == template.value) {
|
|
||||||
tweak.forEach((element) => {
|
|
||||||
if (element[tw] && Object.keys(element[tw])?.length === 0) {
|
|
||||||
const filteredTweaks = tweak.filter((obj) => {
|
|
||||||
const prop = obj[Object.keys(obj)[0]].prop;
|
|
||||||
return prop !== undefined && prop !== null && prop !== "";
|
|
||||||
});
|
|
||||||
addTweaks(filteredTweaks);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const newTweak = {
|
|
||||||
[tw]: {
|
|
||||||
[template["name"]!]: changes,
|
|
||||||
},
|
|
||||||
} as uniqueTweakType;
|
|
||||||
tweak.push(newTweak);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tweak && tweak.length > 0) {
|
|
||||||
const cloneTweak = cloneDeep(tweak);
|
|
||||||
addCodes(cloneTweak);
|
|
||||||
addTweaks(cloneTweak);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const addCodes = (cloneTweak) => {
|
|
||||||
const pythonApiCode = getPythonApiCode(flow?.id, autoLogin, cloneTweak);
|
|
||||||
const runCurlCode = getCurlRunCode(
|
|
||||||
flow?.id,
|
|
||||||
autoLogin,
|
|
||||||
cloneTweak,
|
|
||||||
flow?.endpoint_name,
|
|
||||||
);
|
|
||||||
const jsApiCode = getJsApiCode(
|
|
||||||
flow?.id,
|
|
||||||
autoLogin,
|
|
||||||
cloneTweak,
|
|
||||||
flow?.endpoint_name,
|
|
||||||
);
|
|
||||||
const webhookCurlCode = getCurlWebhookCode(
|
|
||||||
flow?.id,
|
|
||||||
autoLogin,
|
|
||||||
flow?.endpoint_name,
|
|
||||||
);
|
|
||||||
const pythonCode = getPythonCode(flow?.name, cloneTweak);
|
|
||||||
const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin);
|
|
||||||
const codesObj = getCodesObj({
|
|
||||||
runCurlCode,
|
|
||||||
webhookCurlCode,
|
|
||||||
pythonApiCode,
|
|
||||||
jsApiCode,
|
|
||||||
pythonCode,
|
|
||||||
widgetCode,
|
|
||||||
});
|
|
||||||
const tabsOrder = getTabsOrder(includeWebhook, isThereTweaks);
|
|
||||||
if (tabs && tabs?.length > 0) {
|
|
||||||
tabs.forEach((tab, idx) => {
|
|
||||||
const order = tabsOrder[idx];
|
|
||||||
if (order && order.toLowerCase() === tab.name.toLowerCase()) {
|
|
||||||
const codeToFind = codesObj.find(
|
|
||||||
(c) => c.name.toLowerCase() === tab.name.toLowerCase(),
|
|
||||||
);
|
|
||||||
tab.code = codeToFind?.code;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<BaseModal open={open} setOpen={setOpen}>
|
|
||||||
<BaseModal.Trigger asChild>{children}</BaseModal.Trigger>
|
|
||||||
<BaseModal.Header description={EXPORT_CODE_DIALOG}>
|
|
||||||
<span className="pr-2">API</span>
|
|
||||||
<IconComponent
|
|
||||||
name="Code2"
|
|
||||||
className="h-6 w-6 pl-1 text-gray-800 dark:text-white"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
</BaseModal.Header>
|
|
||||||
<BaseModal.Content overflowHidden>
|
|
||||||
<CodeTabsComponent
|
|
||||||
isThereTweaks={isThereTweaks}
|
|
||||||
isThereWH={includeWebhook ?? false}
|
|
||||||
flow={flow}
|
|
||||||
tabs={tabs!}
|
|
||||||
activeTab={activeTab}
|
|
||||||
setActiveTab={setActiveTab}
|
|
||||||
tweaks={{
|
|
||||||
tweak,
|
|
||||||
tweaksList,
|
|
||||||
buildContent,
|
|
||||||
buildTweakObject,
|
|
||||||
getValue,
|
|
||||||
}}
|
|
||||||
activeTweaks={activeTweaks}
|
|
||||||
setActiveTweaks={setActiveTweaks}
|
|
||||||
allowExport
|
|
||||||
/>
|
|
||||||
</BaseModal.Content>
|
|
||||||
</BaseModal>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export default ApiModal;
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
export function buildContent(value: string) {
|
|
||||||
const htmlContent = (
|
|
||||||
<div className="w-[200px]">
|
|
||||||
<span>{value != null && value != "" ? value : "None"}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
return htmlContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default buildContent;
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
import { FlowType } from "../../../types/flow";
|
|
||||||
|
|
||||||
export function buildTweaks(flow: FlowType) {
|
|
||||||
return flow.data!.nodes.reduce((acc, node) => {
|
|
||||||
acc[node.data.id] = {};
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
import { LANGFLOW_SUPPORTED_TYPES } from "../../../constants/constants";
|
|
||||||
|
|
||||||
export const checkCanBuildTweakObject = (element, templateField) => {
|
|
||||||
return (
|
|
||||||
element.data.node.template[templateField] &&
|
|
||||||
templateField.charAt(0) !== "_" &&
|
|
||||||
element.data.node.template[templateField].show &&
|
|
||||||
LANGFLOW_SUPPORTED_TYPES.has(
|
|
||||||
element.data.node.template[templateField].type,
|
|
||||||
) &&
|
|
||||||
templateField !== "code"
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { TemplateVariableType } from "../../../types/api";
|
import { InputFieldType } from "@/types/api";
|
||||||
import { convertArrayToObj } from "../../../utils/reactflowUtils";
|
import { convertArrayToObj } from "../../../utils/reactflowUtils";
|
||||||
|
|
||||||
export const getChangesType = (
|
export const getChangesType = (
|
||||||
changes: string | string[] | boolean | number | Object[] | Object,
|
changes: string | string[] | boolean | number | Object[] | Object,
|
||||||
template: TemplateVariableType,
|
template: InputFieldType,
|
||||||
) => {
|
) => {
|
||||||
if (typeof changes === "string" && template.type === "float") {
|
if (typeof changes === "string" && template.type === "float") {
|
||||||
changes = parseFloat(changes);
|
changes = parseFloat(changes);
|
||||||
|
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
import {
|
|
||||||
getCodesObjProps,
|
|
||||||
getCodesObjReturn,
|
|
||||||
} from "../../../types/utils/functions";
|
|
||||||
|
|
||||||
export default function getCodesObj({
|
|
||||||
runCurlCode,
|
|
||||||
webhookCurlCode,
|
|
||||||
pythonApiCode,
|
|
||||||
jsApiCode,
|
|
||||||
pythonCode,
|
|
||||||
widgetCode,
|
|
||||||
}: getCodesObjProps): getCodesObjReturn {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
name: "run curl",
|
|
||||||
code: runCurlCode,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "webhook curl",
|
|
||||||
code: webhookCurlCode,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "python api",
|
|
||||||
code: pythonApiCode,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "js api",
|
|
||||||
code: jsApiCode,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "python code",
|
|
||||||
code: pythonCode,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "chat widget html",
|
|
||||||
code: widgetCode,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
@ -7,10 +7,12 @@
|
||||||
export function getCurlRunCode(
|
export function getCurlRunCode(
|
||||||
flowId: string,
|
flowId: string,
|
||||||
isAuth: boolean,
|
isAuth: boolean,
|
||||||
tweaksBuildedObject,
|
tweaksBuildedObject?: {},
|
||||||
endpointName?: string | null,
|
endpointName?: string | null,
|
||||||
): string {
|
): string {
|
||||||
const tweaksObject = tweaksBuildedObject[0];
|
let tweaksString = "{}";
|
||||||
|
if (tweaksBuildedObject)
|
||||||
|
tweaksString = JSON.stringify(tweaksBuildedObject, null, 2);
|
||||||
// show the endpoint name in the curl command if it exists
|
// show the endpoint name in the curl command if it exists
|
||||||
return `curl -X POST \\
|
return `curl -X POST \\
|
||||||
"${window.location.protocol}//${window.location.host}/api/v1/run/${
|
"${window.location.protocol}//${window.location.host}/api/v1/run/${
|
||||||
|
|
@ -22,7 +24,7 @@ export function getCurlRunCode(
|
||||||
-d '{"input_value": "message",
|
-d '{"input_value": "message",
|
||||||
"output_type": "chat",
|
"output_type": "chat",
|
||||||
"input_type": "chat",
|
"input_type": "chat",
|
||||||
"tweaks": ${JSON.stringify(tweaksObject, null, 2)}}'
|
"tweaks": ${tweaksString}}'
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,17 +9,13 @@
|
||||||
export default function getJsApiCode(
|
export default function getJsApiCode(
|
||||||
flowId: string,
|
flowId: string,
|
||||||
isAuth: boolean,
|
isAuth: boolean,
|
||||||
tweaksBuildedObject: any[],
|
tweaksBuildedObject: {},
|
||||||
endpointName?: string | null,
|
endpointName?: string | null,
|
||||||
): string {
|
): string {
|
||||||
let tweaksString = "{}";
|
let tweaksString = "{}";
|
||||||
if (tweaksBuildedObject && tweaksBuildedObject.length > 0) {
|
if (tweaksBuildedObject)
|
||||||
const tweaksObject = tweaksBuildedObject[0];
|
tweaksString = JSON.stringify(tweaksBuildedObject, null, 2);
|
||||||
if (!tweaksObject) {
|
|
||||||
throw new Error("Expected tweaks object is not provided.");
|
|
||||||
}
|
|
||||||
tweaksString = JSON.stringify(tweaksObject, null, 2);
|
|
||||||
}
|
|
||||||
return `class LangflowClient {
|
return `class LangflowClient {
|
||||||
constructor(baseURL, apiKey) {
|
constructor(baseURL, apiKey) {
|
||||||
this.baseURL = baseURL;
|
this.baseURL = baseURL;
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,30 @@
|
||||||
|
import { NodeType } from "@/types/flow";
|
||||||
|
import { cloneDeep } from "lodash";
|
||||||
import { LANGFLOW_SUPPORTED_TYPES } from "../../../constants/constants";
|
import { LANGFLOW_SUPPORTED_TYPES } from "../../../constants/constants";
|
||||||
|
|
||||||
export const getNodesWithDefaultValue = (flow) => {
|
export const getNodesWithDefaultValue = (nodes: NodeType[]) => {
|
||||||
let arrNodesWithValues: string[] = [];
|
const filteredNodes: NodeType[] = [];
|
||||||
|
|
||||||
flow["data"]!["nodes"].forEach((node) => {
|
nodes.forEach((node) => {
|
||||||
if (!node["data"]["node"]["template"]) {
|
if (node?.data?.node?.template) {
|
||||||
return;
|
const templateKeys = Object.keys(node.data.node.template).filter(
|
||||||
}
|
|
||||||
Object.keys(node["data"]["node"]["template"])
|
|
||||||
.filter(
|
|
||||||
(templateField) =>
|
(templateField) =>
|
||||||
templateField.charAt(0) !== "_" &&
|
templateField.charAt(0) !== "_" &&
|
||||||
node.data.node.template[templateField]?.show &&
|
node!.data!.node!.template[templateField]?.show &&
|
||||||
LANGFLOW_SUPPORTED_TYPES.has(
|
LANGFLOW_SUPPORTED_TYPES.has(
|
||||||
node.data.node.template[templateField].type,
|
node!.data!.node!.template[templateField].type,
|
||||||
),
|
) &&
|
||||||
)
|
templateField !== "code",
|
||||||
.map((n, i) => {
|
);
|
||||||
arrNodesWithValues.push(node["id"]);
|
const newNode = cloneDeep(node);
|
||||||
});
|
if (newNode?.data?.node?.template) {
|
||||||
|
newNode.data.node.template = templateKeys.reduce((acc, key) => {
|
||||||
|
acc[key] = cloneDeep(node?.data?.node?.template[key]);
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
filteredNodes.push(newNode);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
return filteredNodes;
|
||||||
const tweaksListFiltered = arrNodesWithValues.filter((value, index, self) => {
|
|
||||||
return self.indexOf(value) === index;
|
|
||||||
});
|
|
||||||
return tweaksListFiltered;
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -9,20 +9,15 @@
|
||||||
export default function getPythonApiCode(
|
export default function getPythonApiCode(
|
||||||
flowId: string,
|
flowId: string,
|
||||||
isAuth: boolean,
|
isAuth: boolean,
|
||||||
tweaksBuildedObject: any[],
|
tweaksBuildedObject?: {},
|
||||||
endpointName?: string | null,
|
endpointName?: string | null,
|
||||||
): string {
|
): string {
|
||||||
let tweaksString = "{}";
|
let tweaksString = "{}";
|
||||||
if (tweaksBuildedObject && tweaksBuildedObject.length > 0) {
|
if (tweaksBuildedObject)
|
||||||
const tweaksObject = tweaksBuildedObject[0];
|
tweaksString = JSON.stringify(tweaksBuildedObject, null, 2)
|
||||||
if (!tweaksObject) {
|
|
||||||
throw new Error("expected tweaks");
|
|
||||||
}
|
|
||||||
tweaksString = JSON.stringify(tweaksObject, null, 2)
|
|
||||||
.replace(/true/g, "True")
|
.replace(/true/g, "True")
|
||||||
.replace(/false/g, "False")
|
.replace(/false/g, "False")
|
||||||
.replace(/null|undefined/g, "None");
|
.replace(/null|undefined/g, "None");
|
||||||
}
|
|
||||||
|
|
||||||
return `import argparse
|
return `import argparse
|
||||||
import json
|
import json
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,14 @@
|
||||||
*/
|
*/
|
||||||
export default function getPythonCode(
|
export default function getPythonCode(
|
||||||
flowName: string,
|
flowName: string,
|
||||||
tweaksBuildedObject: any[],
|
tweaksBuildedObject: {},
|
||||||
): string {
|
): string {
|
||||||
let tweaksString = "{}";
|
let tweaksString = "{}";
|
||||||
if (tweaksBuildedObject && tweaksBuildedObject.length > 0) {
|
if (tweaksBuildedObject)
|
||||||
const tweaksObject = tweaksBuildedObject[0];
|
tweaksString = JSON.stringify(tweaksBuildedObject, null, 2)
|
||||||
if (!tweaksObject) {
|
|
||||||
throw new Error("expected tweaks");
|
|
||||||
}
|
|
||||||
tweaksString = JSON.stringify(tweaksObject, null, 2)
|
|
||||||
.replace(/true/g, "True")
|
.replace(/true/g, "True")
|
||||||
.replace(/false/g, "False")
|
.replace(/false/g, "False")
|
||||||
.replace(/null|undefined/g, "None");
|
.replace(/null|undefined/g, "None");
|
||||||
}
|
|
||||||
|
|
||||||
return `from langflow.load import run_flow_from_json
|
return `from langflow.load import run_flow_from_json
|
||||||
TWEAKS = ${tweaksString}
|
TWEAKS = ${tweaksString}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
import { cloneDeep } from "lodash";
|
|
||||||
import { TABS_ORDER } from "../../../constants/constants";
|
|
||||||
|
|
||||||
export default function getTabsOrder(
|
|
||||||
isThereWH: boolean = false,
|
|
||||||
isThereTweaks: boolean = false,
|
|
||||||
): string[] {
|
|
||||||
const defaultOrder = cloneDeep(TABS_ORDER);
|
|
||||||
if (isThereTweaks) {
|
|
||||||
defaultOrder.push("tweaks");
|
|
||||||
}
|
|
||||||
if (isThereWH) {
|
|
||||||
defaultOrder.splice(1, 0, "webhook curl");
|
|
||||||
}
|
|
||||||
return defaultOrder;
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
import { TemplateVariableType } from "../../../types/api";
|
|
||||||
import { NodeType } from "../../../types/flow";
|
|
||||||
|
|
||||||
export const getValue = (
|
|
||||||
value: string,
|
|
||||||
node: NodeType,
|
|
||||||
template: TemplateVariableType,
|
|
||||||
tweak: Object[],
|
|
||||||
) => {
|
|
||||||
let returnValue = value ?? "";
|
|
||||||
|
|
||||||
if (tweak.length > 0) {
|
|
||||||
for (const obj of tweak) {
|
|
||||||
Object.keys(obj).forEach((key) => {
|
|
||||||
const value = obj[key];
|
|
||||||
if (key == node["id"]) {
|
|
||||||
Object.keys(value).forEach((key) => {
|
|
||||||
if (key == template["name"]) {
|
|
||||||
returnValue = value[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return value ?? "";
|
|
||||||
}
|
|
||||||
return returnValue;
|
|
||||||
};
|
|
||||||
|
|
@ -1,15 +1,18 @@
|
||||||
|
import { tabsArrayType } from "@/types/components";
|
||||||
|
|
||||||
export function createTabsArray(
|
export function createTabsArray(
|
||||||
codes,
|
codes,
|
||||||
includeWebhookCurl = false,
|
includeWebhookCurl = false,
|
||||||
includeTweaks = false,
|
includeTweaks = false,
|
||||||
) {
|
) {
|
||||||
const tabs = [
|
const tabs: tabsArrayType[] = [
|
||||||
{
|
{
|
||||||
name: "Run cURL",
|
name: "Run cURL",
|
||||||
mode: "bash",
|
mode: "bash",
|
||||||
image: "https://curl.se/logo/curl-symbol-transparent.png",
|
image: "https://curl.se/logo/curl-symbol-transparent.png",
|
||||||
language: "sh",
|
language: "sh",
|
||||||
code: codes[0],
|
code: codes[0],
|
||||||
|
hasTweaks: includeTweaks,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Python API",
|
name: "Python API",
|
||||||
|
|
@ -18,6 +21,7 @@ export function createTabsArray(
|
||||||
"https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w",
|
"https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w",
|
||||||
language: "py",
|
language: "py",
|
||||||
code: codes[2],
|
code: codes[2],
|
||||||
|
hasTweaks: includeTweaks,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "JS API",
|
name: "JS API",
|
||||||
|
|
@ -25,6 +29,7 @@ export function createTabsArray(
|
||||||
image: "https://cdn-icons-png.flaticon.com/512/136/136530.png",
|
image: "https://cdn-icons-png.flaticon.com/512/136/136530.png",
|
||||||
language: "js",
|
language: "js",
|
||||||
code: codes[3],
|
code: codes[3],
|
||||||
|
hasTweaks: includeTweaks,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Python Code",
|
name: "Python Code",
|
||||||
|
|
@ -32,6 +37,7 @@ export function createTabsArray(
|
||||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||||
language: "py",
|
language: "py",
|
||||||
code: codes[4],
|
code: codes[4],
|
||||||
|
hasTweaks: includeTweaks,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Chat Widget HTML",
|
name: "Chat Widget HTML",
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,8 @@ export default function CodeAreaModal({
|
||||||
.then((apiReturn) => {
|
.then((apiReturn) => {
|
||||||
const { data, type } = apiReturn.data;
|
const { data, type } = apiReturn.data;
|
||||||
if (data && type) {
|
if (data && type) {
|
||||||
setNodeClass(data, code, type);
|
setValue(code);
|
||||||
|
setNodeClass(data, type);
|
||||||
setError({ detail: { error: undefined, traceback: undefined } });
|
setError({ detail: { error: undefined, traceback: undefined } });
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
import TableComponent from "@/components/tableComponent";
|
||||||
|
import { APIClassType } from "@/types/api";
|
||||||
|
import { ColDef } from "ag-grid-community";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import useColumnDefs from "../../hooks/use-column-defs";
|
||||||
|
import useRowData from "../../hooks/use-row-data";
|
||||||
|
|
||||||
|
export function EditNodeComponent({
|
||||||
|
open,
|
||||||
|
nodeId,
|
||||||
|
nodeClass,
|
||||||
|
isTweaks,
|
||||||
|
autoHeight,
|
||||||
|
hideVisibility,
|
||||||
|
}: {
|
||||||
|
open: boolean;
|
||||||
|
nodeId: string;
|
||||||
|
nodeClass: APIClassType;
|
||||||
|
isTweaks?: boolean;
|
||||||
|
autoHeight?: boolean;
|
||||||
|
hideVisibility?: boolean;
|
||||||
|
}) {
|
||||||
|
const rowData = useRowData(nodeClass, open);
|
||||||
|
|
||||||
|
const columnDefs: ColDef[] = useColumnDefs(
|
||||||
|
nodeId,
|
||||||
|
open,
|
||||||
|
isTweaks,
|
||||||
|
hideVisibility,
|
||||||
|
);
|
||||||
|
return useMemo(
|
||||||
|
() => (
|
||||||
|
<div className="flex h-full flex-col">
|
||||||
|
<div className="h-full">
|
||||||
|
{nodeClass && (
|
||||||
|
<TableComponent
|
||||||
|
domLayout={autoHeight ? "autoHeight" : undefined}
|
||||||
|
key={"editNode"}
|
||||||
|
tooltipShowDelay={0.5}
|
||||||
|
columnDefs={columnDefs}
|
||||||
|
rowData={rowData}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
[nodeClass],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,24 +1,16 @@
|
||||||
|
import TableAdvancedToggleCellRender from "@/components/tableComponent/components/tableAdvancedToggleCellRender";
|
||||||
import { ColDef, ValueGetterParams } from "ag-grid-community";
|
import { ColDef, ValueGetterParams } from "ag-grid-community";
|
||||||
import { useMemo, useState } from "react";
|
import { useMemo } from "react";
|
||||||
import TableNodeCellRender from "../../../components/tableComponent/components/tableNodeCellRender";
|
import TableNodeCellRender from "../../../components/tableComponent/components/tableNodeCellRender";
|
||||||
import TableToggleCellRender from "../../../components/tableComponent/components/tableToggleCellRender";
|
|
||||||
import { APIClassType } from "../../../types/api";
|
|
||||||
import { NodeDataType } from "../../../types/flow";
|
|
||||||
|
|
||||||
const useColumnDefs = (
|
const useColumnDefs = (
|
||||||
nodeClass: APIClassType,
|
nodeId: string,
|
||||||
handleOnNewValue: (newValue: any, name: string, setDb?: boolean) => void,
|
|
||||||
handleNodeClass: (
|
|
||||||
newNodeClass: APIClassType,
|
|
||||||
name: string,
|
|
||||||
code: string,
|
|
||||||
type?: string,
|
|
||||||
) => void,
|
|
||||||
changeAdvanced: (n: string) => void,
|
|
||||||
open: boolean,
|
open: boolean,
|
||||||
|
isTweaks?: boolean,
|
||||||
|
hideVisibility?: boolean,
|
||||||
) => {
|
) => {
|
||||||
const columnDefs: ColDef[] = useMemo(
|
const columnDefs: ColDef[] = useMemo(() => {
|
||||||
() => [
|
const colDefs: ColDef[] = [
|
||||||
{
|
{
|
||||||
headerName: "Field Name",
|
headerName: "Field Name",
|
||||||
field: "display_name",
|
field: "display_name",
|
||||||
|
|
@ -52,10 +44,9 @@ const useColumnDefs = (
|
||||||
cellRenderer: TableNodeCellRender,
|
cellRenderer: TableNodeCellRender,
|
||||||
valueGetter: (params: ValueGetterParams) => {
|
valueGetter: (params: ValueGetterParams) => {
|
||||||
return {
|
return {
|
||||||
value: params.data.value,
|
nodeId: nodeId,
|
||||||
nodeClass: nodeClass,
|
parameterId: params.data.key,
|
||||||
handleOnNewValue: handleOnNewValue,
|
isTweaks,
|
||||||
handleNodeClass: handleNodeClass,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
minWidth: 340,
|
minWidth: 340,
|
||||||
|
|
@ -64,27 +55,26 @@ const useColumnDefs = (
|
||||||
resizable: false,
|
resizable: false,
|
||||||
cellClass: "no-border",
|
cellClass: "no-border",
|
||||||
},
|
},
|
||||||
{
|
];
|
||||||
|
if (!hideVisibility) {
|
||||||
|
colDefs.push({
|
||||||
headerName: "Show",
|
headerName: "Show",
|
||||||
field: "advanced",
|
field: "advanced",
|
||||||
cellRenderer: TableToggleCellRender,
|
cellRenderer: TableAdvancedToggleCellRender,
|
||||||
valueGetter: (params: ValueGetterParams) => {
|
valueGetter: (params: ValueGetterParams) => {
|
||||||
return {
|
return {
|
||||||
name: params.data.name,
|
nodeId,
|
||||||
enabled: !params.data.advanced,
|
parameterId: params.data.key,
|
||||||
setEnabled: () => {
|
|
||||||
changeAdvanced(params.data.key);
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
editable: false,
|
editable: false,
|
||||||
maxWidth: 80,
|
maxWidth: 80,
|
||||||
resizable: false,
|
resizable: false,
|
||||||
cellClass: "no-border",
|
cellClass: "no-border",
|
||||||
},
|
});
|
||||||
],
|
}
|
||||||
[open, nodeClass],
|
return colDefs;
|
||||||
);
|
}, [open]);
|
||||||
|
|
||||||
return columnDefs;
|
return columnDefs;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
import { cloneDeep } from "lodash";
|
|
||||||
import {
|
|
||||||
ERROR_UPDATING_COMPONENT,
|
|
||||||
TITLE_ERROR_UPDATING_COMPONENT,
|
|
||||||
} from "../../../constants/constants";
|
|
||||||
import useAlertStore from "../../../stores/alertStore";
|
|
||||||
import { ResponseErrorTypeAPI } from "../../../types/api";
|
|
||||||
import { NodeDataType } from "../../../types/flow";
|
|
||||||
|
|
||||||
const useHandleOnNewValue = (
|
|
||||||
data: NodeDataType,
|
|
||||||
takeSnapshot: () => void,
|
|
||||||
handleUpdateValues: (name: string, data: NodeDataType) => Promise<any>,
|
|
||||||
debouncedHandleUpdateValues: any,
|
|
||||||
setNode: (id: string, callback: (oldNode: any) => any) => void,
|
|
||||||
) => {
|
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
|
||||||
|
|
||||||
const handleOnNewValue = async (
|
|
||||||
newValue,
|
|
||||||
name,
|
|
||||||
dbValue,
|
|
||||||
skipSnapshot = false,
|
|
||||||
) => {
|
|
||||||
const nodeTemplate = data.node!.template[name];
|
|
||||||
const currentValue = nodeTemplate.value;
|
|
||||||
|
|
||||||
if (currentValue !== newValue && !skipSnapshot) {
|
|
||||||
takeSnapshot();
|
|
||||||
}
|
|
||||||
|
|
||||||
const shouldUpdate =
|
|
||||||
data.node?.template[name].real_time_refresh &&
|
|
||||||
!data.node?.template[name].refresh_button &&
|
|
||||||
currentValue !== newValue;
|
|
||||||
|
|
||||||
const typeToDebounce = nodeTemplate.type;
|
|
||||||
|
|
||||||
nodeTemplate.value = newValue;
|
|
||||||
|
|
||||||
let newTemplate;
|
|
||||||
if (shouldUpdate) {
|
|
||||||
try {
|
|
||||||
if (["int"].includes(typeToDebounce)) {
|
|
||||||
newTemplate = await handleUpdateValues(name, data);
|
|
||||||
} else {
|
|
||||||
newTemplate = await debouncedHandleUpdateValues(name, data);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
let responseError = error as ResponseErrorTypeAPI;
|
|
||||||
setErrorData({
|
|
||||||
title: TITLE_ERROR_UPDATING_COMPONENT,
|
|
||||||
list: [
|
|
||||||
responseError?.response?.data?.detail.error ??
|
|
||||||
ERROR_UPDATING_COMPONENT,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setNode(data.id, (oldNode) => {
|
|
||||||
const newNode = cloneDeep(oldNode);
|
|
||||||
newNode.data = {
|
|
||||||
...newNode.data,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (dbValue !== undefined) {
|
|
||||||
newNode.data.node.template[name].load_from_db = dbValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.node?.template[name].real_time_refresh && newTemplate) {
|
|
||||||
newNode.data.node.template = newTemplate;
|
|
||||||
} else {
|
|
||||||
newNode.data.node.template[name].value = newValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return newNode;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return { handleOnNewValue };
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useHandleOnNewValue;
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
import { cloneDeep } from "lodash";
|
|
||||||
import { NodeDataType } from "../../../types/flow";
|
|
||||||
|
|
||||||
const useHandleNodeClass = (
|
|
||||||
data: NodeDataType,
|
|
||||||
takeSnapshot: () => void,
|
|
||||||
setNode: (id: string, callback: (oldNode: any) => any) => void,
|
|
||||||
updateNodeInternals: (id: string) => void,
|
|
||||||
) => {
|
|
||||||
const handleNodeClass = (newNodeClass, name, code, type?: string) => {
|
|
||||||
if (!data.node) return;
|
|
||||||
if (data.node!.template[name].value !== code) {
|
|
||||||
takeSnapshot();
|
|
||||||
}
|
|
||||||
|
|
||||||
setNode(data.id, (oldNode) => {
|
|
||||||
let newNode = cloneDeep(oldNode);
|
|
||||||
|
|
||||||
newNode.data = {
|
|
||||||
...newNode.data,
|
|
||||||
node: newNodeClass,
|
|
||||||
description: newNodeClass.description ?? data.node!.description,
|
|
||||||
display_name: newNodeClass.display_name ?? data.node!.display_name,
|
|
||||||
};
|
|
||||||
if (type) {
|
|
||||||
newNode.data.node.template[name].type = type;
|
|
||||||
}
|
|
||||||
newNode.data.node.template[name].value = code;
|
|
||||||
|
|
||||||
return newNode;
|
|
||||||
});
|
|
||||||
|
|
||||||
updateNodeInternals(data.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
return { handleNodeClass };
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useHandleNodeClass;
|
|
||||||
|
|
@ -1,17 +1,12 @@
|
||||||
import sortFields from "@/CustomNodes/utils/sort-fields";
|
import sortFields from "@/CustomNodes/utils/sort-fields";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { APIClassType } from "../../../types/api";
|
import { APIClassType } from "../../../types/api";
|
||||||
import { NodeDataType } from "../../../types/flow";
|
|
||||||
|
|
||||||
const useRowData = (
|
const useRowData = (nodeClass: APIClassType, open: boolean) => {
|
||||||
myData: NodeDataType,
|
|
||||||
nodeClass: APIClassType,
|
|
||||||
open: boolean,
|
|
||||||
) => {
|
|
||||||
const rowData = useMemo(() => {
|
const rowData = useMemo(() => {
|
||||||
return Object.keys(myData.node!.template)
|
return Object.keys(nodeClass.template)
|
||||||
.filter((key: string) => {
|
.filter((key: string) => {
|
||||||
const templateParam = myData.node!.template[key] as any;
|
const templateParam = nodeClass.template[key] as any;
|
||||||
return (
|
return (
|
||||||
key.charAt(0) !== "_" &&
|
key.charAt(0) !== "_" &&
|
||||||
templateParam.show &&
|
templateParam.show &&
|
||||||
|
|
@ -21,9 +16,9 @@ const useRowData = (
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.sort((a, b) => sortFields(a, b, myData.node?.field_order ?? []))
|
.sort((a, b) => sortFields(a, b, nodeClass.field_order ?? []))
|
||||||
.map((key: string) => {
|
.map((key: string) => {
|
||||||
const templateParam = myData.node!.template[key] as any;
|
const templateParam = nodeClass.template[key] as any;
|
||||||
return {
|
return {
|
||||||
...templateParam,
|
...templateParam,
|
||||||
key: key,
|
key: key,
|
||||||
|
|
|
||||||
|
|
@ -1,120 +1,58 @@
|
||||||
import { ColDef } from "ag-grid-community";
|
import { APIClassType } from "@/types/api";
|
||||||
import { forwardRef, useState } from "react";
|
import { customStringify } from "@/utils/reactflowUtils";
|
||||||
import { useUpdateNodeInternals } from "reactflow";
|
import { useEffect, useState } from "react";
|
||||||
import TableComponent from "../../components/tableComponent";
|
|
||||||
import { Badge } from "../../components/ui/badge";
|
import { Badge } from "../../components/ui/badge";
|
||||||
import { Button } from "../../components/ui/button";
|
import { Button } from "../../components/ui/button";
|
||||||
import { useDarkStore } from "../../stores/darkStore";
|
import { useDarkStore } from "../../stores/darkStore";
|
||||||
import useFlowStore from "../../stores/flowStore";
|
|
||||||
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
|
||||||
import { APIClassType } from "../../types/api";
|
|
||||||
import { NodeDataType } from "../../types/flow";
|
import { NodeDataType } from "../../types/flow";
|
||||||
import {
|
|
||||||
debouncedHandleUpdateValues,
|
|
||||||
handleUpdateValues,
|
|
||||||
} from "../../utils/parameterUtils";
|
|
||||||
import BaseModal from "../baseModal";
|
import BaseModal from "../baseModal";
|
||||||
import useColumnDefs from "./hooks/use-column-defs";
|
import { EditNodeComponent } from "./components/editNodeComponent";
|
||||||
import useHandleChangeAdvanced from "./hooks/use-handle-change-advanced";
|
|
||||||
import useHandleOnNewValue from "./hooks/use-handle-new-value";
|
|
||||||
import useHandleNodeClass from "./hooks/use-handle-node-class";
|
|
||||||
import useRowData from "./hooks/use-row-data";
|
|
||||||
|
|
||||||
const EditNodeModal = forwardRef(
|
const EditNodeModal = ({
|
||||||
(
|
open,
|
||||||
{
|
setOpen,
|
||||||
nodeLength,
|
data,
|
||||||
open,
|
}: {
|
||||||
setOpen,
|
open: boolean;
|
||||||
data,
|
setOpen: (open: boolean) => void;
|
||||||
}: {
|
data: NodeDataType;
|
||||||
nodeLength: number;
|
}) => {
|
||||||
open: boolean;
|
const isDark = useDarkStore((state) => state.dark);
|
||||||
setOpen: (open: boolean) => void;
|
|
||||||
data: NodeDataType;
|
|
||||||
},
|
|
||||||
ref,
|
|
||||||
) => {
|
|
||||||
const isDark = useDarkStore((state) => state.dark);
|
|
||||||
const setNode = useFlowStore((state) => state.setNode);
|
|
||||||
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
|
|
||||||
const updateNodeInternals = useUpdateNodeInternals();
|
|
||||||
|
|
||||||
const { handleOnNewValue: handleOnNewValueHook } = useHandleOnNewValue(
|
const [nodeClass, setNodeClass] = useState<APIClassType>(data.node!);
|
||||||
data,
|
|
||||||
takeSnapshot,
|
|
||||||
handleUpdateValues,
|
|
||||||
debouncedHandleUpdateValues,
|
|
||||||
setNode,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { handleNodeClass: handleNodeClassHook } = useHandleNodeClass(
|
useEffect(() => {
|
||||||
data,
|
if (
|
||||||
takeSnapshot,
|
customStringify(Object.keys(data?.node?.template ?? {})) ===
|
||||||
setNode,
|
customStringify(Object.keys(nodeClass?.template ?? {}))
|
||||||
updateNodeInternals,
|
)
|
||||||
);
|
return;
|
||||||
|
setNodeClass(data.node!);
|
||||||
|
}, [data.node]);
|
||||||
|
|
||||||
const [nodeClass, setNodeClass] = useState<APIClassType>(data.node!);
|
return (
|
||||||
|
<BaseModal key={data.id} open={open} setOpen={setOpen}>
|
||||||
const handleNodeClass = (
|
<BaseModal.Trigger>
|
||||||
newNodeClass: APIClassType,
|
<></>
|
||||||
name: string,
|
</BaseModal.Trigger>
|
||||||
code: string,
|
<BaseModal.Header description={data.node?.description!}>
|
||||||
type?: string,
|
<span className="pr-2">{data.node?.display_name ?? data.type}</span>
|
||||||
) => {
|
<div>
|
||||||
handleNodeClassHook(newNodeClass, name, code, type);
|
<Badge size="sm" variant={isDark ? "gray" : "secondary"}>
|
||||||
setNodeClass(newNodeClass);
|
ID: {data.id}
|
||||||
};
|
</Badge>
|
||||||
|
</div>
|
||||||
const { handleChangeAdvanced: handleChangeAdvancedHook } =
|
</BaseModal.Header>
|
||||||
useHandleChangeAdvanced(data, takeSnapshot, setNode, updateNodeInternals);
|
<BaseModal.Content>
|
||||||
|
<EditNodeComponent open={open} nodeClass={nodeClass} nodeId={data.id} />
|
||||||
const rowData = useRowData(data, nodeClass, open);
|
</BaseModal.Content>
|
||||||
|
<BaseModal.Footer>
|
||||||
const columnDefs: ColDef[] = useColumnDefs(
|
<div className="flex w-full justify-end gap-2 pt-2">
|
||||||
nodeClass,
|
<Button onClick={() => setOpen(false)}>Close</Button>
|
||||||
handleOnNewValueHook,
|
</div>
|
||||||
handleNodeClass,
|
</BaseModal.Footer>
|
||||||
handleChangeAdvancedHook,
|
</BaseModal>
|
||||||
open,
|
);
|
||||||
);
|
};
|
||||||
|
|
||||||
return (
|
|
||||||
<BaseModal key={data.id} open={open} setOpen={setOpen}>
|
|
||||||
<BaseModal.Trigger>
|
|
||||||
<></>
|
|
||||||
</BaseModal.Trigger>
|
|
||||||
<BaseModal.Header description={data.node?.description!}>
|
|
||||||
<span className="pr-2">{data.node?.display_name ?? data.type}</span>
|
|
||||||
<div>
|
|
||||||
<Badge size="sm" variant={isDark ? "gray" : "secondary"}>
|
|
||||||
ID: {data.id}
|
|
||||||
</Badge>
|
|
||||||
</div>
|
|
||||||
</BaseModal.Header>
|
|
||||||
<BaseModal.Content>
|
|
||||||
<div className="flex h-full flex-col">
|
|
||||||
<div className="h-full">
|
|
||||||
{nodeLength > 0 && (
|
|
||||||
<TableComponent
|
|
||||||
key={"editNode"}
|
|
||||||
tooltipShowDelay={0.5}
|
|
||||||
columnDefs={columnDefs}
|
|
||||||
rowData={rowData}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</BaseModal.Content>
|
|
||||||
<BaseModal.Footer>
|
|
||||||
<div className="flex w-full justify-end gap-2 pt-2">
|
|
||||||
<Button onClick={() => setOpen(false)}>Close</Button>
|
|
||||||
</div>
|
|
||||||
</BaseModal.Footer>
|
|
||||||
</BaseModal>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export default EditNodeModal;
|
export default EditNodeModal;
|
||||||
|
|
|
||||||
|
|
@ -147,8 +147,9 @@ export default function GenericModal({
|
||||||
if (
|
if (
|
||||||
JSON.stringify(apiReturn.data?.frontend_node) !== JSON.stringify({})
|
JSON.stringify(apiReturn.data?.frontend_node) !== JSON.stringify({})
|
||||||
) {
|
) {
|
||||||
if (setNodeClass)
|
setValue(inputValue);
|
||||||
setNodeClass(apiReturn.data?.frontend_node, inputValue);
|
apiReturn.data.frontend_node.template.template.value = inputValue;
|
||||||
|
if (setNodeClass) setNodeClass(apiReturn.data?.frontend_node);
|
||||||
setModalOpen(closeModal);
|
setModalOpen(closeModal);
|
||||||
setIsEdit(false);
|
setIsEdit(false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
|
import useHandleOnNewValue from "@/CustomNodes/hooks/use-handle-new-value";
|
||||||
|
import useHandleNodeClass from "@/CustomNodes/hooks/use-handle-node-class";
|
||||||
import { usePostRetrieveVertexOrder } from "@/controllers/API/queries/vertex";
|
import { usePostRetrieveVertexOrder } from "@/controllers/API/queries/vertex";
|
||||||
|
import { APIClassType } from "@/types/api";
|
||||||
import _, { cloneDeep } from "lodash";
|
import _, { cloneDeep } from "lodash";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useHotkeys } from "react-hotkeys-hook";
|
import { useHotkeys } from "react-hotkeys-hook";
|
||||||
|
|
@ -22,7 +25,6 @@ import useFlowStore from "../../../../stores/flowStore";
|
||||||
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
|
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
|
||||||
import { useShortcutsStore } from "../../../../stores/shortcuts";
|
import { useShortcutsStore } from "../../../../stores/shortcuts";
|
||||||
import { useStoreStore } from "../../../../stores/storeStore";
|
import { useStoreStore } from "../../../../stores/storeStore";
|
||||||
import { APIClassType } from "../../../../types/api";
|
|
||||||
import { nodeToolbarPropsType } from "../../../../types/components";
|
import { nodeToolbarPropsType } from "../../../../types/components";
|
||||||
import { FlowType } from "../../../../types/flow";
|
import { FlowType } from "../../../../types/flow";
|
||||||
import {
|
import {
|
||||||
|
|
@ -31,7 +33,7 @@ import {
|
||||||
expandGroupNode,
|
expandGroupNode,
|
||||||
updateFlowPosition,
|
updateFlowPosition,
|
||||||
} from "../../../../utils/reactflowUtils";
|
} from "../../../../utils/reactflowUtils";
|
||||||
import { classNames, cn, isThereModal } from "../../../../utils/utils";
|
import { classNames, cn } from "../../../../utils/utils";
|
||||||
import isWrappedWithClass from "../PageComponent/utils/is-wrapped-with-class";
|
import isWrappedWithClass from "../PageComponent/utils/is-wrapped-with-class";
|
||||||
import ToolbarSelectItem from "./toolbarSelectItem";
|
import ToolbarSelectItem from "./toolbarSelectItem";
|
||||||
|
|
||||||
|
|
@ -384,57 +386,20 @@ export default function NodeToolbarComponent({
|
||||||
|
|
||||||
const setNode = useFlowStore((state) => state.setNode);
|
const setNode = useFlowStore((state) => state.setNode);
|
||||||
|
|
||||||
const handleOnNewValue = (
|
const { handleOnNewValue: handleOnNewValueHook } = useHandleOnNewValue({
|
||||||
newValue: string | string[] | boolean | Object[],
|
node: data.node!,
|
||||||
): void => {
|
nodeId: data.id,
|
||||||
if (data.node!.template[name].value !== newValue) {
|
name,
|
||||||
takeSnapshot();
|
});
|
||||||
}
|
|
||||||
|
|
||||||
data.node!.template[name].value = newValue; // necessary to enable ctrl+z inside the input
|
const handleOnNewValue = (value: string | string[]) => {
|
||||||
|
handleOnNewValueHook({ value });
|
||||||
setNode(data.id, (oldNode) => {
|
|
||||||
let newNode = cloneDeep(oldNode);
|
|
||||||
|
|
||||||
newNode.data = {
|
|
||||||
...newNode.data,
|
|
||||||
};
|
|
||||||
|
|
||||||
newNode.data.node.template[name].value = newValue;
|
|
||||||
|
|
||||||
return newNode;
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleNodeClass = (
|
const { handleNodeClass: handleNodeClassHook } = useHandleNodeClass(data.id);
|
||||||
newNodeClass: APIClassType,
|
|
||||||
code?: string,
|
|
||||||
type?: string,
|
|
||||||
): void => {
|
|
||||||
if (!data.node) return;
|
|
||||||
if (data.node!.template[name].value !== code) {
|
|
||||||
takeSnapshot();
|
|
||||||
}
|
|
||||||
|
|
||||||
setNode(data.id, (oldNode) => {
|
const handleNodeClass = (newNodeClass: APIClassType, type: string) => {
|
||||||
let newNode = cloneDeep(oldNode);
|
handleNodeClassHook(newNodeClass, type);
|
||||||
|
|
||||||
newNode.data = {
|
|
||||||
...newNode.data,
|
|
||||||
node: newNodeClass,
|
|
||||||
description: newNodeClass.description ?? data.node!.description,
|
|
||||||
display_name: newNodeClass.display_name ?? data.node!.display_name,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (type) {
|
|
||||||
newNode.data.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
newNode.data.node.template[name].value = code;
|
|
||||||
|
|
||||||
return newNode;
|
|
||||||
});
|
|
||||||
updateNodeInternals(data.id);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const [openModal, setOpenModal] = useState(false);
|
const [openModal, setOpenModal] = useState(false);
|
||||||
|
|
@ -748,9 +713,7 @@ export default function NodeToolbarComponent({
|
||||||
</ConfirmationModal>
|
</ConfirmationModal>
|
||||||
{showModalAdvanced && (
|
{showModalAdvanced && (
|
||||||
<EditNodeModal
|
<EditNodeModal
|
||||||
// setOpenWDoubleClick={setOpenWDoubleClick}
|
|
||||||
data={data}
|
data={data}
|
||||||
nodeLength={nodeLength}
|
|
||||||
open={showModalAdvanced}
|
open={showModalAdvanced}
|
||||||
setOpen={setShowModalAdvanced}
|
setOpen={setShowModalAdvanced}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,127 @@
|
||||||
|
import { getChangesType } from "@/modals/apiModal/utils/get-changes-types";
|
||||||
|
import {
|
||||||
|
getCurlRunCode,
|
||||||
|
getCurlWebhookCode,
|
||||||
|
} from "@/modals/apiModal/utils/get-curl-code";
|
||||||
|
import getJsApiCode from "@/modals/apiModal/utils/get-js-api-code";
|
||||||
|
import { getNodesWithDefaultValue } from "@/modals/apiModal/utils/get-nodes-with-default-value";
|
||||||
|
import getPythonApiCode from "@/modals/apiModal/utils/get-python-api-code";
|
||||||
|
import getPythonCode from "@/modals/apiModal/utils/get-python-code";
|
||||||
|
import getWidgetCode from "@/modals/apiModal/utils/get-widget-code";
|
||||||
|
import { createTabsArray } from "@/modals/apiModal/utils/tabs-array";
|
||||||
|
import { FlowType, NodeDataType } from "@/types/flow";
|
||||||
|
import { customStringify } from "@/utils/reactflowUtils";
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import { TweaksStoreType } from "../types/zustand/tweaks";
|
import { TweaksStoreType } from "../types/zustand/tweaks";
|
||||||
|
import useFlowStore from "./flowStore";
|
||||||
|
|
||||||
export const useTweaksStore = create<TweaksStoreType>((set, get) => ({
|
export const useTweaksStore = create<TweaksStoreType>((set, get) => ({
|
||||||
tweak: [],
|
activeTweaks: false,
|
||||||
setTweak: (tweak) => set({ tweak }),
|
setActiveTweaks: (activeTweaks: boolean) => {
|
||||||
tweaksList: [],
|
set({ activeTweaks }), get().refreshTabs();
|
||||||
setTweaksList: (tweaksList) => set({ tweaksList }),
|
},
|
||||||
|
nodes: [],
|
||||||
|
setNodes: (change) => {
|
||||||
|
let newChange = typeof change === "function" ? change(get().nodes) : change;
|
||||||
|
|
||||||
|
set({
|
||||||
|
nodes: newChange,
|
||||||
|
});
|
||||||
|
get().refreshTabs();
|
||||||
|
},
|
||||||
|
setNode: (id, change) => {
|
||||||
|
let newChange =
|
||||||
|
typeof change === "function"
|
||||||
|
? change(get().nodes.find((node) => node.id === id)!)
|
||||||
|
: change;
|
||||||
|
get().setNodes((oldNodes) =>
|
||||||
|
oldNodes.map((node) => {
|
||||||
|
if (node.id === id) {
|
||||||
|
if ((node.data as NodeDataType).node?.frozen) {
|
||||||
|
(newChange.data as NodeDataType).node!.frozen = false;
|
||||||
|
}
|
||||||
|
return newChange;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getNode: (id: string) => {
|
||||||
|
return get().nodes.find((node) => node.id === id);
|
||||||
|
},
|
||||||
|
autoLogin: false,
|
||||||
|
flow: null,
|
||||||
|
initialSetup: (autoLogin: boolean, flow: FlowType) => {
|
||||||
|
useFlowStore.getState().unselectAll();
|
||||||
|
set({
|
||||||
|
nodes: getNodesWithDefaultValue(flow?.data?.nodes ?? []),
|
||||||
|
autoLogin,
|
||||||
|
flow,
|
||||||
|
});
|
||||||
|
get().refreshTabs();
|
||||||
|
},
|
||||||
|
tabs: [],
|
||||||
|
refreshTabs: () => {
|
||||||
|
const autoLogin = get().autoLogin;
|
||||||
|
const flow = get().flow;
|
||||||
|
const tweak = {};
|
||||||
|
const nodes = get().nodes;
|
||||||
|
const originalNodes = flow?.data?.nodes;
|
||||||
|
if (!flow) return;
|
||||||
|
|
||||||
|
nodes.forEach((node) => {
|
||||||
|
const originalNodeTemplate = originalNodes?.find((n) => n.id === node.id)
|
||||||
|
?.data?.node?.template;
|
||||||
|
const nodeTemplate = node.data?.node?.template;
|
||||||
|
if (originalNodeTemplate && nodeTemplate) {
|
||||||
|
const currentTweak = {};
|
||||||
|
Object.keys(nodeTemplate).forEach((name) => {
|
||||||
|
if (
|
||||||
|
customStringify(nodeTemplate[name]) !==
|
||||||
|
customStringify(originalNodeTemplate[name]) ||
|
||||||
|
get().activeTweaks
|
||||||
|
) {
|
||||||
|
currentTweak[name] = getChangesType(
|
||||||
|
nodeTemplate[name].value,
|
||||||
|
nodeTemplate[name],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tweak[node.id] = currentTweak;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const pythonApiCode = getPythonApiCode(flow?.id, autoLogin, tweak);
|
||||||
|
const runCurlCode = getCurlRunCode(
|
||||||
|
flow?.id,
|
||||||
|
autoLogin,
|
||||||
|
tweak,
|
||||||
|
flow?.endpoint_name,
|
||||||
|
);
|
||||||
|
const jsApiCode = getJsApiCode(
|
||||||
|
flow?.id,
|
||||||
|
autoLogin,
|
||||||
|
tweak,
|
||||||
|
flow?.endpoint_name,
|
||||||
|
);
|
||||||
|
const webhookCurlCode = getCurlWebhookCode(
|
||||||
|
flow?.id,
|
||||||
|
autoLogin,
|
||||||
|
flow?.endpoint_name,
|
||||||
|
);
|
||||||
|
const pythonCode = getPythonCode(flow?.name, tweak);
|
||||||
|
const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin);
|
||||||
|
|
||||||
|
const codesArray = [
|
||||||
|
runCurlCode,
|
||||||
|
webhookCurlCode,
|
||||||
|
pythonApiCode,
|
||||||
|
jsApiCode,
|
||||||
|
pythonCode,
|
||||||
|
widgetCode,
|
||||||
|
];
|
||||||
|
set({
|
||||||
|
tabs: createTabsArray(codesArray, !!flow.webhook, nodes.length > 0),
|
||||||
|
});
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { handleOnNewValueType } from "@/CustomNodes/hooks/use-handle-new-value";
|
||||||
import { ReactElement, ReactNode, SetStateAction } from "react";
|
import { ReactElement, ReactNode, SetStateAction } from "react";
|
||||||
import { ReactFlowJsonObject } from "reactflow";
|
import { ReactFlowJsonObject } from "reactflow";
|
||||||
import { InputOutput } from "../../constants/enums";
|
import { InputOutput } from "../../constants/enums";
|
||||||
|
|
@ -89,6 +90,7 @@ export type InputListComponentType = {
|
||||||
editNode?: boolean;
|
editNode?: boolean;
|
||||||
componentName?: string;
|
componentName?: string;
|
||||||
playgroundDisabled?: boolean;
|
playgroundDisabled?: boolean;
|
||||||
|
id?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type InputGlobalComponentType = {
|
export type InputGlobalComponentType = {
|
||||||
|
|
@ -105,9 +107,9 @@ export type KeyPairListComponentType = {
|
||||||
onChange: (value: Object[]) => void;
|
onChange: (value: Object[]) => void;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
editNode?: boolean;
|
editNode?: boolean;
|
||||||
duplicateKey?: boolean;
|
|
||||||
editNodeModal?: boolean;
|
editNodeModal?: boolean;
|
||||||
isList?: boolean;
|
isList?: boolean;
|
||||||
|
id?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DictComponentType = {
|
export type DictComponentType = {
|
||||||
|
|
@ -159,7 +161,7 @@ export type outputComponentType = {
|
||||||
export type PromptAreaComponentType = {
|
export type PromptAreaComponentType = {
|
||||||
field_name?: string;
|
field_name?: string;
|
||||||
nodeClass?: APIClassType;
|
nodeClass?: APIClassType;
|
||||||
setNodeClass?: (value: APIClassType, code?: string) => void;
|
setNodeClass?: (value: APIClassType) => void;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
onChange: (
|
onChange: (
|
||||||
value: string[] | string,
|
value: string[] | string,
|
||||||
|
|
@ -183,7 +185,7 @@ export type CodeAreaComponentType = {
|
||||||
value: string;
|
value: string;
|
||||||
editNode?: boolean;
|
editNode?: boolean;
|
||||||
nodeClass?: APIClassType;
|
nodeClass?: APIClassType;
|
||||||
setNodeClass?: (value: APIClassType, code?: string) => void;
|
setNodeClass?: (value: APIClassType, type: string) => void;
|
||||||
dynamic?: boolean;
|
dynamic?: boolean;
|
||||||
id?: string;
|
id?: string;
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
|
|
@ -194,15 +196,11 @@ export type CodeAreaComponentType = {
|
||||||
export type FileComponentType = {
|
export type FileComponentType = {
|
||||||
IOInputProps?;
|
IOInputProps?;
|
||||||
disabled: boolean;
|
disabled: boolean;
|
||||||
onChange: (
|
handleOnNewValue: handleOnNewValueType;
|
||||||
value: string[] | string,
|
|
||||||
dbValue?: boolean,
|
|
||||||
skipSnapshot?: boolean,
|
|
||||||
) => void;
|
|
||||||
value: string;
|
value: string;
|
||||||
fileTypes: Array<string>;
|
fileTypes: Array<string>;
|
||||||
onFileChange: (value: string) => void;
|
|
||||||
editNode?: boolean;
|
editNode?: boolean;
|
||||||
|
id?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DisclosureComponentType = {
|
export type DisclosureComponentType = {
|
||||||
|
|
@ -622,11 +620,7 @@ export type codeAreaModalPropsType = {
|
||||||
setOpenModal?: (bool: boolean) => void;
|
setOpenModal?: (bool: boolean) => void;
|
||||||
value: string;
|
value: string;
|
||||||
nodeClass: APIClassType | undefined;
|
nodeClass: APIClassType | undefined;
|
||||||
setNodeClass: (
|
setNodeClass: (Class: APIClassType, type: string) => void | undefined;
|
||||||
Class: APIClassType,
|
|
||||||
code?: string,
|
|
||||||
type?: string,
|
|
||||||
) => void | undefined;
|
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
dynamic?: boolean;
|
dynamic?: boolean;
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
|
|
@ -655,7 +649,7 @@ export type genericModalPropsType = {
|
||||||
type: number;
|
type: number;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
nodeClass?: APIClassType;
|
nodeClass?: APIClassType;
|
||||||
setNodeClass?: (Class: APIClassType, code?: string) => void;
|
setNodeClass?: (Class: APIClassType, type?: string) => void;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
id?: string;
|
id?: string;
|
||||||
readonly?: boolean;
|
readonly?: boolean;
|
||||||
|
|
@ -701,53 +695,25 @@ export type cardComponentPropsType = {
|
||||||
button?: JSX.Element;
|
button?: JSX.Element;
|
||||||
};
|
};
|
||||||
|
|
||||||
type tabsArrayType = {
|
export type tabsArrayType = {
|
||||||
code: string;
|
code: string;
|
||||||
image: string;
|
image: string;
|
||||||
language: string;
|
language: string;
|
||||||
mode: string;
|
mode: string;
|
||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
};
|
hasTweaks?: boolean;
|
||||||
|
|
||||||
type getValueNodeType = {
|
|
||||||
id: string;
|
|
||||||
node: NodeType;
|
|
||||||
type: string;
|
|
||||||
value: null;
|
|
||||||
};
|
|
||||||
|
|
||||||
type codeTabsFuncTempType = {
|
|
||||||
[key: string]: string | boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type codeTabsPropsType = {
|
export type codeTabsPropsType = {
|
||||||
isThereTweaks?: boolean;
|
open: boolean;
|
||||||
isThereWH?: boolean;
|
|
||||||
flow?: FlowType;
|
|
||||||
tabs: Array<tabsArrayType>;
|
tabs: Array<tabsArrayType>;
|
||||||
activeTab: string;
|
activeTab: string;
|
||||||
setActiveTab: (value: string) => void;
|
setActiveTab: (value: string) => void;
|
||||||
isMessage?: boolean;
|
isMessage?: boolean;
|
||||||
tweaks?: {
|
tweaksNodes?: Array<NodeType>;
|
||||||
tweak?: tweakType;
|
|
||||||
tweaksList?: Array<string>;
|
|
||||||
buildContent?: (value: string) => ReactNode;
|
|
||||||
getValue?: (
|
|
||||||
value: string,
|
|
||||||
node: NodeType,
|
|
||||||
template: InputFieldType,
|
|
||||||
tweak: tweakType,
|
|
||||||
) => string;
|
|
||||||
buildTweakObject?: (
|
|
||||||
tw: string,
|
|
||||||
changes: string | string[] | boolean | number | Object[] | Object,
|
|
||||||
template: InputFieldType,
|
|
||||||
) => Promise<string | void>;
|
|
||||||
};
|
|
||||||
activeTweaks?: boolean;
|
activeTweaks?: boolean;
|
||||||
setActiveTweaks?: (value: boolean) => void;
|
setActiveTweaks?: (value: boolean) => void;
|
||||||
allowExport?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type crashComponentPropsType = {
|
export type crashComponentPropsType = {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,22 @@
|
||||||
import { tweakType } from "../../components";
|
import { FlowType, NodeType } from "@/types/flow";
|
||||||
|
import { tabsArrayType } from "../../components";
|
||||||
|
|
||||||
export type TweaksStoreType = {
|
export type TweaksStoreType = {
|
||||||
tweak: tweakType;
|
activeTweaks: boolean;
|
||||||
setTweak: (tweak: tweakType) => void;
|
setActiveTweaks: (activeTweaks: boolean) => void;
|
||||||
tweaksList: string[];
|
nodes: NodeType[];
|
||||||
setTweaksList: (tweaksList: string[]) => void;
|
setNodes: (
|
||||||
|
update: NodeType[] | ((oldState: NodeType[]) => NodeType[]),
|
||||||
|
skipSave?: boolean,
|
||||||
|
) => void;
|
||||||
|
setNode: (
|
||||||
|
id: string,
|
||||||
|
update: NodeType | ((oldState: NodeType) => NodeType),
|
||||||
|
) => void;
|
||||||
|
getNode: (id: string) => NodeType | undefined;
|
||||||
|
tabs: tabsArrayType[];
|
||||||
|
initialSetup: (autoLogin: boolean, flow: FlowType) => void;
|
||||||
|
refreshTabs: () => void;
|
||||||
|
autoLogin: boolean;
|
||||||
|
flow: FlowType | null;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { cloneDeep, get } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import {
|
import {
|
||||||
Connection,
|
Connection,
|
||||||
Edge,
|
Edge,
|
||||||
|
|
@ -1033,7 +1033,7 @@ export function mergeNodeTemplates({
|
||||||
});
|
});
|
||||||
return template;
|
return template;
|
||||||
}
|
}
|
||||||
function isTargetHandleConnected(
|
export function isTargetHandleConnected(
|
||||||
edges: Edge[],
|
edges: Edge[],
|
||||||
key: string,
|
key: string,
|
||||||
field: InputFieldType,
|
field: InputFieldType,
|
||||||
|
|
@ -1042,6 +1042,7 @@ function isTargetHandleConnected(
|
||||||
/*
|
/*
|
||||||
this function receives a flow and a handleId and check if there is a connection with this handle
|
this function receives a flow and a handleId and check if there is a connection with this handle
|
||||||
*/
|
*/
|
||||||
|
if (!field) return true;
|
||||||
if (field.proxy) {
|
if (field.proxy) {
|
||||||
if (
|
if (
|
||||||
edges.some(
|
edges.some(
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ test("Basic Prompting (Hello, World)", async ({ page }) => {
|
||||||
.getByTestId("popover-anchor-input-api_key")
|
.getByTestId("popover-anchor-input-api_key")
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").click();
|
await page.getByTestId("dropdown_str_model_name").click();
|
||||||
await page.getByTestId("gpt-4o-1-option").click();
|
await page.getByTestId("gpt-4o-1-option").click();
|
||||||
|
|
||||||
await page.waitForTimeout(2000);
|
await page.waitForTimeout(2000);
|
||||||
|
|
|
||||||
|
|
@ -51,18 +51,18 @@ test("Blog Writer", async ({ page }) => {
|
||||||
.getByTestId("popover-anchor-input-api_key")
|
.getByTestId("popover-anchor-input-api_key")
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").click();
|
await page.getByTestId("dropdown_str_model_name").click();
|
||||||
await page.getByTestId("gpt-4o-1-option").click();
|
await page.getByTestId("gpt-4o-1-option").click();
|
||||||
|
|
||||||
await page.waitForTimeout(2000);
|
await page.waitForTimeout(2000);
|
||||||
await page
|
await page
|
||||||
.getByTestId("input-list-input_urls-0")
|
.getByTestId("inputlist_str_urls_0")
|
||||||
.nth(0)
|
.nth(0)
|
||||||
.fill(
|
.fill(
|
||||||
"https://www.natgeokids.com/uk/discover/animals/sea-life/turtle-facts/",
|
"https://www.natgeokids.com/uk/discover/animals/sea-life/turtle-facts/",
|
||||||
);
|
);
|
||||||
await page
|
await page
|
||||||
.getByTestId("input-list-input_urls-1")
|
.getByTestId("inputlist_str_urls_1")
|
||||||
.nth(0)
|
.nth(0)
|
||||||
.fill("https://www.originaldiving.com/blog/top-ten-turtle-facts");
|
.fill("https://www.originaldiving.com/blog/top-ten-turtle-facts");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ test("Complex Agent", async ({ page }) => {
|
||||||
.nth(i)
|
.nth(i)
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").nth(i).click();
|
await page.getByTestId("dropdown_str_model_name").nth(i).click();
|
||||||
await page.getByTestId("gpt-4o-1-option").last().click();
|
await page.getByTestId("gpt-4o-1-option").last().click();
|
||||||
|
|
||||||
await page.waitForTimeout(1000);
|
await page.waitForTimeout(1000);
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ test("Document QA", async ({ page }) => {
|
||||||
.getByTestId("popover-anchor-input-api_key")
|
.getByTestId("popover-anchor-input-api_key")
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").click();
|
await page.getByTestId("dropdown_str_model_name").click();
|
||||||
await page.getByTestId("gpt-4o-1-option").click();
|
await page.getByTestId("gpt-4o-1-option").click();
|
||||||
|
|
||||||
await page.waitForTimeout(2000);
|
await page.waitForTimeout(2000);
|
||||||
|
|
|
||||||
|
|
@ -65,12 +65,12 @@ test("Hierarchical Tasks Agent", async ({ page }) => {
|
||||||
.nth(1)
|
.nth(1)
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").first().click();
|
await page.getByTestId("dropdown_str_model_name").first().click();
|
||||||
await page.getByTestId("gpt-4o-1-option").first().click();
|
await page.getByTestId("gpt-4o-1-option").first().click();
|
||||||
|
|
||||||
await page.waitForTimeout(2000);
|
await page.waitForTimeout(2000);
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").last().click();
|
await page.getByTestId("dropdown_str_model_name").last().click();
|
||||||
await page.getByTestId("gpt-4o-1-option").last().click();
|
await page.getByTestId("gpt-4o-1-option").last().click();
|
||||||
|
|
||||||
await page.waitForTimeout(2000);
|
await page.waitForTimeout(2000);
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ test("Memory Chatbot", async ({ page }) => {
|
||||||
.getByTestId("popover-anchor-input-api_key")
|
.getByTestId("popover-anchor-input-api_key")
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").click();
|
await page.getByTestId("dropdown_str_model_name").click();
|
||||||
await page.getByTestId("gpt-4o-1-option").click();
|
await page.getByTestId("gpt-4o-1-option").click();
|
||||||
|
|
||||||
await page.waitForTimeout(2000);
|
await page.waitForTimeout(2000);
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ test("Sequential Tasks Agent", async ({ page }) => {
|
||||||
.first()
|
.first()
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").click();
|
await page.getByTestId("dropdown_str_model_name").click();
|
||||||
await page.getByTestId("gpt-4o-1-option").click();
|
await page.getByTestId("gpt-4o-1-option").click();
|
||||||
|
|
||||||
await page.waitForTimeout(2000);
|
await page.waitForTimeout(2000);
|
||||||
|
|
|
||||||
|
|
@ -96,21 +96,21 @@ test("Vector Store RAG", async ({ page }) => {
|
||||||
await page.waitForTimeout(2000);
|
await page.waitForTimeout(2000);
|
||||||
|
|
||||||
await page.getByTestId("button_run_astra db").first().click();
|
await page.getByTestId("button_run_astra db").first().click();
|
||||||
await page.waitForSelector("text=built successfully", { timeout: 30000 });
|
await page.waitForSelector("text=built successfully", { timeout: 60000 * 2 });
|
||||||
|
|
||||||
await page.getByText("built successfully").last().click({
|
await page.getByText("built successfully").last().click({
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
});
|
});
|
||||||
|
|
||||||
await page.getByTestId("button_run_chat output").click();
|
await page.getByTestId("button_run_chat output").click();
|
||||||
await page.waitForSelector("text=built successfully", { timeout: 30000 });
|
await page.waitForSelector("text=built successfully", { timeout: 60000 * 2 });
|
||||||
|
|
||||||
await page.getByText("built successfully").last().click({
|
await page.getByText("built successfully").last().click({
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
});
|
});
|
||||||
|
|
||||||
await page.getByTestId("button_run_astra db").last().click();
|
await page.getByTestId("button_run_astra db").last().click();
|
||||||
await page.waitForSelector("text=built successfully", { timeout: 30000 });
|
await page.waitForSelector("text=built successfully", { timeout: 60000 * 2 });
|
||||||
|
|
||||||
await page.getByText("built successfully").last().click({
|
await page.getByText("built successfully").last().click({
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ test("user must be able to send an image on chat", async ({ page }) => {
|
||||||
.getByTestId("popover-anchor-input-api_key")
|
.getByTestId("popover-anchor-input-api_key")
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").click();
|
await page.getByTestId("dropdown_str_model_name").click();
|
||||||
await page.getByTestId("gpt-4o-1-option").click();
|
await page.getByTestId("gpt-4o-1-option").click();
|
||||||
|
|
||||||
await page.waitForSelector("text=Chat Input", { timeout: 30000 });
|
await page.waitForSelector("text=Chat Input", { timeout: 30000 });
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ test("user must be able to see output inspection", async ({ page }) => {
|
||||||
.getByTestId("popover-anchor-input-api_key")
|
.getByTestId("popover-anchor-input-api_key")
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").click();
|
await page.getByTestId("dropdown_str_model_name").click();
|
||||||
await page.getByTestId("gpt-4o-1-option").click();
|
await page.getByTestId("gpt-4o-1-option").click();
|
||||||
|
|
||||||
await page.waitForTimeout(2000);
|
await page.waitForTimeout(2000);
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ test("user must interact with chat with Input/Output", async ({ page }) => {
|
||||||
.getByTestId("popover-anchor-input-api_key")
|
.getByTestId("popover-anchor-input-api_key")
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").click();
|
await page.getByTestId("dropdown_str_model_name").click();
|
||||||
await page.getByTestId("gpt-4o-1-option").click();
|
await page.getByTestId("gpt-4o-1-option").click();
|
||||||
|
|
||||||
await page.waitForTimeout(2000);
|
await page.waitForTimeout(2000);
|
||||||
|
|
@ -86,7 +86,7 @@ test("user must interact with chat with Input/Output", async ({ page }) => {
|
||||||
await page.keyboard.press("Escape");
|
await page.keyboard.press("Escape");
|
||||||
|
|
||||||
await page
|
await page
|
||||||
.getByTestId("textarea-input_value")
|
.getByTestId("textarea_str_input_value")
|
||||||
.nth(0)
|
.nth(0)
|
||||||
.fill(
|
.fill(
|
||||||
"testtesttesttesttesttestte;.;.,;,.;,.;.,;,..,;;;;;;;;;;;;;;;;;;;;;,;.;,.;,.,;.,;.;.,~~çççççççççççççççççççççççççççççççççççççççisdajfdasiopjfaodisjhvoicxjiovjcxizopjviopasjioasfhjaiohf23432432432423423sttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttestççççççççççççççççççççççççççççççççç,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,!",
|
"testtesttesttesttesttestte;.;.,;,.;,.;.,;,..,;;;;;;;;;;;;;;;;;;;;;,;.;,.;,.,;.,;.;.,~~çççççççççççççççççççççççççççççççççççççççisdajfdasiopjfaodisjhvoicxjiovjcxizopjviopasjioasfhjaiohf23432432432423423sttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttestççççççççççççççççççççççççççççççççç,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,!",
|
||||||
|
|
|
||||||
|
|
@ -80,12 +80,14 @@ test("should create a flow with decision", async ({ page }) => {
|
||||||
await page.getByTestId("input-list-plus-btn_texts-0").click();
|
await page.getByTestId("input-list-plus-btn_texts-0").click();
|
||||||
|
|
||||||
await page
|
await page
|
||||||
.getByTestId("input-list-input_texts-0")
|
.getByTestId("inputlist_str_texts_0")
|
||||||
|
.first()
|
||||||
.fill("big news! langflow 1.0 is out");
|
.fill("big news! langflow 1.0 is out");
|
||||||
await page
|
await page
|
||||||
.getByTestId("input-list-input_texts-1")
|
.getByTestId("inputlist_str_texts_1")
|
||||||
|
.first()
|
||||||
.fill("uhul that movie was awesome");
|
.fill("uhul that movie was awesome");
|
||||||
await page.getByTestId("input-list-input_texts-2").fill("love you babe");
|
await page.getByTestId("inputlist_str_texts_2").first().fill("love you babe");
|
||||||
|
|
||||||
await page.getByTitle("zoom out").click();
|
await page.getByTitle("zoom out").click();
|
||||||
await page.getByTitle("zoom out").click();
|
await page.getByTitle("zoom out").click();
|
||||||
|
|
@ -108,15 +110,12 @@ test("should create a flow with decision", async ({ page }) => {
|
||||||
await page.getByTestId("input-list-plus-btn_texts-0").last().click();
|
await page.getByTestId("input-list-plus-btn_texts-0").last().click();
|
||||||
await page.getByTestId("input-list-plus-btn_texts-0").last().click();
|
await page.getByTestId("input-list-plus-btn_texts-0").last().click();
|
||||||
|
|
||||||
|
await page.getByTestId("inputlist_str_texts_0").last().fill("oh my cat died");
|
||||||
await page
|
await page
|
||||||
.getByTestId("input-list-input_texts-0")
|
.getByTestId("inputlist_str_texts_1")
|
||||||
.last()
|
|
||||||
.fill("oh my cat died");
|
|
||||||
await page
|
|
||||||
.getByTestId("input-list-input_texts-1")
|
|
||||||
.last()
|
.last()
|
||||||
.fill("No one loves me");
|
.fill("No one loves me");
|
||||||
await page.getByTestId("input-list-input_texts-2").last().fill("not cool..");
|
await page.getByTestId("inputlist_str_texts_2").last().fill("not cool..");
|
||||||
|
|
||||||
await page.getByPlaceholder("Search").click();
|
await page.getByPlaceholder("Search").click();
|
||||||
await page.getByPlaceholder("Search").fill("parse data");
|
await page.getByPlaceholder("Search").fill("parse data");
|
||||||
|
|
@ -348,8 +347,8 @@ test("should create a flow with decision", async ({ page }) => {
|
||||||
await page.mouse.up();
|
await page.mouse.up();
|
||||||
|
|
||||||
//edit prompt
|
//edit prompt
|
||||||
await page.getByTestId("prompt-input-template").first().click();
|
await page.getByTestId("promptarea_prompt_template").first().click();
|
||||||
await page.getByTestId("modal-prompt-input-template").first().fill(`
|
await page.getByTestId("modal-promptarea_prompt_template").first().fill(`
|
||||||
{Condition}
|
{Condition}
|
||||||
|
|
||||||
Answer with either TRUE or FALSE (and nothing else).
|
Answer with either TRUE or FALSE (and nothing else).
|
||||||
|
|
@ -551,7 +550,7 @@ AI:
|
||||||
.getByTestId("popover-anchor-input-api_key")
|
.getByTestId("popover-anchor-input-api_key")
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").click();
|
await page.getByTestId("dropdown_str_model_name").click();
|
||||||
await page.getByTestId("gpt-4o-1-option").click();
|
await page.getByTestId("gpt-4o-1-option").click();
|
||||||
|
|
||||||
await page.getByLabel("fit view").click();
|
await page.getByLabel("fit view").click();
|
||||||
|
|
@ -570,7 +569,7 @@ AI:
|
||||||
await page.getByTestId("icon-LucideSend").click();
|
await page.getByTestId("icon-LucideSend").click();
|
||||||
|
|
||||||
await page.waitForSelector("text=🥲", {
|
await page.waitForSelector("text=🥲", {
|
||||||
timeout: 100000,
|
timeout: 1200000,
|
||||||
});
|
});
|
||||||
|
|
||||||
await page.getByText("🥲").isVisible();
|
await page.getByText("🥲").isVisible();
|
||||||
|
|
|
||||||
|
|
@ -46,22 +46,24 @@ test("dropDownComponent", async ({ page }) => {
|
||||||
await page.getByTitle("zoom out").click();
|
await page.getByTitle("zoom out").click();
|
||||||
await page.getByTestId("title-Amazon Bedrock").click();
|
await page.getByTestId("title-Amazon Bedrock").click();
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_id").click();
|
await page.getByTestId("dropdown_str_model_id").click();
|
||||||
|
|
||||||
await page.getByTestId("value-dropdown-dropdown-model_id").click();
|
await page
|
||||||
|
.getByTestId("anthropic.claude-3-haiku-20240307-v1:0-10-option")
|
||||||
|
.click();
|
||||||
|
|
||||||
let value = await page
|
let value = await page
|
||||||
.getByTestId("value-dropdown-dropdown-model_id")
|
.getByTestId("anthropic.claude-3-haiku-20240307-v1:0-10-option")
|
||||||
.first()
|
.first()
|
||||||
.innerText();
|
.innerText();
|
||||||
if (value !== "anthropic.claude-3-haiku-20240307-v1:0") {
|
if (value !== "anthropic.claude-3-haiku-20240307-v1:0") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_id").click();
|
await page.getByTestId("dropdown_str_model_id").click();
|
||||||
await page.getByText("anthropic.claude-v2").last().click();
|
await page.getByText("anthropic.claude-v2").last().click();
|
||||||
|
|
||||||
value = await page.getByTestId("dropdown-model_id").innerText();
|
value = await page.getByTestId("dropdown_str_model_id").innerText();
|
||||||
if (value !== "anthropic.claude-v2:1") {
|
if (value !== "anthropic.claude-v2:1") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
@ -71,7 +73,9 @@ test("dropDownComponent", async ({ page }) => {
|
||||||
await page.getByTestId("more-options-modal").click();
|
await page.getByTestId("more-options-modal").click();
|
||||||
await page.getByTestId("edit-button-modal").click();
|
await page.getByTestId("edit-button-modal").click();
|
||||||
|
|
||||||
value = await page.getByTestId("dropdown-edit-model_id").innerText();
|
value = await page
|
||||||
|
.getByTestId("value-dropdown-dropdown_str_edit_model_id")
|
||||||
|
.innerText();
|
||||||
if (value !== "anthropic.claude-v2:1") {
|
if (value !== "anthropic.claude-v2:1") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
@ -136,17 +140,21 @@ test("dropDownComponent", async ({ page }) => {
|
||||||
await page.locator('//*[@id="showmodel_id"]').isChecked(),
|
await page.locator('//*[@id="showmodel_id"]').isChecked(),
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
|
|
||||||
await page.getByTestId("dropdown-edit-model_id").click();
|
await page.getByTestId("value-dropdown-dropdown_str_edit_model_id").click();
|
||||||
await page.getByText("cohere").last().click();
|
await page.getByText("cohere").last().click();
|
||||||
|
|
||||||
value = await page.getByTestId("dropdown-edit-model_id").innerText();
|
value = await page
|
||||||
|
.getByTestId("value-dropdown-dropdown_str_edit_model_id")
|
||||||
|
.innerText();
|
||||||
if (value !== "cohere.embed-multilingual-v3") {
|
if (value !== "cohere.embed-multilingual-v3") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
||||||
await page.getByText("Close").last().click();
|
await page.getByText("Close").last().click();
|
||||||
|
|
||||||
value = await page.getByTestId("dropdown-model_id").innerText();
|
value = await page
|
||||||
|
.getByTestId("value-dropdown-dropdown_str_model_id")
|
||||||
|
.innerText();
|
||||||
if (value !== "cohere.embed-multilingual-v3") {
|
if (value !== "cohere.embed-multilingual-v3") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -147,8 +147,15 @@ test("should be able to upload a file", async ({ page }) => {
|
||||||
await page.mouse.up();
|
await page.mouse.up();
|
||||||
|
|
||||||
await page.getByText("Playground", { exact: true }).click();
|
await page.getByText("Playground", { exact: true }).click();
|
||||||
|
|
||||||
|
await page.waitForSelector("text=Run Flow", {
|
||||||
|
timeout: 30000,
|
||||||
|
});
|
||||||
|
|
||||||
await page.getByText("Run Flow", { exact: true }).click();
|
await page.getByText("Run Flow", { exact: true }).click();
|
||||||
|
|
||||||
await page.waitForTimeout(3000);
|
await page.waitForTimeout(3000);
|
||||||
|
|
||||||
const textOutput = await page.getByPlaceholder("Empty").first().inputValue();
|
const textOutput = await page.getByPlaceholder("Empty").first().inputValue();
|
||||||
|
|
||||||
expect(textOutput).toContain("this is a test file");
|
expect(textOutput).toContain("this is a test file");
|
||||||
|
|
|
||||||
|
|
@ -8,146 +8,6 @@ test("user must be able to freeze a path", async ({ page }) => {
|
||||||
"OPENAI_API_KEY required to run this test",
|
"OPENAI_API_KEY required to run this test",
|
||||||
);
|
);
|
||||||
|
|
||||||
// const codeOpenAI = `
|
|
||||||
// import operator
|
|
||||||
// from functools import reduce
|
|
||||||
|
|
||||||
// from langchain_openai import ChatOpenAI
|
|
||||||
// from pydantic.v1 import SecretStr
|
|
||||||
|
|
||||||
// from langflow.base.constants import STREAM_INFO_TEXT
|
|
||||||
// from langflow.base.models.model import LCModelComponent
|
|
||||||
// from langflow.base.models.openai_constants import MODEL_NAMES
|
|
||||||
// from langflow.field_typing import LanguageModel
|
|
||||||
// from langflow.inputs import (
|
|
||||||
// BoolInput,
|
|
||||||
// DictInput,
|
|
||||||
// DropdownInput,
|
|
||||||
// FloatInput,
|
|
||||||
// IntInput,
|
|
||||||
// MessageInput,
|
|
||||||
// SecretStrInput,
|
|
||||||
// StrInput,
|
|
||||||
// )
|
|
||||||
|
|
||||||
// class OpenAIModelComponent(LCModelComponent):
|
|
||||||
// display_name = "OpenAI"
|
|
||||||
// description = "Generates text using OpenAI LLMs."
|
|
||||||
// icon = "OpenAI"
|
|
||||||
// name = "OpenAIModel"
|
|
||||||
|
|
||||||
// inputs = [
|
|
||||||
// MessageInput(name="input_value", display_name="Input"),
|
|
||||||
// IntInput(
|
|
||||||
// name="max_tokens",
|
|
||||||
// display_name="Max Tokens",
|
|
||||||
// advanced=True,
|
|
||||||
// info="The maximum number of tokens to generate. Set to 0 for unlimited tokens.",
|
|
||||||
// ),
|
|
||||||
// DictInput(name="model_kwargs", display_name="Model Kwargs", advanced=True),
|
|
||||||
// BoolInput(
|
|
||||||
// name="json_mode",
|
|
||||||
// display_name="JSON Mode",
|
|
||||||
// advanced=True,
|
|
||||||
// info="If True, it will output JSON regardless of passing a schema.",
|
|
||||||
// ),
|
|
||||||
// DictInput(
|
|
||||||
// name="output_schema",
|
|
||||||
// is_list=True,
|
|
||||||
// display_name="Schema",
|
|
||||||
// advanced=True,
|
|
||||||
// info="The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.",
|
|
||||||
// ),
|
|
||||||
// DropdownInput(
|
|
||||||
// name="model_name", display_name="Model Name", advanced=False, options=MODEL_NAMES, value=MODEL_NAMES[0]
|
|
||||||
// ),
|
|
||||||
// StrInput(
|
|
||||||
// name="openai_api_base",
|
|
||||||
// display_name="OpenAI API Base",
|
|
||||||
// advanced=True,
|
|
||||||
// info="The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.",
|
|
||||||
// ),
|
|
||||||
// SecretStrInput(
|
|
||||||
// name="api_key",
|
|
||||||
// display_name="OpenAI API Key",
|
|
||||||
// info="The OpenAI API Key to use for the OpenAI model.",
|
|
||||||
// advanced=False,
|
|
||||||
// value="OPENAI_API_KEY",
|
|
||||||
// ),
|
|
||||||
// FloatInput(name="temperature", display_name="Temperature", value=0.1),
|
|
||||||
// BoolInput(name="stream", display_name="Stream", info=STREAM_INFO_TEXT, advanced=True),
|
|
||||||
// StrInput(
|
|
||||||
// name="system_message",
|
|
||||||
// display_name="System Message",
|
|
||||||
// info="System message to pass to the model.",
|
|
||||||
// advanced=True,
|
|
||||||
// ),
|
|
||||||
// IntInput(
|
|
||||||
// name="seed",
|
|
||||||
// display_name="Seed",
|
|
||||||
// info="The seed controls the reproducibility of the job.",
|
|
||||||
// advanced=True,
|
|
||||||
// value=1,
|
|
||||||
// ),
|
|
||||||
// ]
|
|
||||||
|
|
||||||
// def build_model(self) -> LanguageModel: # type: ignore[type-var]
|
|
||||||
// # self.output_schema is a list of dictionaries
|
|
||||||
// # let's convert it to a dictionary
|
|
||||||
// output_schema_dict: dict[str, str] = reduce(operator.ior, self.output_schema or {}, {})
|
|
||||||
// openai_api_key = self.api_key
|
|
||||||
// temperature = self.temperature
|
|
||||||
// model_name: str = self.model_name
|
|
||||||
// max_tokens = self.max_tokens
|
|
||||||
// model_kwargs = self.model_kwargs or {}
|
|
||||||
// openai_api_base = self.openai_api_base or "https://api.openai.com/v1"
|
|
||||||
// json_mode = bool(output_schema_dict) or self.json_mode
|
|
||||||
// seed = self.seed
|
|
||||||
|
|
||||||
// if openai_api_key:
|
|
||||||
// api_key = SecretStr(openai_api_key)
|
|
||||||
// else:
|
|
||||||
// api_key = None
|
|
||||||
// output = ChatOpenAI(
|
|
||||||
// max_tokens=max_tokens or None,
|
|
||||||
// model_kwargs=model_kwargs,
|
|
||||||
// model=model_name,
|
|
||||||
// base_url=openai_api_base,
|
|
||||||
// api_key=api_key,
|
|
||||||
// temperature=0.8,
|
|
||||||
// seed=seed,
|
|
||||||
// )
|
|
||||||
// if json_mode:
|
|
||||||
// if output_schema_dict:
|
|
||||||
// output = output.with_structured_output(schema=output_schema_dict, method="json_mode") # type: ignore
|
|
||||||
// else:
|
|
||||||
// output = output.bind(response_format={"type": "json_object"}) # type: ignore
|
|
||||||
|
|
||||||
// return output # type: ignore
|
|
||||||
|
|
||||||
// def _get_exception_message(self, e: Exception):
|
|
||||||
// """
|
|
||||||
// Get a message from an OpenAI exception.
|
|
||||||
|
|
||||||
// Args:
|
|
||||||
// exception (Exception): The exception to get the message from.
|
|
||||||
|
|
||||||
// Returns:
|
|
||||||
// str: The message from the exception.
|
|
||||||
// """
|
|
||||||
|
|
||||||
// try:
|
|
||||||
// from openai import BadRequestError
|
|
||||||
// except ImportError:
|
|
||||||
// return
|
|
||||||
// if isinstance(e, BadRequestError):
|
|
||||||
// message = e.body.get("message") # type: ignore
|
|
||||||
// if message:
|
|
||||||
// return message
|
|
||||||
// return
|
|
||||||
|
|
||||||
// `;
|
|
||||||
|
|
||||||
if (!process.env.CI) {
|
if (!process.env.CI) {
|
||||||
dotenv.config({ path: path.resolve(__dirname, "../../.env") });
|
dotenv.config({ path: path.resolve(__dirname, "../../.env") });
|
||||||
}
|
}
|
||||||
|
|
@ -195,23 +55,15 @@ test("user must be able to freeze a path", async ({ page }) => {
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page
|
await page
|
||||||
.getByTestId("textarea-input_value")
|
.getByTestId("textarea_str_input_value")
|
||||||
.first()
|
.first()
|
||||||
.fill(
|
.fill(
|
||||||
"say a random number between 1 and 100000 and a random animal that lives in the sea",
|
"say a random number between 1 and 100000 and a random animal that lives in the sea",
|
||||||
);
|
);
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").click();
|
await page.getByTestId("dropdown_str_model_name").click();
|
||||||
await page.getByTestId("gpt-4o-1-option").click();
|
await page.getByTestId("gpt-4o-1-option").click();
|
||||||
|
|
||||||
// await page.getByText("OpenAI").first().click();
|
|
||||||
|
|
||||||
// await page.getByTestId("code-button-modal").first().click();
|
|
||||||
|
|
||||||
// await page.locator("textarea").press("Control+a");
|
|
||||||
// await page.locator("textarea").fill(codeOpenAI);
|
|
||||||
// await page.locator('//*[@id="checkAndSaveBtn"]').click();
|
|
||||||
|
|
||||||
await page.waitForTimeout(2000);
|
await page.waitForTimeout(2000);
|
||||||
|
|
||||||
await page.getByTestId("float-input").fill("1.0");
|
await page.getByTestId("float-input").fill("1.0");
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ test("erase button should clear the chat messages", async ({ page }) => {
|
||||||
.getByTestId("popover-anchor-input-api_key")
|
.getByTestId("popover-anchor-input-api_key")
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").click();
|
await page.getByTestId("dropdown_str_model_name").click();
|
||||||
await page.getByTestId("gpt-4o-1-option").click();
|
await page.getByTestId("gpt-4o-1-option").click();
|
||||||
|
|
||||||
await page.waitForTimeout(2000);
|
await page.waitForTimeout(2000);
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ test("should delete rows from table message", async ({ page }) => {
|
||||||
.getByTestId("popover-anchor-input-api_key")
|
.getByTestId("popover-anchor-input-api_key")
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").click();
|
await page.getByTestId("dropdown_str_model_name").click();
|
||||||
await page.getByTestId("gpt-4o-1-option").click();
|
await page.getByTestId("gpt-4o-1-option").click();
|
||||||
|
|
||||||
await page.waitForTimeout(2000);
|
await page.waitForTimeout(2000);
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ test("should copy code from playground modal", async ({ page }) => {
|
||||||
.getByTestId("popover-anchor-input-api_key")
|
.getByTestId("popover-anchor-input-api_key")
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").click();
|
await page.getByTestId("dropdown_str_model_name").click();
|
||||||
await page.getByTestId("gpt-4o-1-option").click();
|
await page.getByTestId("gpt-4o-1-option").click();
|
||||||
|
|
||||||
const elementsChatInput = await page
|
const elementsChatInput = await page
|
||||||
|
|
|
||||||
|
|
@ -39,34 +39,28 @@ test("InputListComponent", async ({ page }) => {
|
||||||
await page.getByTitle("zoom out").click();
|
await page.getByTitle("zoom out").click();
|
||||||
await page.getByTitle("zoom out").click();
|
await page.getByTitle("zoom out").click();
|
||||||
|
|
||||||
await page.getByTestId("input-list-input_urls-0").fill("test test test test");
|
await page.getByTestId("inputlist_str_urls_0").fill("test test test test");
|
||||||
|
|
||||||
await page.getByTestId("input-list-plus-btn_urls-0").click();
|
await page.getByTestId("input-list-plus-btn_urls-0").click();
|
||||||
|
|
||||||
await page.getByTestId("input-list-plus-btn_urls-0").click();
|
await page.getByTestId("input-list-plus-btn_urls-0").click();
|
||||||
|
|
||||||
await page
|
await page
|
||||||
.getByTestId("input-list-input_urls-1")
|
.getByTestId("inputlist_str_urls_1")
|
||||||
.fill("test1 test1 test1 test1");
|
.fill("test1 test1 test1 test1");
|
||||||
|
|
||||||
await page
|
await page
|
||||||
.getByTestId("input-list-input_urls-2")
|
.getByTestId("inputlist_str_urls_2")
|
||||||
.fill("test2 test2 test2 test2");
|
.fill("test2 test2 test2 test2");
|
||||||
|
|
||||||
await page.getByTestId("div-generic-node").click();
|
await page.getByTestId("div-generic-node").click();
|
||||||
await page.getByTestId("more-options-modal").click();
|
await page.getByTestId("more-options-modal").click();
|
||||||
await page.getByTestId("edit-button-modal").click();
|
await page.getByTestId("edit-button-modal").click();
|
||||||
|
|
||||||
const value0 = await page
|
const value0 = await page.getByTestId("inputlist_str_urls_0").inputValue();
|
||||||
.getByTestId("input-list-input-edit_urls-0")
|
const value1 = await page.getByTestId("inputlist_str_urls_1").inputValue();
|
||||||
.inputValue();
|
|
||||||
const value1 = await page
|
|
||||||
.getByTestId("input-list-input-edit_urls-1")
|
|
||||||
.inputValue();
|
|
||||||
|
|
||||||
const value2 = await page
|
const value2 = await page.getByTestId("inputlist_str_urls_2").inputValue();
|
||||||
.getByTestId("input-list-input-edit_urls-2")
|
|
||||||
.inputValue();
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
value0 !== "test test test test" ||
|
value0 !== "test test test test" ||
|
||||||
|
|
@ -94,15 +88,15 @@ test("InputListComponent", async ({ page }) => {
|
||||||
await page.getByTestId("input-list-plus-btn_urls-0").click();
|
await page.getByTestId("input-list-plus-btn_urls-0").click();
|
||||||
await page.getByTestId("input-list-plus-btn_urls-0").click();
|
await page.getByTestId("input-list-plus-btn_urls-0").click();
|
||||||
|
|
||||||
await page.getByTestId("input-list-input_urls-0").fill("test test test test");
|
await page.getByTestId("inputlist_str_urls_0").fill("test test test test");
|
||||||
await page
|
await page
|
||||||
.getByTestId("input-list-input_urls-1")
|
.getByTestId("inputlist_str_urls_1")
|
||||||
.fill("test1 test1 test1 test1");
|
.fill("test1 test1 test1 test1");
|
||||||
await page
|
await page
|
||||||
.getByTestId("input-list-input_urls-2")
|
.getByTestId("inputlist_str_urls_2")
|
||||||
.fill("test2 test2 test2 test2");
|
.fill("test2 test2 test2 test2");
|
||||||
await page
|
await page
|
||||||
.getByTestId("input-list-input_urls-3")
|
.getByTestId("inputlist_str_urls_3")
|
||||||
.fill("test3 test3 test3 test3");
|
.fill("test3 test3 test3 test3");
|
||||||
|
|
||||||
await page.getByTestId("div-generic-node").click();
|
await page.getByTestId("div-generic-node").click();
|
||||||
|
|
@ -110,16 +104,16 @@ test("InputListComponent", async ({ page }) => {
|
||||||
await page.getByTestId("edit-button-modal").click();
|
await page.getByTestId("edit-button-modal").click();
|
||||||
|
|
||||||
const value0Edit = await page
|
const value0Edit = await page
|
||||||
.getByTestId("input-list-input-edit_urls-0")
|
.getByTestId("inputlist_str_edit_urls_0")
|
||||||
.inputValue();
|
.inputValue();
|
||||||
const value1Edit = await page
|
const value1Edit = await page
|
||||||
.getByTestId("input-list-input-edit_urls-1")
|
.getByTestId("inputlist_str_edit_urls_1")
|
||||||
.inputValue();
|
.inputValue();
|
||||||
const value2Edit = await page
|
const value2Edit = await page
|
||||||
.getByTestId("input-list-input-edit_urls-2")
|
.getByTestId("inputlist_str_edit_urls_2")
|
||||||
.inputValue();
|
.inputValue();
|
||||||
const value3Edit = await page
|
const value3Edit = await page
|
||||||
.getByTestId("input-list-input-edit_urls-3")
|
.getByTestId("inputlist_str_edit_urls_3")
|
||||||
.inputValue();
|
.inputValue();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|
|
||||||
|
|
@ -52,21 +52,19 @@ test("IntComponent", async ({ page }) => {
|
||||||
await page.getByTestId("showmax_tokens").click();
|
await page.getByTestId("showmax_tokens").click();
|
||||||
|
|
||||||
await page.getByText("Close").last().click();
|
await page.getByText("Close").last().click();
|
||||||
await page.getByTestId("int-input-max_tokens").click();
|
await page.getByTestId("int_int_max_tokens").click();
|
||||||
await page
|
await page.getByTestId("int_int_max_tokens").fill("1020304050");
|
||||||
.getByTestId("int-input-max_tokens")
|
|
||||||
.fill("123456789123456789123456789");
|
|
||||||
|
|
||||||
let value = await page.getByTestId("int-input-max_tokens").inputValue();
|
let value = await page.getByTestId("int_int_max_tokens").inputValue();
|
||||||
|
|
||||||
if (value != "123456789123456789123456789") {
|
if (value != "1020304050") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
||||||
await page.getByTestId("int-input-max_tokens").click();
|
await page.getByTestId("int_int_max_tokens").click();
|
||||||
await page.getByTestId("int-input-max_tokens").fill("0");
|
await page.getByTestId("int_int_max_tokens").fill("0");
|
||||||
|
|
||||||
value = await page.getByTestId("int-input-max_tokens").inputValue();
|
value = await page.getByTestId("int_int_max_tokens").inputValue();
|
||||||
|
|
||||||
if (value != "0") {
|
if (value != "0") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
|
|
@ -86,16 +84,14 @@ test("IntComponent", async ({ page }) => {
|
||||||
await page.getByTestId("more-options-modal").click();
|
await page.getByTestId("more-options-modal").click();
|
||||||
await page.getByTestId("edit-button-modal").click();
|
await page.getByTestId("edit-button-modal").click();
|
||||||
|
|
||||||
value = await page.getByTestId("edit-int-input-max_tokens").inputValue();
|
value = await page.getByTestId("int_int_edit_max_tokens").inputValue();
|
||||||
|
|
||||||
if (value != "0") {
|
if (value != "0") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
||||||
await page.getByTestId("edit-int-input-max_tokens").click();
|
await page.getByTestId("int_int_edit_max_tokens").click();
|
||||||
await page
|
await page.getByTestId("int_int_edit_max_tokens").fill("60708090");
|
||||||
.getByTestId("edit-int-input-max_tokens")
|
|
||||||
.fill("123456789123456789123456789");
|
|
||||||
|
|
||||||
await page.locator('//*[@id="showmodel_kwargs"]').click();
|
await page.locator('//*[@id="showmodel_kwargs"]').click();
|
||||||
expect(
|
expect(
|
||||||
|
|
@ -167,33 +163,29 @@ test("IntComponent", async ({ page }) => {
|
||||||
await page.getByTestId("more-options-modal").click();
|
await page.getByTestId("more-options-modal").click();
|
||||||
await page.getByTestId("edit-button-modal").click();
|
await page.getByTestId("edit-button-modal").click();
|
||||||
|
|
||||||
await page.locator('//*[@id="showtimeout"]').click();
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="showtimeout"]').isChecked(),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
const valueEditNode = await page
|
const valueEditNode = await page
|
||||||
.getByTestId("edit-int-input-max_tokens")
|
.getByTestId("int_int_max_tokens")
|
||||||
.inputValue();
|
.inputValue();
|
||||||
|
|
||||||
if (valueEditNode != "123456789123456789123456789") {
|
if (valueEditNode != "128000") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
||||||
await page.getByText("Close").last().click();
|
await page.getByText("Close").last().click();
|
||||||
await page.getByTestId("int-input-max_tokens").click();
|
await page.getByTestId("int_int_max_tokens").click();
|
||||||
await page.getByTestId("int-input-max_tokens").fill("3");
|
await page.getByTestId("int_int_max_tokens").fill("3");
|
||||||
|
|
||||||
let value = await page.getByTestId("int-input-max_tokens").inputValue();
|
let value = await page.getByTestId("int_int_max_tokens").inputValue();
|
||||||
|
|
||||||
if (value != "3") {
|
if (value != "3") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
||||||
await page.getByTestId("int-input-max_tokens").click();
|
await page.getByTestId("int_int_max_tokens").click();
|
||||||
await page.getByTestId("int-input-max_tokens").fill("-3");
|
await page.getByTestId("int_int_max_tokens").fill("-3");
|
||||||
|
await page.getByTestId("div-generic-node").click();
|
||||||
|
|
||||||
value = await page.getByTestId("int-input-max_tokens").inputValue();
|
value = await page.getByTestId("int_int_max_tokens").inputValue();
|
||||||
|
|
||||||
if (value != "0") {
|
if (value != "0") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ test("should able to see and interact with logs", async ({ page }) => {
|
||||||
.getByTestId("popover-anchor-input-api_key")
|
.getByTestId("popover-anchor-input-api_key")
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").click();
|
await page.getByTestId("dropdown_str_model_name").click();
|
||||||
await page.getByTestId("gpt-4o-1-option").click();
|
await page.getByTestId("gpt-4o-1-option").click();
|
||||||
|
|
||||||
await page.waitForTimeout(2000);
|
await page.waitForTimeout(2000);
|
||||||
|
|
|
||||||
|
|
@ -28,151 +28,73 @@ test("NestedComponent", async ({ page }) => {
|
||||||
});
|
});
|
||||||
await page.getByTestId("extended-disclosure").click();
|
await page.getByTestId("extended-disclosure").click();
|
||||||
await page.getByPlaceholder("Search").click();
|
await page.getByPlaceholder("Search").click();
|
||||||
await page.getByPlaceholder("Search").fill("pinecone");
|
await page.getByPlaceholder("Search").fill("api request");
|
||||||
|
|
||||||
await page.waitForTimeout(1000);
|
await page.waitForTimeout(1000);
|
||||||
|
|
||||||
await page
|
await page
|
||||||
.getByTestId("vectorstoresPinecone")
|
.getByTestId("dataAPI Request")
|
||||||
.first()
|
.first()
|
||||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||||
await page.click('//*[@id="react-flow-id"]');
|
await page.click('//*[@id="react-flow-id"]');
|
||||||
|
|
||||||
|
await page.getByTitle("fit view").click();
|
||||||
|
await page.getByTitle("zoom out").click();
|
||||||
|
await page.getByTitle("zoom out").click();
|
||||||
|
await page.getByTitle("zoom out").click();
|
||||||
|
|
||||||
|
await page.getByTestId("dict_nesteddict_headers").first().click();
|
||||||
|
await page
|
||||||
|
.getByText("{")
|
||||||
|
.last()
|
||||||
|
.hover()
|
||||||
|
.then(async () => {
|
||||||
|
await page.locator(".json-view--edit").first().click();
|
||||||
|
await page.locator(".json-view--input").first().fill("keytest");
|
||||||
|
await page.locator(".json-view--edit").first().click();
|
||||||
|
|
||||||
|
await page.locator(".json-view--edit").first().click();
|
||||||
|
await page.locator(".json-view--input").first().fill("keytest1");
|
||||||
|
await page.locator(".json-view--edit").first().click();
|
||||||
|
|
||||||
|
await page.locator(".json-view--edit").first().click();
|
||||||
|
await page.locator(".json-view--input").first().fill("keytest2");
|
||||||
|
await page.locator(".json-view--edit").first().click();
|
||||||
|
});
|
||||||
|
|
||||||
|
await page
|
||||||
|
.locator(".json-view--pair")
|
||||||
|
.first()
|
||||||
|
.hover()
|
||||||
|
.then(async () => {
|
||||||
|
await page.locator(".json-view--edit").nth(2).click();
|
||||||
|
await page.locator(".json-view--null").first().fill("proptest1");
|
||||||
|
await page.locator(".json-view--edit").nth(2).click();
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.getByText("Save").last().click();
|
||||||
|
|
||||||
|
await page.getByTestId("div-generic-node").click();
|
||||||
|
|
||||||
await page.getByTestId("more-options-modal").click();
|
await page.getByTestId("more-options-modal").click();
|
||||||
await page.getByTestId("edit-button-modal").click();
|
await page.getByTestId("edit-button-modal").click();
|
||||||
|
|
||||||
// showindex_name
|
await page.getByTestId("dict_nesteddict_edit_headers").first().click();
|
||||||
await page.locator('//*[@id="showindex_name"]').click();
|
|
||||||
|
|
||||||
expect(
|
expect(await page.getByText("keytest", { exact: true }).count()).toBe(1);
|
||||||
await page.locator('//*[@id="showindex_name"]').isChecked(),
|
expect(await page.getByText("keytest1", { exact: true }).count()).toBe(1);
|
||||||
).toBeFalsy();
|
expect(await page.getByText("keytest2", { exact: true }).count()).toBe(1);
|
||||||
|
expect(await page.getByText("proptest1").count()).toBe(1);
|
||||||
|
|
||||||
// shownamespace
|
await page
|
||||||
await page.locator('//*[@id="shownamespace"]').click();
|
.locator(".json-view--pair")
|
||||||
|
.first()
|
||||||
|
.hover()
|
||||||
|
.then(async () => {
|
||||||
|
await page.locator(".json-view--edit").nth(3).click();
|
||||||
|
await page.locator(".json-view--edit").nth(2).click();
|
||||||
|
});
|
||||||
|
|
||||||
expect(
|
expect(await page.getByText("keytest", { exact: true }).count()).toBe(0);
|
||||||
await page.locator('//*[@id="shownamespace"]').isChecked(),
|
expect(await page.getByText("proptest1").count()).toBe(0);
|
||||||
).toBeFalsy();
|
|
||||||
|
|
||||||
// showpinecone_api_key
|
|
||||||
await page.locator('//*[@id="showpinecone_api_key"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="showpinecone_api_key"]').isChecked(),
|
|
||||||
).toBeFalsy();
|
|
||||||
|
|
||||||
// showindex_name
|
|
||||||
await page.locator('//*[@id="showindex_name"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="showindex_name"]').isChecked(),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
// shownamespace
|
|
||||||
await page.locator('//*[@id="shownamespace"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="shownamespace"]').isChecked(),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
// showpinecone_api_key
|
|
||||||
await page.locator('//*[@id="showpinecone_api_key"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="showpinecone_api_key"]').isChecked(),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
// showindex_name
|
|
||||||
await page.locator('//*[@id="showindex_name"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="showindex_name"]').isChecked(),
|
|
||||||
).toBeFalsy();
|
|
||||||
|
|
||||||
// shownamespace
|
|
||||||
await page.locator('//*[@id="shownamespace"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="shownamespace"]').isChecked(),
|
|
||||||
).toBeFalsy();
|
|
||||||
|
|
||||||
// showpinecone_api_key
|
|
||||||
await page.locator('//*[@id="showpinecone_api_key"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="showpinecone_api_key"]').isChecked(),
|
|
||||||
).toBeFalsy();
|
|
||||||
|
|
||||||
// showindex_name
|
|
||||||
await page.locator('//*[@id="showindex_name"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="showindex_name"]').isChecked(),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
// shownamespace
|
|
||||||
await page.locator('//*[@id="shownamespace"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="shownamespace"]').isChecked(),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
// showpinecone_api_key
|
|
||||||
await page.locator('//*[@id="showpinecone_api_key"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="showpinecone_api_key"]').isChecked(),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
// showindex_name
|
|
||||||
await page.locator('//*[@id="showindex_name"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="showindex_name"]').isChecked(),
|
|
||||||
).toBeFalsy();
|
|
||||||
|
|
||||||
// shownamespace
|
|
||||||
await page.locator('//*[@id="shownamespace"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="shownamespace"]').isChecked(),
|
|
||||||
).toBeFalsy();
|
|
||||||
|
|
||||||
// showpinecone_api_key
|
|
||||||
await page.locator('//*[@id="showpinecone_api_key"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="showpinecone_api_key"]').isChecked(),
|
|
||||||
).toBeFalsy();
|
|
||||||
|
|
||||||
// showindex_name
|
|
||||||
await page.locator('//*[@id="showindex_name"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="showindex_name"]').isChecked(),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
// shownamespace
|
|
||||||
await page.locator('//*[@id="shownamespace"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="shownamespace"]').isChecked(),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
// showpinecone_api_key
|
|
||||||
await page.locator('//*[@id="showpinecone_api_key"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="showpinecone_api_key"]').isChecked(),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
//showtext_key
|
|
||||||
await page.locator('//*[@id="showtext_key"]').click();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await page.locator('//*[@id="showtext_key"]').isChecked(),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
await page.getByText("Close").last().click();
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -41,14 +41,14 @@ test("PromptTemplateComponent", async ({ page }) => {
|
||||||
await page.getByTitle("zoom out").click();
|
await page.getByTitle("zoom out").click();
|
||||||
await page.getByTitle("zoom out").click();
|
await page.getByTitle("zoom out").click();
|
||||||
await page.getByTitle("zoom out").click();
|
await page.getByTitle("zoom out").click();
|
||||||
await page.getByTestId("prompt-input-template").click();
|
await page.getByTestId("promptarea_prompt_template").click();
|
||||||
|
|
||||||
await page
|
await page
|
||||||
.getByTestId("modal-prompt-input-template")
|
.getByTestId("modal-promptarea_prompt_template")
|
||||||
.fill("{prompt} example {prompt1}");
|
.fill("{prompt} example {prompt1}");
|
||||||
|
|
||||||
let value = await page
|
let value = await page
|
||||||
.getByTestId("modal-prompt-input-template")
|
.getByTestId("modal-promptarea_prompt_template")
|
||||||
.inputValue();
|
.inputValue();
|
||||||
|
|
||||||
if (value != "{prompt} example {prompt1}") {
|
if (value != "{prompt} example {prompt1}") {
|
||||||
|
|
@ -67,10 +67,10 @@ test("PromptTemplateComponent", async ({ page }) => {
|
||||||
|
|
||||||
await page.getByTestId("genericModalBtnSave").click();
|
await page.getByTestId("genericModalBtnSave").click();
|
||||||
|
|
||||||
await page.getByTestId("div-textarea-prompt").click();
|
await page.getByTestId("textarea_str_prompt").click();
|
||||||
await page.getByTestId("textarea-prompt").fill("prompt_value_!@#!@#");
|
await page.getByTestId("textarea_str_prompt").fill("prompt_value_!@#!@#");
|
||||||
|
|
||||||
value = await page.getByTestId("textarea-prompt").inputValue();
|
value = await page.getByTestId("textarea_str_prompt").inputValue();
|
||||||
|
|
||||||
if (value != "prompt_value_!@#!@#") {
|
if (value != "prompt_value_!@#!@#") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
|
|
@ -79,7 +79,6 @@ test("PromptTemplateComponent", async ({ page }) => {
|
||||||
await page.getByTestId("div-generic-node").click();
|
await page.getByTestId("div-generic-node").click();
|
||||||
|
|
||||||
await page.getByTestId("more-options-modal").click();
|
await page.getByTestId("more-options-modal").click();
|
||||||
|
|
||||||
await page.getByTestId("save-button-modal").click();
|
await page.getByTestId("save-button-modal").click();
|
||||||
|
|
||||||
const replace = await page.getByTestId("replace-button").isVisible();
|
const replace = await page.getByTestId("replace-button").isVisible();
|
||||||
|
|
@ -88,18 +87,12 @@ test("PromptTemplateComponent", async ({ page }) => {
|
||||||
await page.getByTestId("replace-button").click();
|
await page.getByTestId("replace-button").click();
|
||||||
}
|
}
|
||||||
|
|
||||||
await page.getByTestId("div-textarea-prompt1").click();
|
await page.getByTestId("textarea_str_prompt1").click();
|
||||||
await page
|
await page
|
||||||
.getByTestId("textarea-prompt1")
|
.getByTestId("textarea_str_prompt1")
|
||||||
.fill("prompt_name_test_123123!@#!@#");
|
.fill("prompt_name_test_123123!@#!@#");
|
||||||
|
|
||||||
value = await page.getByTestId("textarea-prompt1").inputValue();
|
value = await page.getByTestId("textarea_str_prompt1").inputValue();
|
||||||
|
|
||||||
if (value != "prompt_name_test_123123!@#!@#") {
|
|
||||||
expect(false).toBeTruthy();
|
|
||||||
}
|
|
||||||
|
|
||||||
value = await page.getByTestId("textarea-prompt1").inputValue();
|
|
||||||
|
|
||||||
if (value != "prompt_name_test_123123!@#!@#") {
|
if (value != "prompt_name_test_123123!@#!@#") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
|
|
@ -109,36 +102,38 @@ test("PromptTemplateComponent", async ({ page }) => {
|
||||||
await page.getByTestId("edit-button-modal").click();
|
await page.getByTestId("edit-button-modal").click();
|
||||||
|
|
||||||
value =
|
value =
|
||||||
(await page.locator('//*[@id="textarea-edit-prompt"]').textContent()) ?? "";
|
(await page.locator('//*[@id="textarea_str_edit_prompt"]').textContent()) ??
|
||||||
|
"";
|
||||||
|
|
||||||
if (value != "prompt_value_!@#!@#") {
|
if (value != "prompt_value_!@#!@#") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
||||||
value =
|
value =
|
||||||
(await page.locator('//*[@id="textarea-edit-prompt1"]').textContent()) ??
|
(await page
|
||||||
"";
|
.locator('//*[@id="textarea_str_edit_prompt1"]')
|
||||||
|
.textContent()) ?? "";
|
||||||
|
|
||||||
if (value != "prompt_name_test_123123!@#!@#") {
|
if (value != "prompt_name_test_123123!@#!@#") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
||||||
value = await page
|
value = await page
|
||||||
.locator('//*[@id="prompt-area-edit-template"]')
|
.locator('//*[@id="promptarea_prompt_edit_template"]')
|
||||||
.innerText();
|
.innerText();
|
||||||
|
|
||||||
if (value != "{prompt} example {prompt1}") {
|
if (value != "{prompt} example {prompt1}") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
||||||
await page.locator('//*[@id="textarea-edit-prompt1"]').click();
|
await page.locator('//*[@id="textarea_str_edit_prompt1"]').click();
|
||||||
await page
|
await page
|
||||||
.getByTestId("text-area-modal")
|
.getByTestId("text-area-modal")
|
||||||
.fill("prompt_edit_test_12312312321!@#$");
|
.fill("prompt_edit_test_12312312321!@#$");
|
||||||
|
|
||||||
await page.getByText("Finish Editing", { exact: true }).click();
|
await page.getByText("Finish Editing", { exact: true }).click();
|
||||||
|
|
||||||
await page.locator('//*[@id="textarea-edit-prompt"]').click();
|
await page.locator('//*[@id="textarea_str_edit_prompt"]').click();
|
||||||
await page
|
await page
|
||||||
.getByTestId("text-area-modal")
|
.getByTestId("text-area-modal")
|
||||||
.fill("prompt_edit_test_44444444444!@#$");
|
.fill("prompt_edit_test_44444444444!@#$");
|
||||||
|
|
@ -191,22 +186,24 @@ test("PromptTemplateComponent", async ({ page }) => {
|
||||||
expect(await page.locator('//*[@id="showprompt1"]').isChecked()).toBeTruthy();
|
expect(await page.locator('//*[@id="showprompt1"]').isChecked()).toBeTruthy();
|
||||||
|
|
||||||
value =
|
value =
|
||||||
(await page.locator('//*[@id="textarea-edit-prompt"]').textContent()) ?? "";
|
(await page.locator('//*[@id="textarea_str_edit_prompt"]').textContent()) ??
|
||||||
|
"";
|
||||||
|
|
||||||
if (value != "prompt_edit_test_44444444444!@#$") {
|
if (value != "prompt_edit_test_44444444444!@#$") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
||||||
value =
|
value =
|
||||||
(await page.locator('//*[@id="textarea-edit-prompt1"]').textContent()) ??
|
(await page
|
||||||
"";
|
.locator('//*[@id="textarea_str_edit_prompt1"]')
|
||||||
|
.textContent()) ?? "";
|
||||||
|
|
||||||
if (value != "prompt_edit_test_12312312321!@#$") {
|
if (value != "prompt_edit_test_12312312321!@#$") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
}
|
}
|
||||||
|
|
||||||
value = await page
|
value = await page
|
||||||
.locator('//*[@id="prompt-area-edit-template"]')
|
.locator('//*[@id="promptarea_prompt_edit_template"]')
|
||||||
.innerText();
|
.innerText();
|
||||||
|
|
||||||
if (value != "{prompt} example {prompt1}") {
|
if (value != "{prompt} example {prompt1}") {
|
||||||
|
|
|
||||||
|
|
@ -52,9 +52,9 @@ test("TextAreaModalComponent", async ({ page }) => {
|
||||||
await page.getByTitle("zoom out").click();
|
await page.getByTitle("zoom out").click();
|
||||||
await page.getByTitle("zoom out").click();
|
await page.getByTitle("zoom out").click();
|
||||||
await page.getByTitle("zoom out").click();
|
await page.getByTitle("zoom out").click();
|
||||||
await page.getByTestId("prompt-input-template").click();
|
await page.getByTestId("promptarea_prompt_template").click();
|
||||||
|
|
||||||
await page.getByTestId("modal-prompt-input-template").fill("{text}");
|
await page.getByTestId("modal-promptarea_prompt_template").fill("{text}");
|
||||||
|
|
||||||
let valueBadgeOne = await page.locator('//*[@id="badge0"]').innerText();
|
let valueBadgeOne = await page.locator('//*[@id="badge0"]').innerText();
|
||||||
if (valueBadgeOne != "text") {
|
if (valueBadgeOne != "text") {
|
||||||
|
|
@ -64,12 +64,12 @@ test("TextAreaModalComponent", async ({ page }) => {
|
||||||
await page.getByTestId("genericModalBtnSave").click();
|
await page.getByTestId("genericModalBtnSave").click();
|
||||||
|
|
||||||
await page
|
await page
|
||||||
.getByTestId("textarea-text")
|
.getByTestId("textarea_str_text")
|
||||||
.fill(
|
.fill(
|
||||||
"test test test test test test test test test test test !@#%*)( 123456789101010101010101111111111 !!!!!!!!!!",
|
"test test test test test test test test test test test !@#%*)( 123456789101010101010101111111111 !!!!!!!!!!",
|
||||||
);
|
);
|
||||||
|
|
||||||
await page.getByTestId("textarea-text-ExternalLink").click();
|
await page.getByTestId("textarea_str_text-ExternalLink").click();
|
||||||
|
|
||||||
await page.waitForTimeout(500);
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
|
|
@ -86,7 +86,9 @@ test("TextAreaModalComponent", async ({ page }) => {
|
||||||
|
|
||||||
await page.getByTestId("genericModalBtnSave").click();
|
await page.getByTestId("genericModalBtnSave").click();
|
||||||
|
|
||||||
const valueTextArea = await page.getByTestId("textarea-text").inputValue();
|
const valueTextArea = await page
|
||||||
|
.getByTestId("textarea_str_text")
|
||||||
|
.inputValue();
|
||||||
|
|
||||||
if (valueTextArea != "test123123") {
|
if (valueTextArea != "test123123") {
|
||||||
expect(false).toBeTruthy();
|
expect(false).toBeTruthy();
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ test("TextInputOutputComponent", async ({ page }) => {
|
||||||
.getByTestId("popover-anchor-input-api_key")
|
.getByTestId("popover-anchor-input-api_key")
|
||||||
.fill(process.env.OPENAI_API_KEY ?? "");
|
.fill(process.env.OPENAI_API_KEY ?? "");
|
||||||
|
|
||||||
await page.getByTestId("dropdown-model_name").click();
|
await page.getByTestId("dropdown_str_model_name").click();
|
||||||
await page.getByTestId("gpt-4o-1-option").click();
|
await page.getByTestId("gpt-4o-1-option").click();
|
||||||
|
|
||||||
await page.waitForTimeout(2000);
|
await page.waitForTimeout(2000);
|
||||||
|
|
|
||||||
|
|
@ -70,20 +70,30 @@ test("ToggleComponent", async ({ page }) => {
|
||||||
|
|
||||||
await page.getByTitle("fit view").click();
|
await page.getByTitle("fit view").click();
|
||||||
|
|
||||||
await page.getByTestId("toggle-load_hidden").click();
|
await page.getByTestId("toggle_bool_load_hidden").click();
|
||||||
expect(await page.getByTestId("toggle-load_hidden").isChecked()).toBeTruthy();
|
expect(
|
||||||
|
await page.getByTestId("toggle_bool_load_hidden").isChecked(),
|
||||||
|
).toBeTruthy();
|
||||||
|
|
||||||
await page.getByTestId("toggle-load_hidden").click();
|
await page.getByTestId("toggle_bool_load_hidden").click();
|
||||||
expect(await page.getByTestId("toggle-load_hidden").isChecked()).toBeFalsy();
|
expect(
|
||||||
|
await page.getByTestId("toggle_bool_load_hidden").isChecked(),
|
||||||
|
).toBeFalsy();
|
||||||
|
|
||||||
await page.getByTestId("toggle-load_hidden").click();
|
await page.getByTestId("toggle_bool_load_hidden").click();
|
||||||
expect(await page.getByTestId("toggle-load_hidden").isChecked()).toBeTruthy();
|
expect(
|
||||||
|
await page.getByTestId("toggle_bool_load_hidden").isChecked(),
|
||||||
|
).toBeTruthy();
|
||||||
|
|
||||||
await page.getByTestId("toggle-load_hidden").click();
|
await page.getByTestId("toggle_bool_load_hidden").click();
|
||||||
expect(await page.getByTestId("toggle-load_hidden").isChecked()).toBeFalsy();
|
expect(
|
||||||
|
await page.getByTestId("toggle_bool_load_hidden").isChecked(),
|
||||||
|
).toBeFalsy();
|
||||||
|
|
||||||
await page.getByTestId("toggle-load_hidden").click();
|
await page.getByTestId("toggle_bool_load_hidden").click();
|
||||||
expect(await page.getByTestId("toggle-load_hidden").isChecked()).toBeTruthy();
|
expect(
|
||||||
|
await page.getByTestId("toggle_bool_load_hidden").isChecked(),
|
||||||
|
).toBeTruthy();
|
||||||
|
|
||||||
await page.getByTestId("div-generic-node").click();
|
await page.getByTestId("div-generic-node").click();
|
||||||
|
|
||||||
|
|
@ -99,7 +109,9 @@ test("ToggleComponent", async ({ page }) => {
|
||||||
await page.getByTestId("more-options-modal").click();
|
await page.getByTestId("more-options-modal").click();
|
||||||
await page.getByTestId("edit-button-modal").click();
|
await page.getByTestId("edit-button-modal").click();
|
||||||
|
|
||||||
expect(await page.getByTestId("toggle-load_hidden").isChecked()).toBeTruthy();
|
expect(
|
||||||
|
await page.getByTestId("toggle_bool_load_hidden").isChecked(),
|
||||||
|
).toBeTruthy();
|
||||||
|
|
||||||
await page.locator('//*[@id="showload_hidden"]').click();
|
await page.locator('//*[@id="showload_hidden"]').click();
|
||||||
expect(
|
expect(
|
||||||
|
|
@ -154,7 +166,7 @@ test("ToggleComponent", async ({ page }) => {
|
||||||
|
|
||||||
await page.getByText("Close").last().click();
|
await page.getByText("Close").last().click();
|
||||||
|
|
||||||
const plusButtonLocator = page.getByTestId("toggle-load_hidden");
|
const plusButtonLocator = page.getByTestId("toggle_bool_load_hidden");
|
||||||
const elementCount = await plusButtonLocator?.count();
|
const elementCount = await plusButtonLocator?.count();
|
||||||
if (elementCount === 0) {
|
if (elementCount === 0) {
|
||||||
expect(true).toBeTruthy();
|
expect(true).toBeTruthy();
|
||||||
|
|
@ -170,34 +182,34 @@ test("ToggleComponent", async ({ page }) => {
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
await page.getByTestId("toggle-edit-load_hidden").isChecked(),
|
await page.getByTestId("toggle_bool_load_hidden").isChecked(),
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
|
|
||||||
await page.getByText("Close").last().click();
|
await page.getByText("Close").last().click();
|
||||||
|
|
||||||
await page.getByTestId("toggle-load_hidden").click();
|
await page.getByTestId("toggle_bool_load_hidden").click();
|
||||||
expect(
|
expect(
|
||||||
await page.getByTestId("toggle-load_hidden").isChecked(),
|
await page.getByTestId("toggle_bool_load_hidden").isChecked(),
|
||||||
).toBeFalsy();
|
).toBeFalsy();
|
||||||
|
|
||||||
await page.getByTestId("toggle-load_hidden").click();
|
await page.getByTestId("toggle_bool_load_hidden").click();
|
||||||
expect(
|
expect(
|
||||||
await page.getByTestId("toggle-load_hidden").isChecked(),
|
await page.getByTestId("toggle_bool_load_hidden").isChecked(),
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
|
|
||||||
await page.getByTestId("toggle-load_hidden").click();
|
await page.getByTestId("toggle_bool_load_hidden").click();
|
||||||
expect(
|
expect(
|
||||||
await page.getByTestId("toggle-load_hidden").isChecked(),
|
await page.getByTestId("toggle_bool_load_hidden").isChecked(),
|
||||||
).toBeFalsy();
|
).toBeFalsy();
|
||||||
|
|
||||||
await page.getByTestId("toggle-load_hidden").click();
|
await page.getByTestId("toggle_bool_load_hidden").click();
|
||||||
expect(
|
expect(
|
||||||
await page.getByTestId("toggle-load_hidden").isChecked(),
|
await page.getByTestId("toggle_bool_load_hidden").isChecked(),
|
||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
|
|
||||||
await page.getByTestId("toggle-load_hidden").click();
|
await page.getByTestId("toggle_bool_load_hidden").click();
|
||||||
expect(
|
expect(
|
||||||
await page.getByTestId("toggle-load_hidden").isChecked(),
|
await page.getByTestId("toggle_bool_load_hidden").isChecked(),
|
||||||
).toBeFalsy();
|
).toBeFalsy();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -35,18 +35,14 @@ test("curl_api_generation", async ({ page, context }) => {
|
||||||
.locator("div")
|
.locator("div")
|
||||||
.first()
|
.first()
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
|
||||||
await page
|
await page
|
||||||
.getByRole("textbox", { name: "Type something..." })
|
.getByTestId("popover-anchor-input-openai_api_base-edit")
|
||||||
.first()
|
|
||||||
.click();
|
|
||||||
await page
|
|
||||||
.getByRole("textbox", { name: "Type something..." })
|
|
||||||
.first()
|
|
||||||
.press("Control+a");
|
|
||||||
await page
|
|
||||||
.getByRole("textbox", { name: "Type something..." })
|
|
||||||
.first()
|
.first()
|
||||||
.fill("teste");
|
.fill("teste");
|
||||||
|
|
||||||
await page.getByRole("tab", { name: "cURL" }).click();
|
await page.getByRole("tab", { name: "cURL" }).click();
|
||||||
await page.getByTestId("icon-Copy").click();
|
await page.getByTestId("icon-Copy").click();
|
||||||
const handle2 = await page.evaluateHandle(() =>
|
const handle2 = await page.evaluateHandle(() =>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue