mirror of
https://github.com/ToolJet/ToolJet
synced 2026-05-23 17:08:34 +00:00
moved out pages from app definition
This commit is contained in:
parent
537c423e06
commit
b132098c4c
14 changed files with 189 additions and 36 deletions
|
|
@ -84,6 +84,7 @@ export const Container = ({
|
|||
const [newThread, addNewThread] = useState({});
|
||||
const [isContainerFocused, setContainerFocus] = useState(false);
|
||||
const [canvasHeight, setCanvasHeight] = useState(null);
|
||||
|
||||
const router = useRouter();
|
||||
const canvasRef = useRef(null);
|
||||
const focusedParentIdRef = useRef(undefined);
|
||||
|
|
@ -181,7 +182,20 @@ export const Container = ({
|
|||
},
|
||||
};
|
||||
|
||||
appDefinitionChanged(newDefinition, { containerChanges: true });
|
||||
//need to check if a new component is added or deleted
|
||||
|
||||
const oldComponents = appDefinition.pages[currentPageId]?.components ?? {};
|
||||
const newComponents = boxes;
|
||||
|
||||
const componendAdded = Object.keys(newComponents).length > Object.keys(oldComponents).length;
|
||||
|
||||
const opts = { containerChanges: true };
|
||||
|
||||
if (componendAdded) {
|
||||
opts.componentAdded = true;
|
||||
}
|
||||
|
||||
appDefinitionChanged(newDefinition, opts);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [boxes]);
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ 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 { computeAppDiff, resetAllStores } from '@/_stores/utils';
|
||||
import { setCookie } from '@/_helpers/cookie';
|
||||
import { shallow } from 'zustand/shallow';
|
||||
import { useEditorActions, useEditorState, useEditorStore } from '@/_stores/editorStore';
|
||||
|
|
@ -105,7 +105,7 @@ const EditorComponent = (props) => {
|
|||
const { socket } = createWebsocketConnection(props?.params?.id);
|
||||
const mounted = useMounted();
|
||||
|
||||
const { updateState, updateAppDefinitionDiff } = useAppDataActions();
|
||||
const { updateState, updateAppDefinitionDiff, updateAppVersion } = useAppDataActions();
|
||||
const { updateEditorState, updateQueryConfirmationList } = useEditorActions();
|
||||
const {
|
||||
noOfVersionsSupported,
|
||||
|
|
@ -127,7 +127,8 @@ const EditorComponent = (props) => {
|
|||
|
||||
const dataQueries = useDataQueries();
|
||||
|
||||
const { isMaintenanceOn, appId, app, currentUser, currentVersionId, appDefinitionDiff } = useAppInfo();
|
||||
const { isMaintenanceOn, appId, app, currentUser, currentVersionId, appDefinitionDiff, appDiffOptions } =
|
||||
useAppInfo();
|
||||
|
||||
const [currentPageId, setCurrentPageId] = useState(null);
|
||||
const [zoomLevel, setZoomLevel] = useState(1);
|
||||
|
|
@ -213,6 +214,7 @@ const EditorComponent = (props) => {
|
|||
if (currentUser?.current_organization_id) {
|
||||
fetchGlobalDataSources();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [JSON.stringify(currentUser?.current_organization_id)]);
|
||||
|
||||
// Handle appDefinition updates
|
||||
|
|
@ -630,6 +632,7 @@ const EditorComponent = (props) => {
|
|||
};
|
||||
|
||||
//!--------
|
||||
|
||||
const fetchApp = async (startingPageHandle) => {
|
||||
const _appId = props?.params?.id;
|
||||
|
||||
|
|
@ -638,7 +641,7 @@ const EditorComponent = (props) => {
|
|||
useAppVersionStore.getState().actions.updateReleasedVersionId(data.current_version_id);
|
||||
await fetchDataSources(data.editing_version?.id);
|
||||
await fetchDataQueries(data.editing_version?.id, true, true);
|
||||
|
||||
console.log('---piku [fetching app]---]', { data, defaultDef: defaultDefinition(props.darkMode) });
|
||||
let dataDefinition = data.definition ?? defaults(data.definition, defaultDefinition(props.darkMode));
|
||||
|
||||
const pages = Object.entries(dataDefinition.pages).map(([pageId, page]) => ({ id: pageId, ...page }));
|
||||
|
|
@ -774,6 +777,7 @@ const EditorComponent = (props) => {
|
|||
});
|
||||
|
||||
const diffPatches = diff(appDefinition, updatedAppDefinition);
|
||||
|
||||
const inversePatches = diff(updatedAppDefinition, appDefinition);
|
||||
const shouldUpdate = !_.isEmpty(diffPatches) && !isEqual(appDefinitionDiff, diffPatches);
|
||||
|
||||
|
|
@ -784,6 +788,9 @@ const EditorComponent = (props) => {
|
|||
setUndoStack((prev) => [...prev, undoPatches]);
|
||||
|
||||
updateAppDefinitionDiff(diffPatches);
|
||||
updateState({
|
||||
appDiffOptions: opts,
|
||||
});
|
||||
updateEditorState({
|
||||
isSaving: true,
|
||||
appDefinition: updatedAppDefinition,
|
||||
|
|
@ -804,13 +811,11 @@ const EditorComponent = (props) => {
|
|||
isSaving: false,
|
||||
});
|
||||
} else if (!isEmpty(props?.editingVersion)) {
|
||||
appVersionService
|
||||
.save(
|
||||
appId,
|
||||
props.editingVersion?.id,
|
||||
{ definition: appDefinition, diff: appDefinitionDiff },
|
||||
isUserSwitchedVersion
|
||||
)
|
||||
const componentDiff = computeAppDiff(appDefinitionDiff, currentPageId, appDiffOptions);
|
||||
|
||||
// console.log('---piku [componentDiff]--', componentDiff);
|
||||
|
||||
updateAppVersion(appId, props.editingVersion?.id, appDefinition, componentDiff, isUserSwitchedVersion)
|
||||
.then(() => {
|
||||
const _editingVersion = {
|
||||
...props.editingVersion,
|
||||
|
|
@ -918,6 +923,7 @@ const EditorComponent = (props) => {
|
|||
}, [JSON.stringify(undoStack), JSON.stringify(redoStack)]);
|
||||
|
||||
const componentDefinitionChanged = (componentDefinition, props) => {
|
||||
console.log('---arpit checking:::: ', { props });
|
||||
if (props?.isVersionReleased) {
|
||||
useAppVersionStore.getState().actions.enableReleasedVersionPopupState();
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -44,11 +44,12 @@ function del(appId, versionId) {
|
|||
}
|
||||
|
||||
function save(appId, versionId, values, isUserSwitchedVersion = false) {
|
||||
console.log('---piku [version saved]', { values });
|
||||
const body = { is_user_switched_version: isUserSwitchedVersion };
|
||||
if (values.definition) body['definition'] = values.definition;
|
||||
if (values.name) body['name'] = values.name;
|
||||
if (values.diff) body['app_diff'] = values.diff;
|
||||
|
||||
console.log('---arpit [app version service]', { values });
|
||||
const requestOptions = {
|
||||
method: 'PUT',
|
||||
headers: authHeader(),
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { shallow } from 'zustand/shallow';
|
||||
import { appVersionService } from '@/_services';
|
||||
import { create, zustandDevTools } from './utils';
|
||||
|
||||
const initialState = {
|
||||
|
|
@ -19,6 +19,7 @@ const initialState = {
|
|||
layouts: [],
|
||||
eventHandlers: [],
|
||||
appDefinitionDiff: null,
|
||||
appDiffOptions: {},
|
||||
};
|
||||
|
||||
export const useAppDataStore = create(
|
||||
|
|
@ -30,6 +31,14 @@ export const useAppDataStore = create(
|
|||
updateApps: (apps) => set(() => ({ apps: apps })),
|
||||
updateState: (state) => set((prev) => ({ ...prev, ...state })),
|
||||
updateAppDefinitionDiff: (appDefinitionDiff) => set(() => ({ appDefinitionDiff: appDefinitionDiff })),
|
||||
updateAppVersion: async (appId, versionId, appDefinition, appDefinitionDiff, isUserSwitchedVersion = false) => {
|
||||
return await appVersionService.save(
|
||||
appId,
|
||||
versionId,
|
||||
{ definition: appDefinition, diff: appDefinitionDiff },
|
||||
isUserSwitchedVersion
|
||||
);
|
||||
},
|
||||
},
|
||||
}),
|
||||
{ name: 'App Data Store' }
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import { create as _create } from 'zustand';
|
||||
import { devtools } from 'zustand/middleware';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import { diff } from 'deep-object-diff';
|
||||
import { componentTypes } from '@/Editor/WidgetManager/components';
|
||||
import _ from 'lodash';
|
||||
|
||||
export const zustandDevTools = (fn, options = {}) =>
|
||||
devtools(fn, { ...options, enabled: process.env.NODE_ENV === 'production' ? false : true });
|
||||
|
|
@ -21,3 +25,54 @@ export const resetAllStores = () => {
|
|||
resetter();
|
||||
}
|
||||
};
|
||||
|
||||
const defaultComponent = {
|
||||
name: '',
|
||||
properties: {},
|
||||
styles: {},
|
||||
validation: {},
|
||||
events: [],
|
||||
};
|
||||
|
||||
const updateType = Object.freeze({
|
||||
pageDefinitionChanged: 'pages',
|
||||
containerChanges: 'layout',
|
||||
componentAdded: 'components',
|
||||
componentDefinitionChanged: 'components',
|
||||
});
|
||||
|
||||
export const computeAppDiff = (appDiff, currentPageId, opts) => {
|
||||
let type;
|
||||
let updateDiff;
|
||||
|
||||
if (opts?.pageDefinitionChanged) {
|
||||
updateDiff = appDiff?.pages[currentPageId];
|
||||
|
||||
type = updateType.pageDefinitionChanged;
|
||||
} else if ((opts?.containerChanges || opts?.componentDefinitionChanged) && !opts?.componentAdded) {
|
||||
const currentPageComponents = appDiff?.pages[currentPageId]?.components;
|
||||
|
||||
updateDiff = currentPageComponents;
|
||||
type = opts?.componentDefinitionChanged ? updateType.componentDefinitionChanged : updateType.containerChanges;
|
||||
} else if (opts?.componentAdded) {
|
||||
const currentPageComponents = appDiff?.pages[currentPageId]?.components;
|
||||
|
||||
updateDiff = _.toPairs(currentPageComponents ?? []).reduce((result, [id, component]) => {
|
||||
const componentMeta = componentTypes.find((comp) => comp.component === component.component.component);
|
||||
|
||||
const metaDiff = diff(componentMeta, component.component);
|
||||
|
||||
result[id] = _.defaultsDeep(metaDiff, defaultComponent);
|
||||
|
||||
return result;
|
||||
// result[id].componentId = id;
|
||||
// return { ..._.defaultsDeep(metaDiff, defaultComponent), componentId: id };
|
||||
}, {});
|
||||
|
||||
type = updateType.componentDefinitionChanged;
|
||||
}
|
||||
|
||||
console.log('---piku [currentPageComponents]', { updateDiff, opts, type });
|
||||
|
||||
return { updateDiff, type };
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { MigrationInterface, QueryRunner, TableColumn } from 'typeorm';
|
||||
|
||||
export class UpdateAppVersionEntity1691006886775 implements MigrationInterface {
|
||||
export class UpdateAppVersionEntity1691006886222 implements MigrationInterface {
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
// Add the new columns to the app_versions table
|
||||
await queryRunner.addColumn(
|
||||
|
|
@ -17,21 +17,16 @@ export class CreatePageTable1691004576333 implements MigrationInterface {
|
|||
type: 'varchar',
|
||||
isNullable: false,
|
||||
},
|
||||
{
|
||||
name: 'page_handle',
|
||||
type: 'varchar',
|
||||
isNullable: false,
|
||||
},
|
||||
{
|
||||
name: 'app_version_id',
|
||||
type: 'uuid',
|
||||
isNullable: false,
|
||||
},
|
||||
{
|
||||
name: 'update_id',
|
||||
type: 'varchar',
|
||||
isNullable: false,
|
||||
},
|
||||
{
|
||||
name: 'last_hashed_diff',
|
||||
type: 'varchar',
|
||||
isNullable: false,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
|
|
|||
|
|
@ -28,11 +28,14 @@ import { EntityManager } from 'typeorm';
|
|||
import { ValidAppInterceptor } from 'src/interceptors/valid.app.interceptor';
|
||||
import { AppDecorator } from 'src/decorators/app.decorator';
|
||||
|
||||
import { ComponentsService } from '@services/components.service';
|
||||
|
||||
@Controller('apps')
|
||||
export class AppsController {
|
||||
constructor(
|
||||
private appsService: AppsService,
|
||||
private foldersService: FoldersService,
|
||||
private componentsService: ComponentsService,
|
||||
private appsAbilityFactory: AppsAbilityFactory
|
||||
) {}
|
||||
|
||||
|
|
@ -79,11 +82,16 @@ export class AppsController {
|
|||
}
|
||||
|
||||
const response = decamelizeKeys(app);
|
||||
|
||||
const seralizedQueries = [];
|
||||
const dataQueriesForVersion = app.editingVersion
|
||||
? await this.appsService.findDataQueriesForVersion(app.editingVersion.id)
|
||||
: [];
|
||||
|
||||
const pagesForVersion = app.editingVersion ? await this.appsService.findPagesForVersion(app.editingVersion.id) : [];
|
||||
|
||||
console.log('------arpit [pagesforVersion]', { pagesForVersion });
|
||||
|
||||
// serialize queries
|
||||
for (const query of dataQueriesForVersion) {
|
||||
const decamelizedQuery = decamelizeKeys(query);
|
||||
|
|
@ -93,6 +101,7 @@ export class AppsController {
|
|||
|
||||
response['data_queries'] = seralizedQueries;
|
||||
response['definition'] = app.editingVersion?.definition;
|
||||
response['pages'] = decamelizeKeys(pagesForVersion);
|
||||
|
||||
//! if editing version exists, camelize the definition
|
||||
if (app.editingVersion && app.editingVersion.definition) {
|
||||
|
|
@ -311,6 +320,13 @@ export class AppsController {
|
|||
throw new ForbiddenException('You do not have permissions to perform this action');
|
||||
}
|
||||
|
||||
const updateType = versionEditDto.app_diff?.type;
|
||||
console.log('----arpit apps controller => ', { updateType });
|
||||
|
||||
// if(updateType=== 'components') {
|
||||
// await this.componentsService.createOrUpdate(versionEditDto.app_diff.components, versionId)
|
||||
// }
|
||||
|
||||
await this.appsService.updateVersion(version, versionEditDto, app.organizationId);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,4 +20,7 @@ export class VersionEditDto {
|
|||
@IsOptional()
|
||||
@IsBoolean()
|
||||
is_user_switched_version: boolean;
|
||||
|
||||
@IsOptional()
|
||||
app_diff: any;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany, JoinColumn } from 'typeorm';
|
||||
import { Page } from './page.entity';
|
||||
import { Layout } from './layout.entity';
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ export class Component {
|
|||
name: string;
|
||||
|
||||
@Column({ name: 'page_id' })
|
||||
PageId: string;
|
||||
pageId: string;
|
||||
|
||||
@Column('simple-json')
|
||||
properties: any;
|
||||
|
|
@ -23,6 +23,7 @@ export class Component {
|
|||
validations: any;
|
||||
|
||||
@ManyToOne(() => Page, (page) => page.components)
|
||||
@JoinColumn({ name: 'page_id' })
|
||||
page: Page;
|
||||
|
||||
@OneToMany(() => Layout, (layout) => layout.component)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany } from 'typeorm';
|
||||
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, OneToMany, JoinColumn } from 'typeorm';
|
||||
import { AppVersion } from './app_version.entity';
|
||||
import { Component } from './component.entity';
|
||||
|
||||
|
|
@ -10,16 +10,14 @@ export class Page {
|
|||
@Column()
|
||||
name: string;
|
||||
|
||||
@Column()
|
||||
AppVersionId: string;
|
||||
@Column({ name: 'page_handle' })
|
||||
pageHandle: string;
|
||||
|
||||
@Column()
|
||||
updateId: string;
|
||||
|
||||
@Column()
|
||||
lastHashedDiff: string;
|
||||
@Column({ name: 'app_version_id' })
|
||||
appVersionId: string;
|
||||
|
||||
@ManyToOne(() => AppVersion, (appVersion) => appVersion.pages)
|
||||
@JoinColumn({ name: 'app_version_id' })
|
||||
appVersion: AppVersion;
|
||||
|
||||
@OneToMany(() => Component, (component) => component.page)
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ import { Page } from 'src/entities/page.entity';
|
|||
import { EventHandler } from 'src/entities/event_handler.entity';
|
||||
import { Layout } from 'src/entities/layout.entity';
|
||||
|
||||
import { ComponentsService } from '@services/components.service';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([
|
||||
|
|
@ -77,6 +79,7 @@ import { Layout } from 'src/entities/layout.entity';
|
|||
PluginsService,
|
||||
PluginsHelper,
|
||||
AppEnvironmentService,
|
||||
ComponentsService,
|
||||
],
|
||||
controllers: [AppsController, AppUsersController, AppsImportExportController],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import { AppEnvironmentService } from './app_environments.service';
|
|||
import { decode } from 'js-base64';
|
||||
import { DataSourceScopes } from 'src/helpers/data_source.constants';
|
||||
import { DataBaseConstraints } from 'src/helpers/db_constraints.constants';
|
||||
import { Page } from 'src/entities/page.entity';
|
||||
|
||||
@Injectable()
|
||||
export class AppsService {
|
||||
|
|
@ -117,7 +118,29 @@ export class AppsService {
|
|||
);
|
||||
|
||||
//create default app version
|
||||
await this.createVersion(user, app, 'v1', null, null, manager);
|
||||
const appVersion = await this.createVersion(user, app, 'v1', null, null, manager);
|
||||
|
||||
const defaultHomePage = await manager.save(
|
||||
manager.create(Page, {
|
||||
name: 'Home',
|
||||
pageHandle: 'home',
|
||||
appVersionId: appVersion.id,
|
||||
})
|
||||
);
|
||||
|
||||
// Set default values for app version
|
||||
appVersion.showViewerNavigation = true;
|
||||
appVersion.homePageId = defaultHomePage.id;
|
||||
appVersion.globalSettings = {
|
||||
hideHeader: false,
|
||||
appInMaintenance: false,
|
||||
canvasMaxWidth: 1292,
|
||||
canvasMaxWidthType: 'px',
|
||||
canvasMaxHeight: 2400,
|
||||
canvasBackgroundColor: '#edeff5',
|
||||
backgroundFxQuery: '',
|
||||
};
|
||||
await manager.save(appVersion);
|
||||
|
||||
await manager.save(
|
||||
manager.create(AppUser, {
|
||||
|
|
@ -363,6 +386,15 @@ export class AppsService {
|
|||
});
|
||||
}
|
||||
|
||||
async findPagesForVersion(appVersionId: string): Promise<Page[]> {
|
||||
return await dbTransactionWrap(async (manager: EntityManager) => {
|
||||
return manager
|
||||
.createQueryBuilder(Page, 'pages')
|
||||
.where('pages.appVersionId = :appVersionId', { appVersionId }) // Replace 'AppVersionId' with the actual column name
|
||||
.getMany();
|
||||
});
|
||||
}
|
||||
|
||||
async createNewDataSourcesAndQueriesForVersion(
|
||||
manager: EntityManager,
|
||||
appVersion: AppVersion,
|
||||
|
|
|
|||
20
server/src/services/components.service.ts
Normal file
20
server/src/services/components.service.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Component } from 'src/entities/component.entity'; // Adjust the import path as per your project structure
|
||||
|
||||
@Injectable()
|
||||
export class ComponentsService {
|
||||
constructor(
|
||||
@InjectRepository(Component)
|
||||
private componentsRepository: Repository<Component>
|
||||
) {}
|
||||
|
||||
async findOne(id: string): Promise<Component> {
|
||||
return this.componentsRepository.findOne(id);
|
||||
}
|
||||
|
||||
async createOrUpdate(componentDiff: any) {
|
||||
console.log('----arpit:::: component service', { componentDiff });
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue