Add Types & Refactor Card Components (useHooks) (#2365)

This pull request introduces two improvements:

Type Annotations for Custom Hooks: Enhances code readability and
maintainability by adding type annotations to our custom hooks. This
will improve IDE support and help catch potential errors early in the
development process.

Card Component Refactor (useHooks): Refactors card components to
leverage the useHooks pattern. This improves code organization and
potentially simplifies component logic.

These changes improve the overall codebase quality and make it easier to
understand and maintain.
This commit is contained in:
Gabriel Luiz Freitas Almeida 2024-06-25 17:12:20 -07:00 committed by GitHub
commit 51fd1cca39
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 502 additions and 276 deletions

View file

@ -6,13 +6,14 @@ import {
} from "../../constants/constants";
import useAlertStore from "../../stores/alertStore";
import { ResponseErrorDetailAPI } from "../../types/api";
import { NodeDataType } from "../../types/flow";
const useFetchDataOnMount = (
data,
name,
handleUpdateValues,
setNode,
setIsLoading,
data: NodeDataType,
name: string,
handleUpdateValues: (name: string, data: NodeDataType) => Promise<any>,
setNode: (id: string, callback: (oldNode: any) => any) => void,
setIsLoading: (value: boolean) => void,
) => {
const setErrorData = useAlertStore((state) => state.setErrorData);

View file

@ -5,15 +5,16 @@ import {
} from "../../constants/constants";
import useAlertStore from "../../stores/alertStore";
import { ResponseErrorTypeAPI } from "../../types/api";
import { NodeDataType } from "../../types/flow";
const useHandleOnNewValue = (
data,
name,
takeSnapshot,
handleUpdateValues,
debouncedHandleUpdateValues,
setNode,
setIsLoading,
data: NodeDataType,
name: string,
takeSnapshot: () => void,
handleUpdateValues: (name: string, data: NodeDataType) => Promise<any>,
debouncedHandleUpdateValues: any,
setNode: (id: string, callback: (oldNode: any) => any) => void,
setIsLoading: (value: boolean) => void,
) => {
const setErrorData = useAlertStore((state) => state.setErrorData);

View file

@ -1,11 +1,12 @@
import { cloneDeep } from "lodash";
import { NodeDataType } from "../../types/flow";
const useHandleNodeClass = (
data,
name,
takeSnapshot,
setNode,
updateNodeInternals,
data: NodeDataType,
name: string,
takeSnapshot: () => void,
setNode: (id: string, callback: (oldNode: any) => any) => void,
updateNodeInternals: (id: string) => void,
) => {
const handleNodeClass = (newNodeClass, code, type?: string) => {
if (!data.node) return;

View file

@ -7,7 +7,10 @@ import useAlertStore from "../../stores/alertStore";
import { ResponseErrorDetailAPI } from "../../types/api";
import { handleUpdateValues } from "../../utils/parameterUtils";
const useHandleRefreshButtonPress = (setIsLoading, setNode) => {
const useHandleRefreshButtonPress = (
setIsLoading: (value: boolean) => void,
setNode: (id: string, callback: (oldNode: any) => any) => void,
) => {
const setErrorData = useAlertStore((state) => state.setErrorData);
const handleRefreshButtonPress = async (name, data) => {

View file

@ -1,6 +1,11 @@
import { useEffect } from "react";
import { FlowPoolType } from "../../types/zustand/flow";
const useUpdateValidationStatus = (dataId, flowPool, setValidationStatus) => {
const useUpdateValidationStatus = (
dataId: string,
flowPool: FlowPoolType,
setValidationStatus: (value: any) => void,
) => {
useEffect(() => {
const relevantData =
flowPool[dataId] && flowPool[dataId]?.length > 0

View file

@ -4,7 +4,7 @@ import { isErrorLog } from "../../types/utils/typeCheckingUtils";
const useValidationStatusString = (
validationStatus: VertexBuildTypeAPI | null,
setValidationString,
setValidationString: (value: any) => void,
) => {
useEffect(() => {
if (validationStatus && validationStatus.data?.outputs) {

View file

@ -0,0 +1,19 @@
import { useEffect } from "react";
import { storeComponent } from "../../../types/store";
const useDataEffect = (
data: storeComponent,
setLikedByUser: (value: any) => void,
setLikesCount: (value: any) => void,
setDownloadsCount: (value: any) => void,
) => {
useEffect(() => {
if (data) {
setLikedByUser(data?.liked_by_user ?? false);
setLikesCount(data?.liked_by_count ?? 0);
setDownloadsCount(data?.downloads_count ?? 0);
}
}, [data, data?.liked_by_count, data?.liked_by_user, data?.downloads_count]);
};
export default useDataEffect;

View file

@ -0,0 +1,55 @@
import { useState } from "react";
import { getComponent } from "../../../controllers/API";
import useFlowsManagerStore from "../../../stores/flowsManagerStore";
import { storeComponent } from "../../../types/store";
import cloneFlowWithParent from "../../../utils/storeUtils";
const useInstallComponent = (
data: storeComponent,
name: string,
isStore: boolean,
downloadsCount: number,
setDownloadsCount: (value: any) => void,
setLoading: (value: boolean) => void,
setSuccessData: (value: { title: string }) => void,
setErrorData: (value: { title: string; list: string[] }) => void,
) => {
const addFlow = useFlowsManagerStore((state) => state.addFlow);
const handleInstall = () => {
const temp = downloadsCount;
setDownloadsCount((old) => Number(old) + 1);
setLoading(true);
getComponent(data.id)
.then((res) => {
const newFlow = cloneFlowWithParent(res, res.id, data.is_component);
addFlow(true, newFlow)
.then((id) => {
setSuccessData({
title: `${name} ${isStore ? "Downloaded" : "Installed"} Successfully.`,
});
setLoading(false);
})
.catch((error) => {
setLoading(false);
setErrorData({
title: `Error ${isStore ? "downloading" : "installing"} the ${name}`,
list: [error.response.data.detail],
});
});
})
.catch((err) => {
setLoading(false);
setErrorData({
title: `Error ${isStore ? "downloading" : "installing"} the ${name}`,
list: [err.response.data.detail],
});
setDownloadsCount(temp);
});
};
return { handleInstall };
};
export default useInstallComponent;

View file

@ -0,0 +1,51 @@
import { postLikeComponent } from "../../../controllers/API";
import { storeComponent } from "../../../types/store";
const useLikeComponent = (
data: storeComponent,
name: string,
setLoadingLike: (value: boolean) => void,
likedByUser: boolean | null | undefined,
likesCount: number,
setLikedByUser: (value: any) => void,
setLikesCount: (value: any) => void,
setValidApiKey: (value: boolean) => void,
setErrorData: (value: { title: string; list: string[] }) => void,
) => {
const handleLike = () => {
setLoadingLike(true);
if (likedByUser !== undefined || likedByUser !== null) {
const temp = likedByUser;
const tempNum = likesCount;
setLikedByUser((prev) => !prev);
setLikesCount((prev) => (temp ? prev - 1 : prev + 1));
postLikeComponent(data.id)
.then((response) => {
setLoadingLike(false);
setLikesCount(response.data.likes_count);
setLikedByUser(response.data.liked_by_user);
})
.catch((error) => {
setLoadingLike(false);
setLikesCount(tempNum);
setLikedByUser(temp);
if (error.response.status === 403) {
setValidApiKey(false);
} else {
console.error(error);
setErrorData({
title: `Error liking ${name}.`,
list: [error.response.data.detail],
});
}
});
}
};
return {
handleLike,
};
};
export default useLikeComponent;

View file

@ -0,0 +1,34 @@
import { useCallback } from "react";
import { createRoot } from "react-dom/client";
import useFlowsManagerStore from "../../../stores/flowsManagerStore";
import { storeComponent } from "../../../types/store";
import DragCardComponent from "../components/dragCardComponent";
const useDragStart = (data: storeComponent) => {
const getFlowById = useFlowsManagerStore((state) => state.getFlowById);
const onDragStart = useCallback(
(event) => {
let image = <DragCardComponent data={data} />; // Replace with whatever you want here
const ghost = document.createElement("div");
ghost.style.transform = "translate(-10000px, -10000px)";
ghost.style.position = "absolute";
document.body.appendChild(ghost);
event.dataTransfer.setDragImage(ghost, 0, 0);
const root = createRoot(ghost);
root.render(image);
const flow = getFlowById(data.id);
if (flow) {
event.dataTransfer.setData("flow", JSON.stringify(data));
}
},
[data],
);
return { onDragStart };
};
export default useDragStart;

View file

@ -0,0 +1,27 @@
import { useEffect } from "react";
import { FlowType } from "../../../types/flow";
const usePlaygroundEffect = (
currentFlowId: string,
playground: boolean,
openPlayground: boolean,
currentFlow: FlowType | undefined,
setNodes: (value: any, value2: boolean) => void,
setEdges: (value: any, value2: boolean) => void,
cleanFlowPool: () => void,
) => {
useEffect(() => {
if (currentFlowId && playground) {
if (openPlayground) {
setNodes(currentFlow?.data?.nodes ?? [], true);
setEdges(currentFlow?.data?.edges ?? [], true);
} else {
setNodes([], true);
setEdges([], true);
}
cleanFlowPool();
}
}, [openPlayground]);
};
export default usePlaygroundEffect;

View file

@ -28,6 +28,11 @@ import { Checkbox } from "../ui/checkbox";
import { FormControl, FormField } from "../ui/form";
import Loading from "../ui/loading";
import DragCardComponent from "./components/dragCardComponent";
import useDataEffect from "./hooks/use-data-effect";
import useInstallComponent from "./hooks/use-handle-install";
import useLikeComponent from "./hooks/use-handle-like";
import useDragStart from "./hooks/use-on-drag-start";
import usePlaygroundEffect from "./hooks/use-playground-effect";
import { convertTestName } from "./utils/convert-test-name";
export default function CollectionCardComponent({
@ -59,11 +64,9 @@ export default function CollectionCardComponent({
const isStore = false;
const [loading, setLoading] = useState(false);
const [loadingLike, setLoadingLike] = useState(false);
const [liked_by_user, setLiked_by_user] = useState(
data?.liked_by_user ?? false,
);
const [likes_count, setLikes_count] = useState(data?.liked_by_count ?? 0);
const [downloads_count, setDownloads_count] = useState(
const [likedByUser, setLikedByUser] = useState(data?.liked_by_user ?? false);
const [likesCount, setLikesCount] = useState(data?.liked_by_count ?? 0);
const [downloadsCount, setDownloadsCount] = useState(
data?.downloads_count ?? 0,
);
const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
@ -99,115 +102,45 @@ export default function CollectionCardComponent({
return inputs.length > 0 || outputs.length > 0;
}
useEffect(() => {
if (currentFlowId && playground) {
if (openPlayground) {
setNodes(currentFlow?.data?.nodes ?? [], true);
setEdges(currentFlow?.data?.edges ?? [], true);
} else {
setNodes([], true);
setEdges([], true);
}
cleanFlowPool();
}
}, [openPlayground]);
usePlaygroundEffect(
currentFlowId,
playground!,
openPlayground,
currentFlow,
setNodes,
setEdges,
cleanFlowPool,
);
useEffect(() => {
if (data) {
setLiked_by_user(data?.liked_by_user ?? false);
setLikes_count(data?.liked_by_count ?? 0);
setDownloads_count(data?.downloads_count ?? 0);
}
}, [data, data.liked_by_count, data.liked_by_user, data.downloads_count]);
useDataEffect(data, setLikedByUser, setLikesCount, setDownloadsCount);
function handleInstall() {
const temp = downloads_count;
setDownloads_count((old) => Number(old) + 1);
setLoading(true);
getComponent(data.id)
.then((res) => {
const newFlow = cloneFLowWithParent(res, res.id, data.is_component);
addFlow(true, newFlow)
.then((id) => {
setSuccessData({
title: `${name} ${
isStore ? "Downloaded" : "Installed"
} Successfully.`,
});
setLoading(false);
})
.catch((error) => {
setLoading(false);
setErrorData({
title: `Error ${
isStore ? "downloading" : "installing"
} the ${name}`,
list: [error["response"]["data"]["detail"]],
});
});
})
.catch((err) => {
setLoading(false);
setErrorData({
title: `Error ${isStore ? "downloading" : "installing"} the ${name}`,
list: [err["response"]["data"]["detail"]],
});
setDownloads_count(temp);
});
}
const { handleInstall } = useInstallComponent(
data,
name,
isStore,
downloadsCount,
setDownloadsCount,
setLoading,
setSuccessData,
setErrorData,
);
function handleLike() {
setLoadingLike(true);
if (liked_by_user !== undefined || liked_by_user !== null) {
const temp = liked_by_user;
const tempNum = likes_count;
setLiked_by_user((prev) => !prev);
if (!temp) {
setLikes_count((prev) => Number(prev) + 1);
} else {
setLikes_count((prev) => Number(prev) - 1);
}
postLikeComponent(data.id)
.then((response) => {
setLoadingLike(false);
setLikes_count(response.data.likes_count);
setLiked_by_user(response.data.liked_by_user);
})
.catch((error) => {
setLoadingLike(false);
setLikes_count(tempNum);
setLiked_by_user(temp);
if (error.response.status === 403) {
setValidApiKey(false);
} else {
console.error(error);
setErrorData({
title: `Error liking ${name}.`,
list: [error["response"]["data"]["detail"]],
});
}
});
}
}
const { handleLike } = useLikeComponent(
data,
name,
setLoadingLike,
likedByUser,
likesCount,
setLikedByUser,
setLikesCount,
setValidApiKey,
setErrorData,
);
const isSelectedCard =
selectedFlowsComponentsCards?.includes(data?.id) ?? false;
function onDragStart(event: React.DragEvent<any>) {
let image: JSX.Element = <DragCardComponent data={data} />; // <== whatever you want here
var ghost = document.createElement("div");
ghost.style.transform = "translate(-10000px, -10000px)";
ghost.style.position = "absolute";
document.body.appendChild(ghost);
event.dataTransfer.setDragImage(ghost, 0, 0);
const root = createRoot(ghost);
root.render(image);
const flow = getFlowById(data.id);
if (flow) {
event.dataTransfer.setData("flow", JSON.stringify(data));
}
}
const { onDragStart } = useDragStart(data);
return (
<>
@ -264,7 +197,7 @@ export default function CollectionCardComponent({
<span className="flex items-center gap-1.5 text-xs text-muted-foreground">
<IconComponent name="Heart" className={cn("h-4 w-4")} />
<span data-testid={`likes-${data.name}`}>
{likes_count ?? 0}
{likesCount ?? 0}
</span>
</span>
</ShadTooltip>
@ -275,7 +208,7 @@ export default function CollectionCardComponent({
className="h-4 w-4"
/>
<span data-testid={`downloads-${data.name}`}>
{downloads_count ?? 0}
{downloadsCount ?? 0}
</span>
</span>
</ShadTooltip>
@ -324,20 +257,7 @@ export default function CollectionCardComponent({
)}
</span>
)}
<div className="flex w-full flex-1 flex-wrap gap-2">
{/* {data.tags &&
data.tags.length > 0 &&
data.tags.map((tag, index) => (
<Badge
key={index}
variant="outline"
size="xq"
className="text-muted-foreground"
>
{tag.name}
</Badge>
))} */}
</div>
<div className="flex w-full flex-1 flex-wrap gap-2"></div>
</div>
<CardDescription className="pb-2 pt-2">
@ -457,7 +377,7 @@ export default function CollectionCardComponent({
name="Heart"
className={cn(
"h-5 w-5",
liked_by_user
likedByUser
? "fill-destructive stroke-destructive"
: "",
!authorized ? "text-ring" : "",

View file

@ -9,7 +9,10 @@ import useFlowsManagerStore from "../../../stores/flowsManagerStore";
import { useFolderStore } from "../../../stores/foldersStore";
import { addVersionToDuplicates } from "../../../utils/reactflowUtils";
const useFileDrop = (folderId, folderChangeCallback) => {
const useFileDrop = (
folderId: string,
folderChangeCallback: (folderId: string) => void,
) => {
const setFolderDragging = useFolderStore((state) => state.setFolderDragging);
const setFolderIdDragging = useFolderStore(
(state) => state.setFolderIdDragging,

View file

@ -1,6 +1,9 @@
import { useEffect } from "react";
const useAutoResizeTextArea = (value, inputRef) => {
const useAutoResizeTextArea = (
value: string,
inputRef: React.RefObject<HTMLInputElement>,
) => {
useEffect(() => {
if (inputRef.current && inputRef.current.scrollHeight! !== 0) {
inputRef.current.style!.height = "inherit"; // Reset the height

View file

@ -7,10 +7,10 @@ import {
import useFileUpload from "./use-file-upload";
const useDragAndDrop = (
setIsDragging,
setFiles,
currentFlowId,
setErrorData,
setIsDragging: (value: boolean) => void,
setFiles: (value: any) => void,
currentFlowId: string,
setErrorData: (value: any) => void,
) => {
const dragOver = (e) => {
e.preventDefault();

View file

@ -1,6 +1,9 @@
import { useEffect } from "react";
const useFocusOnUnlock = (lockChat, inputRef) => {
const useFocusOnUnlock = (
lockChat: boolean,
inputRef: React.RefObject<HTMLInputElement>,
) => {
useEffect(() => {
if (!lockChat && inputRef.current) {
inputRef.current.focus();

View file

@ -1,3 +1,4 @@
import { AxiosResponse } from "axios";
import { useEffect } from "react";
import ShortUniqueId from "short-unique-id";
import {
@ -6,9 +7,18 @@ import {
SN_ERROR_TEXT,
} from "../../../../../../constants/constants";
import useAlertStore from "../../../../../../stores/alertStore";
import { UploadFileTypeAPI } from "../../../../../../types/api";
import useFileUpload from "./use-file-upload";
const useUpload = (uploadFile, currentFlowId, setFiles, lockChat) => {
const useUpload = (
uploadFile: (
file: File,
id: string,
) => Promise<AxiosResponse<UploadFileTypeAPI>>,
currentFlowId: string,
setFiles: any,
lockChat: boolean,
) => {
const setErrorData = useAlertStore((state) => state.setErrorData);
useEffect(() => {
const handlePaste = (event: ClipboardEvent): void => {

View file

@ -2,9 +2,10 @@ import { ColDef, ValueGetterParams } from "ag-grid-community";
import { useMemo } from "react";
import TableNodeCellRender from "../../../components/tableComponent/components/tableNodeCellRender";
import TableToggleCellRender from "../../../components/tableComponent/components/tableToggleCellRender";
import { NodeDataType } from "../../../types/flow";
const useColumnDefs = (
myData: any,
myData: NodeDataType,
handleOnNewValue: (newValue: any, name: string) => void,
handleOnChangeDb: (value: boolean, key: string) => void,
changeAdvanced: (n: string) => void,

View file

@ -1,14 +1,12 @@
import { useMemo } from "react";
import { LANGFLOW_SUPPORTED_TYPES } from "../../../constants/constants";
import { TemplateVariableType } from "../../../types/api";
import { NodeDataType } from "../../../types/flow";
const useRowData = (myData, open) => {
const useRowData = (myData: NodeDataType, open: boolean) => {
const rowData = useMemo(() => {
return Object.keys(myData.node!.template)
.filter((key: string) => {
const templateParam = myData.node!.template[
key
] as TemplateVariableType;
const templateParam = myData.node!.template[key] as any;
return (
key.charAt(0) !== "_" &&
templateParam.show &&
@ -20,9 +18,7 @@ const useRowData = (myData, open) => {
);
})
.map((key: string) => {
const templateParam = myData.node!.template[
key
] as TemplateVariableType;
const templateParam = myData.node!.template[key] as any;
return {
...templateParam,
key: key,

View file

@ -16,13 +16,11 @@ const EditNodeModal = forwardRef(
nodeLength,
open,
setOpen,
// setOpenWDoubleClick,
data,
}: {
nodeLength: number;
open: boolean;
setOpen: (open: boolean) => void;
// setOpenWDoubleClick: (open: boolean) => void;
data: NodeDataType;
},
ref,

View file

@ -0,0 +1,58 @@
import React from "react";
import { Link, useNavigate } from "react-router-dom";
import CollectionCardComponent from "../../../../../../components/cardComponent";
import IconComponent from "../../../../../../components/genericIconComponent";
import { Button } from "../../../../../../components/ui/button";
const CollectionCard = ({ item, type, isLoading, control }) => {
const navigate = useNavigate();
const isComponent = item.is_component ?? false;
const editFlowLink = `/flow/${item.id}`;
const editFlowButtonTestId = `edit-flow-button-${item.id}`;
const handleClick = () => {
if (!isComponent) {
navigate(editFlowLink);
}
};
const renderButton = () => {
if (!isComponent) {
return (
<Link to={editFlowLink}>
<Button
tabIndex={-1}
variant="outline"
size="sm"
className="whitespace-nowrap"
data-testid={editFlowButtonTestId}
>
<IconComponent
name="ExternalLink"
className="main-page-nav-button select-none"
/>
Edit Flow
</Button>
</Link>
);
}
return null;
};
return (
<CollectionCardComponent
is_component={type === "component"}
data={{
is_component: isComponent,
...item,
}}
disabled={isLoading}
data-testid={editFlowButtonTestId}
button={renderButton()!}
onClick={!isComponent ? handleClick : undefined}
playground={!isComponent}
control={control}
/>
);
};
export default CollectionCard;

View file

@ -1,15 +1,15 @@
import { useCallback } from "react";
const useDeleteMultipleFlows = (
selectedFlowsComponentsCards,
removeFlow,
resetFilter,
getFoldersApi,
folderId,
myCollectionId,
getFolderById,
setSuccessData,
setErrorData,
selectedFlowsComponentsCards: string[],
removeFlow: (selectedFlowsComponentsCards: string[]) => Promise<void>,
resetFilter: () => void,
getFoldersApi: (refetch?: boolean) => Promise<void>,
folderId: string | undefined,
myCollectionId: string,
getFolderById: (id: string) => void,
setSuccessData: (data: { title: string }) => void,
setErrorData: (data: { title: string; list: string[] }) => void,
) => {
const handleDeleteMultiple = useCallback(() => {
removeFlow(selectedFlowsComponentsCards)

View file

@ -1,6 +1,9 @@
import { useMemo } from "react";
const useDescriptionModal = (selectedFlowsComponentsCards, type) => {
const useDescriptionModal = (
selectedFlowsComponentsCards: string[] | undefined,
type: string | undefined,
) => {
const getDescriptionModal = useMemo(() => {
const getTypeLabel = (type) => {
const labels = {

View file

@ -1,10 +1,11 @@
import cloneDeep from "lodash/cloneDeep";
import { useEffect } from "react";
import { FlowType } from "../../../../../types/flow";
const useFilteredFlows = (
flowsFromFolder,
searchFlowsComponents,
setAllFlows,
flowsFromFolder: FlowType[],
searchFlowsComponents: string,
setAllFlows: (value: any[]) => void,
) => {
useEffect(() => {
const newFlows = cloneDeep(flowsFromFolder || []);

View file

@ -1,18 +1,31 @@
import { useCallback } from "react";
import { XYPosition } from "reactflow";
import { FlowType } from "../../../../../types/flow";
const useDuplicateFlows = (
selectedFlowsComponentsCards,
addFlow,
allFlows,
resetFilter,
getFoldersApi,
folderId,
myCollectionId,
getFolderById,
setSuccessData,
setSelectedFlowsComponentsCards,
handleSelectAll,
cardTypes,
selectedFlowsComponentsCards: string[],
addFlow: (
newProject: boolean,
flow?: FlowType,
override?: boolean,
position?: XYPosition,
fromDragAndDrop?: boolean,
) => Promise<string | undefined>,
allFlows: any[],
resetFilter: () => void,
getFoldersApi: (
refetch?: boolean,
startupApplication?: boolean,
) => Promise<void>,
folderId: string,
myCollectionId: string,
getFolderById: (id: string) => void,
setSuccessData: (data: { title: string }) => void,
setSelectedFlowsComponentsCards: (
selectedFlowsComponentsCards: string[],
) => void,
handleSelectAll: (select: boolean) => void,
cardTypes: string,
) => {
const handleDuplicate = useCallback(() => {
Promise.all(

View file

@ -1,15 +1,18 @@
import { useCallback } from "react";
import { FlowType } from "../../../../../types/flow";
const useExportFlows = (
selectedFlowsComponentsCards,
allFlows,
downloadFlow,
removeApiKeys,
version,
setSuccessData,
setSelectedFlowsComponentsCards,
handleSelectAll,
cardTypes,
selectedFlowsComponentsCards: string[],
allFlows: Array<FlowType>,
downloadFlow: (flow: any, name: string, description: string) => void,
removeApiKeys: (flow: any) => any,
version: string,
setSuccessData: (data: { title: string }) => void,
setSelectedFlowsComponentsCards: (
selectedFlowsComponentsCards: string[],
) => void,
handleSelectAll: (select: boolean) => void,
cardTypes: string,
) => {
const handleExport = useCallback(() => {
selectedFlowsComponentsCards.forEach((selectedFlowId) => {

View file

@ -1,6 +1,11 @@
import { useCallback } from "react";
import { FlowType } from "../../../../../types/flow";
const useSelectAll = (flowsFromFolder, getValues, setValue) => {
const useSelectAll = (
flowsFromFolder: FlowType[],
getValues: () => Record<string, boolean>,
setValue: (key: string, value: boolean) => void,
) => {
const handleSelectAll = useCallback(
(select) => {
const flowsFromFolderIds = flowsFromFolder?.map((f) => f.id);

View file

@ -1,15 +1,15 @@
import { useCallback } from "react";
const useSelectOptionsChange = (
selectedFlowsComponentsCards,
setErrorData,
setOpenDelete,
handleDuplicate,
handleExport,
selectedFlowsComponentsCards: string[] | undefined,
setErrorData: (data: { title: string; list: string[] }) => void,
setOpenDelete: (value: boolean) => void,
handleDuplicate: () => void,
handleExport: () => void,
) => {
const handleSelectOptionsChange = useCallback(
(action) => {
const hasSelected = selectedFlowsComponentsCards?.length > 0;
const hasSelected = selectedFlowsComponentsCards?.length! > 0;
if (!hasSelected) {
setErrorData({
title: "No items selected",

View file

@ -1,8 +1,10 @@
import { useEffect } from "react";
const useSelectedFlows = (
entireFormValues,
setSelectedFlowsComponentsCards,
entireFormValues: Record<string, boolean> | undefined,
setSelectedFlowsComponentsCards: (
selectedFlowsComponentsCards: string[],
) => void,
) => {
useEffect(() => {
if (!entireFormValues || Object.keys(entireFormValues).length === 0) return;

View file

@ -19,6 +19,7 @@ import { getNameByType } from "../../utils/get-name-by-type";
import { sortFlows } from "../../utils/sort-flows";
import EmptyComponent from "../emptyComponent";
import HeaderComponent from "../headerComponent";
import CollectionCard from "./components/collectionCard";
import useDeleteMultipleFlows from "./hooks/use-delete-multiple";
import useDescriptionModal from "./hooks/use-description-modal";
import useFilteredFlows from "./hooks/use-filtered-flows";
@ -61,7 +62,6 @@ export default function ComponentsComponent({
const [handleFileDrop] = useFileDrop(uploadFlow, type)!;
const [pageSize, setPageSize] = useState(20);
const [pageIndex, setPageIndex] = useState(1);
const navigate = useNavigate();
const location = useLocation();
const all: FlowType[] = sortFlows(allFlows, type);
const start = (pageIndex - 1) * pageSize;
@ -94,7 +94,7 @@ export default function ComponentsComponent({
getFolderById(folderId ? folderId : myCollectionId);
}, [location]);
useFilteredFlows(flowsFromFolder, searchFlowsComponents, setAllFlows);
useFilteredFlows(flowsFromFolder!, searchFlowsComponents, setAllFlows);
const resetFilter = () => {
setPageIndex(1);
@ -107,7 +107,7 @@ export default function ComponentsComponent({
const methods = useForm();
const { handleSelectAll } = useSelectAll(
flowsFromFolder,
flowsFromFolder!,
getValues,
setValue,
);
@ -119,7 +119,7 @@ export default function ComponentsComponent({
resetFilter,
getFoldersApi,
folderId,
myCollectionId,
myCollectionId!,
getFolderById,
setSuccessData,
setSelectedFlowsComponentsCards,
@ -155,7 +155,7 @@ export default function ComponentsComponent({
resetFilter,
getFoldersApi,
folderId,
myCollectionId,
myCollectionId!,
getFolderById,
setSuccessData,
setErrorData,
@ -205,43 +205,10 @@ export default function ComponentsComponent({
{data?.map((item) => (
<FormProvider {...methods} key={item.id}>
<form>
<CollectionCardComponent
is_component={type === "component"}
data={{
is_component: item.is_component ?? false,
...item,
}}
disabled={isLoading}
data-testid={"edit-flow-button-" + item.id}
button={
!item.is_component ? (
<Link to={"/flow/" + item.id}>
<Button
tabIndex={-1}
variant="outline"
size="sm"
className="whitespace-nowrap"
data-testid={"edit-flow-button-" + item.id}
>
<IconComponent
name="ExternalLink"
className="main-page-nav-button select-none"
/>
Edit Flow
</Button>
</Link>
) : (
<></>
)
}
onClick={
!item.is_component
? () => {
navigate("/flow/" + item.id);
}
: undefined
}
playground={!item.is_component}
<CollectionCard
item={item}
type={type}
isLoading={isLoading}
control={control}
/>
</form>

View file

@ -2,7 +2,7 @@ import useAlertStore from "../../../stores/alertStore";
import { useFolderStore } from "../../../stores/foldersStore";
import { deleteFolder, getFolderById } from "../services";
const useDeleteFolder = ({ navigate }) => {
const useDeleteFolder = ({ navigate }: { navigate: (url: string) => void }) => {
const setSuccessData = useAlertStore((state) => state.setSuccessData);
const setErrorData = useAlertStore((state) => state.setErrorData);
const folderToEdit = useFolderStore((state) => state.folderToEdit);

View file

@ -1,7 +1,26 @@
import { XYPosition } from "reactflow";
import { CONSOLE_ERROR_MSG } from "../../../constants/alerts_constants";
import useAlertStore from "../../../stores/alertStore";
const useDropdownOptions = ({ uploadFlow, navigate, is_component }) => {
const useDropdownOptions = ({
uploadFlow,
navigate,
is_component,
}: {
uploadFlow: ({
newProject,
file,
isComponent,
position,
}: {
newProject: boolean;
file?: File;
isComponent: boolean | null;
position?: XYPosition;
}) => Promise<string | never>;
navigate: (url: string) => void;
is_component: boolean;
}) => {
const setSuccessData = useAlertStore((state) => state.setSuccessData);
const setErrorData = useAlertStore((state) => state.setErrorData);
const handleImportFromJSON = () => {

View file

@ -1,6 +1,12 @@
import { getApiKey } from "../../../../../controllers/API";
import { Users } from "../../../../../types/api";
const useApiKeys = (userData, setLoadingKeys, keysList, setUserId) => {
const useApiKeys = (
userData: Users | null,
setLoadingKeys: (load: boolean) => void,
keysList: React.MutableRefObject<never[]>,
setUserId: (userId: string) => void,
) => {
const fetchApiKeys = () => {
setLoadingKeys(true);
getApiKey()

View file

@ -7,10 +7,10 @@ import {
import { deleteApiKey } from "../../../../../controllers/API";
const useDeleteApiKeys = (
selectedRows,
resetFilter,
setSuccessData,
setErrorData,
selectedRows: string[],
resetFilter: () => void,
setSuccessData: (data: { title: string }) => void,
setErrorData: (data: { title: string; list: string[] }) => void,
) => {
const handleDeleteKey = () => {
Promise.all(selectedRows.map((selectedRow) => deleteApiKey(selectedRow)))

View file

@ -4,7 +4,10 @@ import {
BASE_URL_API,
} from "../../../../../../../../../constants/constants";
const usePreloadImages = (profilePictures, setImagesLoaded) => {
const usePreloadImages = (
profilePictures: { [key: string]: string[] },
setImagesLoaded: (value: boolean) => void,
) => {
const preloadImages = async (imageUrls) => {
return Promise.all(
imageUrls.map(

View file

@ -5,8 +5,13 @@ import {
SAVE_SUCCESS_ALERT,
} from "../../../../constants/alerts_constants";
import { resetPassword } from "../../../../controllers/API";
import { Users } from "../../../../types/api";
const usePatchPassword = (userData, setSuccessData, setErrorData) => {
const usePatchPassword = (
userData: Users | null,
setSuccessData: (data: { title: string; list?: string[] }) => void,
setErrorData: (data: { title: string; list: string[] }) => void,
) => {
const handlePatchPassword = async (password, cnfPassword, handleInput) => {
if (password !== cnfPassword) {
setErrorData({
@ -16,7 +21,7 @@ const usePatchPassword = (userData, setSuccessData, setErrorData) => {
return;
}
try {
if (password !== "") await resetPassword(userData.id, { password });
if (password !== "") await resetPassword(userData!.id, { password });
handleInput({ target: { name: "password", value: "" } });
handleInput({ target: { name: "cnfPassword", value: "" } });
setSuccessData({ title: SAVE_SUCCESS_ALERT });

View file

@ -4,21 +4,22 @@ import {
SAVE_SUCCESS_ALERT,
} from "../../../../constants/alerts_constants";
import { updateUser } from "../../../../controllers/API";
import { Users } from "../../../../types/api";
const usePatchProfilePicture = (
setSuccessData,
setErrorData,
currentUserData,
setUserData,
setSuccessData: (data: { title: string; list?: string[] }) => void,
setErrorData: (data: { title: string; list: string[] }) => void,
currentUserData: Users | null,
setUserData: (data: any) => void,
) => {
const handlePatchProfilePicture = async (profile_picture) => {
try {
if (profile_picture !== "") {
await updateUser(currentUserData.id, {
await updateUser(currentUserData!.id, {
profile_image: profile_picture,
});
let newUserData = cloneDeep(currentUserData);
newUserData.profile_image = profile_picture;
newUserData!.profile_image = profile_picture;
setUserData(newUserData);
}
setSuccessData({ title: SAVE_SUCCESS_ALERT });

View file

@ -7,11 +7,11 @@ import { AuthContext } from "../../../../contexts/authContext";
import { addApiKeyStore } from "../../../../controllers/API";
const useSaveKey = (
setSuccessData,
setErrorData,
setHasApiKey,
setValidApiKey,
setLoadingApiKey,
setSuccessData: (data: { title: string }) => void,
setErrorData: (data: { title: string; list: string[] }) => void,
setHasApiKey: (hasApiKey: boolean) => void,
setValidApiKey: (validApiKey: boolean) => void,
setLoadingApiKey: (loadingApiKey: boolean) => void,
) => {
const { storeApiKey } = useContext(AuthContext);

View file

@ -1,6 +1,9 @@
import { useEffect } from "react";
const useScrollToElement = (scrollId, setCurrentFlowId) => {
const useScrollToElement = (
scrollId: string | null | undefined,
setCurrentFlowId: (currentFlowId: string) => void,
) => {
useEffect(() => {
const element = document.getElementById(scrollId ?? "null");
if (element) {

View file

@ -1,8 +1,11 @@
import { ColDef, ColGroupDef } from "ag-grid-community";
import { useEffect } from "react";
import { getMessagesTable } from "../../../../../controllers/API";
import { useMessagesStore } from "../../../../../stores/messagesStore";
const useMessagesTable = (setColumns) => {
const useMessagesTable = (
setColumns: (data: Array<ColDef | ColGroupDef>) => void,
) => {
const setMessages = useMessagesStore((state) => state.setMessages);
useEffect(() => {
const fetchData = async () => {

View file

@ -2,10 +2,10 @@ import { deleteMessagesFn } from "../../../../../controllers/API";
import { useMessagesStore } from "../../../../../stores/messagesStore";
const useRemoveMessages = (
setSelectedRows,
setSuccessData,
setErrorData,
selectedRows,
setSelectedRows: (data: number[]) => void,
setSuccessData: (data: { title: string }) => void,
setErrorData: (data: { title: string }) => void,
selectedRows: number[],
) => {
const deleteMessages = useMessagesStore((state) => state.removeMessages);

View file

@ -2,7 +2,10 @@ import { updateMessageApi } from "../../../../../controllers/API";
import { useMessagesStore } from "../../../../../stores/messagesStore";
import { Message } from "../../../../../types/messages";
const useUpdateMessage = (setSuccessData, setErrorData) => {
const useUpdateMessage = (
setSuccessData: (data: { title: string; list?: string[] }) => void,
setErrorData: (data: { title: string; list?: string[] }) => void,
) => {
const updateMessage = useMessagesStore((state) => state.updateMessage);
const handleUpdate = async (data: Message) => {