diff --git a/frontend/src/Editor/Container.jsx b/frontend/src/Editor/Container.jsx index 74c812d46e..3362897c45 100644 --- a/frontend/src/Editor/Container.jsx +++ b/frontend/src/Editor/Container.jsx @@ -60,6 +60,8 @@ export const Container = ({ [JSON.stringify(appDefinition), currentPageId] ); + console.log('----mohaaan components', { components }); + const currentState = useCurrentState(); const { appVersionsId, enableReleasedVersionPopupState, isVersionReleased } = useAppVersionStore( (state) => ({ diff --git a/frontend/src/Editor/EditorFunc.jsx b/frontend/src/Editor/EditorFunc.jsx index 2e2e058c49..b2460694e6 100644 --- a/frontend/src/Editor/EditorFunc.jsx +++ b/frontend/src/Editor/EditorFunc.jsx @@ -66,6 +66,7 @@ import { useAppDataActions, useAppDataStore, useAppInfo } from '@/_stores/appDat import { useMounted } from '@/_hooks/use-mount'; // eslint-disable-next-line import/no-unresolved import { diff } from 'deep-object-diff'; +import { camelizeKeys } from 'humps'; setAutoFreeze(false); enablePatches(); @@ -226,6 +227,7 @@ const EditorComponent = (props) => { } if (mounted && didAppDefinitionChanged && currentPageId) { + console.log('----mohaaan: useEffecr', { appDefinition }); const components = appDefinition?.pages[currentPageId]?.components || {}; computeComponentState(components); @@ -345,13 +347,9 @@ const EditorComponent = (props) => { theme: { name: props?.darkMode ? 'dark' : 'light' }, urlparams: JSON.parse(JSON.stringify(queryString.parse(props.location.search))), }; - const page = { - ...props?.currentState?.page, - handle: props?.pageHandle, - variables: {}, - }; + updateState({ appId: props?.params?.id }); - useCurrentStateStore.getState().actions.setCurrentState({ globals, page }); + useCurrentStateStore.getState().actions.setCurrentState({ globals }); }; const fetchDataQueries = async (id, selectFirstQuery = false, runQueriesOnAppLoad = false) => { @@ -632,6 +630,29 @@ const EditorComponent = (props) => { }; //!-------- + const buildAppDefinition = (data) => { + const editingVersion = _.omit(camelizeKeys(data.editing_version), ['definition', 'updatedAt', 'createdAt', 'name']); + + editingVersion['currentVersionId'] = editingVersion.id; + _.unset(editingVersion, 'id'); + + const pages = data.pages.reduce((acc, page) => { + acc[page.id] = page; + + return acc; + }, {}); + + const appJSON = { + globalSettings: editingVersion.globalSettings, + homePageId: editingVersion.homePageId, + showHideViewerNavigation: editingVersion.showHideViewerNavigation ?? true, + pages: pages, + }; + + return appJSON; + }; + + //****** */ const fetchApp = async (startingPageHandle) => { const _appId = props?.params?.id; @@ -641,12 +662,30 @@ 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 appDefData = buildAppDefinition(data); - const pages = Object.entries(dataDefinition.pages).map(([pageId, page]) => ({ id: pageId, ...page })); + // let dataDefinition = data.definition ?? defaults(data.definition, defaultDefinition(props.darkMode)); + + // const pages = Object.entries(dataDefinition.pages).map(([pageId, page]) => ({ id: pageId, ...page })); + // const startingPageId = pages.filter((page) => page.handle === startingPageHandle)[0]?.id; + // const homePageId = !startingPageHandle || startingPageId === 'null' ? dataDefinition.homePageId : startingPageId; + + // !------ + const appJson = appDefData; + const pages = data.pages; const startingPageId = pages.filter((page) => page.handle === startingPageHandle)[0]?.id; - const homePageId = !startingPageHandle || startingPageId === 'null' ? dataDefinition.homePageId : startingPageId; + const homePageId = !startingPageId || startingPageId === 'null' ? appJson.homePageId : startingPageId; + + const currentComponents = appJson.pages[homePageId]?.components ?? {}; + console.log('---piku [fetching app] [pages] ==> ', { currentComponents }); + const currentpageData = { + handle: appJson.pages[homePageId]?.handle, + name: appJson.pages[homePageId]?.name, + id: homePageId, + variables: {}, + }; + + // !------ setCurrentPageId(homePageId); @@ -662,20 +701,15 @@ const EditorComponent = (props) => { }); useCurrentStateStore.getState().actions.setCurrentState({ - page: { - handle: dataDefinition.pages[homePageId]?.handle, - name: dataDefinition.pages[homePageId]?.name, - id: homePageId, - variables: {}, - }, + page: currentpageData, }); updateEditorState({ isLoading: false, - appDefinition: dataDefinition, + appDefinition: appJson, }); - for (const event of dataDefinition.pages[homePageId]?.events ?? []) { + for (const event of appJson.pages[homePageId]?.events ?? []) { await handleEvent(event.eventId, event); } getCanvasWidth(); @@ -813,9 +847,7 @@ const EditorComponent = (props) => { } else if (!isEmpty(props?.editingVersion)) { const componentDiff = computeAppDiff(appDefinitionDiff, currentPageId, appDiffOptions); - // console.log('---piku [componentDiff]--', componentDiff); - - updateAppVersion(appId, props.editingVersion?.id, appDefinition, componentDiff, isUserSwitchedVersion) + updateAppVersion(appId, props.editingVersion?.id, currentPageId, componentDiff, isUserSwitchedVersion) .then(() => { const _editingVersion = { ...props.editingVersion, diff --git a/frontend/src/Editor/LeftSidebar/SidebarInspector.jsx b/frontend/src/Editor/LeftSidebar/SidebarInspector.jsx index d2b1a8be7b..5a556c4281 100644 --- a/frontend/src/Editor/LeftSidebar/SidebarInspector.jsx +++ b/frontend/src/Editor/LeftSidebar/SidebarInspector.jsx @@ -44,6 +44,7 @@ export const LeftSidebarInspector = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [appDefinition['selectedComponent']]); const currentState = useCurrentState(); + const queries = {}; if (!_.isEmpty(dataQueries)) { diff --git a/frontend/src/_helpers/appUtils.js b/frontend/src/_helpers/appUtils.js index 75faf228c4..373a6bd57a 100644 --- a/frontend/src/_helpers/appUtils.js +++ b/frontend/src/_helpers/appUtils.js @@ -1133,7 +1133,7 @@ export function computeComponentState(components = {}) { Object.keys(components).forEach((key) => { const component = components[key]; const componentMeta = componentTypes.find((comp) => component.component.component === comp.component); - + console.log('------tj: computeComponentState', { component, currentComponents }); const existingComponentName = Object.keys(currentComponents).find((comp) => currentComponents[comp].id === key); const existingValues = currentComponents[existingComponentName]; diff --git a/frontend/src/_services/appVersion.service.js b/frontend/src/_services/appVersion.service.js index 26c6893851..07b9036bd6 100644 --- a/frontend/src/_services/appVersion.service.js +++ b/frontend/src/_services/appVersion.service.js @@ -7,6 +7,7 @@ export const appVersionService = { create, del, save, + autoSaveApp, }; function getAll(appId) { @@ -44,7 +45,7 @@ function del(appId, versionId) { } function save(appId, versionId, values, isUserSwitchedVersion = false) { - console.log('---piku [version saved]', { values }); + // 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; @@ -58,3 +59,22 @@ function save(appId, versionId, values, isUserSwitchedVersion = false) { }; return fetch(`${config.apiUrl}/apps/${appId}/versions/${versionId}`, requestOptions).then(handleResponse); } +function autoSaveApp(appId, versionId, diff, type, pageId, operation, isUserSwitchedVersion = false) { + console.log('---piku [version saved] [v2]', { operation, type, diff }); + + const OPERATION = Object.freeze({ + create: 'POST', + update: 'PUT', + delete: 'DELETE', + }); + + const body = { is_user_switched_version: isUserSwitchedVersion, pageId, diff: diff }; + + const requestOptions = { + method: OPERATION[operation], + headers: authHeader(), + credentials: 'include', + body: JSON.stringify(body), + }; + return fetch(`${config.apiUrl}/apps/${appId}/versions/${versionId}/${type}`, requestOptions).then(handleResponse); +} diff --git a/frontend/src/_stores/appDataStore.js b/frontend/src/_stores/appDataStore.js index 716672c656..778142f29b 100644 --- a/frontend/src/_stores/appDataStore.js +++ b/frontend/src/_stores/appDataStore.js @@ -31,11 +31,15 @@ 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( + updateAppVersion: async (appId, versionId, pageId, appDefinitionDiff, isUserSwitchedVersion = false) => { + // console.log('-piku :: from store', { appDefinitionDiff }); + return await appVersionService.autoSaveApp( appId, versionId, - { definition: appDefinition, diff: appDefinitionDiff }, + appDefinitionDiff.updateDiff, + appDefinitionDiff.type, + pageId, + appDefinitionDiff.operation, isUserSwitchedVersion ); }, diff --git a/frontend/src/_stores/utils.js b/frontend/src/_stores/utils.js index 0d76eecfdf..78ee079f4e 100644 --- a/frontend/src/_stores/utils.js +++ b/frontend/src/_stores/utils.js @@ -36,7 +36,7 @@ const defaultComponent = { const updateType = Object.freeze({ pageDefinitionChanged: 'pages', - containerChanges: 'layout', + containerChanges: 'components/layout', componentAdded: 'components', componentDefinitionChanged: 'components', }); @@ -44,6 +44,7 @@ const updateType = Object.freeze({ export const computeAppDiff = (appDiff, currentPageId, opts) => { let type; let updateDiff; + let operation = 'update'; if (opts?.pageDefinitionChanged) { updateDiff = appDiff?.pages[currentPageId]; @@ -64,9 +65,10 @@ export const computeAppDiff = (appDiff, currentPageId, opts) => { result[id] = _.defaultsDeep(metaDiff, defaultComponent); + result[id].layouts = appDiff.pages[currentPageId].components[id].layouts; + + operation = 'create'; return result; - // result[id].componentId = id; - // return { ..._.defaultsDeep(metaDiff, defaultComponent), componentId: id }; }, {}); type = updateType.componentDefinitionChanged; @@ -74,5 +76,5 @@ export const computeAppDiff = (appDiff, currentPageId, opts) => { console.log('---piku [currentPageComponents]', { updateDiff, opts, type }); - return { updateDiff, type }; + return { updateDiff, type, operation }; }; diff --git a/server/migrations/1691007037021-CreateLayoutTable.ts b/server/migrations/1691007037021-CreateLayoutTable.ts index aedd4e84d6..a6b9900df1 100644 --- a/server/migrations/1691007037021-CreateLayoutTable.ts +++ b/server/migrations/1691007037021-CreateLayoutTable.ts @@ -12,24 +12,31 @@ export class CreateLayoutTable1691007037021 implements MigrationInterface { isPrimary: true, default: 'gen_random_uuid()', }, - { - name: 'name', - type: 'varchar', - isNullable: false, - }, { name: 'type', - type: 'varchar', + type: 'enum', + enumName: 'layput_type', + enum: ['desktop', 'mobile'], isNullable: false, }, { name: 'top', - type: 'integer', + type: 'double precision', isNullable: false, }, { name: 'left', - type: 'integer', + type: 'double precision', + isNullable: false, + }, + { + name: 'width', + type: 'double precision', + isNullable: false, + }, + { + name: 'height', + type: 'double precision', isNullable: false, }, { diff --git a/server/src/controllers/apps.controller.ts b/server/src/controllers/apps.controller.ts index 022253f8e9..e06d0e834f 100644 --- a/server/src/controllers/apps.controller.ts +++ b/server/src/controllers/apps.controller.ts @@ -29,6 +29,7 @@ import { ValidAppInterceptor } from 'src/interceptors/valid.app.interceptor'; import { AppDecorator } from 'src/decorators/app.decorator'; import { ComponentsService } from '@services/components.service'; +import { PageService } from '@services/page.service'; @Controller('apps') export class AppsController { @@ -36,6 +37,7 @@ export class AppsController { private appsService: AppsService, private foldersService: FoldersService, private componentsService: ComponentsService, + private pageService: PageService, private appsAbilityFactory: AppsAbilityFactory ) {} @@ -88,9 +90,7 @@ export class AppsController { ? await this.appsService.findDataQueriesForVersion(app.editingVersion.id) : []; - const pagesForVersion = app.editingVersion ? await this.appsService.findPagesForVersion(app.editingVersion.id) : []; - - console.log('------arpit [pagesforVersion]', { pagesForVersion }); + const pagesForVersion = app.editingVersion ? await this.pageService.findPagesForVersion(app.editingVersion.id) : []; // serialize queries for (const query of dataQueriesForVersion) { @@ -320,16 +320,87 @@ 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) - // } + // const updateType = versionEditDto.app_diff?.type; + // console.log('----arpit apps controller => ', { updateType }); await this.appsService.updateVersion(version, versionEditDto, app.organizationId); return; } + @UseGuards(JwtAuthGuard) + @UseInterceptors(ValidAppInterceptor) + @Post(':id/versions/:versionId/components') + async createComponent( + @User() user, + @Param('id') id, + @Param('versionId') versionId, + @Body() versionEditDto: VersionEditDto + ) { + const version = await this.appsService.findVersion(versionId); + const app = version.app; + + if (app.id !== id) { + throw new BadRequestException(); + } + const ability = await this.appsAbilityFactory.appsActions(user, id); + + if (!ability.can('updateVersions', app)) { + throw new ForbiddenException('You do not have permissions to perform this action'); + } + + // const updateType = versionEditDto.app_diff?.type; + console.log('----arpit apps controller v2 => ', { versionEditDto }); + await this.componentsService.create(versionEditDto.diff, versionEditDto.pageId); + } + @UseGuards(JwtAuthGuard) + @UseInterceptors(ValidAppInterceptor) + @Put(':id/versions/:versionId/components') + async updateComponent( + @User() user, + @Param('id') id, + @Param('versionId') versionId, + @Body() versionEditDto: VersionEditDto + ) { + const version = await this.appsService.findVersion(versionId); + const app = version.app; + + if (app.id !== id) { + throw new BadRequestException(); + } + const ability = await this.appsAbilityFactory.appsActions(user, id); + + if (!ability.can('updateVersions', app)) { + throw new ForbiddenException('You do not have permissions to perform this action'); + } + + // const updateType = versionEditDto.app_diff?.type; + console.log('----arpit apps controller v2 [update] => ', { versionEditDto }); + await this.componentsService.update(versionEditDto.diff); + } + @UseGuards(JwtAuthGuard) + @UseInterceptors(ValidAppInterceptor) + @Put(':id/versions/:versionId/components/layout') + async updateComponentLayput( + @User() user, + @Param('id') id, + @Param('versionId') versionId, + @Body() versionEditDto: VersionEditDto + ) { + const version = await this.appsService.findVersion(versionId); + const app = version.app; + + if (app.id !== id) { + throw new BadRequestException(); + } + const ability = await this.appsAbilityFactory.appsActions(user, id); + + if (!ability.can('updateVersions', app)) { + throw new ForbiddenException('You do not have permissions to perform this action'); + } + + // const updateType = versionEditDto.app_diff?.type; + console.log('----arpit apps controller v2 |layput | [update] => ', { versionEditDto }); + await this.componentsService.componentLayoutChange(versionEditDto.diff); + } @UseGuards(JwtAuthGuard) @UseInterceptors(ValidAppInterceptor) diff --git a/server/src/controllers/apps.controller.v2.ts b/server/src/controllers/apps.controller.v2.ts new file mode 100644 index 0000000000..786bda3135 --- /dev/null +++ b/server/src/controllers/apps.controller.v2.ts @@ -0,0 +1,12 @@ +import { Controller } from '@nestjs/common'; +// import { JwtAuthGuard } from '../../src/modules/auth/jwt-auth.guard'; + +@Controller({ + path: 'apps', + version: '2', // Set the version to '2' +}) +export class AppsControllerV2 { + constructor(/* Add your services and dependencies here */) {} + + // Add your new version 2 methods here +} diff --git a/server/src/dto/version-edit.dto.ts b/server/src/dto/version-edit.dto.ts index 305055af69..2736652982 100644 --- a/server/src/dto/version-edit.dto.ts +++ b/server/src/dto/version-edit.dto.ts @@ -22,5 +22,9 @@ export class VersionEditDto { is_user_switched_version: boolean; @IsOptional() - app_diff: any; + diff: any; + + @IsOptional() + @IsString() + pageId: string; } diff --git a/server/src/entities/layout.entity.ts b/server/src/entities/layout.entity.ts index c0ee7ac8c6..82dea912aa 100644 --- a/server/src/entities/layout.entity.ts +++ b/server/src/entities/layout.entity.ts @@ -1,4 +1,4 @@ -import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm'; +import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm'; import { Component } from './component.entity'; @Entity({ name: 'layouts' }) @@ -6,21 +6,25 @@ export class Layout { @PrimaryGeneratedColumn('uuid') id: string; - @Column({ name: 'name' }) - name: string; - - @Column({ name: 'type' }) + @Column({ type: 'enum', enumName: 'layout_type', name: 'type', enum: ['desktop', 'mobile'] }) type: string; - @Column({ name: 'top' }) + @Column({ name: 'top', type: 'double precision' }) top: number; - @Column({ name: 'left' }) + @Column({ name: 'left', type: 'double precision' }) left: number; + @Column({ name: 'width', type: 'double precision' }) + width: number; + + @Column({ name: 'height', type: 'double precision' }) + height: number; + @Column({ name: 'component_id' }) - ComponentId: string; + componentId: string; @ManyToOne(() => Component, (component) => component.layouts) + @JoinColumn({ name: 'component_id' }) component: Component; } diff --git a/server/src/modules/apps/apps.module.ts b/server/src/modules/apps/apps.module.ts index f89d7a0dde..6923858b8b 100644 --- a/server/src/modules/apps/apps.module.ts +++ b/server/src/modules/apps/apps.module.ts @@ -39,6 +39,7 @@ import { EventHandler } from 'src/entities/event_handler.entity'; import { Layout } from 'src/entities/layout.entity'; import { ComponentsService } from '@services/components.service'; +import { PageService } from '@services/page.service'; @Module({ imports: [ @@ -80,6 +81,7 @@ import { ComponentsService } from '@services/components.service'; PluginsHelper, AppEnvironmentService, ComponentsService, + PageService, ], controllers: [AppsController, AppUsersController, AppsImportExportController], }) diff --git a/server/src/services/apps.service.ts b/server/src/services/apps.service.ts index 09193c2caf..d1bb036c18 100644 --- a/server/src/services/apps.service.ts +++ b/server/src/services/apps.service.ts @@ -386,15 +386,6 @@ export class AppsService { }); } - async findPagesForVersion(appVersionId: string): Promise { - 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, diff --git a/server/src/services/components.service.ts b/server/src/services/components.service.ts index d25bbb8cb6..07fca7f185 100644 --- a/server/src/services/components.service.ts +++ b/server/src/services/components.service.ts @@ -1,7 +1,10 @@ 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 +import { EntityManager, Repository } from 'typeorm'; +import { Component } from 'src/entities/component.entity'; +import { Layout } from 'src/entities/layout.entity'; +import { Page } from 'src/entities/page.entity'; +import { dbTransactionWrap } from 'src/helpers/utils.helper'; @Injectable() export class ComponentsService { @@ -14,7 +17,190 @@ export class ComponentsService { return this.componentsRepository.findOne(id); } - async createOrUpdate(componentDiff: any) { - console.log('----arpit:::: component service', { componentDiff }); + async create(componentDiff: object, pageId: string) { + return dbTransactionWrap(async (manager: EntityManager) => { + const page = await manager.findOne(Page, pageId); + + const newComponents = this.transformComponentData(componentDiff); + const componentLayouts = []; + + newComponents.forEach((component) => { + component.page = page; + }); + + const savedComponents = await manager.save(Component, newComponents); + + savedComponents.forEach((component) => { + const componentLayout = componentDiff[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 manager.save(Layout, componentLayouts); + + return {}; + }); + } + + async update(componentDiff: object) { + return dbTransactionWrap(async (manager) => { + for (const componentId in componentDiff) { + const { component } = componentDiff[componentId]; + + const componentData = await manager.findOne(Component, componentId); + + if (!componentData) { + return { + error: { + message: `Component with id ${componentId} does not exist`, + }, + }; + } + + const isComponentDefinitionChanged = component.definition ? true : false; + + if (isComponentDefinitionChanged) { + const updatedDefinition = component.definition; + const columnsUpdated = Object.keys(updatedDefinition); + + const newComponentData = columnsUpdated.reduce((acc, column) => { + const newColumnData = { + ...componentData[column], + ...updatedDefinition[column], + }; + + acc[column] = newColumnData; + return acc; + }, {}); + + await manager.update(Component, componentId, newComponentData); + return; + } + + await manager.update(Component, componentId, component); + + return; + } + }); + } + + async componentLayoutChange(componenstLayoutDiff: object) { + return dbTransactionWrap(async (manager: EntityManager) => { + for (const componentId in componenstLayoutDiff) { + const { layouts } = componenstLayoutDiff[componentId]; + + const componentLayout = await manager.findOne(Layout, { componentId }); + + if (!componentLayout) { + return { + error: { + message: `Component with id ${componentId} does not exist`, + }, + }; + } + + for (const type in layouts) { + const layout = { + type, + ...layouts[type], + }; + const currentLayout = Object.assign({}, componentLayout); + + const newLayout = { + ...currentLayout, + ...layout, + }; + + console.log('--arpit [layput changed]', { type, layout, componentLayout, newLayout }); + + await manager.update(Layout, { id: componentLayout.id }, newLayout); + } + } + }); + } + + async getAllComponents(pageId: string) { + // need to get all components for a page with their layouts + + return dbTransactionWrap(async (manager: EntityManager) => { + return manager + .createQueryBuilder(Component, 'component') + .leftJoinAndSelect('component.layouts', 'layout') + .where('component.pageId = :pageId', { pageId }) + .getMany() + .then((components) => { + return components.reduce((acc, component) => { + const componentId = component.id; + const componentData = component; + const componentLayout = component.layouts[0]; + + const transformedData = this.createComponentWithLayout(componentData, componentLayout); + + acc[componentId] = transformedData[componentId]; + + return acc; + }, {}); + }); + }); + } + + transformComponentData(data: object): Component[] { + const transformedComponents: Component[] = []; + + for (const componentId in data) { + const componentData = data[componentId]; + + const transformedComponent: Component = new Component(); + transformedComponent.id = componentId; + transformedComponent.name = componentData.name; + transformedComponent.properties = componentData.properties || {}; + transformedComponent.styles = componentData.styles || {}; + transformedComponent.validations = componentData.validation || {}; + + transformedComponents.push(transformedComponent); + } + + return transformedComponents; + } + + createComponentWithLayout(componentData, layoutData) { + const { id, name, properties, styles, validations } = componentData; + const { type, top, left, width, height } = layoutData; + + const componentWithLayout = { + [id]: { + component: { + name, + definition: { + properties, + styles, + validations, + }, + }, + layouts: { + [type]: { + top, + left, + width, + height, + }, + }, + }, + }; + + return componentWithLayout; } } diff --git a/server/src/services/page.service.ts b/server/src/services/page.service.ts new file mode 100644 index 0000000000..38574285f2 --- /dev/null +++ b/server/src/services/page.service.ts @@ -0,0 +1,35 @@ +import { Injectable } from '@nestjs/common'; +import { EntityManager, Repository } from 'typeorm'; +import { InjectRepository } from '@nestjs/typeorm'; + +import { Page } from 'src/entities/page.entity'; +import { ComponentsService } from './components.service'; + +@Injectable() +export class PageService { + constructor( + private readonly manager: EntityManager, + @InjectRepository(Page) + private readonly pageRepository: Repository, + + private componentsService: ComponentsService + ) {} + + async findPagesForVersion(appVersionId: string): Promise { + const allPages = await this.pageRepository.find({ appVersionId }); + + const pagesWithComponents = await Promise.all( + allPages.map(async (page) => { + const components = await this.componentsService.getAllComponents(page.id); + delete page.appVersionId; + return { ...page, components }; + }) + ); + + return pagesWithComponents; + } + + async findOne(id: string): Promise { + return this.pageRepository.findOne(id); + } +}