@@ -552,7 +597,7 @@ export default function GenericNode({
!data.node?.description) &&
nameEditable
? "font-light italic"
- : ""
+ : "",
)}
onClick={(e) => {
setInputDescription(true);
@@ -614,13 +659,13 @@ export default function GenericNode({
}
title={getFieldTitle(
data.node?.template!,
- templateField
+ templateField,
)}
info={data.node?.template[templateField].info}
name={templateField}
tooltipTitle={
data.node?.template[templateField].input_types?.join(
- "\n"
+ "\n",
) ?? data.node?.template[templateField].type
}
required={data.node!.template[templateField].required}
@@ -647,7 +692,7 @@ export default function GenericNode({
{" "}
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..4cbfbd8df 100644
--- a/src/frontend/src/CustomNodes/hooks/use-check-code-validity.tsx
+++ b/src/frontend/src/CustomNodes/hooks/use-check-code-validity.tsx
@@ -26,7 +26,8 @@ const useCheckCodeValidity = (
const componentsToIgnore = ["Custom Component", "Prompt"];
if (
currentCode !== thisNodesCode &&
- !componentsToIgnore.includes(data.node!.display_name)
+ !componentsToIgnore.includes(data.node!.display_name) &&
+ !(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/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/index.tsx b/src/frontend/src/components/headerComponent/index.tsx
index 455cdf8a4..eb27a1482 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/sidebarComponent/components/sideBarFolderButtons/index.tsx b/src/frontend/src/components/sidebarComponent/components/sideBarFolderButtons/index.tsx
index 234eb9304..d43f753c5 100644
--- a/src/frontend/src/components/sidebarComponent/components/sideBarFolderButtons/index.tsx
+++ b/src/frontend/src/components/sidebarComponent/components/sideBarFolderButtons/index.tsx
@@ -31,7 +31,7 @@ const SideBarFoldersButtonsComponent = ({
const [foldersNames, setFoldersNames] = useState({});
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
const [editFolders, setEditFolderName] = useState(
- folders.map((obj) => ({ name: obj.name, edit: false }))
+ folders.map((obj) => ({ name: obj.name, edit: false })),
);
const uploadFolder = useFolderStore((state) => state.uploadFolder);
const currentFolder = pathname.split("/");
@@ -58,7 +58,7 @@ const SideBarFoldersButtonsComponent = ({
const { dragOver, dragEnter, dragLeave, onDrop } = useFileDrop(
folderId,
- handleFolderChange
+ handleFolderChange,
);
const handleUploadFlowsToFolder = () => {
@@ -86,7 +86,7 @@ const SideBarFoldersButtonsComponent = ({
addFolder({ name: "New Folder", parent_id: null, description: "" }).then(
(res) => {
getFoldersApi(true);
- }
+ },
);
}
@@ -132,7 +132,7 @@ const SideBarFoldersButtonsComponent = ({
<>
{folders.map((item, index) => {
const editFolderName = editFolders?.filter(
- (folder) => folder.name === item.name
+ (folder) => folder.name === item.name,
)[0];
return (
handleChangeFolder!(item.id!)}
>
@@ -218,7 +218,7 @@ const SideBarFoldersButtonsComponent = ({
folders.map((obj) => ({
name: obj.name,
edit: false,
- }))
+ })),
);
}
if (e.key === "Enter") {
@@ -251,10 +251,10 @@ const SideBarFoldersButtonsComponent = ({
};
const updatedFolder = await updateFolder(
body,
- item.id!
+ item.id!,
);
const updateFolders = folders.filter(
- (f) => f.name !== item.name
+ (f) => f.name !== item.name,
);
setFolders([...updateFolders, updatedFolder]);
setFoldersNames({});
@@ -262,7 +262,7 @@ const SideBarFoldersButtonsComponent = ({
folders.map((obj) => ({
name: obj.name,
edit: false,
- }))
+ })),
);
} else {
setFoldersNames((old) => ({
diff --git a/src/frontend/src/components/tableComponent/components/tableNodeCellRender/index.tsx b/src/frontend/src/components/tableComponent/components/tableNodeCellRender/index.tsx
index 6351d5d98..86db7de9c 100644
--- a/src/frontend/src/components/tableComponent/components/tableNodeCellRender/index.tsx
+++ b/src/frontend/src/components/tableComponent/components/tableNodeCellRender/index.tsx
@@ -63,8 +63,8 @@ export default function TableNodeCellRender({
...id,
proxy: templateData.proxy,
}
- : id
- )
+ : id,
+ ),
) ?? false;
function getCellType() {
switch (templateData.type) {
@@ -135,7 +135,7 @@ export default function TableNodeCellRender({
1 ? "my-3" : ""
+ templateValue?.length > 1 ? "my-3" : "",
)}
>
{
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 28a87bcaf..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,
@@ -62,7 +63,7 @@ export async function sendAll(data: sendAllProps) {
}
export async function postValidateCode(
- code: string
+ code: string,
): Promise> {
return await api.post(`${BASE_URL_API}validate/code`, { code });
}
@@ -77,7 +78,7 @@ export async function postValidateCode(
export async function postValidatePrompt(
name: string,
template: string,
- frontend_node: APIClassType
+ frontend_node: APIClassType,
): Promise> {
return api.post(`${BASE_URL_API}validate/prompt`, {
name,
@@ -150,7 +151,7 @@ export async function saveFlowToDatabase(newFlow: {
* @throws Will throw an error if the update fails.
*/
export async function updateFlowInDatabase(
- updatedFlow: FlowType
+ updatedFlow: FlowType,
): Promise {
try {
const response = await api.patch(`${BASE_URL_API}flows/${updatedFlow.id}`, {
@@ -328,7 +329,7 @@ export async function getHealth() {
*
*/
export async function getBuildStatus(
- flowId: string
+ flowId: string,
): Promise> {
return await api.get(`${BASE_URL_API}build/${flowId}/status`);
}
@@ -341,7 +342,7 @@ export async function getBuildStatus(
*
*/
export async function postBuildInit(
- flow: FlowType
+ flow: FlowType,
): Promise> {
return await api.post(`${BASE_URL_API}build/init/${flow.id}`, flow);
}
@@ -357,16 +358,29 @@ export async function postBuildInit(
*/
export async function uploadFile(
file: File,
- id: string
+ id: string,
): Promise> {
const formData = new FormData();
formData.append("file", file);
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
+ apiClass: APIClassType,
): Promise> {
// let template = apiClass.template;
return await api.post(`${BASE_URL_API}custom_component`, {
@@ -379,7 +393,7 @@ export async function postCustomComponentUpdate(
code: string,
template: APITemplateType,
field: string,
- field_value: any
+ field_value: any,
): Promise> {
return await api.post(`${BASE_URL_API}custom_component/update`, {
code,
@@ -401,7 +415,7 @@ export async function onLogin(user: LoginType) {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
- }
+ },
);
if (response.status === 200) {
@@ -463,11 +477,11 @@ export async function addUser(user: UserInputType): Promise> {
export async function getUsersPage(
skip: number,
- limit: number
+ limit: number,
): Promise> {
try {
const res = await api.get(
- `${BASE_URL_API}users/?skip=${skip}&limit=${limit}`
+ `${BASE_URL_API}users/?skip=${skip}&limit=${limit}`,
);
if (res.status === 200) {
return res.data;
@@ -504,7 +518,7 @@ export async function resetPassword(user_id: string, user: resetPasswordType) {
try {
const res = await api.patch(
`${BASE_URL_API}users/${user_id}/reset-password`,
- user
+ user,
);
if (res.status === 200) {
return res.data;
@@ -578,7 +592,7 @@ export async function saveFlowStore(
last_tested_version?: string;
},
tags: string[],
- publicFlow = false
+ publicFlow = false,
): Promise {
try {
const response = await api.post(`${BASE_URL_API}store/components/`, {
@@ -707,7 +721,7 @@ export async function postStoreComponents(component: Component) {
export async function getComponent(component_id: string) {
try {
const res = await api.get(
- `${BASE_URL_API}store/components/${component_id}`
+ `${BASE_URL_API}store/components/${component_id}`,
);
if (res.status === 200) {
return res.data;
@@ -722,7 +736,7 @@ export async function searchComponent(
page?: number | null,
limit?: number | null,
status?: string | null,
- tags?: string[]
+ tags?: string[],
): Promise {
try {
let url = `${BASE_URL_API}store/components/`;
@@ -834,7 +848,7 @@ export async function updateFlowStore(
},
tags: string[],
publicFlow = false,
- id: string
+ id: string,
): Promise {
try {
const response = await api.patch(`${BASE_URL_API}store/components/${id}`, {
@@ -918,7 +932,7 @@ export async function deleteGlobalVariable(id: string) {
export async function updateGlobalVariable(
name: string,
value: string,
- id: string
+ id: string,
) {
try {
const response = api.patch(`${BASE_URL_API}variables/${id}`, {
@@ -937,7 +951,7 @@ export async function getVerticesOrder(
startNodeId?: string | null,
stopNodeId?: string | null,
nodes?: Node[],
- Edges?: Edge[]
+ Edges?: Edge[],
): Promise> {
// nodeId is optional and is a query parameter
// if nodeId is not provided, the API will return all vertices
@@ -957,7 +971,7 @@ export async function getVerticesOrder(
return await api.post(
`${BASE_URL_API}build/${flowId}/vertices`,
data,
- config
+ config,
);
}
@@ -965,7 +979,7 @@ export async function postBuildVertex(
flowId: string,
vertexId: string,
input_value: string,
- files?: string[]
+ files?: string[],
): Promise> {
// input_value is optional and is a query parameter
const data = { inputs: { input_value: input_value ?? "" } };
@@ -974,7 +988,7 @@ export async function postBuildVertex(
}
return await api.post(
`${BASE_URL_API}build/${flowId}/vertices/${vertexId}`,
- data
+ data,
);
}
@@ -998,7 +1012,7 @@ export async function getFlowPool({
}
export async function deleteFlowPool(
- flowId: string
+ flowId: string,
): Promise> {
const config = {};
config["params"] = { flow_id: flowId };
@@ -1012,7 +1026,7 @@ export async function deleteFlowPool(
* @returns A promise that resolves to an array of AxiosResponse objects representing the delete responses.
*/
export async function multipleDeleteFlowsComponents(
- flowIds: string[]
+ flowIds: string[],
): Promise[]> {
const batches: string[][] = [];
@@ -1035,7 +1049,7 @@ export async function multipleDeleteFlowsComponents(
// Execute all delete requests
const responses: Promise>[] = batches.map((batch) =>
- deleteBatch(batch)
+ deleteBatch(batch),
);
// Return the responses after all requests are completed
@@ -1045,7 +1059,7 @@ export async function multipleDeleteFlowsComponents(
export async function getTransactionTable(
id: string,
mode: "intersection" | "union",
- params = {}
+ params = {},
): Promise<{ rows: Array