feat: Add conditional API key display for auth and auto-login (#8684)

*  Add IS_AUTO_LOGIN constant to handle auto login feature in NodeInputField and TableNodeCellRender components
🔧 Add loginLangflow utility function to facilitate login process in tests

*  (NodeInputField/index.tsx): introduce useIsAutoLogin hook to simplify logic for determining auto login status
 (tableNodeCellRender/index.tsx): introduce useIsAutoLogin hook to simplify logic for determining auto login status
📝 (use-is-auto-login.ts): add custom hook useIsAutoLogin to encapsulate logic for determining auto login status
This commit is contained in:
Cristhian Zanforlin Lousa 2025-06-23 15:53:08 -03:00 committed by GitHub
commit 0895ebbdcb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 131 additions and 6 deletions

View file

@ -6,6 +6,7 @@ import {
CustomParameterLabel,
getCustomParameterTitle,
} from "@/customization/components/custom-parameter";
import { useIsAutoLogin } from "@/hooks/use-is-auto-login";
import useAuthStore from "@/stores/authStore";
import { cn } from "@/utils/utils";
import { useEffect, useMemo, useRef } from "react";
@ -16,6 +17,7 @@ import {
DEFAULT_TOOLSET_PLACEHOLDER,
FLEX_VIEW_TYPES,
ICON_STROKE_WIDTH,
IS_AUTO_LOGIN,
LANGFLOW_SUPPORTED_TYPES,
} from "../../../../constants/constants";
import useFlowStore from "../../../../stores/flowStore";
@ -44,13 +46,17 @@ export default function NodeInputField({
isToolMode = false,
}: NodeInputFieldComponentType): JSX.Element {
const ref = useRef<HTMLDivElement>(null);
const isAuth = useAuthStore((state) => state.isAuthenticated);
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
const isAutoLogin = useIsAutoLogin();
const shouldDisplayApiKey = isAuthenticated && !isAutoLogin;
const { currentFlowId, currentFlowName } = useFlowStore(
useShallow((state) => ({
currentFlowId: state.currentFlow?.id,
currentFlowName: state.currentFlow?.name,
})),
);
const myData = useTypesStore((state) => state.data);
const postTemplateValue = usePostTemplateValue({
node: data.node!,
@ -75,10 +81,10 @@ export default function NodeInputField({
flowId: currentFlowId ?? "",
nodeType: data?.type?.toLowerCase() ?? "",
flowName: currentFlowName ?? "",
isAuth,
isAuth: shouldDisplayApiKey!,
variableName: name,
};
}, [data?.node?.id, isAuth, name]);
}, [data?.node?.id, shouldDisplayApiKey, name]);
useFetchDataOnMount(
data.node!,

View file

@ -2,6 +2,8 @@ import useHandleOnNewValue from "@/CustomNodes/hooks/use-handle-new-value";
import useHandleNodeClass from "@/CustomNodes/hooks/use-handle-node-class";
import { ParameterRenderComponent } from "@/components/core/parameterRenderComponent";
import { NodeInfoType } from "@/components/core/parameterRenderComponent/types";
import { IS_AUTO_LOGIN } from "@/constants/constants";
import { useIsAutoLogin } from "@/hooks/use-is-auto-login";
import useAuthStore from "@/stores/authStore";
import useFlowStore from "@/stores/flowStore";
import { APIClassType } from "@/types/api";
@ -17,7 +19,9 @@ export default function TableNodeCellRender({
const node = useFlowStore((state) => state.getNode(nodeId));
const parameter = node?.data?.node?.template?.[parameterId];
const currentFlow = useFlowStore((state) => state.currentFlow);
const isAuth = useAuthStore((state) => state.isAuthenticated);
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
const isAutoLogin = useIsAutoLogin();
const shouldDisplayApiKey = isAuthenticated && !isAutoLogin;
const disabled = isTargetHandleConnected(
edges,
@ -43,10 +47,10 @@ export default function TableNodeCellRender({
flowId: currentFlow?.id ?? "",
nodeType: node?.data?.type?.toLowerCase() ?? "",
flowName: currentFlow?.name ?? "",
isAuth,
isAuth: shouldDisplayApiKey!,
variableName: parameterId,
};
}, [nodeId, isAuth, parameterId]);
}, [nodeId, shouldDisplayApiKey, parameterId]);
return (
parameter && (

View file

@ -0,0 +1,8 @@
import { IS_AUTO_LOGIN } from "@/constants/constants";
import useAuthStore from "@/stores/authStore";
export const useIsAutoLogin = (): boolean => {
const autoLogin = useAuthStore((state) => state.autoLogin);
const isAutoLoginEnv = IS_AUTO_LOGIN;
return autoLogin ?? isAutoLoginEnv;
};

View file

@ -0,0 +1,99 @@
import { expect, test } from "@playwright/test";
import { adjustScreenView } from "../../utils/adjust-screen-view";
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
import { extractAndCleanCode } from "../../utils/extract-and-clean-code";
import { loginLangflow } from "../../utils/login-langflow";
test(
"user must be able to see api key in webhook component when auto login is disabled",
{ tag: ["@release"] },
async ({ page }) => {
await page.route("**/api/v1/auto_login", (route) => {
route.fulfill({
status: 500,
contentType: "application/json",
body: JSON.stringify({
detail: { auto_login: false },
}),
});
});
await loginLangflow(page);
await awaitBootstrapTest(page, { skipGoto: true });
await page.waitForSelector('[data-testid="blank-flow"]', {
timeout: 30000,
});
await page.getByTestId("blank-flow").click();
await page.getByTestId("sidebar-search-input").click();
await page.getByTestId("sidebar-search-input").fill("webhook");
await page.waitForSelector('[data-testid="dataWebhook"]', {
timeout: 3000,
});
await page
.getByTestId("dataWebhook")
.hover()
.then(async () => {
await page.getByTestId("add-component-button-webhook").click();
});
await adjustScreenView(page);
await page.getByTestId("title-Webhook").click();
await page.getByTestId("edit-button-modal").click();
await page
.getByTestId("button_open_text_area_modal_str_edit_curl_advanced")
.click();
const curl = await page.getByTestId("text-area-modal").inputValue();
expect(curl).toContain("x-api-key");
},
);
test(
"user must be able to not see api key in webhook component when auto login is enabled",
{ tag: ["@release"] },
async ({ page }) => {
await awaitBootstrapTest(page);
await page.waitForSelector('[data-testid="blank-flow"]', {
timeout: 30000,
});
await page.getByTestId("blank-flow").click();
await page.getByTestId("sidebar-search-input").click();
await page.getByTestId("sidebar-search-input").fill("webhook");
await page.waitForSelector('[data-testid="dataWebhook"]', {
timeout: 3000,
});
await page
.getByTestId("dataWebhook")
.hover()
.then(async () => {
await page.getByTestId("add-component-button-webhook").click();
});
await adjustScreenView(page);
await page.getByTestId("title-Webhook").click();
await page.getByTestId("edit-button-modal").click();
await page
.getByTestId("button_open_text_area_modal_str_edit_curl_advanced")
.click();
const curl = await page.getByTestId("text-area-modal").inputValue();
expect(curl).not.toContain("x-api-key");
},
);

View file

@ -0,0 +1,8 @@
import { Page } from "playwright/test";
export const loginLangflow = async (page: Page) => {
await page.goto("/");
await page.getByPlaceholder("Username").fill("langflow");
await page.getByPlaceholder("Password").fill("langflow");
await page.getByRole("button", { name: "Sign In" }).click();
};