merging all branches/feat

This commit is contained in:
cristhianzl 2024-06-06 21:43:59 -03:00
commit 02cca793eb
44 changed files with 309 additions and 192 deletions

View file

@ -21,6 +21,7 @@ import {
LANGFLOW_SUPPORTED_TYPES,
TOOLTIP_EMPTY,
} from "../../../../constants/constants";
import OutputModal from "../../../../customNodes/genericNode/components/outputModal";
import { Case } from "../../../../shared/components/caseComponent";
import useFlowStore from "../../../../stores/flowStore";
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
@ -44,7 +45,6 @@ import useFetchDataOnMount from "../../../hooks/use-fetch-data-on-mount";
import useHandleOnNewValue from "../../../hooks/use-handle-new-value";
import useHandleNodeClass from "../../../hooks/use-handle-node-class";
import useHandleRefreshButtonPress from "../../../hooks/use-handle-refresh-buttons";
import OutputModal from "../outputModal";
import TooltipRenderComponent from "../tooltipRenderComponent";
import { TEXT_FIELD_TYPES } from "./constants";
@ -284,7 +284,7 @@ export default function ParameterComponent({
"h-5 w-5 rounded-md",
displayOutputPreview && !unknownOutput
? " hover:bg-secondary-foreground/5 hover:text-medium-indigo"
: " cursor-not-allowed text-muted-foreground",
: " cursor-not-allowed text-muted-foreground"
)}
name={"ScanEye"}
/>

View file

@ -11,6 +11,8 @@ import {
STATUS_BUILDING,
} from "../../constants/constants";
import { BuildStatus } from "../../constants/enums";
import { countHandlesFn } from "../../customNodes/helpers/count-handles";
import { getSpecificClassFromBuildStatus } from "../../customNodes/helpers/get-class-from-build-status";
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
import useAlertStore from "../../stores/alertStore";
import { useDarkStore } from "../../stores/darkStore";
@ -22,8 +24,6 @@ import { NodeDataType } from "../../types/flow";
import { handleKeyDown, scapedJSONStringfy } from "../../utils/reactflowUtils";
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
import { classNames, cn } from "../../utils/utils";
import { countHandlesFn } from "../helpers/count-handles";
import { getSpecificClassFromBuildStatus } from "../helpers/get-class-from-build-status";
import useCheckCodeValidity from "../hooks/use-check-code-validity";
import useIconNodeRender from "../hooks/use-icon-render";
import useIconStatus from "../hooks/use-icons-status";
@ -127,7 +127,7 @@ export default function GenericNode({
const names = classNames(
baseBorderClass,
nodeSizeClass,
"generic-node-div",
"generic-node-div group/node",
specificClassFromBuildStatus
);
return names;

View file

@ -51,13 +51,15 @@ export default function ErrorAlert({
/>
</div>
<div className="ml-3">
<h3 className="error-build-foreground">{title}</h3>
<h3 className="error-build-foreground line-clamp-2">{title}</h3>
{list?.length !== 0 &&
list?.some((item) => item !== null && item !== undefined) ? (
<div className="error-build-message-div">
<ul className="error-build-message-list">
{list.map((item, index) => (
<li key={index}>{item}</li>
<li key={index} className="line-clamp-5">
{item}
</li>
))}
</ul>
</div>

View file

@ -47,7 +47,7 @@ export default function NoticeAlert({
/>
</div>
<div className="ml-3 flex-1 md:flex md:justify-between">
<p className="text-sm text-info-foreground word-break-break-word">
<p className="line-clamp-2 text-sm text-info-foreground word-break-break-word">
{title}
</p>
<p className="mt-3 text-sm md:ml-6 md:mt-0">

View file

@ -45,7 +45,7 @@ export default function SuccessAlert({
/>
</div>
<div className="ml-3">
<p className="success-alert-message">{title}</p>
<p className="success-alert-message line-clamp-2">{title}</p>
</div>
</div>
</div>

View file

@ -56,7 +56,7 @@ export default function Header(): JSX.Element {
const lastFlowVisitedIndex = routeHistory
.reverse()
.findIndex(
(path) => path.includes("/flow/") && path !== location.pathname
(path) => path.includes("/flow/") && path !== location.pathname,
);
const lastFlowVisited = routeHistory[lastFlowVisitedIndex];
@ -200,6 +200,28 @@ export default function Header(): JSX.Element {
/>
</DropdownMenuTrigger>
<DropdownMenuContent>
{!autoLogin && (
<>
<DropdownMenuLabel>
<div className="flex items-center gap-3">
<div
className={
"h-5 w-5 rounded-full focus-visible:outline-0 " +
(userData?.profile_image ??
(userData?.id
? gradients[
parseInt(userData?.id ?? "", 30) %
gradients.length
]
: "bg-gray-500"))
}
/>
{userData?.username ?? "User"}
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
</>
)}
<DropdownMenuLabel>General</DropdownMenuLabel>
<DropdownMenuItem
className="cursor-pointer"

View file

@ -13,6 +13,7 @@ import IconComponent, {
import { Button, buttonVariants } from "../../../ui/button";
import { Input } from "../../../ui/input";
import useFileDrop from "../../hooks/use-on-file-drop";
import useAlertStore from "../../../../stores/alertStore";
type SideBarFoldersButtonsComponentProps = {
folders: FolderType[];
@ -51,6 +52,7 @@ const SideBarFoldersButtonsComponent = ({
const location = useLocation();
const folderId = location?.state?.folderId ?? myCollectionId;
const getFolderById = useFolderStore((state) => state.getFolderById);
const setErrorData = useAlertStore((state) => state.setErrorData);
const handleFolderChange = (folderId: string) => {
getFolderById(folderId);
@ -62,7 +64,17 @@ const SideBarFoldersButtonsComponent = ({
);
const handleUploadFlowsToFolder = () => {
uploadFolder(folderId);
uploadFolder(folderId)
.then(() => {
getFolderById(folderId);
})
.catch((err) => {
console.log(err);
setErrorData({
title: `Error on upload`,
list: [err["response"]["data"]],
});
});
};
const handleDownloadFolder = (id: string) => {

View file

@ -668,7 +668,7 @@ export const ZERO_NOTIFICATIONS = "No new notifications";
export const SUCCESS_BUILD = "Built sucessfully ✨";
export const ALERT_SAVE_WITH_API =
"Caution: Uncheck this box only removes API keys from fields specifically designated for API keys.";
"Caution: Unchecking this box only removes API keys from fields specifically designated for API keys.";
export const SAVE_WITH_API_CHECKBOX = "Save with my API keys";
export const EDIT_TEXT_MODAL_TITLE = "Edit Text";

View file

@ -45,7 +45,7 @@ const ExportModal = forwardRef(
is_component: false,
},
name!,
description
description,
);
setNoticeData({
title: API_WARNING_NOTICE_ALERT,
@ -61,7 +61,7 @@ const ExportModal = forwardRef(
is_component: false,
}),
name!,
description
description,
);
setOpen(false);
}}
@ -94,7 +94,7 @@ const ExportModal = forwardRef(
{SAVE_WITH_API_CHECKBOX}
</label>
</div>
<span className=" text-xs text-destructive ">
<span className="mt-1 text-xs text-destructive ">
{ALERT_SAVE_WITH_API}
</span>
</BaseModal.Content>
@ -102,6 +102,6 @@ const ExportModal = forwardRef(
<BaseModal.Footer submit={{ label: "Download Flow" }} />
</BaseModal>
);
}
},
);
export default ExportModal;

View file

@ -4,7 +4,9 @@ import { FormProvider, useForm, useWatch } from "react-hook-form";
import { Link, useLocation, useNavigate } from "react-router-dom";
import CollectionCardComponent from "../../../../components/cardComponent";
import CardsWrapComponent from "../../../../components/cardsWrapComponent";
import IconComponent from "../../../../components/genericIconComponent";
import IconComponent, {
ForwardedIconComponent,
} from "../../../../components/genericIconComponent";
import PaginatorComponent from "../../../../components/paginatorComponent";
import { SkeletonCardComponent } from "../../../../components/skeletonCardComponent";
import { Button } from "../../../../components/ui/button";
@ -18,6 +20,9 @@ import { getNameByType } from "../../utils/get-name-by-type";
import { sortFlows } from "../../utils/sort-flows";
import EmptyComponent from "../emptyComponent";
import HeaderComponent from "../headerComponent";
import { downloadFlow, removeApiKeys } from "../../../../utils/reactflowUtils";
import { useDarkStore } from "../../../../stores/darkStore";
import { UPLOAD_ERROR_ALERT } from "../../../../constants/alerts_constants";
export default function ComponentsComponent({
type = "all",
@ -31,22 +36,22 @@ export default function ComponentsComponent({
const allFlows = useFlowsManagerStore((state) => state.allFlows);
const flowsFromFolder = useFolderStore(
(state) => state.selectedFolder?.flows
(state) => state.selectedFolder?.flows,
);
const setSuccessData = useAlertStore((state) => state.setSuccessData);
const setErrorData = useAlertStore((state) => state.setErrorData);
const [openDelete, setOpenDelete] = useState(false);
const searchFlowsComponents = useFlowsManagerStore(
(state) => state.searchFlowsComponents
(state) => state.searchFlowsComponents,
);
const setSelectedFlowsComponentsCards = useFlowsManagerStore(
(state) => state.setSelectedFlowsComponentsCards
(state) => state.setSelectedFlowsComponentsCards,
);
const selectedFlowsComponentsCards = useFlowsManagerStore(
(state) => state.selectedFlowsComponentsCards
(state) => state.selectedFlowsComponentsCards,
);
const [handleFileDrop] = useFileDrop(uploadFlow, type)!;
@ -82,7 +87,7 @@ export default function ComponentsComponent({
f.name.toLowerCase().includes(searchFlowsComponents.toLowerCase()) ||
f.description
.toLowerCase()
.includes(searchFlowsComponents.toLowerCase())
.includes(searchFlowsComponents.toLowerCase()),
);
if (searchFlowsComponents === "") {
@ -129,6 +134,8 @@ export default function ComponentsComponent({
setOpenDelete(true);
} else if (action === "duplicate") {
handleDuplicate();
} else if (action === "export") {
handleExport();
}
};
@ -137,9 +144,9 @@ export default function ComponentsComponent({
selectedFlowsComponentsCards.map((selectedFlow) =>
addFlow(
true,
allFlows.find((flow) => flow.id === selectedFlow)
)
)
allFlows.find((flow) => flow.id === selectedFlow),
),
),
).then(() => {
resetFilter();
getFoldersApi(true);
@ -152,6 +159,47 @@ export default function ComponentsComponent({
});
};
const handleImport = () => {
uploadFlow({ newProject: true, isComponent: false })
.then(() => {
resetFilter();
getFoldersApi(true);
if (!folderId || folderId === myCollectionId) {
getFolderById(folderId ? folderId : myCollectionId);
}
setSelectedFlowsComponentsCards([]);
setSuccessData({ title: "Flows imported successfully" });
})
.catch((error) => {
setErrorData({
title: UPLOAD_ERROR_ALERT,
list: [error],
});
});
};
const version = useDarkStore((state) => state.version);
const handleExport = () => {
selectedFlowsComponentsCards.map((selectedFlowId) => {
const selectedFlow = allFlows.find((flow) => flow.id === selectedFlowId);
downloadFlow(
removeApiKeys({
id: selectedFlow!.id,
data: selectedFlow!.data!,
description: selectedFlow!.description,
name: selectedFlow!.name,
last_tested_version: version,
is_component: false,
}),
selectedFlow!.name,
selectedFlow!.description,
);
});
setSuccessData({ title: "Flows exported successfully" });
};
const handleDeleteMultiple = () => {
removeFlow(selectedFlowsComponentsCards)
.then(() => {
@ -161,7 +209,7 @@ export default function ComponentsComponent({
getFolderById(folderId ? folderId : myCollectionId);
}
setSuccessData({
title: "Selected items deleted successfully!",
title: "Selected items deleted successfully",
});
})
.catch(() => {
@ -180,7 +228,7 @@ export default function ComponentsComponent({
return true;
}
return false;
}
},
);
setSelectedFlowsComponentsCards(selectedFlows);
@ -215,20 +263,23 @@ export default function ComponentsComponent({
if (type === "all") return allFlows?.length;
return allFlows?.filter(
(f) => (f.is_component ?? false) === (type === "component")
(f) => (f.is_component ?? false) === (type === "component"),
)?.length;
};
return (
<>
{allFlows?.length > 0 && (
<HeaderComponent
handleDelete={() => handleSelectOptionsChange("delete")}
handleSelectAll={handleSelectAll}
handleDuplicate={() => handleSelectOptionsChange("duplicate")}
disableFunctions={!(selectedFlowsComponentsCards?.length > 0)}
/>
)}
<div className="flex w-full gap-4 pb-5">
{allFlows?.length > 0 && (
<HeaderComponent
handleDelete={() => handleSelectOptionsChange("delete")}
handleSelectAll={handleSelectAll}
handleDuplicate={() => handleSelectOptionsChange("duplicate")}
handleExport={() => handleSelectOptionsChange("export")}
disableFunctions={!(selectedFlowsComponentsCards?.length > 0)}
/>
)}
</div>
<CardsWrapComponent
onFileDrop={handleFileDrop}

View file

@ -13,7 +13,7 @@ const EmptyComponent = ({}: EmptyComponentProps) => {
return (
<>
<div className="mt-6 flex w-full items-center justify-center text-center">
<div className="mt-2 flex w-full items-center justify-center text-center">
<div className="flex-max-width h-full flex-col">
<div className="align-center flex w-full justify-center gap-1 ">
<span className="text-muted-foreground">

View file

@ -1,13 +1,17 @@
import { useState } from "react";
import IconComponent from "../../../../components/genericIconComponent";
import IconComponent, {
ForwardedIconComponent,
} from "../../../../components/genericIconComponent";
import ShadTooltip from "../../../../components/shadTooltipComponent";
import { Checkbox } from "../../../../components/ui/checkbox";
import { cn } from "../../../../utils/utils";
import { Button } from "../../../../components/ui/button";
type HeaderComponentProps = {
handleSelectAll: (select) => void;
handleDelete: () => void;
handleDuplicate: () => void;
handleExport: () => void;
disableFunctions: boolean;
};
@ -15,6 +19,7 @@ const HeaderComponent = ({
handleSelectAll,
handleDelete,
handleDuplicate,
handleExport,
disableFunctions,
}: HeaderComponentProps) => {
const [shouldSelectAll, setShouldSelectAll] = useState(true);
@ -26,29 +31,46 @@ const HeaderComponent = ({
return (
<>
<div className="grid grid-cols-3 pb-5">
<div className="col-auto grid-cols-1 self-center justify-self-start">
<a onClick={handleClick} className="text-sm">
<div className="header-menu-bar-display ">
<div
className="header-menu-flow-name"
data-testid="select_all_collection"
>
<div className="flex items-center space-x-2">
<Checkbox checked={!shouldSelectAll} id="terms" />
<label
onClick={handleClick}
htmlFor="terms"
className="label cursor-pointer text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
>
{shouldSelectAll ? "Select All" : "Unselect All"}
</label>
</div>
</div>
<div className="flex w-full items-center justify-between gap-4">
<div className="flex items-center justify-self-start">
<Button
variant="none"
size="none"
onClick={handleClick}
className="text-sm"
>
<div className="flex items-center space-x-2">
<Checkbox checked={!shouldSelectAll} id="terms" />
<span className="label text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
{shouldSelectAll ? "Select All" : "Unselect All"}
</span>
</div>
</a>
</Button>
</div>
<div className="col-span-2 flex grid-cols-1 gap-2 justify-self-end">
<div className="flex items-center gap-2">
<div>
<ShadTooltip
content={
disableFunctions ? (
<span>Select items to export</span>
) : (
<span>Export selected items</span>
)
}
>
<Button
variant="none"
size="none"
onClick={handleExport}
disabled={disableFunctions}
>
<IconComponent
name="FileDown"
className={cn("h-5 w-5 text-primary transition-all")}
/>
</Button>
</ShadTooltip>
</div>
<div>
<ShadTooltip
content={
@ -59,12 +81,17 @@ const HeaderComponent = ({
)
}
>
<button onClick={handleDuplicate} disabled={disableFunctions}>
<Button
variant="none"
size="none"
onClick={handleDuplicate}
disabled={disableFunctions}
>
<IconComponent
name="Copy"
className={cn("h-5 w-5 text-primary transition-all")}
/>
</button>
</Button>
</ShadTooltip>
</div>
<div>
@ -77,15 +104,20 @@ const HeaderComponent = ({
)
}
>
<button onClick={handleDelete} disabled={disableFunctions}>
<Button
variant="none"
size="none"
onClick={handleDelete}
disabled={disableFunctions}
>
<IconComponent
name="Trash2"
className={cn(
"h-5 w-5 text-primary transition-all",
disableFunctions ? "" : "hover:text-destructive"
disableFunctions ? "" : "hover:text-destructive",
)}
/>
</button>
</Button>
</ShadTooltip>
</div>
</div>

View file

@ -8,7 +8,7 @@ import useFlowsManagerStore from "../../stores/flowsManagerStore";
export default function SettingsPage(): JSX.Element {
const pathname = location.pathname;
const setCurrentFlowId = useFlowsManagerStore(
(state) => state.setCurrentFlowId
(state) => state.setCurrentFlowId,
);
useEffect(() => {
setCurrentFlowId("");
@ -59,7 +59,10 @@ export default function SettingsPage(): JSX.Element {
title: "Messages",
href: "/settings/messages",
icon: (
<ForwardedIconComponent name="Keyboard" className="w-5 stroke-[1.5]" />
<ForwardedIconComponent
name="MessagesSquare"
className="w-4 flex-shrink-0 justify-start stroke-[1.5]"
/>
),
},
];
@ -72,8 +75,10 @@ export default function SettingsPage(): JSX.Element {
<aside className="flex h-full shrink-0 flex-col space-y-6 lg:w-[20vw]">
<SidebarNav items={sidebarNavItems} />
</aside>
<div className="h-full w-full flex-1 pb-8">
<Outlet />
<div className="flex h-full w-full flex-1 flex-col">
<div className="flex-1 pb-8">
<Outlet />
</div>
</div>
</div>
</PageLayout>

View file

@ -52,23 +52,17 @@ export default function ApiKeysPage() {
/>
<div className="flex h-full w-full flex-col justify-between">
<Card x-chunk="dashboard-04-chunk-2" className="h-full pt-4">
<CardContent className="h-full">
<TableComponent
overlayNoRowsTemplate="No data available"
onSelectionChanged={(event: SelectionChangedEvent) => {
setSelectedRows(
event.api.getSelectedRows().map((row) => row.id),
);
}}
rowSelection="multiple"
suppressRowClickSelection={true}
pagination={true}
columnDefs={columnDefs}
rowData={keysList.current}
/>
</CardContent>
</Card>
<TableComponent
overlayNoRowsTemplate="No data available"
onSelectionChanged={(event: SelectionChangedEvent) => {
setSelectedRows(event.api.getSelectedRows().map((row) => row.id));
}}
rowSelection="multiple"
suppressRowClickSelection={true}
pagination={true}
columnDefs={columnDefs}
rowData={keysList.current}
/>
</div>
</div>
);

View file

@ -16,13 +16,13 @@ import { cn } from "../../../../utils/utils";
export default function GlobalVariablesPage() {
const globalVariablesEntries = useGlobalVariablesStore(
(state) => state.globalVariablesEntries
(state) => state.globalVariablesEntries,
);
const removeGlobalVariable = useGlobalVariablesStore(
(state) => state.removeGlobalVariable
(state) => state.removeGlobalVariable,
);
const globalVariables = useGlobalVariablesStore(
(state) => state.globalVariables
(state) => state.globalVariables,
);
const setErrorData = useAlertStore((state) => state.setErrorData);
const getVariableId = useGlobalVariablesStore((state) => state.getVariableId);
@ -154,7 +154,7 @@ export default function GlobalVariablesPage() {
<IconComponent
name="Trash2"
className={cn(
"h-5 w-5 text-destructive group-disabled:text-primary"
"h-5 w-5 text-destructive group-disabled:text-primary",
)}
/>
</Button>
@ -168,23 +168,17 @@ export default function GlobalVariablesPage() {
</div>
<div className="flex h-full w-full flex-col justify-between">
<Card x-chunk="dashboard-04-chunk-2" className="h-full pt-4">
<CardContent className="h-full">
<TableComponent
overlayNoRowsTemplate="No data available"
onSelectionChanged={(event: SelectionChangedEvent) => {
setSelectedRows(
event.api.getSelectedRows().map((row) => row.name)
);
}}
rowSelection="multiple"
suppressRowClickSelection={true}
pagination={true}
columnDefs={colDefs}
rowData={rowData}
/>
</CardContent>
</Card>
<TableComponent
overlayNoRowsTemplate="No data available"
onSelectionChanged={(event: SelectionChangedEvent) => {
setSelectedRows(event.api.getSelectedRows().map((row) => row.name));
}}
rowSelection="multiple"
suppressRowClickSelection={true}
pagination={true}
columnDefs={colDefs}
rowData={rowData}
/>
</div>
</div>
);

View file

@ -115,15 +115,11 @@ export default function ShortcutsPage() {
</div>
</div>
<div className="flex h-full w-full flex-col justify-between">
<Card x-chunk="dashboard-04-chunk-2" className="h-full pt-4">
<CardContent className="h-full">
<TableComponent
pagination={false}
columnDefs={colDefs}
rowData={nodesRowData}
/>
</CardContent>
</Card>
<TableComponent
pagination={false}
columnDefs={colDefs}
rowData={nodesRowData}
/>
</div>
</div>
);

View file

@ -27,7 +27,7 @@ export default function MessagesPage() {
setSelectedRows,
setSuccessData,
setErrorData,
selectedRows
selectedRows,
);
const { handleUpdate } = useUpdateMessage(setSuccessData, setErrorData);
@ -52,29 +52,25 @@ export default function MessagesPage() {
handleRemoveMessages={handleRemoveMessages}
/>
<div className="flex h-full w-full flex-col justify-between pb-8">
<Card x-chunk="dashboard-04-chunk-2" className="h-full pt-4">
<CardContent className="h-full">
<TableComponent
readOnlyEdit
onCellEditRequest={(event) => {
handleUpdateMessage(event);
}}
editable={["Sender Name", "Message"]}
overlayNoRowsTemplate="No data available"
onSelectionChanged={(event: SelectionChangedEvent) => {
setSelectedRows(
event.api.getSelectedRows().map((row) => row.index)
);
}}
rowSelection="multiple"
suppressRowClickSelection={true}
pagination={true}
columnDefs={columns}
rowData={messages}
/>
</CardContent>
</Card>
<div className="flex h-full w-full flex-col justify-between">
<TableComponent
readOnlyEdit
onCellEditRequest={(event) => {
handleUpdateMessage(event);
}}
editable={["Sender Name", "Message"]}
overlayNoRowsTemplate="No data available"
onSelectionChanged={(event: SelectionChangedEvent) => {
setSelectedRows(
event.api.getSelectedRows().map((row) => row.index),
);
}}
rowSelection="multiple"
suppressRowClickSelection={true}
pagination={true}
columnDefs={columns}
rowData={messages}
/>
</div>
</div>
);

View file

@ -7,6 +7,7 @@ import {
} from "../pages/MainPage/services";
import { FoldersStoreType } from "../types/zustand/folders";
import useFlowsManagerStore from "./flowsManagerStore";
import { uploadFlowsToDatabase } from "../controllers/API";
export const useFolderStore = create<FoldersStoreType>((set, get) => ({
folders: [],
@ -17,18 +18,18 @@ export const useFolderStore = create<FoldersStoreType>((set, get) => ({
getFolders().then(
(res) => {
const foldersWithoutStarterProjects = res.filter(
(folder) => folder.name !== STARTER_FOLDER_NAME
(folder) => folder.name !== STARTER_FOLDER_NAME,
);
const starterProjects = res.find(
(folder) => folder.name === STARTER_FOLDER_NAME
(folder) => folder.name === STARTER_FOLDER_NAME,
);
set({ starterProjectId: starterProjects!.id ?? "" });
set({ folders: foldersWithoutStarterProjects });
const myCollectionId = res?.find(
(f) => f.name === DEFAULT_FOLDER
(f) => f.name === DEFAULT_FOLDER,
)?.id;
set({ myCollectionId });
@ -45,7 +46,7 @@ export const useFolderStore = create<FoldersStoreType>((set, get) => ({
set({ folders: [] });
get().setLoading(false);
reject();
}
},
);
}
});
@ -65,7 +66,7 @@ export const useFolderStore = create<FoldersStoreType>((set, get) => ({
},
() => {
get().setLoadingById(false);
}
},
);
}
},
@ -100,7 +101,7 @@ export const useFolderStore = create<FoldersStoreType>((set, get) => ({
folderIdDragging: "",
setFolderIdDragging: (id) => set(() => ({ folderIdDragging: id })),
uploadFolder: () => {
return new Promise<void>(() => {
return new Promise<void>((resolve, reject) => {
const input = document.createElement("input");
input.type = "file";
input.onchange = (event: Event) => {
@ -111,8 +112,31 @@ export const useFolderStore = create<FoldersStoreType>((set, get) => ({
const file = (event.target as HTMLInputElement).files![0];
const formData = new FormData();
formData.append("file", file);
uploadFlowsFromFolders(formData).then(() => {
get().getFoldersApi(true);
file.text().then((text) => {
const data = JSON.parse(text);
if (data.data?.nodes) {
useFlowsManagerStore
.getState()
.addFlow(true, data)
.then(() => {
resolve();
})
.catch((error) => {
reject(error);
});
} else {
uploadFlowsFromFolders(formData)
.then(() => {
get()
.getFoldersApi(true)
.then(() => {
resolve();
});
})
.catch((error) => {
reject(error);
});
}
});
}
};

View file

@ -20,7 +20,7 @@ export type FoldersStoreType = {
setFolderUrl: (folderUrl: string) => void;
folderDragging: boolean;
setFolderDragging: (set: boolean) => void;
uploadFolder: (folderId: string) => void;
uploadFolder: (folderId: string) => Promise<void>;
folderIdDragging: string;
setFolderIdDragging: (id: string) => void;
starterProjectId: string;

View file

@ -56,6 +56,7 @@ import {
FolderIcon,
FolderPlus,
FolderPlusIcon,
FolderUp,
FormInput,
Forward,
Gift,
@ -433,6 +434,7 @@ export const nodeIconsLucide: iconsType = {
ChevronLeft,
SlidersHorizontal,
Palette,
FolderUp,
Blocks,
ChevronDown,
ArrowLeft,