@solidstarters/solid-core 1.2.62 → 1.2.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidstarters/solid-core",
3
- "version": "1.2.62",
3
+ "version": "1.2.64",
4
4
  "description": "This module is a NestJS module containing all the required core providers required by a Solid application",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/interfaces.ts CHANGED
@@ -162,4 +162,8 @@ export interface QueuesModuleOptions {
162
162
  name: string;
163
163
  type: BrokerType;
164
164
  queueName: string;
165
- }
165
+ }
166
+
167
+ export type MediaWithFullUrl = Media & {
168
+ _full_url: string;
169
+ };
@@ -158,11 +158,18 @@ export class CrudHelperService {
158
158
 
159
159
  buildFilterQuery(qb: SelectQueryBuilder<any>, basicFilterDto: BasicFilterDto, entityAlias: string): SelectQueryBuilder<any> { //TODO : Check how to pass a type to SelectQueryBuilder instead of any
160
160
  let { limit, offset, showSoftDeleted, filters } = basicFilterDto;
161
- const { fields, sort, groupBy, populate = [] } = basicFilterDto;
161
+ const { fields, sort, groupBy, populate = [], populateMedia=[] } = basicFilterDto;
162
162
 
163
163
  // Normalize the fields, sort, groupBy and populate options i.e (since they can be either a string or an array of strings, when coming from the request)
164
164
  const normalizedFields = this.normalize(fields);
165
165
  const normalizedPopulate = this.normalize(populate);
166
+ const normalizedPopulateMedia = this.normalize(populateMedia);
167
+
168
+ // if normalizedPopulateMedia, has any nested media paths, then add then to populate excluding the last part
169
+ const additionalPopulate = this.additionalRelationsRequiredForMediaPopulation(normalizedPopulateMedia);
170
+ // Add the additional populate relations to the normalizedPopulate, if they are not already present
171
+ normalizedPopulate.push(...additionalPopulate.filter((relation) => !normalizedPopulate.includes(relation)));
172
+
166
173
  const normalizedSort = this.normalize(sort);
167
174
  const normalizedGroupBy = this.normalize(groupBy);
168
175
  if (normalizedGroupBy.length > 1) {
@@ -223,6 +230,17 @@ export class CrudHelperService {
223
230
  return qb;
224
231
  }
225
232
 
233
+ additionalRelationsRequiredForMediaPopulation(normalizedPopulateMedia: string[]) {
234
+ // Populate relations containing the media field
235
+ return normalizedPopulateMedia
236
+ .filter(pm => pm.includes("."))
237
+ .map((pm) => {
238
+ const mediaPathParts = pm.split('.');
239
+ if (mediaPathParts.length <= 1) return pm;
240
+ return mediaPathParts.slice(0, -1).join('.');
241
+ });
242
+ }
243
+
226
244
  private buildPopulateQuery(normalizedPopulate: string[], entityAlias: string, qb: SelectQueryBuilder<any>) {
227
245
  normalizedPopulate.forEach((relation) => {
228
246
  this.buildJoinQueryForRelation(qb, entityAlias, relation);
@@ -1,4 +1,4 @@
1
- import { BadRequestException } from "@nestjs/common";
1
+ import { BadRequestException, Optional } from "@nestjs/common";
2
2
  import { ConfigService } from "@nestjs/config";
3
3
  import { DiscoveryService, ModuleRef } from "@nestjs/core";
4
4
  import { EntityManager, In, IsNull, Not, QueryFailedError, SelectQueryBuilder } from "typeorm";
@@ -28,14 +28,13 @@ import { SelectionDynamicFieldCrudManager } from "../helpers/field-crud-managers
28
28
  import { SelectionStaticFieldCrudManager } from "../helpers/field-crud-managers/SelectionStaticFieldCrudManager";
29
29
  import { ShortTextFieldCrudManager } from "../helpers/field-crud-managers/ShortTextFieldCrudManager";
30
30
  import { UUIDFieldCrudManager } from "../helpers/field-crud-managers/UUIDFieldCrudManager";
31
- import { FieldCrudManager } from "../interfaces";
31
+ import { FieldCrudManager, MediaWithFullUrl } from "../interfaces";
32
32
  import { CrudHelperService } from "./crud-helper.service";
33
33
  import { FileService } from "./file.service";
34
34
  import { getMediaStorageProvider } from "./mediaStorageProviders";
35
35
  import { ModelMetadataService } from "./model-metadata.service";
36
36
  import { ModuleMetadataService } from "./module-metadata.service";
37
37
  import { UserContextService } from "./user-context.service";
38
- import { Optional } from "@nestjs/common";
39
38
  const DEFAULT_LIMIT = 10;
40
39
  const DEFAULT_OFFSET = 0;
41
40
  export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDto, so we get the proper types in our service
@@ -496,42 +495,85 @@ export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDt
496
495
  return r;
497
496
  }
498
497
 
499
- private async handlePopulateMedia(populateMedia: string[], entities: T[]) {
500
- const model = await this.modelMetadataService.findOneBySingularName(this.modelName, {
501
- fields: {
502
- model: true,
503
- mediaStorageProvider: true,
498
+ private async handlePopulateMedia(populateMedia: string[], entities: T[]) {
499
+ const model = await this.entityManager.getRepository(ModelMetadata).findOne({
500
+ where: {
501
+ singularName: this.modelName,
504
502
  },
505
- module: true,
503
+ relations: ['fields', 'fields.mediaStorageProvider', 'fields.model','module'],
506
504
  });
507
505
 
508
- const mediaFields = model.fields.filter(field => (field.type === 'mediaSingle' || field.type === 'mediaMultiple') && populateMedia.includes(field.name)
509
- );
510
-
511
- if (mediaFields.length > 0) {
512
- // Map over all entities and retrieve media in parallel for each entity
513
- await Promise.all(entities.map(async (entity) => {
514
- const mediaObj: Record<string, any> = {};
515
- // Retrieve media for each media field in parallel
516
- const media = await Promise.all(mediaFields.map(async (mediaField) => {
517
- const storageProviderMetadata = mediaField.mediaStorageProvider;
518
- const storageProviderType = storageProviderMetadata.type as MediaStorageProviderType;
519
- const storageProvider = await getMediaStorageProvider(this.moduleRef, storageProviderType);
520
- const mediaResult = await storageProvider.retrieve(entity, mediaField);
521
- mediaObj[mediaField.name] = mediaResult;
522
- }));
523
-
524
- // If media is found, assign to _media field
525
- if (media.length > 0) {
526
- entity['_media'] = mediaObj;
527
- }
528
- }));
506
+ // Will iterate through every entity & all populateMedia & call getMediaDetails for each field
507
+ for (const entity of entities) {
508
+ const mediaObj: Record<string, any> = {};
509
+ for (const mediaFieldPath of populateMedia) {
510
+ mediaObj[mediaFieldPath] = await this.getMediaObject(mediaFieldPath, model, entity);
511
+ }
512
+ entity['_media'] = mediaObj;
513
+ }
514
+ return entities;
515
+ }
516
+
517
+ private async getMediaObject(mediaFieldPath: string, model: ModelMetadata, entity: T) {
518
+ if (mediaFieldPath.includes('.')) { // mediaFieldPath is a nested field
519
+ const pathParts = mediaFieldPath.split('.');
520
+ const mediaFieldMetadata = await this.getFieldMetadataRecursively(pathParts, model.fields);
521
+ if (!mediaFieldMetadata) {
522
+ throw new BadRequestException(`Media field ${mediaFieldPath} not found in model ${this.modelName}`);
523
+ }
524
+
525
+ // We can assume that the media field entity model is already populated as part of the entity data
526
+ const mediaFieldEntity = this.getMediaFieldEntity(entity, pathParts);
527
+ if (!mediaFieldEntity) {
528
+ throw new BadRequestException(`Media field path ${mediaFieldPath} is not populated in model ${this.modelName}`);
529
+ }
530
+ const mediaWithFullUrl = await this.getMediaWithFullUrl(mediaFieldEntity, mediaFieldMetadata);
531
+ return mediaWithFullUrl;
532
+ }
533
+ else {
534
+ // mediaFieldPath is a single field
535
+ const mediaFieldMetadata = model.fields.find(field => field.name === mediaFieldPath);
536
+ if (!mediaFieldMetadata) {
537
+ throw new BadRequestException(`Media field ${mediaFieldPath} not found in model ${this.modelName}`);
538
+ }
539
+ const mediaWithFullUrl = await this.getMediaWithFullUrl(entity, mediaFieldMetadata);
540
+ return mediaWithFullUrl;
529
541
  }
530
542
  }
531
543
 
544
+ private getMediaFieldEntity(entity: T, mediaPathParts: string[]) {
545
+ let mediaFieldEntity = entity;
546
+ for (let i = 0; i < mediaPathParts.length - 1; i++) {
547
+ const pathPart = mediaPathParts[i];
548
+ if (mediaFieldEntity[pathPart]) {
549
+ mediaFieldEntity = mediaFieldEntity[pathPart];
550
+ } else {
551
+ throw new BadRequestException(`Media field ${pathPart} not found in entity ${JSON.stringify(entity)}`);
552
+ }
553
+ }
554
+ return mediaFieldEntity;
555
+ }
556
+
557
+ async getMediaWithFullUrl(mediaEntity: any, mediaFieldMetadata: FieldMetadata): Promise<MediaWithFullUrl>{
558
+ const storageProviderMetadata = mediaFieldMetadata.mediaStorageProvider;
559
+ const storageProviderType = storageProviderMetadata.type as MediaStorageProviderType;
560
+ const storageProvider = await getMediaStorageProvider(this.moduleRef, storageProviderType);
561
+ const mediaDetails = await storageProvider.retrieve(mediaEntity, mediaFieldMetadata);
562
+ return mediaDetails as MediaWithFullUrl;
563
+ }
564
+
532
565
  async findOne(id: number, query: any, solidRequestContext: any = {}) {
533
566
  const { populate = [], fields = [], populateMedia = [] } = query;
534
567
 
568
+ // const normalizedFields = this.crudHelperService.normalize(fields);
569
+ const normalizedPopulate = this.crudHelperService.normalize(populate);
570
+ const normalizedPopulateMedia = this.crudHelperService.normalize(populateMedia);
571
+
572
+ // if normalizedPopulateMedia, has any nested media paths, then add then to populate excluding the last part
573
+ const additionalPopulate = this.crudHelperService.additionalRelationsRequiredForMediaPopulation(normalizedPopulateMedia);
574
+ // Add the additional populate relations to the normalizedPopulate, if they are not already present
575
+ normalizedPopulate.push(...additionalPopulate.filter((relation) => !normalizedPopulate.includes(relation)));
576
+
535
577
  const model = await this.loadModel();
536
578
  // Check wheather user has update permission for model
537
579
  if (solidRequestContext.activeUser) {
@@ -541,42 +583,21 @@ export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDt
541
583
  }
542
584
  }
543
585
 
544
- const entity = await this.repo.findOne({
586
+ let entity = await this.repo.findOne({
545
587
  where: {
546
588
  //@ts-ignore
547
589
  id: id,
548
590
  },
549
- relations: populate,
591
+ relations: normalizedPopulate,
550
592
  select: fields,
551
593
  });
552
594
  if (!entity) {
553
595
  throw new Error(`Entity [${this.moduleName}.${this.modelName}] with id ${id} not found`);
554
596
  }
555
597
  // Populate the entity with the media
556
- if (populateMedia.length > 0) {
557
- const model = await this.modelMetadataService.findOneBySingularName(this.modelName, {
558
- fields: {
559
- model: true,
560
- mediaStorageProvider: true,
561
- },
562
- module: true,
563
- });
564
- const mediaObj: Record<string, any> = {};
565
- for (const mediaField of model.fields.filter(field => field.type === 'mediaSingle' || field.type === 'mediaMultiple')) {
566
- if (!populateMedia.includes(mediaField.name)) {
567
- continue;
568
- }
569
- const storageProviderMetadata = mediaField.mediaStorageProvider;
570
- const storageProviderType = storageProviderMetadata.type as MediaStorageProviderType;
571
- const storageProvider = await getMediaStorageProvider(this.moduleRef, storageProviderType);
572
- const mediaResult = await storageProvider.retrieve(entity, mediaField);
573
- let obj = { [mediaField.name]: mediaResult }
574
- mediaObj[mediaField.name] = mediaResult;
575
- // entity['media'][mediaField.name] = await storageProvider.retrieve(entity, mediaField);
576
- }
577
- if (Object.keys(mediaObj).length > 0) {
578
- entity['_media'] = mediaObj;
579
- }
598
+ if (normalizedPopulateMedia.length > 0) {
599
+ const populatedEntities = await this.handlePopulateMedia(normalizedPopulateMedia, [entity]);
600
+ entity = populatedEntities[0] as Awaited<T>;
580
601
  }
581
602
  return entity;
582
603
  }
@@ -775,4 +796,37 @@ export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDt
775
796
  }
776
797
 
777
798
 
799
+ async getFieldMetadataRecursively(pathParts: string[], fields: FieldMetadata[]) {
800
+ if (!pathParts || pathParts.length === 0) {
801
+ throw new BadRequestException('Path parts cannot be empty');
802
+ }
803
+
804
+ const [currentPart, ...remainingParts] = pathParts;
805
+ const field = fields.find(field => field.name === currentPart);
806
+
807
+ if (!field) {
808
+ throw new BadRequestException(`Field ${currentPart} not found in model ${this.modelName}`);
809
+ }
810
+
811
+ // Base case: last part, return the field
812
+ if (remainingParts.length === 0) {
813
+ return field;
814
+ }
815
+
816
+ if (!field.relationCoModelSingularName) {
817
+ throw new BadRequestException(`Field ${field.name} does not define a relationCoModelSingularName`);
818
+ }
819
+
820
+ const relationCoModel = await this.entityManager.getRepository(ModelMetadata).findOne({
821
+ where: { singularName: field.relationCoModelSingularName },
822
+ relations: ['fields', 'fields.mediaStorageProvider', 'fields.model'],
823
+ });
824
+
825
+ if (!relationCoModel) {
826
+ throw new BadRequestException(`Model ${field.relationCoModelSingularName} not found`);
827
+ }
828
+
829
+ return this.getFieldMetadataRecursively(remainingParts, relationCoModel.fields);
830
+ }
778
831
  }
832
+
@@ -232,105 +232,6 @@ export class ModelMetadataService {
232
232
  model = await manager.save(updatedModelMetadataDto);
233
233
  }
234
234
 
235
- // const modelViews = [{
236
- // name: `${model.singularName}-list-view`,
237
- // displayName: `${model.displayName}`,
238
- // type: 'list',
239
- // context: "{}",
240
- // module: resolvedModule,
241
- // model: model,
242
- // layout: JSON.stringify({
243
- // type: "list",
244
- // attrs: {
245
- // pagination: true,
246
- // pageSizeOptions: [
247
- // 10,
248
- // 25,
249
- // 50
250
- // ],
251
- // enableGlobalSearch: true,
252
- // create: true,
253
- // edit: true,
254
- // delete: true
255
- // },
256
- // children: listViewLayout
257
- // }, null, 2)
258
- // },
259
- // {
260
- // name: `${model.singularName}-form-view`,
261
- // displayName: `${model.displayName}`,
262
- // type: 'form',
263
- // context: "{}",
264
- // module: model.module,
265
- // model: model,
266
- // layout: JSON.stringify(
267
- // {
268
- // type: "form",
269
- // attrs: { name: "form-1", label: `${model.displayName}`, className: "grid" },
270
- // children: [
271
- // {
272
- // type: "sheet",
273
- // attrs: { name: "sheet-1" },
274
- // children: [
275
- // {
276
- // type: "row",
277
- // attrs: { name: "group-1", label: "", className: "" },
278
- // children: [
279
- // {
280
- // type: "column",
281
- // attrs: { name: "group-1", label: "", className: "col-6" },
282
- // children: formViewLayout
283
- // }
284
- // ]
285
- // }
286
- // ]
287
- // }
288
- // ]
289
- // }, null, 2)
290
- // }
291
- // ];
292
- // const viewRepo = manager.getRepository(ViewMetadata);
293
- // for (let j = 0; j < modelViews.length; j++) {
294
- // const view = modelViews[j];
295
- // const createdView = await viewRepo.create(view);
296
- // await viewRepo.save(createdView);
297
- // }
298
-
299
- // const view = await viewRepo.findOneBy({ name: `${model.singularName}-list-view` });
300
-
301
- // const action = {
302
- // displayName: `${model.displayName} List View`,
303
- // name: `${model.singularName}-list-view`,
304
- // type: "solid",
305
- // domain: "",
306
- // context: "",
307
- // customComponent: `/admin/address-master/${model.singularName}/all`,
308
- // customIsModal: true,
309
- // serverEndpoint: "",
310
- // view: view,
311
- // module: resolvedModule,
312
- // model: model
313
- // };
314
- // const actionRepo = manager.getRepository(ActionMetadata);
315
- // const createdAction = await actionRepo.create(action);
316
- // const newAction = await actionRepo.save(createdAction);
317
-
318
- // const adminRole = await this.roleService.findRoleByName('Admin');
319
-
320
- // const menu = {
321
- // displayName: `${model.displayName}`,
322
- // name: `${model.singularName}`,
323
- // sequenceNumber: 1,
324
- // action: newAction,
325
- // module: resolvedModule,
326
- // roles: [adminRole],
327
- // parentMenuItemUserKey: ""
328
- // };
329
-
330
- // const menuRepo = manager.getRepository(MenuItemMetadata);
331
- // const createdMenu = await menuRepo.create(menu);
332
- // await menuRepo.save(createdMenu);
333
-
334
235
  return model;
335
236
  }
336
237
 
@@ -360,122 +261,14 @@ export class ModelMetadataService {
360
261
  fields: []
361
262
  }
362
263
 
363
- const listViewLayoutFields = [{ type: "field", attrs: { name: `id`, sortable: true, filterable: true } }];
364
- const formViewLayoutFields = [];
365
-
366
264
  for (let i = 0; i < model.fields.length; i++) {
367
265
  const field = model.fields[i];
368
- if (!field.isSystem) {
369
-
370
- const fieldObject: Record<string, any> = await this.fieldMetadataService.createFieldConfig(field);
371
- modelMetaData.fields.push(fieldObject);
372
- listViewLayoutFields.push({ type: "field", attrs: { name: `${field.name}`, sortable: true, filterable: true } })
373
- formViewLayoutFields.push({ type: "field", attrs: { name: `${field.name}` } })
374
-
375
- }
376
- }
377
- const column1Fields = [];
378
- const column2Fields = [];
379
-
380
- // Distribute fields between two columns
381
- for (let i = 0; i < formViewLayoutFields.length; i++) {
382
- if (i % 2 === 0) {
383
- column1Fields.push(formViewLayoutFields[i]);
384
- } else {
385
- column2Fields.push(formViewLayoutFields[i]);
386
- }
266
+ if (field.isSystem) continue;
267
+ const fieldObject: Record<string, any> = await this.fieldMetadataService.createFieldConfig(field);
268
+ modelMetaData.fields.push(fieldObject);
387
269
  }
388
- const action = {
389
- displayName: `${model.displayName} List View`,
390
- name: `${model.singularName}-list-view`,
391
- type: "solid",
392
- domain: "",
393
- context: "",
394
- customComponent: `/admin/address-master/${model.singularName}/all`,
395
- customIsModal: true,
396
- serverEndpoint: "",
397
- viewUserKey: `${model.singularName}-list-view`,
398
- moduleUserKey: `${model.module.name}`,
399
- modelUserKey: `${model.singularName}`
400
- };
401
-
402
- const menu = {
403
- displayName: `${model.displayName}`,
404
- name: `${model.singularName}-menu-item`,
405
- sequenceNumber: 1,
406
- actionUserKey: `${model.singularName}-list-view`,
407
- moduleUserKey: `${model.module.name}`,
408
- parentMenuItemUserKey: ""
409
- };
410
-
411
- const modelListview = {
412
- name: `${model.singularName}-list-view`,
413
- displayName: `${model.displayName}`,
414
- type: "list",
415
- context: "{}",
416
- moduleUserKey: `${model.module.name}`,
417
- modelUserKey: `${model.singularName}`,
418
- layout: {
419
- type: "list",
420
- attrs: {
421
- pagination: true,
422
- pageSizeOptions: [
423
- 10,
424
- 25,
425
- 50
426
- ],
427
- enableGlobalSearch: true,
428
- create: true,
429
- edit: true,
430
- delete: true
431
- },
432
- children: listViewLayoutFields
433
- }
434
- };
435
-
436
-
437
- const modelFormView = {
438
- name: `${model.singularName}-form-view`,
439
- displayName: `${model.displayName}`,
440
- type: "form",
441
- context: "{}",
442
- moduleUserKey: `${model.module.name}`,
443
- modelUserKey: `${model.singularName}`,
444
- layout: {
445
- type: "form",
446
- attrs: { name: "form-1", label: `${model.displayName}`, className: "grid" },
447
- children: [
448
- {
449
- type: "sheet",
450
- attrs: { name: "sheet-1" },
451
- children: [
452
- {
453
- type: "row",
454
- attrs: { name: "sheet-1" },
455
- children: [
456
- {
457
- type: "column",
458
- attrs: { name: "group-1", label: "", className: "col-6" },
459
- children: column1Fields
460
- },
461
- {
462
- type: "column",
463
- attrs: { name: "group-2", label: "", className: "col-6" },
464
- children: column2Fields
465
- }]
466
- },
467
- ]
468
- }
469
- ]
470
- }
471
- };
472
270
  // Update the `models` array
473
271
  metaData.moduleMetadata.models.push(modelMetaData);
474
- metaData.menus.push(menu);
475
- metaData.actions.push(action);
476
- metaData.views.push(modelListview);
477
- metaData.views.push(modelFormView);
478
-
479
272
 
480
273
  // Write the updated object back to the file
481
274
  const updatedContent = JSON.stringify(metaData, null, 2);
@@ -734,6 +527,163 @@ export class ModelMetadataService {
734
527
  await this.generateCode(inverseOptions);
735
528
  }
736
529
 
530
+ await this.generateVAMConfig(model.id);
531
+
532
+ return `${removeFieldCodeOuput} \n ${refreshModelCodeOutput}`;
533
+ }
534
+
535
+ // Generate the View, Action and Menu configuration for the model
536
+ private async generateVAMConfig(modelId: number) {
537
+ try {
538
+ return await this.dataSource.transaction(async (manager: EntityManager) => {
539
+ const modelRepository = manager.getRepository(ModelMetadata);
540
+ const model = await modelRepository.findOne({
541
+ where: {
542
+ id: modelId
543
+ },
544
+ relations: ["fields", "module"]
545
+ });
546
+ await this.populateVAMConfigInDb(model);
547
+ await this.populateVAMConfigInFile(model);
548
+ });
549
+ } catch (error) {
550
+ this.logger.error('generateVAMConfig Transaction failed:', error);
551
+ throw error;
552
+ }
553
+ }
554
+
555
+ private async populateVAMConfigInFile(model: ModelMetadata) {
556
+ try {
557
+ const filePath = this.moduleMetadataHelperService.getModuleMetadataFilePath(model.module.name);
558
+ const metaData = await this.moduleMetadataHelperService.getModuleMetadataConfiguration(filePath);
559
+
560
+ const listViewLayoutFields = [{ type: "field", attrs: { name: `id`, sortable: true, filterable: true } }];
561
+ const formViewLayoutFields = [];
562
+
563
+ for (let i = 0; i < model.fields.length; i++) {
564
+ const field = model.fields[i];
565
+ if (field.isSystem) continue;
566
+ listViewLayoutFields.push({ type: "field", attrs: { name: `${field.name}`, sortable: true, filterable: true } })
567
+ formViewLayoutFields.push({ type: "field", attrs: { name: `${field.name}` } })
568
+ }
569
+ this.populateVAMConfigInFileInternal(formViewLayoutFields, model, listViewLayoutFields, metaData);
570
+ // Write the updated object back to the file
571
+ const updatedContent = JSON.stringify(metaData, null, 2);
572
+ await fs.writeFile(filePath, updatedContent);
573
+
574
+ } catch (error) {
575
+ // console.error('File creation failed:', error);
576
+ this.logger.error('File updation failed for View, action, menus config:', error);
577
+ throw new Error('File updation failed for View, action, menus config'); // Trigger rollback
578
+ }
579
+ }
580
+
581
+ // Populate the View, Actions and Menus in the config file
582
+ private populateVAMConfigInFileInternal(formViewLayoutFields: any[], model: ModelMetadata, listViewLayoutFields: { type: string; attrs: { name: string; sortable: boolean; filterable: boolean; }; }[], metaData: any) {
583
+ const column1Fields = [];
584
+ const column2Fields = [];
585
+
586
+ // Distribute fields between two columns
587
+ for (let i = 0; i < formViewLayoutFields.length; i++) {
588
+ if (i % 2 === 0) {
589
+ column1Fields.push(formViewLayoutFields[i]);
590
+ } else {
591
+ column2Fields.push(formViewLayoutFields[i]);
592
+ }
593
+ }
594
+ const action = {
595
+ displayName: `${model.displayName} List View`,
596
+ name: `${model.singularName}-list-view`,
597
+ type: "solid",
598
+ domain: "",
599
+ context: "",
600
+ customComponent: `/admin/address-master/${model.singularName}/all`,
601
+ customIsModal: true,
602
+ serverEndpoint: "",
603
+ viewUserKey: `${model.singularName}-list-view`,
604
+ moduleUserKey: `${model.module.name}`,
605
+ modelUserKey: `${model.singularName}`
606
+ };
607
+
608
+ const menu = {
609
+ displayName: `${model.displayName}`,
610
+ name: `${model.singularName}-menu-item`,
611
+ sequenceNumber: 1,
612
+ actionUserKey: `${model.singularName}-list-view`,
613
+ moduleUserKey: `${model.module.name}`,
614
+ parentMenuItemUserKey: ""
615
+ };
616
+
617
+ const modelListview = {
618
+ name: `${model.singularName}-list-view`,
619
+ displayName: `${model.displayName}`,
620
+ type: "list",
621
+ context: "{}",
622
+ moduleUserKey: `${model.module.name}`,
623
+ modelUserKey: `${model.singularName}`,
624
+ layout: {
625
+ type: "list",
626
+ attrs: {
627
+ pagination: true,
628
+ pageSizeOptions: [
629
+ 10,
630
+ 25,
631
+ 50
632
+ ],
633
+ enableGlobalSearch: true,
634
+ create: true,
635
+ edit: true,
636
+ delete: true
637
+ },
638
+ children: listViewLayoutFields
639
+ }
640
+ };
641
+
642
+
643
+ const modelFormView = {
644
+ name: `${model.singularName}-form-view`,
645
+ displayName: `${model.displayName}`,
646
+ type: "form",
647
+ context: "{}",
648
+ moduleUserKey: `${model.module.name}`,
649
+ modelUserKey: `${model.singularName}`,
650
+ layout: {
651
+ type: "form",
652
+ attrs: { name: "form-1", label: `${model.displayName}`, className: "grid" },
653
+ children: [
654
+ {
655
+ type: "sheet",
656
+ attrs: { name: "sheet-1" },
657
+ children: [
658
+ {
659
+ type: "row",
660
+ attrs: { name: "sheet-1" },
661
+ children: [
662
+ {
663
+ type: "column",
664
+ attrs: { name: "group-1", label: "", className: "col-6" },
665
+ children: column1Fields
666
+ },
667
+ {
668
+ type: "column",
669
+ attrs: { name: "group-2", label: "", className: "col-6" },
670
+ children: column2Fields
671
+ }
672
+ ]
673
+ },
674
+ ]
675
+ }
676
+ ]
677
+ }
678
+ };
679
+ metaData.menus.push(menu);
680
+ metaData.actions.push(action);
681
+ metaData.views.push(modelListview);
682
+ metaData.views.push(modelFormView);
683
+ }
684
+
685
+ //Populate the View, Actions and Menus in the database
686
+ private async populateVAMConfigInDb(model: ModelMetadata) {
737
687
  const jsonFieldsList = model.fields.filter((field: FieldMetadata) => field.isSystem !== true);
738
688
 
739
689
  const listViewLayout = jsonFieldsList.map(field => ({
@@ -872,8 +822,6 @@ export class ModelMetadataService {
872
822
  const createdMenu = menuRepo.create(menuData);
873
823
  await menuRepo.save(createdMenu);
874
824
  }
875
-
876
- return `${removeFieldCodeOuput} \n ${refreshModelCodeOutput}`;
877
825
  }
878
826
 
879
827
  private async generateCode(options: CodeGenerationOptions) {