From 437e3a45acc3c3248201a0146b4a8bd624d2dca3 Mon Sep 17 00:00:00 2001 From: arpitnath Date: Sun, 6 Aug 2023 16:20:21 +0530 Subject: [PATCH] fixed page actions: add, rename, delete --- frontend/src/Editor/Container.jsx | 2 +- frontend/src/Editor/EditorFunc.jsx | 191 ++++++++++++++++++++++++++--- frontend/src/_helpers/appUtils.js | 1 + 3 files changed, 178 insertions(+), 16 deletions(-) diff --git a/frontend/src/Editor/Container.jsx b/frontend/src/Editor/Container.jsx index 126f2485ce..c4a1bce38b 100644 --- a/frontend/src/Editor/Container.jsx +++ b/frontend/src/Editor/Container.jsx @@ -57,7 +57,7 @@ export const Container = ({ const components = useMemo( () => appDefinition.pages[currentPageId]?.components ?? {}, // eslint-disable-next-line react-hooks/exhaustive-deps - [JSON.stringify(appDefinition)] + [JSON.stringify(appDefinition), currentPageId] ); const currentState = useCurrentState(); diff --git a/frontend/src/Editor/EditorFunc.jsx b/frontend/src/Editor/EditorFunc.jsx index aed625ff7a..2db3c36366 100644 --- a/frontend/src/Editor/EditorFunc.jsx +++ b/frontend/src/Editor/EditorFunc.jsx @@ -128,6 +128,9 @@ const EditorComponent = (props) => { const [isDragging, setIsDragging] = useState(false); + const [showPageDeletionConfirmation, setShowPageDeletionConfirmation] = useState(null); + const [isDeletingPage, setIsDeletingPage] = useState(false); + // refs const canvasContainerRef = useRef(null); const dataSourceModalRef = useRef(null); @@ -712,23 +715,31 @@ const EditorComponent = (props) => { }); } - // Create a new copy of appDefinition with lodash's cloneDeep - const updatedAppDefinition = _.cloneDeep(appDefinition); + let updatedAppDefinition; + + updatedAppDefinition = _.cloneDeep(appDefinition); if (_.isEmpty(updatedAppDefinition)) return; - const currentPageComponents = newDefinition.pages[currentPageId]?.components; + if (opts?.containerChanges || opts?.componentDefinitionChanged) { + const currentPageComponents = newDefinition.pages[currentPageId]?.components; - updatedAppDefinition.pages[currentPageId].components = currentPageComponents; + updatedAppDefinition.pages[currentPageId].components = currentPageComponents; + } + + if (opts?.pageDefinitionChanged) { + updatedAppDefinition.pages = newDefinition.pages; + } const diffPatches = diff(appDefinition, updatedAppDefinition); const shouldUpdate = !_.isEmpty(diffPatches) && !isEqual(appDefinitionDiff, diffPatches); - // console.log('--arpit | appDefinitionChanged func() | diffPatches', { - // diffPatches, - // appDefinitionDiff, - // shouldUpdate, - // }); + console.log('--arpit | appDefinitionChanged func() | diffPatches', { + diffPatches, + appDefinitionDiff, + shouldUpdate, + opts, + }); if (shouldUpdate) { updateEditorState({ @@ -738,8 +749,6 @@ const EditorComponent = (props) => { updateAppDefinitionDiff(diffPatches); computeComponentState(updatedAppDefinition.pages[currentPageId]?.components); } - - // if (!opts.skipAutoSave) autoSave(); }; const saveEditingVersion = (isUserSwitchedVersion = false) => { @@ -1033,6 +1042,149 @@ const EditorComponent = (props) => { } }; + //Page actions + const renamePage = (pageId, newName) => { + if (Object.entries(appDefinition.pages).some(([pId, { name }]) => newName === name && pId !== pageId)) { + return toast.error('Page name already exists'); + } + if (newName.trim().length === 0) { + toast.error('Page name cannot be empty'); + return; + } + + const copyOfAppDefinition = JSON.parse(JSON.stringify(appDefinition)); + + copyOfAppDefinition.pages[pageId].name = newName; + + appDefinitionChanged(copyOfAppDefinition, { pageDefinitionChanged: true }); + }; + + const addNewPage = ({ name, handle }) => { + // check for unique page handles + const pageExists = Object.values(appDefinition.pages).some((page) => page.name === name); + + if (pageExists) { + toast.error('Page name already exists'); + return; + } + + const pageHandles = Object.values(appDefinition.pages).map((page) => page.handle); + + let newHandle = handle; + // If handle already exists, finds a unique handle by incrementing a number until it is not found in the array of existing page handles. + for (let handleIndex = 1; pageHandles.includes(newHandle); handleIndex++) { + newHandle = `${handle}-${handleIndex}`; + } + + const copyOfAppDefinition = JSON.parse(JSON.stringify(appDefinition)); + const newPageId = uuid(); + + copyOfAppDefinition.pages[newPageId] = { + name, + handle: newHandle, + components: {}, + }; + + setCurrentPageId(newPageId); + + appDefinitionChanged(copyOfAppDefinition, { pageDefinitionChanged: true, switchPage: true, pageId: newPageId }); + }; + + const switchPage = (pageId, queryParams = []) => { + // document.getElementById('real-canvas').scrollIntoView(); + if (currentPageId === pageId && currentState.page.handle === appDefinition?.pages[pageId]?.handle) { + return; + } + const { name, handle, events } = appDefinition.pages[pageId]; + + if (!name || !handle) return; + + const copyOfAppDefinition = JSON.parse(JSON.stringify(appDefinition)); + const queryParamsString = queryParams.map(([key, value]) => `${key}=${value}`).join('&'); + + props?.navigate(`/${getWorkspaceId()}/apps/${appId}/${handle}?${queryParamsString}`); + + const { globals: existingGlobals } = currentState; + + const page = { + id: pageId, + name, + handle, + variables: copyOfAppDefinition.pages[pageId]?.variables ?? {}, + }; + + const globals = { + ...existingGlobals, + urlparams: JSON.parse(JSON.stringify(queryString.parse(queryParamsString))), + }; + useCurrentStateStore.getState().actions.setCurrentState({ globals, page }); + + setCurrentPageId(pageId); + handleInspectorView(); + + // computeComponentState(copyOfAppDefinition.pages[pageId]?.components ?? {}).then(async () => { + // for (const event of events ?? []) { + // await handleEvent(event.eventId, event); + // } + // }); + }; + + const deletePageRequest = (pageId, isHomePage = false, pageName = '') => { + setShowPageDeletionConfirmation({ + isOpen: true, + pageId, + isHomePage, + pageName, + }); + }; + + const cancelDeletePageRequest = () => { + setShowPageDeletionConfirmation({ + isOpen: false, + pageId: null, + isHomePage: false, + pageName: null, + }); + }; + + const executeDeletepageRequest = () => { + const pageId = showPageDeletionConfirmation.pageId; + const isHomePage = showPageDeletionConfirmation.isHomePage; + if (Object.keys(appDefinition.pages).length === 1) { + toast.error('You cannot delete the only page in your app.'); + return; + } + + setIsDeletingPage({ + isDeletingPage: true, + }); + + const copyOfAppDefinition = JSON.parse(JSON.stringify(appDefinition)); + + const toBeDeletedPage = copyOfAppDefinition.pages[pageId]; + + const newAppDefinition = { + ...copyOfAppDefinition, + pages: omit(copyOfAppDefinition.pages, pageId), + }; + + const newCurrentPageId = isHomePage ? Object.keys(copyOfAppDefinition.pages)[0] : copyOfAppDefinition.homePageId; + + setCurrentPageId(newCurrentPageId); + updateEditorState({ + isSaving: true, + }); + setIsDeletingPage(false); + + appDefinitionChanged(newAppDefinition, { + pageDefinitionChanged: true, + }); + + toast.success(`${toBeDeletedPage.name} page deleted.`); + + switchPage(newCurrentPageId); + }; + // !------- const currentState = props?.currentState; @@ -1055,6 +1207,15 @@ const EditorComponent = (props) => { return (
+ executeDeletepageRequest()} + onCancel={() => cancelDeletePageRequest()} + darkMode={props.darkMode} + /> {props.isVersionReleased && } { ref={dataSourceModalRef} isSaving={isSaving} currentPageId={currentPageId} - // addNewPage={addNewPage} - // switchPage={switchPage} - // deletePage={deletePageRequest} - // renamePage={renamePage} + addNewPage={addNewPage} + switchPage={switchPage} + deletePage={deletePageRequest} + renamePage={renamePage} // clonePage={clonePage} // hidePage={hidePage} // unHidePage={unHidePage} diff --git a/frontend/src/_helpers/appUtils.js b/frontend/src/_helpers/appUtils.js index 1a97a53e9b..06fa159639 100644 --- a/frontend/src/_helpers/appUtils.js +++ b/frontend/src/_helpers/appUtils.js @@ -1163,6 +1163,7 @@ export function computeComponentState(components = {}) { }; } }); + useCurrentStateStore.getState().actions.setCurrentState({ components: { ...componentState,