diff --git a/src/backend/base/langflow/api/utils.py b/src/backend/base/langflow/api/utils.py index 048f14ac3..1dbd68d8f 100644 --- a/src/backend/base/langflow/api/utils.py +++ b/src/backend/base/langflow/api/utils.py @@ -86,6 +86,10 @@ def update_frontend_node_with_template_values(frontend_node, raw_frontend_node): update_template_values(frontend_node["template"], raw_frontend_node["template"]) + old_code = raw_frontend_node["template"]["code"]["value"] + new_code = frontend_node["template"]["code"]["value"] + frontend_node["edited"] = old_code != new_code + return frontend_node diff --git a/src/backend/base/langflow/api/v1/files.py b/src/backend/base/langflow/api/v1/files.py index bbe97f81a..f6293686f 100644 --- a/src/backend/base/langflow/api/v1/files.py +++ b/src/backend/base/langflow/api/v1/files.py @@ -2,6 +2,7 @@ import hashlib from http import HTTPStatus from io import BytesIO from uuid import UUID +from pathlib import Path from fastapi import APIRouter, Depends, HTTPException, UploadFile from fastapi.responses import StreamingResponse @@ -99,6 +100,47 @@ async def download_image(file_name: str, flow_id: UUID, storage_service: Storage raise HTTPException(status_code=500, detail=str(e)) +@router.get("/profile_pictures/{folder_name}/{file_name}") +async def download_profile_picture( + folder_name: str, + file_name: str, + storage_service: StorageService = Depends(get_storage_service), +): + try: + extension = file_name.split(".")[-1] + config_dir = get_storage_service().settings_service.settings.config_dir + config_path = Path(config_dir) + folder_path = config_path / 'profile_pictures' / folder_name + content_type = build_content_type_from_extension(extension) + file_content = await storage_service.get_file(flow_id=folder_path, file_name=file_name) + return StreamingResponse(BytesIO(file_content), media_type=content_type) + + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + + +@router.get("/profile_pictures/list") +async def list_profile_pictures(storage_service: StorageService = Depends(get_storage_service)): + try: + config_dir = get_storage_service().settings_service.settings.config_dir + config_path = Path(config_dir) + + people_path = config_path / "profile_pictures/People" + space_path = config_path / "profile_pictures/Space" + + people = await storage_service.list_files(flow_id=people_path) + space = await storage_service.list_files(flow_id=space_path) + + files = [Path("People") / i for i in people] + files += [Path("Space") / i for i in space] + + return {"files": files} + + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + + + @router.get("/list/{flow_id}") async def list_files( flow_id: UUID = Depends(get_flow_id), storage_service: StorageService = Depends(get_storage_service) diff --git a/src/backend/base/langflow/api/v1/monitor.py b/src/backend/base/langflow/api/v1/monitor.py index ffd01b470..b748e4955 100644 --- a/src/backend/base/langflow/api/v1/monitor.py +++ b/src/backend/base/langflow/api/v1/monitor.py @@ -117,6 +117,21 @@ async def get_transactions( dicts = monitor_service.get_transactions( source=source, target=target, status=status, order_by=order_by, flow_id=flow_id ) - return [TransactionModelResponse(**d) for d in dicts] + result = [] + for d in dicts: + d = TransactionModelResponse( + index=d["index"], + timestamp=d["timestamp"], + vertex_id=d["vertex_id"], + inputs=d["inputs"], + outputs=d["outputs"], + status=d["status"], + error=d["error"], + flow_id=d["flow_id"], + source=d["vertex_id"], + target=d["target_id"], + ) + result.append(d) + return result except Exception as e: raise HTTPException(status_code=500, detail=str(e)) diff --git a/src/backend/base/langflow/graph/graph/base.py b/src/backend/base/langflow/graph/graph/base.py index 57ccc6a9d..06074ee1d 100644 --- a/src/backend/base/langflow/graph/graph/base.py +++ b/src/backend/base/langflow/graph/graph/base.py @@ -769,11 +769,13 @@ class Graph: next_runnable_vertices, top_level_vertices = await self.get_next_and_top_level_vertices( lock, set_cache_coro, vertex ) - log_transaction(vertex, status="success") + flow_id = self.flow_id + log_transaction(flow_id, vertex, status="success") return next_runnable_vertices, top_level_vertices, result_dict, params, valid, artifacts, vertex except Exception as exc: logger.exception(f"Error building vertex: {exc}") - log_transaction(vertex, status="failure", error=str(exc)) + flow_id = self.flow_id + log_transaction(flow_id, vertex, status="failure", error=str(exc)) raise exc async def get_next_and_top_level_vertices( diff --git a/src/backend/base/langflow/graph/vertex/base.py b/src/backend/base/langflow/graph/vertex/base.py index 99aed5b02..a94bd7a46 100644 --- a/src/backend/base/langflow/graph/vertex/base.py +++ b/src/backend/base/langflow/graph/vertex/base.py @@ -529,12 +529,13 @@ class Vertex: Returns: The built result if use_result is True, else the built object. """ + flow_id = self.graph.flow_id if not self._built: - log_transaction(vertex=self, target=requester, status="error") + log_transaction(flow_id, vertex=self, target=requester, status="error") raise ValueError(f"Component {self.display_name} has not been built yet") result = self._built_result if self.use_result else self._built_object - log_transaction(vertex=self, target=requester, status="success") + log_transaction(flow_id, vertex=self, target=requester, status="success") return result async def _build_vertex_and_update_params(self, key, vertex: "Vertex"): diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-01.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-01.png new file mode 100644 index 000000000..fa4fed5d1 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-01.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-02.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-02.png new file mode 100644 index 000000000..6519e7657 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-02.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-03.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-03.png new file mode 100644 index 000000000..512a5b037 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-03.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-04.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-04.png new file mode 100644 index 000000000..6c84a0792 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-04.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-05.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-05.png new file mode 100644 index 000000000..8e4b22298 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-05.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-06.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-06.png new file mode 100644 index 000000000..d317eb499 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-06.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-07.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-07.png new file mode 100644 index 000000000..ed2ed8214 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-07.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-08.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-08.png new file mode 100644 index 000000000..0785f59ea Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-08.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-09.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-09.png new file mode 100644 index 000000000..8dd5b1677 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-09.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-10.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-10.png new file mode 100644 index 000000000..058dff1a8 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-10.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-11.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-11.png new file mode 100644 index 000000000..a517fad0d Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-11.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-12.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-12.png new file mode 100644 index 000000000..508590f18 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-12.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-13.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-13.png new file mode 100644 index 000000000..90865a49d Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-13.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-14.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-14.png new file mode 100644 index 000000000..269621bb2 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-14.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-15.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-15.png new file mode 100644 index 000000000..da85a4e30 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-15.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-16.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-16.png new file mode 100644 index 000000000..cf30ae136 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-16.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-17.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-17.png new file mode 100644 index 000000000..d53cd7997 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-17.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-18.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-18.png new file mode 100644 index 000000000..e0ac43aab Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-18.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-19.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-19.png new file mode 100644 index 000000000..d04a96a27 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-19.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-20.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-20.png new file mode 100644 index 000000000..e2d6e99bc Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-20.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-21.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-21.png new file mode 100644 index 000000000..392b004e2 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-21.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-22.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-22.png new file mode 100644 index 000000000..606aed15d Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-22.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-23.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-23.png new file mode 100644 index 000000000..c16d96d41 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-23.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-24.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-24.png new file mode 100644 index 000000000..e0dd6a1b2 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-24.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-25.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-25.png new file mode 100644 index 000000000..08aeb61c3 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-25.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-26.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-26.png new file mode 100644 index 000000000..312ef035c Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-26.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-27.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-27.png new file mode 100644 index 000000000..95972203e Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-01-27.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-01.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-01.png new file mode 100644 index 000000000..b55f875ac Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-01.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-02.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-02.png new file mode 100644 index 000000000..b51a3b136 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-02.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-03.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-03.png new file mode 100644 index 000000000..8b386a081 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-03.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-04.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-04.png new file mode 100644 index 000000000..e36804f81 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-04.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-05.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-05.png new file mode 100644 index 000000000..7e4661821 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-05.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-06.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-06.png new file mode 100644 index 000000000..5ce14b221 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-06.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-07.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-07.png new file mode 100644 index 000000000..c91f89584 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-07.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-08.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-08.png new file mode 100644 index 000000000..4f4c4ab2e Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-08.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-09.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-09.png new file mode 100644 index 000000000..9c1b5b34d Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-09.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-10.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-10.png new file mode 100644 index 000000000..6746a9cc1 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-10.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-11.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-11.png new file mode 100644 index 000000000..771ed1869 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-11.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-12.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-12.png new file mode 100644 index 000000000..f32aa58ee Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-12.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-13.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-13.png new file mode 100644 index 000000000..ae8db49a6 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-13.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-14.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-14.png new file mode 100644 index 000000000..038272194 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-14.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-15.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-15.png new file mode 100644 index 000000000..073b456a0 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-15.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-16.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-16.png new file mode 100644 index 000000000..5369cf9af Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-16.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-17.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-17.png new file mode 100644 index 000000000..1f143bc30 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-17.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-18.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-18.png new file mode 100644 index 000000000..3456bf542 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-18.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-19.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-19.png new file mode 100644 index 000000000..a8f673724 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-19.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-20.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-20.png new file mode 100644 index 000000000..5384bf7a1 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-20.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-21.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-21.png new file mode 100644 index 000000000..1c6a39bbf Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-21.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-22.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-22.png new file mode 100644 index 000000000..976f94dc1 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-22.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-23.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-23.png new file mode 100644 index 000000000..c6ca79192 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-23.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-24.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-24.png new file mode 100644 index 000000000..429f74046 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-24.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-25.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-25.png new file mode 100644 index 000000000..38aeea19c Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-25.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-26.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-26.png new file mode 100644 index 000000000..65342b59d Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-26.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-27.png b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-27.png new file mode 100644 index 000000000..1c2fc7717 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/People/People Avatar-02-27.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/026-alien.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/026-alien.png new file mode 100644 index 000000000..218c03407 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/026-alien.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/027-satellite.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/027-satellite.png new file mode 100644 index 000000000..f72f22226 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/027-satellite.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/028-alien.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/028-alien.png new file mode 100644 index 000000000..2e558a69d Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/028-alien.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/029-telescope.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/029-telescope.png new file mode 100644 index 000000000..6c3622fea Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/029-telescope.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/030-books.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/030-books.png new file mode 100644 index 000000000..f1b5cf777 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/030-books.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/031-planet.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/031-planet.png new file mode 100644 index 000000000..289a237c9 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/031-planet.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/032-constellation.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/032-constellation.png new file mode 100644 index 000000000..ca09192a6 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/032-constellation.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/033-planet.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/033-planet.png new file mode 100644 index 000000000..de3bf7548 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/033-planet.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/034-alien.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/034-alien.png new file mode 100644 index 000000000..0ed7f3a46 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/034-alien.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/035-globe.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/035-globe.png new file mode 100644 index 000000000..b58ec3148 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/035-globe.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/036-eclipse.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/036-eclipse.png new file mode 100644 index 000000000..4cb944fd2 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/036-eclipse.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/037-meteor.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/037-meteor.png new file mode 100644 index 000000000..f1e11b5ed Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/037-meteor.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/038-eclipse.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/038-eclipse.png new file mode 100644 index 000000000..63c8893ed Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/038-eclipse.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/039-Asteroid.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/039-Asteroid.png new file mode 100644 index 000000000..8b858f28e Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/039-Asteroid.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/040-mission.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/040-mission.png new file mode 100644 index 000000000..0befc44f1 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/040-mission.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/041-spaceship.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/041-spaceship.png new file mode 100644 index 000000000..d499c98b6 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/041-spaceship.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/042-space shuttle.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/042-space shuttle.png new file mode 100644 index 000000000..f13df646b Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/042-space shuttle.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/043-space shuttle.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/043-space shuttle.png new file mode 100644 index 000000000..136dc8031 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/043-space shuttle.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/044-rocket.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/044-rocket.png new file mode 100644 index 000000000..16d60e221 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/044-rocket.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/045-astronaut.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/045-astronaut.png new file mode 100644 index 000000000..fdb107548 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/045-astronaut.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/046-rocket.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/046-rocket.png new file mode 100644 index 000000000..e2808eb39 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/046-rocket.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/047-computer.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/047-computer.png new file mode 100644 index 000000000..cc3bbf904 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/047-computer.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/048-satellite.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/048-satellite.png new file mode 100644 index 000000000..0548cb820 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/048-satellite.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/049-astronaut.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/049-astronaut.png new file mode 100644 index 000000000..99654c52e Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/049-astronaut.png differ diff --git a/src/backend/base/langflow/initial_setup/profile_pictures/Space/050-space robot.png b/src/backend/base/langflow/initial_setup/profile_pictures/Space/050-space robot.png new file mode 100644 index 000000000..52c23b249 Binary files /dev/null and b/src/backend/base/langflow/initial_setup/profile_pictures/Space/050-space robot.png differ diff --git a/src/backend/base/langflow/initial_setup/setup.py b/src/backend/base/langflow/initial_setup/setup.py index 83408d8b9..e10d55dd9 100644 --- a/src/backend/base/langflow/initial_setup/setup.py +++ b/src/backend/base/langflow/initial_setup/setup.py @@ -1,5 +1,6 @@ import logging import os +import shutil from collections import defaultdict from copy import deepcopy from datetime import datetime, timezone @@ -20,7 +21,7 @@ from langflow.services.database.models.user.crud import get_user_by_username from langflow.services.deps import get_settings_service, session_scope from langflow.services.database.models.folder.utils import create_default_folder_if_it_doesnt_exist -from langflow.services.deps import get_variable_service +from langflow.services.deps import get_variable_service, get_storage_service STARTER_FOLDER_NAME = "Starter Projects" @@ -104,6 +105,25 @@ def load_starter_projects() -> list[tuple[Path, dict]]: return starter_projects +def copy_profile_pictures(): + config_dir = get_storage_service().settings_service.settings.config_dir + origin = Path(__file__).parent / "profile_pictures" + target = Path(config_dir) / "profile_pictures" + + if not os.path.exists(origin): + raise ValueError(f"The source folder '{origin}' does not exist.") + + if not os.path.exists(target): + os.makedirs(target) + + try: + shutil.copytree(origin, target, dirs_exist_ok=True) + logger.debug(f"Folder copied from '{origin}' to '{target}'") + + except Exception as e: + logger.error(f"Error copying the folder: {e}") + + def get_project_data(project): project_name = project.get("name") project_description = project.get("description") @@ -286,6 +306,7 @@ def create_or_update_starter_projects(): new_folder = create_starter_folder(session) starter_projects = load_starter_projects() delete_start_projects(session, new_folder.id) + copy_profile_pictures() for project_path, project in starter_projects: ( project_name, diff --git a/src/backend/base/langflow/interface/initialize/loading.py b/src/backend/base/langflow/interface/initialize/loading.py index 42fa4e7a1..6ff498c0c 100644 --- a/src/backend/base/langflow/interface/initialize/loading.py +++ b/src/backend/base/langflow/interface/initialize/loading.py @@ -85,7 +85,9 @@ def update_params_with_load_from_db_fields( logger.info(f"Using environment variable {params[field]} for {field}") if key is None: logger.warning(f"Could not get value for {field}. Setting it to None.") - params[field] = key + + if field != "session_id": + params[field] = key except Exception as exc: logger.error(f"Failed to get value for {field} from custom component. Setting it to None. Error: {exc}") diff --git a/src/backend/base/langflow/services/monitor/schema.py b/src/backend/base/langflow/services/monitor/schema.py index 8f9c57752..4cb057ccc 100644 --- a/src/backend/base/langflow/services/monitor/schema.py +++ b/src/backend/base/langflow/services/monitor/schema.py @@ -14,9 +14,10 @@ class TransactionModel(BaseModel): vertex_id: str target_id: str | None = None inputs: dict - outputs: dict + outputs: Optional[dict] = None status: str error: Optional[str] = None + flow_id: Optional[str] = Field(default=None, alias="flow_id") class Config: from_attributes = True @@ -41,9 +42,12 @@ class TransactionModelResponse(BaseModel): timestamp: Optional[datetime] = Field(default_factory=datetime.now, alias="timestamp") vertex_id: str inputs: dict - outputs: dict + outputs: Optional[dict] = None status: str error: Optional[str] = None + flow_id: Optional[str] = Field(default=None, alias="flow_id") + source: Optional[str] = None + target: Optional[str] = None class Config: from_attributes = True diff --git a/src/backend/base/langflow/services/monitor/service.py b/src/backend/base/langflow/services/monitor/service.py index e15cb39dd..6c37672af 100644 --- a/src/backend/base/langflow/services/monitor/service.py +++ b/src/backend/base/langflow/services/monitor/service.py @@ -168,7 +168,9 @@ class MonitorService(Service): order_by: Optional[str] = "timestamp", flow_id: Optional[str] = None, ): - query = "SELECT index,flow_id, source, target, target_args, status, error, timestamp FROM transactions" + query = ( + "SELECT index,flow_id, status, error, timestamp, vertex_id, inputs, outputs, target_id FROM transactions" + ) conditions = [] if source: conditions.append(f"source = '{source}'") @@ -183,7 +185,7 @@ class MonitorService(Service): query += " WHERE " + " AND ".join(conditions) if order_by: - query += f" ORDER BY {order_by}" + query += f" ORDER BY {order_by} DESC" with duckdb.connect(str(self.db_path)) as conn: df = conn.execute(query).df() diff --git a/src/backend/base/langflow/services/monitor/utils.py b/src/backend/base/langflow/services/monitor/utils.py index ea7a3bad6..706d62348 100644 --- a/src/backend/base/langflow/services/monitor/utils.py +++ b/src/backend/base/langflow/services/monitor/utils.py @@ -178,7 +178,7 @@ def build_clean_params(target: "Vertex") -> dict: return params -def log_transaction(vertex: "Vertex", status, target: Optional["Vertex"] = None, error=None): +def log_transaction(flow_id, vertex: "Vertex", status, target: Optional["Vertex"] = None, error=None): try: monitor_service = get_monitor_service() clean_params = build_clean_params(vertex) @@ -186,10 +186,11 @@ def log_transaction(vertex: "Vertex", status, target: Optional["Vertex"] = None, "vertex_id": str(vertex.id), "target_id": str(target.id) if target else None, "inputs": clean_params, - "outputs": vertex.result.model_dump_json(), + "outputs": vertex.result.model_dump_json() if vertex.result else None, "timestamp": monitor_service.get_timestamp(), "status": status, "error": error, + "flow_id": flow_id, } monitor_service.add_row(table_name="transactions", data=data) except Exception as e: diff --git a/src/frontend/src/App.css b/src/frontend/src/App.css index 809959757..5a97d371e 100644 --- a/src/frontend/src/App.css +++ b/src/frontend/src/App.css @@ -174,3 +174,12 @@ body { border: none !important; outline: none; } + +/* selected */ +.react-flow__edge.selected .react-flow__edge-path { + stroke: var(--selected) !important; +} + +.react-flow__edge .react-flow__edge-path { + stroke: var(--connection) !important; +} diff --git a/src/frontend/src/CustomNodes/GenericNode/components/outputModal/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/outputModal/index.tsx index c5b442614..b3185acb1 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/outputModal/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/outputModal/index.tsx @@ -4,7 +4,7 @@ import SwitchOutputView from "./components/switchOutputView"; export default function OutputModal({ open, setOpen, nodeId }): JSX.Element { return ( - +
Component Output diff --git a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx index 198e1e1a7..941c86271 100644 --- a/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/components/parameterComponent/index.tsx @@ -274,7 +274,9 @@ export default function ParameterComponent({ : "Please build the component first" } > - + )}
diff --git a/src/frontend/src/CustomNodes/GenericNode/index.tsx b/src/frontend/src/CustomNodes/GenericNode/index.tsx index 60ae4e3a2..431327d8e 100644 --- a/src/frontend/src/CustomNodes/GenericNode/index.tsx +++ b/src/frontend/src/CustomNodes/GenericNode/index.tsx @@ -10,6 +10,7 @@ import { RUN_TIMESTAMP_PREFIX, STATUS_BUILD, STATUS_BUILDING, + TOOLTIP_OUTDATED_NODE, } from "../../constants/constants"; import { BuildStatus } from "../../constants/enums"; import { countHandlesFn } from "../helpers/count-handles"; @@ -35,6 +36,8 @@ import getFieldTitle from "../utils/get-field-title"; import sortFields from "../utils/sort-fields"; import isWrappedWithClass from "../../pages/FlowPage/components/PageComponent/utils/is-wrapped-with-class"; import ParameterComponent from "./components/parameterComponent"; +import { postCustomComponent } from "../../controllers/API"; +import { cloneDeep } from "lodash"; export default function GenericNode({ data, @@ -204,6 +207,33 @@ export default function GenericNode({ setShowNode(data.showNode ?? true); }, [data.showNode]); + const [loadingUpdate, setLoadingUpdate] = useState(false); + + const handleUpdateCode = () => { + setLoadingUpdate(true); + takeSnapshot(); + // to update we must get the code from the templates in useTypesStore + const thisNodeTemplate = templates[data.type]?.template; + // if the template does not have a code key + // return + if (!thisNodeTemplate?.code) return; + + const currentCode = thisNodeTemplate.code.value; + if (data.node) { + postCustomComponent(currentCode, data.node) + .then((apiReturn) => { + const { data } = apiReturn; + if (data && updateNodeCode) { + updateNodeCode(data, currentCode, "code"); + setLoadingUpdate(false); + } + }) + .catch((err) => { + console.log(err); + }); + } + }; + const memoizedNodeToolbarComponent = useMemo(() => { return ( @@ -226,8 +256,6 @@ export default function GenericNode({ showNode={showNode} openAdvancedModal={false} onCloseAdvancedModal={() => {}} - updateNodeCode={updateNodeCode} - isOutdated={isOutdated} selected={selected} /> @@ -448,54 +476,71 @@ export default function GenericNode({ {showNode && ( <> - {STATUS_BUILDING} - ) : !validationStatus ? ( - {STATUS_BUILD} - ) : ( -
-
- {lastRunTime && ( -
-
{RUN_TIMESTAMP_PREFIX}
-
- {lastRunTime} +
+ {isOutdated && ( + + + + )} + {STATUS_BUILDING} + ) : !validationStatus ? ( + {STATUS_BUILD} + ) : ( +
+
+ {lastRunTime && ( +
+
{RUN_TIMESTAMP_PREFIX}
+
+ {lastRunTime} +
+ )} +
+
+
Duration:
+
+ {validationStatus?.data.duration}
- )} -
-
-
Duration:
-
- {validationStatus?.data.duration}
-
- ) - } - side="bottom" - > - -
+
+ {renderIconStatus()} +
+ + +
)}
diff --git a/src/frontend/src/CustomNodes/hooks/use-check-code-validity.tsx b/src/frontend/src/CustomNodes/hooks/use-check-code-validity.tsx index 0b83429f8..ec4d586f6 100644 --- a/src/frontend/src/CustomNodes/hooks/use-check-code-validity.tsx +++ b/src/frontend/src/CustomNodes/hooks/use-check-code-validity.tsx @@ -23,10 +23,11 @@ const useCheckCodeValidity = ( if (!thisNodeTemplate.code) return; const currentCode = thisNodeTemplate.code?.value; const thisNodesCode = data.node!.template?.code?.value; - const componentsToIgnore = ["Custom Component", "Prompt"]; + const componentsToIgnore = ["CustomComponent", "Prompt"]; if ( currentCode !== thisNodesCode && - !componentsToIgnore.includes(data.node!.display_name) + !componentsToIgnore.includes(data.type) && + !(data.node?.edited ?? false) ) { setIsOutdated(true); } else { diff --git a/src/frontend/src/CustomNodes/hooks/use-update-node-code.tsx b/src/frontend/src/CustomNodes/hooks/use-update-node-code.tsx index 28220d141..f1593597f 100644 --- a/src/frontend/src/CustomNodes/hooks/use-update-node-code.tsx +++ b/src/frontend/src/CustomNodes/hooks/use-update-node-code.tsx @@ -19,6 +19,7 @@ const useUpdateNodeCode = ( node: newNodeClass, description: newNodeClass.description ?? dataNode.description, display_name: newNodeClass.display_name ?? dataNode.display_name, + edited: false, }; newNode.data.node.template[name].value = code; diff --git a/src/frontend/src/assets/profile-circle.png b/src/frontend/src/assets/profile-circle.png new file mode 100644 index 000000000..e63f97c59 Binary files /dev/null and b/src/frontend/src/assets/profile-circle.png differ diff --git a/src/frontend/src/components/arrayReaderComponent/index.tsx b/src/frontend/src/components/arrayReaderComponent/index.tsx index bcbfde010..6e151d426 100644 --- a/src/frontend/src/components/arrayReaderComponent/index.tsx +++ b/src/frontend/src/components/arrayReaderComponent/index.tsx @@ -1,10 +1,12 @@ +import TableAutoCellRender from "../tableComponent/components/tableAutoCellRender"; + export default function ArrayReader({ array }: { array: any[] }): JSX.Element { //TODO check array type return (
    {array.map((item, index) => ( -
  • {item}
  • +
  • {}
  • ))}
diff --git a/src/frontend/src/components/cardComponent/index.tsx b/src/frontend/src/components/cardComponent/index.tsx index 8b16d9040..0e2e2e09f 100644 --- a/src/frontend/src/components/cardComponent/index.tsx +++ b/src/frontend/src/components/cardComponent/index.tsx @@ -217,7 +217,7 @@ export default function CollectionCardComponent({ data-testid={`card-${convertTestName(data.name)}`} //TODO check color schema className={cn( - "group relative flex min-h-[11rem] flex-col justify-between overflow-hidden transition-all hover:bg-muted/50 hover:shadow-md hover:dark:bg-[#ffffff10]", + "group relative flex h-[11rem] flex-col justify-between overflow-hidden transition-all hover:bg-muted/50 hover:shadow-md hover:dark:bg-[#ffffff10]", disabled ? "pointer-events-none opacity-50" : "", onClick ? "cursor-pointer" : "", isSelectedCard ? "border border-selected" : "", diff --git a/src/frontend/src/components/gradientChooserComponent/index.tsx b/src/frontend/src/components/gradientChooserComponent/index.tsx deleted file mode 100644 index 3467aedb8..000000000 --- a/src/frontend/src/components/gradientChooserComponent/index.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { gradients } from "../../utils/styleUtils"; - -export default function GradientChooserComponent({ value, onChange }) { - return ( -
- {gradients.map((gradient, idx) => ( -
{ - onChange(gradient); - }} - className={ - "duration-400 h-12 w-12 cursor-pointer rounded-full transition-all " + - gradient + - (value === gradient ? " shadow-lg ring-2 ring-primary" : "") - } - key={idx} - >
- ))} -
- ); -} diff --git a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx index 6babcf5fd..6405e258a 100644 --- a/src/frontend/src/components/headerComponent/components/menuBar/index.tsx +++ b/src/frontend/src/components/headerComponent/components/menuBar/index.tsx @@ -9,7 +9,7 @@ import { import { useNavigate } from "react-router-dom"; import { UPLOAD_ERROR_ALERT } from "../../../../constants/alerts_constants"; -import { SAVED_HOVER } from "../../../../constants/constants"; +import { IS_MAC, SAVED_HOVER } from "../../../../constants/constants"; import ExportModal from "../../../../modals/exportModal"; import FlowLogsModal from "../../../../modals/flowLogsModal"; import FlowSettingsModal from "../../../../modals/flowSettingsModal"; @@ -115,7 +115,7 @@ export const MenuBar = ({}: {}): JSX.Element => { title: UPLOAD_ERROR_ALERT, list: [error], }); - }, + } ); }} > @@ -139,7 +139,7 @@ export const MenuBar = ({}: {}): JSX.Element => { > Undo - {navigator.userAgent.toUpperCase().includes("MAC") ? ( + {IS_MAC ? ( { > Redo - {navigator.userAgent.toUpperCase().includes("MAC") ? ( + {IS_MAC ? ( { name={isBuilding || saveLoading ? "Loader2" : "CheckCircle2"} className={cn( "h-4 w-4", - isBuilding || saveLoading ? "animate-spin" : "animate-wiggle", + isBuilding || saveLoading ? "animate-spin" : "animate-wiggle" )} /> {printByBuildStatus()} diff --git a/src/frontend/src/components/headerComponent/index.tsx b/src/frontend/src/components/headerComponent/index.tsx index 455cdf8a4..7c094ca22 100644 --- a/src/frontend/src/components/headerComponent/index.tsx +++ b/src/frontend/src/components/headerComponent/index.tsx @@ -1,9 +1,12 @@ import { useContext } from "react"; +import profileCircle from "../../assets/profile-circle.png"; import { FaDiscord, FaGithub } from "react-icons/fa"; import { RiTwitterXFill } from "react-icons/ri"; import { Link, useLocation, useNavigate, useParams } from "react-router-dom"; import AlertDropdown from "../../alerts/alertDropDown"; import { + BACKEND_URL, + BASE_URL_API, LOCATIONS_TO_RETURN, USER_PROJECTS_HEADER, } from "../../constants/constants"; @@ -192,34 +195,35 @@ export default function Header(): JSX.Element { variant="none" size="none" data-testid="user-profile-settings" - className={ - "h-7 w-7 rounded-full focus-visible:outline-0 " + - (userData?.profile_image ?? - (userData?.id - ? gradients[ - parseInt(userData?.id ?? "", 30) % gradients.length - ] - : "bg-gray-500")) - } - /> + > + + {!autoLogin && ( <>
-
+ {userData?.username ?? "User"}
diff --git a/src/frontend/src/components/recordsOutputComponent/index.tsx b/src/frontend/src/components/recordsOutputComponent/index.tsx index 36c3a7370..957a43cc7 100644 --- a/src/frontend/src/components/recordsOutputComponent/index.tsx +++ b/src/frontend/src/components/recordsOutputComponent/index.tsx @@ -13,7 +13,9 @@ function RecordsOutputComponent({ rows: any; columnMode?: "intersection" | "union"; }) { + console.log("rows", rows); const columns = extractColumnsFromRows(rows, columnMode); + console.log("columns", columns); const columnDefs = columns.map((col, idx) => ({ ...col, diff --git a/src/frontend/src/components/tableComponent/components/TableOptions/index.tsx b/src/frontend/src/components/tableComponent/components/TableOptions/index.tsx index 3c3095f9a..7ad2d11f3 100644 --- a/src/frontend/src/components/tableComponent/components/TableOptions/index.tsx +++ b/src/frontend/src/components/tableComponent/components/TableOptions/index.tsx @@ -17,7 +17,7 @@ export default function TableOptions({ stateChange: boolean; }): JSX.Element { return ( -
+
diff --git a/src/frontend/src/components/tableComponent/components/tableAutoCellRender/index.tsx b/src/frontend/src/components/tableComponent/components/tableAutoCellRender/index.tsx index 0c5c00ac9..4a6020f78 100644 --- a/src/frontend/src/components/tableComponent/components/tableAutoCellRender/index.tsx +++ b/src/frontend/src/components/tableComponent/components/tableAutoCellRender/index.tsx @@ -9,20 +9,17 @@ import { Badge } from "../../../ui/badge"; export default function TableAutoCellRender({ value, -}: CustomCellRendererProps) { +}: CustomCellRendererProps | { value: any }) { function getCellType() { switch (typeof value) { case "object": if (value === null) { return String(value); } else if (Array.isArray(value)) { - return ; - } else if (value.definitions) { - // use a custom render defined by the sender + return ; } else { return ; } - break; case "string": if (isTimeStampString(value)) { return ; diff --git a/src/frontend/src/components/tableComponent/index.tsx b/src/frontend/src/components/tableComponent/index.tsx index 64cc1d45a..ee7455e01 100644 --- a/src/frontend/src/components/tableComponent/index.tsx +++ b/src/frontend/src/components/tableComponent/index.tsx @@ -12,8 +12,8 @@ import { cn, toTitleCase } from "../../utils/utils"; import ForwardedIconComponent from "../genericIconComponent"; import { Alert, AlertDescription, AlertTitle } from "../ui/alert"; import TableOptions from "./components/TableOptions"; -import resetGrid from "./utils/reset-grid-columns"; import { useParams } from "react-router-dom"; +import resetGrid from "./utils/reset-grid-columns"; interface TableComponentProps extends AgGridReactProps { columnDefs: NonNullable; @@ -128,7 +128,8 @@ const TableComponent = forwardRef< > { - if ( - e.sources.includes("columnVisibility") || - e.sources.includes("columnOrder") - ) { + console.log(e); + if (e.sources.some((source) => source.includes("column"))) { setColumnStateChange(true); } }} /> 0} + hasSelection={realRef.current?.api?.getSelectedRows().length > 0} duplicateRow={props.onDuplicate ? props.onDuplicate : undefined} deleteRow={props.onDelete ? props.onDelete : undefined} resetGrid={() => { + console.log("teste"); resetGrid(realRef, initialColumnDefs); setTimeout(() => { setColumnStateChange(false); diff --git a/src/frontend/src/components/ui/button.tsx b/src/frontend/src/components/ui/button.tsx index c8bb6c5b8..92d6f41a9 100644 --- a/src/frontend/src/components/ui/button.tsx +++ b/src/frontend/src/components/ui/button.tsx @@ -5,7 +5,7 @@ import { cn } from "../../utils/utils"; import ForwardedIconComponent from "../genericIconComponent"; const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background", + "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background", { variants: { variant: { diff --git a/src/frontend/src/constants/alerts_constants.tsx b/src/frontend/src/constants/alerts_constants.tsx index ebc7543d5..c6dfa035b 100644 --- a/src/frontend/src/constants/alerts_constants.tsx +++ b/src/frontend/src/constants/alerts_constants.tsx @@ -31,6 +31,8 @@ export const INVALID_SELECTION_ERROR_ALERT = "Invalid selection"; export const EDIT_PASSWORD_ERROR_ALERT = "Error changing password"; export const EDIT_PASSWORD_ALERT_LIST = "Passwords do not match"; export const SAVE_ERROR_ALERT = "Error saving changes"; +export const PROFILE_PICTURES_GET_ERROR_ALERT = + "Error retrieving profile pictures"; export const SIGNUP_ERROR_ALERT = "Error signing up"; export const APIKEY_ERROR_ALERT = "API Key Error"; export const NOAPI_ERROR_ALERT = diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index 312915eb5..e13f1105e 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -589,7 +589,7 @@ export const CONTROL_INPUT_STATE = { export const CONTROL_PATCH_USER_STATE = { password: "", cnfPassword: "", - gradient: "", + profilePicture: "", apikey: "", }; @@ -661,6 +661,9 @@ export const OUTPUT_TYPES = new Set([ export const CHAT_FIRST_INITIAL_TEXT = "Start a conversation and click the agent's thoughts"; +export const TOOLTIP_OUTDATED_NODE = + "Your component is outdated. Click to update (data may be lost)"; + export const CHAT_SECOND_INITIAL_TEXT = "to inspect the chaining process."; export const ZERO_NOTIFICATIONS = "No new notifications"; @@ -731,14 +734,16 @@ export const AUTHORIZED_DUPLICATE_REQUESTS = [ export const SAVE_DEBOUNCE_TIME = 300; +export const IS_MAC = navigator.userAgent.toUpperCase().includes("MAC"); + export const defaultShortcuts = [ { name: "Advanced Settings", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Shift + A`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Shift + A`, }, { name: "Minimize", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Q`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Q`, }, { name: "Code", @@ -746,23 +751,23 @@ export const defaultShortcuts = [ }, { name: "Copy", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + C`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + C`, }, { name: "Duplicate", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + D`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + D`, }, { name: "Share", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Shift + S`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Shift + S`, }, { name: "Docs", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Shift + D`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Shift + D`, }, { name: "Save", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + S`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + S`, }, { name: "Delete", @@ -770,43 +775,43 @@ export const defaultShortcuts = [ }, { name: "Open playground", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + K`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + K`, }, { name: "Undo", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Z`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Z`, }, { name: "Redo", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + Y`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + Y`, }, { name: "Group", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + G`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + G`, }, { name: "Cut", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + X`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + X`, }, { name: "Paste", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + V`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + V`, }, { name: "API", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + R`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + R`, }, { name: "Download", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + J`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + J`, }, { name: "Update", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + U`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + U`, }, { name: "Freeze", - shortcut: `${navigator.userAgent.toUpperCase().includes("MAC") ? "Cmd" : "Ctrl"} + F`, + shortcut: `${IS_MAC ? "Cmd" : "Ctrl"} + F`, }, ]; diff --git a/src/frontend/src/controllers/API/api.tsx b/src/frontend/src/controllers/API/api.tsx index 91abedd18..4070b784f 100644 --- a/src/frontend/src/controllers/API/api.tsx +++ b/src/frontend/src/controllers/API/api.tsx @@ -1,4 +1,4 @@ -import axios, { AxiosError, AxiosInstance } from "axios"; +import axios, { Axios, AxiosError, AxiosInstance } from "axios"; import { useContext, useEffect } from "react"; import { Cookies } from "react-cookie"; import { renewAccessToken } from "."; @@ -83,8 +83,10 @@ function ApiInterceptor() { (config) => { const checkRequest = checkDuplicateRequestAndStoreRequest(config); + const controller = new AbortController(); + if (!checkRequest) { - return Promise.reject("Duplicate request."); + controller.abort("Duplicate Request"); } const accessToken = cookies.get("access_token_lf"); @@ -92,7 +94,10 @@ function ApiInterceptor() { config.headers["Authorization"] = `Bearer ${accessToken}`; } - return config; + return { + ...config, + signal: controller.signal, + }; }, (error) => { return Promise.reject(error); diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index 069577c77..fd3847e97 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -8,6 +8,7 @@ import { APITemplateType, Component, LoginType, + ProfilePicturesTypeAPI, Users, VertexBuildTypeAPI, VerticesOrderTypeAPI, @@ -364,6 +365,19 @@ export async function uploadFile( return await api.post(`${BASE_URL_API}files/upload/${id}`, formData); } +export async function getProfilePictures(): Promise { + try { + const res = await api.get(`${BASE_URL_API}files/profile_pictures/list`); + + if (res.status === 200) { + return res.data; + } + } catch (error) { + throw error; + } + return null; +} + export async function postCustomComponent( code: string, apiClass: APIClassType, diff --git a/src/frontend/src/index.tsx b/src/frontend/src/index.tsx index 62e73f091..9c828e086 100644 --- a/src/frontend/src/index.tsx +++ b/src/frontend/src/index.tsx @@ -12,13 +12,11 @@ import { StrictMode } from "react"; import "./style/classes.css"; const root = ReactDOM.createRoot( - document.getElementById("root") as HTMLElement + document.getElementById("root") as HTMLElement, ); root.render( - - - - - + + + , ); reportWebVitals(); diff --git a/src/frontend/src/modals/IOModal/components/chatView/chatInput/components/buttonSendWrapper/index.tsx b/src/frontend/src/modals/IOModal/components/chatView/chatInput/components/buttonSendWrapper/index.tsx index ff93a9f7b..52a3ff4dc 100644 --- a/src/frontend/src/modals/IOModal/components/chatView/chatInput/components/buttonSendWrapper/index.tsx +++ b/src/frontend/src/modals/IOModal/components/chatView/chatInput/components/buttonSendWrapper/index.tsx @@ -1,14 +1,25 @@ import IconComponent from "../../../../../../../components/genericIconComponent"; import { Case } from "../../../../../../../shared/components/caseComponent"; +import { FilePreviewType } from "../../../../../../../types/components"; import { classNames } from "../../../../../../../utils/utils"; +type ButtonSendWrapperProps = { + send: () => void; + lockChat: boolean; + noInput: boolean; + saveLoading: boolean; + chatValue: string; + files: FilePreviewType[]; +}; + const ButtonSendWrapper = ({ send, lockChat, noInput, saveLoading, chatValue, -}) => { + files, +}: ButtonSendWrapperProps) => { return (
diff --git a/src/frontend/src/modals/IOModal/components/chatView/index.tsx b/src/frontend/src/modals/IOModal/components/chatView/index.tsx index f183c830e..067cf525c 100644 --- a/src/frontend/src/modals/IOModal/components/chatView/index.tsx +++ b/src/frontend/src/modals/IOModal/components/chatView/index.tsx @@ -25,7 +25,7 @@ export default function ChatView({ setLockChat, }: chatViewProps): JSX.Element { const { flowPool, outputs, inputs, CleanFlowPool } = useFlowStore(); - const { setNoticeData } = useAlertStore(); + const { setErrorData } = useAlertStore(); const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId); const messagesRef = useRef(null); const [chatHistory, setChatHistory] = useState([]); @@ -161,6 +161,7 @@ export default function ChatView({ setIsDragging, setFiles, currentFlowId, + setErrorData, ); return ( diff --git a/src/frontend/src/modals/IOModal/index.tsx b/src/frontend/src/modals/IOModal/index.tsx index 47f826b50..e047a3694 100644 --- a/src/frontend/src/modals/IOModal/index.tsx +++ b/src/frontend/src/modals/IOModal/index.tsx @@ -208,7 +208,9 @@ export default function IOModal({ {outputs.length > 0 && ( Outputs )} - {haveChat && History} + {haveChat && ( + Memories + )}
diff --git a/src/frontend/src/modals/editNodeModal/hooks/use-column-defs.tsx b/src/frontend/src/modals/editNodeModal/hooks/use-column-defs.tsx index edcca5281..5dff3567e 100644 --- a/src/frontend/src/modals/editNodeModal/hooks/use-column-defs.tsx +++ b/src/frontend/src/modals/editNodeModal/hooks/use-column-defs.tsx @@ -23,8 +23,6 @@ const useColumnDefs = ( : templateParam.name) ?? params.data.key ); }, - tooltipField: "display_name", - tooltipComponent: TableTooltipRender, wrapText: true, autoHeight: true, flex: 1, @@ -35,7 +33,6 @@ const useColumnDefs = ( headerName: "Description", field: "info", tooltipField: "info", - tooltipComponent: TableTooltipRender, wrapText: true, autoHeight: true, flex: 2, diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx index 9a02a6415..40dfa0066 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/index.tsx @@ -11,7 +11,6 @@ import { SelectItem, SelectTrigger, } from "../../../../components/ui/select-custom"; -import { postCustomComponent } from "../../../../controllers/API"; import ConfirmationModal from "../../../../modals/confirmationModal"; import EditNodeModal from "../../../../modals/editNodeModal"; import ShareModal from "../../../../modals/shareModal"; @@ -42,12 +41,8 @@ export default function NodeToolbarComponent({ showNode, name = "code", selected, - updateNodeCode, setShowState, onCloseAdvancedModal, - isOutdated, - // openWDoubleClick, - // setOpenWDoubleClick, }: nodeToolbarPropsType): JSX.Element { const nodeLength = Object.keys(data.node!.template).filter( (templateField) => @@ -62,16 +57,14 @@ export default function NodeToolbarComponent({ data.node.template[templateField].type === "Any" || data.node.template[templateField].type === "int" || data.node.template[templateField].type === "dict" || - data.node.template[templateField].type === "NestedDict"), + data.node.template[templateField].type === "NestedDict") ).length; - const templates = useTypesStore((state) => state.templates); const hasStore = useStoreStore((state) => state.hasStore); const hasApiKey = useStoreStore((state) => state.hasApiKey); const validApiKey = useStoreStore((state) => state.validApiKey); const shortcuts = useShortcutsStore((state) => state.shortcuts); const unselectAll = useFlowStore((state) => state.unselectAll); - function handleMinimizeWShortcut(e: KeyboardEvent) { e.preventDefault(); if (isMinimal) { @@ -203,7 +196,7 @@ export default function NodeToolbarComponent({ const [showconfirmShare, setShowconfirmShare] = useState(false); const [showOverrideModal, setShowOverrideModal] = useState(false); const [flowComponent, setFlowComponent] = useState( - createFlowComponent(cloneDeep(data), version), + createFlowComponent(cloneDeep(data), version) ); // useEffect(() => { @@ -222,7 +215,7 @@ export default function NodeToolbarComponent({ const updateNodeInternals = useUpdateNodeInternals(); const setLastCopiedSelection = useFlowStore( - (state) => state.setLastCopiedSelection, + (state) => state.setLastCopiedSelection ); const setSuccessData = useAlertStore((state) => state.setSuccessData); @@ -296,7 +289,7 @@ export default function NodeToolbarComponent({ nodes, edges, setNodes, - setEdges, + setEdges ); break; case "override": @@ -320,51 +313,20 @@ export default function NodeToolbarComponent({ y: 10, paneX: nodes.find((node) => node.id === data.id)?.position.x, paneY: nodes.find((node) => node.id === data.id)?.position.y, - }, + } ); - break; - case "update": - takeSnapshot(); - // to update we must get the code from the templates in useTypesStore - const thisNodeTemplate = templates[data.type]?.template; - // if the template does not have a code key - // return - if (!thisNodeTemplate?.code) return; - - const currentCode = thisNodeTemplate.code.value; - if (data.node) { - postCustomComponent(currentCode, data.node) - .then((apiReturn) => { - const { data } = apiReturn; - if (data && updateNodeCode) { - updateNodeCode(data, currentCode, "code"); - } - }) - .catch((err) => { - console.log(err); - }); - setNode(data.id, (oldNode) => { - let newNode = cloneDeep(oldNode); - newNode.data = { - ...data, - }; - newNode.data.node.template.code.value = currentCode; - return newNode; - }); - } - break; } }; const isSaved = flows.some((flow) => - Object.values(flow).includes(data.node?.display_name!), + Object.values(flow).includes(data.node?.display_name!) ); const setNode = useFlowStore((state) => state.setNode); const handleOnNewValue = ( - newValue: string | string[] | boolean | Object[], + newValue: string | string[] | boolean | Object[] ): void => { if (data.node!.template[name].value !== newValue) { takeSnapshot(); @@ -463,7 +425,7 @@ export default function NodeToolbarComponent({ @@ -512,7 +474,7 @@ export default function NodeToolbarComponent({
obj.name === "Code")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Code"} icon={"Code"} dataTestId="code-button-modal" @@ -544,7 +505,6 @@ export default function NodeToolbarComponent({ shortcuts.find((obj) => obj.name === "Advanced Settings") ?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Advanced"} icon={"Settings2"} dataTestId="edit-button-modal" @@ -556,7 +516,6 @@ export default function NodeToolbarComponent({ shortcut={ shortcuts.find((obj) => obj.name === "Save")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Save"} icon={"SaveAll"} dataTestId="save-button-modal" @@ -567,7 +526,6 @@ export default function NodeToolbarComponent({ shortcut={ shortcuts.find((obj) => obj.name === "Duplicate")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Duplicate"} icon={"Copy"} dataTestId="copy-button-modal" @@ -578,26 +536,11 @@ export default function NodeToolbarComponent({ shortcut={ shortcuts.find((obj) => obj.name === "Copy")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Copy"} icon={"Clipboard"} dataTestId="copy-button-modal" /> - {isOutdated && ( - - obj.name === "Update")?.shortcut! - } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} - value={"Update"} - icon={"Code"} - dataTestId="update-button-modal" - ping={isOutdated} - /> - - )} {hasStore && ( obj.name === "Share")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Share"} icon={"Share3"} dataTestId="share-button-modal" @@ -621,7 +563,6 @@ export default function NodeToolbarComponent({ shortcuts.find((obj) => obj.name === "Download") ?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Download"} icon={"Download"} dataTestId="Download-button-modal" @@ -636,7 +577,6 @@ export default function NodeToolbarComponent({ shortcut={ shortcuts.find((obj) => obj.name === "Docs")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Docs"} icon={"FileText"} dataTestId="docs-button-modal" @@ -649,7 +589,6 @@ export default function NodeToolbarComponent({ shortcuts.find((obj) => obj.name === "Minimize") ?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={showNode ? "Minimize" : "Expand"} icon={showNode ? "Minimize2" : "Maximize2"} dataTestId="minimize-button-modal" @@ -662,7 +601,6 @@ export default function NodeToolbarComponent({ shortcut={ shortcuts.find((obj) => obj.name === "Group")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Ungroup"} icon={"Ungroup"} dataTestId="group-button-modal" @@ -674,7 +612,6 @@ export default function NodeToolbarComponent({ shortcut={ shortcuts.find((obj) => obj.name === "Freeze")?.shortcut! } - isMac={navigator.userAgent.toUpperCase().includes("MAC")} value={"Freeze"} icon={"Snowflake"} dataTestId="group-button-modal" diff --git a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx index 1db08834f..0c3045da9 100644 --- a/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/nodeToolbarComponent/toolbarSelectItem/index.tsx @@ -8,7 +8,6 @@ export default function ToolbarSelectItem({ dataTestId, ping, shortcut, - isMac, }: toolbarSelectItemProps) { let hasShift = false; const fixedShortcut = shortcut?.split("+"); @@ -18,7 +17,7 @@ export default function ToolbarSelectItem({ } }); const filteredShortcut = fixedShortcut.filter( - (key) => !key.toLowerCase().includes("shift"), + (key) => !key.toLowerCase().includes("shift") ); let shortcutWPlus = ""; if (!hasShift) shortcutWPlus = filteredShortcut.join("+"); diff --git a/src/frontend/src/pages/ProfileSettingsPage/index.tsx b/src/frontend/src/pages/ProfileSettingsPage/index.tsx index a7af7c86a..78e328623 100644 --- a/src/frontend/src/pages/ProfileSettingsPage/index.tsx +++ b/src/frontend/src/pages/ProfileSettingsPage/index.tsx @@ -2,7 +2,7 @@ import * as Form from "@radix-ui/react-form"; import { cloneDeep } from "lodash"; import { useContext, useEffect, useState } from "react"; import IconComponent from "../../components/genericIconComponent"; -import GradientChooserComponent from "../../components/gradientChooserComponent"; +import GradientChooserComponent from "../SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent"; import Header from "../../components/headerComponent"; import InputComponent from "../../components/inputComponent"; import { Button } from "../../components/ui/button"; @@ -24,11 +24,11 @@ import { import { gradients } from "../../utils/styleUtils"; export default function ProfileSettingsPage(): JSX.Element { const setCurrentFlowId = useFlowsManagerStore( - (state) => state.setCurrentFlowId + (state) => state.setCurrentFlowId, ); const [inputState, setInputState] = useState( - CONTROL_PATCH_USER_STATE + CONTROL_PATCH_USER_STATE, ); // set null id diff --git a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfileGradientForm/index.tsx b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfileGradientForm/index.tsx deleted file mode 100644 index a92a00103..000000000 --- a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfileGradientForm/index.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import * as Form from "@radix-ui/react-form"; -import GradientChooserComponent from "../../../../../../components/gradientChooserComponent"; -import { Button } from "../../../../../../components/ui/button"; -import { - Card, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "../../../../../../components/ui/card"; -import { gradients } from "../../../../../../utils/styleUtils"; - -type ProfileGradientFormComponentProps = { - gradient: string; - handleInput: (event: any) => void; - handlePatchGradient: (gradient: string) => void; - userData: any; -}; -const ProfileGradientFormComponent = ({ - gradient, - handleInput, - handlePatchGradient, - userData, -}: ProfileGradientFormComponentProps) => { - return ( - <> - { - handlePatchGradient(gradient); - event.preventDefault(); - }} - > - - - Profile Gradient - - Choose the gradient that appears as your profile picture. - - - -
- { - handleInput({ target: { name: "gradient", value } }); - }} - /> -
-
- - - - - -
-
- - ); -}; -export default ProfileGradientFormComponent; diff --git a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/hooks/use-get-profile-pictures.ts b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/hooks/use-get-profile-pictures.ts new file mode 100644 index 000000000..2997a4b2f --- /dev/null +++ b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/hooks/use-get-profile-pictures.ts @@ -0,0 +1,26 @@ +import { reject } from "lodash"; +import { PROFILE_PICTURES_GET_ERROR_ALERT } from "../../../../../../../../../constants/alerts_constants"; +import { getProfilePictures } from "../../../../../../../../../controllers/API"; +import axios from "axios"; + +const useGetProfilePictures = (setErrorData) => { + const handleGetProfilePictures = async () => { + try { + const profilePictures = await getProfilePictures(); + return profilePictures!.files; + } catch (error) { + if (axios.isCancel(error)) { + console.warn("Request canceled: ", error.message); + } else { + setErrorData({ + title: PROFILE_PICTURES_GET_ERROR_ALERT, + list: [(error as any)?.response?.data?.detail], + }); + } + } + }; + + return { handleGetProfilePictures }; +}; + +export default useGetProfilePictures; diff --git a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/index.tsx b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/index.tsx new file mode 100644 index 000000000..c02c6a560 --- /dev/null +++ b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/components/profilePictureChooserComponent/index.tsx @@ -0,0 +1,84 @@ +import { useEffect, useRef, useState } from "react"; +import useAlertStore from "../../../../../../../../stores/alertStore"; +import { gradients } from "../../../../../../../../utils/styleUtils"; +import useGetProfilePictures from "./hooks/use-get-profile-pictures"; +import { Label } from "../../../../../../../../components/ui/label"; +import { + BACKEND_URL, + BASE_URL_API, +} from "../../../../../../../../constants/constants"; +import HorizontalScrollFadeComponent from "../../../../../../../../components/horizontalScrollFadeComponent"; +import LoadingComponent from "../../../../../../../../components/loadingComponent"; +import Loading from "../../../../../../../../components/ui/loading"; +import { cn } from "../../../../../../../../utils/utils"; +import { Button } from "../../../../../../../../components/ui/button"; +import { useDarkStore } from "../../../../../../../../stores/darkStore"; + +type ProfilePictureChooserComponentProps = { + profilePictures: { [key: string]: string[] }; + loading: boolean; + value: string; + onChange: (value: string) => void; +}; + +export default function ProfilePictureChooserComponent({ + profilePictures, + loading, + value, + onChange, +}: ProfilePictureChooserComponentProps) { + const ref = useRef(null); + const dark = useDarkStore((state) => state.dark); + + useEffect(() => { + if (value && ref) { + ref.current?.scrollIntoView({ behavior: "smooth", block: "center" }); + } + }, [ref]); + + return ( +
+ {loading ? ( + + ) : ( + Object.keys(profilePictures).map((folder, idx) => ( +
+
+ {folder} +
+
+
+ {profilePictures[folder].map((path, idx) => ( + + ))} +
+
+
+ )) + )} +
+ ); +} diff --git a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/index.tsx b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/index.tsx new file mode 100644 index 000000000..a841ecc5e --- /dev/null +++ b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/components/ProfilePictureForm/index.tsx @@ -0,0 +1,109 @@ +import * as Form from "@radix-ui/react-form"; +import { Button } from "../../../../../../components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "../../../../../../components/ui/card"; +import { gradients } from "../../../../../../utils/styleUtils"; +import ProfilePictureChooserComponent from "./components/profilePictureChooserComponent"; +import { useEffect, useState } from "react"; +import { GenericAbortSignal } from "axios"; + +type ProfilePictureFormComponentProps = { + profilePicture: string; + handleInput: (event: any) => void; + handlePatchProfilePicture: (gradient: string) => void; + handleGetProfilePictures: () => Promise; + userData: any; +}; +const ProfilePictureFormComponent = ({ + profilePicture, + handleInput, + handlePatchProfilePicture, + handleGetProfilePictures, + userData, +}: ProfilePictureFormComponentProps) => { + const [profilePictures, setProfilePictures] = useState<{ + [key: string]: string[]; + }>({}); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const abortController = new AbortController(); + + handleGetProfilePictures() + .then((data) => { + if (data) { + data.forEach((profile_picture) => { + const [folder, path] = profile_picture.split("/"); + setProfilePictures((prev) => { + if (prev[folder]) { + prev[folder].push(path); + } else { + prev[folder] = [path]; + } + return prev; + }); + setLoading(false); + }); + } + }) + .catch(() => { + setLoading(false); + }); + + /* + Abort the request as it isn't needed anymore, the component being + unmounted. It helps avoid, among other things, the well-known "can't + perform a React state update on an unmounted component" warning. + */ + return () => abortController.abort(); + }, []); + + return ( + { + handlePatchProfilePicture(profilePicture); + event.preventDefault(); + }} + > + + + Profile Picture + + Choose the image that appears as your profile picture. + + + +
+ { + handleInput({ target: { name: "profilePicture", value } }); + }} + /> +
+
+ + + + + +
+
+ ); +}; +export default ProfilePictureFormComponent; diff --git a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx index 718097152..3c81bdb1c 100644 --- a/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/GeneralPage/index.tsx @@ -9,14 +9,15 @@ import { inputHandlerEventType, patchUserInputStateType, } from "../../../../types/components"; -import usePatchGradient from "../hooks/use-patch-gradient"; +import usePatchProfilePicture from "../hooks/use-patch-profile-picture"; import usePatchPassword from "../hooks/use-patch-password"; import useSaveKey from "../hooks/use-save-key"; import useScrollToElement from "../hooks/use-scroll-to-element"; import GeneralPageHeaderComponent from "./components/GeneralPageHeader"; import PasswordFormComponent from "./components/PasswordForm"; -import ProfileGradientFormComponent from "./components/ProfileGradientForm"; +import ProfilePictureFormComponent from "./components/ProfilePictureForm"; import StoreApiKeyFormComponent from "./components/StoreApiKeyForm"; +import useGetProfilePictures from "./components/ProfilePictureForm/components/profilePictureChooserComponent/hooks/use-get-profile-pictures"; export default function GeneralPage() { const setCurrentFlowId = useFlowsManagerStore( @@ -42,7 +43,7 @@ export default function GeneralPage() { const loadingApiKey = useStoreStore((state) => state.loadingApiKey); const setValidApiKey = useStoreStore((state) => state.updateValidApiKey); const setLoadingApiKey = useStoreStore((state) => state.updateLoadingApiKey); - const { password, cnfPassword, gradient, apikey } = inputState; + const { password, cnfPassword, profilePicture, apikey } = inputState; const { handlePatchPassword } = usePatchPassword( userData, @@ -50,7 +51,9 @@ export default function GeneralPage() { setErrorData, ); - const { handlePatchGradient } = usePatchGradient( + const { handleGetProfilePictures } = useGetProfilePictures(setErrorData); + + const { handlePatchProfilePicture } = usePatchProfilePicture( setSuccessData, setErrorData, userData, @@ -78,10 +81,11 @@ export default function GeneralPage() {
- diff --git a/src/frontend/src/pages/SettingsPage/pages/hooks/use-patch-gradient.tsx b/src/frontend/src/pages/SettingsPage/pages/hooks/use-patch-profile-picture.tsx similarity index 63% rename from src/frontend/src/pages/SettingsPage/pages/hooks/use-patch-gradient.tsx rename to src/frontend/src/pages/SettingsPage/pages/hooks/use-patch-profile-picture.tsx index ea61d4722..584300fdf 100644 --- a/src/frontend/src/pages/SettingsPage/pages/hooks/use-patch-gradient.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/hooks/use-patch-profile-picture.tsx @@ -5,18 +5,20 @@ import { } from "../../../../constants/alerts_constants"; import { updateUser } from "../../../../controllers/API"; -const usePatchGradient = ( +const usePatchProfilePicture = ( setSuccessData, setErrorData, currentUserData, setUserData, ) => { - const handlePatchGradient = async (gradient) => { + const handlePatchProfilePicture = async (profile_picture) => { try { - if (gradient !== "") { - await updateUser(currentUserData.id, { profile_image: gradient }); + if (profile_picture !== "") { + await updateUser(currentUserData.id, { + profile_image: profile_picture, + }); let newUserData = cloneDeep(currentUserData); - newUserData.profile_image = gradient; + newUserData.profile_image = profile_picture; setUserData(newUserData); } setSuccessData({ title: SAVE_SUCCESS_ALERT }); @@ -30,8 +32,8 @@ const usePatchGradient = ( return { currentUserData, - handlePatchGradient, + handlePatchProfilePicture, }; }; -export default usePatchGradient; +export default usePatchProfilePicture; diff --git a/src/frontend/src/stores/flowStore.ts b/src/frontend/src/stores/flowStore.ts index d966868a2..99aea0515 100644 --- a/src/frontend/src/stores/flowStore.ts +++ b/src/frontend/src/stores/flowStore.ts @@ -315,8 +315,6 @@ const useFlowStore = create((set, get) => ({ targetHandle, id, data: cloneDeep(edge.data), - style: { stroke: "#555" }, - className: "stroke-gray-900 ", selected: false, }, newEdges.map((edge) => ({ ...edge, selected: false })), @@ -396,8 +394,8 @@ const useFlowStore = create((set, get) => ({ targetHandle: scapeJSONParse(connection.targetHandle!), sourceHandle: scapeJSONParse(connection.sourceHandle!), }, - style: { stroke: "#555" }, - className: "stroke-foreground stroke-connection", + // style: { stroke: "#555" }, + // className: "stroke-foreground stroke-connection", }, oldEdges, ); diff --git a/src/frontend/src/style/index.css b/src/frontend/src/style/index.css index ec858dfe0..de6af78a5 100644 --- a/src/frontend/src/style/index.css +++ b/src/frontend/src/style/index.css @@ -74,7 +74,7 @@ --ice: #60a5fa; --hover: #1a202e; --disabled-run: #6366f1; - --selected: #2196f3; + --selected: #0369a1; --muted: 223 27% 11%; /* hsl(223 27% 11%) */ --muted-foreground: 215.4 16.3% 56.9%; /* hsl(215 16% 56%) */ @@ -132,7 +132,7 @@ --chat-send: #059669; --status-green: #4ade80; --status-blue: #2563eb; - --connection: #555; + --connection: #6d6c6c; --beta-background: rgb(37 99 235); --beta-foreground: rgb(219 234 254); diff --git a/src/frontend/src/types/api/index.ts b/src/frontend/src/types/api/index.ts index 86dd13c87..2ae8b20f6 100644 --- a/src/frontend/src/types/api/index.ts +++ b/src/frontend/src/types/api/index.ts @@ -93,6 +93,10 @@ export type UploadFileTypeAPI = { flowId: string; }; +export type ProfilePicturesTypeAPI = { + files: string[]; +}; + export type LoginType = { grant_type?: string; username: string; diff --git a/src/frontend/src/types/components/index.ts b/src/frontend/src/types/components/index.ts index 7b282b98e..8d1fef5d1 100644 --- a/src/frontend/src/types/components/index.ts +++ b/src/frontend/src/types/components/index.ts @@ -396,7 +396,7 @@ export type loginInputStateType = { export type patchUserInputStateType = { password: string; cnfPassword: string; - gradient: string; + profilePicture: string; apikey: string; }; @@ -491,7 +491,7 @@ export type ChatInputType = { isDragging: boolean; files: FilePreviewType[]; setFiles: ( - files: FilePreviewType[] | ((prev: FilePreviewType[]) => FilePreviewType[]), + files: FilePreviewType[] | ((prev: FilePreviewType[]) => FilePreviewType[]) ) => void; chatValue: string; inputRef: { @@ -546,13 +546,7 @@ export type nodeToolbarPropsType = { openAdvancedModal?: boolean; onCloseAdvancedModal?: (close: boolean) => void; selected: boolean; - updateNodeCode?: ( - newNodeClass: APIClassType, - code: string, - name: string, - ) => void; setShowState: (show: boolean | SetStateAction) => void; - isOutdated?: boolean; }; export type parsedDataType = { @@ -599,7 +593,7 @@ export type chatMessagePropsType = { updateChat: ( chat: ChatMessageType, message: string, - stream_url?: string, + stream_url?: string ) => void; }; @@ -691,12 +685,12 @@ export type codeTabsPropsType = { value: string, node: NodeType, template: TemplateVariableType, - tweak: tweakType, + tweak: tweakType ) => string; buildTweakObject?: ( tw: string, changes: string | string[] | boolean | number | Object[] | Object, - template: TemplateVariableType, + template: TemplateVariableType ) => Promise; }; activeTweaks?: boolean; @@ -778,7 +772,6 @@ export type IOFileInputProps = { }; export type toolbarSelectItemProps = { - isMac: boolean; value: string; icon: string; style?: string; diff --git a/src/frontend/src/utils/reactflowUtils.ts b/src/frontend/src/utils/reactflowUtils.ts index a1e592458..4c267dc32 100644 --- a/src/frontend/src/utils/reactflowUtils.ts +++ b/src/frontend/src/utils/reactflowUtils.ts @@ -11,6 +11,7 @@ import ShortUniqueId from "short-unique-id"; import getFieldTitle from "../CustomNodes/utils/get-field-title"; import { INPUT_TYPES, + IS_MAC, LANGFLOW_SUPPORTED_TYPES, OUTPUT_TYPES, SUCCESS_BUILD, @@ -99,18 +100,18 @@ export function unselectAllNodes({ updateNodes, data }: unselectAllNodesType) { export function isValidConnection( { source, target, sourceHandle, targetHandle }: Connection, nodes: Node[], - edges: Edge[], + edges: Edge[] ) { const targetHandleObject: targetHandleType = scapeJSONParse(targetHandle!); const sourceHandleObject: sourceHandleType = scapeJSONParse(sourceHandle!); if ( targetHandleObject.inputTypes?.some( - (n) => n === sourceHandleObject.dataType, + (n) => n === sourceHandleObject.dataType ) || sourceHandleObject.baseClasses.some( (t) => targetHandleObject.inputTypes?.some((n) => n === t) || - t === targetHandleObject.type, + t === targetHandleObject.type ) ) { let targetNode = nodes.find((node) => node.id === target!)?.data?.node; @@ -143,7 +144,7 @@ export function removeApiKeys(flow: FlowType): FlowType { export function updateTemplate( reference: APITemplateType, - objectToUpdate: APITemplateType, + objectToUpdate: APITemplateType ): APITemplateType { let clonedObject: APITemplateType = cloneDeep(reference); @@ -179,7 +180,7 @@ export const processFlows = (DbData: FlowType[], skipUpdate = true) => { ] = cloneDeep((flow.data.nodes[0].data as NodeDataType).node!); return; } - if (!skipUpdate) processDataFromFlow(flow, false); + processDataFromFlow(flow, !skipUpdate); } catch (e) { console.log(e); } @@ -203,7 +204,7 @@ export const processDataFromFlow = (flow: FlowType, refreshIds = true) => { export function updateIds( { edges, nodes }: { edges: Edge[]; nodes: Node[] }, - selection?: { edges: Edge[]; nodes: Node[] }, + selection?: { edges: Edge[]; nodes: Node[] } ) { let idsMap = {}; const selectionIds = selection?.nodes.map((n) => n.id); @@ -231,7 +232,7 @@ export function updateIds( edge.source = idsMap[edge.source]; edge.target = idsMap[edge.target]; const sourceHandleObject: sourceHandleType = scapeJSONParse( - edge.sourceHandle!, + edge.sourceHandle! ); edge.sourceHandle = scapedJSONStringfy({ ...sourceHandleObject, @@ -241,7 +242,7 @@ export function updateIds( edge.data.sourceHandle.id = edge.source; } const targetHandleObject: targetHandleType = scapeJSONParse( - edge.targetHandle!, + edge.targetHandle! ); edge.targetHandle = scapedJSONStringfy({ ...targetHandleObject, @@ -287,11 +288,11 @@ export function validateNode(node: NodeType, edges: Edge[]): Array { (scapeJSONParse(edge.targetHandle!) as targetHandleType).fieldName === t && (scapeJSONParse(edge.targetHandle!) as targetHandleType).id === - node.id, + node.id ) ) { errors.push( - `${displayName || type} is missing ${getFieldTitle(template, t)}.`, + `${displayName || type} is missing ${getFieldTitle(template, t)}.` ); } else if ( template[t].type === "dict" && @@ -305,15 +306,15 @@ export function validateNode(node: NodeType, edges: Edge[]): Array { errors.push( `${displayName || type} (${getFieldTitle( template, - t, - )}) contains duplicate keys with the same values.`, + t + )}) contains duplicate keys with the same values.` ); if (hasEmptyKey(template[t].value)) errors.push( `${displayName || type} (${getFieldTitle( template, - t, - )}) field must not be empty.`, + t + )}) field must not be empty.` ); } return errors; @@ -322,7 +323,7 @@ export function validateNode(node: NodeType, edges: Edge[]): Array { export function validateNodes( nodes: Node[], - edges: Edge[], + edges: Edge[] ): // this returns an array of tuples with the node id and the errors Array<{ id: string; errors: Array }> { if (nodes.length === 0) { @@ -343,9 +344,9 @@ export function updateEdges(edges: Edge[]) { if (edges) edges.forEach((edge) => { const targetHandleObject: targetHandleType = scapeJSONParse( - edge.targetHandle!, + edge.targetHandle! ); - edge.className = "stroke-gray-900 stroke-connection"; + edge.className = ""; }); } @@ -410,7 +411,7 @@ export function handleKeyDown( | React.KeyboardEvent | React.KeyboardEvent, inputValue: string | string[] | null, - block: string, + block: string ) { //condition to fix bug control+backspace on Windows/Linux if ( @@ -420,9 +421,7 @@ export function handleKeyDown( (inputValue === block || inputValue?.charAt(inputValue?.length - 1) === " " || specialCharsRegex.test(inputValue?.charAt(inputValue?.length - 1)))) || - (navigator.userAgent.toUpperCase().includes("MAC") && - e.ctrlKey === true && - e.key === "Backspace") + (IS_MAC && e.ctrlKey === true && e.key === "Backspace") ) { e.preventDefault(); e.stopPropagation(); @@ -435,7 +434,7 @@ export function handleKeyDown( } export function handleOnlyIntegerInput( - event: React.KeyboardEvent, + event: React.KeyboardEvent ) { if ( event.key === "." || @@ -451,7 +450,7 @@ export function handleOnlyIntegerInput( export function getConnectedNodes( edge: Edge, - nodes: Array, + nodes: Array ): Array { const sourceId = edge.source; const targetId = edge.target; @@ -552,7 +551,7 @@ export function checkOldEdgesHandles(edges: Edge[]): boolean { !edge.sourceHandle || !edge.targetHandle || !edge.sourceHandle.includes("{") || - !edge.targetHandle.includes("{"), + !edge.targetHandle.includes("{") ); } @@ -575,7 +574,7 @@ export function customStringify(obj: any): string { const keys = Object.keys(obj).sort(); const keyValuePairs = keys.map( - (key) => `"${key}":${customStringify(obj[key])}`, + (key) => `"${key}":${customStringify(obj[key])}` ); return `{${keyValuePairs.join(",")}}`; } @@ -604,7 +603,7 @@ export function getHandleId( source: string, sourceHandle: string, target: string, - targetHandle: string, + targetHandle: string ) { return ( "reactflow__edge-" + source + sourceHandle + "-" + target + targetHandle @@ -615,7 +614,7 @@ export function generateFlow( selection: OnSelectionChangeParams, nodes: Node[], edges: Edge[], - name: string, + name: string ): generateFlowType { const newFlowData = { nodes, edges, viewport: { zoom: 1, x: 0, y: 0 } }; const uid = new ShortUniqueId({ length: 5 }); @@ -624,7 +623,7 @@ export function generateFlow( newFlowData.edges = selection.edges.filter( (edge) => selection.nodes.some((node) => node.id === edge.target) && - selection.nodes.some((node) => node.id === edge.source), + selection.nodes.some((node) => node.id === edge.source) ); newFlowData.nodes = selection.nodes; @@ -645,7 +644,7 @@ export function generateFlow( (edge) => (selection.nodes.some((node) => node.id === edge.target) || selection.nodes.some((node) => node.id === edge.source)) && - newFlowData.edges.every((e) => e.id !== edge.id), + newFlowData.edges.every((e) => e.id !== edge.id) ), }; } @@ -656,13 +655,13 @@ export function reconnectEdges(groupNode: NodeType, excludedEdges: Edge[]) { const { nodes, edges } = groupNode.data.node!.flow!.data!; const lastNode = findLastNode(groupNode.data.node!.flow!.data!); newEdges = newEdges.filter( - (e) => !(nodes.some((n) => n.id === e.source) && e.source !== lastNode?.id), + (e) => !(nodes.some((n) => n.id === e.source) && e.source !== lastNode?.id) ); newEdges.forEach((edge) => { if (lastNode && edge.source === lastNode.id) { edge.source = groupNode.id; let newSourceHandle: sourceHandleType = scapeJSONParse( - edge.sourceHandle!, + edge.sourceHandle! ); newSourceHandle.id = groupNode.id; edge.sourceHandle = scapedJSONStringfy(newSourceHandle); @@ -689,7 +688,7 @@ export function reconnectEdges(groupNode: NodeType, excludedEdges: Edge[]) { export function filterFlow( selection: OnSelectionChangeParams, setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void, - setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void, + setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void ) { setNodes((nodes) => nodes.filter((node) => !selection.nodes.includes(node))); setEdges((edges) => edges.filter((edge) => !selection.edges.includes(edge))); @@ -727,7 +726,7 @@ export function updateFlowPosition(NewPosition: XYPosition, flow: FlowType) { export function concatFlows( flow: FlowType, setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void, - setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void, + setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void ) { const { nodes, edges } = flow.data!; setNodes((old) => [...old, ...nodes]); @@ -736,7 +735,7 @@ export function concatFlows( export function validateSelection( selection: OnSelectionChangeParams, - edges: Edge[], + edges: Edge[] ): Array { const clonedSelection = cloneDeep(selection); const clonedEdges = cloneDeep(edges); @@ -750,7 +749,7 @@ export function validateSelection( let nodesSet = new Set(clonedSelection.nodes.map((n) => n.id)); // then filter the edges that are connected to the nodes in the set let connectedEdges = clonedSelection.edges.filter( - (e) => nodesSet.has(e.source) && nodesSet.has(e.target), + (e) => nodesSet.has(e.source) && nodesSet.has(e.target) ); // add the edges to the selection clonedSelection.edges = connectedEdges; @@ -764,17 +763,17 @@ export function validateSelection( clonedSelection.nodes.some( (node) => isInputNode(node.data as NodeDataType) || - isOutputNode(node.data as NodeDataType), + isOutputNode(node.data as NodeDataType) ) ) { errorsArray.push( - "Please select only nodes that are not input or output nodes", + "Please select only nodes that are not input or output nodes" ); } //check if there are two or more nodes with free outputs if ( clonedSelection.nodes.filter( - (n) => !clonedSelection.edges.some((e) => e.source === n.id), + (n) => !clonedSelection.edges.some((e) => e.source === n.id) ).length > 1 ) { errorsArray.push("Please select only one node with free outputs"); @@ -785,7 +784,7 @@ export function validateSelection( clonedSelection.nodes.some( (node) => !clonedSelection.edges.some((edge) => edge.target === node.id) && - !clonedSelection.edges.some((edge) => edge.source === node.id), + !clonedSelection.edges.some((edge) => edge.source === node.id) ) ) { errorsArray.push("Please select only nodes that are connected"); @@ -842,8 +841,8 @@ export function mergeNodeTemplates({ nodeTemplate[key].display_name ? nodeTemplate[key].display_name : nodeTemplate[key].name - ? toTitleCase(nodeTemplate[key].name) - : toTitleCase(key); + ? toTitleCase(nodeTemplate[key].name) + : toTitleCase(key); } } }); @@ -854,7 +853,7 @@ function isHandleConnected( edges: Edge[], key: string, field: TemplateVariableType, - nodeId: string, + nodeId: string ) { /* this function receives a flow and a handleId and check if there is a connection with this handle @@ -870,7 +869,7 @@ function isHandleConnected( id: nodeId, proxy: { id: field.proxy!.id, field: field.proxy!.field }, inputTypes: field.input_types, - } as targetHandleType), + } as targetHandleType) ) ) { return true; @@ -885,7 +884,7 @@ function isHandleConnected( fieldName: key, id: nodeId, inputTypes: field.input_types, - } as targetHandleType), + } as targetHandleType) ) ) { return true; @@ -908,7 +907,7 @@ export function generateNodeTemplate(Flow: FlowType) { export function generateNodeFromFlow( flow: FlowType, - getNodeId: (type: string) => string, + getNodeId: (type: string) => string ): NodeType { const { nodes } = flow.data!; const outputNode = cloneDeep(findLastNode(flow.data!)); @@ -939,7 +938,7 @@ export function generateNodeFromFlow( export function connectedInputNodesOnHandle( nodeId: string, handleId: string, - { nodes, edges }: { nodes: NodeType[]; edges: Edge[] }, + { nodes, edges }: { nodes: NodeType[]; edges: Edge[] } ) { const connectedNodes: Array<{ name: string; id: string; isGroup: boolean }> = []; @@ -976,7 +975,7 @@ export function connectedInputNodesOnHandle( export function updateProxyIdsOnTemplate( template: APITemplateType, - idsMap: { [key: string]: string }, + idsMap: { [key: string]: string } ) { Object.keys(template).forEach((key) => { if (template[key].proxy && idsMap[template[key].proxy!.id]) { @@ -987,7 +986,7 @@ export function updateProxyIdsOnTemplate( export function updateEdgesIds( edges: Edge[], - idsMap: { [key: string]: string }, + idsMap: { [key: string]: string } ) { edges.forEach((edge) => { let targetHandle: targetHandleType = edge.data.targetHandle; @@ -1005,11 +1004,6 @@ export function processFlowEdges(flow: FlowType) { const newEdges = updateEdgesHandleIds(flow.data); flow.data.edges = newEdges; } - //update edges colors - flow.data.edges.forEach((edge) => { - edge.className = ""; - edge.style = { stroke: "#555" }; - }); } export function expandGroupNode( @@ -1019,7 +1013,7 @@ export function expandGroupNode( nodes: Node[], edges: Edge[], setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void, - setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void, + setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void ) { const idsMap = updateIds(flow!.data!); updateProxyIdsOnTemplate(template, idsMap); @@ -1062,7 +1056,7 @@ export function expandGroupNode( const lastNode = cloneDeep(findLastNode(flow!.data!)); newEdge.source = lastNode!.id; let newSourceHandle: sourceHandleType = scapeJSONParse( - newEdge.sourceHandle!, + newEdge.sourceHandle! ); newSourceHandle.id = lastNode!.id; newEdge.data.sourceHandle = newSourceHandle; @@ -1119,7 +1113,7 @@ export function expandGroupNode( export function getGroupStatus( flow: FlowType, - ssData: { [key: string]: { valid: boolean; params: string } }, + ssData: { [key: string]: { valid: boolean; params: string } } ) { let status = { valid: true, params: SUCCESS_BUILD }; const { nodes } = flow.data!; @@ -1138,7 +1132,7 @@ export function getGroupStatus( export function createFlowComponent( nodeData: NodeDataType, - version: string, + version: string ): FlowType { const flowNode: FlowType = { data: { @@ -1174,7 +1168,7 @@ export function downloadNode(NodeFLow: FlowType) { export function updateComponentNameAndType( data: any, - component: NodeDataType, + component: NodeDataType ) {} export function removeFileNameFromComponents(flow: FlowType) { @@ -1248,7 +1242,7 @@ export function extractFieldsFromComponenents(data: APIObjectType) { export function downloadFlow( flow: FlowType, flowName: string, - flowDescription?: string, + flowDescription?: string ) { let clonedFlow = cloneDeep(flow); removeFileNameFromComponents(clonedFlow); @@ -1258,7 +1252,7 @@ export function downloadFlow( ...clonedFlow, name: flowName, description: flowDescription, - }), + }) )}`; // create a link element and set its properties @@ -1273,7 +1267,7 @@ export function downloadFlow( export function downloadFlows() { downloadFlowsFromDatabase().then((flows) => { const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent( - JSON.stringify(flows), + JSON.stringify(flows) )}`; // create a link element and set its properties @@ -1297,7 +1291,7 @@ export function getRandomDescription(): string { export const createNewFlow = ( flowData: ReactFlowJsonObject, flow: FlowType, - folderId: string, + folderId: string ) => { return { description: flow?.description ?? getRandomDescription(), diff --git a/src/frontend/src/utils/styleUtils.ts b/src/frontend/src/utils/styleUtils.ts index e15966c63..b7e5995c6 100644 --- a/src/frontend/src/utils/styleUtils.ts +++ b/src/frontend/src/utils/styleUtils.ts @@ -116,6 +116,7 @@ import { Settings, Settings2, Share, + AlertTriangle, Share2, Shield, Sliders, @@ -434,6 +435,7 @@ export const nodeIconsLucide: iconsType = { SunIcon, MoonIcon, Bell, + AlertTriangle, ChevronLeft, SlidersHorizontal, Palette, diff --git a/src/frontend/src/utils/utils.ts b/src/frontend/src/utils/utils.ts index aecf874b7..f067f3617 100644 --- a/src/frontend/src/utils/utils.ts +++ b/src/frontend/src/utils/utils.ts @@ -1,7 +1,6 @@ import { ColDef, ColGroupDef } from "ag-grid-community"; import clsx, { ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; -import TableAutoCellRender from "../components/tableComponent/components/tableAutoCellRender"; import { APIDataType, TemplateVariableType } from "../types/api"; import { groupedObjType, @@ -10,6 +9,7 @@ import { } from "../types/components"; import { NodeType } from "../types/flow"; import { FlowState } from "../types/tabs"; +import TableAutoCellRender from "../components/tableComponent/components/tableAutoCellRender"; export function classNames(...classes: Array): string { return classes.filter(Boolean).join(" "); diff --git a/src/frontend/tests/end-to-end/chatInputOutputUser.spec.ts b/src/frontend/tests/end-to-end/chatInputOutputUser.spec.ts index 399d40948..ce1a9ce27 100644 --- a/src/frontend/tests/end-to-end/chatInputOutputUser.spec.ts +++ b/src/frontend/tests/end-to-end/chatInputOutputUser.spec.ts @@ -227,4 +227,8 @@ test("user must be able to send an image on chat", async ({ page }) => { await page.getByTestId("icon-LucideSend").click(); await page.waitForTimeout(2000); await page.getByText("chain.png").isVisible(); + + await page.getByText("Close", { exact: true }).click(); + await page.getByTestId("icon-ScanEye").last().click(); + await page.getByText("Restart").isHidden(); });