moved out pages from app definition

This commit is contained in:
arpitnath 2023-08-10 17:01:03 +05:30
parent 537c423e06
commit b132098c4c
14 changed files with 189 additions and 36 deletions

View file

@ -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]);

View file

@ -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;

View file

@ -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(),

View file

@ -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' }

View file

@ -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 };
};

View file

@ -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(

View file

@ -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,
},
],
})
);

View file

@ -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;
}

View file

@ -20,4 +20,7 @@ export class VersionEditDto {
@IsOptional()
@IsBoolean()
is_user_switched_version: boolean;
@IsOptional()
app_diff: any;
}

View file

@ -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)

View file

@ -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)

View file

@ -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],
})

View file

@ -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,

View 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 });
}
}