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

@ -80,7 +80,10 @@ jobs:
langflowai/langflow-frontend:1.0-alpha
restart-space:
name: Restart HuggingFace Spaces
if: ${{ inputs.release_type == 'main' }}
runs-on: ubuntu-latest
needs: docker_build
strategy:
matrix:
python-version:

View file

@ -35,6 +35,10 @@ jobs:
with:
python-version: "3.10"
cache: "poetry"
- name: Set up Nodejs 20
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Check Version
id: check-version
run: |

View file

@ -1,6 +1,14 @@
# syntax=docker/dockerfile:1
# Keep this syntax directive! It's used to enable Docker BuildKit
FROM node:20-bookworm-slim as builder-node
WORKDIR /app
COPY src/frontend/package.json src/frontend/package-lock.json ./
RUN npm install
COPY src/frontend/ ./
RUN npm run build
################################
# BUILDER-BASE
# Used to build deps + create our virtual environment
@ -48,10 +56,10 @@ COPY pyproject.toml poetry.lock README.md ./
COPY src/ ./src
COPY scripts/ ./scripts
RUN python -m pip install requests --user && cd ./scripts && python update_dependencies.py
COPY --from=builder-node /app/build ./src/backend/base/langflow/frontend
RUN $POETRY_HOME/bin/poetry lock --no-update \
&& $POETRY_HOME/bin/poetry install --no-interaction --no-ansi -E deploy \
&& $POETRY_HOME/bin/poetry build -f wheel \
&& $POETRY_HOME/bin/poetry run pip install dist/*.whl
&& $POETRY_HOME/bin/poetry run pip install dist/*.whl --force-reinstall
################################
# RUNTIME

14
poetry.lock generated
View file

@ -698,13 +698,13 @@ graph = ["gremlinpython (==3.4.6)"]
[[package]]
name = "cassio"
version = "0.1.7"
version = "0.1.8"
description = "A framework-agnostic Python library to seamlessly integrate Apache Cassandra(R) with ML/LLM/genAI workloads."
optional = false
python-versions = "<4.0,>=3.8"
files = [
{file = "cassio-0.1.7-py3-none-any.whl", hash = "sha256:08d1028a20d09bd207de0e17eaf7ae821b3c8e4788555e2d337aa440e0846d87"},
{file = "cassio-0.1.7.tar.gz", hash = "sha256:44f705dff8a9a1c48527db2c9e968686358c960fa21ba940d9e66de00639ad78"},
{file = "cassio-0.1.8-py3-none-any.whl", hash = "sha256:c09e7c884ba7227ff5277c86f3b0f31c523672ea407f56d093c7227e69c54d94"},
{file = "cassio-0.1.8.tar.gz", hash = "sha256:4e09929506cb3dd6fad217e89846d0a1a59069afd24b82c72526ef6f2e9271af"},
]
[package.dependencies]
@ -4327,7 +4327,7 @@ types-requests = ">=2.31.0.2,<3.0.0.0"
[[package]]
name = "langflow-base"
version = "0.0.58"
version = "0.0.59"
description = "A Python package with a built-in web application"
optional = false
python-versions = ">=3.10,<3.13"
@ -5588,13 +5588,13 @@ sympy = "*"
[[package]]
name = "openai"
version = "1.31.2"
version = "1.32.0"
description = "The official Python library for the openai API"
optional = false
python-versions = ">=3.7.1"
files = [
{file = "openai-1.31.2-py3-none-any.whl", hash = "sha256:203cf21294f347c3d7b591e0ccbe18389d6f8967d4237214b926ea76b1e1781c"},
{file = "openai-1.31.2.tar.gz", hash = "sha256:966ab3165b926cb5ec091d2434c90613e2ea8b73ffad984f7fec34bde971725a"},
{file = "openai-1.32.0-py3-none-any.whl", hash = "sha256:953d57669f309002044fd2f678aba9f07a43256d74b3b00cd04afb5b185568ea"},
{file = "openai-1.32.0.tar.gz", hash = "sha256:a6df15a7ab9344b1bc2bc8d83639f68b7a7e2453c0f5e50c1666547eee86f0bd"},
]
[package.dependencies]

View file

@ -1,6 +1,6 @@
[tool.poetry]
name = "langflow"
version = "1.0.0a46"
version = "1.0.0a48"
description = "A Python package with a built-in web application"
authors = ["Langflow <contact@langflow.org>"]
maintainers = [

View file

@ -1,28 +0,0 @@
from .AstraDB import AstraDBVectorStoreComponent
from .Chroma import ChromaComponent
from .FAISS import FAISSComponent
from .MongoDBAtlasVector import MongoDBAtlasComponent
from .Pinecone import PineconeComponent
from .Qdrant import QdrantComponent
from .Redis import RedisComponent
from .SupabaseVectorStore import SupabaseComponent
from .Vectara import VectaraComponent
from .Weaviate import WeaviateVectorStoreComponent
from .pgvector import PGVectorComponent
from .Couchbase import CouchbaseComponent
__all__ = [
"AstraDBVectorStoreComponent",
"ChromaComponent",
"CouchbaseComponent",
"FAISSComponent",
"MongoDBAtlasComponent",
"PineconeComponent",
"QdrantComponent",
"RedisComponent",
"SupabaseComponent",
"VectaraComponent",
"WeaviateVectorStoreComponent",
"base",
"PGVectorComponent",
]

View file

@ -297,7 +297,7 @@ class CodeParser:
bases = self.execute_and_inspect_classes(self.code)
except Exception as e:
# If the code cannot be executed, return an empty list
logger.exception(e)
logger.debug(e)
bases = []
raise e
return bases

View file

@ -78,7 +78,8 @@ class DirectoryReader:
component_tuple = (*build_component(component), component)
components.append(component_tuple)
except Exception as e:
logger.error(f"Error while loading component { component['name']}: {e}")
logger.debug(f"Error while loading component { component['name']}")
logger.debug(e)
continue
items.append({"name": menu["name"], "path": menu["path"], "components": components})
filtered = [menu for menu in items if menu["components"]]
@ -266,8 +267,7 @@ class DirectoryReader:
if validation_result:
try:
output_types = self.get_output_types_from_code(result_content)
except Exception as exc:
logger.exception(f"Error while getting output types from code: {str(exc)}")
except Exception:
output_types = [component_name_camelcase]
else:
output_types = [component_name_camelcase]

View file

@ -132,7 +132,7 @@ class MonitorService(Service):
order: Optional[str] = "DESC",
limit: Optional[int] = None,
):
query = "SELECT index, flow_id, sender_name, sender, session_id, message, artifacts, timestamp FROM messages"
query = "SELECT index, flow_id, sender_name, sender, session_id, message, timestamp FROM messages"
conditions = []
if sender:
conditions.append(f"sender = '{sender}'")

View file

@ -1,6 +1,6 @@
[tool.poetry]
name = "langflow-base"
version = "0.0.58"
version = "0.0.59"
description = "A Python package with a built-in web application"
authors = ["Langflow <contact@langflow.org>"]
maintainers = [

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,