mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-24 09:28:31 +00:00
Merge branch 'appdefinition-architecture-revamp' of https://github.com/ToolJet/ToolJet into feat/react-moveable-integration
This commit is contained in:
commit
64c074aab9
16 changed files with 556 additions and 380 deletions
|
|
@ -58,7 +58,7 @@ export const CreateVersion = ({
|
|||
});
|
||||
|
||||
appVersionService
|
||||
.getOne(appId, data.id)
|
||||
.getAppVersionData(appId, data.id)
|
||||
.then((data) => {
|
||||
setAppDefinitionFromVersion(data);
|
||||
})
|
||||
|
|
|
|||
|
|
@ -484,17 +484,17 @@ export const Container = ({
|
|||
|
||||
const paramUpdated = useCallback(
|
||||
(id, param, value) => {
|
||||
if (Object.keys(value).length > 0) {
|
||||
if (Object.keys(value)?.length > 0) {
|
||||
setBoxes((boxes) =>
|
||||
update(boxes, {
|
||||
[id]: {
|
||||
$merge: {
|
||||
component: {
|
||||
...boxes[id].component,
|
||||
...boxes[id]?.component,
|
||||
definition: {
|
||||
...boxes[id].component.definition,
|
||||
...boxes[id]?.component?.definition,
|
||||
properties: {
|
||||
...boxes[id].component.definition.properties,
|
||||
...boxes?.[id]?.component?.definition?.properties,
|
||||
[param]: value,
|
||||
},
|
||||
},
|
||||
|
|
@ -505,7 +505,7 @@ export const Container = ({
|
|||
);
|
||||
}
|
||||
},
|
||||
[setBoxes]
|
||||
[boxes, setBoxes]
|
||||
);
|
||||
|
||||
const handleAddThread = async (e) => {
|
||||
|
|
|
|||
|
|
@ -55,11 +55,11 @@ import { useDataSourcesStore } from '@/_stores/dataSourcesStore';
|
|||
import { useDataQueries, useDataQueriesStore } from '@/_stores/dataQueriesStore';
|
||||
import { useAppVersionStore, useAppVersionActions, useAppVersionState } from '@/_stores/appVersionStore';
|
||||
import { useQueryPanelStore } from '@/_stores/queryPanelStore';
|
||||
import { useCurrentStateStore, useCurrentState } from '@/_stores/currentStateStore';
|
||||
import { useCurrentStateStore, useCurrentState, getCurrentState } from '@/_stores/currentStateStore';
|
||||
import { computeAppDiff, computeComponentPropertyDiff, isParamFromTableColumn, resetAllStores } from '@/_stores/utils';
|
||||
import { setCookie } from '@/_helpers/cookie';
|
||||
import { useEditorActions, useEditorState, useEditorStore } from '@/_stores/editorStore';
|
||||
import { useAppDataActions, useAppInfo } from '@/_stores/appDataStore';
|
||||
import { useAppDataActions, useAppInfo, useAppDataStore } from '@/_stores/appDataStore';
|
||||
import { useMounted } from '@/_hooks/use-mount';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { diff } from 'deep-object-diff';
|
||||
|
|
@ -81,7 +81,8 @@ const EditorComponent = (props) => {
|
|||
|
||||
const { updateState, updateAppDefinitionDiff, updateAppVersion, setIsSaving, createAppVersionEventHandlers } =
|
||||
useAppDataActions();
|
||||
const { updateEditorState, updateQueryConfirmationList, setSelectedComponents } = useEditorActions();
|
||||
const { updateEditorState, updateQueryConfirmationList, setSelectedComponents, setCurrentPageId } =
|
||||
useEditorActions();
|
||||
|
||||
const { setAppVersions } = useAppVersionActions();
|
||||
const { isVersionReleased, editingVersion, releasedVersionId } = useAppVersionState();
|
||||
|
|
@ -101,6 +102,7 @@ const EditorComponent = (props) => {
|
|||
showComments,
|
||||
showLeftSidebar,
|
||||
queryConfirmationList,
|
||||
currentPageId,
|
||||
} = useEditorState();
|
||||
|
||||
const dataQueries = useDataQueries();
|
||||
|
|
@ -121,7 +123,6 @@ const EditorComponent = (props) => {
|
|||
|
||||
const currentState = useCurrentState();
|
||||
|
||||
const [currentPageId, setCurrentPageId] = useState(null);
|
||||
const [zoomLevel, setZoomLevel] = useState(1);
|
||||
const [isQueryPaneDragging, setIsQueryPaneDragging] = useState(false);
|
||||
const [isQueryPaneExpanded, setIsQueryPaneExpanded] = useState(false); //!check where this is used
|
||||
|
|
@ -179,11 +180,16 @@ const EditorComponent = (props) => {
|
|||
updateState({
|
||||
currentUser: appUserDetails,
|
||||
});
|
||||
|
||||
useCurrentStateStore.getState().actions.setCurrentState({
|
||||
globals: {
|
||||
...currentState.globals,
|
||||
theme: { name: props?.darkMode ? 'dark' : 'light' },
|
||||
urlparams: JSON.parse(JSON.stringify(queryString.parse(props.location.search))),
|
||||
currentUser: userVars,
|
||||
/* Constant value.it will only change for viewer */
|
||||
mode: {
|
||||
value: 'edit',
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -251,7 +257,7 @@ const EditorComponent = (props) => {
|
|||
canvasContainerRef.current.scrollLeft += editorMarginLeft;
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [editorMarginLeft]);
|
||||
}, [editorMarginLeft, canvasContainerRef?.current]);
|
||||
|
||||
useEffect(() => {
|
||||
if (mounted) {
|
||||
|
|
@ -270,6 +276,18 @@ const EditorComponent = (props) => {
|
|||
}
|
||||
};
|
||||
|
||||
const getEditorRef = () => {
|
||||
const editorRef = {
|
||||
appDefinition: useEditorStore.getState().appDefinition,
|
||||
queryConfirmationList: useEditorStore.getState().queryConfirmationList,
|
||||
updateQueryConfirmationList: updateQueryConfirmationList,
|
||||
navigate: props.navigate,
|
||||
switchPage: switchPage,
|
||||
currentPageId: useEditorStore.getState().currentPageId,
|
||||
};
|
||||
return editorRef;
|
||||
};
|
||||
|
||||
const fetchApps = async (page) => {
|
||||
const { apps } = await appService.getAll(page);
|
||||
|
||||
|
|
@ -380,22 +398,15 @@ const EditorComponent = (props) => {
|
|||
threshold: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const globals = {
|
||||
...currentState.globals,
|
||||
theme: { name: props?.darkMode ? 'dark' : 'light' },
|
||||
urlparams: JSON.parse(JSON.stringify(queryString.parse(props.location.search))),
|
||||
};
|
||||
|
||||
updateState({ appId: props?.params?.id });
|
||||
useCurrentStateStore.getState().actions.setCurrentState({ globals });
|
||||
|
||||
getCanvasWidth();
|
||||
initEditorWalkThrough();
|
||||
};
|
||||
|
||||
const fetchDataQueries = async (id, selectFirstQuery = false, runQueriesOnAppLoad = false) => {
|
||||
await useDataQueriesStore.getState().actions.fetchDataQueries(id, selectFirstQuery, runQueriesOnAppLoad);
|
||||
await useDataQueriesStore
|
||||
.getState()
|
||||
.actions.fetchDataQueries(id, selectFirstQuery, runQueriesOnAppLoad, getEditorRef());
|
||||
};
|
||||
|
||||
const fetchDataSources = (id) => {
|
||||
|
|
@ -532,7 +543,7 @@ const EditorComponent = (props) => {
|
|||
};
|
||||
|
||||
const handleEvent = (eventName, event, options) => {
|
||||
return onEvent(editorRef, eventName, event, options, 'edit');
|
||||
return onEvent(getEditorRef(), eventName, event, options, 'edit');
|
||||
};
|
||||
|
||||
const handleRunQuery = (queryId, queryName) => runQuery(editorRef, queryId, queryName);
|
||||
|
|
@ -663,11 +674,12 @@ const EditorComponent = (props) => {
|
|||
|
||||
const appVersions = await appEnvironmentService.getVersionsByEnvironment(data?.id);
|
||||
setAppVersions(appVersions.appVersions);
|
||||
const currentOrgId = data?.organization_id || data?.organizationId;
|
||||
|
||||
updateState({
|
||||
slug: data.slug,
|
||||
isMaintenanceOn: data?.is_maintenance_on,
|
||||
organizationId: data?.organization_id,
|
||||
organizationId: currentOrgId,
|
||||
isPublic: data?.is_public,
|
||||
appName: data?.name,
|
||||
userId: data?.user_id,
|
||||
|
|
@ -709,7 +721,7 @@ const EditorComponent = (props) => {
|
|||
await fetchDataQueries(data.editing_version?.id, true, true);
|
||||
const currentPageEvents = data.events.filter((event) => event.target === 'page' && event.sourceId === homePageId);
|
||||
|
||||
await handleEvent('onPageLoad', currentPageEvents);
|
||||
await handleEvent('onPageLoad', currentPageEvents, {}, true);
|
||||
};
|
||||
|
||||
const fetchApp = async (startingPageHandle, onMount = false) => {
|
||||
|
|
@ -995,8 +1007,22 @@ const EditorComponent = (props) => {
|
|||
setUndoStack((prev) => prev.slice(0, prev.length - 1));
|
||||
setRedoStack((prev) => [...prev, diffToPatches(_diffPatches)]);
|
||||
|
||||
let undoOpts = optsStack.undo[optsStack.undo.length - 1];
|
||||
|
||||
if (undoOpts?.componentDeleted) {
|
||||
undoOpts = {
|
||||
componentAdded: true,
|
||||
};
|
||||
}
|
||||
|
||||
if (undoOpts?.componentAdded) {
|
||||
undoOpts = {
|
||||
componentDeleted: true,
|
||||
};
|
||||
}
|
||||
|
||||
updateState({
|
||||
appDiffOptions: optsStack.undo[optsStack.undo.length - 1],
|
||||
appDiffOptions: undoOpts,
|
||||
});
|
||||
|
||||
setOptsStack((prev) => ({
|
||||
|
|
@ -1270,10 +1296,17 @@ const EditorComponent = (props) => {
|
|||
switchPage: true,
|
||||
pageId: newPageId,
|
||||
});
|
||||
props?.navigate(`/${getWorkspaceId()}/apps/${appId}/${newHandle}`);
|
||||
};
|
||||
|
||||
const switchPage = (pageId, queryParams = []) => {
|
||||
if (currentPageId === pageId && currentState.page.handle === appDefinition?.pages[pageId]?.handle) {
|
||||
// This are fetched from store to handle runQueriesOnAppLoad
|
||||
const currentPageId = useEditorStore.getState().currentPageId;
|
||||
const appDefinition = useEditorStore.getState().appDefinition;
|
||||
const appId = useAppDataStore.getState()?.appId;
|
||||
const pageHandle = getCurrentState().pageHandle;
|
||||
|
||||
if (currentPageId === pageId && pageHandle === appDefinition?.pages[pageId]?.handle) {
|
||||
return;
|
||||
}
|
||||
const { name, handle } = appDefinition.pages[pageId];
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ export function SwitchPage({ getPages, event, handlerChanged, eventIndex, darkMo
|
|||
<div key={index} className="row input-group mt-1">
|
||||
<div className="col">
|
||||
<CodeHinter
|
||||
initialValue={event.queryParams[index][0]}
|
||||
initialValue={event?.queryParams?.[index]?.[0]}
|
||||
onChange={(value) => queryParamChangeHandler(index, 0, value)}
|
||||
mode="javascript"
|
||||
className="form-control codehinter-query-editor-input"
|
||||
|
|
@ -79,7 +79,7 @@ export function SwitchPage({ getPages, event, handlerChanged, eventIndex, darkMo
|
|||
</div>
|
||||
<div className="col">
|
||||
<CodeHinter
|
||||
initialValue={event.queryParams[index][1]}
|
||||
initialValue={event?.queryParams?.[index]?.[1]}
|
||||
onChange={(value) => queryParamChangeHandler(index, 1, value)}
|
||||
mode="javascript"
|
||||
className="form-control codehinter-query-editor-input"
|
||||
|
|
|
|||
|
|
@ -56,17 +56,16 @@ class Chart extends React.Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { dataQueries, component, paramUpdated, componentMeta, components, currentState } = this.state;
|
||||
const data = this.state.component.component.definition.properties.data;
|
||||
const { dataQueries, component, paramUpdated, componentMeta, components, currentState } = this.props;
|
||||
const data = this.props.component.component.definition.properties.data; // since component is not unmounting on every render in current scenario
|
||||
|
||||
const jsonDescription = this.state.component.component.definition.properties.jsonDescription;
|
||||
const jsonDescription = this.props.component.component.definition.properties.jsonDescription;
|
||||
|
||||
const plotFromJson = resolveReferences(
|
||||
this.state.component.component.definition.properties.plotFromJson?.value,
|
||||
this.props.component.component.definition.properties.plotFromJson?.value,
|
||||
currentState
|
||||
);
|
||||
|
||||
const chartType = this.state.component.component.definition.properties.type.value;
|
||||
const chartType = this.props.component.component.definition.properties.type.value;
|
||||
|
||||
let items = [];
|
||||
|
||||
|
|
|
|||
|
|
@ -909,7 +909,6 @@ export const EventManager = ({
|
|||
<div {...droppableProps} ref={innerRef}>
|
||||
{events.map((event, index) => {
|
||||
const actionMeta = ActionTypes.find((action) => action.id === event.event.actionId);
|
||||
|
||||
// const rowClassName = `card-body p-0 ${focusedEventIndex === index ? ' bg-azure-lt' : ''}`;
|
||||
return (
|
||||
<Draggable key={index} draggableId={`${event.eventId}-${index}`} index={index}>
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ class ViewerComponent extends React.Component {
|
|||
runQueries = (data_queries) => {
|
||||
data_queries.forEach((query) => {
|
||||
if (query.options.runOnPageLoad && isQueryRunnable(query)) {
|
||||
runQuery(this, query.id, query.name, undefined, 'view');
|
||||
runQuery(this.getViewerRef(), query.id, query.name, undefined, 'view');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
@ -553,17 +553,19 @@ class ViewerComponent extends React.Component {
|
|||
);
|
||||
};
|
||||
|
||||
handleEvent = (eventName, events, options) => {
|
||||
const { appDefinition, currentPageId } = this.state;
|
||||
const viewerRef = {
|
||||
appDefinition: appDefinition,
|
||||
getViewerRef() {
|
||||
return {
|
||||
appDefinition: this.state.appDefinition,
|
||||
queryConfirmationList: this.props.queryConfirmationList,
|
||||
updateQueryConfirmationList: this.updateQueryConfirmationList,
|
||||
navigate: this.props.navigate,
|
||||
switchPage: this.switchPage,
|
||||
currentPageId: currentPageId,
|
||||
currentPageId: this.state.currentPageId,
|
||||
};
|
||||
onEvent(viewerRef, eventName, events, options, 'view');
|
||||
}
|
||||
|
||||
handleEvent = (eventName, events, options) => {
|
||||
onEvent(this.getViewerRef(), eventName, events, options, 'view');
|
||||
};
|
||||
|
||||
computeCanvasMaxWidth = () => {
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export default function ExportAppModal({ title, show, closeModal, customClassNam
|
|||
const requestBody = {
|
||||
...appOpts,
|
||||
...(exportTjDb && { tooljet_database: tables }),
|
||||
organization_id: app.organization_id,
|
||||
organization_id: app.organization_id ?? app.organizationId,
|
||||
};
|
||||
|
||||
appService
|
||||
|
|
|
|||
|
|
@ -1703,24 +1703,34 @@ export function snapToGrid(canvasWidth, x, y) {
|
|||
return [snappedX, snappedY];
|
||||
}
|
||||
export const removeSelectedComponent = (pageId, newDefinition, selectedComponents, updateAppDefinition) => {
|
||||
selectedComponents.forEach((component) => {
|
||||
let childComponents = [];
|
||||
const toDeleteComponents = [];
|
||||
|
||||
if (newDefinition.pages[pageId].components[component.id]?.component?.component === 'Tabs') {
|
||||
childComponents = Object.keys(newDefinition.pages[pageId].components).filter((key) =>
|
||||
newDefinition.pages[pageId].components[key].parent?.startsWith(component.id)
|
||||
);
|
||||
} else {
|
||||
childComponents = Object.keys(newDefinition.pages[pageId].components).filter(
|
||||
(key) => newDefinition.pages[pageId].components[key].parent === component.id
|
||||
);
|
||||
if (selectedComponents.length < 1) return getSelectedText();
|
||||
|
||||
const { components: allComponents } = newDefinition.pages[pageId];
|
||||
|
||||
const findAllChildComponents = (componentId) => {
|
||||
if (!toDeleteComponents.includes(componentId)) {
|
||||
toDeleteComponents.push(componentId);
|
||||
|
||||
// Find the children of this component
|
||||
const children = getAllChildComponents(allComponents, componentId).map((child) => child.componentId);
|
||||
|
||||
if (children.length > 0) {
|
||||
// Recursively find children of children
|
||||
children.forEach((child) => {
|
||||
findAllChildComponents(child);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
childComponents.forEach((componentId) => {
|
||||
delete newDefinition.pages[pageId].components[componentId];
|
||||
});
|
||||
selectedComponents.forEach((component) => {
|
||||
findAllChildComponents(component.id);
|
||||
});
|
||||
|
||||
delete newDefinition.pages[pageId].components[component.id];
|
||||
toDeleteComponents.forEach((componentId) => {
|
||||
delete newDefinition.pages[pageId].components[componentId];
|
||||
});
|
||||
|
||||
updateAppDefinition(newDefinition, { componentDefinitionChanged: true, componentDeleted: true });
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export const useDataQueriesStore = create(
|
|||
...initialState,
|
||||
actions: {
|
||||
// TODO: Remove editor state while changing currentState
|
||||
fetchDataQueries: async (appVersionId, selectFirstQuery = false, runQueriesOnAppLoad = false) => {
|
||||
fetchDataQueries: async (appVersionId, selectFirstQuery = false, runQueriesOnAppLoad = false, ref) => {
|
||||
set({ loadingDataQueries: true });
|
||||
const data = await dataqueryService.getAll(appVersionId);
|
||||
set((state) => ({
|
||||
|
|
@ -62,7 +62,7 @@ export const useDataQueriesStore = create(
|
|||
}
|
||||
|
||||
// Runs query on loading application
|
||||
if (runQueriesOnAppLoad) runQueries(data.data_queries, {});
|
||||
if (runQueriesOnAppLoad) runQueries(data.data_queries, ref);
|
||||
},
|
||||
setDataQueries: (dataQueries) => set({ dataQueries }),
|
||||
deleteDataQueries: (queryId) => {
|
||||
|
|
|
|||
|
|
@ -38,57 +38,58 @@ const initialState = {
|
|||
defaultComponentStateComputed: false,
|
||||
showLeftSidebar: true,
|
||||
queryConfirmationList: [],
|
||||
currentPageId: null,
|
||||
};
|
||||
|
||||
export const useEditorStore = create(
|
||||
zustandDevTools(
|
||||
(set, get) => ({
|
||||
...initialState,
|
||||
actions: {
|
||||
setShowComments: (showComments) =>
|
||||
set({ showComments }, false, {
|
||||
type: ACTIONS.SET_HOVERED_COMPONENT,
|
||||
showComments,
|
||||
}),
|
||||
toggleComments: () =>
|
||||
set({ showComments: !get().showComments }, false, {
|
||||
type: ACTIONS.TOGGLE_COMMENTS,
|
||||
}),
|
||||
toggleCurrentLayout: (currentLayout) =>
|
||||
set({ currentLayout }, false, {
|
||||
type: ACTIONS.TOGGLE_CURRENT_LAYOUT,
|
||||
currentLayout,
|
||||
}),
|
||||
setIsEditorActive: (isEditorActive) => set(() => ({ isEditorActive })),
|
||||
updateEditorState: (state) => set((prev) => ({ ...prev, ...state })),
|
||||
updateQueryConfirmationList: (queryConfirmationList) => set({ queryConfirmationList }),
|
||||
setHoveredComponent: (hoveredComponent) =>
|
||||
set({ hoveredComponent }, false, {
|
||||
type: ACTIONS.SET_HOVERED_COMPONENT,
|
||||
hoveredComponent,
|
||||
}),
|
||||
setSelectionInProgress: (isSelectionInProgress) => {
|
||||
set(
|
||||
{
|
||||
isSelectionInProgress,
|
||||
},
|
||||
false,
|
||||
{ type: ACTIONS.SET_SELECTION_IN_PROGRESS }
|
||||
);
|
||||
},
|
||||
setSelectedComponents: (selectedComponents, isMulti = false) => {
|
||||
const newSelectedComponents = isMulti
|
||||
? [...get().selectedComponents, ...selectedComponents]
|
||||
: selectedComponents;
|
||||
|
||||
set({
|
||||
selectedComponents: newSelectedComponents,
|
||||
});
|
||||
},
|
||||
// Dev tools for this store are disabled comments since its freezing chrome tab
|
||||
(set, get) => ({
|
||||
...initialState,
|
||||
actions: {
|
||||
setShowComments: (showComments) =>
|
||||
set({ showComments }, false, {
|
||||
type: ACTIONS.SET_HOVERED_COMPONENT,
|
||||
showComments,
|
||||
}),
|
||||
toggleComments: () =>
|
||||
set({ showComments: !get().showComments }, false, {
|
||||
type: ACTIONS.TOGGLE_COMMENTS,
|
||||
}),
|
||||
toggleCurrentLayout: (currentLayout) =>
|
||||
set({ currentLayout }, false, {
|
||||
type: ACTIONS.TOGGLE_CURRENT_LAYOUT,
|
||||
currentLayout,
|
||||
}),
|
||||
setIsEditorActive: (isEditorActive) => set(() => ({ isEditorActive })),
|
||||
updateEditorState: (state) => set((prev) => ({ ...prev, ...state })),
|
||||
updateQueryConfirmationList: (queryConfirmationList) => set({ queryConfirmationList }),
|
||||
setHoveredComponent: (hoveredComponent) =>
|
||||
set({ hoveredComponent }, false, {
|
||||
type: ACTIONS.SET_HOVERED_COMPONENT,
|
||||
hoveredComponent,
|
||||
}),
|
||||
setSelectionInProgress: (isSelectionInProgress) => {
|
||||
set(
|
||||
{
|
||||
isSelectionInProgress,
|
||||
},
|
||||
false,
|
||||
{ type: ACTIONS.SET_SELECTION_IN_PROGRESS }
|
||||
);
|
||||
},
|
||||
}),
|
||||
{ name: STORE_NAME }
|
||||
)
|
||||
setSelectedComponents: (selectedComponents, isMulti = false) => {
|
||||
const newSelectedComponents = isMulti
|
||||
? [...get().selectedComponents, ...selectedComponents]
|
||||
: selectedComponents;
|
||||
|
||||
set({
|
||||
selectedComponents: newSelectedComponents,
|
||||
});
|
||||
},
|
||||
setCurrentPageId: (currentPageId) => set({ currentPageId }),
|
||||
},
|
||||
}),
|
||||
{ name: STORE_NAME }
|
||||
);
|
||||
|
||||
export const useEditorActions = () => useEditorStore((state) => state.actions);
|
||||
|
|
|
|||
|
|
@ -1,225 +0,0 @@
|
|||
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||
import { AppVersion } from '../src/entities/app_version.entity';
|
||||
import { Component } from 'src/entities/component.entity';
|
||||
import { Page } from 'src/entities/page.entity';
|
||||
import { Layout } from 'src/entities/layout.entity';
|
||||
import { EventHandler, Target } from 'src/entities/event_handler.entity';
|
||||
|
||||
export class MigrateAppsDefinitionSchemaTransition1695914619976 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
let progress = 0;
|
||||
|
||||
const entityManager = queryRunner.manager;
|
||||
|
||||
const queryBuilder = queryRunner.connection.createQueryBuilder();
|
||||
|
||||
const appVersionRepository = entityManager.getRepository(AppVersion);
|
||||
|
||||
const appVersions = await appVersionRepository.find();
|
||||
|
||||
console.log(`MigrateAppsDefinitionSchemaTransition1695902112489 Progress ${progress} %`);
|
||||
|
||||
for (const version of appVersions) {
|
||||
progress++;
|
||||
const definition = version['definition'];
|
||||
|
||||
const dataQueries = await queryBuilder
|
||||
.select()
|
||||
.from('data_queries', 'data_queries')
|
||||
.where('app_version_id = :appVersionId', { appVersionId: version.id })
|
||||
.getRawMany();
|
||||
|
||||
let updateHomepageId = null;
|
||||
|
||||
if (definition?.pages) {
|
||||
for (const pageId of Object.keys(definition?.pages)) {
|
||||
const page = definition.pages[pageId];
|
||||
|
||||
const pageEvents = page.events || [];
|
||||
|
||||
const componentEvents = [];
|
||||
|
||||
const pagePostionIntheList = Object.keys(definition?.pages).indexOf(pageId);
|
||||
|
||||
const isHompage = (definition['homePageId'] as any) === pageId;
|
||||
|
||||
const pageComponents = page.components;
|
||||
|
||||
const componentLayouts = [];
|
||||
|
||||
const mappedComponents = this.transformComponentData(pageComponents, componentEvents);
|
||||
|
||||
const newPage = entityManager.create(Page, {
|
||||
name: page.name,
|
||||
|
||||
handle: page.handle,
|
||||
|
||||
appVersionId: version.id,
|
||||
|
||||
index: pagePostionIntheList,
|
||||
});
|
||||
|
||||
const pageCreated = await entityManager.save(newPage);
|
||||
|
||||
mappedComponents.forEach((component) => {
|
||||
component.page = pageCreated;
|
||||
});
|
||||
|
||||
const savedComponents = await entityManager.save(Component, mappedComponents);
|
||||
|
||||
savedComponents.forEach((component) => {
|
||||
const componentLayout = pageComponents[component.id]['layouts'];
|
||||
|
||||
if (componentLayout) {
|
||||
for (const type in componentLayout) {
|
||||
const layout = componentLayout[type];
|
||||
|
||||
const newLayout = new Layout();
|
||||
|
||||
newLayout.type = type;
|
||||
|
||||
newLayout.top = layout.top;
|
||||
|
||||
newLayout.left = layout.left;
|
||||
|
||||
newLayout.width = layout.width;
|
||||
|
||||
newLayout.height = layout.height;
|
||||
|
||||
newLayout.component = component;
|
||||
|
||||
componentLayouts.push(newLayout);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await entityManager.save(Layout, componentLayouts);
|
||||
|
||||
if (pageEvents.length > 0) {
|
||||
pageEvents.forEach(async (event, index) => {
|
||||
const newEvent = {
|
||||
name: event.eventId,
|
||||
|
||||
sourceId: pageCreated.id,
|
||||
|
||||
target: Target.page,
|
||||
|
||||
event: event,
|
||||
|
||||
index: pageEvents.index || index,
|
||||
|
||||
appVersionId: version.id,
|
||||
};
|
||||
|
||||
await entityManager.save(EventHandler, newEvent);
|
||||
});
|
||||
}
|
||||
|
||||
componentEvents.forEach((eventObj) => {
|
||||
if (eventObj.event?.length === 0) return;
|
||||
|
||||
eventObj.event.forEach(async (event, index) => {
|
||||
const newEvent = {
|
||||
name: event.eventId,
|
||||
|
||||
sourceId: eventObj.componentId,
|
||||
|
||||
target: Target.component,
|
||||
|
||||
event: event,
|
||||
|
||||
index: eventObj.index || index,
|
||||
|
||||
appVersionId: version.id,
|
||||
};
|
||||
|
||||
await entityManager.save(EventHandler, newEvent);
|
||||
});
|
||||
});
|
||||
|
||||
if (isHompage) {
|
||||
updateHomepageId = pageCreated.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const dataQuery of dataQueries) {
|
||||
const queryEvents = dataQuery?.options?.events || [];
|
||||
|
||||
if (queryEvents.length > 0) {
|
||||
queryEvents.forEach(async (event, index) => {
|
||||
const newEvent = {
|
||||
name: event.eventId,
|
||||
sourceId: dataQuery.id,
|
||||
target: Target.dataQuery,
|
||||
event: event,
|
||||
index: queryEvents.index || index,
|
||||
appVersionId: version.id,
|
||||
};
|
||||
|
||||
await entityManager.save(EventHandler, newEvent);
|
||||
});
|
||||
}
|
||||
}
|
||||
console.log(
|
||||
`MigrateAppsDefinitionSchemaTransition1695902112489 Progress ${Math.round(
|
||||
(progress / appVersions.length) * 100
|
||||
)} %`
|
||||
);
|
||||
await entityManager.update(
|
||||
AppVersion,
|
||||
{ id: version.id },
|
||||
{
|
||||
homePageId: updateHomepageId,
|
||||
showViewerNavigation: definition.showViewerNavigation || true,
|
||||
globalSettings: definition.globalSettings,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private transformComponentData(data: object, componentEvents: any[]): Component[] {
|
||||
const transformedComponents: Component[] = [];
|
||||
|
||||
for (const componentId in data) {
|
||||
const componentData = data[componentId]['component'];
|
||||
|
||||
const transformedComponent: Component = new Component();
|
||||
|
||||
transformedComponent.id = componentId;
|
||||
|
||||
transformedComponent.name = componentData.name;
|
||||
|
||||
transformedComponent.type = componentData.component;
|
||||
|
||||
transformedComponent.properties = componentData.definition.properties || {};
|
||||
|
||||
transformedComponent.styles = componentData.definition.styles || {};
|
||||
|
||||
transformedComponent.validation = componentData.definition.validation || {};
|
||||
|
||||
transformedComponent.parent = data[componentId].parent || null;
|
||||
|
||||
transformedComponents.push(transformedComponent);
|
||||
|
||||
componentEvents.push({
|
||||
componentId: componentId,
|
||||
|
||||
event: componentData.definition.events,
|
||||
});
|
||||
}
|
||||
|
||||
return transformedComponents;
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DELETE FROM page');
|
||||
await queryRunner.query('DELETE FROM component');
|
||||
await queryRunner.query('DELETE FROM layout');
|
||||
await queryRunner.query('DELETE FROM event_handler');
|
||||
|
||||
await queryRunner.query('ALTER TABLE app_version DROP COLUMN IF EXISTS homePageId');
|
||||
await queryRunner.query('ALTER TABLE app_version DROP COLUMN IF EXISTS globalSettings');
|
||||
await queryRunner.query('ALTER TABLE app_version DROP COLUMN IF EXISTS showViewerNavigation');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,240 @@
|
|||
import { In, MigrationInterface, QueryRunner } from 'typeorm';
|
||||
import { AppVersion } from '../src/entities/app_version.entity';
|
||||
import { Component } from 'src/entities/component.entity';
|
||||
import { Page } from 'src/entities/page.entity';
|
||||
import { Layout } from 'src/entities/layout.entity';
|
||||
import { EventHandler, Target } from 'src/entities/event_handler.entity';
|
||||
import { DataQuery } from 'src/entities/data_query.entity';
|
||||
import { MigrationProgress, processDataInBatches } from 'src/helpers/utils.helper';
|
||||
|
||||
export class MigrateAppsDefinitionSchemaTransition1697473340856 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
// let progress = 0;
|
||||
const entityManager = queryRunner.manager;
|
||||
const appVersionRepository = entityManager.getRepository(AppVersion);
|
||||
const appVersions = await appVersionRepository.find();
|
||||
const totalApps = appVersions.length;
|
||||
|
||||
const migrationProgress = new MigrationProgress('MigrateAppsDefinitionSchemaTransition1697473340856', totalApps);
|
||||
|
||||
const batchSize = 100; // Number of apps to migrate at a time
|
||||
|
||||
await processDataInBatches(
|
||||
entityManager,
|
||||
async (entityManager, skip, take) => {
|
||||
return entityManager.find(AppVersion, {
|
||||
where: { id: In(appVersions.map((appVersion) => appVersion.id)) },
|
||||
take,
|
||||
skip,
|
||||
});
|
||||
},
|
||||
async (entityManager, versions: AppVersion[]) => {
|
||||
for (const version of versions) {
|
||||
const definition = version['definition'];
|
||||
|
||||
if (!definition) return;
|
||||
|
||||
const dataQueriesRepository = entityManager.getRepository(DataQuery);
|
||||
const dataQueries = await dataQueriesRepository.find({
|
||||
where: { appVersionId: version.id },
|
||||
});
|
||||
|
||||
let updateHomepageId = null;
|
||||
|
||||
if (definition?.pages) {
|
||||
for (const pageId of Object.keys(definition?.pages)) {
|
||||
const page = definition.pages[pageId];
|
||||
const pageEvents = page.events || [];
|
||||
const componentEvents = [];
|
||||
const pagePositionInTheList = Object.keys(definition?.pages).indexOf(pageId);
|
||||
const isHomepage = (definition['homePageId'] as any) === pageId;
|
||||
const pageComponents = page.components;
|
||||
const componentLayouts = [];
|
||||
const mappedComponents = this.transformComponentData(pageComponents, componentEvents);
|
||||
const newPage = entityManager.create(Page, {
|
||||
name: page.name,
|
||||
handle: page.handle,
|
||||
appVersionId: version.id,
|
||||
disabled: page.disabled || false,
|
||||
hidden: page.hidden || false,
|
||||
index: pagePositionInTheList,
|
||||
});
|
||||
|
||||
const pageCreated = await entityManager.save(newPage);
|
||||
mappedComponents.forEach((component) => {
|
||||
component.page = pageCreated;
|
||||
});
|
||||
|
||||
const savedComponents = await entityManager.save(Component, mappedComponents);
|
||||
|
||||
savedComponents.forEach((component) => {
|
||||
const componentLayout = pageComponents[component.id]['layouts'];
|
||||
|
||||
if (componentLayout) {
|
||||
for (const type in componentLayout) {
|
||||
const layout = componentLayout[type];
|
||||
const newLayout = new Layout();
|
||||
newLayout.type = type;
|
||||
newLayout.top = layout.top;
|
||||
newLayout.left = layout.left;
|
||||
newLayout.width = layout.width;
|
||||
newLayout.height = layout.height;
|
||||
newLayout.component = component;
|
||||
componentLayouts.push(newLayout);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await entityManager.save(Layout, componentLayouts);
|
||||
|
||||
if (pageEvents.length > 0) {
|
||||
pageEvents.forEach(async (event, index) => {
|
||||
const newEvent = {
|
||||
name: event.eventId,
|
||||
sourceId: pageCreated.id,
|
||||
target: Target.page,
|
||||
event: event,
|
||||
index: pageEvents.index || index,
|
||||
appVersionId: version.id,
|
||||
};
|
||||
|
||||
await entityManager.save(EventHandler, newEvent);
|
||||
});
|
||||
}
|
||||
|
||||
componentEvents.forEach((eventObj) => {
|
||||
if (eventObj.event?.length === 0) return;
|
||||
|
||||
eventObj.event.forEach(async (event, index) => {
|
||||
const newEvent = {
|
||||
name: event.eventId,
|
||||
sourceId: eventObj.componentId,
|
||||
target: Target.component,
|
||||
event: event,
|
||||
index: eventObj.index || index,
|
||||
appVersionId: version.id,
|
||||
};
|
||||
|
||||
await entityManager.save(EventHandler, newEvent);
|
||||
});
|
||||
});
|
||||
|
||||
savedComponents.forEach(async (component) => {
|
||||
if (component.type === 'Table') {
|
||||
const tableActions = component.properties?.actions?.value || [];
|
||||
const tableColumns = component.properties?.columns?.value || [];
|
||||
const tableActionAndColumnEvents = [];
|
||||
|
||||
tableActions.forEach((action) => {
|
||||
const actionEvents = action.events || [];
|
||||
|
||||
actionEvents.forEach((event, index) => {
|
||||
tableActionAndColumnEvents.push({
|
||||
name: event.eventId,
|
||||
sourceId: component.id,
|
||||
target: Target.tableAction,
|
||||
event: { ...event, ref: action.name },
|
||||
index: event.index ?? index,
|
||||
appVersionId: version.id,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
tableColumns.forEach((column) => {
|
||||
if (column?.columnType !== 'toggle') return;
|
||||
const columnEvents = column.events || [];
|
||||
|
||||
columnEvents.forEach((event, index) => {
|
||||
tableActionAndColumnEvents.push({
|
||||
name: event.eventId,
|
||||
sourceId: component.id,
|
||||
target: Target.tableColumn,
|
||||
event: { ...event, ref: column.name },
|
||||
index: event.index ?? index,
|
||||
appVersionId: version.id,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
await entityManager.save(EventHandler, tableActionAndColumnEvents);
|
||||
}
|
||||
});
|
||||
|
||||
if (isHomepage) {
|
||||
updateHomepageId = pageCreated.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const dataQuery of dataQueries) {
|
||||
const queryEvents = dataQuery?.options?.events || [];
|
||||
|
||||
if (queryEvents.length > 0) {
|
||||
queryEvents.forEach(async (event, index) => {
|
||||
const newEvent = {
|
||||
name: event.eventId,
|
||||
sourceId: dataQuery.id,
|
||||
target: Target.dataQuery,
|
||||
event: event,
|
||||
index: queryEvents.index || index,
|
||||
appVersionId: version.id,
|
||||
};
|
||||
|
||||
await entityManager.save(EventHandler, newEvent);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
migrationProgress.show();
|
||||
await entityManager.update(
|
||||
AppVersion,
|
||||
{ id: version.id },
|
||||
{
|
||||
homePageId: updateHomepageId,
|
||||
showViewerNavigation: definition?.showViewerNavigation || true,
|
||||
globalSettings: definition.globalSettings,
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
batchSize
|
||||
);
|
||||
}
|
||||
|
||||
private transformComponentData(data: object, componentEvents: any[]): Component[] {
|
||||
const transformedComponents: Component[] = [];
|
||||
|
||||
for (const componentId in data) {
|
||||
const componentData = data[componentId]['component'];
|
||||
|
||||
const transformedComponent: Component = new Component();
|
||||
|
||||
transformedComponent.id = componentId;
|
||||
transformedComponent.name = componentData.name;
|
||||
transformedComponent.type = componentData.component;
|
||||
transformedComponent.properties = componentData.definition.properties || {};
|
||||
transformedComponent.styles = componentData.definition.styles || {};
|
||||
transformedComponent.validation = componentData.definition.validation || {};
|
||||
transformedComponent.parent = data[componentId].parent || null;
|
||||
transformedComponents.push(transformedComponent);
|
||||
|
||||
componentEvents.push({
|
||||
componentId: componentId,
|
||||
event: componentData.definition.events,
|
||||
});
|
||||
}
|
||||
|
||||
return transformedComponents;
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query('DELETE FROM page');
|
||||
await queryRunner.query('DELETE FROM component');
|
||||
await queryRunner.query('DELETE FROM layout');
|
||||
await queryRunner.query('DELETE FROM event_handler');
|
||||
|
||||
await queryRunner.query('ALTER TABLE app_version DROP COLUMN IF EXISTS homePageId');
|
||||
await queryRunner.query('ALTER TABLE app_version DROP COLUMN IF EXISTS globalSettings');
|
||||
await queryRunner.query('ALTER TABLE app_version DROP COLUMN IF EXISTS showViewerNavigation');
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import {
|
|||
UseInterceptors,
|
||||
} from '@nestjs/common';
|
||||
import { JwtAuthGuard } from '../../src/modules/auth/jwt-auth.guard';
|
||||
import { AppAuthGuard } from 'src/modules/auth/app-auth.guard';
|
||||
import { AppsService } from '../services/apps.service';
|
||||
import { camelizeKeys, decamelizeKeys } from 'humps';
|
||||
import { AppsAbilityFactory } from 'src/modules/casl/abilities/apps-ability.factory';
|
||||
|
|
@ -101,6 +102,8 @@ export class AppsControllerV2 {
|
|||
return response;
|
||||
}
|
||||
|
||||
@UseGuards(AppAuthGuard) // This guard will allow access for unauthenticated user if the app is public
|
||||
@Get('slugs/:slug')
|
||||
async appFromSlug(@User() user, @AppDecorator() app: App) {
|
||||
if (user) {
|
||||
const ability = await this.appsAbilityFactory.appsActions(user, app.id);
|
||||
|
|
|
|||
|
|
@ -355,8 +355,6 @@ export class AppImportExportService {
|
|||
appResourceMappings.dataQueryMapping
|
||||
);
|
||||
|
||||
// !-----
|
||||
|
||||
let updateHomepageId = null;
|
||||
|
||||
if (updatedDefinition?.pages) {
|
||||
|
|
@ -381,10 +379,15 @@ export class AppImportExportService {
|
|||
handle: page.handle,
|
||||
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
|
||||
index: pagePostionIntheList,
|
||||
disabled: page.disabled || false,
|
||||
hidden: page.hidden || false,
|
||||
});
|
||||
const pageCreated = await manager.save(newPage);
|
||||
|
||||
appResourceMappings.pagesMapping[pageId] = pageCreated.id;
|
||||
|
||||
mappedComponents.forEach((component) => {
|
||||
appResourceMappings.componentsMapping[component.id] = component.id;
|
||||
component.page = pageCreated;
|
||||
});
|
||||
|
||||
|
|
@ -445,14 +448,54 @@ export class AppImportExportService {
|
|||
});
|
||||
});
|
||||
|
||||
savedComponents.forEach(async (component) => {
|
||||
if (component.type === 'Table') {
|
||||
const tableActions = component.properties?.actions?.value || [];
|
||||
const tableColumns = component.properties?.columns?.value || [];
|
||||
|
||||
const tableActionAndColumnEvents = [];
|
||||
|
||||
tableActions.forEach((action) => {
|
||||
const actionEvents = action.events || [];
|
||||
|
||||
actionEvents.forEach((event, index) => {
|
||||
tableActionAndColumnEvents.push({
|
||||
name: event.eventId,
|
||||
sourceId: component.id,
|
||||
target: Target.tableAction,
|
||||
event: { ...event, ref: action.name },
|
||||
index: event.index ?? index,
|
||||
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
tableColumns.forEach((column) => {
|
||||
if (column?.columnType !== 'toggle') return;
|
||||
const columnEvents = column.events || [];
|
||||
|
||||
columnEvents.forEach((event, index) => {
|
||||
tableActionAndColumnEvents.push({
|
||||
name: event.eventId,
|
||||
sourceId: component.id,
|
||||
target: Target.tableColumn,
|
||||
event: { ...event, ref: column.name },
|
||||
index: event.index ?? index,
|
||||
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
await manager.save(EventHandler, tableActionAndColumnEvents);
|
||||
}
|
||||
});
|
||||
|
||||
if (isHompage) {
|
||||
updateHomepageId = pageCreated.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//!----
|
||||
|
||||
await manager.update(
|
||||
AppVersion,
|
||||
{ id: appResourceMappings.appVersionMapping[importingAppVersion.id] },
|
||||
|
|
@ -464,6 +507,19 @@ export class AppImportExportService {
|
|||
}
|
||||
}
|
||||
|
||||
const appVersionIds = Object.values(appResourceMappings.appVersionMapping);
|
||||
|
||||
for (const appVersionId of appVersionIds) {
|
||||
await this.updateEventActionsForNewVersionWithNewMappingIds(
|
||||
manager,
|
||||
appVersionId,
|
||||
appResourceMappings.dataQueryMapping,
|
||||
appResourceMappings.componentsMapping,
|
||||
appResourceMappings.pagesMapping,
|
||||
isNormalizedAppDefinitionSchema
|
||||
);
|
||||
}
|
||||
|
||||
await this.setEditingVersionAsLatestVersion(manager, appResourceMappings.appVersionMapping, importingAppVersions);
|
||||
|
||||
return appResourceMappings;
|
||||
|
|
@ -576,12 +632,30 @@ export class AppImportExportService {
|
|||
appResourceMappings.dataQueryMapping = dataQueryMapping;
|
||||
}
|
||||
|
||||
for (const page of importingPages) {
|
||||
const isChildOfTabsOrCalendar = (component, allComponents = [], componentParentId = undefined) => {
|
||||
if (componentParentId) {
|
||||
const parentId = component?.parent?.split('-').slice(0, -1).join('-');
|
||||
|
||||
const parentComponent = allComponents.find((comp) => comp.id === parentId);
|
||||
|
||||
if (parentComponent) {
|
||||
return parentComponent.type === 'Tabs' || parentComponent.type === 'Calendar';
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const pagesOfAppVersion = importingPages.filter((page) => page.appVersionId === importingAppVersion.id);
|
||||
|
||||
for (const page of pagesOfAppVersion) {
|
||||
const newPage = manager.create(Page, {
|
||||
name: page.name,
|
||||
handle: page.handle,
|
||||
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
|
||||
index: page.index,
|
||||
disabled: page.disabled || false,
|
||||
hidden: page.hidden || false,
|
||||
});
|
||||
|
||||
const pageCreated = await manager.save(newPage);
|
||||
|
|
@ -599,12 +673,26 @@ export class AppImportExportService {
|
|||
for (const component of pageComponents) {
|
||||
const newComponent = new Component();
|
||||
|
||||
let parentId = component.parent ? component.parent : null;
|
||||
|
||||
const isParentTabOrCalendar = isChildOfTabsOrCalendar(component, pageComponents, parentId);
|
||||
|
||||
if (isParentTabOrCalendar) {
|
||||
const childTabId = component.parent.split('-')[component.parent.split('-').length - 1];
|
||||
const _parentId = component?.parent?.split('-').slice(0, -1).join('-');
|
||||
const mappedParentId = appResourceMappings.componentsMapping[_parentId];
|
||||
|
||||
parentId = `${mappedParentId}-${childTabId}`;
|
||||
} else {
|
||||
parentId = appResourceMappings.componentsMapping[parentId];
|
||||
}
|
||||
|
||||
newComponent.name = component.name;
|
||||
newComponent.type = component.type;
|
||||
newComponent.properties = component.properties;
|
||||
newComponent.styles = component.styles;
|
||||
newComponent.validation = component.validation;
|
||||
newComponent.parent = component.parent || null;
|
||||
newComponent.parent = component.parent ? parentId : null;
|
||||
|
||||
newComponent.page = pageCreated;
|
||||
|
||||
|
|
@ -629,14 +717,14 @@ export class AppImportExportService {
|
|||
|
||||
if (componentEvents.length > 0) {
|
||||
componentEvents.forEach(async (componentEvent) => {
|
||||
const newEvent = {
|
||||
name: componentEvent.name,
|
||||
sourceId: savedComponent.id,
|
||||
target: componentEvent.target,
|
||||
event: componentEvent.event,
|
||||
index: componentEvent.index,
|
||||
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
|
||||
};
|
||||
const newEvent = new EventHandler();
|
||||
newEvent.name = componentEvent.name;
|
||||
newEvent.sourceId = savedComponent.id;
|
||||
newEvent.target = componentEvent.target;
|
||||
newEvent.event = componentEvent.event;
|
||||
newEvent.index = componentEvent.index;
|
||||
newEvent.appVersionId = appResourceMappings.appVersionMapping[importingAppVersion.id];
|
||||
|
||||
await manager.save(EventHandler, newEvent);
|
||||
});
|
||||
}
|
||||
|
|
@ -675,18 +763,11 @@ export class AppImportExportService {
|
|||
|
||||
if (importingQueryEvents.length > 0) {
|
||||
importingQueryEvents.forEach(async (dataQueryEvent) => {
|
||||
const updatedEventDefinition = this.updateEventActionsForNewVersionWithNewMappingIds(
|
||||
dataQueryEvent,
|
||||
appResourceMappings.dataQueryMapping,
|
||||
appResourceMappings.componentsMapping,
|
||||
appResourceMappings.pagesMapping
|
||||
);
|
||||
|
||||
const newEvent = {
|
||||
name: dataQueryEvent.name,
|
||||
sourceId: mappedNewDataQuery.id,
|
||||
target: dataQueryEvent.target,
|
||||
event: updatedEventDefinition,
|
||||
event: dataQueryEvent.event,
|
||||
index: dataQueryEvent.index,
|
||||
appVersionId: appResourceMappings.appVersionMapping[importingAppVersion.id],
|
||||
};
|
||||
|
|
@ -698,18 +779,11 @@ export class AppImportExportService {
|
|||
delete mappedNewDataQuery?.options?.events;
|
||||
|
||||
queryEvents.forEach(async (event, index) => {
|
||||
const updatedEventDefinition = this.updateEventActionsForNewVersionWithNewMappingIds(
|
||||
{ event: event },
|
||||
appResourceMappings.dataQueryMapping,
|
||||
appResourceMappings.componentsMapping,
|
||||
appResourceMappings.pagesMapping
|
||||
);
|
||||
|
||||
const newEvent = {
|
||||
name: event.eventId,
|
||||
sourceId: mappedNewDataQuery.id,
|
||||
target: Target.dataQuery,
|
||||
event: updatedEventDefinition,
|
||||
event: event,
|
||||
index: queryEvents.index || index,
|
||||
appVersionId: mappedNewDataQuery.appVersionId,
|
||||
};
|
||||
|
|
@ -1374,29 +1448,39 @@ export class AppImportExportService {
|
|||
return { ...queryOptions, table_id: tooljetDatabaseMapping[queryOptions.table_id]?.id };
|
||||
}
|
||||
|
||||
updateEventActionsForNewVersionWithNewMappingIds(
|
||||
queryEvent: EventHandler | { event: any },
|
||||
async updateEventActionsForNewVersionWithNewMappingIds(
|
||||
manager: EntityManager,
|
||||
versionId: string,
|
||||
oldDataQueryToNewMapping: Record<string, unknown>,
|
||||
oldComponentToNewComponentMapping: Record<string, unknown>,
|
||||
oldPageToNewPageMapping: Record<string, unknown>
|
||||
oldPageToNewPageMapping: Record<string, unknown>,
|
||||
isNormalizedAppDefinitionSchema: boolean
|
||||
) {
|
||||
const event = JSON.parse(JSON.stringify(queryEvent));
|
||||
if (!isNormalizedAppDefinitionSchema) return;
|
||||
|
||||
const eventDefinition = event.event;
|
||||
const allEvents = await manager.find(EventHandler, {
|
||||
where: { appVersionId: versionId },
|
||||
});
|
||||
|
||||
if (eventDefinition?.actionId === 'run-query') {
|
||||
eventDefinition.queryId = oldDataQueryToNewMapping[eventDefinition.queryId];
|
||||
for (const event of allEvents) {
|
||||
const eventDefinition = event.event;
|
||||
|
||||
if (eventDefinition?.actionId === 'run-query') {
|
||||
eventDefinition.queryId = oldDataQueryToNewMapping[eventDefinition.queryId];
|
||||
}
|
||||
|
||||
if (eventDefinition?.actionId === 'control-component') {
|
||||
eventDefinition.componentId = oldComponentToNewComponentMapping[eventDefinition.componentId];
|
||||
}
|
||||
|
||||
if (eventDefinition?.actionId === 'switch-page') {
|
||||
eventDefinition.pageId = oldPageToNewPageMapping[eventDefinition.pageId];
|
||||
}
|
||||
|
||||
event.event = eventDefinition;
|
||||
|
||||
await manager.save(event);
|
||||
}
|
||||
|
||||
if (eventDefinition?.actionId === 'control-component') {
|
||||
eventDefinition.componentId = oldComponentToNewComponentMapping[eventDefinition.componentId];
|
||||
}
|
||||
|
||||
if (eventDefinition?.actionId === 'switch-page') {
|
||||
eventDefinition.pageId = oldPageToNewPageMapping[eventDefinition.pageId];
|
||||
}
|
||||
|
||||
return eventDefinition;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -459,12 +459,28 @@ export class AppsService {
|
|||
const oldComponentToNewComponentMapping = {};
|
||||
const oldPageToNewPageMapping = {};
|
||||
|
||||
const isChildOfTabsOrCalendar = (component, allComponents = [], componentParentId = undefined) => {
|
||||
if (componentParentId) {
|
||||
const parentId = component?.parent?.split('-').slice(0, -1).join('-');
|
||||
|
||||
const parentComponent = allComponents.find((comp) => comp.id === parentId);
|
||||
|
||||
if (parentComponent) {
|
||||
return parentComponent.type === 'Tabs' || parentComponent.type === 'Calendar';
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
for (const page of pages) {
|
||||
const savedPage = await manager.save(
|
||||
manager.create(Page, {
|
||||
name: page.name,
|
||||
handle: page.handle,
|
||||
index: page.index,
|
||||
disabled: page.disabled,
|
||||
hidden: page.hidden,
|
||||
appVersionId: appVersion.id,
|
||||
})
|
||||
);
|
||||
|
|
@ -497,13 +513,27 @@ export class AppsService {
|
|||
|
||||
oldComponentToNewComponentMapping[component.id] = newComponent.id;
|
||||
|
||||
let parentId = component.parent ? component.parent : null;
|
||||
|
||||
const isParentTabOrCalendar = isChildOfTabsOrCalendar(component, page.components, parentId);
|
||||
|
||||
if (isParentTabOrCalendar) {
|
||||
const childTabId = component.parent.split('-')[component.parent.split('-').length - 1];
|
||||
const _parentId = component?.parent?.split('-').slice(0, -1).join('-');
|
||||
const mappedParentId = oldComponentToNewComponentMapping[_parentId];
|
||||
|
||||
parentId = `${mappedParentId}-${childTabId}`;
|
||||
} else {
|
||||
parentId = oldComponentToNewComponentMapping[parentId];
|
||||
}
|
||||
|
||||
newComponent.name = component.name;
|
||||
newComponent.type = component.type;
|
||||
newComponent.pageId = savedPage.id;
|
||||
newComponent.properties = component.properties;
|
||||
newComponent.styles = component.styles;
|
||||
newComponent.validation = component.validation;
|
||||
newComponent.parent = component.parent ? oldComponentToNewComponentMapping[component.parent] : null;
|
||||
newComponent.parent = component.parent ? parentId : null;
|
||||
newComponent.page = savedPage;
|
||||
|
||||
newComponents.push(newComponent);
|
||||
|
|
|
|||
Loading…
Reference in a new issue