@solidstarters/solid-core 1.2.149 → 1.2.151

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.
Files changed (82) hide show
  1. package/dist/dtos/create-scheduled-job.dto.d.ts +1 -0
  2. package/dist/dtos/create-scheduled-job.dto.d.ts.map +1 -1
  3. package/dist/dtos/create-scheduled-job.dto.js +5 -1
  4. package/dist/dtos/create-scheduled-job.dto.js.map +1 -1
  5. package/dist/dtos/create-user.dto.js +3 -3
  6. package/dist/dtos/create-user.dto.js.map +1 -1
  7. package/dist/dtos/update-scheduled-job.dto.d.ts +1 -0
  8. package/dist/dtos/update-scheduled-job.dto.d.ts.map +1 -1
  9. package/dist/dtos/update-scheduled-job.dto.js +5 -1
  10. package/dist/dtos/update-scheduled-job.dto.js.map +1 -1
  11. package/dist/entities/scheduled-job.entity.d.ts +2 -0
  12. package/dist/entities/scheduled-job.entity.d.ts.map +1 -1
  13. package/dist/entities/scheduled-job.entity.js +8 -1
  14. package/dist/entities/scheduled-job.entity.js.map +1 -1
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +1 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.d.ts.map +1 -1
  20. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js +4 -1
  21. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js.map +1 -1
  22. package/dist/repository/scheduled-job.repository.d.ts +29 -0
  23. package/dist/repository/scheduled-job.repository.d.ts.map +1 -0
  24. package/dist/repository/scheduled-job.repository.js +85 -0
  25. package/dist/repository/scheduled-job.repository.js.map +1 -0
  26. package/dist/seeders/module-metadata-seeder.service.d.ts +4 -1
  27. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  28. package/dist/seeders/module-metadata-seeder.service.js +20 -2
  29. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  30. package/dist/seeders/seed-data/solid-core-metadata.json +156 -78
  31. package/dist/services/ai-interaction.service.d.ts +1 -1
  32. package/dist/services/ai-interaction.service.d.ts.map +1 -1
  33. package/dist/services/ai-interaction.service.js +4 -3
  34. package/dist/services/ai-interaction.service.js.map +1 -1
  35. package/dist/services/computed-fields/entity/concat-entity-computed-field-provider.service.d.ts.map +1 -1
  36. package/dist/services/computed-fields/entity/concat-entity-computed-field-provider.service.js +16 -12
  37. package/dist/services/computed-fields/entity/concat-entity-computed-field-provider.service.js.map +1 -1
  38. package/dist/services/media.service.d.ts.map +1 -1
  39. package/dist/services/media.service.js +2 -2
  40. package/dist/services/media.service.js.map +1 -1
  41. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js +3 -2
  42. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js.map +1 -1
  43. package/dist/services/mediaStorageProviders/file-storage-provider.js +6 -4
  44. package/dist/services/mediaStorageProviders/file-storage-provider.js.map +1 -1
  45. package/dist/services/scheduled-jobs/scheduler.service.d.ts.map +1 -1
  46. package/dist/services/scheduled-jobs/scheduler.service.js +1 -1
  47. package/dist/services/scheduled-jobs/scheduler.service.js.map +1 -1
  48. package/dist/services/textract.service.d.ts +20 -0
  49. package/dist/services/textract.service.d.ts.map +1 -0
  50. package/dist/services/textract.service.js +199 -0
  51. package/dist/services/textract.service.js.map +1 -0
  52. package/dist/solid-core.module.d.ts.map +1 -1
  53. package/dist/solid-core.module.js +7 -0
  54. package/dist/solid-core.module.js.map +1 -1
  55. package/dist/subscribers/scheduled-job.subscriber.d.ts +19 -0
  56. package/dist/subscribers/scheduled-job.subscriber.d.ts.map +1 -0
  57. package/dist/subscribers/scheduled-job.subscriber.js +175 -0
  58. package/dist/subscribers/scheduled-job.subscriber.js.map +1 -0
  59. package/dist/tsconfig.tsbuildinfo +1 -1
  60. package/package.json +2 -1
  61. package/src/dtos/create-scheduled-job.dto.ts +3 -0
  62. package/src/dtos/create-user.dto.ts +2 -2
  63. package/src/dtos/update-scheduled-job.dto.ts +3 -0
  64. package/src/entities/scheduled-job.entity.ts +7 -2
  65. package/src/index.ts +1 -0
  66. package/src/jobs/database/trigger-mcp-client-subscriber-database.service.ts +8 -1
  67. package/src/repository/scheduled-job.repository.ts +94 -0
  68. package/src/seeders/module-metadata-seeder.service.ts +20 -1
  69. package/src/seeders/seed-data/solid-core-metadata.json +156 -78
  70. package/src/services/ai-interaction.service.ts +4 -3
  71. package/src/services/computed-fields/entity/concat-entity-computed-field-provider.service.ts +28 -18
  72. package/src/services/media.service.ts +2 -3
  73. package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +2 -2
  74. package/src/services/mediaStorageProviders/file-storage-provider.ts +4 -4
  75. package/src/services/scheduled-jobs/scheduler.service.ts +2 -2
  76. package/src/services/textract.service.ts +189 -0
  77. package/src/solid-core.module.ts +7 -0
  78. package/src/subscribers/scheduled-job.subscriber.ts +176 -0
  79. package/src/# computed field pending issues.md +0 -3
  80. package/src/services/pending_import_issues +0 -3
  81. package/src/services/question-data-providers/test.sql +0 -1
  82. package/test.json +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidstarters/solid-core",
3
- "version": "1.2.149",
3
+ "version": "1.2.151",
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",
@@ -34,6 +34,7 @@
34
34
  "dependencies": {
35
35
  "@angular-devkit/core": "^18.0.3",
36
36
  "@aws-sdk/client-s3": "^3.637.0",
37
+ "@aws-sdk/client-textract": "^3.873.0",
37
38
  "@aws-sdk/s3-request-presigner": "^3.828.0",
38
39
  "@elasticemail/elasticemail-client": "^4.0.23",
39
40
  "@hapi/joi": "^17.1.1",
@@ -62,4 +62,7 @@ export class CreateScheduledJobDto {
62
62
  @IsString()
63
63
  @ApiProperty()
64
64
  job: string;
65
+
66
+ @IsNotEmpty()
67
+ moduleId: number;
65
68
  }
@@ -23,12 +23,12 @@ export class CreateUserDto {
23
23
  @ApiProperty()
24
24
  mobile: string;
25
25
  @IsOptional()
26
- @Matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).*$/)
26
+ @Matches(/^$|^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).*$/)
27
27
  @IsString()
28
28
  @ApiProperty()
29
29
  password: string;
30
30
  @IsOptional()
31
- @Matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).*$/)
31
+ @Matches(/^$|^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).*$/)
32
32
  @IsString()
33
33
  @ApiProperty()
34
34
  passwordConfirm: string;
@@ -69,4 +69,7 @@ export class UpdateScheduledJobDto {
69
69
  @IsString()
70
70
  @ApiProperty()
71
71
  job: string;
72
+
73
+ @IsNotEmpty()
74
+ moduleId: number;
72
75
  }
@@ -1,8 +1,10 @@
1
- import { Entity, Column } from 'typeorm';
1
+ import { Entity, Column, ManyToOne, JoinColumn, Index } from 'typeorm';
2
2
  import { CommonEntity } from './common.entity';
3
+ import { ModuleMetadata } from 'src/entities/module-metadata.entity';
3
4
 
4
5
  @Entity('ss_scheduled_job')
5
6
  export class ScheduledJob extends CommonEntity {
7
+ @Index({ unique: true })
6
8
  @Column({ type: "varchar" })
7
9
  scheduleName: string;
8
10
  @Column({ type: "boolean", default: false })
@@ -27,4 +29,7 @@ export class ScheduledJob extends CommonEntity {
27
29
  dayOfWeek: string;
28
30
  @Column({ type: "varchar" })
29
31
  job: string;
30
- }
32
+ @ManyToOne(() => ModuleMetadata, { onDelete: "CASCADE", nullable: false })
33
+ @JoinColumn({ referencedColumnName: 'id' })
34
+ module: ModuleMetadata;
35
+ }
package/src/index.ts CHANGED
@@ -218,6 +218,7 @@ export * from './services/crud.service'
218
218
  export * from './services/email-template.service'
219
219
  export * from './services/field-metadata.service'
220
220
  export * from './services/file.service'
221
+ export * from './services/textract.service'
221
222
  export * from './services/hashing.service'
222
223
  export * from './services/list-of-values.service'
223
224
  export * from './services/mail/elastic-email.service'
@@ -46,6 +46,8 @@ export class TriggerMcpClientSubscriberDatabase extends DatabaseSubscriber<Trigg
46
46
  const prompt = aiInteraction.message;
47
47
 
48
48
  // Use this to invoke our mcp client
49
+ // TODO: try / catch ...
50
+ // Handle the rejection gracefully...
49
51
  const aiResponse = await this.aiInteractionService.runMcpPrompt(prompt);
50
52
  this.triggerMcpClientSubscriberLogger.log(`aiResponse: `);
51
53
  this.triggerMcpClientSubscriberLogger.log(JSON.stringify(aiResponse));
@@ -75,7 +77,7 @@ export class TriggerMcpClientSubscriberDatabase extends DatabaseSubscriber<Trigg
75
77
  else {
76
78
  let nestedResponse = aiResponse.response.trim();
77
79
 
78
- await this.aiInteractionService.create({
80
+ const genAiInteraction = await this.aiInteractionService.create({
79
81
  userId: aiInteraction.user.id,
80
82
  threadId: aiInteraction.threadId,
81
83
  parentInteractionId: aiInteraction.id,
@@ -88,6 +90,11 @@ export class TriggerMcpClientSubscriberDatabase extends DatabaseSubscriber<Trigg
88
90
  metadata: JSON.stringify(aiResponse),
89
91
  isApplied: aiInteraction.isApplied
90
92
  });
93
+
94
+ // If the human interaction was with isAutoApply=true, then we can go ahead and autoApply.
95
+ if (aiInteraction.isAutoApply) {
96
+ this.aiInteractionService.applySolidAiInteraction(genAiInteraction.id);
97
+ }
91
98
  }
92
99
 
93
100
  return aiResponse;
@@ -0,0 +1,94 @@
1
+ import { Injectable, Logger } from "@nestjs/common";
2
+ import { ModuleMetadata } from "src/entities/module-metadata.entity";
3
+ import { ScheduledJob } from "src/entities/scheduled-job.entity";
4
+ import { SolidRegistry } from "src/helpers/solid-registry";
5
+ import { CrudHelperService } from "src/services/crud-helper.service";
6
+ import { DataSource, Repository } from "typeorm";
7
+
8
+ // This should match whatever DTO structure you’re using in your seeding logic
9
+ export type CreateScheduledJobDto = {
10
+ scheduleName: string;
11
+ isActive?: boolean;
12
+ frequency: string;
13
+ startTime?: Date;
14
+ endTime?: Date;
15
+ startDate?: Date;
16
+ endDate?: Date;
17
+ dayOfMonth?: number;
18
+ lastRunAt?: Date;
19
+ nextRunAt?: Date;
20
+ dayOfWeek?: string;
21
+ job: string;
22
+ moduleUserKey: string;
23
+ };
24
+
25
+ @Injectable()
26
+ export class ScheduledJobRepository extends Repository<ScheduledJob> {
27
+ private readonly logger = new Logger(ScheduledJobRepository.name);
28
+
29
+ constructor(
30
+ private dataSource: DataSource,
31
+ private readonly solidRegistry: SolidRegistry,
32
+ private readonly crudHelperService: CrudHelperService
33
+ ) {
34
+ super(ScheduledJob, dataSource.createEntityManager());
35
+ }
36
+
37
+ /**
38
+ * Converts an entity to a plain DTO object.
39
+ */
40
+ async toDto(scheduledJob: ScheduledJob): Promise<CreateScheduledJobDto> {
41
+ const moduleRepo = this.dataSource.getRepository(ModuleMetadata);
42
+ const moduleEntity = await moduleRepo.findOne({
43
+ where: { id: scheduledJob.module?.id },
44
+ });
45
+
46
+ if (!moduleEntity) {
47
+ throw new Error(`Module with ID ${scheduledJob.module?.id} not found`);
48
+ }
49
+ return {
50
+ scheduleName: scheduledJob.scheduleName,
51
+ isActive: scheduledJob.isActive,
52
+ frequency: scheduledJob.frequency,
53
+ startTime: scheduledJob.startTime,
54
+ endTime: scheduledJob.endTime,
55
+ startDate: scheduledJob.startDate,
56
+ endDate: scheduledJob.endDate,
57
+ dayOfMonth: scheduledJob.dayOfMonth,
58
+ lastRunAt: scheduledJob.lastRunAt,
59
+ nextRunAt: scheduledJob.nextRunAt,
60
+ dayOfWeek: scheduledJob.dayOfWeek,
61
+ job: scheduledJob.job,
62
+ moduleUserKey: moduleEntity.name,
63
+ };
64
+ }
65
+
66
+ async upsertWithDto(dto: CreateScheduledJobDto): Promise<ScheduledJob> {
67
+ const moduleRepo = this.dataSource.getRepository(ModuleMetadata);
68
+
69
+ const moduleEntity = await moduleRepo.findOne({
70
+ where: { name: dto.moduleUserKey },
71
+ });
72
+
73
+ if (!moduleEntity) {
74
+ throw new Error(`Module with ID ${dto.moduleUserKey} not found`);
75
+ }
76
+
77
+ const jobData = {
78
+ ...dto,
79
+ module: moduleEntity,
80
+ };
81
+ const existing = await this.findOne({
82
+ where: { scheduleName: dto.scheduleName },
83
+ });
84
+
85
+ if (existing) {
86
+ const merged = this.merge(existing, jobData);
87
+ this.logger.debug(`Updating scheduled job: ${dto.scheduleName}`);
88
+ return this.save(merged);
89
+ } else {
90
+ this.logger.debug(`Creating scheduled job: ${dto.scheduleName}`);
91
+ return this.save(this.create(jobData));
92
+ }
93
+ }
94
+ }
@@ -39,6 +39,8 @@ import { CreateListOfValuesDto } from 'src/dtos/create-list-of-values.dto';
39
39
  import { SystemFieldsSeederService } from './system-fields-seeder.service';
40
40
  import { CreateDashboardDto } from 'src/dtos/create-dashboard.dto';
41
41
  import { DashboardRepository } from 'src/repository/dashboard.repository';
42
+ // import { CreateScheduledJobDto } from 'src/dtos/create-scheduled-job.dto';
43
+ import { ScheduledJobRepository, CreateScheduledJobDto } from 'src/repository/scheduled-job.repository';
42
44
 
43
45
  @Injectable()
44
46
  export class ModuleMetadataSeederService {
@@ -73,6 +75,7 @@ export class ModuleMetadataSeederService {
73
75
  readonly securityRuleRepo: SecurityRuleRepository,
74
76
  readonly systemFieldsSeederService: SystemFieldsSeederService,
75
77
  readonly dashboardRepo: DashboardRepository,
78
+ readonly scheduledJobRepository: ScheduledJobRepository,
76
79
  ) { }
77
80
 
78
81
  async seed() {
@@ -221,9 +224,15 @@ export class ModuleMetadataSeederService {
221
224
  await this.seedDashboards(dashboards);
222
225
  this.logger.log(`[End] Processing dashboards for ${moduleMetadata.name}`);
223
226
 
227
+ // Scheduled Jobs
228
+ this.logger.debug(`[Start] Processing scheduled jobs for ${moduleMetadata.name}`);
229
+ const scheduledJobs: CreateScheduledJobDto[] = overallMetadata.scheduledJobs;
230
+ if (scheduledJobs?.length > 0) {
231
+ await this.seedScheduledJobs(scheduledJobs);
232
+ }
233
+ this.logger.debug(`[End] Processing scheduled jobs for ${moduleMetadata.name}`);
224
234
 
225
235
  this.logger.debug(`[End] module seed data: ${overallMetadata}`);
226
-
227
236
  }
228
237
 
229
238
  // Post seed data file processing.
@@ -588,4 +597,14 @@ export class ModuleMetadataSeederService {
588
597
  }
589
598
  }
590
599
 
600
+ async seedScheduledJobs(createScheduledJobDto: CreateScheduledJobDto[]) {
601
+ if (!createScheduledJobDto || createScheduledJobDto.length === 0) {
602
+ this.logger.debug(`No scheduled jobs found to seed`);
603
+ return;
604
+ }
605
+ for (const dto of createScheduledJobDto) {
606
+ await this.scheduledJobRepository.upsertWithDto(dto);
607
+ }
608
+ }
609
+
591
610
  }
@@ -2548,7 +2548,7 @@
2548
2548
  "userKeyFieldUserKey": "scheduleName",
2549
2549
  "isChild": false,
2550
2550
  "enableAuditTracking": true,
2551
- "enableSoftDelete": true,
2551
+ "enableSoftDelete": false,
2552
2552
  "draftPublishWorkflow": false,
2553
2553
  "internationalisation": false,
2554
2554
  "fields": [
@@ -2797,6 +2797,22 @@
2797
2797
  "selectionValueType": "string",
2798
2798
  "selectionDynamicProvider": "ListOfScheduledJobsSelectionProvider",
2799
2799
  "selectionDynamicProviderCtxt": "{}"
2800
+ },
2801
+ {
2802
+ "name": "module",
2803
+ "displayName": "Module",
2804
+ "type": "relation",
2805
+ "required": true,
2806
+ "unique": false,
2807
+ "index": true,
2808
+ "private": false,
2809
+ "encrypt": false,
2810
+ "relationType": "many-to-one",
2811
+ "relationCoModelSingularName": "moduleMetadata",
2812
+ "relationCreateInverse": false,
2813
+ "relationCascade": "cascade",
2814
+ "relationModelModuleName": "solid-core",
2815
+ "isSystem": true
2800
2816
  }
2801
2817
  ]
2802
2818
  },
@@ -10219,6 +10235,13 @@
10219
10235
  "isSearchable": true
10220
10236
  }
10221
10237
  },
10238
+ {
10239
+ "type": "field",
10240
+ "attrs": {
10241
+ "name": "module",
10242
+ "isSearchable": true
10243
+ }
10244
+ },
10222
10245
  {
10223
10246
  "type": "field",
10224
10247
  "attrs": {
@@ -10313,100 +10336,154 @@
10313
10336
  },
10314
10337
  "children": [
10315
10338
  {
10316
- "type": "row",
10339
+ "type": "notebook",
10317
10340
  "attrs": {
10318
- "name": "sheet-1"
10341
+ "name": "notebook-1"
10319
10342
  },
10320
10343
  "children": [
10321
10344
  {
10322
- "type": "column",
10345
+ "type": "page",
10323
10346
  "attrs": {
10324
- "name": "group-1",
10325
- "label": "Basic",
10326
- "className": "col-6"
10347
+ "name": "page-general",
10348
+ "label": "General"
10327
10349
  },
10328
10350
  "children": [
10329
10351
  {
10330
- "type": "field",
10331
- "attrs": {
10332
- "name": "scheduleName"
10333
- }
10334
- },
10335
- {
10336
- "type": "field",
10352
+ "type": "row",
10337
10353
  "attrs": {
10338
- "name": "job"
10339
- }
10354
+ "name": "row-general"
10355
+ },
10356
+ "children": [
10357
+ {
10358
+ "type": "column",
10359
+ "attrs": {
10360
+ "name": "group-basic",
10361
+ "label": "Basic",
10362
+ "className": "col-6"
10363
+ },
10364
+ "children": [
10365
+ {
10366
+ "type": "field",
10367
+ "attrs": {
10368
+ "name": "scheduleName"
10369
+ }
10370
+ },
10371
+ {
10372
+ "type": "field",
10373
+ "attrs": {
10374
+ "name": "job"
10375
+ }
10376
+ },
10377
+ {
10378
+ "type": "field",
10379
+ "attrs": {
10380
+ "name": "module"
10381
+ }
10382
+ },
10383
+ {
10384
+ "type": "field",
10385
+ "attrs": {
10386
+ "name": "isActive"
10387
+ }
10388
+ }
10389
+ ]
10390
+ },
10391
+ {
10392
+ "type": "column",
10393
+ "attrs": {
10394
+ "name": "group-config",
10395
+ "label": "Configuration",
10396
+ "className": "col-6"
10397
+ },
10398
+ "children": [
10399
+ {
10400
+ "type": "field",
10401
+ "attrs": {
10402
+ "name": "frequency"
10403
+ }
10404
+ },
10405
+ {
10406
+ "type": "field",
10407
+ "attrs": {
10408
+ "name": "startTime"
10409
+ }
10410
+ },
10411
+ {
10412
+ "type": "field",
10413
+ "attrs": {
10414
+ "name": "endTime"
10415
+ }
10416
+ },
10417
+ {
10418
+ "type": "field",
10419
+ "attrs": {
10420
+ "name": "startDate"
10421
+ }
10422
+ },
10423
+ {
10424
+ "type": "field",
10425
+ "attrs": {
10426
+ "name": "endDate"
10427
+ }
10428
+ },
10429
+ {
10430
+ "type": "field",
10431
+ "attrs": {
10432
+ "name": "dayOfWeek"
10433
+ }
10434
+ },
10435
+ {
10436
+ "type": "field",
10437
+ "attrs": {
10438
+ "name": "dayOfMonth"
10439
+ }
10440
+ }
10441
+ ]
10442
+ }
10443
+ ]
10340
10444
  }
10341
10445
  ]
10342
10446
  },
10343
10447
  {
10344
- "type": "column",
10448
+ "type": "page",
10345
10449
  "attrs": {
10346
- "name": "group-1",
10347
- "label": "Configuration",
10348
- "className": "col-6"
10450
+ "name": "page-runtime",
10451
+ "label": "Runtime"
10349
10452
  },
10350
10453
  "children": [
10351
10454
  {
10352
- "type": "field",
10353
- "attrs": {
10354
- "name": "isActive"
10355
- }
10356
- },
10357
- {
10358
- "type": "field",
10359
- "attrs": {
10360
- "name": "frequency"
10361
- }
10362
- },
10363
- {
10364
- "type": "field",
10365
- "attrs": {
10366
- "name": "startTime"
10367
- }
10368
- },
10369
- {
10370
- "type": "field",
10371
- "attrs": {
10372
- "name": "endTime"
10373
- }
10374
- },
10375
- {
10376
- "type": "field",
10377
- "attrs": {
10378
- "name": "startDate"
10379
- }
10380
- },
10381
- {
10382
- "type": "field",
10383
- "attrs": {
10384
- "name": "endDate"
10385
- }
10386
- },
10387
- {
10388
- "type": "field",
10389
- "attrs": {
10390
- "name": "lastRunAt"
10391
- }
10392
- },
10393
- {
10394
- "type": "field",
10395
- "attrs": {
10396
- "name": "nextRunAt"
10397
- }
10398
- },
10399
- {
10400
- "type": "field",
10401
- "attrs": {
10402
- "name": "dayOfWeek"
10403
- }
10404
- },
10405
- {
10406
- "type": "field",
10455
+ "type": "row",
10407
10456
  "attrs": {
10408
- "name": "dayOfMonth"
10409
- }
10457
+ "name": "row-runtime"
10458
+ },
10459
+ "children": [
10460
+ {
10461
+ "type": "column",
10462
+ "attrs": {
10463
+ "name": "group-runtime",
10464
+ "label": "Execution",
10465
+ "className": "col-12"
10466
+ },
10467
+ "children": [
10468
+ {
10469
+ "type": "field",
10470
+ "attrs": {
10471
+ "name": "lastRunAt",
10472
+ "disabled": true,
10473
+ "readOnly": true
10474
+ }
10475
+ },
10476
+ {
10477
+ "type": "field",
10478
+ "attrs": {
10479
+ "name": "nextRunAt",
10480
+ "disabled": true,
10481
+ "readOnly": true
10482
+ }
10483
+ }
10484
+ ]
10485
+ }
10486
+ ]
10410
10487
  }
10411
10488
  ]
10412
10489
  }
@@ -12279,5 +12356,6 @@
12279
12356
  }
12280
12357
  ],
12281
12358
  "checksums": [],
12282
- "listOfValues": []
12359
+ "listOfValues": [],
12360
+ "scheduledJobs": []
12283
12361
  }
@@ -43,19 +43,20 @@ export class AiInteractionService extends CRUDService<AiInteraction> {
43
43
  super(modelMetadataService, moduleMetadataService, configService, fileService, discoveryService, crudHelperService, entityManager, repo, 'aiInteraction', 'solid-core', moduleRef);
44
44
  }
45
45
 
46
- async triggerMcpClientJob(prompt: string): Promise<any> {
46
+ async triggerMcpClientJob(prompt: string, isAutoApply: boolean = false, threadId: string = null): Promise<any> {
47
47
  const activeUser: ActiveUserData = this.requestContextService.getActiveUser();
48
48
 
49
49
  const aiInteraction = await this.create({
50
50
  userId: activeUser.sub,
51
- threadId: `thread-${activeUser.sub}`,
51
+ threadId: threadId ? threadId : `thread-${activeUser.sub}`,
52
52
  role: 'human',
53
53
  message: prompt,
54
54
  contentType: '',
55
55
  errorMessage: '',
56
56
  modelUsed: '',
57
57
  responseTimeMs: 0,
58
- metadata: ''
58
+ metadata: '',
59
+ isAutoApply: isAutoApply
59
60
  });
60
61
  const m = {
61
62
  payload: {
@@ -1,5 +1,5 @@
1
1
  import { Injectable } from "@nestjs/common";
2
- import { kebabCase } from "lodash";
2
+ import { kebabCase, get } from "lodash";
3
3
  import { ComputedFieldProvider } from "src/decorators/computed-field-provider.decorator";
4
4
  import { CommonEntity } from "src/entities/common.entity";
5
5
  import { ComputedFieldMetadata } from "src/helpers/solid-registry";
@@ -24,28 +24,38 @@ export class ConcatEntityComputedFieldProvider<T extends CommonEntity> implement
24
24
  return "Computed field provider used to create fields whose value is a concatenation of other fields in the same model.";
25
25
  }
26
26
 
27
- async preComputeValue(triggerEntity: T, computedFieldMetadata: ComputedFieldMetadata<ConcatComputedFieldContext>){
27
+ async preComputeValue(triggerEntity: T, computedFieldMetadata: ComputedFieldMetadata<ConcatComputedFieldContext>) {
28
28
  const { computedFieldValueProviderCtxt } = computedFieldMetadata;
29
- const separator = computedFieldValueProviderCtxt.separator || ' '; // Default to space if no separator is provided
30
- const fields = computedFieldValueProviderCtxt.fields || [];
31
- const slugify = computedFieldValueProviderCtxt.slugify || false;
32
-
33
- let concatenatedString = '';
34
- for (let i = 0; i < fields.length; i++) {
35
- const field = fields[i];
36
-
37
- // if slugify then each field val to be converted to a slug before concatenation
38
- let fieldVal = triggerEntity[field];
39
- if (slugify && typeof fieldVal === 'string') {
40
- fieldVal = kebabCase(fieldVal);
29
+ const separator = computedFieldValueProviderCtxt.separator ?? ' ';
30
+ const fields: string[] = computedFieldValueProviderCtxt.fields ?? [];
31
+ const slugify = computedFieldValueProviderCtxt.slugify ?? false;
32
+
33
+ const parts: string[] = [];
34
+
35
+ for (const fieldExpr of fields) {
36
+ let val = get(triggerEntity as any, fieldExpr);
37
+
38
+ // normalize to string (skip null/undefined)
39
+ if (val == null) continue;
40
+
41
+ if (typeof val !== 'string') {
42
+ val = String(val);
41
43
  }
42
44
 
43
- if (concatenatedString) {
44
- concatenatedString += separator;
45
+ if (slugify) {
46
+ val = kebabCase(val);
47
+ }
48
+
49
+ // ignore empty strings so you don't get stray separators
50
+ if (val.length > 0) {
51
+ parts.push(val);
45
52
  }
46
- concatenatedString += fieldVal;
47
53
  }
48
- triggerEntity[computedFieldMetadata.fieldName] = concatenatedString; //This set the computed value on the entity, since for pre-compute, entity and triggerEntity are the same
54
+
55
+ const concatenatedString = parts.join(separator);
56
+
57
+ // set the computed field on the entity
58
+ (triggerEntity as any)[computedFieldMetadata.fieldName] = concatenatedString;
49
59
  }
50
60
 
51
61
  }
@@ -84,7 +84,6 @@ export class MediaService extends CRUDService<Media> {
84
84
  const savedMedias = [];
85
85
  for (let i = 0; i < files.length; i++) {
86
86
 
87
-
88
87
  createDto['fieldMetadata'] = await this.fieldMetadataRepo.findOne({
89
88
  where: {
90
89
  id: createDto['fieldMetadataId']
@@ -113,9 +112,9 @@ export class MediaService extends CRUDService<Media> {
113
112
  const fileName = this.getFileName(file);
114
113
  let awsFileUrl;
115
114
  if (createDto.mediaStorageProviderMetadata.isPublic === true) {
116
- awsFileUrl = await this.fileService.copyToS3(file.path, file.mimetype, fileName, createDto.mediaStorageProviderMetadata.bucketName,);
117
- } else {
118
115
  awsFileUrl = await this.fileService.copyToS3WithPublic(file.path, file.mimetype, fileName, createDto.mediaStorageProviderMetadata.bucketName,);
116
+ } else {
117
+ awsFileUrl = await this.fileService.copyToS3(file.path, file.mimetype, fileName, createDto.mediaStorageProviderMetadata.bucketName,);
119
118
  }
120
119
  // createDto['relativeUri'] = this.getAwsS3FullFilePath(awsFileUrl, createDto.mediaStorageProviderMetadata.bucketName, createDto.mediaStorageProviderMetadata.region);
121
120
  createDto['relativeUri'] = awsFileUrl
@@ -60,7 +60,7 @@ export class FileS3StorageProvider<T> implements MediaStorageProvider<T> {
60
60
  throw new Error("Entity must be an instance of CommonEntity"); //FIXME This needs to be handled through generics. e.g T extends CommonEntity
61
61
  }
62
62
  const result: Media[] = [];
63
- files.forEach(async (file) => {
63
+ for (const file of files) {
64
64
  const fileName = this.getFileName(file);
65
65
  // Store the file in the configured S3 Bucket
66
66
  let awsFileUrl;
@@ -84,7 +84,7 @@ export class FileS3StorageProvider<T> implements MediaStorageProvider<T> {
84
84
  }) as unknown as Media;
85
85
  result.push(mediaEntity);
86
86
  this.logger.debug(`Stored media with`, mediaEntity);
87
- });
87
+ };
88
88
  return result;
89
89
  }
90
90