mirror of
https://github.com/langflow-ai/langflow.git
synced 2026-07-24 02:05:11 +08:00
fix: Raw input value leaks into Global Variables dropdown list (#12660)
* Variable input shown in dropdown * added testcases * [autofix.ci] apply automated fixes --------- Co-authored-by: Olayinka Adelakun <olayinkaadelakun@Olayinkas-MacBook-Pro.local> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
@ -2,6 +2,7 @@ import { render, waitFor } from "@testing-library/react";
|
||||
import InputGlobalComponent from "..";
|
||||
|
||||
const mockUseGetGlobalVariables = jest.fn();
|
||||
const mockInputComponent = jest.fn().mockReturnValue(null);
|
||||
|
||||
jest.mock("@/controllers/API/queries/variables", () => ({
|
||||
useGetGlobalVariables: () => mockUseGetGlobalVariables(),
|
||||
@ -32,7 +33,10 @@ jest.mock(
|
||||
"@/components/core/parameterRenderComponent/components/inputComponent",
|
||||
() => ({
|
||||
__esModule: true,
|
||||
default: () => null,
|
||||
default: (props: Record<string, unknown>) => {
|
||||
mockInputComponent(props);
|
||||
return null;
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
@ -104,4 +108,112 @@ describe("InputGlobalComponent", () => {
|
||||
expect(handleOnNewValue).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("options passed to InputComponent", () => {
|
||||
const configuredVariables = [
|
||||
{ name: "MY_API_KEY" },
|
||||
{ name: "ANOTHER_VAR" },
|
||||
];
|
||||
|
||||
beforeEach(() => {
|
||||
mockUseGetGlobalVariables.mockReturnValue({
|
||||
data: configuredVariables,
|
||||
isFetchedAfterMount: true,
|
||||
isFetching: false,
|
||||
isSuccess: true,
|
||||
});
|
||||
});
|
||||
|
||||
const getRenderedOptions = (): string[] =>
|
||||
mockInputComponent.mock.calls[mockInputComponent.mock.calls.length - 1][0]
|
||||
.options as string[];
|
||||
|
||||
it("does not add typed camelCase text to the dropdown", () => {
|
||||
render(
|
||||
<InputGlobalComponent
|
||||
id="test"
|
||||
value="invalidKey"
|
||||
display_name="API Key"
|
||||
handleOnNewValue={handleOnNewValue}
|
||||
load_from_db={false}
|
||||
password={true}
|
||||
editNode={false}
|
||||
disabled={false}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(getRenderedOptions()).not.toContain("invalidKey");
|
||||
expect(getRenderedOptions()).toEqual(["MY_API_KEY", "ANOTHER_VAR"]);
|
||||
});
|
||||
|
||||
it("does not add SCREAMING_SNAKE_CASE typed text to the dropdown", () => {
|
||||
render(
|
||||
<InputGlobalComponent
|
||||
id="test"
|
||||
value="OPENAI_API_KEY"
|
||||
display_name="API Key"
|
||||
handleOnNewValue={handleOnNewValue}
|
||||
load_from_db={false}
|
||||
password={true}
|
||||
editNode={false}
|
||||
disabled={false}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(getRenderedOptions()).not.toContain("OPENAI_API_KEY");
|
||||
expect(getRenderedOptions()).toEqual(["MY_API_KEY", "ANOTHER_VAR"]);
|
||||
});
|
||||
|
||||
it("shows only configured global variables when the field is not a password field", () => {
|
||||
render(
|
||||
<InputGlobalComponent
|
||||
id="test"
|
||||
value="SOME_TYPED_VALUE"
|
||||
display_name="Some Field"
|
||||
handleOnNewValue={handleOnNewValue}
|
||||
load_from_db={false}
|
||||
password={false}
|
||||
editNode={false}
|
||||
disabled={false}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(getRenderedOptions()).toEqual(["MY_API_KEY", "ANOTHER_VAR"]);
|
||||
});
|
||||
|
||||
it("temporarily includes an orphaned variable reference while it is being cleared", () => {
|
||||
render(
|
||||
<InputGlobalComponent
|
||||
id="test"
|
||||
value="DELETED_VAR"
|
||||
display_name="API Key"
|
||||
handleOnNewValue={handleOnNewValue}
|
||||
load_from_db={true}
|
||||
password={false}
|
||||
editNode={false}
|
||||
disabled={false}
|
||||
/>,
|
||||
);
|
||||
|
||||
expect(getRenderedOptions()).toContain("DELETED_VAR");
|
||||
});
|
||||
|
||||
it("does not duplicate a variable that already exists in the configured list", () => {
|
||||
render(
|
||||
<InputGlobalComponent
|
||||
id="test"
|
||||
value="MY_API_KEY"
|
||||
display_name="API Key"
|
||||
handleOnNewValue={handleOnNewValue}
|
||||
load_from_db={true}
|
||||
password={false}
|
||||
editNode={false}
|
||||
disabled={false}
|
||||
/>,
|
||||
);
|
||||
|
||||
const options = getRenderedOptions();
|
||||
expect(options.filter((o) => o === "MY_API_KEY")).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { useEffect } from "react";
|
||||
import { useGetGlobalVariables } from "@/controllers/API/queries/variables";
|
||||
import GeneralDeleteConfirmationModal from "@/shared/components/delete-confirmation-modal";
|
||||
import { looksLikeVariableName } from "../../../../../utils/reactflowUtils";
|
||||
import { cn } from "../../../../../utils/utils";
|
||||
import ForwardedIconComponent from "../../../../common/genericIconComponent";
|
||||
import { CommandItem } from "../../../../ui/command";
|
||||
@ -143,14 +142,11 @@ export default function InputGlobalComponent({
|
||||
|
||||
let variableOptions = typedGlobalVariables.map((variable) => variable.name);
|
||||
|
||||
const isEnvVarName =
|
||||
password && currentValue && looksLikeVariableName(currentValue);
|
||||
if (
|
||||
(loadFromDb &&
|
||||
currentValue &&
|
||||
!valueExists &&
|
||||
!variableOptions.includes(currentValue)) ||
|
||||
(isEnvVarName && !variableOptions.includes(currentValue))
|
||||
loadFromDb &&
|
||||
currentValue &&
|
||||
!valueExists &&
|
||||
!variableOptions.includes(currentValue)
|
||||
) {
|
||||
variableOptions = [...variableOptions, currentValue];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user