From f62e85d609da72fd78eb43cb8c62d5ac6c2f4bec Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Wed, 30 Jul 2025 16:30:18 +0300 Subject: [PATCH 01/64] fix(633): fix the bug --- GUI/src/components/ServicesTable/index.tsx | 5 ++++- GUI/src/store/services.store.ts | 14 ++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/GUI/src/components/ServicesTable/index.tsx b/GUI/src/components/ServicesTable/index.tsx index 3df7a38a8..bf1f2ad8a 100644 --- a/GUI/src/components/ServicesTable/index.tsx +++ b/GUI/src/components/ServicesTable/index.tsx @@ -110,12 +110,15 @@ const ServicesTable: FC = ({ isCommon = false }) => { }; const deleteSelectedService = () => { + // todo delete here useServiceListStore .getState() .deleteSelectedService( () => setIsDeletePopupVisible(false), t("overview.service.toast.deleted"), - t("overview.service.toast.failed.delete") + t("overview.service.toast.failed.delete"), + pagination, + sorting ); }; diff --git a/GUI/src/store/services.store.ts b/GUI/src/store/services.store.ts index 795af56df..5d362524d 100644 --- a/GUI/src/store/services.store.ts +++ b/GUI/src/store/services.store.ts @@ -37,7 +37,13 @@ interface ServiceStoreState { sorting: SortingState ) => Promise; checkServiceIntentConnection: (onConnected: (response: Trigger) => void, onNotConnected: () => void) => Promise; - deleteSelectedService: (onEnd: () => void, successMessage: string, errorMessage: string) => Promise; + deleteSelectedService: ( + onEnd: () => void, + successMessage: string, + errorMessage: string, + pagination: PaginationState, + sorting: SortingState + ) => Promise; requestServiceIntentConnection: ( onEnd: () => void, successMessage: string, @@ -212,7 +218,7 @@ const useServiceListStore = create((set, get, store) => ({ onNotConnected(); } }, - deleteSelectedService: async (onEnd, successMessage, errorMessage) => { + deleteSelectedService: async (onEnd, successMessage, errorMessage, pagination, sorting) => { const selectedService = get().selectedService; if (!selectedService) return; @@ -222,8 +228,8 @@ const useServiceListStore = create((set, get, store) => ({ type: selectedService?.type, }); useToastStore.getState().success({ title: successMessage }); - await useServiceListStore.getState().loadServicesList({ pageIndex: 0, pageSize: 10 }, []); - await useServiceListStore.getState().loadCommonServicesList({ pageIndex: 0, pageSize: 10 }, []); + await useServiceListStore.getState().loadServicesList(pagination, sorting); + await useServiceListStore.getState().loadCommonServicesList(pagination, sorting); } catch (error) { console.error(error); useToastStore.getState().error({ title: errorMessage }); From 8b694361607af1b88e2065e342ee10f402e78c1c Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Wed, 30 Jul 2025 16:33:31 +0300 Subject: [PATCH 02/64] fix(633): clean up --- GUI/src/components/ServicesTable/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/GUI/src/components/ServicesTable/index.tsx b/GUI/src/components/ServicesTable/index.tsx index bf1f2ad8a..7078f9b5c 100644 --- a/GUI/src/components/ServicesTable/index.tsx +++ b/GUI/src/components/ServicesTable/index.tsx @@ -110,7 +110,6 @@ const ServicesTable: FC = ({ isCommon = false }) => { }; const deleteSelectedService = () => { - // todo delete here useServiceListStore .getState() .deleteSelectedService( From 98753d063ec2aaaf2816826ec5747e13363eb30d Mon Sep 17 00:00:00 2001 From: 1AhmedYasser <26207361+1AhmedYasser@users.noreply.github.com> Date: Wed, 30 Jul 2025 19:48:19 +0300 Subject: [PATCH 03/64] chore(644): Added Params Key/Value Pair Changes --- .../Endpoints/Custom/index.tsx | 2 +- .../Endpoints/OpenAPI/index.tsx | 4 +- .../Endpoints/RequestVariables/index.tsx | 57 ++++++------ GUI/src/components/ApiEndpointCard/index.tsx | 15 +--- GUI/src/store/new-services.store.ts | 89 +++++++------------ 5 files changed, 67 insertions(+), 100 deletions(-) diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/Custom/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/Custom/index.tsx index 4afb632ec..f45087c76 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/Custom/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/Custom/index.tsx @@ -142,7 +142,7 @@ const EndpointCustom: React.FC = ({ key={key} requestValues={requestValues} isLive={isLive} - endpointData={endpoint.definitions[0]} + endpoint={endpoint} requestTab={requestTab} setRequestTab={setRequestTab} parentEndpointId={endpoint.endpointId} diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/OpenAPI/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/OpenAPI/index.tsx index 1eb79b2d1..cc62e1c3e 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/OpenAPI/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/OpenAPI/index.tsx @@ -340,11 +340,11 @@ const EndpointOpenAPI: React.FC = ({ key={key} disableRawData isLive={isLive} - endpointData={selectedEndpoint} - updateEndpointData={updateEndpointData} + endpoint={endpoint} requestValues={requestValues} requestTab={requestTab} setRequestTab={setRequestTab} + onParametersChange={() => {}} /> ) : ( diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx index 5f4a4d976..0a290f987 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx @@ -22,7 +22,7 @@ import { PaginationState, SortingState } from "@tanstack/react-table"; type RequestVariablesProps = { disableRawData?: boolean; - endpointData: EndpointDefinition; + endpoint: EndpointData; parentEndpointId?: string; isLive: boolean; requestValues: PreDefinedEndpointEnvVariables; @@ -33,7 +33,7 @@ type RequestVariablesProps = { const RequestVariables: React.FC = ({ disableRawData, - endpointData, + endpoint, isLive, requestValues, requestTab, @@ -51,6 +51,8 @@ const RequestVariables: React.FC = ({ pageSize: 10, }); + console.log("endpoint", endpoint); + const [sorting, setSorting] = useState([]); const constructRow = (id: number, data: EndpointVariableData, nestedLevel: number): RequestVariablesRowData => { @@ -72,10 +74,11 @@ const RequestVariables: React.FC = ({ const getTabsRowsData = (): RequestVariablesTabsRowsData => { return tabs.reduce((tabsRowsData, tab) => { const rows: RequestVariablesRowData[] = []; + const endpointData = endpoint.definitions[0]; if (endpointData) { if (!endpointData[tab]) return tabsRowsData; let rowIdx = 0; - endpointData[tab]!.variables.forEach((variable) => { + endpointData[tab].variables.forEach((variable) => { rows.push(constructRow(rowIdx, variable, 0)); if (["schema", "array"].includes(variable.type)) { rowIdx = getRowsFromNestedSchema(variable, rowIdx, rows, 1); @@ -126,6 +129,7 @@ const RequestVariables: React.FC = ({ const getInitialTabsRawData = (): RequestVariablesTabsRawData => { return tabs.reduce((tabsRawData, tab) => { + const endpointData = endpoint.definitions[0]; return { ...tabsRawData, [tab]: endpointData[tab]?.rawData[isLive ? "value" : "testValue"] ?? "" }; }, {}); }; @@ -137,10 +141,9 @@ const RequestVariables: React.FC = ({ const updateRowVariable = (id: string, variable: string) => { setRowsData((prevRowsData) => { - prevRowsData[requestTab.tab]!.map((row) => { - if (row.id !== id) return row; + prevRowsData[requestTab.tab]!.forEach((row) => { + if (row.id !== id) return; row.variable = variable; - return row; }); // if last row name is edited, add a new row if (!rowsData[requestTab.tab] || id !== `${rowsData[requestTab.tab]!.length - 1}`) return prevRowsData; @@ -152,17 +155,16 @@ const RequestVariables: React.FC = ({ }); return prevRowsData; }); - updateEndpointData(rowsData, endpointData?.id); + updateEndpointData(rowsData, endpoint); }; const updateRowValue = (id: string, value: string) => { if (!rowsData[requestTab.tab]) return; - rowsData[requestTab.tab]!.map((row) => { - if (row.id !== id) return row; + rowsData[requestTab.tab]!.forEach((row) => { + if (row.id !== id) return; row.value = value; - return row; }); - updateEndpointData(rowsData, endpointData?.id); + updateEndpointData(rowsData, endpoint); setKey(key + 1); }; @@ -184,26 +186,19 @@ const RequestVariables: React.FC = ({ }; const deleteVariable = (rowData: RequestVariablesRowData) => { - setEndpoints((prevEndpoints: EndpointData[]) => { - const newEndpoints: EndpointData[] = []; - for (const prevEndpoint of prevEndpoints) { - const defEndpoint = prevEndpoint.definitions.find((x) => x.id === endpointData.id); - const endpoint = defEndpoint?.[requestTab.tab]; + const endpointData = endpoint.definitions[0]; + const defEndpoint = endpoint.definitions.find((x) => x.id === endpointData.id); + const endpointTab = defEndpoint?.[requestTab.tab]; - if (defEndpoint && endpoint) { - if (rowData.endpointVariableId && endpoint.variables.map((v) => v.id).includes(rowData.endpointVariableId)) { - endpoint.variables = endpoint.variables.filter((v) => v.id !== rowData.endpointVariableId); - } else { - endpoint.variables - .filter((variable) => ["schema", "array"].includes(variable.type)) - .forEach((variable) => checkNestedVariables(rowData.endpointVariableId!, variable)); - } - } - - newEndpoints.push(prevEndpoint); + if (defEndpoint && endpointTab) { + if (rowData.endpointVariableId && endpointTab.variables.map((v) => v.id).includes(rowData.endpointVariableId)) { + endpointTab.variables = endpointTab.variables.filter((v) => v.id !== rowData.endpointVariableId); + } else { + endpointTab.variables + .filter((variable) => ["schema", "array"].includes(variable.type)) + .forEach((variable) => checkNestedVariables(rowData.endpointVariableId!, variable)); } - return newEndpoints; - }); + } }; const updateParams = (isValue: boolean, rowId: string, value: string) => { @@ -224,7 +219,7 @@ const RequestVariables: React.FC = ({ if (!row.value || !row.variable) return; parameters.push({ - id: row.endpointVariableId !== undefined ? row.endpointVariableId : row.id, + id: row.endpointVariableId ?? row.id, name: row.variable, type: row.type ?? "custom", required: row.required ?? false, @@ -281,7 +276,7 @@ const RequestVariables: React.FC = ({ name={`${requestTab.tab}-raw-data`} label={""} defaultValue={tabRawData[requestTab.tab]} - onBlur={() => updateEndpointRawData(tabRawData, endpointData.id, parentEndpointId)} + onBlur={() => updateEndpointRawData(tabRawData, endpoint)} onChange={(event) => { setJsonError(undefined); tabRawData[requestTab.tab] = event.target.value; diff --git a/GUI/src/components/ApiEndpointCard/index.tsx b/GUI/src/components/ApiEndpointCard/index.tsx index ea11ba291..92548ad80 100644 --- a/GUI/src/components/ApiEndpointCard/index.tsx +++ b/GUI/src/components/ApiEndpointCard/index.tsx @@ -1,9 +1,8 @@ import { FC, useMemo, useState } from "react"; import * as Tabs from "@radix-ui/react-tabs"; -import { Button, EndpointCustom, EndpointOpenAPI, FormInput, FormSelect, Icon, Switch, Track } from ".."; +import { EndpointCustom, EndpointOpenAPI, FormInput, FormSelect, Switch, Track } from ".."; import { Option } from "../../types/option"; import { useTranslation } from "react-i18next"; -import { MdDeleteOutline } from "react-icons/md"; import "./ApiEndpointCard.scss"; import { RequestTab } from "../../types"; import { EndpointData, EndpointEnv, EndpointTab } from "../../types/endpoint"; @@ -29,7 +28,7 @@ const ApiEndpointCard: FC = ({ onNameChange, onCommonChange, }) => { - const { deleteEndpoint, changeServiceEndpointType, getAvailableRequestValues } = useServiceStore(); + const { changeServiceEndpointType, getAvailableRequestValues } = useServiceStore(); const [selectedTab, setSelectedTab] = useState(EndpointEnv.Live); const [endpointName, setEndpointName] = useState(endpoint.name); const [isCommonEndpoint, setIsCommonEndpoint] = useState(endpoint.isCommon ?? false); @@ -44,7 +43,7 @@ const ApiEndpointCard: FC = ({ const getTabTriggerClasses = (tab: EndpointEnv) => `tab-group__tab-btn ${selectedTab === tab ? "active" : ""}`; - const requestValues = useMemo(() => getAvailableRequestValues(endpoint.endpointId), []); + const requestValues = useMemo(() => getAvailableRequestValues(endpoint), []); return ( = ({ {t("newService.endpoint.single")} - {isDeletable && ( - - )} {[EndpointEnv.Live, EndpointEnv.Test].map((env) => { return ( @@ -83,7 +76,7 @@ const ApiEndpointCard: FC = ({ onSelectionChange={(selection) => { setOption(selection); endpoint.type = selection?.value as EndpointType; - changeServiceEndpointType(endpoint.endpointId, (selection?.value ?? "custom") as EndpointType); + changeServiceEndpointType(endpoint, (selection?.value ?? "custom") as EndpointType); }} defaultValue={option?.value} /> diff --git a/GUI/src/store/new-services.store.ts b/GUI/src/store/new-services.store.ts index 58ab34872..ee7ab9a9d 100644 --- a/GUI/src/store/new-services.store.ts +++ b/GUI/src/store/new-services.store.ts @@ -77,19 +77,15 @@ interface ServiceStoreState { loadService: (id?: string, resetState?: boolean) => Promise | undefined>; loadCommonEndpoints: () => Promise; loadStepPreferences: () => Promise; - getAvailableRequestValues: (endpointId: string) => PreDefinedEndpointEnvVariables; + getAvailableRequestValues: (endpoint: EndpointData) => PreDefinedEndpointEnvVariables; onNameChange: (endpointId: string, oldName: string, newName: string) => void; - changeServiceEndpointType: (id: string, type: EndpointType) => void; + changeServiceEndpointType: (endpoint: EndpointData, type: EndpointType) => void; mapEndpointsToSteps: () => Step[]; selectedTab: EndpointEnv; setSelectedTab: (tab: EndpointEnv) => void; isLive: () => boolean; - updateEndpointRawData: ( - rawData: RequestVariablesTabsRawData, - endpointDataId?: string, - parentEndpointId?: string - ) => void; - updateEndpointData: (data: RequestVariablesTabsRowsData, endpointDataId?: string, parentEndpointId?: string) => void; + updateEndpointRawData: (rawData: RequestVariablesTabsRawData, endpoint?: EndpointData) => void; + updateEndpointData: (data: RequestVariablesTabsRowsData, endpoint?: EndpointData) => void; resetState: () => void; resetAssign: () => void; resetRules: () => void; @@ -248,12 +244,14 @@ const useServiceStore = create((set, get, store) => ({ try { const instance = get().reactFlowInstance; if (!instance) return; - const endpointNodes = instance.getNodes().filter((node) => node.data.stepType === StepType.UserDefined) as Node[]; + const endpointNodes = instance + .getNodes() + .filter((node) => node.data.stepType === StepType.UserDefined) as Node[]; if (endpointNodes.length === 0) { set({ endpointsResponseVariables: [] }); return; - }; - + } + const endpointsFromNodes = endpointNodes.map((node) => node.data.endpoint); const requests = endpointsFromNodes.flatMap((e) => e?.definitions.map((endpoint) => ({ @@ -284,7 +282,7 @@ const useServiceStore = create((set, get, store) => ({ } const variable: EndpointResponseVariable = { - name: endpoint?.name ?? '', + name: endpoint?.name ?? "", chips: chips, }; @@ -499,15 +497,13 @@ const useServiceStore = create((set, get, store) => ({ const taraVariables = Object.keys(data).map((key) => `{{TARA.${key}}}`); get().addProductionVariables(taraVariables); }, - getAvailableRequestValues: (endpointId: string) => { - const variables = get() - .endpoints.filter((endpoint) => endpoint.endpointId !== endpointId) - .map((endpoint) => ({ - id: endpoint.endpointId, - name: endpoint.name, - response: endpoint.definitions.find((x) => x.isSelected)?.response ?? [], - })) - .flatMap(({ id, name, response }) => response?.map((x) => `{{${name === "" ? id : name}.${x.name}}}`)); + getAvailableRequestValues: (endpoint: EndpointData) => { + const selectedDefinition = endpoint.definitions.find((x) => x.isSelected); + const responseVariables = selectedDefinition?.response ?? []; + + const variables = responseVariables.map( + (x) => `{{${endpoint.name === "" ? endpoint.endpointId : endpoint.name}.${x.name}}}` + ); return { prod: [...variables, ...get().availableVariables.prod], @@ -539,17 +535,8 @@ const useServiceStore = create((set, get, store) => ({ }, })); }, - changeServiceEndpointType: (id: string, type: EndpointType) => { - const endpoints = get().endpoints.map((x) => { - if (x.endpointId !== id) return x; - return { - ...x, - type, - definitions: [], - }; - }); - - set({ endpoints }); + changeServiceEndpointType: (endpoint: EndpointData, type: EndpointType) => { + endpoint.type = type; }, mapEndpointsToSteps: (): Step[] => { return get() @@ -567,21 +554,18 @@ const useServiceStore = create((set, get, store) => ({ })); }, setEndpoints: (callback) => { - set((state) => ({ - endpoints: callback(state.endpoints), - })); + // set((state) => ({ + // endpoints: callback(state.endpoints), + // })); }, selectedTab: EndpointEnv.Live, setSelectedTab: (tab: EndpointEnv) => set({ selectedTab: tab }), isLive: () => get().selectedTab === EndpointEnv.Live, - updateEndpointRawData: (data: RequestVariablesTabsRawData, endpointId?: string, parentEndpointId?: string) => { - if (!endpointId) return; - const live = get().isLive() ? "value" : "testValue"; + updateEndpointRawData: (data: RequestVariablesTabsRawData, endpoint?: EndpointData) => { + if (!endpoint) return; + const live = "value"; - const endpoints = JSON.parse(JSON.stringify(get().endpoints)) as EndpointData[]; - const defEndpoint = endpoints - .find((x) => x.endpointId === parentEndpointId) - ?.definitions.find((x) => x.id === endpointId); + const defEndpoint = endpoint.definitions[0]; for (const key in data) { if (defEndpoint?.[key as EndpointTab]) { @@ -589,18 +573,14 @@ const useServiceStore = create((set, get, store) => ({ } } - set({ - endpoints, - }); + endpoint.definitions[0] = defEndpoint; + return endpoint; }, - updateEndpointData: (data: RequestVariablesTabsRowsData, endpointId?: string, parentEndpointId?: string) => { - if (!endpointId) return; + updateEndpointData: (data: RequestVariablesTabsRowsData, endpoint?: EndpointData) => { + if (!endpoint) return; - const live = get().isLive() ? "value" : "testValue"; - const endpoints = JSON.parse(JSON.stringify(get().endpoints)) as EndpointData[]; - const defEndpoint = endpoints - .find((x) => x.endpointId === parentEndpointId) - ?.definitions.find((x) => x.id === endpointId); + const live = "value"; + const defEndpoint = endpoint.definitions[0]; if (!defEndpoint) return; @@ -629,9 +609,8 @@ const useServiceStore = create((set, get, store) => ({ } } - set({ - endpoints, - }); + endpoint.definitions[0] = defEndpoint; + return endpoint; }, reactFlowInstance: null, setReactFlowInstance: (reactFlowInstance) => set({ reactFlowInstance }), From 73c352b7520a26e7877ba721fe97a5f8628a235e Mon Sep 17 00:00:00 2001 From: 1AhmedYasser <26207361+1AhmedYasser@users.noreply.github.com> Date: Wed, 30 Jul 2025 21:47:23 +0300 Subject: [PATCH 04/64] chore(644): Added Body and header updates --- .../RequestVariables/ValueCell/index.tsx | 23 +--- .../Endpoints/RequestVariables/columns.tsx | 2 - .../Endpoints/RequestVariables/index.tsx | 102 +++++++++++------- GUI/src/i18n/en/common.json | 3 +- GUI/src/i18n/et/common.json | 3 +- 5 files changed, 69 insertions(+), 64 deletions(-) diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx index c9d61848e..44fc638d5 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx @@ -1,42 +1,25 @@ import { Row } from "@tanstack/react-table"; -import React, { useEffect, useRef, useState } from "react"; +import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { FormAutocomplete } from "../../../.."; -import { PreDefinedEndpointEnvVariables } from "../../../../../types/endpoint"; import { RequestVariablesRowData, RequestVariablesTableColumns } from "../../../../../types/request-variables"; type ValueCellProps = { row: Row; - requestValues: PreDefinedEndpointEnvVariables; - isLive: boolean; value: string; rowData?: RequestVariablesRowData; updateRowValue: (id: string, value: string) => void; onValueChange: (rowId: string, value: string) => void; }; -const ValueCell: React.FC = ({ row, requestValues, updateRowValue, rowData, isLive, value, onValueChange }) => { +const ValueCell: React.FC = ({ row, updateRowValue, rowData, value, onValueChange }) => { const { t } = useTranslation(); const [inputValue, setInputValue] = useState(value); - const ref = useRef(null); - - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - if (ref.current && !ref.current.contains(event.target as any)) { - if (value !== inputValue) updateRowValue(row.id, inputValue); - } - }; - - document.addEventListener("mousedown", handleClickOutside); - return () => { - document.removeEventListener("mousedown", handleClickOutside); - }; - }, [ref, inputValue]); if (!rowData) return <>; if (rowData.type === "schema" || (rowData.type === "array" && rowData.arrayType === "schema")) return <>; return ( -
+
( r.id === props.row.id)?.value ?? ""} updateRowValue={updateRowValue} diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx index 0a290f987..4ee59ef2c 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx @@ -5,7 +5,6 @@ import * as Tabs from "@radix-ui/react-tabs"; import DataTable from "../../../DataTable"; import { RequestTab } from "../../../../types"; import { - EndpointDefinition, EndpointData, EndpointTab, EndpointVariableData, @@ -45,14 +44,12 @@ const RequestVariables: React.FC = ({ const tabs: EndpointTab[] = [EndpointTab.Params, EndpointTab.Headers, EndpointTab.Body]; const [jsonError, setJsonError] = useState(); const [key, setKey] = useState(0); - const { setEndpoints, updateEndpointRawData, updateEndpointData } = useServiceStore(); + const { updateEndpointRawData, updateEndpointData } = useServiceStore(); const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10, }); - console.log("endpoint", endpoint); - const [sorting, setSorting] = useState([]); const constructRow = (id: number, data: EndpointVariableData, nestedLevel: number): RequestVariablesRowData => { @@ -141,31 +138,46 @@ const RequestVariables: React.FC = ({ const updateRowVariable = (id: string, variable: string) => { setRowsData((prevRowsData) => { - prevRowsData[requestTab.tab]!.forEach((row) => { + const newRowsData = { ...prevRowsData }; + newRowsData[requestTab.tab] = [...(newRowsData[requestTab.tab] || [])]; + + newRowsData[requestTab.tab]!.forEach((row) => { if (row.id !== id) return; row.variable = variable; }); - // if last row name is edited, add a new row - if (!rowsData[requestTab.tab] || id !== `${rowsData[requestTab.tab]!.length - 1}`) return prevRowsData; - prevRowsData[requestTab.tab]!.push({ + + if (!rowsData[requestTab.tab] || id !== `${rowsData[requestTab.tab]!.length - 1}`) return newRowsData; + + newRowsData[requestTab.tab]!.push({ id: `${rowsData[requestTab.tab]!.length}`, required: false, isNameEditable: true, nestedLevel: 0, }); - return prevRowsData; + + return newRowsData; }); updateEndpointData(rowsData, endpoint); }; const updateRowValue = (id: string, value: string) => { - if (!rowsData[requestTab.tab]) return; - rowsData[requestTab.tab]!.forEach((row) => { - if (row.id !== id) return; - row.value = value; + setRowsData((prevRowsData) => { + const newRowsData = { ...prevRowsData }; + const currentTab = newRowsData[requestTab.tab]; + + if (!currentTab) return prevRowsData; + + newRowsData[requestTab.tab] = currentTab.map((row) => { + if (row.id === id) { + return { ...row, value }; + } + return row; + }); + + updateEndpointData(newRowsData, endpoint); + + return newRowsData; }); - updateEndpointData(rowsData, endpoint); - setKey(key + 1); }; const checkNestedVariables = (rowVariableId: string, variable: EndpointVariableData) => { @@ -202,32 +214,42 @@ const RequestVariables: React.FC = ({ }; const updateParams = (isValue: boolean, rowId: string, value: string) => { - if (requestTab.tab === "params") { - if (!rowsData[requestTab.tab]) return; - const newData = rowsData[requestTab.tab]!.map((row) => { - if (row.id !== rowId) return row; - if (isValue) { - row.value = value; - } else { - row.variable = value; - } - return row; - }); + if (!rowsData[requestTab.tab]) return; + const newData = rowsData[requestTab.tab]!.map((row) => { + if (row.id !== rowId) return row; + if (isValue) { + row.value = value; + } else { + row.variable = value; + } + return row; + }); - const parameters: EndpointVariableData[] = []; - newData.forEach((row) => { - if (!row.value || !row.variable) return; + const variables: EndpointVariableData[] = []; + newData.forEach((row) => { + if (!row.value || !row.variable) return; - parameters.push({ - id: row.endpointVariableId ?? row.id, - name: row.variable, - type: row.type ?? "custom", - required: row.required ?? false, - value: row.value, - }); + variables.push({ + id: row.endpointVariableId ?? row.id, + name: row.variable, + type: row.type ?? "custom", + required: row.required ?? false, + value: row.value, }); + }); - onParametersChange(parameters); + if (requestTab.tab === "params") { + onParametersChange(variables); + } else if (requestTab.tab === "body") { + endpoint.definitions[0].body = { + variables: variables, + rawData: {}, + }; + } else if (requestTab.tab === "headers") { + endpoint.definitions[0].headers = { + variables: variables, + rawData: {}, + }; } }; @@ -245,7 +267,7 @@ const RequestVariables: React.FC = ({ updateRowValue, getTabsRowsData, }), - [] + [rowsData] ); const buildRawDataView = (): JSX.Element => { @@ -268,7 +290,7 @@ const RequestVariables: React.FC = ({ setKey(key + 1); }} > - Format JSON + {t("newService.endpoint.formatJson")} = ({ <> Date: Wed, 30 Jul 2025 22:07:56 +0300 Subject: [PATCH 05/64] chore(644): Added New field check on value or variable change --- .../RequestVariables/ValueCell/index.tsx | 1 + .../RequestVariables/VariableCell/index.tsx | 18 ++---------------- .../Endpoints/RequestVariables/columns.tsx | 2 -- .../Endpoints/RequestVariables/index.tsx | 9 +++++++++ 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx index 44fc638d5..c74ba8361 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx @@ -27,6 +27,7 @@ const ValueCell: React.FC = ({ row, updateRowValue, rowData, val onChange={(v: string) => { onValueChange(row.id, v); setInputValue(v); + updateRowValue(row.id, v); }} onSelected={(v) => { setInputValue(v); diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/VariableCell/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/VariableCell/index.tsx index f7d1f6dea..21ca2fea9 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/VariableCell/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/VariableCell/index.tsx @@ -1,5 +1,5 @@ import { Row } from "@tanstack/react-table"; -import React, { useEffect, useRef, useState } from "react"; +import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { FormInput } from "../../../.."; import { RequestVariablesTableColumns, RequestVariablesRowData } from "../../../../../types/request-variables"; @@ -15,31 +15,17 @@ type VariableCellProps = { const VariableCell: React.FC = ({ row, updateRowVariable, rowData, variable, onValueChange }) => { const { t } = useTranslation(); const [inputValue, setInputValue] = useState(variable); - const ref = useRef(null); - - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - if (ref.current && !ref.current.contains(event.target as any)) { - if (variable !== inputValue) updateRowVariable(row.id, inputValue); - } - }; - - document.addEventListener("mousedown", handleClickOutside); - return () => { - document.removeEventListener("mousedown", handleClickOutside); - }; - }, [ref, inputValue]); if (!rowData) return <>; return rowData.isNameEditable ? ( { onValueChange(row.id, e.target.value); setInputValue(e.target.value); + updateRowVariable(row.id, e.target.value); }} value={inputValue} placeholder={t("newService.endpoint.variable") + ".."} diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx index 9efd9c2e9..e79c8f013 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx @@ -29,8 +29,6 @@ export const getColumns = ({ deleteVariable, setRowsData, updateRowVariable, - requestValues, - isLive, updateRowValue, getTabsRowsData, }: GetColumnsConfig) => { diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx index 4ee59ef2c..3c7f1a7ae 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx @@ -174,6 +174,15 @@ const RequestVariables: React.FC = ({ return row; }); + if (!rowsData[requestTab.tab] || id !== `${rowsData[requestTab.tab]!.length - 1}`) return newRowsData; + + newRowsData[requestTab.tab]!.push({ + id: `${rowsData[requestTab.tab]!.length}`, + required: false, + isNameEditable: true, + nestedLevel: 0, + }); + updateEndpointData(newRowsData, endpoint); return newRowsData; From 115de21c2f250e5013763c0da2266c4ee41a4312 Mon Sep 17 00:00:00 2001 From: 1AhmedYasser <26207361+1AhmedYasser@users.noreply.github.com> Date: Wed, 30 Jul 2025 23:22:30 +0300 Subject: [PATCH 06/64] chore(644): Fixed row value --- .../RequestVariables/ValueCell/index.tsx | 6 ++- .../RequestVariables/VariableCell/index.tsx | 12 ++--- .../Endpoints/RequestVariables/columns.tsx | 1 + .../Endpoints/RequestVariables/index.tsx | 47 ++++++++++--------- .../request-variables-table-columns.ts | 11 ++++- 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx index c74ba8361..54bf46ea6 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx @@ -16,8 +16,10 @@ const ValueCell: React.FC = ({ row, updateRowValue, rowData, val const { t } = useTranslation(); const [inputValue, setInputValue] = useState(value); - if (!rowData) return <>; - if (rowData.type === "schema" || (rowData.type === "array" && rowData.arrayType === "schema")) return <>; + if (!row.original) return <>; + if (row.original.type === "schema" || (row.original.type === "array" && row.original.arrayType === "schema")) + return <>; + return (
= ({ row, updateRowVariable, row const { t } = useTranslation(); const [inputValue, setInputValue] = useState(variable); - if (!rowData) return <>; - return rowData.isNameEditable ? ( + if (!row.original) return <>; + return row.original.isNameEditable ? ( = ({ row, updateRowVariable, row placeholder={t("newService.endpoint.variable") + ".."} /> ) : ( -

- {rowData.variable} - {rowData.type && `, (${rowData.type})`} - {rowData.description && `, (${rowData.description})`} +

+ {row.original.variable} + {row.original.type && `, (${row.original.type})`} + {row.original.description && `, (${row.original.description})`}

); }; diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx index e79c8f013..6d4c2ea42 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx @@ -85,6 +85,7 @@ export const getColumns = ({ updateRowValue={updateRowValue} onValueChange={(rowId, value) => { updateParams(true, rowId, value); + updateRowValue(rowId, value); }} /> ), diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx index 3c7f1a7ae..b10a2c1fc 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx @@ -47,7 +47,7 @@ const RequestVariables: React.FC = ({ const { updateEndpointRawData, updateEndpointData } = useServiceStore(); const [pagination, setPagination] = useState({ pageIndex: 0, - pageSize: 10, + pageSize: 5, }); const [sorting, setSorting] = useState([]); @@ -136,6 +136,26 @@ const RequestVariables: React.FC = ({ const getTabTriggerClasses = (tab: EndpointTab) => `endpoint-tab-group__tab-btn ${requestTab.tab === tab ? "active" : ""}`; + const maintainSingleEmptyRow = (rows: RequestVariablesRowData[]) => { + console.log("Maintaining single empty row for:", rows); + const emptyRow = rows.find(row => row.value === undefined && row.variable === undefined); + const nonEmptyRows = rows.filter(row => row.value !== undefined || row.variable !== undefined); + + const baseEmptyRow: RequestVariablesRowData = { + id: nonEmptyRows.length.toString(), + required: false, + isNameEditable: true, + nestedLevel: 0, + }; + + return [ + ...nonEmptyRows, + emptyRow + ? { ...baseEmptyRow, ...emptyRow } + : baseEmptyRow, + ]; + }; + const updateRowVariable = (id: string, variable: string) => { setRowsData((prevRowsData) => { const newRowsData = { ...prevRowsData }; @@ -146,18 +166,10 @@ const RequestVariables: React.FC = ({ row.variable = variable; }); - if (!rowsData[requestTab.tab] || id !== `${rowsData[requestTab.tab]!.length - 1}`) return newRowsData; - - newRowsData[requestTab.tab]!.push({ - id: `${rowsData[requestTab.tab]!.length}`, - required: false, - isNameEditable: true, - nestedLevel: 0, - }); - + newRowsData[requestTab.tab] = maintainSingleEmptyRow(newRowsData[requestTab.tab] || []); + updateEndpointData(newRowsData, endpoint); return newRowsData; }); - updateEndpointData(rowsData, endpoint); }; const updateRowValue = (id: string, value: string) => { @@ -174,17 +186,8 @@ const RequestVariables: React.FC = ({ return row; }); - if (!rowsData[requestTab.tab] || id !== `${rowsData[requestTab.tab]!.length - 1}`) return newRowsData; - - newRowsData[requestTab.tab]!.push({ - id: `${rowsData[requestTab.tab]!.length}`, - required: false, - isNameEditable: true, - nestedLevel: 0, - }); - + newRowsData[requestTab.tab] = maintainSingleEmptyRow(newRowsData[requestTab.tab] || []); updateEndpointData(newRowsData, endpoint); - return newRowsData; }); }; @@ -276,7 +279,7 @@ const RequestVariables: React.FC = ({ updateRowValue, getTabsRowsData, }), - [rowsData] + [] ); const buildRawDataView = (): JSX.Element => { diff --git a/GUI/src/types/request-variables/request-variables-table-columns.ts b/GUI/src/types/request-variables/request-variables-table-columns.ts index 3f04629fe..1b41b7366 100644 --- a/GUI/src/types/request-variables/request-variables-table-columns.ts +++ b/GUI/src/types/request-variables/request-variables-table-columns.ts @@ -1,5 +1,12 @@ export type RequestVariablesTableColumns = { + id: string; + isNameEditable: boolean; required: boolean; - value: any; - variable: string; + nestedLevel: number; + arrayType?: string; + description?: string; + endpointVariableId?: string; + type?: string; + value?: string; + variable?: string; }; From 13d6d10625f7656de64a251cd9cf3ea19fb6299e Mon Sep 17 00:00:00 2001 From: 1AhmedYasser <26207361+1AhmedYasser@users.noreply.github.com> Date: Wed, 30 Jul 2025 23:23:17 +0300 Subject: [PATCH 07/64] chore(644): Removed console.log --- .../ApiEndpointCard/Endpoints/RequestVariables/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx index b10a2c1fc..da4d31269 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx @@ -137,7 +137,6 @@ const RequestVariables: React.FC = ({ `endpoint-tab-group__tab-btn ${requestTab.tab === tab ? "active" : ""}`; const maintainSingleEmptyRow = (rows: RequestVariablesRowData[]) => { - console.log("Maintaining single empty row for:", rows); const emptyRow = rows.find(row => row.value === undefined && row.variable === undefined); const nonEmptyRows = rows.filter(row => row.value !== undefined || row.variable !== undefined); From 7d7f59b7bd8f9bf02818ec9a8df104c8bb9f7aca Mon Sep 17 00:00:00 2001 From: 1AhmedYasser <26207361+1AhmedYasser@users.noreply.github.com> Date: Thu, 31 Jul 2025 10:29:55 +0300 Subject: [PATCH 08/64] chore(644): Removed AutoComplete field from value --- .../RequestVariables/ValueCell/index.tsx | 30 ++++++++----------- .../RequestVariables/VariableCell/index.tsx | 7 ++--- .../Endpoints/RequestVariables/columns.tsx | 3 -- .../Endpoints/RequestVariables/index.tsx | 5 ++-- GUI/src/store/new-services.store.ts | 1 + 5 files changed, 20 insertions(+), 26 deletions(-) diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx index 54bf46ea6..6a24f38b0 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/ValueCell/index.tsx @@ -1,18 +1,17 @@ import { Row } from "@tanstack/react-table"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; -import { FormAutocomplete } from "../../../.."; -import { RequestVariablesRowData, RequestVariablesTableColumns } from "../../../../../types/request-variables"; +import { FormInput } from "../../../.."; +import { RequestVariablesTableColumns } from "../../../../../types/request-variables"; type ValueCellProps = { row: Row; value: string; - rowData?: RequestVariablesRowData; updateRowValue: (id: string, value: string) => void; onValueChange: (rowId: string, value: string) => void; }; -const ValueCell: React.FC = ({ row, updateRowValue, rowData, value, onValueChange }) => { +const ValueCell: React.FC = ({ row, updateRowValue, value, onValueChange }) => { const { t } = useTranslation(); const [inputValue, setInputValue] = useState(value); @@ -22,20 +21,17 @@ const ValueCell: React.FC = ({ row, updateRowValue, rowData, val return (
- { - onValueChange(row.id, v); - setInputValue(v); - updateRowValue(row.id, v); - }} - onSelected={(v) => { - setInputValue(v); - updateRowValue(row.id, v); + { + onValueChange(row.id, e.target.value); + setInputValue(e.target.value); + updateRowValue(row.id, e.target.value); }} - excludeCharacters={new RegExp(/[{}]/)} + value={inputValue} + placeholder={t("newService.endpoint.value") + ".."} />
); diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/VariableCell/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/VariableCell/index.tsx index 48dd635c1..732d6d71a 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/VariableCell/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/VariableCell/index.tsx @@ -2,24 +2,23 @@ import { Row } from "@tanstack/react-table"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { FormInput } from "../../../.."; -import { RequestVariablesTableColumns, RequestVariablesRowData } from "../../../../../types/request-variables"; +import { RequestVariablesTableColumns } from "../../../../../types/request-variables"; type VariableCellProps = { row: Row; updateRowVariable: (id: string, variable: string) => void; variable: string; - rowData?: RequestVariablesRowData; onValueChange: (rowId: string, value: string) => void; }; -const VariableCell: React.FC = ({ row, updateRowVariable, rowData, variable, onValueChange }) => { +const VariableCell: React.FC = ({ row, updateRowVariable, variable, onValueChange }) => { const { t } = useTranslation(); const [inputValue, setInputValue] = useState(variable); if (!row.original) return <>; return row.original.isNameEditable ? ( { diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx index 6d4c2ea42..33f52b3ef 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx @@ -62,7 +62,6 @@ export const getColumns = ({ row={props.row} variable={rowsData[requestTab.tab]!.find((r) => r.id === props.row.id)?.variable ?? ""} updateRowVariable={updateRowVariable} - rowData={rowsData[requestTab.tab]![+props.row.id]} onValueChange={(rowId, value) => { updateParams(false, rowId, value); }} @@ -80,12 +79,10 @@ export const getColumns = ({ cell: (props) => ( r.id === props.row.id)?.value ?? ""} updateRowValue={updateRowValue} onValueChange={(rowId, value) => { updateParams(true, rowId, value); - updateRowValue(rowId, value); }} /> ), diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx index da4d31269..6efa82abb 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx @@ -240,13 +240,14 @@ const RequestVariables: React.FC = ({ newData.forEach((row) => { if (!row.value || !row.variable) return; - variables.push({ + const newVariable: EndpointVariableData = { id: row.endpointVariableId ?? row.id, name: row.variable, type: row.type ?? "custom", required: row.required ?? false, value: row.value, - }); + }; + variables.push(newVariable); }); if (requestTab.tab === "params") { diff --git a/GUI/src/store/new-services.store.ts b/GUI/src/store/new-services.store.ts index ee7ab9a9d..8344b63b1 100644 --- a/GUI/src/store/new-services.store.ts +++ b/GUI/src/store/new-services.store.ts @@ -606,6 +606,7 @@ const useServiceStore = create((set, get, store) => ({ const updatedVariable = data[key as EndpointTab]!.find((updated) => updated.endpointVariableId === variable.id); variable[live] = updatedVariable?.value; variable.name = updatedVariable?.variable ?? variable.name; + variable.value = updatedVariable?.value ?? variable.value; } } From 43da1d3186effb9bb9c1a767fe356235f57e7ce6 Mon Sep 17 00:00:00 2001 From: 1AhmedYasser <26207361+1AhmedYasser@users.noreply.github.com> Date: Thu, 31 Jul 2025 10:54:54 +0300 Subject: [PATCH 09/64] fix(644): Fixed Sonar Issues --- .../Endpoints/OpenAPI/index.tsx | 49 ++----------------- GUI/src/store/new-services.store.ts | 6 +-- 2 files changed, 6 insertions(+), 49 deletions(-) diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/OpenAPI/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/OpenAPI/index.tsx index cc62e1c3e..3f157dffd 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/OpenAPI/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/OpenAPI/index.tsx @@ -9,10 +9,9 @@ import { EndpointData, EndpointDefinition, EndpointVariableData, - EndpointTab, PreDefinedEndpointEnvVariables, } from "../../../../types/endpoint"; -import { RequestVariablesRowData, RequestVariablesTabsRowsData } from "../../../../types/request-variables"; +import { RequestVariablesRowData } from "../../../../types/request-variables"; import useServiceStore from "store/new-services.store"; import api from "../../../../services/api-dev"; @@ -118,10 +117,9 @@ const EndpointOpenAPI: React.FC = ({ }); if (!schema.required) return result; Object.values(schema?.required).forEach((name) => { - result.map((variable) => { - if (variable.name !== name) return variable; + result.forEach((variable) => { + if (variable.name !== name) return; variable.required = true; - return variable; }); }); return result; @@ -215,11 +213,10 @@ const EndpointOpenAPI: React.FC = ({ }); setOpenApiEndpoints(paths); setEndpoints((prevEndpoints) => { - prevEndpoints.map((prevEndpoint) => { - if (prevEndpoint.endpointId !== endpoint.endpointId) return prevEndpoint; + prevEndpoints.forEach((prevEndpoint) => { + if (prevEndpoint.endpointId !== endpoint.endpointId) return; prevEndpoint.definitions = paths; prevEndpoint.openApiUrl = openApiUrl; - return prevEndpoint; }); return prevEndpoints; }); @@ -239,42 +236,6 @@ const EndpointOpenAPI: React.FC = ({ } }; - const updateEndpointData = (data: RequestVariablesTabsRowsData, openApiEndpointId?: string) => { - if (!openApiEndpointId) return; - setEndpoints((prevEndpoints) => { - return prevEndpoints.map((prevEndpoint) => { - if (prevEndpoint.endpointId !== endpoint.endpointId) return prevEndpoint; - updateEndpoint(prevEndpoint, data, openApiEndpointId); - return prevEndpoint; - }); - }); - setKey(key + 1); - }; - - const updateEndpoint = ( - prevEndpoint: EndpointData, - data: RequestVariablesTabsRowsData, - openApiEndpointId?: string - ) => { - prevEndpoint.definitions.forEach((openApiEndpoint) => { - if (openApiEndpoint.id === openApiEndpointId) { - updateOpenApiEndpoint(data, openApiEndpoint); - } - }); - }; - - const updateOpenApiEndpoint = (data: RequestVariablesTabsRowsData, openApiEndpoint: EndpointDefinition) => { - for (const key in data) { - openApiEndpoint[key as EndpointTab]?.variables.forEach((variable) => { - if (["schema", "array"].includes(variable.type)) { - checkNestedVariables(variable, data[key as EndpointTab]!); - } - const updatedVariable = data[key as EndpointTab]!.find((updated) => updated.endpointVariableId === variable.id); - variable[isLive ? "value" : "testValue"] = updatedVariable?.value; - }); - } - }; - const onSelectEndpoint = (selection: Option | null) => { const newSelectedEndpoint = openApiEndpoints.find((openApiEndpoint) => openApiEndpoint.label === selection?.label); setSelectedEndpoint(newSelectedEndpoint); diff --git a/GUI/src/store/new-services.store.ts b/GUI/src/store/new-services.store.ts index 8344b63b1..9b63ab5f4 100644 --- a/GUI/src/store/new-services.store.ts +++ b/GUI/src/store/new-services.store.ts @@ -553,11 +553,7 @@ const useServiceStore = create((set, get, store) => ({ data: endpoint, })); }, - setEndpoints: (callback) => { - // set((state) => ({ - // endpoints: callback(state.endpoints), - // })); - }, + setEndpoints: () => {}, selectedTab: EndpointEnv.Live, setSelectedTab: (tab: EndpointEnv) => set({ selectedTab: tab }), isLive: () => get().selectedTab === EndpointEnv.Live, From eeefc031ee0087bfc2e0f8f248ac4d25d798530a Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Thu, 31 Jul 2025 13:12:10 +0300 Subject: [PATCH 10/64] fix(648): re-order --- .../components/Flow/EdgeTypes/CustomEdge.tsx | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index 68eaf9970..8d3abdd53 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -42,7 +42,6 @@ function CustomEdge({ style, markerEnd, }: EdgeProps) { - const [edgePath, edgeCenterX, edgeCenterY] = getBezierPath({ sourceX, sourceY, @@ -136,6 +135,33 @@ function CustomEdge({ } > + + + {allElements.length > 0 && ( + + + {allElements.map((element) => ( + { + onEdgeAdd(step); + setDropdownOpen(false); + setHasUnsavedChanges(true); + }} + /> + ))} + + + )} + + + )} - - - - {allElements.length > 0 && ( - - - {allElements.map((element) => ( - { - onEdgeAdd(step); - setDropdownOpen(false); - setHasUnsavedChanges(true); - }} - /> - ))} - - - )} - - {isAddEndpointModalVisible && ( From 3abb7f3b8a9fd686e6ed63f72af89a361088dff0 Mon Sep 17 00:00:00 2001 From: 1AhmedYasser <26207361+1AhmedYasser@users.noreply.github.com> Date: Thu, 31 Jul 2025 13:26:47 +0300 Subject: [PATCH 11/64] fix(644): Fixed Value Update --- .../Endpoints/RequestVariables/columns.tsx | 32 ++++++++++--------- .../Endpoints/RequestVariables/index.tsx | 27 ++-------------- GUI/src/store/new-services.store.ts | 4 +-- 3 files changed, 21 insertions(+), 42 deletions(-) diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx index 33f52b3ef..ff8605463 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/columns.tsx @@ -10,16 +10,15 @@ import { PreDefinedEndpointEnvVariables } from "types/endpoint"; import { RequestTab } from "types"; interface GetColumnsConfig { - rowsData: RequestVariablesTabsRowsData, - updateParams: (isValue: boolean, rowId: string, value: string) => void, - requestTab: RequestTab, - deleteVariable: (rowData: RequestVariablesRowData) => void, - setRowsData: React.Dispatch>, - updateRowVariable: (id: string, variable: string) => void, - requestValues: PreDefinedEndpointEnvVariables, - isLive: boolean, - updateRowValue: (id: string, value: string) => void, - getTabsRowsData: () => RequestVariablesTabsRowsData, + rowsData: RequestVariablesTabsRowsData; + updateParams: (isValue: boolean, rowId: string, value: string) => void; + requestTab: RequestTab; + deleteVariable: (rowData: RequestVariablesRowData) => void; + setRowsData: React.Dispatch>; + requestValues: PreDefinedEndpointEnvVariables; + isLive: boolean; + updateRowField: (id: string, field: "variable" | "value", value: string) => void; + getTabsRowsData: () => RequestVariablesTabsRowsData; } export const getColumns = ({ @@ -28,8 +27,7 @@ export const getColumns = ({ requestTab, deleteVariable, setRowsData, - updateRowVariable, - updateRowValue, + updateRowField, getTabsRowsData, }: GetColumnsConfig) => { const columnHelper = createColumnHelper(); @@ -61,7 +59,9 @@ export const getColumns = ({ r.id === props.row.id)?.variable ?? ""} - updateRowVariable={updateRowVariable} + updateRowVariable={(id, variable) => { + updateRowField(id, "variable", variable); + }} onValueChange={(rowId, value) => { updateParams(false, rowId, value); }} @@ -80,7 +80,9 @@ export const getColumns = ({ r.id === props.row.id)?.value ?? ""} - updateRowValue={updateRowValue} + updateRowValue={(id, value) => { + updateRowField(id, "value", value); + }} onValueChange={(rowId, value) => { updateParams(true, rowId, value); }} @@ -112,5 +114,5 @@ export const getColumns = ({ ); }, }), - ] + ]; } diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx index 6efa82abb..be614133a 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx @@ -155,34 +155,14 @@ const RequestVariables: React.FC = ({ ]; }; - const updateRowVariable = (id: string, variable: string) => { + const updateRowField = (id: string, field: "variable" | "value", newValue: string) => { setRowsData((prevRowsData) => { const newRowsData = { ...prevRowsData }; newRowsData[requestTab.tab] = [...(newRowsData[requestTab.tab] || [])]; newRowsData[requestTab.tab]!.forEach((row) => { if (row.id !== id) return; - row.variable = variable; - }); - - newRowsData[requestTab.tab] = maintainSingleEmptyRow(newRowsData[requestTab.tab] || []); - updateEndpointData(newRowsData, endpoint); - return newRowsData; - }); - }; - - const updateRowValue = (id: string, value: string) => { - setRowsData((prevRowsData) => { - const newRowsData = { ...prevRowsData }; - const currentTab = newRowsData[requestTab.tab]; - - if (!currentTab) return prevRowsData; - - newRowsData[requestTab.tab] = currentTab.map((row) => { - if (row.id === id) { - return { ...row, value }; - } - return row; + row[field] = newValue; }); newRowsData[requestTab.tab] = maintainSingleEmptyRow(newRowsData[requestTab.tab] || []); @@ -273,10 +253,9 @@ const RequestVariables: React.FC = ({ requestTab, deleteVariable, setRowsData, - updateRowVariable, + updateRowField, requestValues, isLive, - updateRowValue, getTabsRowsData, }), [] diff --git a/GUI/src/store/new-services.store.ts b/GUI/src/store/new-services.store.ts index 9b63ab5f4..d54e25927 100644 --- a/GUI/src/store/new-services.store.ts +++ b/GUI/src/store/new-services.store.ts @@ -575,7 +575,6 @@ const useServiceStore = create((set, get, store) => ({ updateEndpointData: (data: RequestVariablesTabsRowsData, endpoint?: EndpointData) => { if (!endpoint) return; - const live = "value"; const defEndpoint = endpoint.definitions[0]; if (!defEndpoint) return; @@ -593,14 +592,13 @@ const useServiceStore = create((set, get, store) => ({ name: row.variable, type: "custom", required: false, - [live]: row.value, + value: row.value, }); } } for (const variable of keyedDefEndpoint?.variables ?? []) { const updatedVariable = data[key as EndpointTab]!.find((updated) => updated.endpointVariableId === variable.id); - variable[live] = updatedVariable?.value; variable.name = updatedVariable?.variable ?? variable.name; variable.value = updatedVariable?.value ?? variable.value; } From 946588c49ec7325cf800144e0bf52fe4f695fa61 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Thu, 31 Jul 2025 13:46:01 +0300 Subject: [PATCH 12/64] fix(648): fix typo --- GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx | 2 +- GUI/src/i18n/en/common.json | 2 +- GUI/src/i18n/et/common.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index 8d3abdd53..0a3f6747a 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -169,7 +169,7 @@ function CustomEdge({ onAddClick={async () => { if (!idParam) { useToastStore.getState().error({ - title: t("newService.toast.servieNotFound"), + title: t("newService.toast.serviceNotFound"), message: t("newService.toast.serviceNotFoundEndpointsMessage"), }); } else { diff --git a/GUI/src/i18n/en/common.json b/GUI/src/i18n/en/common.json index f95cc2474..7a32b9c4c 100644 --- a/GUI/src/i18n/en/common.json +++ b/GUI/src/i18n/en/common.json @@ -257,7 +257,7 @@ "saveConfigFailed": "Failed to save config", "testResultSuccess": "Test result- success", "testResultError": "Test result - error", - "servieNotFound": "Service not found", + "serviceNotFound": "Service not found", "serviceNotFoundEndpointsMessage": "Please save the service first to be able to add endpoints", "serviceNameAlreadyExists": "Service name already exists", "elementNameAlreadyExists": "Element name already exists", diff --git a/GUI/src/i18n/et/common.json b/GUI/src/i18n/et/common.json index fe5e4e355..1278bc8a9 100644 --- a/GUI/src/i18n/et/common.json +++ b/GUI/src/i18n/et/common.json @@ -257,7 +257,7 @@ "saveConfigFailed": "Seadete salvestamine ebaõnnestus", "testResultSuccess": "Testi tulemus - edu", "testResultError": "Testi tulemus - viga", - "servieNotFound": "Teenust ei leitud", + "serviceNotFound": "Teenust ei leitud", "serviceNotFoundEndpointsMessage": "Salvesta teenus kõigepealt, et saaksid lisada otspunkte", "serviceNameAlreadyExists": "Teenuse nimi on juba olemas", "elementNameAlreadyExists": "Elementi nimi on juba olemas", From 3ebf984a980bfd9b31f616324ccb23aef1b13da7 Mon Sep 17 00:00:00 2001 From: 1AhmedYasser <26207361+1AhmedYasser@users.noreply.github.com> Date: Thu, 31 Jul 2025 14:22:45 +0300 Subject: [PATCH 13/64] fix(644): Fixed Delete Variable UI Bug --- .../ApiEndpointCard/Endpoints/RequestVariables/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx index be614133a..76b361156 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx @@ -189,6 +189,7 @@ const RequestVariables: React.FC = ({ }; const deleteVariable = (rowData: RequestVariablesRowData) => { + if (rowData.variable === undefined || rowData.value === undefined) return; const endpointData = endpoint.definitions[0]; const defEndpoint = endpoint.definitions.find((x) => x.id === endpointData.id); const endpointTab = defEndpoint?.[requestTab.tab]; @@ -202,6 +203,10 @@ const RequestVariables: React.FC = ({ .forEach((variable) => checkNestedVariables(rowData.endpointVariableId!, variable)); } } + + if (requestTab.tab === "params") { + onParametersChange(endpointTab?.variables ?? []); + } }; const updateParams = (isValue: boolean, rowId: string, value: string) => { @@ -258,7 +263,7 @@ const RequestVariables: React.FC = ({ isLive, getTabsRowsData, }), - [] + [deleteVariable] ); const buildRawDataView = (): JSX.Element => { From fa1829cb2043f1b2015be073a6069ee273f2c878 Mon Sep 17 00:00:00 2001 From: 1AhmedYasser <26207361+1AhmedYasser@users.noreply.github.com> Date: Thu, 31 Jul 2025 15:35:24 +0300 Subject: [PATCH 14/64] chore(0): Fix row deletion ui update --- .../Endpoints/RequestVariables/index.tsx | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx index 76b361156..42637fd80 100644 --- a/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx +++ b/GUI/src/components/ApiEndpointCard/Endpoints/RequestVariables/index.tsx @@ -37,7 +37,6 @@ const RequestVariables: React.FC = ({ requestValues, requestTab, setRequestTab, - parentEndpointId, onParametersChange, }) => { const { t } = useTranslation(); @@ -51,6 +50,7 @@ const RequestVariables: React.FC = ({ }); const [sorting, setSorting] = useState([]); + const [deletedVariable, setDeletedVariable] = useState(undefined); const constructRow = (id: number, data: EndpointVariableData, nestedLevel: number): RequestVariablesRowData => { const value = isLive ? data.value : data.testValue; @@ -167,6 +167,18 @@ const RequestVariables: React.FC = ({ newRowsData[requestTab.tab] = maintainSingleEmptyRow(newRowsData[requestTab.tab] || []); updateEndpointData(newRowsData, endpoint); + if (requestTab.tab === "params") + onParametersChange( + newRowsData[requestTab.tab] + ?.filter((row) => row.value && row.variable) + .map((row) => ({ + id: row.endpointVariableId ?? row.id, + name: row.variable!, + type: row.type ?? "custom", + required: row.required ?? false, + value: row.value!, + })) ?? [] + ); return newRowsData; }); }; @@ -207,6 +219,7 @@ const RequestVariables: React.FC = ({ if (requestTab.tab === "params") { onParametersChange(endpointTab?.variables ?? []); } + setDeletedVariable(rowData); }; const updateParams = (isValue: boolean, rowId: string, value: string) => { @@ -263,7 +276,7 @@ const RequestVariables: React.FC = ({ isLive, getTabsRowsData, }), - [deleteVariable] + [deletedVariable] ); const buildRawDataView = (): JSX.Element => { From e8b41f9b3ec0e60f0e30a9a7f5c1cd6f5690c480 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 16:17:38 +0300 Subject: [PATCH 15/64] fix(648): fix modal height --- GUI/src/components/Dropdown/Dropdown.scss | 72 +++++++++++++---------- GUI/src/components/Dropdown/index.tsx | 16 ++--- 2 files changed, 48 insertions(+), 40 deletions(-) diff --git a/GUI/src/components/Dropdown/Dropdown.scss b/GUI/src/components/Dropdown/Dropdown.scss index d383e23fd..0f8734dae 100644 --- a/GUI/src/components/Dropdown/Dropdown.scss +++ b/GUI/src/components/Dropdown/Dropdown.scss @@ -1,36 +1,44 @@ -@import 'src/styles/tools/spacing'; -@import 'src/styles/tools/color'; -@import 'src/styles/settings/variables/other'; -@import 'src/styles/settings/variables/typography'; +@import "src/styles/tools/spacing"; +@import "src/styles/tools/color"; +@import "src/styles/settings/variables/other"; +@import "src/styles/settings/variables/typography"; .dropdown { - background-color: white; - border-radius: 6px; - box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, 0.35); - z-index: 1000; - resize: both; - overflow: auto; - width: 400px; - min-width: 400px; - max-width: 600px; - min-height: 500px; - max-height: 550px; + background-color: white; + border-radius: 6px; + box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, 0.35); + z-index: 1000; + resize: both; + overflow: auto; + width: 400px; + // min-width: 400px; + // max-width: 600px; + // todo igor needs fine tuning with large monitor + min-height: 1000px !important; + max-height: 1500px !important; + height: auto !important; + display: flex !important; + flex-direction: column !important; - &__header { - padding: get-spacing(haapsalu); - margin-bottom: 12px; - display: flex; - align-items: center; - border-radius: $veera-radius-m $veera-radius-m 0 0; - background-color: get-color(black-coral-0); - border-bottom: 1px solid get-color(black-coral-2); - } - - &__title { - font-size: large; - } - - &__content { - padding: 10px; - } + &__header { + padding: get-spacing(haapsalu); + margin-bottom: 12px; + display: flex; + align-items: center; + border-radius: $veera-radius-m $veera-radius-m 0 0; + background-color: get-color(black-coral-0); + border-bottom: 1px solid get-color(black-coral-2); + flex-shrink: 0; } + + &__title { + font-size: large; + } + + &__content { + padding: 10px; + flex: 1; + overflow-y: auto; + min-height: 0; + } +} diff --git a/GUI/src/components/Dropdown/index.tsx b/GUI/src/components/Dropdown/index.tsx index fb5d1a25b..e748925fa 100644 --- a/GUI/src/components/Dropdown/index.tsx +++ b/GUI/src/components/Dropdown/index.tsx @@ -18,14 +18,14 @@ const Dropdown: FC = ({ open, onOpenChange, trigger, title, child {trigger} - - - {title} - - -
{children}
+ + + {title} + + +
{children}
From 3b9f4269024cbe58f3ff35f19bbf9ac49f5e18b4 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 16:22:30 +0300 Subject: [PATCH 16/64] fix(648): fill modal --- GUI/src/components/Collapsible/Collapsible.scss | 6 ++++++ GUI/src/components/Dropdown/Dropdown.scss | 4 ++-- GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx | 12 ++++++++---- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/GUI/src/components/Collapsible/Collapsible.scss b/GUI/src/components/Collapsible/Collapsible.scss index fab472c7a..6a92d4972 100644 --- a/GUI/src/components/Collapsible/Collapsible.scss +++ b/GUI/src/components/Collapsible/Collapsible.scss @@ -6,6 +6,9 @@ .collapsible { border: 1px solid get-color(black-coral-2); border-radius: 4px; + display: flex; + flex-direction: column; + min-height: 0; &__trigger { width: 100%; @@ -15,6 +18,7 @@ padding: get-spacing(haapsalu); background-color: get-color(extra-light); border-radius: 4px; + flex-shrink: 0; &[aria-expanded="true"] { border-bottom: 1px solid get-color(black-coral-2); @@ -31,5 +35,7 @@ background-color: get-color(white); border-radius: 0 0 4px 4px; overflow: hidden; + flex: 1; + min-height: 0; } } diff --git a/GUI/src/components/Dropdown/Dropdown.scss b/GUI/src/components/Dropdown/Dropdown.scss index 0f8734dae..deac22823 100644 --- a/GUI/src/components/Dropdown/Dropdown.scss +++ b/GUI/src/components/Dropdown/Dropdown.scss @@ -14,8 +14,8 @@ // min-width: 400px; // max-width: 600px; // todo igor needs fine tuning with large monitor - min-height: 1000px !important; - max-height: 1500px !important; + min-height: 700px !important; + max-height: 1000px !important; height: auto !important; display: flex !important; flex-direction: column !important; diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index 0a3f6747a..f14353359 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -55,7 +55,7 @@ function CustomEdge({ const [allElements, setAllElements] = useState([]); const [dropdownOpen, setDropdownOpen] = useState(false); const steps = useServiceStore((state) => state.mapEndpointsToSteps()); - const contentStyle: CSSProperties = { overflowY: "auto", maxHeight: "245px" }; + const contentStyle: CSSProperties = { overflowY: "auto" }; const [isAddEndpointModalVisible, setIsAddEndpointModalVisible] = useState(false); const [isCreatingEndpoint, setIsCreatingEndpoint] = useState(false); const [endpointNameExists, setEndpointNameExists] = useState(false); @@ -134,14 +134,18 @@ function CustomEdge({ } > - + - + {allElements.length > 0 && ( @@ -165,7 +169,7 @@ function CustomEdge({ { if (!idParam) { useToastStore.getState().error({ From 2d59efc4afc7122a8d38520feed2ec18e0b4ca69 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 16:25:14 +0300 Subject: [PATCH 17/64] fix(648): fix height --- GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index f14353359..4e3aad2ac 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -55,7 +55,7 @@ function CustomEdge({ const [allElements, setAllElements] = useState([]); const [dropdownOpen, setDropdownOpen] = useState(false); const steps = useServiceStore((state) => state.mapEndpointsToSteps()); - const contentStyle: CSSProperties = { overflowY: "auto" }; + const contentStyle: CSSProperties = { overflowY: "auto", maxHeight: "335px" }; const [isAddEndpointModalVisible, setIsAddEndpointModalVisible] = useState(false); const [isCreatingEndpoint, setIsCreatingEndpoint] = useState(false); const [endpointNameExists, setEndpointNameExists] = useState(false); @@ -143,7 +143,7 @@ function CustomEdge({ > {allElements.length > 0 && ( @@ -169,7 +169,7 @@ function CustomEdge({ { if (!idParam) { useToastStore.getState().error({ From c53ed419d85a6727065579bbd5fac72ea425f37f Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 16:28:07 +0300 Subject: [PATCH 18/64] Revert "fix(648): fix height" This reverts commit 2d59efc4afc7122a8d38520feed2ec18e0b4ca69. --- GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index 4e3aad2ac..f14353359 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -55,7 +55,7 @@ function CustomEdge({ const [allElements, setAllElements] = useState([]); const [dropdownOpen, setDropdownOpen] = useState(false); const steps = useServiceStore((state) => state.mapEndpointsToSteps()); - const contentStyle: CSSProperties = { overflowY: "auto", maxHeight: "335px" }; + const contentStyle: CSSProperties = { overflowY: "auto" }; const [isAddEndpointModalVisible, setIsAddEndpointModalVisible] = useState(false); const [isCreatingEndpoint, setIsCreatingEndpoint] = useState(false); const [endpointNameExists, setEndpointNameExists] = useState(false); @@ -143,7 +143,7 @@ function CustomEdge({ > {allElements.length > 0 && ( @@ -169,7 +169,7 @@ function CustomEdge({ { if (!idParam) { useToastStore.getState().error({ From d1e6e0d8901f6a06fd27691d63ea6324a284b7e5 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 16:28:12 +0300 Subject: [PATCH 19/64] Revert "fix(648): fill modal" This reverts commit 3b9f4269024cbe58f3ff35f19bbf9ac49f5e18b4. --- GUI/src/components/Collapsible/Collapsible.scss | 6 ------ GUI/src/components/Dropdown/Dropdown.scss | 4 ++-- GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx | 12 ++++-------- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/GUI/src/components/Collapsible/Collapsible.scss b/GUI/src/components/Collapsible/Collapsible.scss index 6a92d4972..fab472c7a 100644 --- a/GUI/src/components/Collapsible/Collapsible.scss +++ b/GUI/src/components/Collapsible/Collapsible.scss @@ -6,9 +6,6 @@ .collapsible { border: 1px solid get-color(black-coral-2); border-radius: 4px; - display: flex; - flex-direction: column; - min-height: 0; &__trigger { width: 100%; @@ -18,7 +15,6 @@ padding: get-spacing(haapsalu); background-color: get-color(extra-light); border-radius: 4px; - flex-shrink: 0; &[aria-expanded="true"] { border-bottom: 1px solid get-color(black-coral-2); @@ -35,7 +31,5 @@ background-color: get-color(white); border-radius: 0 0 4px 4px; overflow: hidden; - flex: 1; - min-height: 0; } } diff --git a/GUI/src/components/Dropdown/Dropdown.scss b/GUI/src/components/Dropdown/Dropdown.scss index deac22823..0f8734dae 100644 --- a/GUI/src/components/Dropdown/Dropdown.scss +++ b/GUI/src/components/Dropdown/Dropdown.scss @@ -14,8 +14,8 @@ // min-width: 400px; // max-width: 600px; // todo igor needs fine tuning with large monitor - min-height: 700px !important; - max-height: 1000px !important; + min-height: 1000px !important; + max-height: 1500px !important; height: auto !important; display: flex !important; flex-direction: column !important; diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index f14353359..0a3f6747a 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -55,7 +55,7 @@ function CustomEdge({ const [allElements, setAllElements] = useState([]); const [dropdownOpen, setDropdownOpen] = useState(false); const steps = useServiceStore((state) => state.mapEndpointsToSteps()); - const contentStyle: CSSProperties = { overflowY: "auto" }; + const contentStyle: CSSProperties = { overflowY: "auto", maxHeight: "245px" }; const [isAddEndpointModalVisible, setIsAddEndpointModalVisible] = useState(false); const [isCreatingEndpoint, setIsCreatingEndpoint] = useState(false); const [endpointNameExists, setEndpointNameExists] = useState(false); @@ -134,18 +134,14 @@ function CustomEdge({ } > - + - + {allElements.length > 0 && ( @@ -169,7 +165,7 @@ function CustomEdge({ { if (!idParam) { useToastStore.getState().error({ From 3ce7e1b94f8c0dfe655b83b6a1fd38aa792d2fd7 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 16:31:31 +0300 Subject: [PATCH 20/64] fix(648): fix height --- GUI/src/components/Dropdown/Dropdown.scss | 4 ++-- GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/GUI/src/components/Dropdown/Dropdown.scss b/GUI/src/components/Dropdown/Dropdown.scss index 0f8734dae..904ce5501 100644 --- a/GUI/src/components/Dropdown/Dropdown.scss +++ b/GUI/src/components/Dropdown/Dropdown.scss @@ -14,8 +14,8 @@ // min-width: 400px; // max-width: 600px; // todo igor needs fine tuning with large monitor - min-height: 1000px !important; - max-height: 1500px !important; + min-height: 235px !important; + max-height: 80vh !important; height: auto !important; display: flex !important; flex-direction: column !important; diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index 0a3f6747a..891eafe46 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -55,7 +55,7 @@ function CustomEdge({ const [allElements, setAllElements] = useState([]); const [dropdownOpen, setDropdownOpen] = useState(false); const steps = useServiceStore((state) => state.mapEndpointsToSteps()); - const contentStyle: CSSProperties = { overflowY: "auto", maxHeight: "245px" }; + const contentStyle: CSSProperties = { overflowY: "auto", maxHeight: "335px" }; const [isAddEndpointModalVisible, setIsAddEndpointModalVisible] = useState(false); const [isCreatingEndpoint, setIsCreatingEndpoint] = useState(false); const [endpointNameExists, setEndpointNameExists] = useState(false); From 1c8458c959a6e0fd596d2859c80d8d6069d9bb92 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 16:34:21 +0300 Subject: [PATCH 21/64] fix(648): cl --- GUI/src/components/Dropdown/Dropdown.scss | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/GUI/src/components/Dropdown/Dropdown.scss b/GUI/src/components/Dropdown/Dropdown.scss index 904ce5501..b09408b39 100644 --- a/GUI/src/components/Dropdown/Dropdown.scss +++ b/GUI/src/components/Dropdown/Dropdown.scss @@ -11,9 +11,8 @@ resize: both; overflow: auto; width: 400px; - // min-width: 400px; - // max-width: 600px; - // todo igor needs fine tuning with large monitor + min-width: 400px; + max-width: 600px; min-height: 235px !important; max-height: 80vh !important; height: auto !important; From 4dfc4ee2382a07f1d91fe66f23aaa1912c615079 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 16:38:08 +0300 Subject: [PATCH 22/64] fix(648): cl --- GUI/src/components/Dropdown/Dropdown.scss | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/GUI/src/components/Dropdown/Dropdown.scss b/GUI/src/components/Dropdown/Dropdown.scss index b09408b39..ec43ea7f8 100644 --- a/GUI/src/components/Dropdown/Dropdown.scss +++ b/GUI/src/components/Dropdown/Dropdown.scss @@ -13,11 +13,9 @@ width: 400px; min-width: 400px; max-width: 600px; - min-height: 235px !important; - max-height: 80vh !important; - height: auto !important; - display: flex !important; - flex-direction: column !important; + min-height: 235px; + max-height: 80vh; + height: auto; &__header { padding: get-spacing(haapsalu); From 79158f30376feb070b386f583cd4f7211a6160a3 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 16:41:46 +0300 Subject: [PATCH 23/64] fix(648): cl --- GUI/src/components/Dropdown/Dropdown.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GUI/src/components/Dropdown/Dropdown.scss b/GUI/src/components/Dropdown/Dropdown.scss index ec43ea7f8..15d1ed047 100644 --- a/GUI/src/components/Dropdown/Dropdown.scss +++ b/GUI/src/components/Dropdown/Dropdown.scss @@ -14,7 +14,7 @@ min-width: 400px; max-width: 600px; min-height: 235px; - max-height: 80vh; + max-height: 75vh; height: auto; &__header { From 60c997617f338ff82e1a8fb1f7febae7e8bc70bd Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 16:56:45 +0300 Subject: [PATCH 24/64] fix(648): cl --- GUI/src/components/Dropdown/Dropdown.scss | 4 ++++ GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/GUI/src/components/Dropdown/Dropdown.scss b/GUI/src/components/Dropdown/Dropdown.scss index 15d1ed047..48aec92ae 100644 --- a/GUI/src/components/Dropdown/Dropdown.scss +++ b/GUI/src/components/Dropdown/Dropdown.scss @@ -16,6 +16,8 @@ min-height: 235px; max-height: 75vh; height: auto; + display: flex; + flex-direction: column; &__header { padding: get-spacing(haapsalu); @@ -37,5 +39,7 @@ flex: 1; overflow-y: auto; min-height: 0; + display: flex; + flex-direction: column; } } diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index 891eafe46..e3951fb48 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -55,7 +55,11 @@ function CustomEdge({ const [allElements, setAllElements] = useState([]); const [dropdownOpen, setDropdownOpen] = useState(false); const steps = useServiceStore((state) => state.mapEndpointsToSteps()); - const contentStyle: CSSProperties = { overflowY: "auto", maxHeight: "335px" }; + const contentStyle: CSSProperties = { + overflowY: "auto", + maxHeight: "calc(37.5vh - 50px)", + minHeight: "100px", + }; const [isAddEndpointModalVisible, setIsAddEndpointModalVisible] = useState(false); const [isCreatingEndpoint, setIsCreatingEndpoint] = useState(false); const [endpointNameExists, setEndpointNameExists] = useState(false); From b46e97f0312508d327dde5e5bc93229ede990950 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 17:00:54 +0300 Subject: [PATCH 25/64] fix(648): fix height completelyt --- GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index e3951fb48..400c47381 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -57,8 +57,8 @@ function CustomEdge({ const steps = useServiceStore((state) => state.mapEndpointsToSteps()); const contentStyle: CSSProperties = { overflowY: "auto", - maxHeight: "calc(37.5vh - 50px)", - minHeight: "100px", + maxHeight: "calc(30vh - 42px)", + minHeight: "80px", }; const [isAddEndpointModalVisible, setIsAddEndpointModalVisible] = useState(false); const [isCreatingEndpoint, setIsCreatingEndpoint] = useState(false); From 466b1bc4f008e69c550a90f0e40ac37e2ec8cec4 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 17:04:32 +0300 Subject: [PATCH 26/64] fix(648): cl --- GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index 400c47381..a612ea79e 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -121,6 +121,7 @@ function CustomEdge({ <> + {/* All elements */} + {/* API elements */} + + {/* Add endpoint modal */} {isAddEndpointModalVisible && ( Date: Sun, 3 Aug 2025 17:05:02 +0300 Subject: [PATCH 27/64] fix(648): cl --- GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index a612ea79e..3e1b1087c 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -121,7 +121,6 @@ function CustomEdge({ <> - {/* All elements */} } > + {/* All elements */} Date: Sun, 3 Aug 2025 17:42:29 +0300 Subject: [PATCH 28/64] fix(648): REVERT LATER --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index f1e85977d..66c379b31 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -45,8 +45,8 @@ services: - database environment: - sqlms.datasources.[0].name=byk - # - sqlms.datasources.[0].jdbcUrl=jdbc:postgresql://database:5432/services_db # For Local Use - - sqlms.datasources.[0].jdbcUrl=jdbc:postgresql://171.22.247.13:5435/services_db + - sqlms.datasources.[0].jdbcUrl=jdbc:postgresql://database:5432/services_db # For Local Use + # - sqlms.datasources.[0].jdbcUrl=jdbc:postgresql://171.22.247.13:5435/services_db - sqlms.datasources.[0].username=byk - sqlms.datasources.[0].password=01234 - logging.level.org.springframework.boot=INFO From ab4438ca4d2a72b175b4f0ac5f07c04187ff4a95 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 17:50:41 +0300 Subject: [PATCH 29/64] feat(648): add endpoints column to user_step_preference table for API elements ordering --- ...0_add_endpoints_to_user_step_preference.xml | 18 ++++++++++++++++++ ...0_add_endpoints_to_user_step_preference.sql | 4 ++++ .../rollback/20250127000000_rollback.sql | 4 ++++ 3 files changed, 26 insertions(+) create mode 100644 DSL/Liquibase/changelog/20250127000000_add_endpoints_to_user_step_preference.xml create mode 100644 DSL/Liquibase/changelog/migrations/20250127000000_add_endpoints_to_user_step_preference.sql create mode 100644 DSL/Liquibase/changelog/migrations/rollback/20250127000000_rollback.sql diff --git a/DSL/Liquibase/changelog/20250127000000_add_endpoints_to_user_step_preference.xml b/DSL/Liquibase/changelog/20250127000000_add_endpoints_to_user_step_preference.xml new file mode 100644 index 000000000..1d5121be2 --- /dev/null +++ b/DSL/Liquibase/changelog/20250127000000_add_endpoints_to_user_step_preference.xml @@ -0,0 +1,18 @@ + + + + + + + + + + \ No newline at end of file diff --git a/DSL/Liquibase/changelog/migrations/20250127000000_add_endpoints_to_user_step_preference.sql b/DSL/Liquibase/changelog/migrations/20250127000000_add_endpoints_to_user_step_preference.sql new file mode 100644 index 000000000..7cdb4bdbc --- /dev/null +++ b/DSL/Liquibase/changelog/migrations/20250127000000_add_endpoints_to_user_step_preference.sql @@ -0,0 +1,4 @@ +-- liquibase formatted sql +-- changeset IgorKrupenja:20250127000000 + +ALTER TABLE user_step_preference ADD COLUMN endpoints UUID[] DEFAULT '{}'; \ No newline at end of file diff --git a/DSL/Liquibase/changelog/migrations/rollback/20250127000000_rollback.sql b/DSL/Liquibase/changelog/migrations/rollback/20250127000000_rollback.sql new file mode 100644 index 000000000..6a5684a5f --- /dev/null +++ b/DSL/Liquibase/changelog/migrations/rollback/20250127000000_rollback.sql @@ -0,0 +1,4 @@ +-- liquibase formatted sql +-- rollback + +ALTER TABLE user_step_preference DROP COLUMN endpoints; \ No newline at end of file From 5fac0e82ca41b8fd6b391113ce72c5da25ebeb44 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 18:03:27 +0300 Subject: [PATCH 30/64] feat(648): update get_endpoints_by_service_id to respect user endpoint preferences --- .../endpoints/get_endpoints_by_service_id.sql | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/DSL/Resql/services/POST/endpoints/get_endpoints_by_service_id.sql b/DSL/Resql/services/POST/endpoints/get_endpoints_by_service_id.sql index ee2e8398c..2de449e67 100644 --- a/DSL/Resql/services/POST/endpoints/get_endpoints_by_service_id.sql +++ b/DSL/Resql/services/POST/endpoints/get_endpoints_by_service_id.sql @@ -3,13 +3,29 @@ WITH LatestEndpoints AS ( FROM endpoints AS e WHERE (e.service_id = :id::uuid OR e.is_common = true) ORDER BY e.endpoint_id, e.id DESC +), +UserPreferences AS ( + SELECT endpoints + FROM user_step_preference + WHERE user_id_code = :user_id_code + ORDER BY created_at DESC + LIMIT 1 ) SELECT - endpoint_id, - name, - type, - is_common, - definitions -FROM LatestEndpoints -WHERE deleted IS FALSE -ORDER BY id DESC; + le.endpoint_id, + le.name, + le.type, + le.is_common, + le.definitions +FROM LatestEndpoints AS le +CROSS JOIN UserPreferences AS up +WHERE le.deleted IS FALSE +ORDER BY + CASE + WHEN up.endpoints IS NULL OR array_length(up.endpoints, 1) = 0 THEN 1 + ELSE array_position(up.endpoints, le.endpoint_id) + END, + CASE + WHEN up.endpoints IS NULL OR array_length(up.endpoints, 1) = 0 THEN le.id + ELSE NULL + END DESC; \ No newline at end of file From 76328aacf1d026162b005f15cd082a87203b6d56 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 18:05:55 +0300 Subject: [PATCH 31/64] feat(648): add user authentication to service-by-id endpoint for endpoint preferences --- DSL/Ruuter/services/GET/service-by-id.yml | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/DSL/Ruuter/services/GET/service-by-id.yml b/DSL/Ruuter/services/GET/service-by-id.yml index 6f2827ec5..5509196bb 100644 --- a/DSL/Ruuter/services/GET/service-by-id.yml +++ b/DSL/Ruuter/services/GET/service-by-id.yml @@ -17,6 +17,26 @@ check_for_parameters: - condition: ${incoming.params == null || incoming.params.id == null} next: return_incorrect_request +get_user_info: + call: http.post + args: + url: "[#SERVICE_TIM]/jwt/custom-jwt-userinfo" + contentType: plaintext + headers: + cookie: ${incoming.headers.cookie} + plaintext: "customJwtCookie" + result: res + +check_user_info_response: + switch: + - condition: ${200 <= res.response.statusCodeValue && res.response.statusCodeValue < 300} + next: assignIdCode + next: return_unauthorized + +assignIdCode: + assign: + idCode: ${res.response.body.idCode} + get_service_by_id: call: http.post args: @@ -31,6 +51,7 @@ get_endpoints_by_service_id: url: "[#SERVICE_RESQL]/endpoints/get_endpoints_by_service_id" body: id: ${incoming.params.id} + user_id_code: ${idCode} result: endpoints_results prepare_results: @@ -57,3 +78,8 @@ return_incorrect_request: status: 400 return: "Required parameter(s) missing" next: end + +return_unauthorized: + status: 401 + return: "unauthorized" + next: end From bb2f7fec07c236224accbf825948a5864c9c4058 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 18:13:46 +0300 Subject: [PATCH 32/64] feat(648): extend preferences endpoints to support both steps and endpoints --- DSL/Resql/services/POST/get-user-step-preferences.sql | 2 +- .../services/POST/update-user-step-preferences.sql | 4 ++-- DSL/Ruuter/services/GET/steps/preferences.yml | 10 +++++++--- DSL/Ruuter/services/POST/steps/preferences.yml | 11 +++++++++-- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/DSL/Resql/services/POST/get-user-step-preferences.sql b/DSL/Resql/services/POST/get-user-step-preferences.sql index 16fe588d9..c2f3650d6 100644 --- a/DSL/Resql/services/POST/get-user-step-preferences.sql +++ b/DSL/Resql/services/POST/get-user-step-preferences.sql @@ -1,4 +1,4 @@ -SELECT steps +SELECT steps, endpoints FROM user_step_preference WHERE user_id_code = :user_id_code ORDER BY created_at DESC diff --git a/DSL/Resql/services/POST/update-user-step-preferences.sql b/DSL/Resql/services/POST/update-user-step-preferences.sql index 98119c0db..b84c6441e 100644 --- a/DSL/Resql/services/POST/update-user-step-preferences.sql +++ b/DSL/Resql/services/POST/update-user-step-preferences.sql @@ -1,2 +1,2 @@ -INSERT INTO user_step_preference(steps, user_id_code) -VALUES(:steps::step_type[], :user_id_code); +INSERT INTO user_step_preference(steps, endpoints, user_id_code) +VALUES(:steps::step_type[], :endpoints::uuid[], :user_id_code); diff --git a/DSL/Ruuter/services/GET/steps/preferences.yml b/DSL/Ruuter/services/GET/steps/preferences.yml index 05b281116..c5de72c86 100644 --- a/DSL/Ruuter/services/GET/steps/preferences.yml +++ b/DSL/Ruuter/services/GET/steps/preferences.yml @@ -39,7 +39,7 @@ check_preferences_response: switch: - condition: ${preferences.response.body.length > 0} next: return_preferences - next: seed_default_user_preferences + next: seed_default_user_preferences seed_default_user_preferences: call: http.post @@ -58,11 +58,15 @@ refetch_user_step_preferences: result: refetched_preferences return_refetched_preferences: - return: ${refetched_preferences.response.body[0].steps} + return: + steps: ${refetched_preferences.response.body[0].steps} + endpoints: ${refetched_preferences.response.body[0].endpoints} next: end return_preferences: - return: ${preferences.response.body[0].steps} + return: + steps: ${preferences.response.body[0].steps} + endpoints: ${preferences.response.body[0].endpoints} next: end return_unauthorized: diff --git a/DSL/Ruuter/services/POST/steps/preferences.yml b/DSL/Ruuter/services/POST/steps/preferences.yml index 7cf177253..913187684 100644 --- a/DSL/Ruuter/services/POST/steps/preferences.yml +++ b/DSL/Ruuter/services/POST/steps/preferences.yml @@ -11,10 +11,14 @@ declaration: - field: steps type: string description: "Body field 'steps'" + - field: endpoints + type: string + description: "Body field 'endpoints'" extractRequestData: assign: - steps: ${incoming.body.steps.join(",")} + steps: ${incoming.body.steps.join(",")} + endpoints: ${incoming.body.endpoints.join(",")} get_user_info: call: http.post @@ -42,6 +46,7 @@ update_user_step_preferences: url: "[#SERVICE_RESQL]/update-user-step-preferences" body: steps: "{${steps}}" + endpoints: "{${endpoints}}" user_id_code: ${idCode} result: update_preferences_res @@ -54,7 +59,9 @@ get_user_step_preferences: result: preferences return_preferences: - return: ${preferences.response.body[0].steps} + return: + steps: ${preferences.response.body[0].steps} + endpoints: ${preferences.response.body[0].endpoints} next: end return_unauthorized: From 154017fe01f578bdc95b22bca78ff162a9be0da6 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 18:28:02 +0300 Subject: [PATCH 33/64] feat(648): fix YAML return statements to return JSON objects instead of nested objects --- DSL/Ruuter/services/GET/steps/preferences.yml | 8 ++------ DSL/Ruuter/services/POST/steps/preferences.yml | 4 +--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/DSL/Ruuter/services/GET/steps/preferences.yml b/DSL/Ruuter/services/GET/steps/preferences.yml index c5de72c86..290f6bb5c 100644 --- a/DSL/Ruuter/services/GET/steps/preferences.yml +++ b/DSL/Ruuter/services/GET/steps/preferences.yml @@ -58,15 +58,11 @@ refetch_user_step_preferences: result: refetched_preferences return_refetched_preferences: - return: - steps: ${refetched_preferences.response.body[0].steps} - endpoints: ${refetched_preferences.response.body[0].endpoints} + return: ${refetched_preferences.response.body[0]} next: end return_preferences: - return: - steps: ${preferences.response.body[0].steps} - endpoints: ${preferences.response.body[0].endpoints} + return: ${preferences.response.body[0]} next: end return_unauthorized: diff --git a/DSL/Ruuter/services/POST/steps/preferences.yml b/DSL/Ruuter/services/POST/steps/preferences.yml index 913187684..61f727229 100644 --- a/DSL/Ruuter/services/POST/steps/preferences.yml +++ b/DSL/Ruuter/services/POST/steps/preferences.yml @@ -59,9 +59,7 @@ get_user_step_preferences: result: preferences return_preferences: - return: - steps: ${preferences.response.body[0].steps} - endpoints: ${preferences.response.body[0].endpoints} + return: ${preferences.response.body[0]} next: end return_unauthorized: From 24da9f0a73774d6ba8b5a654c1ab7187ff39b9a5 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 18:30:35 +0300 Subject: [PATCH 34/64] fix(648): update loadStepPreferences to handle new API response format --- GUI/src/store/new-services.store.ts | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/GUI/src/store/new-services.store.ts b/GUI/src/store/new-services.store.ts index 58ab34872..c30dc96d6 100644 --- a/GUI/src/store/new-services.store.ts +++ b/GUI/src/store/new-services.store.ts @@ -1,6 +1,16 @@ import { create } from "zustand"; import { v4 as uuid } from "uuid"; -import { Edge, EdgeChange, Node, NodeChange, ReactFlowInstance, applyEdgeChanges, applyNodeChanges, getIncomers, getOutgoers } from "@xyflow/react"; +import { + Edge, + EdgeChange, + Node, + NodeChange, + ReactFlowInstance, + applyEdgeChanges, + applyNodeChanges, + getIncomers, + getOutgoers, +} from "@xyflow/react"; import { EndpointData, EndpointEnv, EndpointTab, PreDefinedEndpointEnvVariables } from "types/endpoint"; import { getCommonEndpoints, @@ -248,12 +258,14 @@ const useServiceStore = create((set, get, store) => ({ try { const instance = get().reactFlowInstance; if (!instance) return; - const endpointNodes = instance.getNodes().filter((node) => node.data.stepType === StepType.UserDefined) as Node[]; + const endpointNodes = instance + .getNodes() + .filter((node) => node.data.stepType === StepType.UserDefined) as Node[]; if (endpointNodes.length === 0) { set({ endpointsResponseVariables: [] }); return; - }; - + } + const endpointsFromNodes = endpointNodes.map((node) => node.data.endpoint); const requests = endpointsFromNodes.flatMap((e) => e?.definitions.map((endpoint) => ({ @@ -284,7 +296,7 @@ const useServiceStore = create((set, get, store) => ({ } const variable: EndpointResponseVariable = { - name: endpoint?.name ?? '', + name: endpoint?.name ?? "", chips: chips, }; @@ -472,8 +484,8 @@ const useServiceStore = create((set, get, store) => ({ }, loadStepPreferences: async () => { try { - const response = await api.get<{ response: string[] }>(userStepPreferences()); - set({ stepPreferences: response.data.response }); + const response = await api.get<{ response: { steps: string[]; endpoints: string[] } }>(userStepPreferences()); + set({ stepPreferences: response.data.response.steps || [] }); } catch (error) { console.error("Failed to load step preferences:", error); } From 5ac191283a9edfec6b47359e5363eb0b683994af Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 18:35:29 +0300 Subject: [PATCH 35/64] feat(648): add endpointPreferences to useServiceStore state and API loading --- GUI/src/store/new-services.store.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/GUI/src/store/new-services.store.ts b/GUI/src/store/new-services.store.ts index c30dc96d6..fc3cbabb5 100644 --- a/GUI/src/store/new-services.store.ts +++ b/GUI/src/store/new-services.store.ts @@ -52,6 +52,7 @@ interface ServiceStoreState { rules: GroupOrRule[]; isYesNoQuestion: boolean; stepPreferences: string[]; + endpointPreferences: string[]; endpointsResponseVariables: EndpointResponseVariable[]; setIsYesNoQuestion: (value: boolean) => void; changeAssignNode: (assign: Assign[]) => void; @@ -75,6 +76,7 @@ interface ServiceStoreState { setDescription: (description: string) => void; setSlot: (slot: string) => void; setStepPreferences: (stepPreferences: string[]) => void; + setEndpointPreferences: (endpointPreferences: string[]) => void; loadEndpointsResponseVariables: () => void; setSecrets: (newSecrets: PreDefinedEndpointEnvVariables) => void; addProductionVariables: (variables: string[]) => void; @@ -150,6 +152,7 @@ const useServiceStore = create((set, get, store) => ({ rules: [], isYesNoQuestion: false, stepPreferences: [], + endpointPreferences: [], endpointsResponseVariables: [], setIsYesNoQuestion: (value: boolean) => set({ isYesNoQuestion: value }), changeAssignNode: (assignElements) => { @@ -321,6 +324,7 @@ const useServiceStore = create((set, get, store) => ({ setDescription: (description: string) => set({ description }), setSlot: (slot: string) => set({ slot }), setStepPreferences: (stepPreferences: string[]) => set({ stepPreferences }), + setEndpointPreferences: (endpointPreferences: string[]) => set({ endpointPreferences }), isCommon: false, setIsCommon: (isCommon: boolean) => set({ isCommon }), isCommonEndpoint: (id: string) => { @@ -485,7 +489,10 @@ const useServiceStore = create((set, get, store) => ({ loadStepPreferences: async () => { try { const response = await api.get<{ response: { steps: string[]; endpoints: string[] } }>(userStepPreferences()); - set({ stepPreferences: response.data.response.steps || [] }); + set({ + stepPreferences: response.data.response.steps ?? [], + endpointPreferences: response.data.response.endpoints ?? [], + }); } catch (error) { console.error("Failed to load step preferences:", error); } From 7b8a2c2b9afc4c1d1497043d182a798fed822cdf Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 18:48:39 +0300 Subject: [PATCH 36/64] feat(648): add apiElements state to CustomEdge component --- .../components/Flow/EdgeTypes/CustomEdge.tsx | 40 +++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index 3e1b1087c..834e6d272 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -53,8 +53,8 @@ function CustomEdge({ const { t } = useTranslation(); const [allElements, setAllElements] = useState([]); + const [apiElements, setApiElements] = useState(useServiceStore.getState().mapEndpointsToSteps()); const [dropdownOpen, setDropdownOpen] = useState(false); - const steps = useServiceStore((state) => state.mapEndpointsToSteps()); const contentStyle: CSSProperties = { overflowY: "auto", maxHeight: "calc(30vh - 42px)", @@ -75,6 +75,8 @@ function CustomEdge({ const { setHasUnsavedChanges } = useServiceStore(); const stepPreferences = useServiceStore((state) => state.stepPreferences); + // todo why? + const endpointPreferences = useServiceStore((state) => state.endpointPreferences); const onEdgeAdd = useEdgeAdd(id); @@ -104,6 +106,21 @@ function CustomEdge({ } } + // todo common method? + function handleApiDragEnd(event: DragEndEvent) { + const { active, over } = event; + + if (over && active.id !== over.id) { + setApiElements((elements) => { + const oldIndex = elements.findIndex((item) => item.id === active.id); + const newIndex = elements.findIndex((item) => item.id === over.id); + const newElements = arrayMove(elements, oldIndex, newIndex); + updateEndpointPreference(newElements); + return newElements; + }); + } + } + const sensors = useSensors( useSensor(PointerSensor), useSensor(KeyboardSensor, { @@ -117,6 +134,23 @@ function CustomEdge({ }); } + function updateEndpointPreference(endpoints: Step[]) { + // todo why? + const endpointIds = endpoints.map((e) => { + // Try to get endpointId from data first, then fall back to id + if (e.data && typeof e.data === "object" && "endpointId" in e.data) { + return e.data.endpointId; + } + // If no data or no endpointId, use the id as string + return e.id.toString(); + }); + + api.post(userStepPreferences(), { + steps: stepPreferences || [], + endpoints: endpointIds, + }); + } + return ( <> @@ -183,9 +217,9 @@ function CustomEdge({ } }} > - {steps.length > 0 && ( + {apiElements.length > 0 && ( - {steps.map((step) => ( + {apiElements.map((step) => ( Date: Sun, 3 Aug 2025 18:55:49 +0300 Subject: [PATCH 37/64] feat(648): move apiElements state management to store --- .../components/Flow/EdgeTypes/CustomEdge.tsx | 18 ++++++++---------- GUI/src/store/new-services.store.ts | 7 +++++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index 834e6d272..ef7fe5eb3 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -53,7 +53,6 @@ function CustomEdge({ const { t } = useTranslation(); const [allElements, setAllElements] = useState([]); - const [apiElements, setApiElements] = useState(useServiceStore.getState().mapEndpointsToSteps()); const [dropdownOpen, setDropdownOpen] = useState(false); const contentStyle: CSSProperties = { overflowY: "auto", @@ -75,8 +74,8 @@ function CustomEdge({ const { setHasUnsavedChanges } = useServiceStore(); const stepPreferences = useServiceStore((state) => state.stepPreferences); - // todo why? - const endpointPreferences = useServiceStore((state) => state.endpointPreferences); + const apiElements = useServiceStore((state) => state.apiElements); + const setApiElements = useServiceStore((state) => state.setApiElements); const onEdgeAdd = useEdgeAdd(id); @@ -111,13 +110,12 @@ function CustomEdge({ const { active, over } = event; if (over && active.id !== over.id) { - setApiElements((elements) => { - const oldIndex = elements.findIndex((item) => item.id === active.id); - const newIndex = elements.findIndex((item) => item.id === over.id); - const newElements = arrayMove(elements, oldIndex, newIndex); - updateEndpointPreference(newElements); - return newElements; - }); + const currentElements = apiElements; + const oldIndex = currentElements.findIndex((item: Step) => item.id === active.id); + const newIndex = currentElements.findIndex((item: Step) => item.id === over.id); + const newElements = arrayMove(currentElements, oldIndex, newIndex); + setApiElements(newElements); + updateEndpointPreference(newElements); } } diff --git a/GUI/src/store/new-services.store.ts b/GUI/src/store/new-services.store.ts index fc3cbabb5..965b8cdcb 100644 --- a/GUI/src/store/new-services.store.ts +++ b/GUI/src/store/new-services.store.ts @@ -53,6 +53,7 @@ interface ServiceStoreState { isYesNoQuestion: boolean; stepPreferences: string[]; endpointPreferences: string[]; + apiElements: Step[]; endpointsResponseVariables: EndpointResponseVariable[]; setIsYesNoQuestion: (value: boolean) => void; changeAssignNode: (assign: Assign[]) => void; @@ -77,6 +78,7 @@ interface ServiceStoreState { setSlot: (slot: string) => void; setStepPreferences: (stepPreferences: string[]) => void; setEndpointPreferences: (endpointPreferences: string[]) => void; + setApiElements: (apiElements: Step[]) => void; loadEndpointsResponseVariables: () => void; setSecrets: (newSecrets: PreDefinedEndpointEnvVariables) => void; addProductionVariables: (variables: string[]) => void; @@ -153,6 +155,7 @@ const useServiceStore = create((set, get, store) => ({ isYesNoQuestion: false, stepPreferences: [], endpointPreferences: [], + apiElements: [], endpointsResponseVariables: [], setIsYesNoQuestion: (value: boolean) => set({ isYesNoQuestion: value }), changeAssignNode: (assignElements) => { @@ -325,6 +328,7 @@ const useServiceStore = create((set, get, store) => ({ setSlot: (slot: string) => set({ slot }), setStepPreferences: (stepPreferences: string[]) => set({ stepPreferences }), setEndpointPreferences: (endpointPreferences: string[]) => set({ endpointPreferences }), + setApiElements: (apiElements) => set({ apiElements }), isCommon: false, setIsCommon: (isCommon: boolean) => set({ isCommon }), isCommonEndpoint: (id: string) => { @@ -493,6 +497,9 @@ const useServiceStore = create((set, get, store) => ({ stepPreferences: response.data.response.steps ?? [], endpointPreferences: response.data.response.endpoints ?? [], }); + // Update apiElements after setting preferences + const apiElements = get().mapEndpointsToSteps(); + set({ apiElements }); } catch (error) { console.error("Failed to load step preferences:", error); } From e9caf407e1f8c5da2503ff1b2eae82bf35a46198 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Sun, 3 Aug 2025 18:59:34 +0300 Subject: [PATCH 38/64] feat(648): add drag-and-drop functionality to API elements --- GUI/src/components/ApiEndpoint/index.tsx | 29 ++++++-- .../components/Flow/EdgeTypes/CustomEdge.tsx | 73 +++++++++++-------- 2 files changed, 63 insertions(+), 39 deletions(-) diff --git a/GUI/src/components/ApiEndpoint/index.tsx b/GUI/src/components/ApiEndpoint/index.tsx index 004db3811..d14a3740c 100644 --- a/GUI/src/components/ApiEndpoint/index.tsx +++ b/GUI/src/components/ApiEndpoint/index.tsx @@ -4,7 +4,7 @@ import Icon from "components/Icon"; import Track from "components/Track"; import { FC, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; -import { MdDeleteOutline, MdOutlineEdit } from "react-icons/md"; +import { MdDeleteOutline, MdOutlineEdit, MdDragIndicator } from "react-icons/md"; import { Link } from "react-router-dom"; import { deleteEndpoint } from "resources/api-constants"; import useServiceStore from "store/new-services.store"; @@ -18,6 +18,8 @@ import Modal from "components/Modal"; import ApiEndpointCard from "components/ApiEndpointCard"; import { saveEndpoints } from "services/service-builder"; import { removeTrailingUnderscores } from "utils/string-util"; +import { useSortable } from "@dnd-kit/sortable"; +import { CSS } from "@dnd-kit/utilities"; interface RelatedService { serviceId: string; @@ -32,6 +34,14 @@ interface ApiEndpointProps { const ApiEndpoint: FC = ({ step, onClick }) => { const { t } = useTranslation(); + const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: step.id }); + + const style = { + transform: CSS.Transform.toString(transform), + transition, + opacity: isDragging ? 0.5 : 1, + }; + const [relatedServices, setRelatedServices] = useState([]); const [showEditModal, setShowEditModal] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false); @@ -182,18 +192,23 @@ const ApiEndpoint: FC = ({ step, onClick }) => { )} onClick(step)} - draggable={false} > -
- {step.type === "user-defined" && } - {step.label} -
+ +
+ } size="small" /> +
+
+ {step.type === "user-defined" && } + {step.label} +
+
{step.type === "user-defined" && } + {step.data?.isCommon && ( + {t("newService.endpoint.publicEndpoint")} + )} {step.label}
From 0a74210d3aeda5ce2910ec8d33dc61a9fcccf931 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Mon, 4 Aug 2025 13:46:18 +0300 Subject: [PATCH 49/64] feat(648): add spacing between API and PUBLIC icons --- GUI/src/assets/images/public-icon-tag.svg | 4 ++++ .../components/ApiEndpoint/ApiEndpoint.module.scss | 12 +----------- GUI/src/components/ApiEndpoint/index.tsx | 5 ++--- 3 files changed, 7 insertions(+), 14 deletions(-) create mode 100644 GUI/src/assets/images/public-icon-tag.svg diff --git a/GUI/src/assets/images/public-icon-tag.svg b/GUI/src/assets/images/public-icon-tag.svg new file mode 100644 index 000000000..d4f45cb2c --- /dev/null +++ b/GUI/src/assets/images/public-icon-tag.svg @@ -0,0 +1,4 @@ + + + PUBLIC + \ No newline at end of file diff --git a/GUI/src/components/ApiEndpoint/ApiEndpoint.module.scss b/GUI/src/components/ApiEndpoint/ApiEndpoint.module.scss index fe57ca21c..cf6c7149b 100644 --- a/GUI/src/components/ApiEndpoint/ApiEndpoint.module.scss +++ b/GUI/src/components/ApiEndpoint/ApiEndpoint.module.scss @@ -17,23 +17,13 @@ align-items: center; width: 100%; min-width: 0; + gap: 8px; .label { - padding-left: 8px; overflow: hidden; text-overflow: ellipsis; min-width: 0; } - - .commonLabel { - margin-left: 8px; - font-size: 11px; - color: get-color(blue-6); - background-color: get-color(blue-1); - padding: 2px 6px; - border-radius: 4px; - white-space: nowrap; - } } .loader { diff --git a/GUI/src/components/ApiEndpoint/index.tsx b/GUI/src/components/ApiEndpoint/index.tsx index f79a0623a..2b781ed2b 100644 --- a/GUI/src/components/ApiEndpoint/index.tsx +++ b/GUI/src/components/ApiEndpoint/index.tsx @@ -12,6 +12,7 @@ import useToastStore from "store/toasts.store"; import { Step, StepType } from "types"; import { EndpointData } from "types/endpoint"; import apiIconTag from "../../assets/images/api-icon-tag.svg"; +import publicIconTag from "../../assets/images/public-icon-tag.svg"; import styles from "./ApiEndpoint.module.scss"; import api from "../../services/api-dev"; import Modal from "components/Modal"; @@ -206,9 +207,7 @@ const ApiEndpoint: FC = ({ step, onClick }) => {
{step.type === "user-defined" && } - {step.data?.isCommon && ( - {t("newService.endpoint.publicEndpoint")} - )} + {step.data?.isCommon && } {step.label}
From c7aa0cdafbf3163f461c41fc8b8a5734da5e2b01 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Mon, 4 Aug 2025 14:01:07 +0300 Subject: [PATCH 50/64] feat(648): convert API and PUBLIC icons to CSS badges with translations --- GUI/src/assets/images/api-icon-tag.svg | 3 --- GUI/src/assets/images/public-icon-tag.svg | 4 ---- .../ApiEndpoint/ApiEndpoint.module.scss | 19 +++++++++++++++++++ GUI/src/components/ApiEndpoint/index.tsx | 7 +++---- GUI/src/i18n/en/common.json | 3 ++- GUI/src/i18n/et/common.json | 3 ++- 6 files changed, 26 insertions(+), 13 deletions(-) delete mode 100644 GUI/src/assets/images/api-icon-tag.svg delete mode 100644 GUI/src/assets/images/public-icon-tag.svg diff --git a/GUI/src/assets/images/api-icon-tag.svg b/GUI/src/assets/images/api-icon-tag.svg deleted file mode 100644 index e2ed74604..000000000 --- a/GUI/src/assets/images/api-icon-tag.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/GUI/src/assets/images/public-icon-tag.svg b/GUI/src/assets/images/public-icon-tag.svg deleted file mode 100644 index d4f45cb2c..000000000 --- a/GUI/src/assets/images/public-icon-tag.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - PUBLIC - \ No newline at end of file diff --git a/GUI/src/components/ApiEndpoint/ApiEndpoint.module.scss b/GUI/src/components/ApiEndpoint/ApiEndpoint.module.scss index cf6c7149b..b2b597661 100644 --- a/GUI/src/components/ApiEndpoint/ApiEndpoint.module.scss +++ b/GUI/src/components/ApiEndpoint/ApiEndpoint.module.scss @@ -24,6 +24,25 @@ text-overflow: ellipsis; min-width: 0; } + + .apiBadge, + .publicBadge { + color: white; + font-size: 10px; + font-weight: bold; + padding: 2px 6px; + border-radius: 2px; + white-space: nowrap; + text-transform: uppercase; + } + + .apiBadge { + background-color: #8bb4d5; + } + + .publicBadge { + background-color: #6b9bc5; + } } .loader { diff --git a/GUI/src/components/ApiEndpoint/index.tsx b/GUI/src/components/ApiEndpoint/index.tsx index 2b781ed2b..0ee21799f 100644 --- a/GUI/src/components/ApiEndpoint/index.tsx +++ b/GUI/src/components/ApiEndpoint/index.tsx @@ -11,8 +11,7 @@ import useServiceStore from "store/new-services.store"; import useToastStore from "store/toasts.store"; import { Step, StepType } from "types"; import { EndpointData } from "types/endpoint"; -import apiIconTag from "../../assets/images/api-icon-tag.svg"; -import publicIconTag from "../../assets/images/public-icon-tag.svg"; + import styles from "./ApiEndpoint.module.scss"; import api from "../../services/api-dev"; import Modal from "components/Modal"; @@ -206,8 +205,8 @@ const ApiEndpoint: FC = ({ step, onClick }) => { } size="small" />
- {step.type === "user-defined" && } - {step.data?.isCommon && } + {step.type === "user-defined" && API} + {step.data?.isCommon && {t("serviceFlow.apiElements.public")}} {step.label}
diff --git a/GUI/src/i18n/en/common.json b/GUI/src/i18n/en/common.json index 7a32b9c4c..cd1c83685 100644 --- a/GUI/src/i18n/en/common.json +++ b/GUI/src/i18n/en/common.json @@ -387,7 +387,8 @@ "deleteSuccess": "API element deleted successfully", "deleteError": "Failed to delete API element", "editSuccess": "API element edited successfully", - "editError": "Failed to edit API element" + "editError": "Failed to edit API element", + "public": "Public" }, "multiChoiceQuestion": { "questionPlaceholder": "Enter a question", diff --git a/GUI/src/i18n/et/common.json b/GUI/src/i18n/et/common.json index 1278bc8a9..66f6a9ce8 100644 --- a/GUI/src/i18n/et/common.json +++ b/GUI/src/i18n/et/common.json @@ -387,7 +387,8 @@ "deleteSuccess": "API element kustutatud", "deleteError": "API elementi kustutamine ebaõnnestus", "editSuccess": "API element edukalt muudetud", - "editError": "API elemendi muutmine ebaõnnestus" + "editError": "API elemendi muutmine ebaõnnestus", + "public": "Avalik" }, "multiChoiceQuestion": { "title": "Mitmevalikuline küsimus", From d7b14f4a80f42e1d326ebacef39b5c1158d21102 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Mon, 4 Aug 2025 14:06:09 +0300 Subject: [PATCH 51/64] fix(648): ensure endpoint list updates when new endpoints are added --- GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index 53b6384dc..d075799f2 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -82,6 +82,7 @@ function CustomEdge({ const stepPreferences = useServiceStore((state) => state.stepPreferences); const mapEndpointsToSteps = useServiceStore((state) => state.mapEndpointsToSteps); + const endpoints = useServiceStore((state) => state.endpoints); const onEdgeAdd = useEdgeAdd(id); @@ -100,7 +101,8 @@ function CustomEdge({ useEffect(() => { const steps = mapEndpointsToSteps(); setApiElements(steps); - }, [mapEndpointsToSteps]); + // endpoints in the dependency array below needed to re-run when new endpoints are added + }, [mapEndpointsToSteps, endpoints]); function handleDragEnd(event: DragEndEvent) { const { active, over } = event; From d122dd2b6f7e47608d79768fcfb03d7bf41aae43 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Mon, 4 Aug 2025 14:10:43 +0300 Subject: [PATCH 52/64] fix(648): cl --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 5c4c97e10..99117912b 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,8 @@ **/npm-debug.log* /.idea/ **/package-lock.json + +# Cursor IDE +.cursor/ +.cursorrules +.cursorrules.json From 3e9f7996423a60d8c149a9e056eee15237d99b9b Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Mon, 4 Aug 2025 14:12:31 +0300 Subject: [PATCH 53/64] fix(648): cl --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 66c379b31..f1e85977d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -45,8 +45,8 @@ services: - database environment: - sqlms.datasources.[0].name=byk - - sqlms.datasources.[0].jdbcUrl=jdbc:postgresql://database:5432/services_db # For Local Use - # - sqlms.datasources.[0].jdbcUrl=jdbc:postgresql://171.22.247.13:5435/services_db + # - sqlms.datasources.[0].jdbcUrl=jdbc:postgresql://database:5432/services_db # For Local Use + - sqlms.datasources.[0].jdbcUrl=jdbc:postgresql://171.22.247.13:5435/services_db - sqlms.datasources.[0].username=byk - sqlms.datasources.[0].password=01234 - logging.level.org.springframework.boot=INFO From 25d21cd212bce61d82b75fa4e695dd7a7d67054c Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Mon, 4 Aug 2025 14:16:42 +0300 Subject: [PATCH 54/64] fix(648): cl --- GUI/src/services/service-builder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GUI/src/services/service-builder.ts b/GUI/src/services/service-builder.ts index 279f8b93d..a95909480 100644 --- a/GUI/src/services/service-builder.ts +++ b/GUI/src/services/service-builder.ts @@ -6,7 +6,7 @@ import { Edge, Node } from "@xyflow/react"; import { createEndpoint, createNewService, editService, testService, updateEndpoint } from "resources/api-constants"; import useServiceStore from "store/new-services.store"; import useToastStore from "store/toasts.store"; -import { Step, StepType } from "types"; +import { StepType } from "types"; import { EndpointData, EndpointVariableData } from "types/endpoint"; import api from "../services/api-dev"; import { NodeDataProps } from "types/service-flow"; From e1b054e8a5a8d3fa7de0c6a4204c7c9f09bd798b Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Mon, 4 Aug 2025 15:53:20 +0300 Subject: [PATCH 55/64] feat(648): temporarily filter step elements to show only specific types --- .../components/Flow/EdgeTypes/CustomEdge.tsx | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index d075799f2..c427e8ff5 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -89,11 +89,22 @@ function CustomEdge({ useEffect(() => { const elements: Step[] = []; stepPreferences.forEach((preference, index) => { - elements.push({ - id: index, - label: t(`${stepsLabels[preference as StepType]}`), - type: preference as StepType, - }); + // TODO: Add more steps when they are ready + const allowedSteps = [ + StepType.Condition, + StepType.Assign, + StepType.MultiChoiceQuestion, + StepType.FinishingStepRedirect, + StepType.FinishingStepEnd, + ]; + + if (allowedSteps.includes(preference as StepType)) { + elements.push({ + id: index, + label: t(`${stepsLabels[preference as StepType]}`), + type: preference as StepType, + }); + } }); setAllElements(elements); }, [stepPreferences]); From 3500c44692e06d361052d6e2a6342d79e4982704 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Mon, 4 Aug 2025 16:12:21 +0300 Subject: [PATCH 56/64] feat(648): handle endpoint deletion by removing from user preferences --- .../remove_endpoint_from_preferences.sql | 15 +++++++++++++++ .../services/POST/services/delete-endpoint.yml | 8 ++++++++ 2 files changed, 23 insertions(+) create mode 100644 DSL/Resql/services/POST/endpoints/remove_endpoint_from_preferences.sql diff --git a/DSL/Resql/services/POST/endpoints/remove_endpoint_from_preferences.sql b/DSL/Resql/services/POST/endpoints/remove_endpoint_from_preferences.sql new file mode 100644 index 000000000..c68a375bd --- /dev/null +++ b/DSL/Resql/services/POST/endpoints/remove_endpoint_from_preferences.sql @@ -0,0 +1,15 @@ +-- Remove a specific endpoint from all user step preferences +-- This is called when an endpoint is deleted to clean up references + +INSERT INTO user_step_preference (steps, endpoints, user_id_code) +SELECT + steps, + array_remove(endpoints, :endpoint_id::uuid) AS endpoints, + user_id_code +FROM user_step_preference AS usp1 +WHERE endpoints @> ARRAY[:endpoint_id::uuid] + AND created_at = ( + SELECT MAX(created_at) + FROM user_step_preference AS usp2 + WHERE usp2.user_id_code = usp1.user_id_code + ); \ No newline at end of file diff --git a/DSL/Ruuter/services/POST/services/delete-endpoint.yml b/DSL/Ruuter/services/POST/services/delete-endpoint.yml index bf5f6319c..f585495ea 100644 --- a/DSL/Ruuter/services/POST/services/delete-endpoint.yml +++ b/DSL/Ruuter/services/POST/services/delete-endpoint.yml @@ -20,6 +20,14 @@ delete_endpoint: id: ${incoming.body.id} result: res +remove_from_preferences: + call: http.post + args: + url: "[#SERVICE_RESQL]/endpoints/remove_endpoint_from_preferences" + body: + endpoint_id: ${incoming.body.id} + result: preferences_res + return_ok: status: 200 return: "Endpoint deleted" From 23c3839e1b09875a743fc5140a966f43716433c8 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Mon, 4 Aug 2025 16:18:46 +0300 Subject: [PATCH 57/64] feat(648): handle service deletion by removing its endpoints from user preferences --- ...ove_service_endpoints_from_preferences.sql | 23 +++++++++++++++++++ DSL/Ruuter/services/POST/services/delete.yml | 9 ++++++++ 2 files changed, 32 insertions(+) create mode 100644 DSL/Resql/services/POST/endpoints/remove_service_endpoints_from_preferences.sql diff --git a/DSL/Resql/services/POST/endpoints/remove_service_endpoints_from_preferences.sql b/DSL/Resql/services/POST/endpoints/remove_service_endpoints_from_preferences.sql new file mode 100644 index 000000000..019e80fb5 --- /dev/null +++ b/DSL/Resql/services/POST/endpoints/remove_service_endpoints_from_preferences.sql @@ -0,0 +1,23 @@ +-- Remove all non-common endpoints of a deleted service from all user step preferences +-- This is called when a service is deleted to clean up references to its endpoints + +INSERT INTO user_step_preference (steps, endpoints, user_id_code) +SELECT + steps, + array_remove(endpoints, le.endpoint_id) AS endpoints, + user_id_code +FROM user_step_preference AS usp1 +CROSS JOIN ( + SELECT DISTINCT ON (endpoint_id) endpoint_id + FROM endpoints + WHERE service_id = :serviceId::uuid + AND is_common = FALSE + AND deleted = FALSE + ORDER BY endpoint_id, id DESC +) AS le +WHERE usp1.endpoints @> ARRAY[le.endpoint_id] + AND usp1.created_at = ( + SELECT MAX(created_at) + FROM user_step_preference AS usp2 + WHERE usp2.user_id_code = usp1.user_id_code + ); \ No newline at end of file diff --git a/DSL/Ruuter/services/POST/services/delete.yml b/DSL/Ruuter/services/POST/services/delete.yml index 544e8aea4..455fc6828 100644 --- a/DSL/Ruuter/services/POST/services/delete.yml +++ b/DSL/Ruuter/services/POST/services/delete.yml @@ -113,6 +113,15 @@ delete_endpoints_by_service_id: body: serviceId: ${id} result: delete_endpoint_results + next: remove_service_endpoints_from_preferences + +remove_service_endpoints_from_preferences: + call: http.post + args: + url: "[#SERVICE_RESQL]/endpoints/remove_service_endpoints_from_preferences" + body: + serviceId: ${id} + result: remove_preferences_results next: delete_mcq_files delete_mcq_files: From e0b29f1662472cce93ccbdbdb3c4d460bb3329fe Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Mon, 4 Aug 2025 16:37:22 +0300 Subject: [PATCH 58/64] feat(648): simplify endpoint preference updates to use IDs directly --- GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index c427e8ff5..60c1637a3 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -134,7 +134,8 @@ function CustomEdge({ const currentElements = apiElements; const newElements = reorderElements(currentElements, active.id, over.id); setApiElements(newElements); - updateEndpointPreference(newElements); + const endpointIds = newElements.map((e) => e.data?.endpointId).filter((id): id is string => Boolean(id)); + updateEndpointPreference(endpointIds); } } @@ -152,9 +153,7 @@ function CustomEdge({ }); } - function updateEndpointPreference(endpoints: Step[]) { - const endpointIds = endpoints.map((e) => e.data?.endpointId).filter(Boolean); - + function updateEndpointPreference(endpointIds: string[]) { api.post(userStepPreferences(), { steps: stepPreferences, endpoints: endpointIds, @@ -296,6 +295,12 @@ function CustomEdge({ [passedEndpoint], () => { useServiceStore.getState().addEndpoint(passedEndpoint); + // Add the new endpoint to user preferences + const currentEndpointIds = apiElements + .map((e) => e.data?.endpointId) + .filter((id): id is string => Boolean(id)); + const newEndpointIds = [...currentEndpointIds, passedEndpoint.endpointId]; + updateEndpointPreference(newEndpointIds); setIsAddEndpointModalVisible(false); setEndpoint({ endpointId: uuid(), name: "", definitions: [], isNew: true }); useToastStore.getState().success({ title: t("serviceFlow.apiElements.createSuccess") }); From d7fe4ab8aa0e6614ca464a64d270f629e6f9982d Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Mon, 4 Aug 2025 16:43:29 +0300 Subject: [PATCH 59/64] feat(648): extract add endpoint modal into separate component --- .../Flow/EdgeTypes/AddEndpointModal.tsx | 98 +++++++++++++++++++ .../components/Flow/EdgeTypes/CustomEdge.tsx | 85 ++-------------- 2 files changed, 106 insertions(+), 77 deletions(-) create mode 100644 GUI/src/components/Flow/EdgeTypes/AddEndpointModal.tsx diff --git a/GUI/src/components/Flow/EdgeTypes/AddEndpointModal.tsx b/GUI/src/components/Flow/EdgeTypes/AddEndpointModal.tsx new file mode 100644 index 000000000..d2189442f --- /dev/null +++ b/GUI/src/components/Flow/EdgeTypes/AddEndpointModal.tsx @@ -0,0 +1,98 @@ +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { v4 as uuid } from "uuid"; +import { ApiEndpointCard, Button, Modal, Track } from "components"; +import { EndpointData } from "../../../types/endpoint/endpoint-data"; +import useToastStore from "store/toasts.store"; +import useServiceStore from "store/new-services.store"; +import { saveEndpoints } from "../../../services/service-builder"; + +interface AddEndpointModalProps { + isVisible: boolean; + onClose: () => void; + onUpdatePreferences: (endpointIds: string[]) => void; + currentEndpointIds: string[]; +} + +const AddEndpointModal: React.FC = ({ + isVisible, + onClose, + onUpdatePreferences, + currentEndpointIds, +}) => { + const { t } = useTranslation(); + const [endpoint, setEndpoint] = useState({ + endpointId: uuid(), + name: "", + definitions: [], + isNew: true, + }); + const [endpointName, setEndpointName] = useState(""); + const [endpointNameExists, setEndpointNameExists] = useState(false); + const [isCommonEndpoint, setIsCommonEndpoint] = useState(false); + const [isCreatingEndpoint, setIsCreatingEndpoint] = useState(false); + + const handleClose = () => { + setEndpoint({ endpointId: uuid(), name: "", definitions: [], isNew: true }); + setEndpointName(""); + setIsCommonEndpoint(false); + setIsCreatingEndpoint(false); + onClose(); + }; + + const handleCreate = () => { + const passedEndpoint = endpoint; + passedEndpoint.name = endpointName; + passedEndpoint.isCommon = isCommonEndpoint; + setIsCreatingEndpoint(true); + + saveEndpoints( + [passedEndpoint], + () => { + useServiceStore.getState().addEndpoint(passedEndpoint); + // Add the new endpoint to user preferences + const newEndpointIds = [...currentEndpointIds, passedEndpoint.endpointId]; + onUpdatePreferences(newEndpointIds); + + handleClose(); + useToastStore.getState().success({ title: t("serviceFlow.apiElements.createSuccess") }); + setIsCreatingEndpoint(false); + }, + (error) => { + console.error(`Error creating API endpoint: ${error}`); + useToastStore.getState().error({ title: t("serviceFlow.apiElements.createError") }); + setIsCreatingEndpoint(false); + } + ); + }; + + if (!isVisible) return null; + + return ( + + + + + + + + + + ); +}; + +export default AddEndpointModal; diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index 60c1637a3..d2840b098 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -1,11 +1,11 @@ import { BaseEdge, EdgeLabelRenderer, EdgeProps, getBezierPath } from "@xyflow/react"; import { CSSProperties, memo, useEffect, useState } from "react"; -import { ApiEndpointCard, Button, Collapsible, Dropdown, Modal, StepElement, Track } from "components"; +import { Collapsible, Dropdown, StepElement, Track } from "components"; import useServiceStore from "store/new-services.store"; import ApiEndpoint from "components/ApiEndpoint"; +import AddEndpointModal from "./AddEndpointModal"; import { useTranslation } from "react-i18next"; import { Step, stepsLabels, StepType } from "types"; -import { v4 as uuid } from "uuid"; import { arrayMove, SortableContext, @@ -25,8 +25,6 @@ import { import { userStepPreferences } from "resources/api-constants"; import api from "services/api"; import useEdgeAdd from "hooks/flow/useEdgeAdd"; -import { EndpointData } from "types/endpoint"; -import { saveEndpoints } from "services/service-builder"; import useToastStore from "store/toasts.store"; import { useParams } from "react-router-dom"; @@ -67,17 +65,7 @@ function CustomEdge({ minHeight: "80px", }; const [isAddEndpointModalVisible, setIsAddEndpointModalVisible] = useState(false); - const [isCreatingEndpoint, setIsCreatingEndpoint] = useState(false); - const [endpointNameExists, setEndpointNameExists] = useState(false); - const [endpoint, setEndpoint] = useState({ - endpointId: uuid(), - name: "", - definitions: [], - isNew: true, - }); const { id: idParam } = useParams(); - const [endpointName, setEndpointName] = useState(endpoint.name ?? ""); - const [isCommonEndpoint, setIsCommonEndpoint] = useState(endpoint.isCommon ?? false); const { setHasUnsavedChanges } = useServiceStore(); const stepPreferences = useServiceStore((state) => state.stepPreferences); @@ -257,69 +245,12 @@ function CustomEdge({ {/* Add endpoint modal */} - {isAddEndpointModalVisible && ( - { - setEndpoint({ endpointId: uuid(), name: "", definitions: [], isNew: true }); - setIsAddEndpointModalVisible(false); - }} - > - - - - - - - - - )} + setIsAddEndpointModalVisible(false)} + onUpdatePreferences={updateEndpointPreference} + currentEndpointIds={apiElements.map((e) => e.data?.endpointId).filter((id): id is string => Boolean(id))} + /> ); From fb2760f883dbdb1e5f7be0aaf19c220c8d6921a7 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Mon, 4 Aug 2025 16:47:03 +0300 Subject: [PATCH 60/64] feat(648): remove isVisible prop from AddEndpointModal, handle visibility in parent --- .../components/Flow/EdgeTypes/AddEndpointModal.tsx | 10 +--------- GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx | 13 +++++++------ 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/GUI/src/components/Flow/EdgeTypes/AddEndpointModal.tsx b/GUI/src/components/Flow/EdgeTypes/AddEndpointModal.tsx index d2189442f..6839122fa 100644 --- a/GUI/src/components/Flow/EdgeTypes/AddEndpointModal.tsx +++ b/GUI/src/components/Flow/EdgeTypes/AddEndpointModal.tsx @@ -8,18 +8,12 @@ import useServiceStore from "store/new-services.store"; import { saveEndpoints } from "../../../services/service-builder"; interface AddEndpointModalProps { - isVisible: boolean; onClose: () => void; onUpdatePreferences: (endpointIds: string[]) => void; currentEndpointIds: string[]; } -const AddEndpointModal: React.FC = ({ - isVisible, - onClose, - onUpdatePreferences, - currentEndpointIds, -}) => { +const AddEndpointModal: React.FC = ({ onClose, onUpdatePreferences, currentEndpointIds }) => { const { t } = useTranslation(); const [endpoint, setEndpoint] = useState({ endpointId: uuid(), @@ -66,8 +60,6 @@ const AddEndpointModal: React.FC = ({ ); }; - if (!isVisible) return null; - return ( diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index d2840b098..4696cfadd 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -245,12 +245,13 @@ function CustomEdge({ {/* Add endpoint modal */} - setIsAddEndpointModalVisible(false)} - onUpdatePreferences={updateEndpointPreference} - currentEndpointIds={apiElements.map((e) => e.data?.endpointId).filter((id): id is string => Boolean(id))} - /> + {isAddEndpointModalVisible && ( + setIsAddEndpointModalVisible(false)} + onUpdatePreferences={updateEndpointPreference} + currentEndpointIds={apiElements.map((e) => e.data!.endpointId)} + /> + )} ); From 010ed8b751270001771d190c247722ab7e6b1a34 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Mon, 4 Aug 2025 16:51:16 +0300 Subject: [PATCH 61/64] fix(648): fix on all reorder --- GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index 4696cfadd..94de59d83 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -77,7 +77,7 @@ function CustomEdge({ useEffect(() => { const elements: Step[] = []; stepPreferences.forEach((preference, index) => { - // TODO: Add more steps when they are ready + // Add more steps when they are ready const allowedSteps = [ StepType.Condition, StepType.Assign, @@ -122,7 +122,7 @@ function CustomEdge({ const currentElements = apiElements; const newElements = reorderElements(currentElements, active.id, over.id); setApiElements(newElements); - const endpointIds = newElements.map((e) => e.data?.endpointId).filter((id): id is string => Boolean(id)); + const endpointIds = newElements.map((e) => e.data!.endpointId); updateEndpointPreference(endpointIds); } } @@ -137,7 +137,7 @@ function CustomEdge({ function updateStepPreference(steps: Step[]) { api.post(userStepPreferences(), { steps: steps.map((e) => e.type), - endpoints: [], + endpoints: apiElements.map((e) => e.data!.endpointId), }); } From 7b091da8e4e52ba9862190e56c3fa9cab0427500 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Mon, 4 Aug 2025 16:53:24 +0300 Subject: [PATCH 62/64] feat(648): extract endpoint ID helper function to reduce duplication --- GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx index 94de59d83..7efd0340c 100644 --- a/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx +++ b/GUI/src/components/Flow/EdgeTypes/CustomEdge.tsx @@ -34,6 +34,10 @@ function reorderElements(elements: T[], activeId: string | number, overId: st return arrayMove(elements, oldIndex, newIndex); } +function getEndpointIds(elements: Step[]): string[] { + return elements.map((e) => e.data!.endpointId); +} + function CustomEdge({ id, label, @@ -122,7 +126,7 @@ function CustomEdge({ const currentElements = apiElements; const newElements = reorderElements(currentElements, active.id, over.id); setApiElements(newElements); - const endpointIds = newElements.map((e) => e.data!.endpointId); + const endpointIds = getEndpointIds(newElements); updateEndpointPreference(endpointIds); } } @@ -137,7 +141,7 @@ function CustomEdge({ function updateStepPreference(steps: Step[]) { api.post(userStepPreferences(), { steps: steps.map((e) => e.type), - endpoints: apiElements.map((e) => e.data!.endpointId), + endpoints: getEndpointIds(apiElements), }); } @@ -249,7 +253,7 @@ function CustomEdge({ setIsAddEndpointModalVisible(false)} onUpdatePreferences={updateEndpointPreference} - currentEndpointIds={apiElements.map((e) => e.data!.endpointId)} + currentEndpointIds={getEndpointIds(apiElements)} /> )} From df43bd67e59a72564e9a67d137e27c5ea84aa0e8 Mon Sep 17 00:00:00 2001 From: Igor Krupenja Date: Mon, 4 Aug 2025 16:59:52 +0300 Subject: [PATCH 63/64] fix(648): tran --- GUI/src/i18n/en/common.json | 2 +- GUI/src/i18n/et/common.json | 2 +- GUI/src/types/step.ts | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/GUI/src/i18n/en/common.json b/GUI/src/i18n/en/common.json index cd1c83685..ad4a0dc3e 100644 --- a/GUI/src/i18n/en/common.json +++ b/GUI/src/i18n/en/common.json @@ -280,7 +280,7 @@ "openNewWebpage": "Open new webpage", "fileGeneration": "File generation", "fileSigning": "File signing", - "conversationEnd": "End conversation", + "serviceEnd": "End service", "redirectConversationToSupport": "Direct to Customer Support", "rules": "Rules", "rasaRules": "Rasa Rules", diff --git a/GUI/src/i18n/et/common.json b/GUI/src/i18n/et/common.json index 66f6a9ce8..b99f66983 100644 --- a/GUI/src/i18n/et/common.json +++ b/GUI/src/i18n/et/common.json @@ -280,7 +280,7 @@ "openNewWebpage": "Uue veebilehe avamine", "fileGeneration": "Faili genereerimine", "fileSigning": "Faili allkirjastamine", - "conversationEnd": "Vestluse lõpetamine", + "serviceEnd": "Teenuse lõpetamine", "redirectConversationToSupport": "Klienditeenindusse suunamine", "rules": "Reeglid", "rasaRules": "Rasa reeglid", diff --git a/GUI/src/types/step.ts b/GUI/src/types/step.ts index b08adc129..e7c5504bc 100644 --- a/GUI/src/types/step.ts +++ b/GUI/src/types/step.ts @@ -22,10 +22,9 @@ export const stepsLabels: Record = { [StepType.FileSign]: "serviceFlow.element.fileSigning", [StepType.Step]: "serviceFlow.element.step", [StepType.Rule]: "serviceFlow.element.rule", - [StepType.FinishingStepEnd]: "serviceFlow.element.conversationEnd", + [StepType.FinishingStepEnd]: "serviceFlow.element.serviceEnd", [StepType.FinishingStepRedirect]: "serviceFlow.element.redirectConversationToSupport", [StepType.UserDefined]: "serviceFlow.element.userDefined", [StepType.RasaRules]: "serviceFlow.element.rasaRules", [StepType.SiGa]: "serviceFlow.element.siga", }; - From 6640f25bdcd9607bcbbb27eb0c8cd117430b8551 Mon Sep 17 00:00:00 2001 From: 1AhmedYasser <26207361+1AhmedYasser@users.noreply.github.com> Date: Tue, 5 Aug 2025 10:43:21 +0300 Subject: [PATCH 64/64] chore(658): Added Environments to previous variables --- .../services/POST/services/create-endpoint.yml | 2 +- .../services/POST/services/update-endpoint.yml | 2 +- .../FlowElementsPopup/PreviousVariables.tsx | 11 ++++++++++- GUI/src/i18n/en/common.json | 3 +++ GUI/src/i18n/et/common.json | 3 +++ GUI/src/resources/variables-constants.ts | 15 +++++++++++++-- 6 files changed, 31 insertions(+), 5 deletions(-) diff --git a/DSL/Ruuter/services/POST/services/create-endpoint.yml b/DSL/Ruuter/services/POST/services/create-endpoint.yml index 7917956ae..2c73fd454 100644 --- a/DSL/Ruuter/services/POST/services/create-endpoint.yml +++ b/DSL/Ruuter/services/POST/services/create-endpoint.yml @@ -24,7 +24,7 @@ declaration: type: string description: "Service UUID" - field: definitions - type: json + type: object description: "Endpoint definitions" create_endpoint: diff --git a/DSL/Ruuter/services/POST/services/update-endpoint.yml b/DSL/Ruuter/services/POST/services/update-endpoint.yml index 5b2304a3e..9228079d1 100644 --- a/DSL/Ruuter/services/POST/services/update-endpoint.yml +++ b/DSL/Ruuter/services/POST/services/update-endpoint.yml @@ -21,7 +21,7 @@ declaration: type: string description: "Service UUID" - field: definitions - type: json + type: object description: "Endpoint definitions" params: - field: id diff --git a/GUI/src/components/FlowElementsPopup/PreviousVariables.tsx b/GUI/src/components/FlowElementsPopup/PreviousVariables.tsx index 19224a31a..d84494be0 100644 --- a/GUI/src/components/FlowElementsPopup/PreviousVariables.tsx +++ b/GUI/src/components/FlowElementsPopup/PreviousVariables.tsx @@ -12,7 +12,7 @@ import { getTypeColor, isObject } from "utils/object-util"; import Tooltip from "../Tooltip"; import { v4 } from "uuid"; import { getHelperTooltips } from "utils/constants"; -import { datesVariables, helperVariables } from "resources/variables-constants"; +import { datesVariables, environmentVariables, helperVariables } from "resources/variables-constants"; import { Node, Edge } from "@xyflow/react"; import { NodeDataProps } from "types/service-flow"; @@ -131,6 +131,15 @@ const PreviousVariables: FC = ({ nodeId }) => { /> )} + + ", + "environmentVariables": { + "title": "Environment Variables" + }, "helpers": { "title": "Tools", "map": "Change items", diff --git a/GUI/src/i18n/et/common.json b/GUI/src/i18n/et/common.json index 16fd266e3..9cb42a402 100644 --- a/GUI/src/i18n/et/common.json +++ b/GUI/src/i18n/et/common.json @@ -331,6 +331,9 @@ "previousVariables": { "assignElements": "Määra elemendid", "noName": "", + "environmentVariables": { + "title": "Keskkonnamuutujad" + }, "dates": { "title": "Kuupäevad", "currentDate": "Praegune kuupäev", diff --git a/GUI/src/resources/variables-constants.ts b/GUI/src/resources/variables-constants.ts index 8de7b4314..b7cde650a 100644 --- a/GUI/src/resources/variables-constants.ts +++ b/GUI/src/resources/variables-constants.ts @@ -3,10 +3,16 @@ import { DATE_CONSTANTS, HELPERS_CONSTANTS } from "utils/constants"; import { stringToTemplate } from "utils/string-util"; import { v4 } from "uuid"; -const createTemplate = (id: string, key: string, value: string, tooltip: string | undefined = undefined): Assign => ({ +const createTemplate = ( + id: string, + key: string, + value: string, + tooltip: string | undefined = undefined, + valueFormat: "plain" | "formatted" = "formatted" +): Assign => ({ id, key, - value: stringToTemplate(value), + value: valueFormat === 'formatted' ? stringToTemplate(value) : value, tooltip, }); @@ -37,3 +43,8 @@ export const helperVariables: Assign[] = [ createTemplate(v4(), `${helpersTrPath}.reduce`, HELPERS_CONSTANTS.REDUCE), createTemplate(v4(), `${helpersTrPath}.mapAndJoin`, HELPERS_CONSTANTS.MAP_AND_JOIN), ]; + +export const environmentVariables: Assign[] = [ + createTemplate(v4(), "XTR", "[#XTR]", undefined, 'plain'), + createTemplate(v4(), "Open Search", "[#OPENSEARCH]", undefined, 'plain'), +];