From b946feba05aa21fd311c8d7f9302ec0ba01bdb62 Mon Sep 17 00:00:00 2001 From: Arpit Date: Mon, 16 Oct 2023 10:48:03 +0530 Subject: [PATCH 01/18] [appdef] fixes: Creating page not changing the slug (#7873) * fixes: Creating page not changing the slug * removes extra whitespace --- frontend/src/Editor/EditorFunc.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/Editor/EditorFunc.jsx b/frontend/src/Editor/EditorFunc.jsx index e5b7713060..b439d0dd67 100644 --- a/frontend/src/Editor/EditorFunc.jsx +++ b/frontend/src/Editor/EditorFunc.jsx @@ -1270,6 +1270,7 @@ const EditorComponent = (props) => { switchPage: true, pageId: newPageId, }); + props?.navigate(`/${getWorkspaceId()}/apps/${appId}/${newHandle}`); }; const switchPage = (pageId, queryParams = []) => { From da599e135b9e5ab2ecde4df70568ea2fe33192f9 Mon Sep 17 00:00:00 2001 From: Arpit Date: Mon, 16 Oct 2023 12:53:42 +0530 Subject: [PATCH 02/18] [appdef] fixes: on importing a exported app child components are not present in the parent component (#7864) * fixes: on importing a exported app child components are not present in the parent component * handles parent component mapping for tabs and calendar component * handles parent component mapping for tabs and calendar component for new versions --- .../src/services/app_import_export.service.ts | 30 ++++++++++++++++++- server/src/services/apps.service.ts | 30 ++++++++++++++++++- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/server/src/services/app_import_export.service.ts b/server/src/services/app_import_export.service.ts index d9decca543..9a84c2f1e3 100644 --- a/server/src/services/app_import_export.service.ts +++ b/server/src/services/app_import_export.service.ts @@ -576,6 +576,20 @@ export class AppImportExportService { appResourceMappings.dataQueryMapping = dataQueryMapping; } + const isChildOfTabsOrCalendar = (component, allComponents = [], componentParentId = undefined) => { + if (componentParentId) { + const parentId = component?.parent?.split('-').slice(0, -1).join('-'); + + const parentComponent = allComponents.find((comp) => comp.id === parentId); + + if (parentComponent) { + return parentComponent.type === 'Tabs' || parentComponent.type === 'Calendar'; + } + } + + return false; + }; + for (const page of importingPages) { const newPage = manager.create(Page, { name: page.name, @@ -599,12 +613,26 @@ export class AppImportExportService { for (const component of pageComponents) { const newComponent = new Component(); + let parentId = component.parent ? component.parent : null; + + const isParentTabOrCalendar = isChildOfTabsOrCalendar(component, pageComponents, parentId); + + if (isParentTabOrCalendar) { + const childTabId = component.parent.split('-')[component.parent.split('-').length - 1]; + const _parentId = component?.parent?.split('-').slice(0, -1).join('-'); + const mappedParentId = appResourceMappings.componentsMapping[_parentId]; + + parentId = `${mappedParentId}-${childTabId}`; + } else { + parentId = appResourceMappings.componentsMapping[parentId]; + } + newComponent.name = component.name; newComponent.type = component.type; newComponent.properties = component.properties; newComponent.styles = component.styles; newComponent.validation = component.validation; - newComponent.parent = component.parent || null; + newComponent.parent = component.parent ? parentId : null; newComponent.page = pageCreated; diff --git a/server/src/services/apps.service.ts b/server/src/services/apps.service.ts index bca36716e4..a784127a96 100644 --- a/server/src/services/apps.service.ts +++ b/server/src/services/apps.service.ts @@ -459,6 +459,20 @@ export class AppsService { const oldComponentToNewComponentMapping = {}; const oldPageToNewPageMapping = {}; + const isChildOfTabsOrCalendar = (component, allComponents = [], componentParentId = undefined) => { + if (componentParentId) { + const parentId = component?.parent?.split('-').slice(0, -1).join('-'); + + const parentComponent = allComponents.find((comp) => comp.id === parentId); + + if (parentComponent) { + return parentComponent.type === 'Tabs' || parentComponent.type === 'Calendar'; + } + } + + return false; + }; + for (const page of pages) { const savedPage = await manager.save( manager.create(Page, { @@ -497,13 +511,27 @@ export class AppsService { oldComponentToNewComponentMapping[component.id] = newComponent.id; + let parentId = component.parent ? component.parent : null; + + const isParentTabOrCalendar = isChildOfTabsOrCalendar(component, page.components, parentId); + + if (isParentTabOrCalendar) { + const childTabId = component.parent.split('-')[component.parent.split('-').length - 1]; + const _parentId = component?.parent?.split('-').slice(0, -1).join('-'); + const mappedParentId = oldComponentToNewComponentMapping[_parentId]; + + parentId = `${mappedParentId}-${childTabId}`; + } else { + parentId = oldComponentToNewComponentMapping[parentId]; + } + newComponent.name = component.name; newComponent.type = component.type; newComponent.pageId = savedPage.id; newComponent.properties = component.properties; newComponent.styles = component.styles; newComponent.validation = component.validation; - newComponent.parent = component.parent ? oldComponentToNewComponentMapping[component.parent] : null; + newComponent.parent = component.parent ? parentId : null; newComponent.page = savedPage; newComponents.push(newComponent); From a000a7fdd9eea63c65f9a5436bf5b8ef737bc33a Mon Sep 17 00:00:00 2001 From: Arpit Date: Mon, 16 Oct 2023 13:13:13 +0530 Subject: [PATCH 03/18] [appdef] api endpoint fixes (#7888) * fixes: moved fetching app version to v2 api * fixes: app slug api --- frontend/src/Editor/AppVersionsManager/CreateVersionModal.jsx | 2 +- server/src/controllers/apps.controller.v2.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/Editor/AppVersionsManager/CreateVersionModal.jsx b/frontend/src/Editor/AppVersionsManager/CreateVersionModal.jsx index 3ac7048900..2801f278b0 100644 --- a/frontend/src/Editor/AppVersionsManager/CreateVersionModal.jsx +++ b/frontend/src/Editor/AppVersionsManager/CreateVersionModal.jsx @@ -58,7 +58,7 @@ export const CreateVersion = ({ }); appVersionService - .getOne(appId, data.id) + .getAppVersionData(appId, data.id) .then((data) => { setAppDefinitionFromVersion(data); }) diff --git a/server/src/controllers/apps.controller.v2.ts b/server/src/controllers/apps.controller.v2.ts index 7c972581ef..aa3b791466 100644 --- a/server/src/controllers/apps.controller.v2.ts +++ b/server/src/controllers/apps.controller.v2.ts @@ -13,6 +13,7 @@ import { UseInterceptors, } from '@nestjs/common'; import { JwtAuthGuard } from '../../src/modules/auth/jwt-auth.guard'; +import { AppAuthGuard } from 'src/modules/auth/app-auth.guard'; import { AppsService } from '../services/apps.service'; import { camelizeKeys, decamelizeKeys } from 'humps'; import { AppsAbilityFactory } from 'src/modules/casl/abilities/apps-ability.factory'; @@ -101,6 +102,8 @@ export class AppsControllerV2 { return response; } + @UseGuards(AppAuthGuard) // This guard will allow access for unauthenticated user if the app is public + @Get('slugs/:slug') async appFromSlug(@User() user, @AppDecorator() app: App) { if (user) { const ability = await this.appsAbilityFactory.appsActions(user, app.id); From f94b49e180bc115f1a441d45d582eb369d979d02 Mon Sep 17 00:00:00 2001 From: Nakul Nagargade <133095394+nakulnagargade@users.noreply.github.com> Date: Mon, 16 Oct 2023 15:36:18 +0530 Subject: [PATCH 04/18] Fixes CurrentUser & Mode not present in globals in inspector (#7812) * Fix current user not being present in inspector * Add Mode in globas in inspector * Fix creating page not changing the slug. * Revert "Fix creating page not changing the slug." This reverts commit 0ff9c18ab8b622a0fa96f6d7b200898c19b060f4. --- frontend/src/Editor/EditorFunc.jsx | 16 ++--- frontend/src/_stores/editorStore.js | 93 ++++++++++++++--------------- 2 files changed, 52 insertions(+), 57 deletions(-) diff --git a/frontend/src/Editor/EditorFunc.jsx b/frontend/src/Editor/EditorFunc.jsx index b439d0dd67..89931834f3 100644 --- a/frontend/src/Editor/EditorFunc.jsx +++ b/frontend/src/Editor/EditorFunc.jsx @@ -179,11 +179,16 @@ const EditorComponent = (props) => { updateState({ currentUser: appUserDetails, }); - useCurrentStateStore.getState().actions.setCurrentState({ globals: { ...currentState.globals, + theme: { name: props?.darkMode ? 'dark' : 'light' }, + urlparams: JSON.parse(JSON.stringify(queryString.parse(props.location.search))), currentUser: userVars, + /* Constant value.it will only change for viewer */ + mode: { + value: 'edit', + }, }, }); } @@ -380,16 +385,7 @@ const EditorComponent = (props) => { threshold: 0, }, }); - - const globals = { - ...currentState.globals, - theme: { name: props?.darkMode ? 'dark' : 'light' }, - urlparams: JSON.parse(JSON.stringify(queryString.parse(props.location.search))), - }; - updateState({ appId: props?.params?.id }); - useCurrentStateStore.getState().actions.setCurrentState({ globals }); - getCanvasWidth(); initEditorWalkThrough(); }; diff --git a/frontend/src/_stores/editorStore.js b/frontend/src/_stores/editorStore.js index 27c2c898d1..82d86fbe36 100644 --- a/frontend/src/_stores/editorStore.js +++ b/frontend/src/_stores/editorStore.js @@ -41,54 +41,53 @@ const initialState = { }; export const useEditorStore = create( - zustandDevTools( - (set, get) => ({ - ...initialState, - actions: { - setShowComments: (showComments) => - set({ showComments }, false, { - type: ACTIONS.SET_HOVERED_COMPONENT, - showComments, - }), - toggleComments: () => - set({ showComments: !get().showComments }, false, { - type: ACTIONS.TOGGLE_COMMENTS, - }), - toggleCurrentLayout: (currentLayout) => - set({ currentLayout }, false, { - type: ACTIONS.TOGGLE_CURRENT_LAYOUT, - currentLayout, - }), - setIsEditorActive: (isEditorActive) => set(() => ({ isEditorActive })), - updateEditorState: (state) => set((prev) => ({ ...prev, ...state })), - updateQueryConfirmationList: (queryConfirmationList) => set({ queryConfirmationList }), - setHoveredComponent: (hoveredComponent) => - set({ hoveredComponent }, false, { - type: ACTIONS.SET_HOVERED_COMPONENT, - hoveredComponent, - }), - setSelectionInProgress: (isSelectionInProgress) => { - set( - { - isSelectionInProgress, - }, - false, - { type: ACTIONS.SET_SELECTION_IN_PROGRESS } - ); - }, - setSelectedComponents: (selectedComponents, isMulti = false) => { - const newSelectedComponents = isMulti - ? [...get().selectedComponents, ...selectedComponents] - : selectedComponents; - - set({ - selectedComponents: newSelectedComponents, - }); - }, + // Dev tools for this store are disabled comments since its freezing chrome tab + (set, get) => ({ + ...initialState, + actions: { + setShowComments: (showComments) => + set({ showComments }, false, { + type: ACTIONS.SET_HOVERED_COMPONENT, + showComments, + }), + toggleComments: () => + set({ showComments: !get().showComments }, false, { + type: ACTIONS.TOGGLE_COMMENTS, + }), + toggleCurrentLayout: (currentLayout) => + set({ currentLayout }, false, { + type: ACTIONS.TOGGLE_CURRENT_LAYOUT, + currentLayout, + }), + setIsEditorActive: (isEditorActive) => set(() => ({ isEditorActive })), + updateEditorState: (state) => set((prev) => ({ ...prev, ...state })), + updateQueryConfirmationList: (queryConfirmationList) => set({ queryConfirmationList }), + setHoveredComponent: (hoveredComponent) => + set({ hoveredComponent }, false, { + type: ACTIONS.SET_HOVERED_COMPONENT, + hoveredComponent, + }), + setSelectionInProgress: (isSelectionInProgress) => { + set( + { + isSelectionInProgress, + }, + false, + { type: ACTIONS.SET_SELECTION_IN_PROGRESS } + ); }, - }), - { name: STORE_NAME } - ) + setSelectedComponents: (selectedComponents, isMulti = false) => { + const newSelectedComponents = isMulti + ? [...get().selectedComponents, ...selectedComponents] + : selectedComponents; + + set({ + selectedComponents: newSelectedComponents, + }); + }, + }, + }), + { name: STORE_NAME } ); export const useEditorActions = () => useEditorStore((state) => state.actions); From af24f6ef56888b1f0faee368054dd44c8ee9f5ae Mon Sep 17 00:00:00 2001 From: Nakul Nagargade <133095394+nakulnagargade@users.noreply.github.com> Date: Mon, 16 Oct 2023 15:37:51 +0530 Subject: [PATCH 05/18] Fixes on adding query params in event handler, breaking the app (#7889) * Fix on version change if left sidebar is open canvas not scrolling right * Fix on adding query params in event handler, breaking the app * Fix --- frontend/src/Editor/EditorFunc.jsx | 2 +- .../Editor/Inspector/ActionConfigurationPanels/GotoApp.jsx | 6 ++++-- .../Inspector/ActionConfigurationPanels/SwitchPage.jsx | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/frontend/src/Editor/EditorFunc.jsx b/frontend/src/Editor/EditorFunc.jsx index 89931834f3..bc9909cffc 100644 --- a/frontend/src/Editor/EditorFunc.jsx +++ b/frontend/src/Editor/EditorFunc.jsx @@ -256,7 +256,7 @@ const EditorComponent = (props) => { canvasContainerRef.current.scrollLeft += editorMarginLeft; } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [editorMarginLeft]); + }, [editorMarginLeft, canvasContainerRef?.current]); useEffect(() => { if (mounted) { diff --git a/frontend/src/Editor/Inspector/ActionConfigurationPanels/GotoApp.jsx b/frontend/src/Editor/Inspector/ActionConfigurationPanels/GotoApp.jsx index d42ebee133..3c8636d647 100644 --- a/frontend/src/Editor/Inspector/ActionConfigurationPanels/GotoApp.jsx +++ b/frontend/src/Editor/Inspector/ActionConfigurationPanels/GotoApp.jsx @@ -6,8 +6,10 @@ import { useTranslation } from 'react-i18next'; export function GotoApp({ getAllApps, event, handlerChanged, eventIndex, darkMode }) { const queryParamChangeHandler = (index, key, value) => { - event.queryParams[index][key] = value; - handlerChanged(eventIndex, 'queryParams', event.queryParams); + if (event?.queryParams?.[index]?.[key]) { + event.queryParams[index][key] = value; + handlerChanged(eventIndex, 'queryParams', event.queryParams); + } }; const { t } = useTranslation(); diff --git a/frontend/src/Editor/Inspector/ActionConfigurationPanels/SwitchPage.jsx b/frontend/src/Editor/Inspector/ActionConfigurationPanels/SwitchPage.jsx index cd3dffe52e..dc697c4797 100644 --- a/frontend/src/Editor/Inspector/ActionConfigurationPanels/SwitchPage.jsx +++ b/frontend/src/Editor/Inspector/ActionConfigurationPanels/SwitchPage.jsx @@ -69,7 +69,7 @@ export function SwitchPage({ getPages, event, handlerChanged, eventIndex, darkMo
queryParamChangeHandler(index, 0, value)} mode="javascript" className="form-control codehinter-query-editor-input" @@ -79,7 +79,7 @@ export function SwitchPage({ getPages, event, handlerChanged, eventIndex, darkMo
queryParamChangeHandler(index, 1, value)} mode="javascript" className="form-control codehinter-query-editor-input" From cfdf3294530c37236dfe2416a81ed0f640cdcd8f Mon Sep 17 00:00:00 2001 From: Nakul Nagargade <133095394+nakulnagargade@users.noreply.github.com> Date: Mon, 16 Oct 2023 15:38:09 +0530 Subject: [PATCH 06/18] Fix on version change if left sidebar is open canvas not scrolling right (#7884) From 18363a5bc1c14d5e14bbe5faba7a1a8c29337596 Mon Sep 17 00:00:00 2001 From: Arpit Date: Mon, 16 Oct 2023 15:43:38 +0530 Subject: [PATCH 07/18] fixes: fixes on on app load switch page action via run queires (#7858) * fixes: fixes on on app load switch page action via run queires * Fix * refactor * Fix on load event not appearing on viewer --------- Co-authored-by: Nakul Nagargade --- frontend/src/Editor/Container.jsx | 10 +++--- frontend/src/Editor/EditorFunc.jsx | 39 +++++++++++++++++++----- frontend/src/Editor/Viewer.jsx | 16 +++++----- frontend/src/_stores/dataQueriesStore.js | 4 +-- frontend/src/_stores/editorStore.js | 2 ++ 5 files changed, 49 insertions(+), 22 deletions(-) diff --git a/frontend/src/Editor/Container.jsx b/frontend/src/Editor/Container.jsx index e13fa3a277..19d2eb7bf2 100644 --- a/frontend/src/Editor/Container.jsx +++ b/frontend/src/Editor/Container.jsx @@ -413,17 +413,17 @@ export const Container = ({ const paramUpdated = useCallback( (id, param, value) => { - if (Object.keys(value).length > 0) { + if (boxes.length && Object.keys(value)?.length > 0) { setBoxes((boxes) => update(boxes, { [id]: { $merge: { component: { - ...boxes[id].component, + ...boxes[id]?.component, definition: { - ...boxes[id].component.definition, + ...boxes[id]?.component?.definition, properties: { - ...boxes[id].component.definition.properties, + ...boxes?.[id]?.component?.definition?.properties, [param]: value, }, }, @@ -434,7 +434,7 @@ export const Container = ({ ); } }, - [setBoxes] + [boxes, setBoxes] ); const handleAddThread = async (e) => { diff --git a/frontend/src/Editor/EditorFunc.jsx b/frontend/src/Editor/EditorFunc.jsx index bc9909cffc..116e288131 100644 --- a/frontend/src/Editor/EditorFunc.jsx +++ b/frontend/src/Editor/EditorFunc.jsx @@ -29,6 +29,7 @@ import { removeSelectedComponent, buildAppDefinition, buildComponentMetaDefinition, + runQueries, } from '@/_helpers/appUtils'; import { Confirm } from './Viewer/Confirm'; import { Tooltip as ReactTooltip } from 'react-tooltip'; @@ -55,11 +56,11 @@ import { useDataSourcesStore } from '@/_stores/dataSourcesStore'; import { useDataQueries, useDataQueriesStore } from '@/_stores/dataQueriesStore'; import { useAppVersionStore, useAppVersionActions, useAppVersionState } from '@/_stores/appVersionStore'; import { useQueryPanelStore } from '@/_stores/queryPanelStore'; -import { useCurrentStateStore, useCurrentState } from '@/_stores/currentStateStore'; +import { useCurrentStateStore, useCurrentState, getCurrentState } from '@/_stores/currentStateStore'; import { computeAppDiff, computeComponentPropertyDiff, isParamFromTableColumn, resetAllStores } from '@/_stores/utils'; import { setCookie } from '@/_helpers/cookie'; import { useEditorActions, useEditorState, useEditorStore } from '@/_stores/editorStore'; -import { useAppDataActions, useAppInfo } from '@/_stores/appDataStore'; +import { useAppDataActions, useAppInfo, useAppDataStore } from '@/_stores/appDataStore'; import { useMounted } from '@/_hooks/use-mount'; // eslint-disable-next-line import/no-unresolved import { diff } from 'deep-object-diff'; @@ -81,7 +82,8 @@ const EditorComponent = (props) => { const { updateState, updateAppDefinitionDiff, updateAppVersion, setIsSaving, createAppVersionEventHandlers } = useAppDataActions(); - const { updateEditorState, updateQueryConfirmationList, setSelectedComponents } = useEditorActions(); + const { updateEditorState, updateQueryConfirmationList, setSelectedComponents, setCurrentPageId } = + useEditorActions(); const { setAppVersions } = useAppVersionActions(); const { isVersionReleased, editingVersion, releasedVersionId } = useAppVersionState(); @@ -101,6 +103,7 @@ const EditorComponent = (props) => { showComments, showLeftSidebar, queryConfirmationList, + currentPageId, } = useEditorState(); const dataQueries = useDataQueries(); @@ -121,7 +124,6 @@ const EditorComponent = (props) => { const currentState = useCurrentState(); - const [currentPageId, setCurrentPageId] = useState(null); const [zoomLevel, setZoomLevel] = useState(1); const [isQueryPaneDragging, setIsQueryPaneDragging] = useState(false); const [isQueryPaneExpanded, setIsQueryPaneExpanded] = useState(false); //!check where this is used @@ -275,6 +277,18 @@ const EditorComponent = (props) => { } }; + const getEditorRef = () => { + const editorRef = { + appDefinition: useEditorStore.getState().appDefinition, + queryConfirmationList: useEditorStore.getState().queryConfirmationList, + updateQueryConfirmationList: updateQueryConfirmationList, + navigate: props.navigate, + switchPage: switchPage, + currentPageId: useEditorStore.getState().currentPageId, + }; + return editorRef; + }; + const fetchApps = async (page) => { const { apps } = await appService.getAll(page); @@ -391,7 +405,10 @@ const EditorComponent = (props) => { }; const fetchDataQueries = async (id, selectFirstQuery = false, runQueriesOnAppLoad = false) => { - await useDataQueriesStore.getState().actions.fetchDataQueries(id, selectFirstQuery, runQueriesOnAppLoad); + // // editorRef can be undefined when runQueriesOnAppLoad + await useDataQueriesStore + .getState() + .actions.fetchDataQueries(id, selectFirstQuery, runQueriesOnAppLoad, getEditorRef()); }; const fetchDataSources = (id) => { @@ -528,7 +545,7 @@ const EditorComponent = (props) => { }; const handleEvent = (eventName, event, options) => { - return onEvent(editorRef, eventName, event, options, 'edit'); + return onEvent(getEditorRef(), eventName, event, options, 'edit'); }; const handleRunQuery = (queryId, queryName) => runQuery(editorRef, queryId, queryName); @@ -705,7 +722,7 @@ const EditorComponent = (props) => { await fetchDataQueries(data.editing_version?.id, true, true); const currentPageEvents = data.events.filter((event) => event.target === 'page' && event.sourceId === homePageId); - await handleEvent('onPageLoad', currentPageEvents); + await handleEvent('onPageLoad', currentPageEvents, {}, true); }; const fetchApp = async (startingPageHandle, onMount = false) => { @@ -1270,7 +1287,13 @@ const EditorComponent = (props) => { }; const switchPage = (pageId, queryParams = []) => { - if (currentPageId === pageId && currentState.page.handle === appDefinition?.pages[pageId]?.handle) { + // This are fetched from store to handle runQueriesOnAppLoad + const currentPageId = useEditorStore.getState().currentPageId; + const appDefinition = useEditorStore.getState().appDefinition; + const appId = useAppDataStore.getState()?.appId; + const pageHandle = getCurrentState().pageHandle; + + if (currentPageId === pageId && pageHandle === appDefinition?.pages[pageId]?.handle) { return; } const { name, handle } = appDefinition.pages[pageId]; diff --git a/frontend/src/Editor/Viewer.jsx b/frontend/src/Editor/Viewer.jsx index e87724e976..4583505b90 100644 --- a/frontend/src/Editor/Viewer.jsx +++ b/frontend/src/Editor/Viewer.jsx @@ -226,7 +226,7 @@ class ViewerComponent extends React.Component { runQueries = (data_queries) => { data_queries.forEach((query) => { if (query.options.runOnPageLoad && isQueryRunnable(query)) { - runQuery(this, query.id, query.name, undefined, 'view'); + runQuery(this.getViewerRef(), query.id, query.name, undefined, 'view'); } }); }; @@ -553,17 +553,19 @@ class ViewerComponent extends React.Component { ); }; - handleEvent = (eventName, events, options) => { - const { appDefinition, currentPageId } = this.state; - const viewerRef = { - appDefinition: appDefinition, + getViewerRef() { + return { + appDefinition: this.state.appDefinition, queryConfirmationList: this.props.queryConfirmationList, updateQueryConfirmationList: this.updateQueryConfirmationList, navigate: this.props.navigate, switchPage: this.switchPage, - currentPageId: currentPageId, + currentPageId: this.state.currentPageId, }; - onEvent(viewerRef, eventName, events, options, 'view'); + } + + handleEvent = (eventName, events, options) => { + onEvent(this.getViewerRef(), eventName, events, options, 'view'); }; computeCanvasMaxWidth = () => { diff --git a/frontend/src/_stores/dataQueriesStore.js b/frontend/src/_stores/dataQueriesStore.js index 557e690435..72f4e22c99 100644 --- a/frontend/src/_stores/dataQueriesStore.js +++ b/frontend/src/_stores/dataQueriesStore.js @@ -31,7 +31,7 @@ export const useDataQueriesStore = create( ...initialState, actions: { // TODO: Remove editor state while changing currentState - fetchDataQueries: async (appVersionId, selectFirstQuery = false, runQueriesOnAppLoad = false) => { + fetchDataQueries: async (appVersionId, selectFirstQuery = false, runQueriesOnAppLoad = false, ref) => { set({ loadingDataQueries: true }); const data = await dataqueryService.getAll(appVersionId); set((state) => ({ @@ -62,7 +62,7 @@ export const useDataQueriesStore = create( } // Runs query on loading application - if (runQueriesOnAppLoad) runQueries(data.data_queries, {}); + if (runQueriesOnAppLoad) runQueries(data.data_queries, ref); }, setDataQueries: (dataQueries) => set({ dataQueries }), deleteDataQueries: (queryId) => { diff --git a/frontend/src/_stores/editorStore.js b/frontend/src/_stores/editorStore.js index 82d86fbe36..a42dc2ae88 100644 --- a/frontend/src/_stores/editorStore.js +++ b/frontend/src/_stores/editorStore.js @@ -38,6 +38,7 @@ const initialState = { defaultComponentStateComputed: false, showLeftSidebar: true, queryConfirmationList: [], + currentPageId: null, }; export const useEditorStore = create( @@ -85,6 +86,7 @@ export const useEditorStore = create( selectedComponents: newSelectedComponents, }); }, + setCurrentPageId: (currentPageId) => set({ currentPageId }), }, }), { name: STORE_NAME } From cc48e936ea793a607df29a810f06a0207ec3fef9 Mon Sep 17 00:00:00 2001 From: Arpit Date: Mon, 16 Oct 2023 16:49:42 +0530 Subject: [PATCH 08/18] [appdef] fixes: event actions mapping for import-export (#7895) * fixes: event actions mapping for import-export * fixes: updates organisation id --- frontend/src/Editor/EditorFunc.jsx | 3 +- .../src/Editor/Inspector/EventManager.jsx | 1 - frontend/src/HomePage/ExportAppModal.jsx | 2 +- .../src/services/app_import_export.service.ts | 85 ++++++++++--------- 4 files changed, 48 insertions(+), 43 deletions(-) diff --git a/frontend/src/Editor/EditorFunc.jsx b/frontend/src/Editor/EditorFunc.jsx index 116e288131..3fa48e67ab 100644 --- a/frontend/src/Editor/EditorFunc.jsx +++ b/frontend/src/Editor/EditorFunc.jsx @@ -676,11 +676,12 @@ const EditorComponent = (props) => { const appVersions = await appEnvironmentService.getVersionsByEnvironment(data?.id); setAppVersions(appVersions.appVersions); + const currentOrgId = data?.organization_id || data?.organizationId; updateState({ slug: data.slug, isMaintenanceOn: data?.is_maintenance_on, - organizationId: data?.organization_id, + organizationId: currentOrgId, isPublic: data?.is_public, appName: data?.name, userId: data?.user_id, diff --git a/frontend/src/Editor/Inspector/EventManager.jsx b/frontend/src/Editor/Inspector/EventManager.jsx index 55559b6898..8a4ba36e59 100644 --- a/frontend/src/Editor/Inspector/EventManager.jsx +++ b/frontend/src/Editor/Inspector/EventManager.jsx @@ -909,7 +909,6 @@ export const EventManager = ({
{events.map((event, index) => { const actionMeta = ActionTypes.find((action) => action.id === event.event.actionId); - // const rowClassName = `card-body p-0 ${focusedEventIndex === index ? ' bg-azure-lt' : ''}`; return ( diff --git a/frontend/src/HomePage/ExportAppModal.jsx b/frontend/src/HomePage/ExportAppModal.jsx index fa2b74e0fc..a52fdd5eae 100644 --- a/frontend/src/HomePage/ExportAppModal.jsx +++ b/frontend/src/HomePage/ExportAppModal.jsx @@ -54,7 +54,7 @@ export default function ExportAppModal({ title, show, closeModal, customClassNam const requestBody = { ...appOpts, ...(exportTjDb && { tooljet_database: tables }), - organization_id: app.organization_id, + organization_id: app.organization_id ?? app.organizationId, }; appService diff --git a/server/src/services/app_import_export.service.ts b/server/src/services/app_import_export.service.ts index 9a84c2f1e3..db6bb52701 100644 --- a/server/src/services/app_import_export.service.ts +++ b/server/src/services/app_import_export.service.ts @@ -464,6 +464,18 @@ export class AppImportExportService { } } + const appVersionIds = Object.values(appResourceMappings.appVersionMapping); + + for (const appVersionId of appVersionIds) { + await this.updateEventActionsForNewVersionWithNewMappingIds( + manager, + appVersionId, + appResourceMappings.dataQueryMapping, + appResourceMappings.componentsMapping, + appResourceMappings.pagesMapping + ); + } + await this.setEditingVersionAsLatestVersion(manager, appResourceMappings.appVersionMapping, importingAppVersions); return appResourceMappings; @@ -657,14 +669,14 @@ export class AppImportExportService { if (componentEvents.length > 0) { componentEvents.forEach(async (componentEvent) => { - const newEvent = { - name: componentEvent.name, - sourceId: savedComponent.id, - target: componentEvent.target, - event: componentEvent.event, - index: componentEvent.index, - appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id], - }; + const newEvent = new EventHandler(); + newEvent.name = componentEvent.name; + newEvent.sourceId = savedComponent.id; + newEvent.target = componentEvent.target; + newEvent.event = componentEvent.event; + newEvent.index = componentEvent.index; + newEvent.appVersionId = appResourceMappings.appVersionMapping[importingAppVersion.id]; + await manager.save(EventHandler, newEvent); }); } @@ -703,18 +715,11 @@ export class AppImportExportService { if (importingQueryEvents.length > 0) { importingQueryEvents.forEach(async (dataQueryEvent) => { - const updatedEventDefinition = this.updateEventActionsForNewVersionWithNewMappingIds( - dataQueryEvent, - appResourceMappings.dataQueryMapping, - appResourceMappings.componentsMapping, - appResourceMappings.pagesMapping - ); - const newEvent = { name: dataQueryEvent.name, sourceId: mappedNewDataQuery.id, target: dataQueryEvent.target, - event: updatedEventDefinition, + event: dataQueryEvent.event, index: dataQueryEvent.index, appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id], }; @@ -726,18 +731,11 @@ export class AppImportExportService { delete mappedNewDataQuery?.options?.events; queryEvents.forEach(async (event, index) => { - const updatedEventDefinition = this.updateEventActionsForNewVersionWithNewMappingIds( - { event: event }, - appResourceMappings.dataQueryMapping, - appResourceMappings.componentsMapping, - appResourceMappings.pagesMapping - ); - const newEvent = { name: event.eventId, sourceId: mappedNewDataQuery.id, target: Target.dataQuery, - event: updatedEventDefinition, + event: event.event, index: queryEvents.index || index, appVersionId: mappedNewDataQuery.appVersionId, }; @@ -1402,29 +1400,36 @@ export class AppImportExportService { return { ...queryOptions, table_id: tooljetDatabaseMapping[queryOptions.table_id]?.id }; } - updateEventActionsForNewVersionWithNewMappingIds( - queryEvent: EventHandler | { event: any }, + async updateEventActionsForNewVersionWithNewMappingIds( + manager: EntityManager, + versionId: string, oldDataQueryToNewMapping: Record, oldComponentToNewComponentMapping: Record, oldPageToNewPageMapping: Record ) { - const event = JSON.parse(JSON.stringify(queryEvent)); + const allEvents = await manager.find(EventHandler, { + where: { appVersionId: versionId }, + }); - const eventDefinition = event.event; + for (const event of allEvents) { + const eventDefinition = event.event; - if (eventDefinition?.actionId === 'run-query') { - eventDefinition.queryId = oldDataQueryToNewMapping[eventDefinition.queryId]; + if (eventDefinition?.actionId === 'run-query') { + eventDefinition.queryId = oldDataQueryToNewMapping[eventDefinition.queryId]; + } + + if (eventDefinition?.actionId === 'control-component') { + eventDefinition.componentId = oldComponentToNewComponentMapping[eventDefinition.componentId]; + } + + if (eventDefinition?.actionId === 'switch-page') { + eventDefinition.pageId = oldPageToNewPageMapping[eventDefinition.pageId]; + } + + event.event = eventDefinition; + + await manager.save(event); } - - if (eventDefinition?.actionId === 'control-component') { - eventDefinition.componentId = oldComponentToNewComponentMapping[eventDefinition.componentId]; - } - - if (eventDefinition?.actionId === 'switch-page') { - eventDefinition.pageId = oldPageToNewPageMapping[eventDefinition.pageId]; - } - - return eventDefinition; } } From e01f2bcff96f9a3e7fbc9936c5a897d473904944 Mon Sep 17 00:00:00 2001 From: arpitnath Date: Mon, 16 Oct 2023 19:23:30 +0530 Subject: [PATCH 09/18] fixes: templates event mapping --- server/src/services/app_import_export.service.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/server/src/services/app_import_export.service.ts b/server/src/services/app_import_export.service.ts index db6bb52701..4b7eb8524d 100644 --- a/server/src/services/app_import_export.service.ts +++ b/server/src/services/app_import_export.service.ts @@ -355,8 +355,6 @@ export class AppImportExportService { appResourceMappings.dataQueryMapping ); - // !----- - let updateHomepageId = null; if (updatedDefinition?.pages) { @@ -384,7 +382,10 @@ export class AppImportExportService { }); const pageCreated = await manager.save(newPage); + appResourceMappings.pagesMapping[pageId] = pageCreated.id; + mappedComponents.forEach((component) => { + appResourceMappings.componentsMapping[component.id] = component.id; component.page = pageCreated; }); @@ -451,8 +452,6 @@ export class AppImportExportService { } } - //!---- - await manager.update( AppVersion, { id: appResourceMappings.appVersionMapping[importingAppVersion.id] }, @@ -735,7 +734,7 @@ export class AppImportExportService { name: event.eventId, sourceId: mappedNewDataQuery.id, target: Target.dataQuery, - event: event.event, + event: event, index: queryEvents.index || index, appVersionId: mappedNewDataQuery.appVersionId, }; From 08965f462c0e27a442728bb30db98ef386c6000e Mon Sep 17 00:00:00 2001 From: arpitnath Date: Mon, 16 Oct 2023 19:34:22 +0530 Subject: [PATCH 10/18] do not app again for not normalized apps --- server/src/services/app_import_export.service.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/server/src/services/app_import_export.service.ts b/server/src/services/app_import_export.service.ts index 4b7eb8524d..e304a26194 100644 --- a/server/src/services/app_import_export.service.ts +++ b/server/src/services/app_import_export.service.ts @@ -471,7 +471,8 @@ export class AppImportExportService { appVersionId, appResourceMappings.dataQueryMapping, appResourceMappings.componentsMapping, - appResourceMappings.pagesMapping + appResourceMappings.pagesMapping, + isNormalizedAppDefinitionSchema ); } @@ -1404,8 +1405,11 @@ export class AppImportExportService { versionId: string, oldDataQueryToNewMapping: Record, oldComponentToNewComponentMapping: Record, - oldPageToNewPageMapping: Record + oldPageToNewPageMapping: Record, + isNormalizedAppDefinitionSchema: boolean ) { + if (!isNormalizedAppDefinitionSchema) return; + const allEvents = await manager.find(EventHandler, { where: { appVersionId: versionId }, }); From b58188b63c1a194d9fd3adbe7f61c1cc2b8fbf77 Mon Sep 17 00:00:00 2001 From: Arpit Date: Tue, 17 Oct 2023 00:07:33 +0530 Subject: [PATCH 11/18] [appdef]migrations fix (#7910) * fixes: page attributes * fixes: table action and column events for imported apps (prev) and app migrations * adds processDataInBatches * fixes: app data migrations * create a new queryBuilder instance for each batch to ensure that there's no interference between batches * fix: app migration * cleanup --- ...6-MigrateAppsDefinitionSchemaTransition.ts | 225 ---------------- ...6-MigrateAppsDefinitionSchemaTransition.ts | 240 ++++++++++++++++++ .../src/services/app_import_export.service.ts | 42 +++ 3 files changed, 282 insertions(+), 225 deletions(-) delete mode 100644 server/data-migrations/1695914619976-MigrateAppsDefinitionSchemaTransition.ts create mode 100644 server/data-migrations/1697473340856-MigrateAppsDefinitionSchemaTransition.ts diff --git a/server/data-migrations/1695914619976-MigrateAppsDefinitionSchemaTransition.ts b/server/data-migrations/1695914619976-MigrateAppsDefinitionSchemaTransition.ts deleted file mode 100644 index bf3d5a9471..0000000000 --- a/server/data-migrations/1695914619976-MigrateAppsDefinitionSchemaTransition.ts +++ /dev/null @@ -1,225 +0,0 @@ -import { MigrationInterface, QueryRunner } from 'typeorm'; -import { AppVersion } from '../src/entities/app_version.entity'; -import { Component } from 'src/entities/component.entity'; -import { Page } from 'src/entities/page.entity'; -import { Layout } from 'src/entities/layout.entity'; -import { EventHandler, Target } from 'src/entities/event_handler.entity'; - -export class MigrateAppsDefinitionSchemaTransition1695914619976 implements MigrationInterface { - public async up(queryRunner: QueryRunner): Promise { - let progress = 0; - - const entityManager = queryRunner.manager; - - const queryBuilder = queryRunner.connection.createQueryBuilder(); - - const appVersionRepository = entityManager.getRepository(AppVersion); - - const appVersions = await appVersionRepository.find(); - - console.log(`MigrateAppsDefinitionSchemaTransition1695902112489 Progress ${progress} %`); - - for (const version of appVersions) { - progress++; - const definition = version['definition']; - - const dataQueries = await queryBuilder - .select() - .from('data_queries', 'data_queries') - .where('app_version_id = :appVersionId', { appVersionId: version.id }) - .getRawMany(); - - let updateHomepageId = null; - - if (definition?.pages) { - for (const pageId of Object.keys(definition?.pages)) { - const page = definition.pages[pageId]; - - const pageEvents = page.events || []; - - const componentEvents = []; - - const pagePostionIntheList = Object.keys(definition?.pages).indexOf(pageId); - - const isHompage = (definition['homePageId'] as any) === pageId; - - const pageComponents = page.components; - - const componentLayouts = []; - - const mappedComponents = this.transformComponentData(pageComponents, componentEvents); - - const newPage = entityManager.create(Page, { - name: page.name, - - handle: page.handle, - - appVersionId: version.id, - - index: pagePostionIntheList, - }); - - const pageCreated = await entityManager.save(newPage); - - mappedComponents.forEach((component) => { - component.page = pageCreated; - }); - - const savedComponents = await entityManager.save(Component, mappedComponents); - - savedComponents.forEach((component) => { - const componentLayout = pageComponents[component.id]['layouts']; - - if (componentLayout) { - for (const type in componentLayout) { - const layout = componentLayout[type]; - - const newLayout = new Layout(); - - newLayout.type = type; - - newLayout.top = layout.top; - - newLayout.left = layout.left; - - newLayout.width = layout.width; - - newLayout.height = layout.height; - - newLayout.component = component; - - componentLayouts.push(newLayout); - } - } - }); - - await entityManager.save(Layout, componentLayouts); - - if (pageEvents.length > 0) { - pageEvents.forEach(async (event, index) => { - const newEvent = { - name: event.eventId, - - sourceId: pageCreated.id, - - target: Target.page, - - event: event, - - index: pageEvents.index || index, - - appVersionId: version.id, - }; - - await entityManager.save(EventHandler, newEvent); - }); - } - - componentEvents.forEach((eventObj) => { - if (eventObj.event?.length === 0) return; - - eventObj.event.forEach(async (event, index) => { - const newEvent = { - name: event.eventId, - - sourceId: eventObj.componentId, - - target: Target.component, - - event: event, - - index: eventObj.index || index, - - appVersionId: version.id, - }; - - await entityManager.save(EventHandler, newEvent); - }); - }); - - if (isHompage) { - updateHomepageId = pageCreated.id; - } - } - } - - for (const dataQuery of dataQueries) { - const queryEvents = dataQuery?.options?.events || []; - - if (queryEvents.length > 0) { - queryEvents.forEach(async (event, index) => { - const newEvent = { - name: event.eventId, - sourceId: dataQuery.id, - target: Target.dataQuery, - event: event, - index: queryEvents.index || index, - appVersionId: version.id, - }; - - await entityManager.save(EventHandler, newEvent); - }); - } - } - console.log( - `MigrateAppsDefinitionSchemaTransition1695902112489 Progress ${Math.round( - (progress / appVersions.length) * 100 - )} %` - ); - await entityManager.update( - AppVersion, - { id: version.id }, - { - homePageId: updateHomepageId, - showViewerNavigation: definition.showViewerNavigation || true, - globalSettings: definition.globalSettings, - } - ); - } - } - - private transformComponentData(data: object, componentEvents: any[]): Component[] { - const transformedComponents: Component[] = []; - - for (const componentId in data) { - const componentData = data[componentId]['component']; - - const transformedComponent: Component = new Component(); - - transformedComponent.id = componentId; - - transformedComponent.name = componentData.name; - - transformedComponent.type = componentData.component; - - transformedComponent.properties = componentData.definition.properties || {}; - - transformedComponent.styles = componentData.definition.styles || {}; - - transformedComponent.validation = componentData.definition.validation || {}; - - transformedComponent.parent = data[componentId].parent || null; - - transformedComponents.push(transformedComponent); - - componentEvents.push({ - componentId: componentId, - - event: componentData.definition.events, - }); - } - - return transformedComponents; - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query('DELETE FROM page'); - await queryRunner.query('DELETE FROM component'); - await queryRunner.query('DELETE FROM layout'); - await queryRunner.query('DELETE FROM event_handler'); - - await queryRunner.query('ALTER TABLE app_version DROP COLUMN IF EXISTS homePageId'); - await queryRunner.query('ALTER TABLE app_version DROP COLUMN IF EXISTS globalSettings'); - await queryRunner.query('ALTER TABLE app_version DROP COLUMN IF EXISTS showViewerNavigation'); - } -} diff --git a/server/data-migrations/1697473340856-MigrateAppsDefinitionSchemaTransition.ts b/server/data-migrations/1697473340856-MigrateAppsDefinitionSchemaTransition.ts new file mode 100644 index 0000000000..d90faa240a --- /dev/null +++ b/server/data-migrations/1697473340856-MigrateAppsDefinitionSchemaTransition.ts @@ -0,0 +1,240 @@ +import { In, MigrationInterface, QueryRunner } from 'typeorm'; +import { AppVersion } from '../src/entities/app_version.entity'; +import { Component } from 'src/entities/component.entity'; +import { Page } from 'src/entities/page.entity'; +import { Layout } from 'src/entities/layout.entity'; +import { EventHandler, Target } from 'src/entities/event_handler.entity'; +import { DataQuery } from 'src/entities/data_query.entity'; +import { MigrationProgress, processDataInBatches } from 'src/helpers/utils.helper'; + +export class MigrateAppsDefinitionSchemaTransition1697473340856 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + // let progress = 0; + const entityManager = queryRunner.manager; + const appVersionRepository = entityManager.getRepository(AppVersion); + const appVersions = await appVersionRepository.find(); + const totalApps = appVersions.length; + + const migrationProgress = new MigrationProgress('MigrateAppsDefinitionSchemaTransition1697473340856', totalApps); + + const batchSize = 100; // Number of apps to migrate at a time + + await processDataInBatches( + entityManager, + async (entityManager, skip, take) => { + return entityManager.find(AppVersion, { + where: { id: In(appVersions.map((appVersion) => appVersion.id)) }, + take, + skip, + }); + }, + async (entityManager, versions: AppVersion[]) => { + for (const version of versions) { + const definition = version['definition']; + + if (!definition) return; + + const dataQueriesRepository = entityManager.getRepository(DataQuery); + const dataQueries = await dataQueriesRepository.find({ + where: { appVersionId: version.id }, + }); + + let updateHomepageId = null; + + if (definition?.pages) { + for (const pageId of Object.keys(definition?.pages)) { + const page = definition.pages[pageId]; + const pageEvents = page.events || []; + const componentEvents = []; + const pagePositionInTheList = Object.keys(definition?.pages).indexOf(pageId); + const isHomepage = (definition['homePageId'] as any) === pageId; + const pageComponents = page.components; + const componentLayouts = []; + const mappedComponents = this.transformComponentData(pageComponents, componentEvents); + const newPage = entityManager.create(Page, { + name: page.name, + handle: page.handle, + appVersionId: version.id, + disabled: page.disabled || false, + hidden: page.hidden || false, + index: pagePositionInTheList, + }); + + const pageCreated = await entityManager.save(newPage); + mappedComponents.forEach((component) => { + component.page = pageCreated; + }); + + const savedComponents = await entityManager.save(Component, mappedComponents); + + savedComponents.forEach((component) => { + const componentLayout = pageComponents[component.id]['layouts']; + + if (componentLayout) { + for (const type in componentLayout) { + const layout = componentLayout[type]; + const newLayout = new Layout(); + newLayout.type = type; + newLayout.top = layout.top; + newLayout.left = layout.left; + newLayout.width = layout.width; + newLayout.height = layout.height; + newLayout.component = component; + componentLayouts.push(newLayout); + } + } + }); + + await entityManager.save(Layout, componentLayouts); + + if (pageEvents.length > 0) { + pageEvents.forEach(async (event, index) => { + const newEvent = { + name: event.eventId, + sourceId: pageCreated.id, + target: Target.page, + event: event, + index: pageEvents.index || index, + appVersionId: version.id, + }; + + await entityManager.save(EventHandler, newEvent); + }); + } + + componentEvents.forEach((eventObj) => { + if (eventObj.event?.length === 0) return; + + eventObj.event.forEach(async (event, index) => { + const newEvent = { + name: event.eventId, + sourceId: eventObj.componentId, + target: Target.component, + event: event, + index: eventObj.index || index, + appVersionId: version.id, + }; + + await entityManager.save(EventHandler, newEvent); + }); + }); + + savedComponents.forEach(async (component) => { + if (component.type === 'Table') { + const tableActions = component.properties?.actions?.value || []; + const tableColumns = component.properties?.columns?.value || []; + const tableActionAndColumnEvents = []; + + tableActions.forEach((action) => { + const actionEvents = action.events || []; + + actionEvents.forEach((event, index) => { + tableActionAndColumnEvents.push({ + name: event.eventId, + sourceId: component.id, + target: Target.tableAction, + event: { ...event, ref: action.name }, + index: event.index ?? index, + appVersionId: version.id, + }); + }); + }); + + tableColumns.forEach((column) => { + if (column?.columnType !== 'toggle') return; + const columnEvents = column.events || []; + + columnEvents.forEach((event, index) => { + tableActionAndColumnEvents.push({ + name: event.eventId, + sourceId: component.id, + target: Target.tableColumn, + event: { ...event, ref: column.name }, + index: event.index ?? index, + appVersionId: version.id, + }); + }); + }); + + await entityManager.save(EventHandler, tableActionAndColumnEvents); + } + }); + + if (isHomepage) { + updateHomepageId = pageCreated.id; + } + } + } + + for (const dataQuery of dataQueries) { + const queryEvents = dataQuery?.options?.events || []; + + if (queryEvents.length > 0) { + queryEvents.forEach(async (event, index) => { + const newEvent = { + name: event.eventId, + sourceId: dataQuery.id, + target: Target.dataQuery, + event: event, + index: queryEvents.index || index, + appVersionId: version.id, + }; + + await entityManager.save(EventHandler, newEvent); + }); + } + } + + migrationProgress.show(); + await entityManager.update( + AppVersion, + { id: version.id }, + { + homePageId: updateHomepageId, + showViewerNavigation: definition?.showViewerNavigation || true, + globalSettings: definition.globalSettings, + } + ); + } + }, + batchSize + ); + } + + private transformComponentData(data: object, componentEvents: any[]): Component[] { + const transformedComponents: Component[] = []; + + for (const componentId in data) { + const componentData = data[componentId]['component']; + + const transformedComponent: Component = new Component(); + + transformedComponent.id = componentId; + transformedComponent.name = componentData.name; + transformedComponent.type = componentData.component; + transformedComponent.properties = componentData.definition.properties || {}; + transformedComponent.styles = componentData.definition.styles || {}; + transformedComponent.validation = componentData.definition.validation || {}; + transformedComponent.parent = data[componentId].parent || null; + transformedComponents.push(transformedComponent); + + componentEvents.push({ + componentId: componentId, + event: componentData.definition.events, + }); + } + + return transformedComponents; + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query('DELETE FROM page'); + await queryRunner.query('DELETE FROM component'); + await queryRunner.query('DELETE FROM layout'); + await queryRunner.query('DELETE FROM event_handler'); + + await queryRunner.query('ALTER TABLE app_version DROP COLUMN IF EXISTS homePageId'); + await queryRunner.query('ALTER TABLE app_version DROP COLUMN IF EXISTS globalSettings'); + await queryRunner.query('ALTER TABLE app_version DROP COLUMN IF EXISTS showViewerNavigation'); + } +} diff --git a/server/src/services/app_import_export.service.ts b/server/src/services/app_import_export.service.ts index e304a26194..06bea10476 100644 --- a/server/src/services/app_import_export.service.ts +++ b/server/src/services/app_import_export.service.ts @@ -446,6 +446,48 @@ export class AppImportExportService { }); }); + savedComponents.forEach(async (component) => { + if (component.type === 'Table') { + const tableActions = component.properties?.actions?.value || []; + const tableColumns = component.properties?.columns?.value || []; + + const tableActionAndColumnEvents = []; + + tableActions.forEach((action) => { + const actionEvents = action.events || []; + + actionEvents.forEach((event, index) => { + tableActionAndColumnEvents.push({ + name: event.eventId, + sourceId: component.id, + target: Target.tableAction, + event: { ...event, ref: action.name }, + index: event.index ?? index, + appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id], + }); + }); + }); + + tableColumns.forEach((column) => { + if (column?.columnType !== 'toggle') return; + const columnEvents = column.events || []; + + columnEvents.forEach((event, index) => { + tableActionAndColumnEvents.push({ + name: event.eventId, + sourceId: component.id, + target: Target.tableColumn, + event: { ...event, ref: column.name }, + index: event.index ?? index, + appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id], + }); + }); + }); + + await manager.save(EventHandler, tableActionAndColumnEvents); + } + }); + if (isHompage) { updateHomepageId = pageCreated.id; } From fb6bf5a157da73a584989a0218de10fb41728ff0 Mon Sep 17 00:00:00 2001 From: arpitnath Date: Tue, 17 Oct 2023 01:48:19 +0530 Subject: [PATCH 12/18] cleanup --- frontend/src/Editor/EditorFunc.jsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/frontend/src/Editor/EditorFunc.jsx b/frontend/src/Editor/EditorFunc.jsx index 3fa48e67ab..ef57fd09de 100644 --- a/frontend/src/Editor/EditorFunc.jsx +++ b/frontend/src/Editor/EditorFunc.jsx @@ -29,7 +29,6 @@ import { removeSelectedComponent, buildAppDefinition, buildComponentMetaDefinition, - runQueries, } from '@/_helpers/appUtils'; import { Confirm } from './Viewer/Confirm'; import { Tooltip as ReactTooltip } from 'react-tooltip'; @@ -405,7 +404,6 @@ const EditorComponent = (props) => { }; const fetchDataQueries = async (id, selectFirstQuery = false, runQueriesOnAppLoad = false) => { - // // editorRef can be undefined when runQueriesOnAppLoad await useDataQueriesStore .getState() .actions.fetchDataQueries(id, selectFirstQuery, runQueriesOnAppLoad, getEditorRef()); @@ -1009,8 +1007,22 @@ const EditorComponent = (props) => { setUndoStack((prev) => prev.slice(0, prev.length - 1)); setRedoStack((prev) => [...prev, diffToPatches(_diffPatches)]); + let undoOpts = optsStack.undo[optsStack.undo.length - 1]; + + if (undoOpts?.componentDeleted) { + undoOpts = { + componentAdded: true, + }; + } + + if (undoOpts?.componentAdded) { + undoOpts = { + componentDeleted: true, + }; + } + updateState({ - appDiffOptions: optsStack.undo[optsStack.undo.length - 1], + appDiffOptions: undoOpts, }); setOptsStack((prev) => ({ From e49ae2d40dc2cb80916a5f5853dc1a9b79574773 Mon Sep 17 00:00:00 2001 From: Arpit Date: Tue, 17 Oct 2023 12:45:31 +0530 Subject: [PATCH 13/18] fixes: table column data not updated on boxes changes in container (#7919) --- frontend/src/Editor/Container.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Editor/Container.jsx b/frontend/src/Editor/Container.jsx index 19d2eb7bf2..285ad2ae78 100644 --- a/frontend/src/Editor/Container.jsx +++ b/frontend/src/Editor/Container.jsx @@ -413,7 +413,7 @@ export const Container = ({ const paramUpdated = useCallback( (id, param, value) => { - if (boxes.length && Object.keys(value)?.length > 0) { + if (Object.keys(value)?.length > 0) { setBoxes((boxes) => update(boxes, { [id]: { From 74c470c6c542439a949317b40fd3fd01c30fa18b Mon Sep 17 00:00:00 2001 From: Arpit Date: Tue, 17 Oct 2023 13:29:19 +0530 Subject: [PATCH 14/18] fixes: creating all pages from all versions (#7905) --- server/src/services/app_import_export.service.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server/src/services/app_import_export.service.ts b/server/src/services/app_import_export.service.ts index 06bea10476..6239e4231f 100644 --- a/server/src/services/app_import_export.service.ts +++ b/server/src/services/app_import_export.service.ts @@ -644,7 +644,9 @@ export class AppImportExportService { return false; }; - for (const page of importingPages) { + const pagesOfAppVersion = importingPages.filter((page) => page.appVersionId === importingAppVersion.id); + + for (const page of pagesOfAppVersion) { const newPage = manager.create(Page, { name: page.name, handle: page.handle, From 40323decef7344cc558a0b2a6f7846f00fd41793 Mon Sep 17 00:00:00 2001 From: Nakul Nagargade <133095394+nakulnagargade@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:36:00 +0530 Subject: [PATCH 15/18] Fix state not changing in chart (#7900) * Fix in chart, toggles are not working * Update Chart.jsx --------- Co-authored-by: Arpit --- frontend/src/Editor/Inspector/Components/Chart.jsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/frontend/src/Editor/Inspector/Components/Chart.jsx b/frontend/src/Editor/Inspector/Components/Chart.jsx index 4c2c20c890..88e55d1e01 100644 --- a/frontend/src/Editor/Inspector/Components/Chart.jsx +++ b/frontend/src/Editor/Inspector/Components/Chart.jsx @@ -56,17 +56,16 @@ class Chart extends React.Component { } render() { - const { dataQueries, component, paramUpdated, componentMeta, components, currentState } = this.state; - const data = this.state.component.component.definition.properties.data; + const { dataQueries, component, paramUpdated, componentMeta, components, currentState } = this.props; + const data = this.props.component.component.definition.properties.data; // since component is not unmounting on every render in current scenario - const jsonDescription = this.state.component.component.definition.properties.jsonDescription; + const jsonDescription = this.props.component.component.definition.properties.jsonDescription; const plotFromJson = resolveReferences( - this.state.component.component.definition.properties.plotFromJson?.value, + this.props.component.component.definition.properties.plotFromJson?.value, currentState ); - - const chartType = this.state.component.component.definition.properties.type.value; + const chartType = this.props.component.component.definition.properties.type.value; let items = []; From 6875e3705f8bdfe9ddde0f35434900a0b41e077e Mon Sep 17 00:00:00 2001 From: Nakul Nagargade <133095394+nakulnagargade@users.noreply.github.com> Date: Tue, 17 Oct 2023 13:36:36 +0530 Subject: [PATCH 16/18] fix event param not updating (#7902) --- .../Editor/Inspector/ActionConfigurationPanels/GotoApp.jsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frontend/src/Editor/Inspector/ActionConfigurationPanels/GotoApp.jsx b/frontend/src/Editor/Inspector/ActionConfigurationPanels/GotoApp.jsx index 3c8636d647..d42ebee133 100644 --- a/frontend/src/Editor/Inspector/ActionConfigurationPanels/GotoApp.jsx +++ b/frontend/src/Editor/Inspector/ActionConfigurationPanels/GotoApp.jsx @@ -6,10 +6,8 @@ import { useTranslation } from 'react-i18next'; export function GotoApp({ getAllApps, event, handlerChanged, eventIndex, darkMode }) { const queryParamChangeHandler = (index, key, value) => { - if (event?.queryParams?.[index]?.[key]) { - event.queryParams[index][key] = value; - handlerChanged(eventIndex, 'queryParams', event.queryParams); - } + event.queryParams[index][key] = value; + handlerChanged(eventIndex, 'queryParams', event.queryParams); }; const { t } = useTranslation(); From e8d3bf3dbf48dc2119284418edfca1eb308e3733 Mon Sep 17 00:00:00 2001 From: Arpit Date: Tue, 17 Oct 2023 13:37:03 +0530 Subject: [PATCH 17/18] [appdef] Pages attributes are missing on versioning or imported app (#7904) * fixes: on creating new version pages attributes are not copied * fixes: on importing apps with pages attributes are not copied * fixes: component double duplication issues --- server/src/services/app_import_export.service.ts | 4 ++++ server/src/services/apps.service.ts | 2 ++ 2 files changed, 6 insertions(+) diff --git a/server/src/services/app_import_export.service.ts b/server/src/services/app_import_export.service.ts index 6239e4231f..259ab9587a 100644 --- a/server/src/services/app_import_export.service.ts +++ b/server/src/services/app_import_export.service.ts @@ -379,6 +379,8 @@ export class AppImportExportService { handle: page.handle, appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id], index: pagePostionIntheList, + disabled: page.disabled || false, + hidden: page.hidden || false, }); const pageCreated = await manager.save(newPage); @@ -652,6 +654,8 @@ export class AppImportExportService { handle: page.handle, appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id], index: page.index, + disabled: page.disabled || false, + hidden: page.hidden || false, }); const pageCreated = await manager.save(newPage); diff --git a/server/src/services/apps.service.ts b/server/src/services/apps.service.ts index a784127a96..92df0026d2 100644 --- a/server/src/services/apps.service.ts +++ b/server/src/services/apps.service.ts @@ -479,6 +479,8 @@ export class AppsService { name: page.name, handle: page.handle, index: page.index, + disabled: page.disabled, + hidden: page.hidden, appVersionId: appVersion.id, }) ); From 91ff545d4efd764f1c272309a37ec558492d37c4 Mon Sep 17 00:00:00 2001 From: Arpit Date: Tue, 17 Oct 2023 13:44:25 +0530 Subject: [PATCH 18/18] fixes: deleting children components via selecto (#7915) --- frontend/src/_helpers/appUtils.js | 38 +++++++++++++++++++------------ 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/frontend/src/_helpers/appUtils.js b/frontend/src/_helpers/appUtils.js index 3e47bc26ba..52752760c7 100644 --- a/frontend/src/_helpers/appUtils.js +++ b/frontend/src/_helpers/appUtils.js @@ -1700,24 +1700,34 @@ export function snapToGrid(canvasWidth, x, y) { return [snappedX, snappedY]; } export const removeSelectedComponent = (pageId, newDefinition, selectedComponents, updateAppDefinition) => { - selectedComponents.forEach((component) => { - let childComponents = []; + const toDeleteComponents = []; - if (newDefinition.pages[pageId].components[component.id]?.component?.component === 'Tabs') { - childComponents = Object.keys(newDefinition.pages[pageId].components).filter((key) => - newDefinition.pages[pageId].components[key].parent?.startsWith(component.id) - ); - } else { - childComponents = Object.keys(newDefinition.pages[pageId].components).filter( - (key) => newDefinition.pages[pageId].components[key].parent === component.id - ); + if (selectedComponents.length < 1) return getSelectedText(); + + const { components: allComponents } = newDefinition.pages[pageId]; + + const findAllChildComponents = (componentId) => { + if (!toDeleteComponents.includes(componentId)) { + toDeleteComponents.push(componentId); + + // Find the children of this component + const children = getAllChildComponents(allComponents, componentId).map((child) => child.componentId); + + if (children.length > 0) { + // Recursively find children of children + children.forEach((child) => { + findAllChildComponents(child); + }); + } } + }; - childComponents.forEach((componentId) => { - delete newDefinition.pages[pageId].components[componentId]; - }); + selectedComponents.forEach((component) => { + findAllChildComponents(component.id); + }); - delete newDefinition.pages[pageId].components[component.id]; + toDeleteComponents.forEach((componentId) => { + delete newDefinition.pages[pageId].components[componentId]; }); updateAppDefinition(newDefinition, { componentDefinitionChanged: true, componentDeleted: true });