mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 09:28:31 +00:00
adapts to main/viewer changes
This commit is contained in:
parent
5c379bd45f
commit
8d402566af
1 changed files with 78 additions and 175 deletions
|
|
@ -1,12 +1,9 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
// appsService,
|
||||
appsService,
|
||||
authenticationService,
|
||||
orgEnvironmentVariableService,
|
||||
orgEnvironmentConstantService,
|
||||
// organizationService,
|
||||
dataqueryService,
|
||||
appService,
|
||||
} from '@/_services';
|
||||
import { DndProvider } from 'react-dnd';
|
||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||
|
|
@ -21,7 +18,6 @@ import {
|
|||
onEvent,
|
||||
runQuery,
|
||||
computeComponentState,
|
||||
buildAppDefinition,
|
||||
} from '@/_helpers/appUtils';
|
||||
import queryString from 'query-string';
|
||||
import ViewerLogoIcon from './Icons/viewer-logo.svg';
|
||||
|
|
@ -37,7 +33,8 @@ import { setCookie } from '@/_helpers/cookie';
|
|||
import { useDataQueriesStore } from '@/_stores/dataQueriesStore';
|
||||
import { useCurrentStateStore } from '@/_stores/currentStateStore';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
import { useAppDataActions, useAppDataStore } from '@/_stores/appDataStore';
|
||||
import { useAppDataStore } from '@/_stores/appDataStore';
|
||||
import { getPreviewQueryParams, redirectToDashboard } from '@/_helpers/routes';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
class ViewerComponent extends React.Component {
|
||||
|
|
@ -56,34 +53,31 @@ class ViewerComponent extends React.Component {
|
|||
isLoading: true,
|
||||
users: null,
|
||||
appDefinition: { pages: {} },
|
||||
queryConfirmationList: [],
|
||||
isAppLoaded: false,
|
||||
pages: {},
|
||||
homepage: null,
|
||||
currentPageId: null,
|
||||
};
|
||||
}
|
||||
|
||||
setStateForApp = (data, byAppSlug = false) => {
|
||||
const appDefData = buildAppDefinition(data);
|
||||
setStateForApp = (data) => {
|
||||
const copyDefinition = _.cloneDeep(data.definition);
|
||||
const pagesObj = copyDefinition.pages || {};
|
||||
|
||||
if (byAppSlug) {
|
||||
appDefData.globalSettings = data.globalSettings;
|
||||
appDefData.homePageId = data.homePageId;
|
||||
appDefData.showViewerNavigation = data.showViewerNavigation;
|
||||
}
|
||||
const newDefinition = {
|
||||
...copyDefinition,
|
||||
pages: pagesObj,
|
||||
};
|
||||
|
||||
this.setState({
|
||||
app: data,
|
||||
isLoading: false,
|
||||
isAppLoaded: true,
|
||||
appDefinition: { ...appDefData },
|
||||
pages: appDefData.pages,
|
||||
appDefinition: newDefinition || { components: {} },
|
||||
});
|
||||
};
|
||||
|
||||
setStateForContainer = async (data, appVersionId) => {
|
||||
const appDefData = buildAppDefinition(data);
|
||||
|
||||
setStateForContainer = async (data) => {
|
||||
const currentUser = this.state.currentUser;
|
||||
let userVars = {};
|
||||
|
||||
|
|
@ -99,57 +93,38 @@ class ViewerComponent extends React.Component {
|
|||
let mobileLayoutHasWidgets = false;
|
||||
|
||||
if (this.props.currentLayout === 'mobile') {
|
||||
const currentComponents = appDefData.pages[appDefData.homePageId].components;
|
||||
const currentComponents = data.definition.pages[data.definition.homePageId].components;
|
||||
mobileLayoutHasWidgets =
|
||||
Object.keys(currentComponents).filter((componentId) => currentComponents[componentId]['layouts']['mobile'])
|
||||
.length > 0;
|
||||
}
|
||||
|
||||
let queryState = {};
|
||||
let dataQueries = [];
|
||||
data.data_queries.forEach((query) => {
|
||||
if (query.pluginId || query?.plugin?.id) {
|
||||
queryState[query.name] = {
|
||||
...query.plugin.manifestFile.data.source.exposedVariables,
|
||||
...this.props.currentState.queries[query.name],
|
||||
};
|
||||
} else {
|
||||
const dataSourceTypeDetail = DataSourceTypes.find((source) => source.kind === query.kind);
|
||||
queryState[query.name] = {
|
||||
...dataSourceTypeDetail.exposedVariables,
|
||||
...this.props.currentState.queries[query.name],
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
if (appVersionId) {
|
||||
const { data_queries } = await dataqueryService.getAll(appVersionId);
|
||||
dataQueries = data_queries;
|
||||
} else {
|
||||
dataQueries = data.data_queries;
|
||||
}
|
||||
const queryConfirmationList = [];
|
||||
|
||||
if (dataQueries.length > 0) {
|
||||
dataQueries.forEach((query) => {
|
||||
if (query?.options && query?.options?.requestConfirmation && query?.options?.runOnPageLoad) {
|
||||
queryConfirmationList.push({ queryId: query.id, queryName: query.name });
|
||||
}
|
||||
|
||||
if (query.pluginId || query?.plugin?.id) {
|
||||
queryState[query.name] = {
|
||||
...query.plugin.manifestFile.data.source.exposedVariables,
|
||||
...this.props.currentState.queries[query.name],
|
||||
};
|
||||
} else {
|
||||
const dataSourceTypeDetail = DataSourceTypes.find((source) => source.kind === query.kind);
|
||||
queryState[query.name] = {
|
||||
...dataSourceTypeDetail.exposedVariables,
|
||||
...this.props.currentState.queries[query.name],
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (queryConfirmationList.length !== 0) {
|
||||
useEditorStore.getState().actions.updateQueryConfirmationList(queryConfirmationList);
|
||||
}
|
||||
const variables = await this.fetchOrgEnvironmentVariables(data.slug, data.is_public);
|
||||
const constants = await this.fetchOrgEnvironmentConstants(data.slug, data.is_public);
|
||||
|
||||
const pages = data.pages;
|
||||
const homePageId = appVersionId ? data.editing_version.homePageId : data?.homePageId;
|
||||
const pages = Object.entries(data.definition.pages).map(([pageId, page]) => ({ id: pageId, ...page }));
|
||||
const homePageId = data.definition.homePageId;
|
||||
const startingPageHandle = this.props?.params?.pageHandle;
|
||||
const currentPageId = pages.filter((page) => page.handle === startingPageHandle)[0]?.id ?? homePageId;
|
||||
const currentPage = pages.find((page) => page.id === currentPageId);
|
||||
|
||||
useDataQueriesStore.getState().actions.setDataQueries(dataQueries);
|
||||
useDataQueriesStore.getState().actions.setDataQueries(data.data_queries);
|
||||
this.props.setCurrentState({
|
||||
queries: queryState,
|
||||
components: {},
|
||||
|
|
@ -172,7 +147,6 @@ class ViewerComponent extends React.Component {
|
|||
...constants,
|
||||
});
|
||||
useEditorStore.getState().actions.toggleCurrentLayout(mobileLayoutHasWidgets ? 'mobile' : 'desktop');
|
||||
this.props.updateState({ events: data.events ?? [] });
|
||||
this.setState(
|
||||
{
|
||||
currentUser,
|
||||
|
|
@ -184,24 +158,21 @@ class ViewerComponent extends React.Component {
|
|||
? `${this.state.deviceWindowWidth}px`
|
||||
: '1292px',
|
||||
selectedComponent: null,
|
||||
dataQueries: dataQueries,
|
||||
dataQueries: data.data_queries,
|
||||
currentPageId: currentPage.id,
|
||||
homepage: appDefData?.pages?.[this.state.appDefinition?.homePageId]?.handle,
|
||||
events: data.events ?? [],
|
||||
pages: {},
|
||||
homepage: this.state.appDefinition?.pages?.[this.state.appDefinition?.homePageId]?.handle,
|
||||
},
|
||||
() => {
|
||||
const components = appDefData?.pages[currentPageId]?.components || {};
|
||||
|
||||
computeComponentState(components).then(async () => {
|
||||
this.setState({ initialComputationOfStateDone: true, defaultComponentStateComputed: true });
|
||||
computeComponentState(this, data?.definition?.pages[currentPage.id]?.components).then(async () => {
|
||||
this.setState({ initialComputationOfStateDone: true });
|
||||
console.log('Default component state computed and set');
|
||||
this.runQueries(dataQueries);
|
||||
|
||||
const currentPageEvents = this.state.events.filter(
|
||||
(event) => event.target === 'page' && event.sourceId === this.state.currentPageId
|
||||
);
|
||||
|
||||
await this.handleEvent('onPageLoad', currentPageEvents);
|
||||
this.runQueries(data.data_queries);
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
@ -210,7 +181,7 @@ class ViewerComponent extends React.Component {
|
|||
runQueries = (data_queries) => {
|
||||
data_queries.forEach((query) => {
|
||||
if (query.options.runOnPageLoad && isQueryRunnable(query)) {
|
||||
runQuery(this.getViewerRef(), query.id, query.name, undefined, 'view');
|
||||
runQuery(this, query.id, query.name, undefined, 'view');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -266,34 +237,34 @@ class ViewerComponent extends React.Component {
|
|||
return variables;
|
||||
};
|
||||
|
||||
loadApplicationBySlug = (slug) => {
|
||||
appService
|
||||
.fetchAppBySlug(slug)
|
||||
loadApplicationBySlug = (slug, authentication_failed = false) => {
|
||||
appsService
|
||||
.getAppBySlug(slug)
|
||||
.then((data) => {
|
||||
this.setStateForApp(data, true);
|
||||
this.setStateForApp(data);
|
||||
this.setStateForContainer(data);
|
||||
this.setWindowTitle(data.name);
|
||||
})
|
||||
.catch(() => {
|
||||
.catch((error) => {
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
});
|
||||
// if (authentication_failed && error?.statusCode === 404) {
|
||||
// /* User is not authenticated. but the app url is wrong */
|
||||
toast.error("Couldn't find the app. \n Please verify the app URL again.");
|
||||
// setTimeout(() => {
|
||||
// redirectToDashboard();
|
||||
// }, 3000);
|
||||
// }
|
||||
if (authentication_failed && error?.statusCode === 404) {
|
||||
/* User is not authenticated. but the app url is wrong */
|
||||
toast.error("Couldn't find the app. \n Please verify the app URL again.");
|
||||
setTimeout(() => {
|
||||
redirectToDashboard();
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
loadApplicationByVersion = (appId, versionId) => {
|
||||
appService
|
||||
.fetchAppByVersion(appId, versionId)
|
||||
appsService
|
||||
.getAppByVersion(appId, versionId)
|
||||
.then((data) => {
|
||||
this.setStateForApp(data);
|
||||
this.setStateForContainer(data, versionId);
|
||||
this.setStateForContainer(data);
|
||||
})
|
||||
.catch(() => {
|
||||
this.setState({
|
||||
|
|
@ -355,9 +326,6 @@ class ViewerComponent extends React.Component {
|
|||
}
|
||||
};
|
||||
|
||||
updateQueryConfirmationList = (queryConfirmationList) =>
|
||||
useEditorStore.getState().actions.updateQueryConfirmationList(queryConfirmationList);
|
||||
|
||||
componentDidMount() {
|
||||
this.setupViewer();
|
||||
const isMobileDevice = this.state.deviceWindowWidth < 600;
|
||||
|
|
@ -415,14 +383,15 @@ class ViewerComponent extends React.Component {
|
|||
name: targetPage.name,
|
||||
},
|
||||
async () => {
|
||||
computeComponentState(this.state.appDefinition?.pages[this.state.currentPageId].components).then(async () => {
|
||||
// eslint-disable-next-line no-unsafe-optional-chaining
|
||||
const currentPageEvents = this.state.events.filter(
|
||||
(event) => event.target === 'page' && event.sourceId === this.state.currentPageId
|
||||
);
|
||||
|
||||
await this.handleEvent('onPageLoad', currentPageEvents);
|
||||
});
|
||||
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);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -472,8 +441,7 @@ class ViewerComponent extends React.Component {
|
|||
switchPage = (id, queryParams = []) => {
|
||||
document.getElementById('real-canvas').scrollIntoView();
|
||||
/* Keep default query params for preview */
|
||||
// const defaultParams = getPreviewQueryParams();
|
||||
const defaultParams = '';
|
||||
const defaultParams = getPreviewQueryParams();
|
||||
|
||||
if (this.state.currentPageId === id) return;
|
||||
|
||||
|
|
@ -493,20 +461,7 @@ class ViewerComponent extends React.Component {
|
|||
);
|
||||
};
|
||||
|
||||
getViewerRef() {
|
||||
return {
|
||||
appDefinition: this.state.appDefinition,
|
||||
queryConfirmationList: this.props.queryConfirmationList,
|
||||
updateQueryConfirmationList: this.updateQueryConfirmationList,
|
||||
navigate: this.props.navigate,
|
||||
switchPage: this.switchPage,
|
||||
currentPageId: this.state.currentPageId,
|
||||
};
|
||||
}
|
||||
|
||||
handleEvent = (eventName, events, options) => {
|
||||
onEvent(this.getViewerRef(), eventName, events, options, 'view');
|
||||
};
|
||||
handleEvent = (eventName, options) => onEvent(this, eventName, options, 'view');
|
||||
|
||||
computeCanvasMaxWidth = () => {
|
||||
const { appDefinition } = this.state;
|
||||
|
|
@ -533,9 +488,7 @@ class ViewerComponent extends React.Component {
|
|||
deviceWindowWidth,
|
||||
defaultComponentStateComputed,
|
||||
dataQueries,
|
||||
errorAppId,
|
||||
errorVersionId,
|
||||
errorDetails,
|
||||
queryConfirmationList,
|
||||
canvasWidth,
|
||||
} = this.state;
|
||||
|
||||
|
|
@ -543,8 +496,6 @@ class ViewerComponent extends React.Component {
|
|||
|
||||
const canvasMaxWidth = this.computeCanvasMaxWidth();
|
||||
|
||||
const queryConfirmationList = this.props.queryConfirmationList;
|
||||
|
||||
if (this.state.app?.isLoading) {
|
||||
return (
|
||||
<div className="tooljet-logo-loader">
|
||||
|
|
@ -570,61 +521,16 @@ class ViewerComponent extends React.Component {
|
|||
</div>
|
||||
);
|
||||
} else {
|
||||
if (errorDetails) {
|
||||
this.handleError(errorDetails, errorAppId, errorVersionId);
|
||||
}
|
||||
|
||||
const pageArray = Object.values(this.state.appDefinition?.pages || {});
|
||||
//checking if page is disabled
|
||||
if (
|
||||
pageArray.find((page) => page.handle === this.props.params.pageHandle)?.disabled &&
|
||||
this.state.currentPageId !== this.state.appDefinition?.homePageId && //Prevent page crashing when home page is disabled
|
||||
this.state.appDefinition?.pages?.[this.state.appDefinition?.homePageId]
|
||||
) {
|
||||
const homeHandle = this.state.appDefinition?.pages?.[this.state.appDefinition?.homePageId]?.handle;
|
||||
let url = `/applications/${this.state.appId}/versions/${this.state.versionId}/${homeHandle}`;
|
||||
if (this.state.slug) {
|
||||
url = `/applications/${this.state.slug}/${homeHandle}`;
|
||||
}
|
||||
return <Navigate to={url} replace />;
|
||||
}
|
||||
|
||||
//checking if page exists
|
||||
if (
|
||||
!pageArray.find((page) => page.handle === this.props.params.pageHandle) &&
|
||||
this.state.appDefinition?.pages?.[this.state.appDefinition?.homePageId]
|
||||
) {
|
||||
const homeHandle = this.state.appDefinition?.pages?.[this.state.appDefinition?.homePageId]?.handle;
|
||||
let url = `/applications/${this.state.appId}/versions/${this.state.versionId}/${homeHandle}`;
|
||||
if (this.state.slug) {
|
||||
url = `/applications/${this.state.slug}/${homeHandle}`;
|
||||
}
|
||||
return <Navigate to={`${url}${this.props.params.pageHandle ? '' : window.location.search}`} replace />;
|
||||
}
|
||||
|
||||
const viewerRef = {
|
||||
appDefinition: appDefinition,
|
||||
queryConfirmationList: this.props.queryConfirmationList,
|
||||
updateQueryConfirmationList: this.updateQueryConfirmationList,
|
||||
navigate: this.props.navigate,
|
||||
switchPage: this.switchPage,
|
||||
currentPageId: this.state.currentPageId,
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="viewer wrapper">
|
||||
<Confirm
|
||||
show={queryConfirmationList.length > 0}
|
||||
message={'Do you want to run this query?'}
|
||||
onConfirm={(queryConfirmationData) =>
|
||||
onQueryConfirmOrCancel(viewerRef, queryConfirmationData, true, 'view')
|
||||
}
|
||||
onCancel={() => onQueryConfirmOrCancel(viewerRef, queryConfirmationList[0], false, 'view')}
|
||||
onConfirm={(queryConfirmationData) => onQueryConfirmOrCancel(this, queryConfirmationData, true, 'view')}
|
||||
onCancel={() => onQueryConfirmOrCancel(this, queryConfirmationList[0], false, 'view')}
|
||||
queryConfirmationData={queryConfirmationList[0]}
|
||||
key={queryConfirmationList[0]?.queryName}
|
||||
darkMode={this.props.darkMode}
|
||||
/>
|
||||
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<ViewerNavigation.Header
|
||||
showHeader={!appDefinition.globalSettings?.hideHeader && isAppLoaded}
|
||||
|
|
@ -680,7 +586,7 @@ class ViewerComponent extends React.Component {
|
|||
snapToGrid={true}
|
||||
appLoading={isLoading}
|
||||
darkMode={this.props.darkMode}
|
||||
onEvent={this.handleEvent}
|
||||
onEvent={(eventName, options) => onEvent(this, eventName, options, 'view')}
|
||||
mode="view"
|
||||
deviceWindowWidth={deviceWindowWidth}
|
||||
selectedComponent={this.state.selectedComponent}
|
||||
|
|
@ -691,9 +597,11 @@ class ViewerComponent extends React.Component {
|
|||
onComponentClick(this, id, component, 'view');
|
||||
}}
|
||||
onComponentOptionChanged={(component, optionName, value) => {
|
||||
return onComponentOptionChanged(component, optionName, value);
|
||||
return onComponentOptionChanged(this, component, optionName, value);
|
||||
}}
|
||||
onComponentOptionsChanged={onComponentOptionsChanged}
|
||||
onComponentOptionsChanged={(component, options) =>
|
||||
onComponentOptionsChanged(this, component, options)
|
||||
}
|
||||
canvasWidth={this.getCanvasWidth()}
|
||||
dataQueries={dataQueries}
|
||||
currentPageId={this.state.currentPageId}
|
||||
|
|
@ -716,24 +624,19 @@ class ViewerComponent extends React.Component {
|
|||
}
|
||||
const withStore = (Component) => (props) => {
|
||||
const currentState = useCurrentStateStore();
|
||||
const { currentLayout, queryConfirmationList } = useEditorStore(
|
||||
const { currentLayout } = useEditorStore(
|
||||
(state) => ({
|
||||
currentLayout: state?.currentLayout,
|
||||
queryConfirmationList: state?.queryConfirmationList,
|
||||
}),
|
||||
shallow
|
||||
);
|
||||
|
||||
const { updateState } = useAppDataActions();
|
||||
|
||||
return (
|
||||
<Component
|
||||
{...props}
|
||||
currentState={currentState}
|
||||
setCurrentState={currentState?.actions?.setCurrentState}
|
||||
currentLayout={currentLayout}
|
||||
updateState={updateState}
|
||||
queryConfirmationList={queryConfirmationList}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue