From 61ce974f7611608a253e14535212857d57610fd4 Mon Sep 17 00:00:00 2001 From: Ankita Kinger Date: Wed, 5 Mar 2025 20:00:50 +0530 Subject: [PATCH 1/3] refactoring to take out the common code so it can be reused for other IDEs --- .../utils/groupAndSortEntitySegmentList.ts | 12 +-- .../hooks/useBlockExecution.ts | 2 +- app/client/src/sagas/IDESaga.tsx | 79 ++----------------- .../sagas/getNextEntityAfterRemove.test.ts | 2 +- app/client/src/sagas/helper.ts | 74 +++++++++++++++++ 5 files changed, 88 insertions(+), 81 deletions(-) diff --git a/app/client/src/IDE/utils/groupAndSortEntitySegmentList.ts b/app/client/src/IDE/utils/groupAndSortEntitySegmentList.ts index 0c661cc82f25..9fa3cb40d5dc 100644 --- a/app/client/src/IDE/utils/groupAndSortEntitySegmentList.ts +++ b/app/client/src/IDE/utils/groupAndSortEntitySegmentList.ts @@ -1,14 +1,14 @@ -import { groupBy, sortBy } from "lodash"; import type { EntityItem } from "ee/IDE/Interfaces/EntityItem"; +import { groupBy, sortBy } from "lodash"; -export type EditorSegmentList = Array<{ +export type EditorSegmentList = Array<{ group: string | "NA"; - items: EntityItem[]; + items: T[]; }>; -export const groupAndSortEntitySegmentList = ( - items: EntityItem[], -): EditorSegmentList => { +export const groupAndSortEntitySegmentList = ( + items: T[], +): EditorSegmentList => { const groups = groupBy(items, (item) => { if (item.group) return item.group; diff --git a/app/client/src/ce/PluginActionEditor/hooks/useBlockExecution.ts b/app/client/src/ce/PluginActionEditor/hooks/useBlockExecution.ts index e1ee5994c5f6..08cc042793cd 100644 --- a/app/client/src/ce/PluginActionEditor/hooks/useBlockExecution.ts +++ b/app/client/src/ce/PluginActionEditor/hooks/useBlockExecution.ts @@ -21,7 +21,7 @@ const useBlockExecution = () => { // this gets the url of the current action's datasource const actionDatasourceUrl = action.datasource.datasourceConfiguration?.url || ""; - const actionDatasourceUrlPath = action.actionConfiguration.path || ""; + const actionDatasourceUrlPath = action.actionConfiguration?.path || ""; // this gets the name of the current action's datasource const actionDatasourceName = action.datasource.name || ""; diff --git a/app/client/src/sagas/IDESaga.tsx b/app/client/src/sagas/IDESaga.tsx index 0f312ad3c977..af022e49db2d 100644 --- a/app/client/src/sagas/IDESaga.tsx +++ b/app/client/src/sagas/IDESaga.tsx @@ -1,5 +1,5 @@ import type { FocusEntityInfo } from "navigation/FocusEntity"; -import { FocusEntity, identifyEntityFromPath } from "navigation/FocusEntity"; +import { FocusEntity } from "navigation/FocusEntity"; import { all, call, put, select, takeEvery } from "redux-saga/effects"; import { getJSTabs, getQueryTabs } from "selectors/ideSelectors"; import { @@ -27,6 +27,11 @@ import { selectQuerySegmentEditorTabs, } from "ee/selectors/appIDESelectors"; import { getCurrentBasePageId } from "selectors/editorSelectors"; +import { + getNextEntityAfterRemove, + getUpdatedTabs, + RedirectAction, +} from "./helper"; export function* updateIDETabsOnRouteChangeSaga(entityInfo: FocusEntityInfo) { const { entity, id, params } = entityInfo; @@ -54,14 +59,6 @@ export function* updateIDETabsOnRouteChangeSaga(entityInfo: FocusEntityInfo) { } } -function* getUpdatedTabs(newId: string, currentTabs: string[]) { - if (currentTabs.includes(newId)) return currentTabs; - - const newTabs = [...currentTabs, newId]; - - return newTabs; -} - export function* handleJSEntityRedirect(deletedId: string) { const basePageId: string = yield select(getCurrentBasePageId); const jsTabs: EntityItem[] = yield select(selectJSSegmentEditorTabs); @@ -108,70 +105,6 @@ export function* handleQueryEntityRedirect(deletedId: string) { } } -/** - * Adds custom redirect logic to redirect after an item is deleted - * 1. Do not navigate if the deleted item is not selected - * 2. If it was the only item, navigate to the list url, to show the blank state - * 3. If there are other items, navigate to an item close to the current one - * **/ - -export enum RedirectAction { - NA = "NA", // No action is needed - LIST = "LIST", // Navigate to a creation URL - ITEM = "ITEM", // Navigate to this item -} - -interface RedirectActionDescription { - action: RedirectAction; - payload?: EntityItem; -} - -export function getNextEntityAfterRemove( - removedId: string, - tabs: EntityItem[], -): RedirectActionDescription { - const currentSelectedEntity = identifyEntityFromPath( - window.location.pathname, - ); - const isSelectedActionRemoved = currentSelectedEntity.id === removedId; - - // If removed item is not currently selected, don't redirect - if (!isSelectedActionRemoved) { - return { - action: RedirectAction.NA, - }; - } - - const indexOfTab = tabs.findIndex((item) => item.key === removedId); - - switch (indexOfTab) { - case -1: - // If no other action is remaining, navigate to the creation url - return { - action: RedirectAction.LIST, - }; - case 0: - // if the removed item is first item, then if tabs present, tabs + 1 - // else otherItems[0] -> TODO: consider changing this logic after discussion with - // design team. May be new listing UI for side by side - if (tabs.length > 1) { - return { - action: RedirectAction.ITEM, - payload: tabs[1], - }; - } else { - return { - action: RedirectAction.LIST, - }; - } - default: - return { - action: RedirectAction.ITEM, - payload: tabs[indexOfTab - 1], - }; - } -} - function* storeIDEViewChangeSaga( action: ReduxAction<{ view: EditorViewMode }>, ) { diff --git a/app/client/src/sagas/getNextEntityAfterRemove.test.ts b/app/client/src/sagas/getNextEntityAfterRemove.test.ts index 77ad93bfd417..8ef76c61e2f1 100644 --- a/app/client/src/sagas/getNextEntityAfterRemove.test.ts +++ b/app/client/src/sagas/getNextEntityAfterRemove.test.ts @@ -1,7 +1,7 @@ import { EditorState } from "IDE/enums"; import { PluginType } from "entities/Plugin"; import * as FocusEntityObj from "navigation/FocusEntity"; -import { RedirectAction, getNextEntityAfterRemove } from "./IDESaga"; +import { RedirectAction, getNextEntityAfterRemove } from "./helper"; import { FocusEntity } from "navigation/FocusEntity"; import type { EntityItem } from "ee/IDE/Interfaces/EntityItem"; diff --git a/app/client/src/sagas/helper.ts b/app/client/src/sagas/helper.ts index 7839552f9daf..a9597e46aaab 100644 --- a/app/client/src/sagas/helper.ts +++ b/app/client/src/sagas/helper.ts @@ -37,6 +37,8 @@ import { } from "../constants/Datasource"; import { type Datasource, ToastMessageType } from "../entities/Datasource"; import { getNextEntityName } from "utils/AppsmithUtils"; +import type { EntityItem } from "ee/IDE/Interfaces/EntityItem"; +import { identifyEntityFromPath } from "navigation/FocusEntity"; // function to extract all objects that have dynamic values export const extractFetchDynamicValueFormConfigs = ( @@ -324,3 +326,75 @@ export function* getInitialActionPayload( actionConfiguration: actionConfig.actionConfiguration, }; } + +export function* getUpdatedTabs(newId: string, currentTabs: string[]) { + if (currentTabs.includes(newId)) return currentTabs; + + const newTabs = [...currentTabs, newId]; + + return newTabs; +} + +/** + * Adds custom redirect logic to redirect after an item is deleted + * 1. Do not navigate if the deleted item is not selected + * 2. If it was the only item, navigate to the list url, to show the blank state + * 3. If there are other items, navigate to an item close to the current one + * **/ + +export enum RedirectAction { + NA = "NA", // No action is needed + LIST = "LIST", // Navigate to a creation URL + ITEM = "ITEM", // Navigate to this item +} + +interface RedirectActionDescription { + action: RedirectAction; + payload?: T; +} + +export function getNextEntityAfterRemove( + removedId: string, + tabs: T[], +): RedirectActionDescription { + const currentSelectedEntity = identifyEntityFromPath( + window.location.pathname, + ); + const isSelectedActionRemoved = currentSelectedEntity.id === removedId; + + // If removed item is not currently selected, don't redirect + if (!isSelectedActionRemoved) { + return { + action: RedirectAction.NA, + }; + } + + const indexOfTab = tabs.findIndex((item) => item.key === removedId); + + switch (indexOfTab) { + case -1: + // If no other action is remaining, navigate to the creation url + return { + action: RedirectAction.LIST, + }; + case 0: + // if the removed item is first item, then if tabs present, tabs + 1 + // else otherItems[0] -> TODO: consider changing this logic after discussion with + // design team. May be new listing UI for side by side + if (tabs.length > 1) { + return { + action: RedirectAction.ITEM, + payload: tabs[1], + }; + } else { + return { + action: RedirectAction.LIST, + }; + } + default: + return { + action: RedirectAction.ITEM, + payload: tabs[indexOfTab - 1], + }; + } +} From 0168713ed7eaac121a89423c095370b6b28fa602 Mon Sep 17 00:00:00 2001 From: Ankita Kinger Date: Thu, 6 Mar 2025 11:17:19 +0530 Subject: [PATCH 2/3] addressing review comments --- .../src/IDE/utils/getNextEntityAfterRemove.ts | 66 +++++++++++++++++ app/client/src/IDE/utils/getUpdatedTabs.ts | 7 ++ app/client/src/sagas/helper.ts | 74 ------------------- 3 files changed, 73 insertions(+), 74 deletions(-) create mode 100644 app/client/src/IDE/utils/getNextEntityAfterRemove.ts create mode 100644 app/client/src/IDE/utils/getUpdatedTabs.ts diff --git a/app/client/src/IDE/utils/getNextEntityAfterRemove.ts b/app/client/src/IDE/utils/getNextEntityAfterRemove.ts new file mode 100644 index 000000000000..2843b7d0ff11 --- /dev/null +++ b/app/client/src/IDE/utils/getNextEntityAfterRemove.ts @@ -0,0 +1,66 @@ +import type { EntityItem } from "ee/IDE/Interfaces/EntityItem"; +import { identifyEntityFromPath } from "navigation/FocusEntity"; + +/** + * Adds custom redirect logic to redirect after an item is deleted + * 1. Do not navigate if the deleted item is not selected + * 2. If it was the only item, navigate to the list url, to show the blank state + * 3. If there are other items, navigate to an item close to the current one + * **/ + +export enum RedirectAction { + NA = "NA", // No action is needed + LIST = "LIST", // Navigate to a creation URL + ITEM = "ITEM", // Navigate to this item +} + +interface RedirectActionDescription { + action: RedirectAction; + payload?: T; +} + +export function getNextEntityAfterRemove( + removedId: string, + tabs: T[], +): RedirectActionDescription { + const currentSelectedEntity = identifyEntityFromPath( + window.location.pathname, + ); + const isSelectedActionRemoved = currentSelectedEntity.id === removedId; + + // If removed item is not currently selected, don't redirect + if (!isSelectedActionRemoved) { + return { + action: RedirectAction.NA, + }; + } + + const indexOfTab = tabs.findIndex((item) => item.key === removedId); + + switch (indexOfTab) { + case -1: + // If no other action is remaining, navigate to the creation url + return { + action: RedirectAction.LIST, + }; + case 0: + // if the removed item is first item, then if tabs present, tabs + 1 + // else otherItems[0] -> TODO: consider changing this logic after discussion with + // design team. May be new listing UI for side by side + if (tabs.length > 1) { + return { + action: RedirectAction.ITEM, + payload: tabs[1], + }; + } else { + return { + action: RedirectAction.LIST, + }; + } + default: + return { + action: RedirectAction.ITEM, + payload: tabs[indexOfTab - 1], + }; + } +} diff --git a/app/client/src/IDE/utils/getUpdatedTabs.ts b/app/client/src/IDE/utils/getUpdatedTabs.ts new file mode 100644 index 000000000000..e2f201ec2145 --- /dev/null +++ b/app/client/src/IDE/utils/getUpdatedTabs.ts @@ -0,0 +1,7 @@ +export function getUpdatedTabs(newId: string, currentTabs: string[]) { + if (currentTabs.includes(newId)) return currentTabs; + + const newTabs = [...currentTabs, newId]; + + return newTabs; +} diff --git a/app/client/src/sagas/helper.ts b/app/client/src/sagas/helper.ts index a9597e46aaab..7839552f9daf 100644 --- a/app/client/src/sagas/helper.ts +++ b/app/client/src/sagas/helper.ts @@ -37,8 +37,6 @@ import { } from "../constants/Datasource"; import { type Datasource, ToastMessageType } from "../entities/Datasource"; import { getNextEntityName } from "utils/AppsmithUtils"; -import type { EntityItem } from "ee/IDE/Interfaces/EntityItem"; -import { identifyEntityFromPath } from "navigation/FocusEntity"; // function to extract all objects that have dynamic values export const extractFetchDynamicValueFormConfigs = ( @@ -326,75 +324,3 @@ export function* getInitialActionPayload( actionConfiguration: actionConfig.actionConfiguration, }; } - -export function* getUpdatedTabs(newId: string, currentTabs: string[]) { - if (currentTabs.includes(newId)) return currentTabs; - - const newTabs = [...currentTabs, newId]; - - return newTabs; -} - -/** - * Adds custom redirect logic to redirect after an item is deleted - * 1. Do not navigate if the deleted item is not selected - * 2. If it was the only item, navigate to the list url, to show the blank state - * 3. If there are other items, navigate to an item close to the current one - * **/ - -export enum RedirectAction { - NA = "NA", // No action is needed - LIST = "LIST", // Navigate to a creation URL - ITEM = "ITEM", // Navigate to this item -} - -interface RedirectActionDescription { - action: RedirectAction; - payload?: T; -} - -export function getNextEntityAfterRemove( - removedId: string, - tabs: T[], -): RedirectActionDescription { - const currentSelectedEntity = identifyEntityFromPath( - window.location.pathname, - ); - const isSelectedActionRemoved = currentSelectedEntity.id === removedId; - - // If removed item is not currently selected, don't redirect - if (!isSelectedActionRemoved) { - return { - action: RedirectAction.NA, - }; - } - - const indexOfTab = tabs.findIndex((item) => item.key === removedId); - - switch (indexOfTab) { - case -1: - // If no other action is remaining, navigate to the creation url - return { - action: RedirectAction.LIST, - }; - case 0: - // if the removed item is first item, then if tabs present, tabs + 1 - // else otherItems[0] -> TODO: consider changing this logic after discussion with - // design team. May be new listing UI for side by side - if (tabs.length > 1) { - return { - action: RedirectAction.ITEM, - payload: tabs[1], - }; - } else { - return { - action: RedirectAction.LIST, - }; - } - default: - return { - action: RedirectAction.ITEM, - payload: tabs[indexOfTab - 1], - }; - } -} From caef1fa00055f52d688f90bf39705c8583459a5d Mon Sep 17 00:00:00 2001 From: Ankita Kinger Date: Thu, 6 Mar 2025 11:41:04 +0530 Subject: [PATCH 3/3] fixing build --- .../{sagas => IDE/utils}/getNextEntityAfterRemove.test.ts | 5 ++++- app/client/src/sagas/IDESaga.tsx | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) rename app/client/src/{sagas => IDE/utils}/getNextEntityAfterRemove.test.ts (94%) diff --git a/app/client/src/sagas/getNextEntityAfterRemove.test.ts b/app/client/src/IDE/utils/getNextEntityAfterRemove.test.ts similarity index 94% rename from app/client/src/sagas/getNextEntityAfterRemove.test.ts rename to app/client/src/IDE/utils/getNextEntityAfterRemove.test.ts index 8ef76c61e2f1..ec9120b5ff09 100644 --- a/app/client/src/sagas/getNextEntityAfterRemove.test.ts +++ b/app/client/src/IDE/utils/getNextEntityAfterRemove.test.ts @@ -1,7 +1,10 @@ import { EditorState } from "IDE/enums"; import { PluginType } from "entities/Plugin"; import * as FocusEntityObj from "navigation/FocusEntity"; -import { RedirectAction, getNextEntityAfterRemove } from "./helper"; +import { + RedirectAction, + getNextEntityAfterRemove, +} from "./getNextEntityAfterRemove"; import { FocusEntity } from "navigation/FocusEntity"; import type { EntityItem } from "ee/IDE/Interfaces/EntityItem"; diff --git a/app/client/src/sagas/IDESaga.tsx b/app/client/src/sagas/IDESaga.tsx index af022e49db2d..42cf5866b480 100644 --- a/app/client/src/sagas/IDESaga.tsx +++ b/app/client/src/sagas/IDESaga.tsx @@ -29,9 +29,9 @@ import { import { getCurrentBasePageId } from "selectors/editorSelectors"; import { getNextEntityAfterRemove, - getUpdatedTabs, RedirectAction, -} from "./helper"; +} from "IDE/utils/getNextEntityAfterRemove"; +import { getUpdatedTabs } from "IDE/utils/getUpdatedTabs"; export function* updateIDETabsOnRouteChangeSaga(entityInfo: FocusEntityInfo) { const { entity, id, params } = entityInfo;