diff --git a/frontend/src/Editor/Container.jsx b/frontend/src/Editor/Container.jsx
index 325970fbe2..6e573c7e4a 100644
--- a/frontend/src/Editor/Container.jsx
+++ b/frontend/src/Editor/Container.jsx
@@ -54,8 +54,11 @@ export const Container = ({
backgroundSize: `${gridWidth}px 10px`,
};
- // eslint-disable-next-line react-hooks/exhaustive-deps
- const components = appDefinition.pages[currentPageId]?.components ?? {};
+ const components = useMemo(
+ () => appDefinition.pages[currentPageId]?.components ?? {},
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ [appDefinition.pages[currentPageId]]
+ );
const currentState = useCurrentState();
const { appVersionsId, enableReleasedVersionPopupState, isVersionReleased } = useAppVersionStore(
(state) => ({
@@ -87,10 +90,12 @@ export const Container = ({
useHotkeys('meta+shift+z, control+shift+z', () => handleRedo());
useHotkeys(
'meta+v, control+v',
- () => {
+ async () => {
if (isContainerFocused && !isVersionReleased) {
- navigator.clipboard.readText().then((cliptext) => {
+ // Check if the clipboard API is available
+ if (navigator.clipboard && typeof navigator.clipboard.readText === 'function') {
try {
+ const cliptext = await navigator.clipboard.readText();
addComponents(
currentPageId,
appDefinition,
@@ -101,7 +106,9 @@ export const Container = ({
} catch (err) {
console.log(err);
}
- });
+ } else {
+ console.log('Clipboard API is not available in this browser.');
+ }
}
enableReleasedVersionPopupState();
},
diff --git a/frontend/src/Editor/Editor.jsx b/frontend/src/Editor/Editor.jsx
index 691f24ba0a..8ba542cc96 100644
--- a/frontend/src/Editor/Editor.jsx
+++ b/frontend/src/Editor/Editor.jsx
@@ -46,12 +46,13 @@ import { ReleasedVersionError } from './AppVersionsManager/ReleasedVersionError'
import { useDataSourcesStore } from '@/_stores/dataSourcesStore';
import { useDataQueriesStore } from '@/_stores/dataQueriesStore';
import { useAppVersionStore } from '@/_stores/appVersionStore';
-import { useEditorStore } from '@/_stores/editorStore';
+import { useEditorState, useEditorStore } from '@/_stores/editorStore';
import { useQueryPanelStore } from '@/_stores/queryPanelStore';
import { useCurrentStateStore, useCurrentState } from '@/_stores/currentStateStore';
import { resetAllStores } from '@/_stores/utils';
import { setCookie } from '@/_helpers/cookie';
import { shallow } from 'zustand/shallow';
+import { useAppDataActions, useAppDataStore } from '@/_stores/appDataStore';
setAutoFreeze(false);
enablePatches();
@@ -110,7 +111,7 @@ class EditorComponent extends React.Component {
deviceWindowWidth: 450,
appDefinition: this.defaultDefinition,
apps: [],
- queryConfirmationList: [],
+ // queryConfirmationList: [],
isSourceSelected: false,
isSaving: false,
isUnsavedQueriesAvailable: false,
@@ -124,6 +125,8 @@ class EditorComponent extends React.Component {
this.autoSave = debounce(this.saveEditingVersion, 3000);
this.realtimeSave = debounce(this.appDefinitionChanged, 500);
+
+ this.appActions = useAppDataStore.getState().actions;
}
setWindowTitle(name) {
@@ -145,6 +148,9 @@ class EditorComponent extends React.Component {
groups: currentSession.group_permissions?.map((group) => group.group),
};
this.setState({ currentUser });
+
+ this.appActions.updateCurrentUser(userVars);
+
useCurrentStateStore.getState().actions.setCurrentState({
globals: {
...this.props.currentState.globals,
@@ -176,7 +182,7 @@ class EditorComponent extends React.Component {
this.getCurrentOrganizationDetails();
this.autoSave();
this.fetchApps(0);
- this.fetchApp(this.props.params.pageHandle);
+ await this.fetchApp(this.props.params.pageHandle);
await this.fetchOrgEnvironmentVariables();
this.initComponentVersioning();
this.initRealtimeSave();
@@ -200,6 +206,7 @@ class EditorComponent extends React.Component {
handle: this.props.pageHandle,
variables: {},
};
+ this.appActions.updateState({ appId: this.props.params.id });
useCurrentStateStore.getState().actions.setCurrentState({ globals, page });
}
@@ -241,7 +248,7 @@ class EditorComponent extends React.Component {
componentDidUpdate(prevProps, prevState) {
if (!isEqual(prevState.appDefinition, this.state.appDefinition)) {
- computeComponentState(this, this.state.appDefinition.pages[this.state.currentPageId]?.components);
+ computeComponentState(this.state.appDefinition.pages[this.state.currentPageId]?.components);
}
if (!isEqual(prevState.editorMarginLeft, this.state.editorMarginLeft)) {
@@ -300,11 +307,8 @@ class EditorComponent extends React.Component {
// eslint-disable-next-line no-unused-vars
appService.setMaintenance(this.state.app.id, newState).then((data) => {
- this.setState({
- app: {
- ...this.state.app,
- is_maintenance_on: newState,
- },
+ this.appActions.updateState({
+ isMaintenanceOn: newState,
});
if (newState) {
@@ -316,11 +320,12 @@ class EditorComponent extends React.Component {
};
fetchApps = (page) => {
- appService.getAll(page).then((data) =>
+ appService.getAll(page).then((data) => {
+ this.appActions.updateState({ apps: data.apps.map((app) => ({ id: app.id, name: app.name, slug: app.slug })) });
this.setState({
apps: data.apps,
- })
- );
+ });
+ });
};
fetchApp = (startingPageHandle) => {
@@ -333,6 +338,15 @@ class EditorComponent extends React.Component {
const startingPageId = pages.filter((page) => page.handle === startingPageHandle)[0]?.id;
const homePageId = startingPageId ?? dataDefinition.homePageId;
+ this.appActions.updateState({
+ slug: data.slug,
+ isMaintenanceOn: data?.is_maintenance_on,
+ organizationId: data?.organization_id,
+ isPublic: data?.is_public,
+ appName: data?.name,
+ userId: data?.user_id,
+ });
+
useCurrentStateStore.getState().actions.setCurrentState({
page: {
handle: dataDefinition.pages[homePageId]?.handle,
@@ -343,6 +357,7 @@ class EditorComponent extends React.Component {
});
useAppVersionStore.getState().actions.updateEditingVersion(data.editing_version);
useAppVersionStore.getState().actions.updateReleasedVersionId(data.current_version_id);
+
this.setState(
{
app: data,
@@ -353,7 +368,7 @@ class EditorComponent extends React.Component {
},
async () => {
- computeComponentState(this, this.state.appDefinition.pages[homePageId]?.components ?? {}).then(async () => {
+ computeComponentState(this.state.appDefinition.pages[homePageId]?.components ?? {}).then(async () => {
this.setWindowTitle(data.name);
useEditorStore.getState().actions.setShowComments(!!queryString.parse(this.props.location.search).threadId);
@@ -425,7 +440,7 @@ class EditorComponent extends React.Component {
this.socket?.send(
JSON.stringify({
event: 'events',
- data: { message: 'dataSourcesChanged', appId: this.state.appId },
+ data: { message: 'dataSourcesChanged', appId: this.state.app?.id },
})
);
} else {
@@ -445,7 +460,7 @@ class EditorComponent extends React.Component {
this.socket?.send(
JSON.stringify({
event: 'events',
- data: { message: 'dataQueriesChanged', appId: this.state.appId },
+ data: { message: 'dataQueriesChanged', appId: this.state.app?.id },
})
);
} else {
@@ -601,10 +616,6 @@ class EditorComponent extends React.Component {
this.switchSidebarTab(2);
};
- handleSlugChange = (newSlug) => {
- this.setState({ slug: newSlug });
- };
-
removeComponents = () => {
if (!this.props.isVersionReleased && this.state?.selectedComponents?.length > 1) {
let newDefinition = cloneDeep(this.state.appDefinition);
@@ -695,7 +706,7 @@ class EditorComponent extends React.Component {
this.handleAddPatch
);
setStateAsync(_self, newDefinition).then(() => {
- computeComponentState(_self, _self.state.appDefinition.pages[currentPageId].components);
+ computeComponentState(_self.state.appDefinition.pages[currentPageId].components);
this.setState({ isSaving: true, appDefinitionLocalVersion: uuid() });
this.autoSave();
this.props.ymap?.set('appDef', {
@@ -753,17 +764,36 @@ class EditorComponent extends React.Component {
return;
}
- cloneComponents(this, this.appDefinitionChanged, false, true);
+ cloneComponents(
+ this.state.selectedComponents,
+ this.state.appDefinition,
+ this.state.currentPageId,
+ this.appDefinitionChanged,
+ false
+ );
};
- copyComponents = () => cloneComponents(this, this.appDefinitionChanged, false);
+ copyComponents = () =>
+ cloneComponents(
+ this.state.selectedComponents,
+ this.state.appDefinition,
+ this.state.currentPageId,
+ this.appDefinitionChanged,
+ false
+ );
cloneComponents = () => {
if (this.props.isVersionReleased) {
useAppVersionStore.getState().actions.enableReleasedVersionPopupState();
return;
}
- cloneComponents(this, this.appDefinitionChanged, true);
+ cloneComponents(
+ this.state.selectedComponents,
+ this.state.appDefinition,
+ this.state.currentPageId,
+ this.appDefinitionChanged,
+ true
+ );
};
decimalToHex = (alpha) => (alpha === 0 ? '00' : Math.round(255 * alpha).toString(16));
@@ -828,7 +858,7 @@ class EditorComponent extends React.Component {
this.socket.send(
JSON.stringify({
event: 'events',
- data: { message: 'versionReleased', appId: this.state.appId },
+ data: { message: 'versionReleased', appId: this.state.app?.id },
})
);
}
@@ -869,7 +899,7 @@ class EditorComponent extends React.Component {
} else if (!isEmpty(this.props?.editingVersion)) {
appVersionService
.save(
- this.state.appId,
+ this.state.app?.id,
this.props.editingVersion?.id,
{ definition: this.state.appDefinition },
isUserSwitchedVersion
@@ -900,7 +930,7 @@ class EditorComponent extends React.Component {
};
handleOnComponentOptionChanged = (component, optionName, value) => {
- return onComponentOptionChanged(this, component, optionName, value);
+ return onComponentOptionChanged(component, optionName, value);
};
handleOnComponentOptionsChanged = (component, options) => {
@@ -923,10 +953,10 @@ class EditorComponent extends React.Component {
sideBarDebugger = {
error: (data) => {
- debuggerActions.error(this, data);
+ debuggerActions.error(data);
},
flush: () => {
- debuggerActions.flush(this);
+ debuggerActions.flush();
},
generateErrorLogs: (errors) => debuggerActions.generateErrorLogs(errors),
};
@@ -1359,7 +1389,7 @@ class EditorComponent extends React.Component {
const queryParamsString = queryParams.map(([key, value]) => `${key}=${value}`).join('&');
- this.props.navigate(`/${getWorkspaceId()}/apps/${this.state.appId}/${handle}?${queryParamsString}`);
+ this.props.navigate(`/${getWorkspaceId()}/apps/${this.state.app?.id}/${handle}?${queryParamsString}`);
const { globals: existingGlobals } = this.props.currentState;
@@ -1390,7 +1420,7 @@ class EditorComponent extends React.Component {
},
() => {
// Move this callback to zustand
- computeComponentState(this, this.state.appDefinition.pages[pageId]?.components ?? {}).then(async () => {
+ computeComponentState(this.state.appDefinition.pages[pageId]?.components ?? {}).then(async () => {
for (const event of events ?? []) {
await this.handleEvent(event.eventId, event);
}
@@ -1452,23 +1482,22 @@ class EditorComponent extends React.Component {
currentSidebarTab,
selectedComponents = [],
appDefinition,
- appId,
- slug,
app,
showLeftSidebar,
isLoading,
zoomLevel,
deviceWindowWidth,
- apps,
- defaultComponentStateComputed,
hoveredComponent,
- queryConfirmationList,
} = this.state;
const currentState = this.props?.currentState;
const editingVersion = this.props?.editingVersion;
const appVersionPreviewLink = editingVersion
? `/applications/${app.id}/versions/${editingVersion.id}/${currentState.page.handle}`
: '';
+ const appId = app?.id;
+
+ const { queryConfirmationList = [], defaultComponentStateComputed } = this.props;
+
return (
@@ -1553,7 +1578,6 @@ class EditorComponent extends React.Component {
updateOnPageLoadEvents={this.updateOnPageLoadEvents}
showHideViewerNavigationControls={this.showHideViewerNavigation}
updateOnSortingPages={this.updateOnSortingPages}
- apps={apps}
setEditorMarginLeft={this.handleEditorMarginLeftChange}
/>
{!this.props.showComments && (
@@ -1691,12 +1715,17 @@ class EditorComponent extends React.Component {
dataQueriesChanged={this.dataQueriesChanged}
fetchDataQueries={this.fetchDataQueries}
darkMode={this.props.darkMode}
- apps={apps}
allComponents={appDefinition.pages[this.state.currentPageId]?.components ?? {}}
appId={appId}
appDefinition={appDefinition}
dataSourceModalHandler={this.dataSourceModalHandler}
- editorRef={this}
+ editorRef={{
+ appDefinition: this.state.appDefinition,
+ queryConfirmationList,
+ updateQueryConfirmationList: this.props.updateQueryConfirmationList,
+ navigate: this.props.navigate,
+ currentPageId: this.state.currentPageId,
+ }}
/>
@@ -1723,7 +1752,6 @@ class EditorComponent extends React.Component {
allComponents={appDefinition.pages[this.state.currentPageId]?.components}
key={selectedComponents[0].id}
switchSidebarTab={this.switchSidebarTab}
- apps={apps}
darkMode={this.props.darkMode}
appDefinitionLocalVersion={this.state.appDefinitionLocalVersion}
pages={this.getPagesWithIds()}
@@ -1756,13 +1784,17 @@ class EditorComponent extends React.Component {
}
const withStore = (Component) => (props) => {
- const { showComments, currentLayout } = useEditorStore(
+ const { showComments, currentLayout, queryConfirmationList, defaultComponentStateComputed, actions } = useEditorStore(
(state) => ({
showComments: state?.showComments,
currentLayout: state?.currentLayout,
+ queryConfirmationList: state?.queryConfirmationList,
+ defaultComponentStateComputed: state?.defaultComponentStateComputed,
+ actions: state?.actions,
}),
shallow
);
+
const { isVersionReleased, editingVersion } = useAppVersionStore(
(state) => ({ isVersionReleased: state.isVersionReleased, editingVersion: state.editingVersion }),
shallow
@@ -1778,6 +1810,9 @@ const withStore = (Component) => (props) => {
currentState={currentState}
showComments={showComments}
currentLayout={currentLayout}
+ queryConfirmationList={queryConfirmationList}
+ updateQueryConfirmationList={actions.updateQueryConfirmationList}
+ defaultComponentStateComputed={defaultComponentStateComputed}
/>
);
};
diff --git a/frontend/src/Editor/EditorFunc.jsx b/frontend/src/Editor/EditorFunc.jsx
new file mode 100644
index 0000000000..af72c4174a
--- /dev/null
+++ b/frontend/src/Editor/EditorFunc.jsx
@@ -0,0 +1,1337 @@
+import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
+import { appService, authenticationService, appVersionService, orgEnvironmentVariableService } from '@/_services';
+import { DndProvider } from 'react-dnd';
+import { HTML5Backend } from 'react-dnd-html5-backend';
+import _, { defaults, cloneDeep, isEqual, isEmpty, debounce, omit, update } from 'lodash';
+import { Container } from './Container';
+import { EditorKeyHooks } from './EditorKeyHooks';
+import { CustomDragLayer } from './CustomDragLayer';
+import { LeftSidebar } from './LeftSidebar';
+import { componentTypes } from './WidgetManager/components';
+import { Inspector } from './Inspector/Inspector';
+import QueryPanel from './QueryPanel/QueryPanel';
+import {
+ onComponentOptionChanged,
+ onComponentOptionsChanged,
+ onEvent,
+ onQueryConfirmOrCancel,
+ runQuery,
+ computeComponentState,
+ debuggerActions,
+ cloneComponents,
+ removeSelectedComponent,
+} from '@/_helpers/appUtils';
+import { Confirm } from './Viewer/Confirm';
+import { Tooltip as ReactTooltip } from 'react-tooltip';
+import CommentNotifications from './CommentNotifications';
+import { WidgetManager } from './WidgetManager';
+import config from 'config';
+import queryString from 'query-string';
+import { toast } from 'react-hot-toast';
+const { produce, enablePatches, setAutoFreeze, applyPatches } = require('immer');
+import { createWebsocketConnection } from '@/_helpers/websocketConnection';
+import RealtimeCursors from '@/Editor/RealtimeCursors';
+import { initEditorWalkThrough } from '@/_helpers/createWalkThrough';
+import { EditorContextWrapper } from './Context/EditorContextWrapper';
+import Selecto from 'react-selecto';
+import { withTranslation } from 'react-i18next';
+import { v4 as uuid } from 'uuid';
+import Skeleton from 'react-loading-skeleton';
+import EditorHeader from './Header';
+import { getWorkspaceId } from '@/_helpers/utils';
+import '@/_styles/editor/react-select-search.scss';
+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 { useQueryPanelStore } from '@/_stores/queryPanelStore';
+import { useCurrentStateStore, useCurrentState } from '@/_stores/currentStateStore';
+import { 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 { useMounted } from '@/_hooks/use-mount';
+
+setAutoFreeze(false);
+enablePatches();
+
+function setWindowTitle(name) {
+ document.title = name ? `${name} - Tooljet` : `My App - Tooljet`;
+}
+
+const decimalToHex = (alpha) => (alpha === 0 ? '00' : Math.round(255 * alpha).toString(16));
+
+const defaultDefinition = (darkMode) => {
+ const defaultPageId = uuid();
+ return {
+ showViewerNavigation: true,
+ homePageId: defaultPageId,
+ pages: {
+ [defaultPageId]: {
+ components: {},
+ handle: 'home',
+ name: 'Home',
+ },
+ },
+ globalSettings: {
+ hideHeader: false,
+ appInMaintenance: false,
+ canvasMaxWidth: 1292,
+ canvasMaxWidthType: 'px',
+ canvasMaxHeight: 2400,
+ canvasBackgroundColor: darkMode ? '#2f3c4c' : '#edeff5',
+ backgroundFxQuery: '',
+ },
+ };
+};
+
+const EditorComponent = (props) => {
+ const { socket } = createWebsocketConnection(props?.params?.id);
+ const mounted = useMounted();
+
+ const { updateState } = useAppDataActions();
+ const { updateEditorState, updateQueryConfirmationList } = useEditorActions();
+ const {
+ noOfVersionsSupported,
+ appDefinition,
+ selectedComponents,
+ currentLayout,
+ canUndo,
+ canRedo,
+ isSaving,
+ saveError,
+ scrollOptions,
+ currentSidebarTab,
+ isLoading,
+ defaultComponentStateComputed,
+ currentVersion,
+ showLeftSidebar,
+ queryConfirmationList,
+ } = useEditorState();
+
+ const dataQueries = useDataQueries();
+
+ const { isMaintenanceOn, appId, app, currentUser, currentVersionId } = useAppInfo();
+
+ const [currentVersionChanges, setCurrentVersionChanges] = useState({});
+ const [currentPageId, setCurrentPageId] = useState(null);
+ const [zoomLevel, setZoomLevel] = useState(1);
+ const [isQueryPaneDragging, setIsQueryPaneDragging] = useState(false);
+ const [isQueryPaneExpanded, setIsQueryPaneExpanded] = useState(false);
+ const [selectionInProgress, setSelectionInProgress] = useState(false);
+ const [hoveredComponent, setHoveredComponent] = useState(null);
+ const [editorMarginLeft, setEditorMarginLeft] = useState(0);
+
+ const [isDragging, setIsDragging] = useState(false);
+
+ // refs
+ const canvasContainerRef = useRef(null);
+ const dataSourceModalRef = useRef(null);
+ const selectionDragRef = useRef(null);
+ const selectionRef = useRef(null);
+
+ useLayoutEffect(() => {
+ resetAllStores();
+ }, []);
+
+ useEffect(() => {
+ updateState({ isLoading: true });
+ // 1. Get the current session and current user from the authentication service
+ const currentSession = authenticationService.currentSessionValue;
+ const currentUser = currentSession?.current_user;
+
+ // 2. Subscribe to changes in the current session using RxJS observable pattern
+ const subscription = authenticationService.currentSession.subscribe((currentSession) => {
+ // 3. Check if the current user and group permissions are available
+ if (currentUser && currentSession?.group_permissions) {
+ // 4. Prepare user details in a format suitable for the application
+ const userVars = {
+ email: currentUser.email,
+ firstName: currentUser.first_name,
+ lastName: currentUser.last_name,
+ groups: currentSession.group_permissions?.map((group) => group.group),
+ };
+
+ const appUserDetails = {
+ ...currentUser,
+ current_organization_id: currentSession.current_organization_id,
+ };
+
+ updateState({
+ currentUser: appUserDetails,
+ });
+
+ useCurrentStateStore.getState().actions.setCurrentState({
+ globals: {
+ ...props.currentState.globals,
+ currentUser: userVars,
+ },
+ });
+ }
+ });
+
+ $componentDidMount();
+
+ // 6. Unsubscribe from the observable when the component is unmounted
+ return () => {
+ document.title = 'Tooljet - Dashboard';
+ socket && socket?.close();
+ subscription.unsubscribe();
+ if (config.ENABLE_MULTIPLAYER_EDITING) props?.provider?.disconnect();
+ useEditorStore.getState().actions.setIsEditorActive(false);
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+
+ // Ref to store the previous appDefinition for comparison
+ const prevAppDefinition = useRef(appDefinition);
+
+ useEffect(() => {
+ if (currentUser?.current_organization_id) {
+ fetchGlobalDataSources();
+ }
+ }, [JSON.stringify(currentUser?.current_organization_id)]);
+
+ // Handle appDefinition updates
+ useEffect(() => {
+ const didAppDefinitionChanged = !_.isEqual(appDefinition, prevAppDefinition.current);
+
+ console.log('---arpit-- appDefinitionChanged', { dataQueries, didAppDefinitionChanged, appDefinition });
+ if (mounted && didAppDefinitionChanged && currentPageId) {
+ console.log('---arpit-- appDefinitionChanged [mounted=true]', { appDefinition });
+ const components = appDefinition?.pages[currentPageId]?.components || {};
+
+ computeComponentState(components);
+
+ if (isSaving) {
+ autoSave();
+ }
+ }
+ prevAppDefinition.current = appDefinition;
+ }, [JSON.stringify({ appDefinition, currentPageId, dataQueries })]);
+
+ const editorRef = {
+ appDefinition: appDefinition,
+ queryConfirmationList: queryConfirmationList,
+ updateQueryConfirmationList: updateQueryConfirmationList,
+ navigate: props.navigate,
+ };
+
+ const handleMessage = (event) => {
+ const { data } = event;
+
+ if (data?.type === 'redirectTo') {
+ const redirectCookie = data?.payload['redirectPath'];
+ setCookie('redirectPath', redirectCookie, 1);
+ }
+ };
+
+ const fetchApps = async (page) => {
+ const { apps } = await appService.getAll(page);
+
+ updateState({ apps: apps.map((app) => ({ id: app.id, name: app.name, slug: app.slug })) });
+ };
+
+ const fetchOrgEnvironmentVariables = () => {
+ orgEnvironmentVariableService.getVariables().then((data) => {
+ const client_variables = {};
+ const server_variables = {};
+ data.variables.map((variable) => {
+ if (variable.variable_type === 'server') {
+ server_variables[variable.variable_name] = 'HiddenEnvironmentVariable';
+ } else {
+ client_variables[variable.variable_name] = variable.value;
+ }
+ });
+
+ useCurrentStateStore.getState().actions.setCurrentState({
+ server: server_variables,
+ client: client_variables,
+ });
+ });
+ };
+
+ // 1. When we receive an undoable action – we can always undo but cannot redo anymore.
+ // 2. Whenever you perform an undo – you can always redo and keep doing undo as long as we have a patch for it.
+ // 3. Whenever you redo – you can always undo and keep doing redo as long as we have a patch for it.
+ const initComponentVersioning = () => {
+ const currentVersion = {
+ [currentPageId]: -1,
+ };
+ setCurrentVersionChanges({});
+ updateEditorState({
+ canUndo: false,
+ canRedo: false,
+ currentVersion,
+ });
+ };
+
+ /**
+ * When a new update is received over-the-websocket connection
+ * the useEffect in Container.jsx is triggered, but already appDef had been updated
+ * to avoid ymap observe going into a infinite loop a check is added where if the
+ * current appDef is equal to the newAppDef then we do not trigger a realtimeSave
+ */
+ const initRealtimeSave = () => {
+ if (!config.ENABLE_MULTIPLAYER_EDITING) return null;
+
+ props.ymap?.observe(() => {
+ if (!isEqual(props.editingVersion?.id, props.ymap?.get('appDef').editingVersionId)) return;
+ if (isEqual(appDefinition, props.ymap?.get('appDef').newDefinition)) return;
+
+ realtimeSave(props.ymap?.get('appDef').newDefinition, { skipAutoSave: true, skipYmapUpdate: true });
+ });
+ };
+
+ const initEventListeners = () => {
+ socket?.addEventListener('message', (event) => {
+ const data = event.data.replace(/^"(.+(?="$))"$/, '$1');
+ if (data === 'versionReleased') fetchApp();
+ else if (data === 'dataQueriesChanged') {
+ fetchDataQueries(props.editingVersion?.id);
+ } else if (data === 'dataSourcesChanged') {
+ fetchDataSources(props.editingVersion?.id);
+ }
+ });
+ };
+
+ const $componentDidMount = async () => {
+ console.log('---arpit-- componentDidMounted effect', { appDefinition, currentPageId });
+ window.addEventListener('message', handleMessage);
+ // autoSave();
+
+ await fetchApps(0);
+ await fetchApp(props.params.pageHandle);
+ await fetchOrgEnvironmentVariables();
+ initComponentVersioning();
+ initRealtimeSave();
+ initEventListeners();
+ updateEditorState({
+ currentSidebarTab: 2,
+ selectedComponents: [],
+ scrollOptions: {
+ container: canvasContainerRef.current,
+ throttleTime: 30,
+ threshold: 0,
+ },
+ });
+
+ const globals = {
+ ...props.currentState.globals,
+ theme: { name: props?.darkMode ? 'dark' : 'light' },
+ urlparams: JSON.parse(JSON.stringify(queryString.parse(props.location.search))),
+ };
+ const page = {
+ ...props?.currentState?.page,
+ handle: props?.pageHandle,
+ variables: {},
+ };
+ updateState({ appId: props?.params?.id });
+ useCurrentStateStore.getState().actions.setCurrentState({ globals, page });
+ };
+
+ const fetchDataQueries = async (id, selectFirstQuery = false, runQueriesOnAppLoad = false) => {
+ await useDataQueriesStore.getState().actions.fetchDataQueries(id, selectFirstQuery, runQueriesOnAppLoad, editorRef);
+ };
+
+ const fetchDataSources = (id) => {
+ useDataSourcesStore.getState().actions.fetchDataSources(id);
+ };
+
+ const fetchGlobalDataSources = () => {
+ const { current_organization_id: organizationId } = currentUser;
+ useDataSourcesStore.getState().actions.fetchGlobalDataSources(organizationId);
+ };
+
+ const onVersionDelete = () => {
+ fetchApp(props.params.pageHandle);
+ };
+
+ const toggleAppMaintenance = () => {
+ const newState = !isMaintenanceOn;
+
+ appService.setMaintenance(appId, newState).then(() => {
+ updateState({
+ isMaintenanceOn: newState,
+ });
+
+ if (newState) {
+ toast.success('Application is on maintenance.');
+ } else {
+ toast.success('Application maintenance is completed');
+ }
+ });
+ };
+
+ const dataSourcesChanged = () => {
+ if (socket instanceof WebSocket && socket?.readyState === WebSocket.OPEN) {
+ socket?.send(
+ JSON.stringify({
+ event: 'events',
+ data: { message: 'dataSourcesChanged', appId: appId },
+ })
+ );
+ } else {
+ fetchDataSources(props.editingVersion?.id);
+ }
+ };
+
+ const globalDataSourcesChanged = () => {
+ fetchGlobalDataSources();
+ };
+
+ const dataQueriesChanged = () => {
+ if (socket instanceof WebSocket && socket?.readyState === WebSocket.OPEN) {
+ socket?.send(
+ JSON.stringify({
+ event: 'events',
+ data: { message: 'dataQueriesChanged', appId: appId },
+ })
+ );
+ } else {
+ fetchDataQueries(props.editingVersion?.id);
+ }
+ };
+
+ const switchSidebarTab = (tabIndex) => {
+ updateEditorState({
+ currentSidebarTab: tabIndex,
+ });
+ };
+
+ const handleInspectorView = () => {
+ switchSidebarTab(2);
+ };
+
+ const onNameChanged = (newName) => {
+ updateState({ appName: newName });
+ setWindowTitle(newName);
+ };
+
+ const onZoomChanged = (zoom) => {
+ setZoomLevel(zoom);
+ };
+
+ const [canvasWidth, setCanvasWidth] = useState(1092);
+
+ const getCanvasWidth = () => {
+ const canvasBoundingRect = document.getElementsByClassName('canvas-area')[0]?.getBoundingClientRect();
+
+ const _canvasWidth = canvasBoundingRect?.width;
+
+ if (_canvasWidth) {
+ setCanvasWidth(_canvasWidth);
+ }
+ };
+
+ const computeCanvasContainerHeight = () => {
+ // 45 = (height of header)
+ // 85 = (the height of the query panel header when minimised) + (height of header)
+ return `calc(${100}% - ${Math.max(useQueryPanelStore.getState().queryPanelHeight + 45, 85)}px)`;
+ };
+
+ const handleQueryPaneDragging = (bool) => setIsQueryPaneDragging(bool);
+ const handleQueryPaneExpanding = (bool) => setIsQueryPaneExpanded(bool);
+
+ //! Needs attention
+ const handleOnComponentOptionChanged = (component, optionName, value) => {
+ return onComponentOptionChanged(component, optionName, value);
+ };
+
+ const handleOnComponentOptionsChanged = (component, options) => {
+ return onComponentOptionsChanged(component, options);
+ };
+
+ const handleComponentClick = (id, component) => {
+ updateEditorState({
+ selectedComponent: { id, component },
+ });
+ switchSidebarTab(1);
+ };
+
+ const handleComponentHover = (id) => {
+ if (selectionInProgress) return;
+ setHoveredComponent(id);
+ };
+
+ const sideBarDebugger = {
+ error: (data) => {
+ debuggerActions.error(data);
+ },
+ flush: () => {
+ debuggerActions.flush();
+ },
+ generateErrorLogs: (errors) => debuggerActions.generateErrorLogs(errors),
+ };
+
+ const changeDarkMode = (newMode) => {
+ useCurrentStateStore.getState().actions.setCurrentState({
+ globals: {
+ ...props.currentState.globals,
+ theme: { name: newMode ? 'dark' : 'light' },
+ },
+ });
+ props.switchDarkMode(newMode);
+ };
+
+ //! Needs attention
+ const handleEvent = (eventName, options) => onEvent(editorRef, eventName, options, 'edit');
+
+ const handleRunQuery = (queryId, queryName) => runQuery(editorRef, queryId, queryName);
+
+ const dataSourceModalHandler = () => {
+ dataSourceModalRef.current.dataSourceModalToggleStateHandler();
+ };
+
+ const onAreaSelectionStart = (e) => {
+ const isMultiSelect = e.inputEvent.shiftKey || selectedComponents.length > 0;
+ setSelectionInProgress(true);
+ const prevSelectedComponents = [...selectedComponents];
+ updateEditorState({
+ selectedComponents: [...(isMultiSelect ? prevSelectedComponents : [])],
+ });
+ };
+
+ const onAreaSelection = (e) => {
+ e.added.forEach((el) => {
+ el.classList.add('resizer-select');
+ });
+ if (selectionInProgress) {
+ e.removed.forEach((el) => {
+ el.classList.remove('resizer-select');
+ });
+ }
+ };
+
+ const onAreaSelectionEnd = (e) => {
+ setSelectionInProgress(false);
+ e.selected.forEach((el, index) => {
+ const id = el.getAttribute('widgetid');
+ const component = appDefinition?.pages[currentPageId].components[id].component;
+ const isMultiSelect = e.inputEvent.shiftKey || (!e.isClick && index != 0);
+ setSelectedComponent(id, component, isMultiSelect);
+ });
+ };
+
+ const setSelectedComponent = (id, component, multiSelect = false) => {
+ if (selectedComponents.length === 0 || !multiSelect) {
+ switchSidebarTab(1);
+ } else {
+ switchSidebarTab(2);
+ }
+
+ const isAlreadySelected = selectedComponents.find((component) => component.id === id);
+
+ if (!isAlreadySelected) {
+ const prevSelectedComponents = [...selectedComponents];
+ updateEditorState({
+ selectedComponents: [...(multiSelect ? prevSelectedComponents : []), { id, component }],
+ });
+ }
+ };
+
+ const onVersionRelease = (versionId) => {
+ useAppVersionStore.getState().actions.updateReleasedVersionId(versionId);
+
+ updateState({
+ currentVersionId: versionId,
+ });
+
+ socket.send(
+ JSON.stringify({
+ event: 'events',
+ data: { message: 'versionReleased', appId: appId },
+ })
+ );
+ };
+
+ const computeCanvasBackgroundColor = () => {
+ //!Global settings needs to be out
+ const { canvasBackgroundColor } = appDefinition?.globalSettings ?? '#edeff5';
+ if (['#2f3c4c', '#edeff5'].includes(canvasBackgroundColor)) {
+ return props.darkMode ? '#2f3c4c' : '#edeff5';
+ }
+ return canvasBackgroundColor;
+ };
+
+ const onAreaSelectionDragStart = (e) => {
+ if (e.inputEvent.target.getAttribute('id') !== 'real-canvas') {
+ selectionDragRef.current = true;
+ } else {
+ selectionDragRef.current = false;
+ }
+ };
+
+ const onAreaSelectionDrag = (e) => {
+ if (selectionDragRef.current) {
+ e.stop();
+ selectionInProgress && setSelectionInProgress(false);
+ }
+ };
+
+ const onAreaSelectionDragEnd = () => {
+ selectionDragRef.current = false;
+ selectionInProgress && setSelectionInProgress(false);
+ };
+
+ const getPagesWithIds = () => {
+ //! Needs attention
+ return Object.entries(appDefinition?.pages).map(([id, page]) => ({ ...page, id }));
+ };
+
+ const handleEditorMarginLeftChange = (value) => setEditorMarginLeft(value);
+
+ const globalSettingsChanged = (key, value) => {
+ if (value?.[1]?.a == undefined) appDefinition.globalSettings[key] = value;
+ else {
+ const hexCode = `${value?.[0]}${decimalToHex(value?.[1]?.a)}`;
+ appDefinition.globalSettings[key] = hexCode;
+ }
+
+ updateEditorState({
+ isSaving: true,
+ appDefinition,
+ });
+
+ props.ymap?.set('appDef', {
+ newDefinition: appDefinition,
+ editingVersionId: props.editingVersion?.id,
+ });
+ // autoSave();
+ };
+
+ //!--------
+ const fetchApp = async (startingPageHandle) => {
+ const _appId = props?.params?.id;
+
+ const callBack = async (data) => {
+ useAppVersionStore.getState().actions.updateEditingVersion(data.editing_version);
+ useAppVersionStore.getState().actions.updateReleasedVersionId(data.current_version_id);
+ await fetchDataSources(data.editing_version?.id);
+ await fetchDataQueries(data.editing_version?.id, true, true);
+
+ // let dataDefinition = defaults(data.definition, defaultDefinition(props.darkMode));
+ let dataDefinition = data.definition ?? defaults(data.definition, defaultDefinition(props.darkMode));
+ console.log('---arpit-- fetching app data', { startingPageHandle, data, dataDefinition });
+
+ const pages = Object.entries(dataDefinition.pages).map(([pageId, page]) => ({ id: pageId, ...page }));
+ const startingPageId = pages.filter((page) => page.handle === startingPageHandle)[0]?.id;
+ const homePageId = startingPageId || dataDefinition.homePageId;
+
+ 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,
+ });
+
+ useCurrentStateStore.getState().actions.setCurrentState({
+ page: {
+ handle: dataDefinition.pages[homePageId]?.handle,
+ name: dataDefinition.pages[homePageId]?.name,
+ id: homePageId,
+ variables: {},
+ },
+ });
+
+ updateEditorState({
+ isLoading: false,
+ appDefinition: dataDefinition,
+ });
+
+ appDefinitionChanged(dataDefinition, {
+ skipAutoSave: true,
+ skipYmapUpdate: true,
+ });
+
+ for (const event of dataDefinition.pages[homePageId]?.events ?? []) {
+ await handleEvent(event.eventId, event);
+ }
+ getCanvasWidth();
+ };
+
+ updateState({
+ isLoading: true,
+ });
+
+ await appService
+ .getApp(_appId)
+ .then(callBack)
+ .finally(() => initEditorWalkThrough());
+ };
+
+ // !--------
+ const setAppDefinitionFromVersion = (version, shouldWeEditVersion = true) => {
+ if (version?.id !== props.editingVersion?.id) {
+ appDefinitionChanged(defaults(version.definition, defaultDefinition(props.darkMode)), {
+ skipAutoSave: true,
+ skipYmapUpdate: true,
+ versionChanged: true,
+ });
+ if (version?.id === currentVersionId) {
+ updateEditorState({
+ canUndo: false,
+ canRedo: false,
+ });
+ }
+ useAppVersionStore.getState().actions.updateEditingVersion(version);
+
+ updateEditorState({
+ isSaving: false,
+ });
+
+ shouldWeEditVersion && saveEditingVersion(true);
+ fetchDataSources(props.editingVersion?.id);
+ fetchDataQueries(props.editingVersion?.id, true);
+ initComponentVersioning();
+ }
+ };
+
+ const appDefinitionChanged = (newDefinition, opts = {}) => {
+ console.log('--arpit | appDefinitionChanged func()');
+ if (_.isEqual(appDefinition, newDefinition)) return;
+ if (config.ENABLE_MULTIPLAYER_EDITING && !opts.skipYmapUpdate) {
+ props.ymap?.set('appDef', {
+ newDefinition,
+ editingVersionId: props.editingVersion?.id,
+ });
+ }
+
+ if (opts?.versionChanged) {
+ setCurrentPageId(newDefinition.homePageId);
+
+ return new Promise((resolve) => {
+ updateEditorState({
+ isSaving: true,
+ appDefinition: newDefinition,
+ // appDefinitionLocalVersion: uuid(),
+ });
+
+ // if (!opts.skipAutoSave) autoSave();
+
+ resolve();
+ });
+ }
+
+ // Create a new copy of appDefinition with lodash's cloneDeep
+ const updatedAppDefinition = _.cloneDeep(appDefinition);
+ const currentPageComponents = newDefinition.pages[currentPageId]?.components;
+
+ if (!updatedAppDefinition.pages[currentPageId]) {
+ updatedAppDefinition.pages[currentPageId] = {}; // Create a new object for the page if it doesn't exist
+ }
+
+ updatedAppDefinition.pages[currentPageId].components = currentPageComponents || {};
+
+ // Call handleAddPatch with the list of changes (if needed)
+ handleAddPatch();
+
+ // Update the editor state with the new appDefinition
+ updateEditorState({
+ isSaving: true,
+ appDefinition: updatedAppDefinition,
+ // appDefinitionLocalVersion: uuid(),
+ });
+
+ // if (!opts.skipAutoSave) autoSave();
+ };
+
+ const saveEditingVersion = (isUserSwitchedVersion = false) => {
+ if (props.isVersionReleased && !isUserSwitchedVersion) {
+ updateEditorState({
+ isSaving: false,
+ });
+ } else if (!isEmpty(props?.editingVersion)) {
+ appVersionService
+ .save(appId, props.editingVersion?.id, { definition: appDefinition }, isUserSwitchedVersion)
+ .then(() => {
+ const _editingVersion = {
+ ...props.editingVersion,
+ ...{ definition: appDefinition },
+ };
+ useAppVersionStore.getState().actions.updateEditingVersion(_editingVersion);
+ updateEditorState({
+ saveError: false,
+ isSaving: false,
+ });
+ })
+ .catch(() => {
+ updateEditorState({
+ saveError: true,
+ isSaving: false,
+ });
+ toast.error('App could not save.');
+ });
+ }
+
+ updateEditorState({
+ saveError: false,
+ isSaving: false,
+ });
+ };
+
+ const realtimeSave = debounce(appDefinitionChanged, 500);
+ const autoSave = debounce(saveEditingVersion, 3000);
+
+ const handleAddPatch = (patches, inversePatches) => {
+ if (isEmpty(patches) && isEmpty(inversePatches)) return;
+ if (isEqual(patches, inversePatches)) return;
+
+ const currentPage = currentPageId;
+ const _currentVersion = currentVersion[currentPage] ?? -1;
+
+ let _currentVersionChanges = {};
+
+ _currentVersionChanges[currentPage] = currentVersionChanges[currentPage] ?? {};
+
+ _currentVersionChanges[currentPage][_currentVersion] = {
+ redo: patches,
+ undo: inversePatches,
+ };
+
+ setCurrentVersionChanges(_currentVersionChanges);
+
+ const _canUndo = _currentVersionChanges[currentPage].hasOwnProperty(_currentVersion);
+ const _canRedo = _currentVersionChanges[currentPage].hasOwnProperty(_currentVersion + 1);
+
+ _currentVersion[currentPage] = currentVersion + 1;
+
+ delete _currentVersionChanges[currentPage][_currentVersion + 1];
+ delete _currentVersionChanges[currentPage][_currentVersion - noOfVersionsSupported];
+
+ setCurrentVersionChanges(_currentVersionChanges);
+
+ updateEditorState({
+ canUndo: _canUndo,
+ canRedo: _canRedo,
+ currentVersion: _currentVersion,
+ });
+ };
+
+ const handleUndo = () => {
+ if (canUndo) {
+ let _currentVersion = currentVersion[currentPageId];
+
+ const _appDefinition = applyPatches(appDefinition, currentVersionChanges[currentPageId][currentVersion - 1].undo);
+
+ const _canUndo = currentVersionChanges[currentPageId].hasOwnProperty(currentVersion - 1);
+ const _canRedo = true;
+ _currentVersion[currentPageId] = _currentVersion - 1;
+
+ if (!_appDefinition) return;
+
+ updateEditorState({
+ appDefinition: _appDefinition,
+ canUndo: _canUndo,
+ canRedo: _canRedo,
+ currentVersion: _currentVersion,
+ isSaving: true,
+ });
+
+ props.ymap?.set('appDef', {
+ newDefinition: appDefinition,
+ editingVersionId: props.editingVersion?.id,
+ });
+
+ // autoSave();
+ }
+ };
+
+ const handleRedo = () => {
+ if (canRedo) {
+ let _currentVersion = currentVersion[currentPageId];
+
+ const _appDefinition = applyPatches(appDefinition, currentVersionChanges[currentPageId][currentVersion].redo);
+
+ const _canUndo = true;
+ const _canRedo = currentVersionChanges[currentPageId].hasOwnProperty(currentVersion + 1);
+ _currentVersion[currentPageId] = currentVersion + 1;
+
+ if (!_appDefinition) return;
+
+ updateEditorState({
+ appDefinition: _appDefinition,
+ canUndo: _canUndo,
+ canRedo: _canRedo,
+ currentVersion: _currentVersion,
+ isSaving: true,
+ });
+
+ props.ymap?.set('appDef', {
+ newDefinition: appDefinition,
+ editingVersionId: props.editingVersion?.id,
+ });
+
+ // autoSave();
+ }
+ };
+
+ const componentDefinitionChanged = (componentDefinition, props) => {
+ console.log('---arpit [componentDefinitionChanged]', { props, componentDefinition });
+ if (props?.isVersionReleased) {
+ useAppVersionStore.getState().actions.enableReleasedVersionPopupState();
+ return;
+ }
+
+ if (appDefinition?.pages[currentPageId]?.components[componentDefinition.id]) {
+ // Create a new copy of appDefinition with lodash's cloneDeep
+ const updatedAppDefinition = _.cloneDeep(appDefinition);
+
+ // Update the component definition in the copy
+ updatedAppDefinition.pages[currentPageId].components[componentDefinition.id].component =
+ componentDefinition.component;
+
+ // Call handleAddPatch with the list of changes (if needed)
+ handleAddPatch();
+
+ // Update the editor state with the new appDefinition
+ updateEditorState({
+ isSaving: true,
+ appDefinition: updatedAppDefinition,
+ // appDefinitionLocalVersion: uuid()
+ });
+
+ // Other actions can be performed here if needed, like autoSave, ymap, etc.
+ computeComponentState(updatedAppDefinition.pages[currentPageId]?.components);
+ // autoSave();
+ props.ymap?.set('appDef', {
+ newDefinition: updatedAppDefinition,
+ editingVersionId: props.editingVersion?.id,
+ });
+ }
+ };
+
+ const removeComponent = (component) => {
+ if (!props.isVersionReleased) {
+ let newDefinition = cloneDeep(appDefinition);
+ // Delete child components when parent is deleted
+
+ let childComponents = [];
+
+ if (newDefinition.pages[currentPageId].components?.[component.id].component.component === 'Tabs') {
+ childComponents = Object.keys(newDefinition.pages[currentPageId].components).filter((key) =>
+ newDefinition.pages[currentPageId].components[key].parent?.startsWith(component.id)
+ );
+ } else {
+ childComponents = Object.keys(newDefinition.pages[currentPageId].components).filter(
+ (key) => newDefinition.pages[currentPageId].components[key].parent === component.id
+ );
+ }
+
+ childComponents.forEach((componentId) => {
+ delete newDefinition.pages[currentPageId].components[componentId];
+ });
+
+ delete newDefinition.pages[currentPageId].components[component.id];
+ const platform = navigator?.userAgentData?.platform || navigator?.platform || 'unknown';
+ if (platform.toLowerCase().indexOf('mac') > -1) {
+ toast('Component deleted! (⌘ + Z to undo)', {
+ icon: '🗑️',
+ });
+ } else {
+ toast('Component deleted! (ctrl + Z to undo)', {
+ icon: '🗑️',
+ });
+ }
+ appDefinitionChanged(newDefinition, {
+ skipAutoSave: props.isVersionReleased,
+ });
+ handleInspectorView();
+ } else {
+ useAppVersionStore.getState().actions.enableReleasedVersionPopupState();
+ }
+ };
+
+ const moveComponents = (direction) => {
+ const gridWidth = (1 * 100) / 43; // width of the canvas grid in percentage
+ const _appDefinition = _.cloneDeep(appDefinition);
+ let newComponents = _appDefinition?.pages[currentPageId].components;
+
+ for (const selectedComponent of selectedComponents) {
+ let top = newComponents[selectedComponent.id].layouts[props.currentLayout].top;
+ let left = newComponents[selectedComponent.id].layouts[props.currentLayout].left;
+
+ switch (direction) {
+ case 'ArrowLeft':
+ left = left - gridWidth;
+ break;
+ case 'ArrowRight':
+ left = left + gridWidth;
+ break;
+ case 'ArrowDown':
+ top = top + 10;
+ break;
+ case 'ArrowUp':
+ top = top - 10;
+ break;
+ }
+
+ newComponents[selectedComponent.id].layouts[props.currentLayout].top = top;
+ newComponents[selectedComponent.id].layouts[props.currentLayout].left = left;
+ }
+
+ _appDefinition.pages[currentPageId].components = newComponents;
+
+ appDefinitionChanged(_appDefinition);
+ };
+
+ const copyComponents = () =>
+ cloneComponents(selectedComponents, appDefinition, currentPageId, appDefinitionChanged, false);
+
+ const cutComponents = () => {
+ if (props.isVersionReleased) {
+ useAppVersionStore.getState().actions.enableReleasedVersionPopupState();
+
+ return;
+ }
+
+ cloneComponents(selectedComponents, appDefinition, currentPageId, appDefinitionChanged, false);
+ };
+
+ const handleEditorEscapeKeyPress = () => {
+ if (selectedComponents?.length > 0) {
+ updateEditorState({
+ selectedComponents: [],
+ });
+ handleInspectorView();
+ }
+ };
+
+ const removeComponents = () => {
+ if (!props.isVersionReleased && selectedComponents?.length > 1) {
+ let newDefinition = cloneDeep(appDefinition);
+
+ removeSelectedComponent(currentPageId, newDefinition, selectedComponents);
+ const platform = navigator?.userAgentData?.platform || navigator?.platform || 'unknown';
+ if (platform.toLowerCase().indexOf('mac') > -1) {
+ toast('Selected components deleted! (⌘ + Z to undo)', {
+ icon: '🗑️',
+ });
+ } else {
+ toast('Selected components deleted! (ctrl + Z to undo)', {
+ icon: '🗑️',
+ });
+ }
+ appDefinitionChanged(newDefinition, {
+ skipAutoSave: props.isVersionReleased,
+ });
+ handleInspectorView();
+ } else if (props.isVersionReleased) {
+ useAppVersionStore.getState().actions.enableReleasedVersionPopupState();
+ }
+ };
+
+ // !-------
+
+ const currentState = props?.currentState;
+ const editingVersion = props?.editingVersion;
+ const appVersionPreviewLink = editingVersion
+ ? `/applications/${app.id}/versions/${editingVersion.id}/${currentState.page.handle}`
+ : '';
+ const deviceWindowWidth = 450;
+
+ if (!appDefinition?.homePageId) {
+ return (
+
+ );
+ }
+
+ return (
+
+ {props.isVersionReleased &&
}
+
+
+
+
+
handleRunQuery(queryId, queryName)}
+ ref={dataSourceModalRef}
+ isSaving={isSaving}
+ currentPageId={currentPageId}
+ // addNewPage={addNewPage}
+ // switchPage={switchPage}
+ // deletePage={deletePageRequest}
+ // renamePage={renamePage}
+ // clonePage={clonePage}
+ // hidePage={hidePage}
+ // unHidePage={unHidePage}
+ // updateHomePage={updateHomePage}
+ // updatePageHandle={updatePageHandle}
+ // updateOnPageLoadEvents={updateOnPageLoadEvents}
+ // showHideViewerNavigationControls={showHideViewerNavigation}
+ // updateOnSortingPages={updateOnSortingPages}
+ setEditorMarginLeft={handleEditorMarginLeftChange}
+ />
+ {!props.showComments && (
+ {
+ canvasContainerRef.current.scrollBy(e.direction[0] * 10, e.direction[1] * 10);
+ }}
+ />
+ )}
+
+
{
+ if (['real-canvas', 'modal'].includes(e.target.className)) {
+ updateEditorState({
+ currentSidebarTab: 2,
+ selectedComponents: [],
+ });
+ setHoveredComponent(null);
+ }
+ }}
+ ref={canvasContainerRef}
+ onScroll={() => {
+ selectionRef.current.checkScroll();
+ }}
+ >
+
+
+ {config.ENABLE_MULTIPLAYER_EDITING && (
+
+ )}
+ {isLoading && (
+
+
+
+
+
+
+
+
+ {Array.from(Array(4)).map((_item, index) => (
+
+ ))}
+
+
+
+
+
+
+
+
+
+
+ )}
+ {defaultComponentStateComputed && (
+ <>
+
+
setIsDragging(isDragging)}
+ />
+ >
+ )}
+
+
+
+
+
+
+
+
+
+ {currentSidebarTab === 1 && (
+
+ {selectedComponents.length === 1 &&
+ !isEmpty(appDefinition?.pages[currentPageId]?.components) &&
+ !isEmpty(appDefinition?.pages[currentPageId]?.components[selectedComponents[0].id]) ? (
+
+ ) : (
+
+ {props.t('editor.inspectComponent', 'Please select a component to inspect')}
+
+ )}
+
+ )}
+
+ {currentSidebarTab === 2 && (
+
+ )}
+
+ {config.COMMENT_FEATURE_ENABLE && props.showComments && (
+
+ )}
+
+
+
+
+ );
+};
+
+const withStore = (Component) => (props) => {
+ const { showComments, currentLayout } = useEditorStore(
+ (state) => ({
+ showComments: state?.showComments,
+ currentLayout: state?.currentLayout,
+ }),
+ shallow
+ );
+ const { isVersionReleased, editingVersion } = useAppVersionStore(
+ (state) => ({ isVersionReleased: state.isVersionReleased, editingVersion: state.editingVersion }),
+ shallow
+ );
+
+ const currentState = useCurrentState();
+
+ return (
+
+ );
+};
+
+export const EditorFunc = withTranslation()(withRouter(withStore(EditorComponent)));
diff --git a/frontend/src/Editor/Header/GlobalSettings.jsx b/frontend/src/Editor/Header/GlobalSettings.jsx
index f0d62fd1fc..9b169ea7dc 100644
--- a/frontend/src/Editor/Header/GlobalSettings.jsx
+++ b/frontend/src/Editor/Header/GlobalSettings.jsx
@@ -19,11 +19,10 @@ export const GlobalSettings = ({
globalSettingsChanged,
darkMode,
toggleAppMaintenance,
- is_maintenance_on,
+ isMaintenanceOn,
}) => {
const { t } = useTranslation();
- const { hideHeader, canvasMaxWidth, canvasMaxWidthType, canvasMaxHeight, canvasBackgroundColor, backgroundFxQuery } =
- globalSettings;
+ const { hideHeader, canvasMaxWidth, canvasMaxWidthType, canvasBackgroundColor, backgroundFxQuery } = globalSettings;
const [showPicker, setShowPicker] = React.useState(false);
const currentState = useCurrentState();
const [forceCodeBox, setForceCodeBox] = React.useState(true);
@@ -87,7 +86,7 @@ export const GlobalSettings = ({
data-cy={`toggle-maintenance-mode`}
className="form-check-input"
type="checkbox"
- checked={is_maintenance_on}
+ checked={isMaintenanceOn}
onChange={() => setConfirmationShow(true)}
/>
@@ -237,7 +236,7 @@ export const GlobalSettings = ({
{
+ updateState({ slug: newSlug });
+ };
+
const { isVersionReleased, editingVersion } = useAppVersionStore(
(state) => ({
isVersionReleased: state.isVersionReleased,
@@ -87,9 +93,9 @@ export default function EditorHeader({
globalSettings={appDefinition.globalSettings}
darkMode={darkMode}
toggleAppMaintenance={toggleAppMaintenance}
- is_maintenance_on={is_maintenance_on}
+ isMaintenanceOn={isMaintenanceOn}
/>
-
+
@@ -167,14 +173,12 @@ export default function EditorHeader({
- {app.id && (
-
- )}
+
diff --git a/frontend/src/Editor/Inspector/EventManager.jsx b/frontend/src/Editor/Inspector/EventManager.jsx
index 3cdf997c16..8e787d16be 100644
--- a/frontend/src/Editor/Inspector/EventManager.jsx
+++ b/frontend/src/Editor/Inspector/EventManager.jsx
@@ -15,13 +15,13 @@ import { useTranslation } from 'react-i18next';
import { useDataQueries } from '@/_stores/dataQueriesStore';
import RunjsParameters from './ActionConfigurationPanels/RunjsParamters';
+import { useAppInfo } from '@/_stores/appDataStore';
export const EventManager = ({
component,
componentMeta,
components,
eventsChanged,
- apps,
excludeEvents,
popOverCallback,
popoverPlacement,
@@ -29,6 +29,8 @@ export const EventManager = ({
hideEmptyEventsAlert,
}) => {
const dataQueries = useDataQueries();
+ const { apps, appId } = useAppInfo();
+
const [events, setEvents] = useState(() => component.component.definition.events || []);
const [focusedEventIndex, setFocusedEventIndex] = useState(null);
const { t } = useTranslation();
@@ -170,7 +172,7 @@ export const EventManager = ({
function getAllApps() {
let appsOptionsList = [];
apps
- .filter((item) => item.slug !== undefined)
+ .filter((item) => item.slug !== undefined && item.id !== appId)
.forEach((item) => {
appsOptionsList.push({
name: item.name,
diff --git a/frontend/src/Editor/Inspector/Inspector.jsx b/frontend/src/Editor/Inspector/Inspector.jsx
index f349abe3a7..e5eb84f818 100644
--- a/frontend/src/Editor/Inspector/Inspector.jsx
+++ b/frontend/src/Editor/Inspector/Inspector.jsx
@@ -28,7 +28,6 @@ export const Inspector = ({
selectedComponentId,
componentDefinitionChanged,
allComponents,
- apps,
darkMode,
switchSidebarTab,
removeComponent,
@@ -285,7 +284,6 @@ export const Inspector = ({
currentState={currentState}
darkMode={darkMode}
eventsChanged={eventsChanged}
- apps={apps}
pages={pages}
allComponents={allComponents}
/>
diff --git a/frontend/src/Editor/QueryManager/Components/QueryManagerBody.jsx b/frontend/src/Editor/QueryManager/Components/QueryManagerBody.jsx
index 4aed281625..67eedb47dd 100644
--- a/frontend/src/Editor/QueryManager/Components/QueryManagerBody.jsx
+++ b/frontend/src/Editor/QueryManager/Components/QueryManagerBody.jsx
@@ -39,7 +39,6 @@ export const QueryManagerBody = forwardRef(
previewLoading,
queryPreviewData,
allComponents,
- apps,
appDefinition,
createDraftQuery,
setOptions,
@@ -309,7 +308,6 @@ export const QueryManagerBody = forwardRef(
componentMeta={queryComponent.componentMeta}
dataQueries={dataQueries}
components={allComponents}
- apps={apps}
popoverPlacement="top"
pages={
appDefinition?.pages ? Object.entries(appDefinition?.pages).map(([id, page]) => ({ ...page, id })) : []
diff --git a/frontend/src/Editor/QueryManager/QueryManager.jsx b/frontend/src/Editor/QueryManager/QueryManager.jsx
index 957b472a9d..1ca04a92fa 100644
--- a/frontend/src/Editor/QueryManager/QueryManager.jsx
+++ b/frontend/src/Editor/QueryManager/QueryManager.jsx
@@ -22,7 +22,6 @@ const QueryManager = ({
dataQueriesChanged,
appId,
darkMode,
- apps,
allComponents,
dataSourceModalHandler,
appDefinition,
@@ -105,7 +104,6 @@ const QueryManager = ({
previewLoading={previewLoading}
queryPreviewData={queryPreviewData}
allComponents={allComponents}
- apps={apps}
appDefinition={appDefinition}
createDraftQuery={createDraftQuery}
setOptions={setOptions}
diff --git a/frontend/src/Editor/QueryPanel/QueryPanel.jsx b/frontend/src/Editor/QueryPanel/QueryPanel.jsx
index 6dd633fca7..3508d01f47 100644
--- a/frontend/src/Editor/QueryPanel/QueryPanel.jsx
+++ b/frontend/src/Editor/QueryPanel/QueryPanel.jsx
@@ -13,7 +13,6 @@ const QueryPanel = ({
dataQueriesChanged,
fetchDataQueries,
darkMode,
- apps,
allComponents,
appId,
appDefinition,
@@ -268,7 +267,6 @@ const QueryPanel = ({
dataQueriesChanged={updateDataQueries}
appId={appId}
darkMode={darkMode}
- apps={apps}
allComponents={allComponents}
dataSourceModalHandler={dataSourceModalHandler}
appDefinition={appDefinition}
diff --git a/frontend/src/Editor/RealtimeEditor.jsx b/frontend/src/Editor/RealtimeEditor.jsx
index 605af7ba7f..41779f4d32 100644
--- a/frontend/src/Editor/RealtimeEditor.jsx
+++ b/frontend/src/Editor/RealtimeEditor.jsx
@@ -3,7 +3,8 @@ import React from 'react';
import config from 'config';
import { RoomProvider } from '@y-presence/react';
import Spinner from '@/_ui/Spinner';
-import { Editor } from '@/Editor';
+import { Editor, EditorFunc } from '@/Editor';
+
import useRouter from '@/_hooks/use-router';
import { useParams } from 'react-router-dom';
const Y = require('yjs');
@@ -70,7 +71,7 @@ export const RealtimeEditor = (props) => {
return (
-
+
);
};
diff --git a/frontend/src/Editor/Viewer.jsx b/frontend/src/Editor/Viewer.jsx
index d50821e8f6..ceb35437b0 100644
--- a/frontend/src/Editor/Viewer.jsx
+++ b/frontend/src/Editor/Viewer.jsx
@@ -168,7 +168,7 @@ class ViewerComponent extends React.Component {
homepage: this.state.appDefinition?.pages?.[this.state.appDefinition?.homePageId]?.handle,
},
() => {
- computeComponentState(this, data?.definition?.pages[currentPage.id]?.components).then(async () => {
+ computeComponentState(data?.definition?.pages[currentPage.id]?.components).then(async () => {
this.setState({ initialComputationOfStateDone: true });
console.log('Default component state computed and set');
this.runQueries(data.data_queries);
@@ -407,15 +407,13 @@ class ViewerComponent extends React.Component {
name: targetPage.name,
},
async () => {
- computeComponentState(this, this.state.appDefinition?.pages[this.state.currentPageId].components).then(
- async () => {
- // eslint-disable-next-line no-unsafe-optional-chaining
- const { events } = this.state.appDefinition?.pages[this.state.currentPageId];
- for (const event of events ?? []) {
- await this.handleEvent(event.eventId, event);
- }
+ computeComponentState(this.state.appDefinition?.pages[this.state.currentPageId].components).then(async () => {
+ // eslint-disable-next-line no-unsafe-optional-chaining
+ const { events } = this.state.appDefinition?.pages[this.state.currentPageId];
+ for (const event of events ?? []) {
+ await this.handleEvent(event.eventId, event);
}
- );
+ });
}
);
}
diff --git a/frontend/src/Editor/index.js b/frontend/src/Editor/index.js
index 8e539b2b32..a5bdf8c189 100644
--- a/frontend/src/Editor/index.js
+++ b/frontend/src/Editor/index.js
@@ -2,3 +2,4 @@
export * from './Editor';
export * from './Viewer';
export * from './DataSourceManager';
+export * from './EditorFunc';
diff --git a/frontend/src/_helpers/appUtils.js b/frontend/src/_helpers/appUtils.js
index 2733e47b66..7e981a29c7 100644
--- a/frontend/src/_helpers/appUtils.js
+++ b/frontend/src/_helpers/appUtils.js
@@ -31,6 +31,7 @@ import { useDataQueriesStore } from '@/_stores/dataQueriesStore';
import { useQueryPanelStore } from '@/_stores/queryPanelStore';
import { useCurrentStateStore, getCurrentState } from '@/_stores/currentStateStore';
import { useAppVersionStore } from '@/_stores/appVersionStore';
+import { useEditorStore } from '@/_stores/editorStore';
const ERROR_TYPES = Object.freeze({
ReferenceError: 'ReferenceError',
@@ -58,7 +59,7 @@ export function setCurrentStateAsync(_ref, changes) {
});
}
-export function onComponentOptionsChanged(_ref, component, options) {
+export function onComponentOptionsChanged(component, options) {
const componentName = component.name;
const components = getCurrentState().components;
let componentData = components[componentName];
@@ -74,7 +75,7 @@ export function onComponentOptionsChanged(_ref, component, options) {
return Promise.resolve();
}
-export function onComponentOptionChanged(_ref, component, option_name, value) {
+export function onComponentOptionChanged(component, option_name, value) {
const componentName = component.name;
const components = getCurrentState().components;
@@ -351,7 +352,7 @@ function showModal(_ref, modal, show) {
return Promise.resolve();
}
- const modalMeta = _ref.state.appDefinition.pages[_ref.state.currentPageId].components[modalId];
+ const modalMeta = _ref.appDefinition.pages[_ref.state.currentPageId].components[modalId]; //! NeedToFix
const _components = {
...getCurrentState().components,
@@ -366,7 +367,7 @@ function showModal(_ref, modal, show) {
return Promise.resolve();
}
-function logoutAction(_ref) {
+function logoutAction() {
localStorage.clear();
authenticationService.logout(true);
@@ -431,7 +432,7 @@ function executeActionWithDebounce(_ref, event, mode, customVariables) {
return runQuery(_ref, queryId, name, undefined, mode, resolvedParams);
}
case 'logout': {
- return logoutAction(_ref);
+ return logoutAction();
}
case 'open-webpage': {
@@ -511,7 +512,7 @@ function executeActionWithDebounce(_ref, event, mode, customVariables) {
}
case 'set-table-page': {
- setTablePageIndex(_ref, event.table, event.pageIndex);
+ setTablePageIndex(event.table, event.pageIndex);
break;
}
@@ -574,7 +575,7 @@ function executeActionWithDebounce(_ref, event, mode, customVariables) {
}
case 'switch-page': {
- _ref.switchPage(event.pageId, resolveReferences(event.queryParams, getCurrentState(), [], customVariables));
+ _ref.switchPage(event.pageId, resolveReferences(event.queryParams, getCurrentState(), [], customVariables)); // arpit [switchPage]
return Promise.resolve();
}
}
@@ -600,7 +601,7 @@ export async function onEvent(_ref, eventName, options, mode = 'edit') {
},
},
});
- runQuery(_ref, queryId, queryName, true, mode, parameters);
+ runQuery(_ref, queryId, queryName, true, mode, parameters); //arpit [runQuery]
}
if (eventName === 'onCalendarEventSelect') {
@@ -737,9 +738,9 @@ export async function onEvent(_ref, eventName, options, mode = 'edit') {
}
if (eventName === 'onBulkUpdate') {
- onComponentOptionChanged(_self, options.component, 'isSavingChanges', true);
+ onComponentOptionChanged(options.component, 'isSavingChanges', true);
await executeActionsForEventId(_self, eventName, options.component, mode, customVariables);
- onComponentOptionChanged(_self, options.component, 'isSavingChanges', false);
+ onComponentOptionChanged(options.component, 'isSavingChanges', false);
}
if (['onDataQuerySuccess', 'onDataQueryFailure'].includes(eventName)) {
@@ -1105,7 +1106,7 @@ export function runQuery(_ref, queryId, queryName, confirmed = undefined, mode =
});
}
-export function setTablePageIndex(_ref, tableId, index) {
+export function setTablePageIndex(tableId, index) {
if (_.isEmpty(tableId)) {
console.log('No table is associated with this event.');
return Promise.resolve();
@@ -1126,7 +1127,7 @@ export function renderTooltip({ props, text }) {
);
}
-export function computeComponentState(_ref, components = {}) {
+export function computeComponentState(components = {}) {
let componentState = {};
const currentComponents = getCurrentState().components;
Object.keys(components).forEach((key) => {
@@ -1168,8 +1169,11 @@ export function computeComponentState(_ref, components = {}) {
},
});
- return setStateAsync(_ref, {
- defaultComponentStateComputed: true,
+ return new Promise((resolve) => {
+ useEditorStore.getState().actions.updateEditorState({
+ defaultComponentStateComputed: true,
+ });
+ resolve();
});
}
@@ -1186,13 +1190,13 @@ export const getSvgIcon = (key, height = 50, width = 50, iconFile = undefined, s
};
export const debuggerActions = {
- error: (_self, errors) => {
+ error: (errors) => {
useCurrentStateStore.getState().actions.setErrors({
...errors,
});
},
- flush: (_self) => {
+ flush: () => {
useCurrentStateStore.getState().actions.setCurrentState({
errors: {},
});
@@ -1312,9 +1316,16 @@ const updateNewComponents = (pageId, appDefinition, newComponents, updateAppDefi
updateAppDefinition(newAppDefinition);
};
-export const cloneComponents = (_ref, updateAppDefinition, isCloning = true, isCut = false) => {
- const { selectedComponents, appDefinition, currentPageId } = _ref.state;
+export const cloneComponents = (
+ selectedComponents,
+ appDefinition,
+ currentPageId,
+ updateAppDefinition,
+ isCloning = true,
+ isCut = false
+) => {
if (selectedComponents.length < 1) return getSelectedText();
+
const { components: allComponents } = appDefinition.pages[currentPageId];
let newDefinition = _.cloneDeep(appDefinition);
let newComponents = [],
@@ -1351,7 +1362,13 @@ export const cloneComponents = (_ref, updateAppDefinition, isCloning = true, isC
navigator.clipboard.writeText(JSON.stringify(newComponentObj));
toast.success('Component copied succesfully');
}
- _ref.setState({ currentSidebarTab: 2 });
+
+ return new Promise((resolve) => {
+ useEditorStore.getState().actions.updateEditorState({
+ currentSidebarTab: 2,
+ });
+ resolve();
+ });
};
const getChildComponents = (allComponents, component, parentComponent, addedComponentId) => {
@@ -1606,7 +1623,7 @@ export const runQueries = (queries, _ref) => {
});
};
-export const computeQueryState = (queries, _ref) => {
+export const computeQueryState = (queries) => {
let queryState = {};
queries.forEach((query) => {
if (query.plugin?.plugin_id) {
diff --git a/frontend/src/_helpers/utils.js b/frontend/src/_helpers/utils.js
index 51d7344b43..12431a4e91 100644
--- a/frontend/src/_helpers/utils.js
+++ b/frontend/src/_helpers/utils.js
@@ -544,10 +544,11 @@ export const hightlightMentionedUserInComment = (comment) => {
};
export const generateAppActions = (_ref, queryId, mode, isPreview = false) => {
- const currentPageId = _ref.state.currentPageId;
- const currentComponents = _ref.state?.appDefinition?.pages[currentPageId]?.components
- ? Object.entries(_ref.state.appDefinition.pages[currentPageId]?.components)
+ const currentPageId = _ref.currentPageId;
+ const currentComponents = _ref.appDefinition?.pages[currentPageId]?.components
+ ? Object.entries(_ref.appDefinition.pages[currentPageId]?.components)
: {};
+
const runQuery = (queryName = '', parameters) => {
const query = useDataQueriesStore.getState().dataQueries.find((query) => query.name === queryName);
diff --git a/frontend/src/_stores/appDataStore.js b/frontend/src/_stores/appDataStore.js
index 7c6ccd612c..aac92a9be1 100644
--- a/frontend/src/_stores/appDataStore.js
+++ b/frontend/src/_stores/appDataStore.js
@@ -1,7 +1,23 @@
+import { shallow } from 'zustand/shallow';
import { create, zustandDevTools } from './utils';
const initialState = {
editingVersion: null,
+ currentUser: null,
+ apps: [],
+ appId: null,
+ appName: null,
+ slug: null,
+ isPublic: null,
+ isMaintenanceOn: null,
+ organizationId: null,
+ currentVersionId: null,
+ userId: null,
+ app: {},
+ components: [],
+ pages: [],
+ layouts: [],
+ eventHandlers: [],
};
export const useAppDataStore = create(
@@ -10,6 +26,8 @@ export const useAppDataStore = create(
...initialState,
actions: {
updateEditingVersion: (version) => set(() => ({ editingVersion: version })),
+ updateApps: (apps) => set(() => ({ apps: apps })),
+ updateState: (state) => set((prev) => ({ ...prev, ...state })),
},
}),
{ name: 'App Data Store' }
@@ -18,3 +36,6 @@ export const useAppDataStore = create(
export const useEditingVersion = () => useAppDataStore((state) => state.editingVersion);
export const useUpdateEditingVersion = () => useAppDataStore((state) => state.actions);
+export const useCurrentUser = () => useAppDataStore((state) => state.currentUser);
+export const useAppInfo = () => useAppDataStore((state) => state);
+export const useAppDataActions = () => useAppDataStore((state) => state.actions);
diff --git a/frontend/src/_stores/dataQueriesStore.js b/frontend/src/_stores/dataQueriesStore.js
index bcfcfaadab..369f311573 100644
--- a/frontend/src/_stores/dataQueriesStore.js
+++ b/frontend/src/_stores/dataQueriesStore.js
@@ -29,7 +29,7 @@ export const useDataQueriesStore = create(
// Runs query on loading application
if (runQueriesOnAppLoad) runQueries(data.data_queries, editorRef);
// Compute query state to be added in the current state
- computeQueryState(data.data_queries, editorRef);
+ computeQueryState(data.data_queries);
const { actions, selectedQuery } = useQueryPanelStore.getState();
if (selectFirstQuery || selectedQuery?.id === 'draftQuery') {
actions.setSelectedQuery(data.data_queries[0]?.id, data.data_queries[0]);
@@ -40,7 +40,7 @@ export const useDataQueriesStore = create(
});
},
setDataQueries: (dataQueries) => set({ dataQueries }),
- deleteDataQueries: (queryId, editorRef) => {
+ deleteDataQueries: (queryId) => {
set({ isDeletingQueryInProcess: true });
dataqueryService
.del(queryId)
@@ -57,8 +57,7 @@ export const useDataQueriesStore = create(
get().actions.fetchDataQueries(
useAppVersionStore.getState().editingVersion?.id,
selectedQuery?.id === queryId,
- false,
- editorRef
+ false
);
})
.catch(({ error }) => {
@@ -122,12 +121,12 @@ export const useDataQueriesStore = create(
});
});
},
- renameQuery: (id, newName, editorRef) => {
+ renameQuery: (id, newName) => {
dataqueryService
.update(id, newName)
.then(() => {
toast.success('Query Name Updated');
- get().actions.fetchDataQueries(useAppVersionStore.getState().editingVersion?.id, false, false, editorRef);
+ get().actions.fetchDataQueries(useAppVersionStore.getState().editingVersion?.id, false, false);
})
.catch(({ error }) => {
toast.error(error);
diff --git a/frontend/src/_stores/editorStore.js b/frontend/src/_stores/editorStore.js
index bb4b83ba8c..87515e1617 100644
--- a/frontend/src/_stores/editorStore.js
+++ b/frontend/src/_stores/editorStore.js
@@ -4,6 +4,25 @@ const initialState = {
currentLayout: 'desktop',
showComments: false,
isEditorActive: false,
+ currentSidebarTab: 2,
+ selectedComponents: [],
+ selectedComponent: null,
+ scrollOptions: {
+ container: null,
+ throttleTime: 0,
+ threshold: 0,
+ },
+ canUndo: false,
+ canRedo: false,
+ currentVersion: {},
+ noOfVersionsSupported: 100,
+ appDefinition: {},
+ isSaving: false,
+ saveError: false,
+ isLoading: true,
+ defaultComponentStateComputed: false,
+ showLeftSidebar: true,
+ queryConfirmationList: [],
};
export const useEditorStore = create(
@@ -15,8 +34,13 @@ export const useEditorStore = create(
toggleComments: () => set({ showComments: !get().showComments }),
toggleCurrentLayout: (currentLayout) => set({ currentLayout }),
setIsEditorActive: (isEditorActive) => set(() => ({ isEditorActive })),
+ updateEditorState: (state) => set((prev) => ({ ...prev, ...state })),
+ updateQueryConfirmationList: (queryConfirmationList) => set({ queryConfirmationList }),
},
}),
{ name: 'Editor Store' }
)
);
+
+export const useEditorActions = () => useEditorStore((state) => state.actions);
+export const useEditorState = () => useEditorStore((state) => state);