merging all branches/feat
This commit is contained in:
parent
a7c1af8c4f
commit
02cca793eb
44 changed files with 309 additions and 192 deletions
3
.github/workflows/docker-build.yml
vendored
3
.github/workflows/docker-build.yml
vendored
|
|
@ -80,7 +80,10 @@ jobs:
|
||||||
langflowai/langflow-frontend:1.0-alpha
|
langflowai/langflow-frontend:1.0-alpha
|
||||||
|
|
||||||
restart-space:
|
restart-space:
|
||||||
|
name: Restart HuggingFace Spaces
|
||||||
|
if: ${{ inputs.release_type == 'main' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
needs: docker_build
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version:
|
python-version:
|
||||||
|
|
|
||||||
4
.github/workflows/pre-release.yml
vendored
4
.github/workflows/pre-release.yml
vendored
|
|
@ -35,6 +35,10 @@ jobs:
|
||||||
with:
|
with:
|
||||||
python-version: "3.10"
|
python-version: "3.10"
|
||||||
cache: "poetry"
|
cache: "poetry"
|
||||||
|
- name: Set up Nodejs 20
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: "20"
|
||||||
- name: Check Version
|
- name: Check Version
|
||||||
id: check-version
|
id: check-version
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,14 @@
|
||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
# Keep this syntax directive! It's used to enable Docker BuildKit
|
# 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
|
# BUILDER-BASE
|
||||||
# Used to build deps + create our virtual environment
|
# Used to build deps + create our virtual environment
|
||||||
|
|
@ -48,10 +56,10 @@ COPY pyproject.toml poetry.lock README.md ./
|
||||||
COPY src/ ./src
|
COPY src/ ./src
|
||||||
COPY scripts/ ./scripts
|
COPY scripts/ ./scripts
|
||||||
RUN python -m pip install requests --user && cd ./scripts && python update_dependencies.py
|
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 \
|
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 build -f wheel \
|
||||||
&& $POETRY_HOME/bin/poetry run pip install dist/*.whl
|
&& $POETRY_HOME/bin/poetry run pip install dist/*.whl --force-reinstall
|
||||||
|
|
||||||
################################
|
################################
|
||||||
# RUNTIME
|
# RUNTIME
|
||||||
|
|
|
||||||
14
poetry.lock
generated
14
poetry.lock
generated
|
|
@ -698,13 +698,13 @@ graph = ["gremlinpython (==3.4.6)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cassio"
|
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."
|
description = "A framework-agnostic Python library to seamlessly integrate Apache Cassandra(R) with ML/LLM/genAI workloads."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "<4.0,>=3.8"
|
python-versions = "<4.0,>=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "cassio-0.1.7-py3-none-any.whl", hash = "sha256:08d1028a20d09bd207de0e17eaf7ae821b3c8e4788555e2d337aa440e0846d87"},
|
{file = "cassio-0.1.8-py3-none-any.whl", hash = "sha256:c09e7c884ba7227ff5277c86f3b0f31c523672ea407f56d093c7227e69c54d94"},
|
||||||
{file = "cassio-0.1.7.tar.gz", hash = "sha256:44f705dff8a9a1c48527db2c9e968686358c960fa21ba940d9e66de00639ad78"},
|
{file = "cassio-0.1.8.tar.gz", hash = "sha256:4e09929506cb3dd6fad217e89846d0a1a59069afd24b82c72526ef6f2e9271af"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
|
|
@ -4327,7 +4327,7 @@ types-requests = ">=2.31.0.2,<3.0.0.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langflow-base"
|
name = "langflow-base"
|
||||||
version = "0.0.58"
|
version = "0.0.59"
|
||||||
description = "A Python package with a built-in web application"
|
description = "A Python package with a built-in web application"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.10,<3.13"
|
python-versions = ">=3.10,<3.13"
|
||||||
|
|
@ -5588,13 +5588,13 @@ sympy = "*"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openai"
|
name = "openai"
|
||||||
version = "1.31.2"
|
version = "1.32.0"
|
||||||
description = "The official Python library for the openai API"
|
description = "The official Python library for the openai API"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7.1"
|
python-versions = ">=3.7.1"
|
||||||
files = [
|
files = [
|
||||||
{file = "openai-1.31.2-py3-none-any.whl", hash = "sha256:203cf21294f347c3d7b591e0ccbe18389d6f8967d4237214b926ea76b1e1781c"},
|
{file = "openai-1.32.0-py3-none-any.whl", hash = "sha256:953d57669f309002044fd2f678aba9f07a43256d74b3b00cd04afb5b185568ea"},
|
||||||
{file = "openai-1.31.2.tar.gz", hash = "sha256:966ab3165b926cb5ec091d2434c90613e2ea8b73ffad984f7fec34bde971725a"},
|
{file = "openai-1.32.0.tar.gz", hash = "sha256:a6df15a7ab9344b1bc2bc8d83639f68b7a7e2453c0f5e50c1666547eee86f0bd"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "langflow"
|
name = "langflow"
|
||||||
version = "1.0.0a46"
|
version = "1.0.0a48"
|
||||||
description = "A Python package with a built-in web application"
|
description = "A Python package with a built-in web application"
|
||||||
authors = ["Langflow <contact@langflow.org>"]
|
authors = ["Langflow <contact@langflow.org>"]
|
||||||
maintainers = [
|
maintainers = [
|
||||||
|
|
|
||||||
|
|
@ -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",
|
|
||||||
]
|
|
||||||
|
|
@ -297,7 +297,7 @@ class CodeParser:
|
||||||
bases = self.execute_and_inspect_classes(self.code)
|
bases = self.execute_and_inspect_classes(self.code)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# If the code cannot be executed, return an empty list
|
# If the code cannot be executed, return an empty list
|
||||||
logger.exception(e)
|
logger.debug(e)
|
||||||
bases = []
|
bases = []
|
||||||
raise e
|
raise e
|
||||||
return bases
|
return bases
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,8 @@ class DirectoryReader:
|
||||||
component_tuple = (*build_component(component), component)
|
component_tuple = (*build_component(component), component)
|
||||||
components.append(component_tuple)
|
components.append(component_tuple)
|
||||||
except Exception as e:
|
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
|
continue
|
||||||
items.append({"name": menu["name"], "path": menu["path"], "components": components})
|
items.append({"name": menu["name"], "path": menu["path"], "components": components})
|
||||||
filtered = [menu for menu in items if menu["components"]]
|
filtered = [menu for menu in items if menu["components"]]
|
||||||
|
|
@ -266,8 +267,7 @@ class DirectoryReader:
|
||||||
if validation_result:
|
if validation_result:
|
||||||
try:
|
try:
|
||||||
output_types = self.get_output_types_from_code(result_content)
|
output_types = self.get_output_types_from_code(result_content)
|
||||||
except Exception as exc:
|
except Exception:
|
||||||
logger.exception(f"Error while getting output types from code: {str(exc)}")
|
|
||||||
output_types = [component_name_camelcase]
|
output_types = [component_name_camelcase]
|
||||||
else:
|
else:
|
||||||
output_types = [component_name_camelcase]
|
output_types = [component_name_camelcase]
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ class MonitorService(Service):
|
||||||
order: Optional[str] = "DESC",
|
order: Optional[str] = "DESC",
|
||||||
limit: Optional[int] = None,
|
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 = []
|
conditions = []
|
||||||
if sender:
|
if sender:
|
||||||
conditions.append(f"sender = '{sender}'")
|
conditions.append(f"sender = '{sender}'")
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "langflow-base"
|
name = "langflow-base"
|
||||||
version = "0.0.58"
|
version = "0.0.59"
|
||||||
description = "A Python package with a built-in web application"
|
description = "A Python package with a built-in web application"
|
||||||
authors = ["Langflow <contact@langflow.org>"]
|
authors = ["Langflow <contact@langflow.org>"]
|
||||||
maintainers = [
|
maintainers = [
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import {
|
||||||
LANGFLOW_SUPPORTED_TYPES,
|
LANGFLOW_SUPPORTED_TYPES,
|
||||||
TOOLTIP_EMPTY,
|
TOOLTIP_EMPTY,
|
||||||
} from "../../../../constants/constants";
|
} from "../../../../constants/constants";
|
||||||
|
import OutputModal from "../../../../customNodes/genericNode/components/outputModal";
|
||||||
import { Case } from "../../../../shared/components/caseComponent";
|
import { Case } from "../../../../shared/components/caseComponent";
|
||||||
import useFlowStore from "../../../../stores/flowStore";
|
import useFlowStore from "../../../../stores/flowStore";
|
||||||
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
|
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 useHandleOnNewValue from "../../../hooks/use-handle-new-value";
|
||||||
import useHandleNodeClass from "../../../hooks/use-handle-node-class";
|
import useHandleNodeClass from "../../../hooks/use-handle-node-class";
|
||||||
import useHandleRefreshButtonPress from "../../../hooks/use-handle-refresh-buttons";
|
import useHandleRefreshButtonPress from "../../../hooks/use-handle-refresh-buttons";
|
||||||
import OutputModal from "../outputModal";
|
|
||||||
import TooltipRenderComponent from "../tooltipRenderComponent";
|
import TooltipRenderComponent from "../tooltipRenderComponent";
|
||||||
import { TEXT_FIELD_TYPES } from "./constants";
|
import { TEXT_FIELD_TYPES } from "./constants";
|
||||||
|
|
||||||
|
|
@ -284,7 +284,7 @@ export default function ParameterComponent({
|
||||||
"h-5 w-5 rounded-md",
|
"h-5 w-5 rounded-md",
|
||||||
displayOutputPreview && !unknownOutput
|
displayOutputPreview && !unknownOutput
|
||||||
? " hover:bg-secondary-foreground/5 hover:text-medium-indigo"
|
? " hover:bg-secondary-foreground/5 hover:text-medium-indigo"
|
||||||
: " cursor-not-allowed text-muted-foreground",
|
: " cursor-not-allowed text-muted-foreground"
|
||||||
)}
|
)}
|
||||||
name={"ScanEye"}
|
name={"ScanEye"}
|
||||||
/>
|
/>
|
||||||
|
|
@ -11,6 +11,8 @@ import {
|
||||||
STATUS_BUILDING,
|
STATUS_BUILDING,
|
||||||
} from "../../constants/constants";
|
} from "../../constants/constants";
|
||||||
import { BuildStatus } from "../../constants/enums";
|
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 NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
|
||||||
import useAlertStore from "../../stores/alertStore";
|
import useAlertStore from "../../stores/alertStore";
|
||||||
import { useDarkStore } from "../../stores/darkStore";
|
import { useDarkStore } from "../../stores/darkStore";
|
||||||
|
|
@ -22,8 +24,6 @@ import { NodeDataType } from "../../types/flow";
|
||||||
import { handleKeyDown, scapedJSONStringfy } from "../../utils/reactflowUtils";
|
import { handleKeyDown, scapedJSONStringfy } from "../../utils/reactflowUtils";
|
||||||
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
|
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
|
||||||
import { classNames, cn } from "../../utils/utils";
|
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 useCheckCodeValidity from "../hooks/use-check-code-validity";
|
||||||
import useIconNodeRender from "../hooks/use-icon-render";
|
import useIconNodeRender from "../hooks/use-icon-render";
|
||||||
import useIconStatus from "../hooks/use-icons-status";
|
import useIconStatus from "../hooks/use-icons-status";
|
||||||
|
|
@ -127,7 +127,7 @@ export default function GenericNode({
|
||||||
const names = classNames(
|
const names = classNames(
|
||||||
baseBorderClass,
|
baseBorderClass,
|
||||||
nodeSizeClass,
|
nodeSizeClass,
|
||||||
"generic-node-div",
|
"generic-node-div group/node",
|
||||||
specificClassFromBuildStatus
|
specificClassFromBuildStatus
|
||||||
);
|
);
|
||||||
return names;
|
return names;
|
||||||
|
|
@ -51,13 +51,15 @@ export default function ErrorAlert({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3">
|
<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?.length !== 0 &&
|
||||||
list?.some((item) => item !== null && item !== undefined) ? (
|
list?.some((item) => item !== null && item !== undefined) ? (
|
||||||
<div className="error-build-message-div">
|
<div className="error-build-message-div">
|
||||||
<ul className="error-build-message-list">
|
<ul className="error-build-message-list">
|
||||||
{list.map((item, index) => (
|
{list.map((item, index) => (
|
||||||
<li key={index}>{item}</li>
|
<li key={index} className="line-clamp-5">
|
||||||
|
{item}
|
||||||
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ export default function NoticeAlert({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3 flex-1 md:flex md:justify-between">
|
<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}
|
{title}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-3 text-sm md:ml-6 md:mt-0">
|
<p className="mt-3 text-sm md:ml-6 md:mt-0">
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ export default function SuccessAlert({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3">
|
<div className="ml-3">
|
||||||
<p className="success-alert-message">{title}</p>
|
<p className="success-alert-message line-clamp-2">{title}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ export default function Header(): JSX.Element {
|
||||||
const lastFlowVisitedIndex = routeHistory
|
const lastFlowVisitedIndex = routeHistory
|
||||||
.reverse()
|
.reverse()
|
||||||
.findIndex(
|
.findIndex(
|
||||||
(path) => path.includes("/flow/") && path !== location.pathname
|
(path) => path.includes("/flow/") && path !== location.pathname,
|
||||||
);
|
);
|
||||||
|
|
||||||
const lastFlowVisited = routeHistory[lastFlowVisitedIndex];
|
const lastFlowVisited = routeHistory[lastFlowVisitedIndex];
|
||||||
|
|
@ -200,6 +200,28 @@ export default function Header(): JSX.Element {
|
||||||
/>
|
/>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent>
|
<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>
|
<DropdownMenuLabel>General</DropdownMenuLabel>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import IconComponent, {
|
||||||
import { Button, buttonVariants } from "../../../ui/button";
|
import { Button, buttonVariants } from "../../../ui/button";
|
||||||
import { Input } from "../../../ui/input";
|
import { Input } from "../../../ui/input";
|
||||||
import useFileDrop from "../../hooks/use-on-file-drop";
|
import useFileDrop from "../../hooks/use-on-file-drop";
|
||||||
|
import useAlertStore from "../../../../stores/alertStore";
|
||||||
|
|
||||||
type SideBarFoldersButtonsComponentProps = {
|
type SideBarFoldersButtonsComponentProps = {
|
||||||
folders: FolderType[];
|
folders: FolderType[];
|
||||||
|
|
@ -51,6 +52,7 @@ const SideBarFoldersButtonsComponent = ({
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const folderId = location?.state?.folderId ?? myCollectionId;
|
const folderId = location?.state?.folderId ?? myCollectionId;
|
||||||
const getFolderById = useFolderStore((state) => state.getFolderById);
|
const getFolderById = useFolderStore((state) => state.getFolderById);
|
||||||
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
|
|
||||||
const handleFolderChange = (folderId: string) => {
|
const handleFolderChange = (folderId: string) => {
|
||||||
getFolderById(folderId);
|
getFolderById(folderId);
|
||||||
|
|
@ -62,7 +64,17 @@ const SideBarFoldersButtonsComponent = ({
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleUploadFlowsToFolder = () => {
|
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) => {
|
const handleDownloadFolder = (id: string) => {
|
||||||
|
|
|
||||||
|
|
@ -668,7 +668,7 @@ export const ZERO_NOTIFICATIONS = "No new notifications";
|
||||||
export const SUCCESS_BUILD = "Built sucessfully ✨";
|
export const SUCCESS_BUILD = "Built sucessfully ✨";
|
||||||
|
|
||||||
export const ALERT_SAVE_WITH_API =
|
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 SAVE_WITH_API_CHECKBOX = "Save with my API keys";
|
||||||
export const EDIT_TEXT_MODAL_TITLE = "Edit Text";
|
export const EDIT_TEXT_MODAL_TITLE = "Edit Text";
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ const ExportModal = forwardRef(
|
||||||
is_component: false,
|
is_component: false,
|
||||||
},
|
},
|
||||||
name!,
|
name!,
|
||||||
description
|
description,
|
||||||
);
|
);
|
||||||
setNoticeData({
|
setNoticeData({
|
||||||
title: API_WARNING_NOTICE_ALERT,
|
title: API_WARNING_NOTICE_ALERT,
|
||||||
|
|
@ -61,7 +61,7 @@ const ExportModal = forwardRef(
|
||||||
is_component: false,
|
is_component: false,
|
||||||
}),
|
}),
|
||||||
name!,
|
name!,
|
||||||
description
|
description,
|
||||||
);
|
);
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
}}
|
}}
|
||||||
|
|
@ -94,7 +94,7 @@ const ExportModal = forwardRef(
|
||||||
{SAVE_WITH_API_CHECKBOX}
|
{SAVE_WITH_API_CHECKBOX}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<span className=" text-xs text-destructive ">
|
<span className="mt-1 text-xs text-destructive ">
|
||||||
{ALERT_SAVE_WITH_API}
|
{ALERT_SAVE_WITH_API}
|
||||||
</span>
|
</span>
|
||||||
</BaseModal.Content>
|
</BaseModal.Content>
|
||||||
|
|
@ -102,6 +102,6 @@ const ExportModal = forwardRef(
|
||||||
<BaseModal.Footer submit={{ label: "Download Flow" }} />
|
<BaseModal.Footer submit={{ label: "Download Flow" }} />
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
export default ExportModal;
|
export default ExportModal;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ import { FormProvider, useForm, useWatch } from "react-hook-form";
|
||||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||||
import CollectionCardComponent from "../../../../components/cardComponent";
|
import CollectionCardComponent from "../../../../components/cardComponent";
|
||||||
import CardsWrapComponent from "../../../../components/cardsWrapComponent";
|
import CardsWrapComponent from "../../../../components/cardsWrapComponent";
|
||||||
import IconComponent from "../../../../components/genericIconComponent";
|
import IconComponent, {
|
||||||
|
ForwardedIconComponent,
|
||||||
|
} from "../../../../components/genericIconComponent";
|
||||||
import PaginatorComponent from "../../../../components/paginatorComponent";
|
import PaginatorComponent from "../../../../components/paginatorComponent";
|
||||||
import { SkeletonCardComponent } from "../../../../components/skeletonCardComponent";
|
import { SkeletonCardComponent } from "../../../../components/skeletonCardComponent";
|
||||||
import { Button } from "../../../../components/ui/button";
|
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 { sortFlows } from "../../utils/sort-flows";
|
||||||
import EmptyComponent from "../emptyComponent";
|
import EmptyComponent from "../emptyComponent";
|
||||||
import HeaderComponent from "../headerComponent";
|
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({
|
export default function ComponentsComponent({
|
||||||
type = "all",
|
type = "all",
|
||||||
|
|
@ -31,22 +36,22 @@ export default function ComponentsComponent({
|
||||||
const allFlows = useFlowsManagerStore((state) => state.allFlows);
|
const allFlows = useFlowsManagerStore((state) => state.allFlows);
|
||||||
|
|
||||||
const flowsFromFolder = useFolderStore(
|
const flowsFromFolder = useFolderStore(
|
||||||
(state) => state.selectedFolder?.flows
|
(state) => state.selectedFolder?.flows,
|
||||||
);
|
);
|
||||||
|
|
||||||
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
const [openDelete, setOpenDelete] = useState(false);
|
const [openDelete, setOpenDelete] = useState(false);
|
||||||
const searchFlowsComponents = useFlowsManagerStore(
|
const searchFlowsComponents = useFlowsManagerStore(
|
||||||
(state) => state.searchFlowsComponents
|
(state) => state.searchFlowsComponents,
|
||||||
);
|
);
|
||||||
|
|
||||||
const setSelectedFlowsComponentsCards = useFlowsManagerStore(
|
const setSelectedFlowsComponentsCards = useFlowsManagerStore(
|
||||||
(state) => state.setSelectedFlowsComponentsCards
|
(state) => state.setSelectedFlowsComponentsCards,
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectedFlowsComponentsCards = useFlowsManagerStore(
|
const selectedFlowsComponentsCards = useFlowsManagerStore(
|
||||||
(state) => state.selectedFlowsComponentsCards
|
(state) => state.selectedFlowsComponentsCards,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [handleFileDrop] = useFileDrop(uploadFlow, type)!;
|
const [handleFileDrop] = useFileDrop(uploadFlow, type)!;
|
||||||
|
|
@ -82,7 +87,7 @@ export default function ComponentsComponent({
|
||||||
f.name.toLowerCase().includes(searchFlowsComponents.toLowerCase()) ||
|
f.name.toLowerCase().includes(searchFlowsComponents.toLowerCase()) ||
|
||||||
f.description
|
f.description
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.includes(searchFlowsComponents.toLowerCase())
|
.includes(searchFlowsComponents.toLowerCase()),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (searchFlowsComponents === "") {
|
if (searchFlowsComponents === "") {
|
||||||
|
|
@ -129,6 +134,8 @@ export default function ComponentsComponent({
|
||||||
setOpenDelete(true);
|
setOpenDelete(true);
|
||||||
} else if (action === "duplicate") {
|
} else if (action === "duplicate") {
|
||||||
handleDuplicate();
|
handleDuplicate();
|
||||||
|
} else if (action === "export") {
|
||||||
|
handleExport();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -137,9 +144,9 @@ export default function ComponentsComponent({
|
||||||
selectedFlowsComponentsCards.map((selectedFlow) =>
|
selectedFlowsComponentsCards.map((selectedFlow) =>
|
||||||
addFlow(
|
addFlow(
|
||||||
true,
|
true,
|
||||||
allFlows.find((flow) => flow.id === selectedFlow)
|
allFlows.find((flow) => flow.id === selectedFlow),
|
||||||
)
|
),
|
||||||
)
|
),
|
||||||
).then(() => {
|
).then(() => {
|
||||||
resetFilter();
|
resetFilter();
|
||||||
getFoldersApi(true);
|
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 = () => {
|
const handleDeleteMultiple = () => {
|
||||||
removeFlow(selectedFlowsComponentsCards)
|
removeFlow(selectedFlowsComponentsCards)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
@ -161,7 +209,7 @@ export default function ComponentsComponent({
|
||||||
getFolderById(folderId ? folderId : myCollectionId);
|
getFolderById(folderId ? folderId : myCollectionId);
|
||||||
}
|
}
|
||||||
setSuccessData({
|
setSuccessData({
|
||||||
title: "Selected items deleted successfully!",
|
title: "Selected items deleted successfully",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
|
@ -180,7 +228,7 @@ export default function ComponentsComponent({
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
setSelectedFlowsComponentsCards(selectedFlows);
|
setSelectedFlowsComponentsCards(selectedFlows);
|
||||||
|
|
@ -215,20 +263,23 @@ export default function ComponentsComponent({
|
||||||
if (type === "all") return allFlows?.length;
|
if (type === "all") return allFlows?.length;
|
||||||
|
|
||||||
return allFlows?.filter(
|
return allFlows?.filter(
|
||||||
(f) => (f.is_component ?? false) === (type === "component")
|
(f) => (f.is_component ?? false) === (type === "component"),
|
||||||
)?.length;
|
)?.length;
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{allFlows?.length > 0 && (
|
<div className="flex w-full gap-4 pb-5">
|
||||||
<HeaderComponent
|
{allFlows?.length > 0 && (
|
||||||
handleDelete={() => handleSelectOptionsChange("delete")}
|
<HeaderComponent
|
||||||
handleSelectAll={handleSelectAll}
|
handleDelete={() => handleSelectOptionsChange("delete")}
|
||||||
handleDuplicate={() => handleSelectOptionsChange("duplicate")}
|
handleSelectAll={handleSelectAll}
|
||||||
disableFunctions={!(selectedFlowsComponentsCards?.length > 0)}
|
handleDuplicate={() => handleSelectOptionsChange("duplicate")}
|
||||||
/>
|
handleExport={() => handleSelectOptionsChange("export")}
|
||||||
)}
|
disableFunctions={!(selectedFlowsComponentsCards?.length > 0)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<CardsWrapComponent
|
<CardsWrapComponent
|
||||||
onFileDrop={handleFileDrop}
|
onFileDrop={handleFileDrop}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ const EmptyComponent = ({}: EmptyComponentProps) => {
|
||||||
|
|
||||||
return (
|
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="flex-max-width h-full flex-col">
|
||||||
<div className="align-center flex w-full justify-center gap-1 ">
|
<div className="align-center flex w-full justify-center gap-1 ">
|
||||||
<span className="text-muted-foreground">
|
<span className="text-muted-foreground">
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,17 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import IconComponent from "../../../../components/genericIconComponent";
|
import IconComponent, {
|
||||||
|
ForwardedIconComponent,
|
||||||
|
} from "../../../../components/genericIconComponent";
|
||||||
import ShadTooltip from "../../../../components/shadTooltipComponent";
|
import ShadTooltip from "../../../../components/shadTooltipComponent";
|
||||||
import { Checkbox } from "../../../../components/ui/checkbox";
|
import { Checkbox } from "../../../../components/ui/checkbox";
|
||||||
import { cn } from "../../../../utils/utils";
|
import { cn } from "../../../../utils/utils";
|
||||||
|
import { Button } from "../../../../components/ui/button";
|
||||||
|
|
||||||
type HeaderComponentProps = {
|
type HeaderComponentProps = {
|
||||||
handleSelectAll: (select) => void;
|
handleSelectAll: (select) => void;
|
||||||
handleDelete: () => void;
|
handleDelete: () => void;
|
||||||
handleDuplicate: () => void;
|
handleDuplicate: () => void;
|
||||||
|
handleExport: () => void;
|
||||||
disableFunctions: boolean;
|
disableFunctions: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -15,6 +19,7 @@ const HeaderComponent = ({
|
||||||
handleSelectAll,
|
handleSelectAll,
|
||||||
handleDelete,
|
handleDelete,
|
||||||
handleDuplicate,
|
handleDuplicate,
|
||||||
|
handleExport,
|
||||||
disableFunctions,
|
disableFunctions,
|
||||||
}: HeaderComponentProps) => {
|
}: HeaderComponentProps) => {
|
||||||
const [shouldSelectAll, setShouldSelectAll] = useState(true);
|
const [shouldSelectAll, setShouldSelectAll] = useState(true);
|
||||||
|
|
@ -26,29 +31,46 @@ const HeaderComponent = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="grid grid-cols-3 pb-5">
|
<div className="flex w-full items-center justify-between gap-4">
|
||||||
<div className="col-auto grid-cols-1 self-center justify-self-start">
|
<div className="flex items-center justify-self-start">
|
||||||
<a onClick={handleClick} className="text-sm">
|
<Button
|
||||||
<div className="header-menu-bar-display ">
|
variant="none"
|
||||||
<div
|
size="none"
|
||||||
className="header-menu-flow-name"
|
onClick={handleClick}
|
||||||
data-testid="select_all_collection"
|
className="text-sm"
|
||||||
>
|
>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Checkbox checked={!shouldSelectAll} id="terms" />
|
<Checkbox checked={!shouldSelectAll} id="terms" />
|
||||||
<label
|
<span className="label text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
|
||||||
onClick={handleClick}
|
{shouldSelectAll ? "Select All" : "Unselect All"}
|
||||||
htmlFor="terms"
|
</span>
|
||||||
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>
|
</div>
|
||||||
</a>
|
</Button>
|
||||||
</div>
|
</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>
|
<div>
|
||||||
<ShadTooltip
|
<ShadTooltip
|
||||||
content={
|
content={
|
||||||
|
|
@ -59,12 +81,17 @@ const HeaderComponent = ({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<button onClick={handleDuplicate} disabled={disableFunctions}>
|
<Button
|
||||||
|
variant="none"
|
||||||
|
size="none"
|
||||||
|
onClick={handleDuplicate}
|
||||||
|
disabled={disableFunctions}
|
||||||
|
>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="Copy"
|
name="Copy"
|
||||||
className={cn("h-5 w-5 text-primary transition-all")}
|
className={cn("h-5 w-5 text-primary transition-all")}
|
||||||
/>
|
/>
|
||||||
</button>
|
</Button>
|
||||||
</ShadTooltip>
|
</ShadTooltip>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -77,15 +104,20 @@ const HeaderComponent = ({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<button onClick={handleDelete} disabled={disableFunctions}>
|
<Button
|
||||||
|
variant="none"
|
||||||
|
size="none"
|
||||||
|
onClick={handleDelete}
|
||||||
|
disabled={disableFunctions}
|
||||||
|
>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="Trash2"
|
name="Trash2"
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-5 w-5 text-primary transition-all",
|
"h-5 w-5 text-primary transition-all",
|
||||||
disableFunctions ? "" : "hover:text-destructive"
|
disableFunctions ? "" : "hover:text-destructive",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</button>
|
</Button>
|
||||||
</ShadTooltip>
|
</ShadTooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
||||||
export default function SettingsPage(): JSX.Element {
|
export default function SettingsPage(): JSX.Element {
|
||||||
const pathname = location.pathname;
|
const pathname = location.pathname;
|
||||||
const setCurrentFlowId = useFlowsManagerStore(
|
const setCurrentFlowId = useFlowsManagerStore(
|
||||||
(state) => state.setCurrentFlowId
|
(state) => state.setCurrentFlowId,
|
||||||
);
|
);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setCurrentFlowId("");
|
setCurrentFlowId("");
|
||||||
|
|
@ -59,7 +59,10 @@ export default function SettingsPage(): JSX.Element {
|
||||||
title: "Messages",
|
title: "Messages",
|
||||||
href: "/settings/messages",
|
href: "/settings/messages",
|
||||||
icon: (
|
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]">
|
<aside className="flex h-full shrink-0 flex-col space-y-6 lg:w-[20vw]">
|
||||||
<SidebarNav items={sidebarNavItems} />
|
<SidebarNav items={sidebarNavItems} />
|
||||||
</aside>
|
</aside>
|
||||||
<div className="h-full w-full flex-1 pb-8">
|
<div className="flex h-full w-full flex-1 flex-col">
|
||||||
<Outlet />
|
<div className="flex-1 pb-8">
|
||||||
|
<Outlet />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
|
|
|
||||||
|
|
@ -52,23 +52,17 @@ export default function ApiKeysPage() {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="flex h-full w-full flex-col justify-between">
|
<div className="flex h-full w-full flex-col justify-between">
|
||||||
<Card x-chunk="dashboard-04-chunk-2" className="h-full pt-4">
|
<TableComponent
|
||||||
<CardContent className="h-full">
|
overlayNoRowsTemplate="No data available"
|
||||||
<TableComponent
|
onSelectionChanged={(event: SelectionChangedEvent) => {
|
||||||
overlayNoRowsTemplate="No data available"
|
setSelectedRows(event.api.getSelectedRows().map((row) => row.id));
|
||||||
onSelectionChanged={(event: SelectionChangedEvent) => {
|
}}
|
||||||
setSelectedRows(
|
rowSelection="multiple"
|
||||||
event.api.getSelectedRows().map((row) => row.id),
|
suppressRowClickSelection={true}
|
||||||
);
|
pagination={true}
|
||||||
}}
|
columnDefs={columnDefs}
|
||||||
rowSelection="multiple"
|
rowData={keysList.current}
|
||||||
suppressRowClickSelection={true}
|
/>
|
||||||
pagination={true}
|
|
||||||
columnDefs={columnDefs}
|
|
||||||
rowData={keysList.current}
|
|
||||||
/>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,13 @@ import { cn } from "../../../../utils/utils";
|
||||||
|
|
||||||
export default function GlobalVariablesPage() {
|
export default function GlobalVariablesPage() {
|
||||||
const globalVariablesEntries = useGlobalVariablesStore(
|
const globalVariablesEntries = useGlobalVariablesStore(
|
||||||
(state) => state.globalVariablesEntries
|
(state) => state.globalVariablesEntries,
|
||||||
);
|
);
|
||||||
const removeGlobalVariable = useGlobalVariablesStore(
|
const removeGlobalVariable = useGlobalVariablesStore(
|
||||||
(state) => state.removeGlobalVariable
|
(state) => state.removeGlobalVariable,
|
||||||
);
|
);
|
||||||
const globalVariables = useGlobalVariablesStore(
|
const globalVariables = useGlobalVariablesStore(
|
||||||
(state) => state.globalVariables
|
(state) => state.globalVariables,
|
||||||
);
|
);
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
const getVariableId = useGlobalVariablesStore((state) => state.getVariableId);
|
const getVariableId = useGlobalVariablesStore((state) => state.getVariableId);
|
||||||
|
|
@ -154,7 +154,7 @@ export default function GlobalVariablesPage() {
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="Trash2"
|
name="Trash2"
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-5 w-5 text-destructive group-disabled:text-primary"
|
"h-5 w-5 text-destructive group-disabled:text-primary",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -168,23 +168,17 @@ export default function GlobalVariablesPage() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex h-full w-full flex-col justify-between">
|
<div className="flex h-full w-full flex-col justify-between">
|
||||||
<Card x-chunk="dashboard-04-chunk-2" className="h-full pt-4">
|
<TableComponent
|
||||||
<CardContent className="h-full">
|
overlayNoRowsTemplate="No data available"
|
||||||
<TableComponent
|
onSelectionChanged={(event: SelectionChangedEvent) => {
|
||||||
overlayNoRowsTemplate="No data available"
|
setSelectedRows(event.api.getSelectedRows().map((row) => row.name));
|
||||||
onSelectionChanged={(event: SelectionChangedEvent) => {
|
}}
|
||||||
setSelectedRows(
|
rowSelection="multiple"
|
||||||
event.api.getSelectedRows().map((row) => row.name)
|
suppressRowClickSelection={true}
|
||||||
);
|
pagination={true}
|
||||||
}}
|
columnDefs={colDefs}
|
||||||
rowSelection="multiple"
|
rowData={rowData}
|
||||||
suppressRowClickSelection={true}
|
/>
|
||||||
pagination={true}
|
|
||||||
columnDefs={colDefs}
|
|
||||||
rowData={rowData}
|
|
||||||
/>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -115,15 +115,11 @@ export default function ShortcutsPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex h-full w-full flex-col justify-between">
|
<div className="flex h-full w-full flex-col justify-between">
|
||||||
<Card x-chunk="dashboard-04-chunk-2" className="h-full pt-4">
|
<TableComponent
|
||||||
<CardContent className="h-full">
|
pagination={false}
|
||||||
<TableComponent
|
columnDefs={colDefs}
|
||||||
pagination={false}
|
rowData={nodesRowData}
|
||||||
columnDefs={colDefs}
|
/>
|
||||||
rowData={nodesRowData}
|
|
||||||
/>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export default function MessagesPage() {
|
||||||
setSelectedRows,
|
setSelectedRows,
|
||||||
setSuccessData,
|
setSuccessData,
|
||||||
setErrorData,
|
setErrorData,
|
||||||
selectedRows
|
selectedRows,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { handleUpdate } = useUpdateMessage(setSuccessData, setErrorData);
|
const { handleUpdate } = useUpdateMessage(setSuccessData, setErrorData);
|
||||||
|
|
@ -52,29 +52,25 @@ export default function MessagesPage() {
|
||||||
handleRemoveMessages={handleRemoveMessages}
|
handleRemoveMessages={handleRemoveMessages}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="flex h-full w-full flex-col justify-between pb-8">
|
<div className="flex h-full w-full flex-col justify-between">
|
||||||
<Card x-chunk="dashboard-04-chunk-2" className="h-full pt-4">
|
<TableComponent
|
||||||
<CardContent className="h-full">
|
readOnlyEdit
|
||||||
<TableComponent
|
onCellEditRequest={(event) => {
|
||||||
readOnlyEdit
|
handleUpdateMessage(event);
|
||||||
onCellEditRequest={(event) => {
|
}}
|
||||||
handleUpdateMessage(event);
|
editable={["Sender Name", "Message"]}
|
||||||
}}
|
overlayNoRowsTemplate="No data available"
|
||||||
editable={["Sender Name", "Message"]}
|
onSelectionChanged={(event: SelectionChangedEvent) => {
|
||||||
overlayNoRowsTemplate="No data available"
|
setSelectedRows(
|
||||||
onSelectionChanged={(event: SelectionChangedEvent) => {
|
event.api.getSelectedRows().map((row) => row.index),
|
||||||
setSelectedRows(
|
);
|
||||||
event.api.getSelectedRows().map((row) => row.index)
|
}}
|
||||||
);
|
rowSelection="multiple"
|
||||||
}}
|
suppressRowClickSelection={true}
|
||||||
rowSelection="multiple"
|
pagination={true}
|
||||||
suppressRowClickSelection={true}
|
columnDefs={columns}
|
||||||
pagination={true}
|
rowData={messages}
|
||||||
columnDefs={columns}
|
/>
|
||||||
rowData={messages}
|
|
||||||
/>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import {
|
||||||
} from "../pages/MainPage/services";
|
} from "../pages/MainPage/services";
|
||||||
import { FoldersStoreType } from "../types/zustand/folders";
|
import { FoldersStoreType } from "../types/zustand/folders";
|
||||||
import useFlowsManagerStore from "./flowsManagerStore";
|
import useFlowsManagerStore from "./flowsManagerStore";
|
||||||
|
import { uploadFlowsToDatabase } from "../controllers/API";
|
||||||
|
|
||||||
export const useFolderStore = create<FoldersStoreType>((set, get) => ({
|
export const useFolderStore = create<FoldersStoreType>((set, get) => ({
|
||||||
folders: [],
|
folders: [],
|
||||||
|
|
@ -17,18 +18,18 @@ export const useFolderStore = create<FoldersStoreType>((set, get) => ({
|
||||||
getFolders().then(
|
getFolders().then(
|
||||||
(res) => {
|
(res) => {
|
||||||
const foldersWithoutStarterProjects = res.filter(
|
const foldersWithoutStarterProjects = res.filter(
|
||||||
(folder) => folder.name !== STARTER_FOLDER_NAME
|
(folder) => folder.name !== STARTER_FOLDER_NAME,
|
||||||
);
|
);
|
||||||
|
|
||||||
const starterProjects = res.find(
|
const starterProjects = res.find(
|
||||||
(folder) => folder.name === STARTER_FOLDER_NAME
|
(folder) => folder.name === STARTER_FOLDER_NAME,
|
||||||
);
|
);
|
||||||
|
|
||||||
set({ starterProjectId: starterProjects!.id ?? "" });
|
set({ starterProjectId: starterProjects!.id ?? "" });
|
||||||
set({ folders: foldersWithoutStarterProjects });
|
set({ folders: foldersWithoutStarterProjects });
|
||||||
|
|
||||||
const myCollectionId = res?.find(
|
const myCollectionId = res?.find(
|
||||||
(f) => f.name === DEFAULT_FOLDER
|
(f) => f.name === DEFAULT_FOLDER,
|
||||||
)?.id;
|
)?.id;
|
||||||
|
|
||||||
set({ myCollectionId });
|
set({ myCollectionId });
|
||||||
|
|
@ -45,7 +46,7 @@ export const useFolderStore = create<FoldersStoreType>((set, get) => ({
|
||||||
set({ folders: [] });
|
set({ folders: [] });
|
||||||
get().setLoading(false);
|
get().setLoading(false);
|
||||||
reject();
|
reject();
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -65,7 +66,7 @@ export const useFolderStore = create<FoldersStoreType>((set, get) => ({
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
get().setLoadingById(false);
|
get().setLoadingById(false);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -100,7 +101,7 @@ export const useFolderStore = create<FoldersStoreType>((set, get) => ({
|
||||||
folderIdDragging: "",
|
folderIdDragging: "",
|
||||||
setFolderIdDragging: (id) => set(() => ({ folderIdDragging: id })),
|
setFolderIdDragging: (id) => set(() => ({ folderIdDragging: id })),
|
||||||
uploadFolder: () => {
|
uploadFolder: () => {
|
||||||
return new Promise<void>(() => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
const input = document.createElement("input");
|
const input = document.createElement("input");
|
||||||
input.type = "file";
|
input.type = "file";
|
||||||
input.onchange = (event: Event) => {
|
input.onchange = (event: Event) => {
|
||||||
|
|
@ -111,8 +112,31 @@ export const useFolderStore = create<FoldersStoreType>((set, get) => ({
|
||||||
const file = (event.target as HTMLInputElement).files![0];
|
const file = (event.target as HTMLInputElement).files![0];
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("file", file);
|
formData.append("file", file);
|
||||||
uploadFlowsFromFolders(formData).then(() => {
|
file.text().then((text) => {
|
||||||
get().getFoldersApi(true);
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ export type FoldersStoreType = {
|
||||||
setFolderUrl: (folderUrl: string) => void;
|
setFolderUrl: (folderUrl: string) => void;
|
||||||
folderDragging: boolean;
|
folderDragging: boolean;
|
||||||
setFolderDragging: (set: boolean) => void;
|
setFolderDragging: (set: boolean) => void;
|
||||||
uploadFolder: (folderId: string) => void;
|
uploadFolder: (folderId: string) => Promise<void>;
|
||||||
folderIdDragging: string;
|
folderIdDragging: string;
|
||||||
setFolderIdDragging: (id: string) => void;
|
setFolderIdDragging: (id: string) => void;
|
||||||
starterProjectId: string;
|
starterProjectId: string;
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ import {
|
||||||
FolderIcon,
|
FolderIcon,
|
||||||
FolderPlus,
|
FolderPlus,
|
||||||
FolderPlusIcon,
|
FolderPlusIcon,
|
||||||
|
FolderUp,
|
||||||
FormInput,
|
FormInput,
|
||||||
Forward,
|
Forward,
|
||||||
Gift,
|
Gift,
|
||||||
|
|
@ -433,6 +434,7 @@ export const nodeIconsLucide: iconsType = {
|
||||||
ChevronLeft,
|
ChevronLeft,
|
||||||
SlidersHorizontal,
|
SlidersHorizontal,
|
||||||
Palette,
|
Palette,
|
||||||
|
FolderUp,
|
||||||
Blocks,
|
Blocks,
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
ArrowLeft,
|
ArrowLeft,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue