import { Injectable, NotFoundException } from '@nestjs/common'; import { TenantDatabaseService } from '../tenant/tenant-database.service'; import { App } from '../models/app.model'; import { AppPage } from '../models/app-page.model'; import { ObjectDefinition } from '../models/object-definition.model'; @Injectable() export class AppBuilderService { constructor(private tenantDbService: TenantDatabaseService) {} // Runtime endpoints async getApps(tenantId: string, userId: string) { const knex = await this.tenantDbService.getTenantKnex(tenantId); // For now, return all apps // In production, you'd filter by user permissions return App.query(knex).withGraphFetched('pages').orderBy('label', 'asc'); } async getApp(tenantId: string, slug: string, userId: string) { const knex = await this.tenantDbService.getTenantKnex(tenantId); const app = await App.query(knex) .findOne({ slug }) .withGraphFetched('pages'); if (!app) { throw new NotFoundException(`App ${slug} not found`); } return app; } async getPage( tenantId: string, appSlug: string, pageSlug: string, userId: string, ) { const knex = await this.tenantDbService.getTenantKnex(tenantId); const app = await this.getApp(tenantId, appSlug, userId); const page = await AppPage.query(knex).findOne({ appId: app.id, slug: pageSlug, }); if (!page) { throw new NotFoundException(`Page ${pageSlug} not found`); } return page; } // Setup endpoints async getAllApps(tenantId: string) { const knex = await this.tenantDbService.getTenantKnex(tenantId); return App.query(knex).withGraphFetched('pages').orderBy('label', 'asc'); } async getAppForSetup(tenantId: string, slug: string) { const knex = await this.tenantDbService.getTenantKnex(tenantId); const app = await App.query(knex) .findOne({ slug }) .withGraphFetched('pages'); if (!app) { throw new NotFoundException(`App ${slug} not found`); } return app; } async createApp( tenantId: string, data: { slug: string; label: string; description?: string; }, ) { const knex = await this.tenantDbService.getTenantKnex(tenantId); return App.query(knex).insert({ ...data, displayOrder: 0, }); } async updateApp( tenantId: string, slug: string, data: { label?: string; description?: string; }, ) { const knex = await this.tenantDbService.getTenantKnex(tenantId); const app = await this.getAppForSetup(tenantId, slug); return App.query(knex).patchAndFetchById(app.id, data); } async createPage( tenantId: string, appSlug: string, data: { slug: string; label: string; type: string; objectApiName?: string; sortOrder?: number; }, ) { const knex = await this.tenantDbService.getTenantKnex(tenantId); const app = await this.getAppForSetup(tenantId, appSlug); return AppPage.query(knex).insert({ appId: app.id, slug: data.slug, label: data.label, type: data.type, objectApiName: data.objectApiName, displayOrder: data.sortOrder || 0, }); } async updatePage( tenantId: string, appSlug: string, pageSlug: string, data: { label?: string; type?: string; objectApiName?: string; sortOrder?: number; }, ) { const knex = await this.tenantDbService.getTenantKnex(tenantId); const app = await this.getAppForSetup(tenantId, appSlug); const page = await AppPage.query(knex).findOne({ appId: app.id, slug: pageSlug, }); if (!page) { throw new NotFoundException(`Page ${pageSlug} not found`); } return AppPage.query(knex).patchAndFetchById(page.id, { ...data, displayOrder: data.sortOrder, }); } }