diff --git a/frontend/src/AppLoader/AppLoader.jsx b/frontend/src/AppLoader/AppLoader.jsx
index b956efdfb4..1d34e0dec2 100644
--- a/frontend/src/AppLoader/AppLoader.jsx
+++ b/frontend/src/AppLoader/AppLoader.jsx
@@ -7,18 +7,32 @@ import config from 'config';
import { safelyParseJSON, stripTrailingSlash, redirectToDashboard, getSubpath, getWorkspaceId } from '@/_helpers/utils';
import { toast } from 'react-hot-toast';
import { useParams } from 'react-router-dom';
+import { useAppDataActions } from '@/_stores/appDataStore';
+import Spinner from '@/_ui/Spinner';
const AppLoaderComponent = (props) => {
const params = useParams();
const appId = params.id;
+ const [shouldLoadApp, setShouldLoadApp] = React.useState(false);
+
+ const { updateState } = useAppDataActions();
+
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => loadAppDetails(), []);
const loadAppDetails = () => {
- appService.getApp(appId, 'edit').catch((error) => {
- handleError(error);
- });
+ appService
+ .getApp(appId, 'edit')
+ .then((data) => {
+ updateState({
+ app: data,
+ });
+ setShouldLoadApp(true);
+ })
+ .catch((error) => {
+ handleError(error);
+ });
};
const switchOrganization = (orgId) => {
@@ -63,7 +77,13 @@ const AppLoaderComponent = (props) => {
}
};
- return config.ENABLE_MULTIPLAYER_EDITING ? : ;
+ if (!shouldLoadApp) return ;
+
+ return config.ENABLE_MULTIPLAYER_EDITING ? (
+
+ ) : (
+
+ );
};
export const AppLoader = withTranslation()(AppLoaderComponent);
diff --git a/frontend/src/Editor/AppVersionsManager/List.jsx b/frontend/src/Editor/AppVersionsManager/List.jsx
index 4d577b5688..0e75636288 100644
--- a/frontend/src/Editor/AppVersionsManager/List.jsx
+++ b/frontend/src/Editor/AppVersionsManager/List.jsx
@@ -1,6 +1,6 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState } from 'react';
import cx from 'classnames';
-import { appVersionService, appEnvironmentService } from '@/_services';
+import { appVersionService } from '@/_services';
import { CustomSelect } from './CustomSelect';
import { toast } from 'react-hot-toast';
import { shallow } from 'zustand/shallow';
@@ -12,7 +12,6 @@ export const AppVersionsManager = function ({
setAppDefinitionFromVersion,
onVersionDelete,
}) {
- const [appVersions, setAppVersions] = useState([]);
const [appVersionStatus, setGetAppVersionStatus] = useState('');
const [deleteVersion, setDeleteVersion] = useState({
versionId: '',
@@ -20,29 +19,16 @@ export const AppVersionsManager = function ({
showModal: false,
});
- const { editingVersion } = useAppVersionStore(
+ const { editingVersion, appVersions, setAppVersions } = useAppVersionStore(
(state) => ({
editingVersion: state.editingVersion,
+ appVersions: state.appVersions,
+ setAppVersions: state.actions?.setAppVersions,
}),
shallow
);
const darkMode = localStorage.getItem('darkMode') === 'true';
- useEffect(() => {
- setGetAppVersionStatus('loading');
- appEnvironmentService
- .getVersionsByEnvironment(appId)
- .then((data) => {
- setAppVersions(data.appVersions);
- setGetAppVersionStatus('success');
- })
- .catch((error) => {
- toast.error(error);
- setGetAppVersionStatus('failure');
- });
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
-
const selectVersion = (id) => {
appVersionService
.getOne(appId, id)
diff --git a/frontend/src/Editor/EditorFunc.jsx b/frontend/src/Editor/EditorFunc.jsx
index 4ed5391399..87fec23114 100644
--- a/frontend/src/Editor/EditorFunc.jsx
+++ b/frontend/src/Editor/EditorFunc.jsx
@@ -1,5 +1,11 @@
import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
-import { appService, authenticationService, appVersionService, orgEnvironmentVariableService } from '@/_services';
+import {
+ appService,
+ authenticationService,
+ appVersionService,
+ orgEnvironmentVariableService,
+ appEnvironmentService,
+} from '@/_services';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import _, {
@@ -55,19 +61,19 @@ import { withRouter } from '@/_hoc/withRouter';
import { ReleasedVersionError } from './AppVersionsManager/ReleasedVersionError';
import { useDataSourcesStore } from '@/_stores/dataSourcesStore';
import { useDataQueries, useDataQueriesStore } from '@/_stores/dataQueriesStore';
-import { useAppVersionStore } from '@/_stores/appVersionStore';
+import { useAppVersionStore, useAppVersionActions } from '@/_stores/appVersionStore';
import { useQueryPanelStore } from '@/_stores/queryPanelStore';
import { useCurrentStateStore, useCurrentState } from '@/_stores/currentStateStore';
import { computeAppDiff, resetAllStores } from '@/_stores/utils';
import { setCookie } from '@/_helpers/cookie';
import { shallow } from 'zustand/shallow';
import { useEditorActions, useEditorState, useEditorStore } from '@/_stores/editorStore';
-import { useAppDataActions, useAppDataStore, useAppInfo } from '@/_stores/appDataStore';
+import { useAppDataActions, useAppInfo } from '@/_stores/appDataStore';
import { useMounted } from '@/_hooks/use-mount';
// eslint-disable-next-line import/no-unresolved
import { diff } from 'deep-object-diff';
-import { camelizeKeys, decamelizeKeys } from 'humps';
+import { camelizeKeys } from 'humps';
setAutoFreeze(false);
enablePatches();
@@ -78,12 +84,88 @@ function setWindowTitle(name) {
const decimalToHex = (alpha) => (alpha === 0 ? '00' : Math.round(255 * alpha).toString(16));
+const buildComponentMetaDefinition = (components = {}, events = []) => {
+ for (const componentId in components) {
+ const currentComponentData = components[componentId];
+ const componentEvents = events
+ .filter((event) => event.sourceId === componentId)
+ ?.map((event) => ({ ...event.event, id: event.id }));
+ const componentMeta = componentTypes.find((comp) => currentComponentData.component.component === comp.component);
+
+ const mergedDefinition = {
+ ...componentMeta.definition,
+ events: componentEvents,
+ properties: {
+ ...componentMeta.definition.properties,
+ ...currentComponentData?.component.definition.properties,
+ },
+
+ styles: {
+ ...componentMeta.definition.styles,
+ ...currentComponentData?.component.definition.styles,
+ },
+ validations: {
+ ...componentMeta.definition.validations,
+ ...currentComponentData?.component.definition.validations,
+ },
+ };
+
+ const mergedComponent = {
+ component: {
+ ...componentMeta,
+ ...currentComponentData.component,
+ },
+ layouts: {
+ ...currentComponentData.layouts,
+ },
+ withDefaultChildren: componentMeta.withDefaultChildren ?? false,
+ };
+
+ mergedComponent.component.definition = mergedDefinition;
+
+ components[componentId] = mergedComponent;
+ }
+
+ return components;
+};
+
+const buildAppDefinition = (data) => {
+ const editingVersion = _.omit(camelizeKeys(data.editing_version), ['definition', 'updatedAt', 'createdAt', 'name']);
+
+ editingVersion['currentVersionId'] = editingVersion.id;
+ _.unset(editingVersion, 'id');
+
+ const eventsData = data?.events;
+
+ const pages = data.pages.reduce((acc, page) => {
+ const currentComponents = buildComponentMetaDefinition(_.cloneDeep(page?.components), eventsData);
+
+ page.components = currentComponents;
+
+ acc[page.id] = page;
+
+ return acc;
+ }, {});
+
+ const appJSON = {
+ globalSettings: editingVersion.globalSettings,
+ homePageId: editingVersion.homePageId,
+ showHideViewerNavigation: editingVersion.showHideViewerNavigation ?? true,
+ pages: pages,
+ };
+
+ return appJSON;
+};
+
const EditorComponent = (props) => {
const { socket } = createWebsocketConnection(props?.params?.id);
const mounted = useMounted();
const { updateState, updateAppDefinitionDiff, updateAppVersion } = useAppDataActions();
const { updateEditorState, updateQueryConfirmationList } = useEditorActions();
+
+ const { setAppVersions } = useAppVersionActions();
+
const {
noOfVersionsSupported,
appDefinition,
@@ -104,8 +186,18 @@ const EditorComponent = (props) => {
const dataQueries = useDataQueries();
- const { isMaintenanceOn, appId, app, currentUser, currentVersionId, appDefinitionDiff, appDiffOptions, events } =
- useAppInfo();
+ const {
+ isMaintenanceOn,
+ appId,
+ app,
+ appName,
+ slug,
+ currentUser,
+ currentVersionId,
+ appDefinitionDiff,
+ appDiffOptions,
+ events,
+ } = useAppInfo();
const [currentPageId, setCurrentPageId] = useState(null);
const [zoomLevel, setZoomLevel] = useState(1);
@@ -299,8 +391,9 @@ const EditorComponent = (props) => {
const $componentDidMount = async () => {
window.addEventListener('message', handleMessage);
+ await fetchApp(props.params.pageHandle, true);
+
await fetchApps(0);
- await fetchApp(props.params.pageHandle);
await fetchOrgEnvironmentVariables();
initComponentVersioning();
initRealtimeSave();
@@ -323,6 +416,9 @@ const EditorComponent = (props) => {
updateState({ appId: props?.params?.id });
useCurrentStateStore.getState().actions.setCurrentState({ globals });
+
+ getCanvasWidth();
+ initEditorWalkThrough();
};
const fetchDataQueries = async (id, selectFirstQuery = false, runQueriesOnAppLoad = false) => {
@@ -604,94 +700,36 @@ const EditorComponent = (props) => {
//!--------
- const buildComponentMetaDefinition = (components = {}, events = []) => {
- for (const componentId in components) {
- const currentComponentData = components[componentId];
- const componentEvents = events
- .filter((event) => event.sourceId === componentId)
- ?.map((event) => ({ ...event.event, id: event.id }));
- const componentMeta = componentTypes.find((comp) => currentComponentData.component.component === comp.component);
-
- const mergedDefinition = {
- ...componentMeta.definition,
- events: componentEvents,
- properties: {
- ...componentMeta.definition.properties,
- ...currentComponentData?.component.definition.properties,
- },
-
- styles: {
- ...componentMeta.definition.styles,
- ...currentComponentData?.component.definition.styles,
- },
- validations: {
- ...componentMeta.definition.validations,
- ...currentComponentData?.component.definition.validations,
- },
- };
-
- const mergedComponent = {
- component: {
- ...componentMeta,
- ...currentComponentData.component,
- },
- layouts: {
- ...currentComponentData.layouts,
- },
- withDefaultChildren: componentMeta.withDefaultChildren ?? false,
- };
-
- mergedComponent.component.definition = mergedDefinition;
-
- components[componentId] = mergedComponent;
- }
-
- return components;
- };
-
- const buildAppDefinition = (data) => {
- const editingVersion = _.omit(camelizeKeys(data.editing_version), ['definition', 'updatedAt', 'createdAt', 'name']);
-
- editingVersion['currentVersionId'] = editingVersion.id;
- _.unset(editingVersion, 'id');
-
- const eventsData = data?.events;
-
- const pages = data.pages.reduce((acc, page) => {
- const currentComponents = buildComponentMetaDefinition(_.cloneDeep(page?.components), eventsData);
-
- page.components = currentComponents;
-
- acc[page.id] = page;
-
- return acc;
- }, {});
-
- const appJSON = {
- globalSettings: editingVersion.globalSettings,
- homePageId: editingVersion.homePageId,
- showHideViewerNavigation: editingVersion.showHideViewerNavigation ?? true,
- pages: pages,
- };
-
- return appJSON;
- };
-
//****** */
- const fetchApp = async (startingPageHandle) => {
+ const fetchApp = async (startingPageHandle, onMount = false) => {
const _appId = props?.params?.id;
const callBack = async (data) => {
useAppVersionStore.getState().actions.updateEditingVersion(data.editing_version);
useAppVersionStore.getState().actions.updateReleasedVersionId(data.current_version_id);
+
+ const appVersions = await appEnvironmentService.getVersionsByEnvironment(data?.id);
+ setAppVersions(appVersions.appVersions);
+
+ updateState({
+ slug: data.slug,
+ isMaintenanceOn: data?.is_maintenance_on,
+ organizationId: data?.organization_id,
+ isPublic: data?.is_public,
+ appName: data?.name,
+ userId: data?.user_id,
+ appId: data?.id,
+ events: data.events,
+ });
+
await fetchDataSources(data.editing_version?.id);
await fetchDataQueries(data.editing_version?.id, true, true);
+
const appDefData = buildAppDefinition(data);
const appJson = appDefData;
const pages = data.pages;
- const events = data.events;
const startingPageId = pages.filter((page) => page.handle === startingPageHandle)[0]?.id;
const homePageId = !startingPageId || startingPageId === 'null' ? appJson.homePageId : startingPageId;
@@ -705,18 +743,6 @@ const EditorComponent = (props) => {
setCurrentPageId(homePageId);
- updateState({
- app: data,
- slug: data.slug,
- isMaintenanceOn: data?.is_maintenance_on,
- organizationId: data?.organization_id,
- isPublic: data?.is_public,
- appName: data?.name,
- userId: data?.user_id,
- appId: data?.id,
- events: events,
- });
-
useCurrentStateStore.getState().actions.setCurrentState({
page: currentpageData,
});
@@ -729,17 +755,13 @@ const EditorComponent = (props) => {
for (const event of appJson.pages[homePageId]?.events ?? []) {
await handleEvent(event.eventId, event);
}
- getCanvasWidth();
};
- updateState({
- isLoading: true,
- });
-
- await appService
- .getApp(_appId)
- .then(callBack)
- .finally(() => initEditorWalkThrough());
+ if (!onMount) {
+ await appService.getApp(_appId).then(callBack);
+ } else {
+ callBack(app);
+ }
};
// !--------
@@ -1498,12 +1520,27 @@ const EditorComponent = (props) => {
: '';
const deviceWindowWidth = 450;
- if (!appDefinition?.homePageId) {
+ if (isLoading) {
return (
-
-
-
{/* */}
-
Loading...
+
+
+
+
+
+
+
+
+ {Array.from(Array(4)).map((_item, index) => (
+
+ ))}
+
+
+
+
+
+
+
+
);
@@ -1541,6 +1578,10 @@ const EditorComponent = (props) => {
onVersionRelease={onVersionRelease}
saveEditingVersion={saveEditingVersion}
onVersionDelete={onVersionDelete}
+ isMaintenanceOn={isMaintenanceOn}
+ appName={appName}
+ appId={appId}
+ slug={slug}
/>
@@ -1558,9 +1599,9 @@ const EditorComponent = (props) => {
appDefinition={{
components: appDefinition?.pages[currentPageId]?.components ?? {},
selectedComponent: selectedComponents ? selectedComponents[selectedComponents.length - 1] : {},
- pages: appDefinition?.pages,
- homePageId: appDefinition.homePageId,
- showViewerNavigation: appDefinition.showViewerNavigation,
+ pages: appDefinition?.pages ?? {},
+ homePageId: appDefinition?.homePageId ?? null,
+ showViewerNavigation: appDefinition?.showViewerNavigation,
}}
setSelectedComponent={setSelectedComponent}
removeComponent={removeComponent}
diff --git a/frontend/src/Editor/Header/index.js b/frontend/src/Editor/Header/index.js
index 06200fa4c0..37e83e691c 100644
--- a/frontend/src/Editor/Header/index.js
+++ b/frontend/src/Editor/Header/index.js
@@ -14,7 +14,7 @@ import config from 'config';
import { useUpdatePresence } from '@y-presence/react';
import { useAppVersionStore } from '@/_stores/appVersionStore';
import { shallow } from 'zustand/shallow';
-import { useAppDataActions, useAppInfo, useCurrentUser } from '@/_stores/appDataStore';
+import { useAppDataActions, useCurrentUser } from '@/_stores/appDataStore';
export default function EditorHeader({
darkMode,
@@ -34,11 +34,13 @@ export default function EditorHeader({
onVersionRelease,
saveEditingVersion,
onVersionDelete,
+ isMaintenanceOn,
+ appName,
+ appId,
+ slug,
}) {
const currentUser = useCurrentUser();
- const { isMaintenanceOn, appName, appId, slug } = useAppInfo();
-
const { updateState } = useAppDataActions();
const handleSlugChange = (newSlug) => {
@@ -54,6 +56,7 @@ export default function EditorHeader({
);
const updatePresence = useUpdatePresence();
+
useEffect(() => {
const initialPresence = {
firstName: currentUser?.first_name ?? '',
diff --git a/frontend/src/_stores/appVersionStore.js b/frontend/src/_stores/appVersionStore.js
index 38e456479f..74f1f7909c 100644
--- a/frontend/src/_stores/appVersionStore.js
+++ b/frontend/src/_stores/appVersionStore.js
@@ -5,6 +5,7 @@ const initialState = {
isUserEditingTheVersion: false,
releasedVersionId: null,
isVersionReleased: false,
+ appVersions: [],
};
export const useAppVersionStore = create(
@@ -21,8 +22,11 @@ export const useAppVersionStore = create(
releasedVersionId: versionId,
isVersionReleased: get().editingVersion?.id ? get().editingVersion?.id === versionId : false,
}),
+ setAppVersions: (versions) => set({ appVersions: versions }),
},
}),
{ name: 'App Version Manager Store' }
)
);
+
+export const useAppVersionActions = () => useAppVersionStore((state) => state.actions);