From 40798c5b5abbc189dff43e63d4bbc6e9704c0d9e Mon Sep 17 00:00:00 2001 From: Cristhian Zanforlin Lousa Date: Fri, 6 Sep 2024 15:30:20 -0300 Subject: [PATCH] refactor: improve readability of several components (#3714) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor to improve readability * refactor to improve readability * refactor to improve readability * refactor to improve readability * refactor to improve readability * refactor to improve readability * refactor to improve readability * refactor to improve readability * ✅ (Simple Agent.spec.ts): update expected count of python words to 2 for accurate test results 📝 (auto-login-off.spec.ts): add a 1-second timeout before checking visibility of a text element to ensure proper rendering and improve test reliability * 📝 (cardComponent/index.tsx): Extract handlePlaygroundClick function to improve code readability and maintainability 📝 (codeAreaComponent/index.tsx): Refactor code to use consistent naming conventions and improve code structure 📝 (rename-label.tsx): Refactor code to use consistent naming conventions and improve code structure 📝 (dictAreaModal/index.tsx): Refactor code to use consistent naming conventions and improve code structure * 🔧 (rename-label.tsx): Refactor RenameLabel component to improve readability and maintainability by restructuring the component logic into separate functions for handling blur, change, and double click events. Split the component rendering logic into separate functions for input and span elements. * update type * [autofix.ci] apply automated fixes --------- Co-authored-by: anovazzi1 Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .../src/components/cardComponent/index.tsx | 52 ++-- .../components/codeAreaComponent/index.tsx | 74 +++-- .../components/dropdownComponent/index.tsx | 240 ++++++++------- .../src/components/floatComponent/index.tsx | 32 +- .../components/inputListComponent/index.tsx | 119 ++++---- .../src/components/intComponent/index.tsx | 59 ++-- .../components/keypairListComponent/index.tsx | 143 ++++----- .../components/multiselectComponent/index.tsx | 273 ++++++++---------- .../src/components/promptComponent/index.tsx | 57 ++-- .../components/textAreaComponent/index.tsx | 210 +++++++------- .../src/components/ui/rename-label.tsx | 96 +++--- .../src/modals/dictAreaModal/index.tsx | 90 +++--- .../tests/end-to-end/auto-login-off.spec.ts | 2 + 13 files changed, 737 insertions(+), 710 deletions(-) diff --git a/src/frontend/src/components/cardComponent/index.tsx b/src/frontend/src/components/cardComponent/index.tsx index 422417d99..e207b8853 100644 --- a/src/frontend/src/components/cardComponent/index.tsx +++ b/src/frontend/src/components/cardComponent/index.tsx @@ -55,6 +55,32 @@ export default function CollectionCardComponent({ const { onDragStart } = useDragStart(data); + const handlePlaygroundClick = (e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + track("Playground Button Clicked", { flowId: data.id }); + setLoadingPlayground(true); + const flow = getFlowById(data.id); + if (flow) { + if (!hasPlayground(flow)) { + setErrorData({ + title: "Error", + list: ["This flow doesn't have a playground."], + }); + setLoadingPlayground(false); + return; + } + setCurrentFlow(flow); + setOpenPlayground(true); + setLoadingPlayground(false); + } else { + setErrorData({ + title: "Error", + list: ["Error getting flow data."], + }); + } + }; + return ( <> { - e.preventDefault(); - e.stopPropagation(); - track("Playground Button Clicked", { flowId: data.id }); - setLoadingPlayground(true); - const flow = getFlowById(data.id); - if (flow) { - if (!hasPlayground(flow)) { - setErrorData({ - title: "Error", - list: ["This flow doesn't have a playground."], - }); - setLoadingPlayground(false); - return; - } - setCurrentFlow(flow); - setOpenPlayground(true); - setLoadingPlayground(false); - } else { - setErrorData({ - title: "Error", - list: ["Error getting flow data."], - }); - } - }} + onClick={handlePlaygroundClick} > {!loadingPlayground ? ( { - if (disabled && myValue !== "") { - setMyValue(""); + if (disabled && componentValue !== "") { + setComponentValue(""); onChange("", undefined, true); } }, [disabled]); useEffect(() => { - setMyValue(typeof value == "string" ? value : JSON.stringify(value)); + setComponentValue(typeof value == "string" ? value : JSON.stringify(value)); }, [value]); + const handleValueChange = (newValue) => { + onChange(newValue); + }; + + const renderInputText = () => ( + + {value !== "" ? value : "Type something..."} + + ); + + const renderExternalLinkIcon = () => { + if (editNode) return null; + + return ( + + ); + }; + return ( -
+
{ - setMyValue(value); - onChange(value); - }} + setValue={handleValueChange} >
- - {myValue !== "" ? myValue : "Type something..."} - - {!editNode && ( - - )} + {renderInputText()} + {renderExternalLinkIcon()}
diff --git a/src/frontend/src/components/dropdownComponent/index.tsx b/src/frontend/src/components/dropdownComponent/index.tsx index f930d18d1..aa1ee20d1 100644 --- a/src/frontend/src/components/dropdownComponent/index.tsx +++ b/src/frontend/src/components/dropdownComponent/index.tsx @@ -69,131 +69,125 @@ export default function Dropdown({ } }, [open]); - return ( - <> - {Object.keys(options ?? [])?.length > 0 || combobox ? ( - <> - {} : setOpen}> - {children ? ( - {children} - ) : ( - - + + ); - - - - )} - - -
- - -
- - No values found. - - {filteredOptions?.map((option, id) => ( - -
- { - onSelect(currentValue); - setOpen(false); - }} - className="items-center overflow-hidden truncate" - data-testid={`${option}-${id ?? ""}-option`} - > - {customValue === option ? ( - - Text:  - - ) : ( - <> - )} - {option} - - -
-
- ))} -
-
-
-
-
- + const renderSearchInput = () => ( +
+ + +
+ ); + + const renderOptionsList = () => ( + + No values found. + + {filteredOptions?.map((option, index) => ( + +
+ { + onSelect(currentValue); + setOpen(false); + }} + className="items-center overflow-hidden truncate" + data-testid={`${option}-${index}-option`} + > + {customValue === option && ( + Text:  + )} + {option} + + +
+
+ ))} +
+
+ ); + + const renderPopoverContent = () => ( + + + {renderSearchInput()} + {renderOptionsList()} + + + ); + + if (Object.keys(options).length === 0 && !combobox) { + return isLoading ? ( +
+ Loading... +
+ ) : ( +
+ + No parameters are available for display. + +
+ ); + } + + return ( + {} : setOpen}> + {children ? ( + {children} ) : ( - <> - {(!isLoading && ( -
- - No parameters are available for display. - -
- )) || ( -
- Loading... -
- )} - + renderTriggerButton() )} - + {renderPopoverContent()} +
); } diff --git a/src/frontend/src/components/floatComponent/index.tsx b/src/frontend/src/components/floatComponent/index.tsx index 979f55aba..1a316a9e1 100644 --- a/src/frontend/src/components/floatComponent/index.tsx +++ b/src/frontend/src/components/floatComponent/index.tsx @@ -20,6 +20,19 @@ export default function FloatComponent({ } }, [disabled]); + const handleInput = (event: React.ChangeEvent) => { + const inputValue = Number(event.target.value); + if (inputValue < min) { + event.target.value = min.toString(); + } else if (inputValue > max) { + event.target.value = max.toString(); + } + }; + + const handleChange = (event) => { + onChange(event.target.value); + }; + return (
) => { - if (Number(event.target.value) < min) { - event.target.value = min.toString(); - } - if (Number(event.target.value) > max) { - event.target.value = max.toString(); - } - }} max={max} value={value ?? ""} disabled={disabled} className={editNode ? "input-edit-node" : ""} - placeholder={`Enter a value`} - onChange={(event) => { - onChange(event.target.value); - }} - onKeyDown={(e) => { - handleKeyDown(e, value, ""); - }} + placeholder="Enter a value" + onInput={handleInput} + onChange={handleChange} + onKeyDown={(e) => handleKeyDown(e, value, "")} />
); diff --git a/src/frontend/src/components/inputListComponent/index.tsx b/src/frontend/src/components/inputListComponent/index.tsx index ddf75c1c1..dce65cb15 100644 --- a/src/frontend/src/components/inputListComponent/index.tsx +++ b/src/frontend/src/components/inputListComponent/index.tsx @@ -29,6 +29,36 @@ export default function InputListComponent({ if (!value?.length) value = [""]; + const handleInputChange = (index, newValue) => { + const newInputList = _.cloneDeep(value); + newInputList[index] = newValue; + onChange(newInputList); + }; + + const addNewInput = (e) => { + e.preventDefault(); + const newInputList = _.cloneDeep(value); + newInputList.push(""); + onChange(newInputList); + }; + + const removeInput = (index, e) => { + e.preventDefault(); + const newInputList = _.cloneDeep(value); + newInputList.splice(index, 1); + onChange(newInputList); + }; + + const getButtonClassName = () => + classNames( + disabled || playgroundDisabled + ? "cursor-not-allowed text-muted-foreground" + : "text-primary hover:text-accent-foreground", + ); + + const getTestId = (type, index) => + `input-list-${type}-btn${editNode ? "-edit" : ""}_${componentName}-${index}`; + return (
- {value.map((singleValue, idx) => { - return ( -
- { - let newInputList = _.cloneDeep(value); - newInputList[idx] = event.target.value; - onChange(newInputList); - }} - data-testid={`${id}_` + idx} + {value.map((singleValue, index) => ( +
+ handleInputChange(index, event.target.value)} + data-testid={`${id}_${index}`} + /> + - ) : ( - - )} -
- ); - })} + +
+ ))}
); } diff --git a/src/frontend/src/components/intComponent/index.tsx b/src/frontend/src/components/intComponent/index.tsx index 10bcad7bf..9ebd54121 100644 --- a/src/frontend/src/components/intComponent/index.tsx +++ b/src/frontend/src/components/intComponent/index.tsx @@ -38,36 +38,57 @@ export default function IntComponent({ onChange(Number(e.target.value)); }; + const getStepValue = () => { + return (Number.isInteger(rangeSpec?.step) ? rangeSpec.step : 1) ?? 1; + }; + + const getMinValue = () => { + return rangeSpec?.min ?? min; + }; + + const getMaxValue = () => { + return rangeSpec?.max ?? undefined; + }; + + const getInputClassName = () => { + return cn( + editNode ? "input-edit-node" : "", + "nopan nodelete nodrag noflow primary-input", + ); + }; + + const handleNumberChange = (newValue) => { + onChange(Number(newValue)); + }; + + const handleInputChange = (event) => { + const inputValue = Number(event.target.value); + if (inputValue < getMinValue()) { + event.target.value = getMinValue().toString(); + } + }; + + const inputRef = useRef(null); + return (
{ - onChange(Number(value)); - }} + step={getStepValue()} + min={getMinValue()} + max={getMaxValue()} + onChange={handleNumberChange} value={value ?? ""} > { - handleKeyDown(event, value, ""); - }} - onInput={(event: React.ChangeEvent) => { - if (Number(event.target.value) < min) { - event.target.value = min.toString(); - } - }} + onKeyDown={(event) => handleKeyDown(event, value, "")} + onInput={handleInputChange} disabled={disabled} placeholder={editNode ? "Integer number" : "Type an integer number"} data-testid={id} - ref={ref} + ref={inputRef} /> diff --git a/src/frontend/src/components/keypairListComponent/index.tsx b/src/frontend/src/components/keypairListComponent/index.tsx index 118097f5e..a77e7107d 100644 --- a/src/frontend/src/components/keypairListComponent/index.tsx +++ b/src/frontend/src/components/keypairListComponent/index.tsx @@ -7,7 +7,6 @@ import { hasDuplicateKeys, } from "@/utils/reactflowUtils"; import { cloneDeep } from "lodash"; -import { classNames } from "../../utils/utils"; import IconComponent from "../genericIconComponent"; import { Input } from "../ui/input"; @@ -27,7 +26,7 @@ export default function KeypairListComponent({ const [duplicateKey, setDuplicateKey] = useState(false); - const myValue = + const values = Object.keys(value || {})?.length === 0 || !value ? [{ "": "" }] : convertObjToArray(value, "dict"); @@ -43,120 +42,100 @@ export default function KeypairListComponent({ }; const handleChangeKey = (event, idx) => { - const oldKey = Object.keys(myValue[idx])[0]; - const updatedObj = { [event.target.value]: myValue[idx][oldKey] }; + const oldKey = Object.keys(values[idx])[0]; + const updatedObj = { [event.target.value]: values[idx][oldKey] }; - const newValue = cloneDeep(myValue); + const newValue = cloneDeep(values); newValue[idx] = updatedObj; handleNewValue(newValue); }; const handleChangeValue = (event, idx) => { - const key = Object.keys(myValue[idx])[0]; + const key = Object.keys(values[idx])[0]; const updatedObj = { [key]: event.target.value }; - const newValue = cloneDeep(myValue); + const newValue = cloneDeep(values); newValue[idx] = updatedObj; handleNewValue(newValue); }; + const addNewKeyValuePair = () => { + const newValues = cloneDeep(values); + newValues.push({ "": "" }); + onChange(newValues); + }; + + const removeKeyValuePair = (index) => { + const newValues = cloneDeep(values); + newValues.splice(index, 1); + onChange(newValues); + }; + + const getInputClassName = (isEditNode, isDuplicateKey) => { + return `${isEditNode ? "input-edit-node" : ""} ${isDuplicateKey ? "input-invalid" : ""}`.trim(); + }; + + const getTestId = (prefix, index) => + `${editNode ? "editNode" : ""}${prefix}${index}`; + return (
1 && editNode ? "mx-2 my-1" : "", - "flex h-full flex-col gap-3", - )} + className={`flex h-full flex-col gap-3 ${values?.length > 1 && editNode ? "mx-2 my-1" : ""}`} > - {myValue?.map((obj, index) => { - return Object.keys(obj).map((key, idx) => { - return ( -
- handleChangeKey(event, index)} - /> + {values?.map((obj, index) => + Object.keys(obj).map((key, idx) => ( +
+ handleChangeKey(event, index)} + /> - handleChangeValue(event, index)} - /> + handleChangeValue(event, index)} + /> - {isList && index === myValue.length - 1 ? ( + {isList && + (index === values.length - 1 ? ( - ) : isList ? ( + ) : ( - ) : ( - "" - )} -
- ); - }); - })} + ))} +
+ )), + )}
); } diff --git a/src/frontend/src/components/multiselectComponent/index.tsx b/src/frontend/src/components/multiselectComponent/index.tsx index d432d6a24..59572469b 100644 --- a/src/frontend/src/components/multiselectComponent/index.tsx +++ b/src/frontend/src/components/multiselectComponent/index.tsx @@ -92,156 +92,139 @@ export default function MultiselectComponent({ } }, [open]); - return ( - <> - {Object.keys(options ?? [])?.length > 0 || combobox ? ( - <> - {} : setOpen}> - {children ? ( - {children} - ) : ( - - + + ); + + const renderSearchInput = () => ( +
+ + { + setSearchValue(event.target.value); + }} + placeholder="Search options..." + className="flex h-9 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50" + /> + +
+ ); + + const renderOptionsList = () => ( + + No values found. + + {filteredOptions.map((option, index) => ( + +
+ + {(customValues.includes(option) || searchValue === option) && ( + Text:  + )} + {option} + - - {value && - value.length > 0 && - options.find((option) => value.includes(option)) - ? value.join(", ") - : "Choose an option..."} - + /> + +
+
+ ))} +
+
+ ); - - - - )} - { - event.preventDefault(); - }} - side="bottom" - avoidCollisions={!!children} - className="noflow nowheel nopan nodelete nodrag p-0" - style={ - children - ? {} - : { minWidth: refButton?.current?.clientWidth ?? "200px" } - } - > - -
- - { - setSearchValue(event.target.value); - searchRoleByTerm(event.target.value); - }} - placeholder="Search options..." - className="flex h-9 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50" - /> - -
+ if (Object.keys(options).length === 0 && !combobox) { + return isLoading ? ( +
+ Loading... +
+ ) : ( +
+ + No parameters are available for display. + +
+ ); + } - - No values found. - - {filteredOptions?.map((option, id) => ( - -
- { - if (value.includes(currentValue)) { - onSelect( - value.filter((v) => v !== currentValue), - ); - } else { - onSelect([...value, currentValue]); - } - }} - className="items-center overflow-hidden truncate" - data-testid={`${option}-${id ?? ""}-option`} - > - {customValues.includes(option) || - searchValue === option ? ( - - Text:  - - ) : ( - <> - )} - {option} - - -
-
- ))} -
-
-
-
-
- + return ( + {} : setOpen}> + {children ? ( + {children} ) : ( - <> - {(!isLoading && ( -
- - No parameters are available for display. - -
- )) || ( -
- Loading... -
- )} - + renderDropdownTrigger() )} - + event.preventDefault()} + side="bottom" + avoidCollisions={!!children} + className="noflow nowheel nopan nodelete nodrag p-0" + style={ + children + ? {} + : { minWidth: refButton?.current?.clientWidth ?? "200px" } + } + > + + {renderSearchInput()} + {renderOptionsList()} + + +
); } diff --git a/src/frontend/src/components/promptComponent/index.tsx b/src/frontend/src/components/promptComponent/index.tsx index 3d3ed8084..9d577ed1e 100644 --- a/src/frontend/src/components/promptComponent/index.tsx +++ b/src/frontend/src/components/promptComponent/index.tsx @@ -1,6 +1,7 @@ import PromptModal from "@/modals/promptModal"; import { useEffect } from "react"; import { PromptAreaComponentType } from "../../types/components"; +import { cn } from "../../utils/utils"; import IconComponent from "../genericIconComponent"; import { Button } from "../ui/button"; @@ -21,8 +22,38 @@ export default function PromptAreaComponent({ } }, [disabled]); + const renderPromptText = () => ( + + {value !== "" ? value : "Type your prompt here..."} + + ); + + const renderExternalLinkIcon = () => { + if (editNode) return null; + + return ( + + ); + }; + return ( -
+
diff --git a/src/frontend/src/components/textAreaComponent/index.tsx b/src/frontend/src/components/textAreaComponent/index.tsx index 9999d624d..b4e749753 100644 --- a/src/frontend/src/components/textAreaComponent/index.tsx +++ b/src/frontend/src/components/textAreaComponent/index.tsx @@ -22,107 +22,117 @@ export default function TextAreaComponent({ } }, [disabled]); - return ( -
-
-