feat: add customization components (#7419)

*  (webhookFieldComponent): Add support for ENABLE_DATASTAX_LANGFLOW feature flag to conditionally show generate token button
🐛 (use-get-config): Set default value for webhook polling interval if not provided in data
♻️ (custom-secret-key-modal-button): Refactor to pass modal props as a separate object to improve readability and maintainability
🔧 (use-generate-token): Add new file for generating token function
🔧 (secretKeyModal): Refactor to use generate token function based on ENABLE_DATASTAX_LANGFLOW flag and separate modal props into a dedicated interface

*  (constants.ts): add default polling interval and timeout constants for better code readability and maintainability
♻️ (use-get-config.ts): refactor to use the newly added default constants for polling interval and timeout to improve code consistency and reduce duplication

* 🐛 (typescript_test.yml): update the maximum shard count calculation to be 25 instead of 10 to improve test distribution and efficiency

* ⚙️ (typescript_test.yml): adjust optimal shard count calculation to ensure a maximum of 10 shards for test execution
♻️ (index.tsx): refactor modalConfigProps assignment to handle cases where modalProps is null or undefined

---------

Co-authored-by: Mike Fortman <michael.fortman@datastax.com>
This commit is contained in:
Cristhian Zanforlin Lousa 2025-04-03 15:56:46 -03:00 committed by GitHub
commit f4a07fac69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 83 additions and 23 deletions

View file

@ -1,7 +1,8 @@
import { AuthContext } from "@/contexts/authContext";
import { useGetBuildsMutation } from "@/controllers/API/queries/_builds/use-get-builds-polling-mutation";
import SecretKeyModalButton from "@/customization/components/custom-secret-key-modal-button";
import useFlowStore from "@/stores/flowStore";
import { ENABLE_DATASTAX_LANGFLOW } from "@/customization/feature-flags";
import { getModalPropsApiKey } from "@/customization/utils/get-modal-props";
import { useContext, useEffect, useRef, useState } from "react";
import { InputProps, TextAreaComponentType } from "../../types";
import CopyFieldAreaComponent from "../copyFieldAreaComponent";
@ -19,14 +20,21 @@ export default function WebhookFieldComponent({
const [userId, setUserId] = useState("");
const { mutate: getBuildsMutation } = useGetBuildsMutation();
const hasInitialized = useRef(false);
const modalProps = getModalPropsApiKey();
const isBackendUrl = nodeInformationMetadata?.variableName === "endpoint";
const isCurlWebhook = nodeInformationMetadata?.variableName === "curl";
const isAuth = nodeInformationMetadata?.isAuth;
const showGenerateToken = isBackendUrl && !editNode && !isAuth;
const showGenerateToken =
(isBackendUrl && !editNode && !isAuth) ||
(ENABLE_DATASTAX_LANGFLOW && !editNode);
useEffect(() => {
if (!editNode && isBackendUrl && !hasInitialized.current) {
const getBuilds =
(!editNode && isBackendUrl && !hasInitialized.current) ||
(ENABLE_DATASTAX_LANGFLOW && !editNode);
if (getBuilds) {
hasInitialized.current = true;
getBuildsMutation({
flowId: nodeInformationMetadata?.flowId!,
@ -69,7 +77,7 @@ export default function WebhookFieldComponent({
{showGenerateToken && (
<div>
<SecretKeyModalButton userId={userId} />
<SecretKeyModalButton userId={userId} modalProps={modalProps} />
</div>
)}
</div>

View file

@ -1062,3 +1062,6 @@ export const OPENAI_VOICES = [
{ name: "shimmer", value: "shimmer" },
{ name: "verse", value: "verse" },
];
export const DEFAULT_POLLING_INTERVAL = 5000;
export const DEFAULT_TIMEOUT = 30000;

View file

@ -1,3 +1,7 @@
import {
DEFAULT_POLLING_INTERVAL,
DEFAULT_TIMEOUT,
} from "@/constants/constants";
import { EventDeliveryType } from "@/constants/enums";
import useFlowsManagerStore from "@/stores/flowsManagerStore";
import { useUtilityStore } from "@/stores/utilityStore";
@ -44,7 +48,7 @@ export const useGetConfig: useQueryFunctionType<undefined, ConfigResponse> = (
if (data) {
const timeoutInMilliseconds = data.frontend_timeout
? data.frontend_timeout * 1000
: 30000;
: DEFAULT_TIMEOUT;
axios.defaults.baseURL = "";
axios.defaults.timeout = timeoutInMilliseconds;
setAutoSaving(data.auto_saving);
@ -52,7 +56,9 @@ export const useGetConfig: useQueryFunctionType<undefined, ConfigResponse> = (
setHealthCheckMaxRetries(data.health_check_max_retries);
setMaxFileSizeUpload(data.max_file_size_upload);
setFeatureFlags(data.feature_flags);
setWebhookPollingInterval(data.webhook_polling_interval);
setWebhookPollingInterval(
data.webhook_polling_interval ?? DEFAULT_POLLING_INTERVAL,
);
}
return data;
};

View file

@ -2,11 +2,11 @@ import { getModalPropsApiKey } from "@/pages/SettingsPage/pages/ApiKeysPage/help
export const SecretKeyModalButton = ({
userId,
modalProps,
}: {
userId: string;
modalProps;
}): JSX.Element => {
const modalProps = getModalPropsApiKey();
return <></>;
};

View file

@ -0,0 +1,7 @@
export const useGenerateToken = (): any => {
const tokenFunction = (() => {
return "token";
}) as any;
tokenFunction.token = "token";
return tokenFunction;
};

View file

@ -1,7 +1,6 @@
import * as Form from "@radix-ui/react-form";
import { Label } from "@radix-ui/react-form";
import { ENABLE_DATASTAX_LANGFLOW } from "@/customization/feature-flags";
import { useGenerateToken } from "@/customization/hooks/use-generate-token";
import { useEffect, useRef, useState } from "react";
import { Input } from "../../components/ui/input";
import { COPIED_NOTICE_ALERT } from "../../constants/alerts_constants";
import { createApiKey } from "../../controllers/API";
import useAlertStore from "../../stores/alertStore";
@ -11,9 +10,21 @@ import { ContentRenderKey } from "./components/content-render";
import { FormKeyRender } from "./components/form-key-render";
import { HeaderRender } from "./components/header-render";
interface ModalProps {
generatedKeyMessage?: React.ReactNode;
// Add this interface for the modal props
interface ModalConfigProps {
title?: string;
description?: React.ReactNode;
inputLabel?: React.ReactNode;
inputPlaceholder?: string;
buttonText?: string;
generatedKeyMessage?: React.ReactNode;
showIcon?: boolean;
}
interface SecretKeyModalProps {
userId?: string;
size?: string;
modalProps?: ModalConfigProps;
}
export default function SecretKeyModal({
@ -21,7 +32,7 @@ export default function SecretKeyModal({
data,
onCloseModal,
modalProps,
}: ApiKeyType & { modalProps?: ModalProps }) {
}: ApiKeyType & { modalProps: SecretKeyModalProps }) {
const [open, setOpen] = useState(false);
const [apiKeyName, setApiKeyName] = useState(data?.apikeyname ?? "");
const [apiKeyValue, setApiKeyValue] = useState("");
@ -29,6 +40,8 @@ export default function SecretKeyModal({
const [textCopied, setTextCopied] = useState(true);
const setSuccessData = useAlertStore((state) => state.setSuccessData);
const inputRef = useRef<HTMLInputElement | null>(null);
const generateToken = useGenerateToken();
const modalConfigProps = modalProps?.modalProps ?? modalProps;
useEffect(() => {
if (open) {
@ -68,14 +81,33 @@ export default function SecretKeyModal({
.catch((err) => {});
}
function handleSubmitForm() {
async function handleSubmitForm() {
if (apiKeyValue) setOpen(false);
if (ENABLE_DATASTAX_LANGFLOW) {
handleDataStaxKey();
} else {
handleOSSKey();
}
}
const handleDataStaxKey = async () => {
try {
const { token } = await generateToken();
setApiKeyValue(token);
setRenderKey(true);
} catch (error) {
console.error("Error generating token:", error);
}
};
const handleOSSKey = () => {
if (!renderKey) {
setRenderKey(true);
handleAddNewKey();
} else {
setOpen(false);
}
}
};
return (
<BaseModal
@ -89,30 +121,32 @@ export default function SecretKeyModal({
clampDescription={3}
description={
renderKey ? (
<>{modalProps?.generatedKeyMessage}</>
<>{modalConfigProps?.generatedKeyMessage}</>
) : (
<>{modalProps?.description}</>
<>{modalConfigProps?.description}</>
)
}
>
<HeaderRender
title={modalProps?.title}
showIcon={modalProps?.showIcon}
title={modalConfigProps?.title}
showIcon={modalConfigProps?.showIcon}
/>
</BaseModal.Header>
<BaseModal.Content>
{renderKey ? (
<ContentRenderKey
inputLabel={String(modalProps?.inputLabel ?? "")}
inputLabel={String(modalConfigProps?.inputLabel ?? "")}
inputRef={inputRef}
apiKeyValue={apiKeyValue}
handleCopyClick={handleCopyClick}
textCopied={textCopied}
renderKey={renderKey}
/>
) : ENABLE_DATASTAX_LANGFLOW ? (
<></>
) : (
<FormKeyRender
modalProps={modalProps}
modalProps={modalConfigProps}
apiKeyName={apiKeyName}
inputRef={inputRef}
setApiKeyName={setApiKeyName}
@ -120,7 +154,9 @@ export default function SecretKeyModal({
)}
</BaseModal.Content>
<BaseModal.Footer
submit={{ label: renderKey ? "Done" : (modalProps?.buttonText ?? "") }}
submit={{
label: renderKey ? "Done" : (modalConfigProps?.buttonText ?? ""),
}}
/>
</BaseModal>
);