Merge branch 'dev' into fix_group_graph
This commit is contained in:
commit
4056cddd5a
44 changed files with 564 additions and 289 deletions
53
Makefile
53
Makefile
|
|
@ -47,20 +47,22 @@ init:
|
||||||
|
|
||||||
|
|
||||||
coverage: ## run the tests and generate a coverage report
|
coverage: ## run the tests and generate a coverage report
|
||||||
poetry run pytest --cov \
|
@poetry run coverage run
|
||||||
--cov-config=.coveragerc \
|
@poetry run coverage erase
|
||||||
--cov-report xml \
|
|
||||||
--cov-report term-missing:skip-covered \
|
|
||||||
--cov-report lcov:coverage/lcov-pytest.info
|
|
||||||
|
|
||||||
|
|
||||||
# allow passing arguments to pytest
|
# allow passing arguments to pytest
|
||||||
unit_tests:
|
unit_tests:
|
||||||
poetry run pytest --ignore=tests/integration --instafail -ra -n auto -m "not api_key_required" $(args)
|
poetry run pytest \
|
||||||
|
--ignore=tests/integration \
|
||||||
|
--instafail -ra -n auto -m "not api_key_required" \
|
||||||
|
$(args)
|
||||||
|
|
||||||
|
|
||||||
integration_tests:
|
integration_tests:
|
||||||
poetry run pytest tests/integration --instafail -ra -n auto $(args)
|
poetry run pytest tests/integration \
|
||||||
|
--instafail -ra -n auto \
|
||||||
|
$(args)
|
||||||
|
|
||||||
format: ## run code formatters
|
format: ## run code formatters
|
||||||
poetry run ruff check . --fix
|
poetry run ruff check . --fix
|
||||||
|
|
@ -129,9 +131,20 @@ start:
|
||||||
@echo 'Running the CLI'
|
@echo 'Running the CLI'
|
||||||
|
|
||||||
ifeq ($(open_browser),false)
|
ifeq ($(open_browser),false)
|
||||||
@make install_backend && poetry run langflow run --path $(path) --log-level $(log_level) --host $(host) --port $(port) --env-file $(env) --no-open-browser
|
@make install_backend && poetry run langflow run \
|
||||||
|
--path $(path) \
|
||||||
|
--log-level $(log_level) \
|
||||||
|
--host $(host) \
|
||||||
|
--port $(port) \
|
||||||
|
--env-file $(env) \
|
||||||
|
--no-open-browser
|
||||||
else
|
else
|
||||||
@make install_backend && poetry run langflow run --path $(path) --log-level $(log_level) --host $(host) --port $(port) --env-file $(env)
|
@make install_backend && poetry run langflow run \
|
||||||
|
--path $(path) \
|
||||||
|
--log-level $(log_level) \
|
||||||
|
--host $(host) \
|
||||||
|
--port $(port) \
|
||||||
|
--env-file $(env)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -166,13 +179,27 @@ backend: ## run the backend in development mode
|
||||||
@echo 'Setting up the environment'
|
@echo 'Setting up the environment'
|
||||||
@make setup_env
|
@make setup_env
|
||||||
make install_backend
|
make install_backend
|
||||||
@-kill -9 $(lsof -t -i:7860)
|
@-kill -9 $$(lsof -t -i:7860)
|
||||||
ifdef login
|
ifdef login
|
||||||
@echo "Running backend autologin is $(login)";
|
@echo "Running backend autologin is $(login)";
|
||||||
LANGFLOW_AUTO_LOGIN=$(login) poetry run uvicorn --factory langflow.main:create_app --host 0.0.0.0 --port 7860 --reload --env-file .env --loop asyncio --workers $(workers)
|
LANGFLOW_AUTO_LOGIN=$(login) poetry run uvicorn \
|
||||||
|
--factory langflow.main:create_app \
|
||||||
|
--host 0.0.0.0 \
|
||||||
|
--port $(port) \
|
||||||
|
--reload \
|
||||||
|
--env-file $(env) \
|
||||||
|
--loop asyncio \
|
||||||
|
--workers $(workers)
|
||||||
else
|
else
|
||||||
@echo "Running backend respecting the .env file";
|
@echo "Running backend respecting the $(env) file";
|
||||||
poetry run uvicorn --factory langflow.main:create_app --host 0.0.0.0 --port 7860 --reload --env-file .env --loop asyncio --workers $(workers)
|
poetry run uvicorn \
|
||||||
|
--factory langflow.main:create_app \
|
||||||
|
--host 0.0.0.0 \
|
||||||
|
--port $(port) \
|
||||||
|
--reload \
|
||||||
|
--env-file $(env) \
|
||||||
|
--loop asyncio \
|
||||||
|
--workers $(workers)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,28 @@ log_cli = true
|
||||||
markers = ["async_test", "api_key_required"]
|
markers = ["async_test", "api_key_required"]
|
||||||
|
|
||||||
|
|
||||||
|
[tool.coverage.run]
|
||||||
|
command_line = """
|
||||||
|
-m pytest
|
||||||
|
--cov --cov-report=term --cov-report=html
|
||||||
|
--instafail -ra -n auto -m "not api_key_required"
|
||||||
|
tests/unit
|
||||||
|
"""
|
||||||
|
source = ["src/backend/base/langflow/"]
|
||||||
|
omit = ["*/alembic/*", "tests/*", "*/__init__.py"]
|
||||||
|
|
||||||
|
|
||||||
|
[tool.coverage.report]
|
||||||
|
sort = "Stmts"
|
||||||
|
skip_empty = true
|
||||||
|
show_missing = false
|
||||||
|
ignore_errors = true
|
||||||
|
|
||||||
|
|
||||||
|
[tool.coverage.html]
|
||||||
|
directory = "coverage"
|
||||||
|
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
exclude = ["src/backend/langflow/alembic/*"]
|
exclude = ["src/backend/langflow/alembic/*"]
|
||||||
line-length = 120
|
line-length = 120
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,14 @@ import {
|
||||||
} from "../../constants/constants";
|
} from "../../constants/constants";
|
||||||
import useAlertStore from "../../stores/alertStore";
|
import useAlertStore from "../../stores/alertStore";
|
||||||
import { ResponseErrorDetailAPI } from "../../types/api";
|
import { ResponseErrorDetailAPI } from "../../types/api";
|
||||||
|
import { NodeDataType } from "../../types/flow";
|
||||||
|
|
||||||
const useFetchDataOnMount = (
|
const useFetchDataOnMount = (
|
||||||
data,
|
data: NodeDataType,
|
||||||
name,
|
name: string,
|
||||||
handleUpdateValues,
|
handleUpdateValues: (name: string, data: NodeDataType) => Promise<any>,
|
||||||
setNode,
|
setNode: (id: string, callback: (oldNode: any) => any) => void,
|
||||||
setIsLoading,
|
setIsLoading: (value: boolean) => void,
|
||||||
) => {
|
) => {
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,16 @@ import {
|
||||||
} from "../../constants/constants";
|
} from "../../constants/constants";
|
||||||
import useAlertStore from "../../stores/alertStore";
|
import useAlertStore from "../../stores/alertStore";
|
||||||
import { ResponseErrorTypeAPI } from "../../types/api";
|
import { ResponseErrorTypeAPI } from "../../types/api";
|
||||||
|
import { NodeDataType } from "../../types/flow";
|
||||||
|
|
||||||
const useHandleOnNewValue = (
|
const useHandleOnNewValue = (
|
||||||
data,
|
data: NodeDataType,
|
||||||
name,
|
name: string,
|
||||||
takeSnapshot,
|
takeSnapshot: () => void,
|
||||||
handleUpdateValues,
|
handleUpdateValues: (name: string, data: NodeDataType) => Promise<any>,
|
||||||
debouncedHandleUpdateValues,
|
debouncedHandleUpdateValues: any,
|
||||||
setNode,
|
setNode: (id: string, callback: (oldNode: any) => any) => void,
|
||||||
setIsLoading,
|
setIsLoading: (value: boolean) => void,
|
||||||
) => {
|
) => {
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
|
import { NodeDataType } from "../../types/flow";
|
||||||
|
|
||||||
const useHandleNodeClass = (
|
const useHandleNodeClass = (
|
||||||
data,
|
data: NodeDataType,
|
||||||
name,
|
name: string,
|
||||||
takeSnapshot,
|
takeSnapshot: () => void,
|
||||||
setNode,
|
setNode: (id: string, callback: (oldNode: any) => any) => void,
|
||||||
updateNodeInternals,
|
updateNodeInternals: (id: string) => void,
|
||||||
) => {
|
) => {
|
||||||
const handleNodeClass = (newNodeClass, code, type?: string) => {
|
const handleNodeClass = (newNodeClass, code, type?: string) => {
|
||||||
if (!data.node) return;
|
if (!data.node) return;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,10 @@ import useAlertStore from "../../stores/alertStore";
|
||||||
import { ResponseErrorDetailAPI } from "../../types/api";
|
import { ResponseErrorDetailAPI } from "../../types/api";
|
||||||
import { handleUpdateValues } from "../../utils/parameterUtils";
|
import { handleUpdateValues } from "../../utils/parameterUtils";
|
||||||
|
|
||||||
const useHandleRefreshButtonPress = (setIsLoading, setNode) => {
|
const useHandleRefreshButtonPress = (
|
||||||
|
setIsLoading: (value: boolean) => void,
|
||||||
|
setNode: (id: string, callback: (oldNode: any) => any) => void,
|
||||||
|
) => {
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
|
|
||||||
const handleRefreshButtonPress = async (name, data) => {
|
const handleRefreshButtonPress = async (name, data) => {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
import { FlowPoolType } from "../../types/zustand/flow";
|
||||||
|
|
||||||
const useUpdateValidationStatus = (dataId, flowPool, setValidationStatus) => {
|
const useUpdateValidationStatus = (
|
||||||
|
dataId: string,
|
||||||
|
flowPool: FlowPoolType,
|
||||||
|
setValidationStatus: (value: any) => void,
|
||||||
|
) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const relevantData =
|
const relevantData =
|
||||||
flowPool[dataId] && flowPool[dataId]?.length > 0
|
flowPool[dataId] && flowPool[dataId]?.length > 0
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { isErrorLog } from "../../types/utils/typeCheckingUtils";
|
||||||
|
|
||||||
const useValidationStatusString = (
|
const useValidationStatusString = (
|
||||||
validationStatus: VertexBuildTypeAPI | null,
|
validationStatus: VertexBuildTypeAPI | null,
|
||||||
setValidationString,
|
setValidationString: (value: any) => void,
|
||||||
) => {
|
) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (validationStatus && validationStatus.data?.outputs) {
|
if (validationStatus && validationStatus.data?.outputs) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { storeComponent } from "../../../types/store";
|
||||||
|
|
||||||
|
const useDataEffect = (
|
||||||
|
data: storeComponent,
|
||||||
|
setLikedByUser: (value: any) => void,
|
||||||
|
setLikesCount: (value: any) => void,
|
||||||
|
setDownloadsCount: (value: any) => void,
|
||||||
|
) => {
|
||||||
|
useEffect(() => {
|
||||||
|
if (data) {
|
||||||
|
setLikedByUser(data?.liked_by_user ?? false);
|
||||||
|
setLikesCount(data?.liked_by_count ?? 0);
|
||||||
|
setDownloadsCount(data?.downloads_count ?? 0);
|
||||||
|
}
|
||||||
|
}, [data, data?.liked_by_count, data?.liked_by_user, data?.downloads_count]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useDataEffect;
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
import { useState } from "react";
|
||||||
|
import { getComponent } from "../../../controllers/API";
|
||||||
|
import useFlowsManagerStore from "../../../stores/flowsManagerStore";
|
||||||
|
import { storeComponent } from "../../../types/store";
|
||||||
|
import cloneFlowWithParent from "../../../utils/storeUtils";
|
||||||
|
|
||||||
|
const useInstallComponent = (
|
||||||
|
data: storeComponent,
|
||||||
|
name: string,
|
||||||
|
isStore: boolean,
|
||||||
|
downloadsCount: number,
|
||||||
|
setDownloadsCount: (value: any) => void,
|
||||||
|
setLoading: (value: boolean) => void,
|
||||||
|
setSuccessData: (value: { title: string }) => void,
|
||||||
|
setErrorData: (value: { title: string; list: string[] }) => void,
|
||||||
|
) => {
|
||||||
|
const addFlow = useFlowsManagerStore((state) => state.addFlow);
|
||||||
|
|
||||||
|
const handleInstall = () => {
|
||||||
|
const temp = downloadsCount;
|
||||||
|
setDownloadsCount((old) => Number(old) + 1);
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
getComponent(data.id)
|
||||||
|
.then((res) => {
|
||||||
|
const newFlow = cloneFlowWithParent(res, res.id, data.is_component);
|
||||||
|
addFlow(true, newFlow)
|
||||||
|
.then((id) => {
|
||||||
|
setSuccessData({
|
||||||
|
title: `${name} ${isStore ? "Downloaded" : "Installed"} Successfully.`,
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setLoading(false);
|
||||||
|
setErrorData({
|
||||||
|
title: `Error ${isStore ? "downloading" : "installing"} the ${name}`,
|
||||||
|
list: [error.response.data.detail],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
setLoading(false);
|
||||||
|
setErrorData({
|
||||||
|
title: `Error ${isStore ? "downloading" : "installing"} the ${name}`,
|
||||||
|
list: [err.response.data.detail],
|
||||||
|
});
|
||||||
|
setDownloadsCount(temp);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return { handleInstall };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useInstallComponent;
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { postLikeComponent } from "../../../controllers/API";
|
||||||
|
import { storeComponent } from "../../../types/store";
|
||||||
|
|
||||||
|
const useLikeComponent = (
|
||||||
|
data: storeComponent,
|
||||||
|
name: string,
|
||||||
|
setLoadingLike: (value: boolean) => void,
|
||||||
|
likedByUser: boolean | null | undefined,
|
||||||
|
likesCount: number,
|
||||||
|
setLikedByUser: (value: any) => void,
|
||||||
|
setLikesCount: (value: any) => void,
|
||||||
|
setValidApiKey: (value: boolean) => void,
|
||||||
|
setErrorData: (value: { title: string; list: string[] }) => void,
|
||||||
|
) => {
|
||||||
|
const handleLike = () => {
|
||||||
|
setLoadingLike(true);
|
||||||
|
if (likedByUser !== undefined || likedByUser !== null) {
|
||||||
|
const temp = likedByUser;
|
||||||
|
const tempNum = likesCount;
|
||||||
|
setLikedByUser((prev) => !prev);
|
||||||
|
setLikesCount((prev) => (temp ? prev - 1 : prev + 1));
|
||||||
|
|
||||||
|
postLikeComponent(data.id)
|
||||||
|
.then((response) => {
|
||||||
|
setLoadingLike(false);
|
||||||
|
setLikesCount(response.data.likes_count);
|
||||||
|
setLikedByUser(response.data.liked_by_user);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setLoadingLike(false);
|
||||||
|
setLikesCount(tempNum);
|
||||||
|
setLikedByUser(temp);
|
||||||
|
if (error.response.status === 403) {
|
||||||
|
setValidApiKey(false);
|
||||||
|
} else {
|
||||||
|
console.error(error);
|
||||||
|
setErrorData({
|
||||||
|
title: `Error liking ${name}.`,
|
||||||
|
list: [error.response.data.detail],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleLike,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useLikeComponent;
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
import { useCallback } from "react";
|
||||||
|
import { createRoot } from "react-dom/client";
|
||||||
|
import useFlowsManagerStore from "../../../stores/flowsManagerStore";
|
||||||
|
import { storeComponent } from "../../../types/store";
|
||||||
|
import DragCardComponent from "../components/dragCardComponent";
|
||||||
|
|
||||||
|
const useDragStart = (data: storeComponent) => {
|
||||||
|
const getFlowById = useFlowsManagerStore((state) => state.getFlowById);
|
||||||
|
|
||||||
|
const onDragStart = useCallback(
|
||||||
|
(event) => {
|
||||||
|
let image = <DragCardComponent data={data} />; // Replace with whatever you want here
|
||||||
|
|
||||||
|
const ghost = document.createElement("div");
|
||||||
|
ghost.style.transform = "translate(-10000px, -10000px)";
|
||||||
|
ghost.style.position = "absolute";
|
||||||
|
document.body.appendChild(ghost);
|
||||||
|
event.dataTransfer.setDragImage(ghost, 0, 0);
|
||||||
|
|
||||||
|
const root = createRoot(ghost);
|
||||||
|
root.render(image);
|
||||||
|
|
||||||
|
const flow = getFlowById(data.id);
|
||||||
|
if (flow) {
|
||||||
|
event.dataTransfer.setData("flow", JSON.stringify(data));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[data],
|
||||||
|
);
|
||||||
|
|
||||||
|
return { onDragStart };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useDragStart;
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { FlowType } from "../../../types/flow";
|
||||||
|
|
||||||
|
const usePlaygroundEffect = (
|
||||||
|
currentFlowId: string,
|
||||||
|
playground: boolean,
|
||||||
|
openPlayground: boolean,
|
||||||
|
currentFlow: FlowType | undefined,
|
||||||
|
setNodes: (value: any, value2: boolean) => void,
|
||||||
|
setEdges: (value: any, value2: boolean) => void,
|
||||||
|
cleanFlowPool: () => void,
|
||||||
|
) => {
|
||||||
|
useEffect(() => {
|
||||||
|
if (currentFlowId && playground) {
|
||||||
|
if (openPlayground) {
|
||||||
|
setNodes(currentFlow?.data?.nodes ?? [], true);
|
||||||
|
setEdges(currentFlow?.data?.edges ?? [], true);
|
||||||
|
} else {
|
||||||
|
setNodes([], true);
|
||||||
|
setEdges([], true);
|
||||||
|
}
|
||||||
|
cleanFlowPool();
|
||||||
|
}
|
||||||
|
}, [openPlayground]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default usePlaygroundEffect;
|
||||||
|
|
@ -28,6 +28,11 @@ import { Checkbox } from "../ui/checkbox";
|
||||||
import { FormControl, FormField } from "../ui/form";
|
import { FormControl, FormField } from "../ui/form";
|
||||||
import Loading from "../ui/loading";
|
import Loading from "../ui/loading";
|
||||||
import DragCardComponent from "./components/dragCardComponent";
|
import DragCardComponent from "./components/dragCardComponent";
|
||||||
|
import useDataEffect from "./hooks/use-data-effect";
|
||||||
|
import useInstallComponent from "./hooks/use-handle-install";
|
||||||
|
import useLikeComponent from "./hooks/use-handle-like";
|
||||||
|
import useDragStart from "./hooks/use-on-drag-start";
|
||||||
|
import usePlaygroundEffect from "./hooks/use-playground-effect";
|
||||||
import { convertTestName } from "./utils/convert-test-name";
|
import { convertTestName } from "./utils/convert-test-name";
|
||||||
|
|
||||||
export default function CollectionCardComponent({
|
export default function CollectionCardComponent({
|
||||||
|
|
@ -59,11 +64,9 @@ export default function CollectionCardComponent({
|
||||||
const isStore = false;
|
const isStore = false;
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [loadingLike, setLoadingLike] = useState(false);
|
const [loadingLike, setLoadingLike] = useState(false);
|
||||||
const [liked_by_user, setLiked_by_user] = useState(
|
const [likedByUser, setLikedByUser] = useState(data?.liked_by_user ?? false);
|
||||||
data?.liked_by_user ?? false,
|
const [likesCount, setLikesCount] = useState(data?.liked_by_count ?? 0);
|
||||||
);
|
const [downloadsCount, setDownloadsCount] = useState(
|
||||||
const [likes_count, setLikes_count] = useState(data?.liked_by_count ?? 0);
|
|
||||||
const [downloads_count, setDownloads_count] = useState(
|
|
||||||
data?.downloads_count ?? 0,
|
data?.downloads_count ?? 0,
|
||||||
);
|
);
|
||||||
const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
|
const currentFlow = useFlowsManagerStore((state) => state.currentFlow);
|
||||||
|
|
@ -99,115 +102,45 @@ export default function CollectionCardComponent({
|
||||||
return inputs.length > 0 || outputs.length > 0;
|
return inputs.length > 0 || outputs.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
usePlaygroundEffect(
|
||||||
if (currentFlowId && playground) {
|
currentFlowId,
|
||||||
if (openPlayground) {
|
playground!,
|
||||||
setNodes(currentFlow?.data?.nodes ?? [], true);
|
openPlayground,
|
||||||
setEdges(currentFlow?.data?.edges ?? [], true);
|
currentFlow,
|
||||||
} else {
|
setNodes,
|
||||||
setNodes([], true);
|
setEdges,
|
||||||
setEdges([], true);
|
cleanFlowPool,
|
||||||
}
|
);
|
||||||
cleanFlowPool();
|
|
||||||
}
|
|
||||||
}, [openPlayground]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useDataEffect(data, setLikedByUser, setLikesCount, setDownloadsCount);
|
||||||
if (data) {
|
|
||||||
setLiked_by_user(data?.liked_by_user ?? false);
|
|
||||||
setLikes_count(data?.liked_by_count ?? 0);
|
|
||||||
setDownloads_count(data?.downloads_count ?? 0);
|
|
||||||
}
|
|
||||||
}, [data, data.liked_by_count, data.liked_by_user, data.downloads_count]);
|
|
||||||
|
|
||||||
function handleInstall() {
|
const { handleInstall } = useInstallComponent(
|
||||||
const temp = downloads_count;
|
data,
|
||||||
setDownloads_count((old) => Number(old) + 1);
|
name,
|
||||||
setLoading(true);
|
isStore,
|
||||||
getComponent(data.id)
|
downloadsCount,
|
||||||
.then((res) => {
|
setDownloadsCount,
|
||||||
const newFlow = cloneFLowWithParent(res, res.id, data.is_component);
|
setLoading,
|
||||||
addFlow(true, newFlow)
|
setSuccessData,
|
||||||
.then((id) => {
|
setErrorData,
|
||||||
setSuccessData({
|
);
|
||||||
title: `${name} ${
|
|
||||||
isStore ? "Downloaded" : "Installed"
|
|
||||||
} Successfully.`,
|
|
||||||
});
|
|
||||||
setLoading(false);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
setLoading(false);
|
|
||||||
setErrorData({
|
|
||||||
title: `Error ${
|
|
||||||
isStore ? "downloading" : "installing"
|
|
||||||
} the ${name}`,
|
|
||||||
list: [error["response"]["data"]["detail"]],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
setLoading(false);
|
|
||||||
setErrorData({
|
|
||||||
title: `Error ${isStore ? "downloading" : "installing"} the ${name}`,
|
|
||||||
list: [err["response"]["data"]["detail"]],
|
|
||||||
});
|
|
||||||
setDownloads_count(temp);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleLike() {
|
const { handleLike } = useLikeComponent(
|
||||||
setLoadingLike(true);
|
data,
|
||||||
if (liked_by_user !== undefined || liked_by_user !== null) {
|
name,
|
||||||
const temp = liked_by_user;
|
setLoadingLike,
|
||||||
const tempNum = likes_count;
|
likedByUser,
|
||||||
setLiked_by_user((prev) => !prev);
|
likesCount,
|
||||||
if (!temp) {
|
setLikedByUser,
|
||||||
setLikes_count((prev) => Number(prev) + 1);
|
setLikesCount,
|
||||||
} else {
|
setValidApiKey,
|
||||||
setLikes_count((prev) => Number(prev) - 1);
|
setErrorData,
|
||||||
}
|
);
|
||||||
postLikeComponent(data.id)
|
|
||||||
.then((response) => {
|
|
||||||
setLoadingLike(false);
|
|
||||||
setLikes_count(response.data.likes_count);
|
|
||||||
setLiked_by_user(response.data.liked_by_user);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
setLoadingLike(false);
|
|
||||||
setLikes_count(tempNum);
|
|
||||||
setLiked_by_user(temp);
|
|
||||||
if (error.response.status === 403) {
|
|
||||||
setValidApiKey(false);
|
|
||||||
} else {
|
|
||||||
console.error(error);
|
|
||||||
setErrorData({
|
|
||||||
title: `Error liking ${name}.`,
|
|
||||||
list: [error["response"]["data"]["detail"]],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const isSelectedCard =
|
const isSelectedCard =
|
||||||
selectedFlowsComponentsCards?.includes(data?.id) ?? false;
|
selectedFlowsComponentsCards?.includes(data?.id) ?? false;
|
||||||
|
|
||||||
function onDragStart(event: React.DragEvent<any>) {
|
const { onDragStart } = useDragStart(data);
|
||||||
let image: JSX.Element = <DragCardComponent data={data} />; // <== whatever you want here
|
|
||||||
|
|
||||||
var ghost = document.createElement("div");
|
|
||||||
ghost.style.transform = "translate(-10000px, -10000px)";
|
|
||||||
ghost.style.position = "absolute";
|
|
||||||
document.body.appendChild(ghost);
|
|
||||||
event.dataTransfer.setDragImage(ghost, 0, 0);
|
|
||||||
const root = createRoot(ghost);
|
|
||||||
root.render(image);
|
|
||||||
const flow = getFlowById(data.id);
|
|
||||||
if (flow) {
|
|
||||||
event.dataTransfer.setData("flow", JSON.stringify(data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -264,7 +197,7 @@ export default function CollectionCardComponent({
|
||||||
<span className="flex items-center gap-1.5 text-xs text-muted-foreground">
|
<span className="flex items-center gap-1.5 text-xs text-muted-foreground">
|
||||||
<IconComponent name="Heart" className={cn("h-4 w-4")} />
|
<IconComponent name="Heart" className={cn("h-4 w-4")} />
|
||||||
<span data-testid={`likes-${data.name}`}>
|
<span data-testid={`likes-${data.name}`}>
|
||||||
{likes_count ?? 0}
|
{likesCount ?? 0}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</ShadTooltip>
|
</ShadTooltip>
|
||||||
|
|
@ -275,7 +208,7 @@ export default function CollectionCardComponent({
|
||||||
className="h-4 w-4"
|
className="h-4 w-4"
|
||||||
/>
|
/>
|
||||||
<span data-testid={`downloads-${data.name}`}>
|
<span data-testid={`downloads-${data.name}`}>
|
||||||
{downloads_count ?? 0}
|
{downloadsCount ?? 0}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</ShadTooltip>
|
</ShadTooltip>
|
||||||
|
|
@ -324,20 +257,7 @@ export default function CollectionCardComponent({
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
<div className="flex w-full flex-1 flex-wrap gap-2">
|
<div className="flex w-full flex-1 flex-wrap gap-2"></div>
|
||||||
{/* {data.tags &&
|
|
||||||
data.tags.length > 0 &&
|
|
||||||
data.tags.map((tag, index) => (
|
|
||||||
<Badge
|
|
||||||
key={index}
|
|
||||||
variant="outline"
|
|
||||||
size="xq"
|
|
||||||
className="text-muted-foreground"
|
|
||||||
>
|
|
||||||
{tag.name}
|
|
||||||
</Badge>
|
|
||||||
))} */}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CardDescription className="pb-2 pt-2">
|
<CardDescription className="pb-2 pt-2">
|
||||||
|
|
@ -457,7 +377,7 @@ export default function CollectionCardComponent({
|
||||||
name="Heart"
|
name="Heart"
|
||||||
className={cn(
|
className={cn(
|
||||||
"h-5 w-5",
|
"h-5 w-5",
|
||||||
liked_by_user
|
likedByUser
|
||||||
? "fill-destructive stroke-destructive"
|
? "fill-destructive stroke-destructive"
|
||||||
: "",
|
: "",
|
||||||
!authorized ? "text-ring" : "",
|
!authorized ? "text-ring" : "",
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,10 @@ import useFlowsManagerStore from "../../../stores/flowsManagerStore";
|
||||||
import { useFolderStore } from "../../../stores/foldersStore";
|
import { useFolderStore } from "../../../stores/foldersStore";
|
||||||
import { addVersionToDuplicates } from "../../../utils/reactflowUtils";
|
import { addVersionToDuplicates } from "../../../utils/reactflowUtils";
|
||||||
|
|
||||||
const useFileDrop = (folderId, folderChangeCallback) => {
|
const useFileDrop = (
|
||||||
|
folderId: string,
|
||||||
|
folderChangeCallback: (folderId: string) => void,
|
||||||
|
) => {
|
||||||
const setFolderDragging = useFolderStore((state) => state.setFolderDragging);
|
const setFolderDragging = useFolderStore((state) => state.setFolderDragging);
|
||||||
const setFolderIdDragging = useFolderStore(
|
const setFolderIdDragging = useFolderStore(
|
||||||
(state) => state.setFolderIdDragging,
|
(state) => state.setFolderIdDragging,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
const useAutoResizeTextArea = (value, inputRef) => {
|
const useAutoResizeTextArea = (
|
||||||
|
value: string,
|
||||||
|
inputRef: React.RefObject<HTMLInputElement>,
|
||||||
|
) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (inputRef.current && inputRef.current.scrollHeight! !== 0) {
|
if (inputRef.current && inputRef.current.scrollHeight! !== 0) {
|
||||||
inputRef.current.style!.height = "inherit"; // Reset the height
|
inputRef.current.style!.height = "inherit"; // Reset the height
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@ import {
|
||||||
import useFileUpload from "./use-file-upload";
|
import useFileUpload from "./use-file-upload";
|
||||||
|
|
||||||
const useDragAndDrop = (
|
const useDragAndDrop = (
|
||||||
setIsDragging,
|
setIsDragging: (value: boolean) => void,
|
||||||
setFiles,
|
setFiles: (value: any) => void,
|
||||||
currentFlowId,
|
currentFlowId: string,
|
||||||
setErrorData,
|
setErrorData: (value: any) => void,
|
||||||
) => {
|
) => {
|
||||||
const dragOver = (e) => {
|
const dragOver = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
const useFocusOnUnlock = (lockChat, inputRef) => {
|
const useFocusOnUnlock = (
|
||||||
|
lockChat: boolean,
|
||||||
|
inputRef: React.RefObject<HTMLInputElement>,
|
||||||
|
) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!lockChat && inputRef.current) {
|
if (!lockChat && inputRef.current) {
|
||||||
inputRef.current.focus();
|
inputRef.current.focus();
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { AxiosResponse } from "axios";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import ShortUniqueId from "short-unique-id";
|
import ShortUniqueId from "short-unique-id";
|
||||||
import {
|
import {
|
||||||
|
|
@ -6,9 +7,18 @@ import {
|
||||||
SN_ERROR_TEXT,
|
SN_ERROR_TEXT,
|
||||||
} from "../../../../../../constants/constants";
|
} from "../../../../../../constants/constants";
|
||||||
import useAlertStore from "../../../../../../stores/alertStore";
|
import useAlertStore from "../../../../../../stores/alertStore";
|
||||||
|
import { UploadFileTypeAPI } from "../../../../../../types/api";
|
||||||
import useFileUpload from "./use-file-upload";
|
import useFileUpload from "./use-file-upload";
|
||||||
|
|
||||||
const useUpload = (uploadFile, currentFlowId, setFiles, lockChat) => {
|
const useUpload = (
|
||||||
|
uploadFile: (
|
||||||
|
file: File,
|
||||||
|
id: string,
|
||||||
|
) => Promise<AxiosResponse<UploadFileTypeAPI>>,
|
||||||
|
currentFlowId: string,
|
||||||
|
setFiles: any,
|
||||||
|
lockChat: boolean,
|
||||||
|
) => {
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handlePaste = (event: ClipboardEvent): void => {
|
const handlePaste = (event: ClipboardEvent): void => {
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,10 @@ import { ColDef, ValueGetterParams } from "ag-grid-community";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import TableNodeCellRender from "../../../components/tableComponent/components/tableNodeCellRender";
|
import TableNodeCellRender from "../../../components/tableComponent/components/tableNodeCellRender";
|
||||||
import TableToggleCellRender from "../../../components/tableComponent/components/tableToggleCellRender";
|
import TableToggleCellRender from "../../../components/tableComponent/components/tableToggleCellRender";
|
||||||
|
import { NodeDataType } from "../../../types/flow";
|
||||||
|
|
||||||
const useColumnDefs = (
|
const useColumnDefs = (
|
||||||
myData: any,
|
myData: NodeDataType,
|
||||||
handleOnNewValue: (newValue: any, name: string) => void,
|
handleOnNewValue: (newValue: any, name: string) => void,
|
||||||
handleOnChangeDb: (value: boolean, key: string) => void,
|
handleOnChangeDb: (value: boolean, key: string) => void,
|
||||||
changeAdvanced: (n: string) => void,
|
changeAdvanced: (n: string) => void,
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { LANGFLOW_SUPPORTED_TYPES } from "../../../constants/constants";
|
import { LANGFLOW_SUPPORTED_TYPES } from "../../../constants/constants";
|
||||||
import { TemplateVariableType } from "../../../types/api";
|
import { NodeDataType } from "../../../types/flow";
|
||||||
|
|
||||||
const useRowData = (myData, open) => {
|
const useRowData = (myData: NodeDataType, open: boolean) => {
|
||||||
const rowData = useMemo(() => {
|
const rowData = useMemo(() => {
|
||||||
return Object.keys(myData.node!.template)
|
return Object.keys(myData.node!.template)
|
||||||
.filter((key: string) => {
|
.filter((key: string) => {
|
||||||
const templateParam = myData.node!.template[
|
const templateParam = myData.node!.template[key] as any;
|
||||||
key
|
|
||||||
] as TemplateVariableType;
|
|
||||||
return (
|
return (
|
||||||
key.charAt(0) !== "_" &&
|
key.charAt(0) !== "_" &&
|
||||||
templateParam.show &&
|
templateParam.show &&
|
||||||
|
|
@ -20,9 +18,7 @@ const useRowData = (myData, open) => {
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.map((key: string) => {
|
.map((key: string) => {
|
||||||
const templateParam = myData.node!.template[
|
const templateParam = myData.node!.template[key] as any;
|
||||||
key
|
|
||||||
] as TemplateVariableType;
|
|
||||||
return {
|
return {
|
||||||
...templateParam,
|
...templateParam,
|
||||||
key: key,
|
key: key,
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,11 @@ const EditNodeModal = forwardRef(
|
||||||
nodeLength,
|
nodeLength,
|
||||||
open,
|
open,
|
||||||
setOpen,
|
setOpen,
|
||||||
// setOpenWDoubleClick,
|
|
||||||
data,
|
data,
|
||||||
}: {
|
}: {
|
||||||
nodeLength: number;
|
nodeLength: number;
|
||||||
open: boolean;
|
open: boolean;
|
||||||
setOpen: (open: boolean) => void;
|
setOpen: (open: boolean) => void;
|
||||||
// setOpenWDoubleClick: (open: boolean) => void;
|
|
||||||
data: NodeDataType;
|
data: NodeDataType;
|
||||||
},
|
},
|
||||||
ref,
|
ref,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
import React from "react";
|
||||||
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
|
import CollectionCardComponent from "../../../../../../components/cardComponent";
|
||||||
|
import IconComponent from "../../../../../../components/genericIconComponent";
|
||||||
|
import { Button } from "../../../../../../components/ui/button";
|
||||||
|
const CollectionCard = ({ item, type, isLoading, control }) => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const isComponent = item.is_component ?? false;
|
||||||
|
const editFlowLink = `/flow/${item.id}`;
|
||||||
|
const editFlowButtonTestId = `edit-flow-button-${item.id}`;
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
if (!isComponent) {
|
||||||
|
navigate(editFlowLink);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderButton = () => {
|
||||||
|
if (!isComponent) {
|
||||||
|
return (
|
||||||
|
<Link to={editFlowLink}>
|
||||||
|
<Button
|
||||||
|
tabIndex={-1}
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
className="whitespace-nowrap"
|
||||||
|
data-testid={editFlowButtonTestId}
|
||||||
|
>
|
||||||
|
<IconComponent
|
||||||
|
name="ExternalLink"
|
||||||
|
className="main-page-nav-button select-none"
|
||||||
|
/>
|
||||||
|
Edit Flow
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CollectionCardComponent
|
||||||
|
is_component={type === "component"}
|
||||||
|
data={{
|
||||||
|
is_component: isComponent,
|
||||||
|
...item,
|
||||||
|
}}
|
||||||
|
disabled={isLoading}
|
||||||
|
data-testid={editFlowButtonTestId}
|
||||||
|
button={renderButton()!}
|
||||||
|
onClick={!isComponent ? handleClick : undefined}
|
||||||
|
playground={!isComponent}
|
||||||
|
control={control}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CollectionCard;
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
|
|
||||||
const useDeleteMultipleFlows = (
|
const useDeleteMultipleFlows = (
|
||||||
selectedFlowsComponentsCards,
|
selectedFlowsComponentsCards: string[],
|
||||||
removeFlow,
|
removeFlow: (selectedFlowsComponentsCards: string[]) => Promise<void>,
|
||||||
resetFilter,
|
resetFilter: () => void,
|
||||||
getFoldersApi,
|
getFoldersApi: (refetch?: boolean) => Promise<void>,
|
||||||
folderId,
|
folderId: string | undefined,
|
||||||
myCollectionId,
|
myCollectionId: string,
|
||||||
getFolderById,
|
getFolderById: (id: string) => void,
|
||||||
setSuccessData,
|
setSuccessData: (data: { title: string }) => void,
|
||||||
setErrorData,
|
setErrorData: (data: { title: string; list: string[] }) => void,
|
||||||
) => {
|
) => {
|
||||||
const handleDeleteMultiple = useCallback(() => {
|
const handleDeleteMultiple = useCallback(() => {
|
||||||
removeFlow(selectedFlowsComponentsCards)
|
removeFlow(selectedFlowsComponentsCards)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|
||||||
const useDescriptionModal = (selectedFlowsComponentsCards, type) => {
|
const useDescriptionModal = (
|
||||||
|
selectedFlowsComponentsCards: string[] | undefined,
|
||||||
|
type: string | undefined,
|
||||||
|
) => {
|
||||||
const getDescriptionModal = useMemo(() => {
|
const getDescriptionModal = useMemo(() => {
|
||||||
const getTypeLabel = (type) => {
|
const getTypeLabel = (type) => {
|
||||||
const labels = {
|
const labels = {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import cloneDeep from "lodash/cloneDeep";
|
import cloneDeep from "lodash/cloneDeep";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
import { FlowType } from "../../../../../types/flow";
|
||||||
|
|
||||||
const useFilteredFlows = (
|
const useFilteredFlows = (
|
||||||
flowsFromFolder,
|
flowsFromFolder: FlowType[],
|
||||||
searchFlowsComponents,
|
searchFlowsComponents: string,
|
||||||
setAllFlows,
|
setAllFlows: (value: any[]) => void,
|
||||||
) => {
|
) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const newFlows = cloneDeep(flowsFromFolder || []);
|
const newFlows = cloneDeep(flowsFromFolder || []);
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,31 @@
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
|
import { XYPosition } from "reactflow";
|
||||||
|
import { FlowType } from "../../../../../types/flow";
|
||||||
|
|
||||||
const useDuplicateFlows = (
|
const useDuplicateFlows = (
|
||||||
selectedFlowsComponentsCards,
|
selectedFlowsComponentsCards: string[],
|
||||||
addFlow,
|
addFlow: (
|
||||||
allFlows,
|
newProject: boolean,
|
||||||
resetFilter,
|
flow?: FlowType,
|
||||||
getFoldersApi,
|
override?: boolean,
|
||||||
folderId,
|
position?: XYPosition,
|
||||||
myCollectionId,
|
fromDragAndDrop?: boolean,
|
||||||
getFolderById,
|
) => Promise<string | undefined>,
|
||||||
setSuccessData,
|
allFlows: any[],
|
||||||
setSelectedFlowsComponentsCards,
|
resetFilter: () => void,
|
||||||
handleSelectAll,
|
getFoldersApi: (
|
||||||
cardTypes,
|
refetch?: boolean,
|
||||||
|
startupApplication?: boolean,
|
||||||
|
) => Promise<void>,
|
||||||
|
folderId: string,
|
||||||
|
myCollectionId: string,
|
||||||
|
getFolderById: (id: string) => void,
|
||||||
|
setSuccessData: (data: { title: string }) => void,
|
||||||
|
setSelectedFlowsComponentsCards: (
|
||||||
|
selectedFlowsComponentsCards: string[],
|
||||||
|
) => void,
|
||||||
|
handleSelectAll: (select: boolean) => void,
|
||||||
|
cardTypes: string,
|
||||||
) => {
|
) => {
|
||||||
const handleDuplicate = useCallback(() => {
|
const handleDuplicate = useCallback(() => {
|
||||||
Promise.all(
|
Promise.all(
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,18 @@
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
|
import { FlowType } from "../../../../../types/flow";
|
||||||
|
|
||||||
const useExportFlows = (
|
const useExportFlows = (
|
||||||
selectedFlowsComponentsCards,
|
selectedFlowsComponentsCards: string[],
|
||||||
allFlows,
|
allFlows: Array<FlowType>,
|
||||||
downloadFlow,
|
downloadFlow: (flow: any, name: string, description: string) => void,
|
||||||
removeApiKeys,
|
removeApiKeys: (flow: any) => any,
|
||||||
version,
|
version: string,
|
||||||
setSuccessData,
|
setSuccessData: (data: { title: string }) => void,
|
||||||
setSelectedFlowsComponentsCards,
|
setSelectedFlowsComponentsCards: (
|
||||||
handleSelectAll,
|
selectedFlowsComponentsCards: string[],
|
||||||
cardTypes,
|
) => void,
|
||||||
|
handleSelectAll: (select: boolean) => void,
|
||||||
|
cardTypes: string,
|
||||||
) => {
|
) => {
|
||||||
const handleExport = useCallback(() => {
|
const handleExport = useCallback(() => {
|
||||||
selectedFlowsComponentsCards.forEach((selectedFlowId) => {
|
selectedFlowsComponentsCards.forEach((selectedFlowId) => {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
|
import { FlowType } from "../../../../../types/flow";
|
||||||
|
|
||||||
const useSelectAll = (flowsFromFolder, getValues, setValue) => {
|
const useSelectAll = (
|
||||||
|
flowsFromFolder: FlowType[],
|
||||||
|
getValues: () => Record<string, boolean>,
|
||||||
|
setValue: (key: string, value: boolean) => void,
|
||||||
|
) => {
|
||||||
const handleSelectAll = useCallback(
|
const handleSelectAll = useCallback(
|
||||||
(select) => {
|
(select) => {
|
||||||
const flowsFromFolderIds = flowsFromFolder?.map((f) => f.id);
|
const flowsFromFolderIds = flowsFromFolder?.map((f) => f.id);
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
|
|
||||||
const useSelectOptionsChange = (
|
const useSelectOptionsChange = (
|
||||||
selectedFlowsComponentsCards,
|
selectedFlowsComponentsCards: string[] | undefined,
|
||||||
setErrorData,
|
setErrorData: (data: { title: string; list: string[] }) => void,
|
||||||
setOpenDelete,
|
setOpenDelete: (value: boolean) => void,
|
||||||
handleDuplicate,
|
handleDuplicate: () => void,
|
||||||
handleExport,
|
handleExport: () => void,
|
||||||
) => {
|
) => {
|
||||||
const handleSelectOptionsChange = useCallback(
|
const handleSelectOptionsChange = useCallback(
|
||||||
(action) => {
|
(action) => {
|
||||||
const hasSelected = selectedFlowsComponentsCards?.length > 0;
|
const hasSelected = selectedFlowsComponentsCards?.length! > 0;
|
||||||
if (!hasSelected) {
|
if (!hasSelected) {
|
||||||
setErrorData({
|
setErrorData({
|
||||||
title: "No items selected",
|
title: "No items selected",
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
const useSelectedFlows = (
|
const useSelectedFlows = (
|
||||||
entireFormValues,
|
entireFormValues: Record<string, boolean> | undefined,
|
||||||
setSelectedFlowsComponentsCards,
|
setSelectedFlowsComponentsCards: (
|
||||||
|
selectedFlowsComponentsCards: string[],
|
||||||
|
) => void,
|
||||||
) => {
|
) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!entireFormValues || Object.keys(entireFormValues).length === 0) return;
|
if (!entireFormValues || Object.keys(entireFormValues).length === 0) return;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ 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 CollectionCard from "./components/collectionCard";
|
||||||
import useDeleteMultipleFlows from "./hooks/use-delete-multiple";
|
import useDeleteMultipleFlows from "./hooks/use-delete-multiple";
|
||||||
import useDescriptionModal from "./hooks/use-description-modal";
|
import useDescriptionModal from "./hooks/use-description-modal";
|
||||||
import useFilteredFlows from "./hooks/use-filtered-flows";
|
import useFilteredFlows from "./hooks/use-filtered-flows";
|
||||||
|
|
@ -61,7 +62,6 @@ export default function ComponentsComponent({
|
||||||
const [handleFileDrop] = useFileDrop(uploadFlow, type)!;
|
const [handleFileDrop] = useFileDrop(uploadFlow, type)!;
|
||||||
const [pageSize, setPageSize] = useState(20);
|
const [pageSize, setPageSize] = useState(20);
|
||||||
const [pageIndex, setPageIndex] = useState(1);
|
const [pageIndex, setPageIndex] = useState(1);
|
||||||
const navigate = useNavigate();
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const all: FlowType[] = sortFlows(allFlows, type);
|
const all: FlowType[] = sortFlows(allFlows, type);
|
||||||
const start = (pageIndex - 1) * pageSize;
|
const start = (pageIndex - 1) * pageSize;
|
||||||
|
|
@ -94,7 +94,7 @@ export default function ComponentsComponent({
|
||||||
getFolderById(folderId ? folderId : myCollectionId);
|
getFolderById(folderId ? folderId : myCollectionId);
|
||||||
}, [location]);
|
}, [location]);
|
||||||
|
|
||||||
useFilteredFlows(flowsFromFolder, searchFlowsComponents, setAllFlows);
|
useFilteredFlows(flowsFromFolder!, searchFlowsComponents, setAllFlows);
|
||||||
|
|
||||||
const resetFilter = () => {
|
const resetFilter = () => {
|
||||||
setPageIndex(1);
|
setPageIndex(1);
|
||||||
|
|
@ -107,7 +107,7 @@ export default function ComponentsComponent({
|
||||||
const methods = useForm();
|
const methods = useForm();
|
||||||
|
|
||||||
const { handleSelectAll } = useSelectAll(
|
const { handleSelectAll } = useSelectAll(
|
||||||
flowsFromFolder,
|
flowsFromFolder!,
|
||||||
getValues,
|
getValues,
|
||||||
setValue,
|
setValue,
|
||||||
);
|
);
|
||||||
|
|
@ -119,7 +119,7 @@ export default function ComponentsComponent({
|
||||||
resetFilter,
|
resetFilter,
|
||||||
getFoldersApi,
|
getFoldersApi,
|
||||||
folderId,
|
folderId,
|
||||||
myCollectionId,
|
myCollectionId!,
|
||||||
getFolderById,
|
getFolderById,
|
||||||
setSuccessData,
|
setSuccessData,
|
||||||
setSelectedFlowsComponentsCards,
|
setSelectedFlowsComponentsCards,
|
||||||
|
|
@ -155,7 +155,7 @@ export default function ComponentsComponent({
|
||||||
resetFilter,
|
resetFilter,
|
||||||
getFoldersApi,
|
getFoldersApi,
|
||||||
folderId,
|
folderId,
|
||||||
myCollectionId,
|
myCollectionId!,
|
||||||
getFolderById,
|
getFolderById,
|
||||||
setSuccessData,
|
setSuccessData,
|
||||||
setErrorData,
|
setErrorData,
|
||||||
|
|
@ -205,43 +205,10 @@ export default function ComponentsComponent({
|
||||||
{data?.map((item) => (
|
{data?.map((item) => (
|
||||||
<FormProvider {...methods} key={item.id}>
|
<FormProvider {...methods} key={item.id}>
|
||||||
<form>
|
<form>
|
||||||
<CollectionCardComponent
|
<CollectionCard
|
||||||
is_component={type === "component"}
|
item={item}
|
||||||
data={{
|
type={type}
|
||||||
is_component: item.is_component ?? false,
|
isLoading={isLoading}
|
||||||
...item,
|
|
||||||
}}
|
|
||||||
disabled={isLoading}
|
|
||||||
data-testid={"edit-flow-button-" + item.id}
|
|
||||||
button={
|
|
||||||
!item.is_component ? (
|
|
||||||
<Link to={"/flow/" + item.id}>
|
|
||||||
<Button
|
|
||||||
tabIndex={-1}
|
|
||||||
variant="outline"
|
|
||||||
size="sm"
|
|
||||||
className="whitespace-nowrap"
|
|
||||||
data-testid={"edit-flow-button-" + item.id}
|
|
||||||
>
|
|
||||||
<IconComponent
|
|
||||||
name="ExternalLink"
|
|
||||||
className="main-page-nav-button select-none"
|
|
||||||
/>
|
|
||||||
Edit Flow
|
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
onClick={
|
|
||||||
!item.is_component
|
|
||||||
? () => {
|
|
||||||
navigate("/flow/" + item.id);
|
|
||||||
}
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
playground={!item.is_component}
|
|
||||||
control={control}
|
control={control}
|
||||||
/>
|
/>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import useAlertStore from "../../../stores/alertStore";
|
||||||
import { useFolderStore } from "../../../stores/foldersStore";
|
import { useFolderStore } from "../../../stores/foldersStore";
|
||||||
import { deleteFolder, getFolderById } from "../services";
|
import { deleteFolder, getFolderById } from "../services";
|
||||||
|
|
||||||
const useDeleteFolder = ({ navigate }) => {
|
const useDeleteFolder = ({ navigate }: { navigate: (url: string) => void }) => {
|
||||||
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 folderToEdit = useFolderStore((state) => state.folderToEdit);
|
const folderToEdit = useFolderStore((state) => state.folderToEdit);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,26 @@
|
||||||
|
import { XYPosition } from "reactflow";
|
||||||
import { CONSOLE_ERROR_MSG } from "../../../constants/alerts_constants";
|
import { CONSOLE_ERROR_MSG } from "../../../constants/alerts_constants";
|
||||||
import useAlertStore from "../../../stores/alertStore";
|
import useAlertStore from "../../../stores/alertStore";
|
||||||
|
|
||||||
const useDropdownOptions = ({ uploadFlow, navigate, is_component }) => {
|
const useDropdownOptions = ({
|
||||||
|
uploadFlow,
|
||||||
|
navigate,
|
||||||
|
is_component,
|
||||||
|
}: {
|
||||||
|
uploadFlow: ({
|
||||||
|
newProject,
|
||||||
|
file,
|
||||||
|
isComponent,
|
||||||
|
position,
|
||||||
|
}: {
|
||||||
|
newProject: boolean;
|
||||||
|
file?: File;
|
||||||
|
isComponent: boolean | null;
|
||||||
|
position?: XYPosition;
|
||||||
|
}) => Promise<string | never>;
|
||||||
|
navigate: (url: string) => void;
|
||||||
|
is_component: boolean;
|
||||||
|
}) => {
|
||||||
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
const setSuccessData = useAlertStore((state) => state.setSuccessData);
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
const handleImportFromJSON = () => {
|
const handleImportFromJSON = () => {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
import { getApiKey } from "../../../../../controllers/API";
|
import { getApiKey } from "../../../../../controllers/API";
|
||||||
|
import { Users } from "../../../../../types/api";
|
||||||
|
|
||||||
const useApiKeys = (userData, setLoadingKeys, keysList, setUserId) => {
|
const useApiKeys = (
|
||||||
|
userData: Users | null,
|
||||||
|
setLoadingKeys: (load: boolean) => void,
|
||||||
|
keysList: React.MutableRefObject<never[]>,
|
||||||
|
setUserId: (userId: string) => void,
|
||||||
|
) => {
|
||||||
const fetchApiKeys = () => {
|
const fetchApiKeys = () => {
|
||||||
setLoadingKeys(true);
|
setLoadingKeys(true);
|
||||||
getApiKey()
|
getApiKey()
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@ import {
|
||||||
import { deleteApiKey } from "../../../../../controllers/API";
|
import { deleteApiKey } from "../../../../../controllers/API";
|
||||||
|
|
||||||
const useDeleteApiKeys = (
|
const useDeleteApiKeys = (
|
||||||
selectedRows,
|
selectedRows: string[],
|
||||||
resetFilter,
|
resetFilter: () => void,
|
||||||
setSuccessData,
|
setSuccessData: (data: { title: string }) => void,
|
||||||
setErrorData,
|
setErrorData: (data: { title: string; list: string[] }) => void,
|
||||||
) => {
|
) => {
|
||||||
const handleDeleteKey = () => {
|
const handleDeleteKey = () => {
|
||||||
Promise.all(selectedRows.map((selectedRow) => deleteApiKey(selectedRow)))
|
Promise.all(selectedRows.map((selectedRow) => deleteApiKey(selectedRow)))
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,10 @@ import {
|
||||||
BASE_URL_API,
|
BASE_URL_API,
|
||||||
} from "../../../../../../../../../constants/constants";
|
} from "../../../../../../../../../constants/constants";
|
||||||
|
|
||||||
const usePreloadImages = (profilePictures, setImagesLoaded) => {
|
const usePreloadImages = (
|
||||||
|
profilePictures: { [key: string]: string[] },
|
||||||
|
setImagesLoaded: (value: boolean) => void,
|
||||||
|
) => {
|
||||||
const preloadImages = async (imageUrls) => {
|
const preloadImages = async (imageUrls) => {
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
imageUrls.map(
|
imageUrls.map(
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,13 @@ import {
|
||||||
SAVE_SUCCESS_ALERT,
|
SAVE_SUCCESS_ALERT,
|
||||||
} from "../../../../constants/alerts_constants";
|
} from "../../../../constants/alerts_constants";
|
||||||
import { resetPassword } from "../../../../controllers/API";
|
import { resetPassword } from "../../../../controllers/API";
|
||||||
|
import { Users } from "../../../../types/api";
|
||||||
|
|
||||||
const usePatchPassword = (userData, setSuccessData, setErrorData) => {
|
const usePatchPassword = (
|
||||||
|
userData: Users | null,
|
||||||
|
setSuccessData: (data: { title: string; list?: string[] }) => void,
|
||||||
|
setErrorData: (data: { title: string; list: string[] }) => void,
|
||||||
|
) => {
|
||||||
const handlePatchPassword = async (password, cnfPassword, handleInput) => {
|
const handlePatchPassword = async (password, cnfPassword, handleInput) => {
|
||||||
if (password !== cnfPassword) {
|
if (password !== cnfPassword) {
|
||||||
setErrorData({
|
setErrorData({
|
||||||
|
|
@ -16,7 +21,7 @@ const usePatchPassword = (userData, setSuccessData, setErrorData) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (password !== "") await resetPassword(userData.id, { password });
|
if (password !== "") await resetPassword(userData!.id, { password });
|
||||||
handleInput({ target: { name: "password", value: "" } });
|
handleInput({ target: { name: "password", value: "" } });
|
||||||
handleInput({ target: { name: "cnfPassword", value: "" } });
|
handleInput({ target: { name: "cnfPassword", value: "" } });
|
||||||
setSuccessData({ title: SAVE_SUCCESS_ALERT });
|
setSuccessData({ title: SAVE_SUCCESS_ALERT });
|
||||||
|
|
|
||||||
|
|
@ -4,21 +4,22 @@ import {
|
||||||
SAVE_SUCCESS_ALERT,
|
SAVE_SUCCESS_ALERT,
|
||||||
} from "../../../../constants/alerts_constants";
|
} from "../../../../constants/alerts_constants";
|
||||||
import { updateUser } from "../../../../controllers/API";
|
import { updateUser } from "../../../../controllers/API";
|
||||||
|
import { Users } from "../../../../types/api";
|
||||||
|
|
||||||
const usePatchProfilePicture = (
|
const usePatchProfilePicture = (
|
||||||
setSuccessData,
|
setSuccessData: (data: { title: string; list?: string[] }) => void,
|
||||||
setErrorData,
|
setErrorData: (data: { title: string; list: string[] }) => void,
|
||||||
currentUserData,
|
currentUserData: Users | null,
|
||||||
setUserData,
|
setUserData: (data: any) => void,
|
||||||
) => {
|
) => {
|
||||||
const handlePatchProfilePicture = async (profile_picture) => {
|
const handlePatchProfilePicture = async (profile_picture) => {
|
||||||
try {
|
try {
|
||||||
if (profile_picture !== "") {
|
if (profile_picture !== "") {
|
||||||
await updateUser(currentUserData.id, {
|
await updateUser(currentUserData!.id, {
|
||||||
profile_image: profile_picture,
|
profile_image: profile_picture,
|
||||||
});
|
});
|
||||||
let newUserData = cloneDeep(currentUserData);
|
let newUserData = cloneDeep(currentUserData);
|
||||||
newUserData.profile_image = profile_picture;
|
newUserData!.profile_image = profile_picture;
|
||||||
setUserData(newUserData);
|
setUserData(newUserData);
|
||||||
}
|
}
|
||||||
setSuccessData({ title: SAVE_SUCCESS_ALERT });
|
setSuccessData({ title: SAVE_SUCCESS_ALERT });
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,11 @@ import { AuthContext } from "../../../../contexts/authContext";
|
||||||
import { addApiKeyStore } from "../../../../controllers/API";
|
import { addApiKeyStore } from "../../../../controllers/API";
|
||||||
|
|
||||||
const useSaveKey = (
|
const useSaveKey = (
|
||||||
setSuccessData,
|
setSuccessData: (data: { title: string }) => void,
|
||||||
setErrorData,
|
setErrorData: (data: { title: string; list: string[] }) => void,
|
||||||
setHasApiKey,
|
setHasApiKey: (hasApiKey: boolean) => void,
|
||||||
setValidApiKey,
|
setValidApiKey: (validApiKey: boolean) => void,
|
||||||
setLoadingApiKey,
|
setLoadingApiKey: (loadingApiKey: boolean) => void,
|
||||||
) => {
|
) => {
|
||||||
const { storeApiKey } = useContext(AuthContext);
|
const { storeApiKey } = useContext(AuthContext);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
const useScrollToElement = (scrollId, setCurrentFlowId) => {
|
const useScrollToElement = (
|
||||||
|
scrollId: string | null | undefined,
|
||||||
|
setCurrentFlowId: (currentFlowId: string) => void,
|
||||||
|
) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const element = document.getElementById(scrollId ?? "null");
|
const element = document.getElementById(scrollId ?? "null");
|
||||||
if (element) {
|
if (element) {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
|
import { ColDef, ColGroupDef } from "ag-grid-community";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { getMessagesTable } from "../../../../../controllers/API";
|
import { getMessagesTable } from "../../../../../controllers/API";
|
||||||
import { useMessagesStore } from "../../../../../stores/messagesStore";
|
import { useMessagesStore } from "../../../../../stores/messagesStore";
|
||||||
|
|
||||||
const useMessagesTable = (setColumns) => {
|
const useMessagesTable = (
|
||||||
|
setColumns: (data: Array<ColDef | ColGroupDef>) => void,
|
||||||
|
) => {
|
||||||
const setMessages = useMessagesStore((state) => state.setMessages);
|
const setMessages = useMessagesStore((state) => state.setMessages);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@ import { deleteMessagesFn } from "../../../../../controllers/API";
|
||||||
import { useMessagesStore } from "../../../../../stores/messagesStore";
|
import { useMessagesStore } from "../../../../../stores/messagesStore";
|
||||||
|
|
||||||
const useRemoveMessages = (
|
const useRemoveMessages = (
|
||||||
setSelectedRows,
|
setSelectedRows: (data: number[]) => void,
|
||||||
setSuccessData,
|
setSuccessData: (data: { title: string }) => void,
|
||||||
setErrorData,
|
setErrorData: (data: { title: string }) => void,
|
||||||
selectedRows,
|
selectedRows: number[],
|
||||||
) => {
|
) => {
|
||||||
const deleteMessages = useMessagesStore((state) => state.removeMessages);
|
const deleteMessages = useMessagesStore((state) => state.removeMessages);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,10 @@ import { updateMessageApi } from "../../../../../controllers/API";
|
||||||
import { useMessagesStore } from "../../../../../stores/messagesStore";
|
import { useMessagesStore } from "../../../../../stores/messagesStore";
|
||||||
import { Message } from "../../../../../types/messages";
|
import { Message } from "../../../../../types/messages";
|
||||||
|
|
||||||
const useUpdateMessage = (setSuccessData, setErrorData) => {
|
const useUpdateMessage = (
|
||||||
|
setSuccessData: (data: { title: string; list?: string[] }) => void,
|
||||||
|
setErrorData: (data: { title: string; list?: string[] }) => void,
|
||||||
|
) => {
|
||||||
const updateMessage = useMessagesStore((state) => state.updateMessage);
|
const updateMessage = useMessagesStore((state) => state.updateMessage);
|
||||||
|
|
||||||
const handleUpdate = async (data: Message) => {
|
const handleUpdate = async (data: Message) => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue