diff --git a/src/frontend/src/CustomNodes/GenericNode/components/OutputComponent/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/OutputComponent/index.tsx index 3b9fbdbd7ade..3bc98ab02c9c 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/OutputComponent/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/OutputComponent/index.tsx @@ -1,12 +1,19 @@ import { ForwardedIconComponent } from "@/components/common/genericIconComponent"; import { Button } from "@/components/ui/button"; import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; + Command, + CommandGroup, + CommandItem, + CommandList, +} from "@/components/ui/command"; + +import { + Popover, + PopoverContentWithoutPortal, + PopoverTrigger, +} from "@/components/ui/popover"; import useFlowStore from "@/stores/flowStore"; +import { useRef } from "react"; import ShadTooltip from "../../../../components/common/shadTooltipComponent"; import { outputComponentType } from "../../../../types/components"; import { cn } from "../../../../utils/utils"; @@ -56,6 +63,7 @@ export default function OutputComponent({ const hasGroupOutputs = outputs?.some?.((output) => output.group_outputs); const isConditionalRouter = nodeType === "ConditionalRouter"; const hasOutputs = outputs.length > 1; + const refButton = useRef(null); const shouldShowDropdown = hasOutputs && !hasLoopOutput && !hasGroupOutputs && !isConditionalRouter; @@ -63,11 +71,13 @@ export default function OutputComponent({ return (
{shouldShowDropdown ? ( - - + + - - - {outputs.map((output) => ( - { - handleSelectOutput && handleSelectOutput(output); - }} - > - - {output.display_name ?? output.name} - - - {output.types.join(", ")} - - - ))} - - + + + + + + {outputs.map((output) => ( + { + handleSelectOutput && handleSelectOutput(output); + }} + value={output.name} + > + + {output.display_name ?? output.name} + + + {output.types.join(", ")} + + + ))} + + + + + ) : ( singleOutput )} diff --git a/src/frontend/src/components/core/dropdownComponent/index.tsx b/src/frontend/src/components/core/dropdownComponent/index.tsx index 880dc06a495b..9f16b73a7972 100644 --- a/src/frontend/src/components/core/dropdownComponent/index.tsx +++ b/src/frontend/src/components/core/dropdownComponent/index.tsx @@ -96,7 +96,7 @@ export default function Dropdown({ const fuse = new Fuse(validOptions, { keys: ["name", "value"] }); const PopoverContentDropdown = children || editNode ? PopoverContent : PopoverContentWithoutPortal; - const { helperText } = baseInputProps; + const { helperText, hasRefreshButton } = baseInputProps; // API and store hooks const postTemplateValue = usePostTemplateValue({ @@ -357,7 +357,7 @@ export default function Dropdown({ ); const renderSearchInput = () => ( -
+
); - const renderCustomOptionDialog = () => ( - - - - - - - - { - setOpenDialog(false); - setOpen(false); - }} - nodeId={nodeId!} - name={name!} - nodeClass={nodeClass!} - /> - - ); - const renderOptionsList = () => ( - - + + {filteredOptions?.length > 0 ? ( filteredOptions?.map((option, index) => (
@@ -452,14 +402,18 @@ export default function Dropdown({ /> )}
0, - "w-full pl-2": !filteredMetadata?.[index]?.icon, + className={cn("flex w-full", { + "pl-2": !filteredMetadata?.[index]?.icon, })} > -
- {option}{" "} +
+ {option} +
+ {filteredMetadata?.[index]?.status && ( -
- {filteredMetadata && filteredMetadata?.length > 0 ? ( -
+ )} + + {filteredMetadata && filteredMetadata?.length > 0 && ( +
{Object.entries( filterMetadataKeys(filteredMetadata?.[index] || {}), ) @@ -495,25 +450,27 @@ export default function Dropdown({ className="mx-1 h-1 w-1 flex-shrink-0 overflow-visible fill-muted-foreground" /> )} -
{`${String(value)} ${key}`}
+
+ {`${String(value)} ${key}`} +
))}
- ) : ( -
- -
)} +
+ +
@@ -527,7 +484,56 @@ export default function Dropdown({ )}
- {dialogInputs && dialogInputs?.fields && renderCustomOptionDialog()} + {dialogInputs && dialogInputs?.fields && ( + + + + + + + + { + setOpenDialog(false); + setOpen(false); + }} + nodeId={nodeId!} + name={name!} + nodeClass={nodeClass!} + /> + + )}
); @@ -540,9 +546,31 @@ export default function Dropdown({ children ? {} : { minWidth: refButton?.current?.clientWidth ?? "200px" } } > - + {options?.length > 0 && renderSearchInput()} {renderOptionsList()} + {!dialogInputs?.fields && hasRefreshButton && ( +
+ + + +
+ )}
); diff --git a/src/frontend/src/components/core/parameterRenderComponent/components/refreshParameterComponent/index.tsx b/src/frontend/src/components/core/parameterRenderComponent/components/refreshParameterComponent/index.tsx deleted file mode 100644 index b7b35c4d2300..000000000000 --- a/src/frontend/src/components/core/parameterRenderComponent/components/refreshParameterComponent/index.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { RefreshButton } from "@/components/ui/refreshButton"; -import { FLEX_VIEW_TYPES } from "@/constants/constants"; -import { usePostTemplateValue } from "@/controllers/API/queries/nodes/use-post-template-value"; -import { mutateTemplate } from "@/CustomNodes/helpers/mutate-template"; -import useAlertStore from "@/stores/alertStore"; -import { APIClassType, InputFieldType } from "@/types/api"; -import { cn } from "@/utils/utils"; -import { InputProps } from "../../types"; - -export function RefreshParameterComponent({ - children, - templateData, - disabled, - nodeClass, - editNode, - handleNodeClass, - nodeId, - name, -}: { - children: React.ReactElement; - templateData: Partial; - disabled: boolean; - nodeClass: APIClassType; - editNode: boolean; - handleNodeClass: (value: any, code?: string, type?: string) => void; - nodeId: string; - name: string; -}) { - const postTemplateValue = usePostTemplateValue({ - parameterId: name, - nodeId: nodeId, - node: nodeClass, - }); - - const setErrorData = useAlertStore((state) => state.setErrorData); - const handleRefreshButtonPress = () => - mutateTemplate( - templateData.value, - nodeId, - nodeClass, - handleNodeClass, - postTemplateValue, - setErrorData, - ); - - const isFlexView = FLEX_VIEW_TYPES.includes(templateData.type ?? ""); - - return ( - (children || - (templateData.refresh_button && !templateData.dialog_inputs)) && ( -
- {children} - {templateData.refresh_button && - !templateData.dialog_inputs?.fields?.data?.node?.template && ( -
- -
- )} -
- ) - ); -} diff --git a/src/frontend/src/components/core/parameterRenderComponent/index.tsx b/src/frontend/src/components/core/parameterRenderComponent/index.tsx index cbd1db2caa1a..ac58be58c94f 100644 --- a/src/frontend/src/components/core/parameterRenderComponent/index.tsx +++ b/src/frontend/src/components/core/parameterRenderComponent/index.tsx @@ -20,7 +20,6 @@ import McpComponent from "./components/mcpComponent"; import MultiselectComponent from "./components/multiselectComponent"; import PromptAreaComponent from "./components/promptComponent"; import QueryComponent from "./components/queryComponent"; -import { RefreshParameterComponent } from "./components/refreshParameterComponent"; import SortableListComponent from "./components/sortableListComponent"; import { StrRenderComponent } from "./components/strRenderComponent"; import ToggleShadComponent from "./components/toggleShadComponent"; @@ -295,20 +294,5 @@ export function ParameterRenderComponent({ } }; - return useMemo( - () => ( - - {renderComponent()} - - ), - [templateData, disabled, nodeId, editNode, nodeClass, name, templateValue], - ); + return renderComponent(); } diff --git a/src/frontend/tests/extended/features/refresh-dropdown-list.spec.ts b/src/frontend/tests/extended/features/refresh-dropdown-list.spec.ts new file mode 100644 index 000000000000..d09d7a77ed4a --- /dev/null +++ b/src/frontend/tests/extended/features/refresh-dropdown-list.spec.ts @@ -0,0 +1,43 @@ +import { test } from "@playwright/test"; +import * as dotenv from "dotenv"; +import path from "path"; +import { awaitBootstrapTest } from "../../utils/await-bootstrap-test"; +import { initialGPTsetup } from "../../utils/initialGPTsetup"; + +test( + "refresh dropdown list", + { tag: ["@release", "@components"] }, + async ({ page }) => { + test.skip( + !process?.env?.ANTHROPIC_API_KEY, + "ANTHROPIC_API_KEY required to run this test", + ); + + if (!process.env.CI) { + dotenv.config({ path: path.resolve(__dirname, "../../.env") }); + } + + await page.goto("/"); + await awaitBootstrapTest(page); + + await page.getByTestId("side_nav_options_all-templates").click(); + await page + .getByRole("heading", { name: "Portfolio Website Code Generator" }) + .click(); + + await page.waitForSelector('[data-testid="fit_view"]', { + timeout: 100000, + }); + + await initialGPTsetup(page, { + skipAdjustScreenView: true, + skipSelectGptModel: true, + }); + + await page.waitForTimeout(3000); + + await page.getByTestId("dropdown_str_model_name").first().click(); + await page.getByTestId("refresh-dropdown-list-model_name").first().click(); + await page.getByText("Loading Options").isVisible({ timeout: 5000 }); + }, +);