@solidstarters/solid-core 1.2.140 → 1.2.142

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 (103) hide show
  1. package/dist/dtos/create-ai-interaction.dto.d.ts +1 -0
  2. package/dist/dtos/create-ai-interaction.dto.d.ts.map +1 -1
  3. package/dist/dtos/create-ai-interaction.dto.js +10 -1
  4. package/dist/dtos/create-ai-interaction.dto.js.map +1 -1
  5. package/dist/dtos/update-ai-interaction.dto.d.ts +1 -0
  6. package/dist/dtos/update-ai-interaction.dto.d.ts.map +1 -1
  7. package/dist/dtos/update-ai-interaction.dto.js +7 -1
  8. package/dist/dtos/update-ai-interaction.dto.js.map +1 -1
  9. package/dist/entities/ai-interaction.entity.d.ts +1 -0
  10. package/dist/entities/ai-interaction.entity.d.ts.map +1 -1
  11. package/dist/entities/ai-interaction.entity.js +9 -1
  12. package/dist/entities/ai-interaction.entity.js.map +1 -1
  13. package/dist/entities/dashboard-question-sql-dataset-config.entity.d.ts +1 -0
  14. package/dist/entities/dashboard-question-sql-dataset-config.entity.d.ts.map +1 -1
  15. package/dist/entities/dashboard-question-sql-dataset-config.entity.js +6 -1
  16. package/dist/entities/dashboard-question-sql-dataset-config.entity.js.map +1 -1
  17. package/dist/entities/dashboard-question.entity.d.ts +1 -0
  18. package/dist/entities/dashboard-question.entity.d.ts.map +1 -1
  19. package/dist/entities/dashboard-question.entity.js +6 -1
  20. package/dist/entities/dashboard-question.entity.js.map +1 -1
  21. package/dist/interfaces.d.ts +2 -2
  22. package/dist/interfaces.d.ts.map +1 -1
  23. package/dist/interfaces.js.map +1 -1
  24. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.d.ts.map +1 -1
  25. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js +4 -2
  26. package/dist/jobs/database/trigger-mcp-client-subscriber-database.service.js.map +1 -1
  27. package/dist/mappers/dashboard-mapper.d.ts.map +1 -1
  28. package/dist/mappers/dashboard-mapper.js +2 -0
  29. package/dist/mappers/dashboard-mapper.js.map +1 -1
  30. package/dist/repository/view-metadata.repository.d.ts +9 -0
  31. package/dist/repository/view-metadata.repository.d.ts.map +1 -0
  32. package/dist/repository/view-metadata.repository.js +42 -0
  33. package/dist/repository/view-metadata.repository.js.map +1 -0
  34. package/dist/seeders/module-metadata-seeder.service.d.ts +1 -1
  35. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  36. package/dist/seeders/module-metadata-seeder.service.js +22 -8
  37. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  38. package/dist/seeders/seed-data/solid-core-metadata.json +61 -0
  39. package/dist/services/ai-interaction.service.d.ts.map +1 -1
  40. package/dist/services/ai-interaction.service.js +1 -0
  41. package/dist/services/ai-interaction.service.js.map +1 -1
  42. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts +19 -0
  43. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts.map +1 -0
  44. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js +69 -0
  45. package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js.map +1 -0
  46. package/dist/services/computed-fields/entity/concat-entity-computed-field-provider.service.d.ts +2 -2
  47. package/dist/services/computed-fields/entity/concat-entity-computed-field-provider.service.d.ts.map +1 -1
  48. package/dist/services/computed-fields/entity/concat-entity-computed-field-provider.service.js +3 -3
  49. package/dist/services/computed-fields/entity/concat-entity-computed-field-provider.service.js.map +1 -1
  50. package/dist/services/computed-fields/entity/noops-entity-computed-field-provider.service.d.ts +10 -0
  51. package/dist/services/computed-fields/entity/noops-entity-computed-field-provider.service.d.ts.map +1 -0
  52. package/dist/services/computed-fields/entity/noops-entity-computed-field-provider.service.js +18 -0
  53. package/dist/services/computed-fields/entity/noops-entity-computed-field-provider.service.js.map +1 -0
  54. package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-mcp-tool-response-handler.service.d.ts +14 -1
  55. package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-mcp-tool-response-handler.service.d.ts.map +1 -1
  56. package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-mcp-tool-response-handler.service.js +81 -5
  57. package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-mcp-tool-response-handler.service.js.map +1 -1
  58. package/dist/services/mcp-tool-response-handlers/solid-save-model-layout-mcp-tool-response-handler.service.d.ts +12 -0
  59. package/dist/services/mcp-tool-response-handlers/solid-save-model-layout-mcp-tool-response-handler.service.d.ts.map +1 -0
  60. package/dist/services/mcp-tool-response-handlers/solid-save-model-layout-mcp-tool-response-handler.service.js +36 -0
  61. package/dist/services/mcp-tool-response-handlers/solid-save-model-layout-mcp-tool-response-handler.service.js.map +1 -0
  62. package/dist/services/setting.service.d.ts.map +1 -1
  63. package/dist/services/setting.service.js +14 -2
  64. package/dist/services/setting.service.js.map +1 -1
  65. package/dist/services/user.service.d.ts +2 -0
  66. package/dist/services/user.service.d.ts.map +1 -1
  67. package/dist/services/user.service.js +15 -0
  68. package/dist/services/user.service.js.map +1 -1
  69. package/dist/services/view-metadata.service.d.ts +3 -2
  70. package/dist/services/view-metadata.service.d.ts.map +1 -1
  71. package/dist/services/view-metadata.service.js +2 -3
  72. package/dist/services/view-metadata.service.js.map +1 -1
  73. package/dist/solid-core.module.d.ts.map +1 -1
  74. package/dist/solid-core.module.js +8 -0
  75. package/dist/solid-core.module.js.map +1 -1
  76. package/dist/subscribers/computed-entity-field.subscriber.d.ts +1 -1
  77. package/dist/subscribers/computed-entity-field.subscriber.d.ts.map +1 -1
  78. package/dist/subscribers/computed-entity-field.subscriber.js +5 -3
  79. package/dist/subscribers/computed-entity-field.subscriber.js.map +1 -1
  80. package/dist/tsconfig.tsbuildinfo +1 -1
  81. package/package.json +1 -1
  82. package/src/dtos/create-ai-interaction.dto.ts +51 -55
  83. package/src/dtos/update-ai-interaction.dto.ts +51 -56
  84. package/src/entities/ai-interaction.entity.ts +29 -34
  85. package/src/entities/dashboard-question-sql-dataset-config.entity.ts +3 -0
  86. package/src/entities/dashboard-question.entity.ts +3 -0
  87. package/src/interfaces.ts +2 -2
  88. package/src/jobs/database/trigger-mcp-client-subscriber-database.service.ts +4 -2
  89. package/src/mappers/dashboard-mapper.ts +2 -1
  90. package/src/repository/view-metadata.repository.ts +31 -0
  91. package/src/seeders/module-metadata-seeder.service.ts +23 -17
  92. package/src/seeders/seed-data/solid-core-metadata.json +61 -0
  93. package/src/services/ai-interaction.service.ts +3 -0
  94. package/src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts +68 -0
  95. package/src/services/computed-fields/entity/concat-entity-computed-field-provider.service.ts +4 -5
  96. package/src/services/computed-fields/entity/noops-entity-computed-field-provider.service.ts +22 -0
  97. package/src/services/mcp-tool-response-handlers/solid-create-dashboard-mcp-tool-response-handler.service.ts +83 -9
  98. package/src/services/mcp-tool-response-handlers/solid-save-model-layout-mcp-tool-response-handler.service.ts +34 -0
  99. package/src/services/setting.service.ts +14 -2
  100. package/src/services/user.service.ts +22 -0
  101. package/src/services/view-metadata.service.ts +3 -2
  102. package/src/solid-core.module.ts +8 -0
  103. package/src/subscribers/computed-entity-field.subscriber.ts +6 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solidstarters/solid-core",
3
- "version": "1.2.140",
3
+ "version": "1.2.142",
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",
@@ -1,60 +1,56 @@
1
1
  import { ApiProperty } from '@nestjs/swagger';
2
2
  import { IsInt } from 'class-validator';
3
3
  import { IsOptional } from 'class-validator';
4
- import { IsString, IsNotEmpty, IsJSON } from 'class-validator';
5
- export class CreateAiInteractionDto {
6
- @IsOptional()
7
- @IsInt()
8
- @ApiProperty()
9
- userId: number;
10
-
11
- @IsString()
12
- @IsOptional()
13
- @ApiProperty()
14
- userUserKey: string;
15
-
16
- @IsNotEmpty()
17
- @IsString()
18
- @ApiProperty()
19
- threadId: string;
20
-
21
- @IsNotEmpty()
22
- @IsString()
23
- @ApiProperty()
24
- role: string;
25
-
26
- @IsNotEmpty()
27
- @IsString()
28
- @ApiProperty()
29
- message: string;
30
-
31
- @IsOptional()
32
- @IsString()
33
- @ApiProperty()
34
- contentType: string;
4
+ import { IsString, IsNotEmpty, IsJSON, IsBoolean } from 'class-validator';
35
5
 
36
- @IsOptional()
37
- @IsString()
38
- @ApiProperty()
39
- status: string;
40
-
41
- @IsOptional()
42
- @IsString()
43
- @ApiProperty()
44
- errorMessage: string;
45
-
46
- @IsOptional()
47
- @IsString()
48
- @ApiProperty()
49
- modelUsed: string;
50
-
51
- @IsOptional()
52
- @IsInt()
53
- @ApiProperty()
54
- responseTimeMs: number;
55
-
56
- @IsOptional()
57
- @IsJSON()
58
- @ApiProperty()
59
- metadata: any;
6
+ export class CreateAiInteractionDto {
7
+ @IsOptional()
8
+ @IsInt()
9
+ @ApiProperty()
10
+ userId: number;
11
+ @IsString()
12
+ @IsOptional()
13
+ @ApiProperty()
14
+ userUserKey: string;
15
+ @IsNotEmpty()
16
+ @IsString()
17
+ @ApiProperty()
18
+ threadId: string;
19
+ @IsNotEmpty()
20
+ @IsString()
21
+ @ApiProperty()
22
+ role: string;
23
+ @IsNotEmpty()
24
+ @IsString()
25
+ @ApiProperty()
26
+ message: string;
27
+ @IsOptional()
28
+ @IsString()
29
+ @ApiProperty()
30
+ contentType: string;
31
+ @IsOptional()
32
+ @IsString()
33
+ @ApiProperty()
34
+ status: string;
35
+ @IsOptional()
36
+ @IsString()
37
+ @ApiProperty()
38
+ errorMessage: string;
39
+ @IsOptional()
40
+ @IsString()
41
+ @ApiProperty()
42
+ modelUsed: string;
43
+ @IsOptional()
44
+ @IsInt()
45
+ @ApiProperty()
46
+ responseTimeMs: number;
47
+ @IsOptional()
48
+ @IsJSON()
49
+ @ApiProperty()
50
+ metadata: any;
51
+
52
+ @IsOptional()
53
+ @IsBoolean()
54
+ @ApiProperty()
55
+ isApplied: boolean = false;
60
56
  }
@@ -1,65 +1,60 @@
1
- import { IsInt,IsOptional, IsString, IsNotEmpty, IsJSON } from 'class-validator';
1
+ import { IsInt,IsOptional, IsString, IsNotEmpty, IsJSON, IsBoolean } from 'class-validator';
2
2
  import { ApiProperty } from '@nestjs/swagger';
3
+
3
4
  export class UpdateAiInteractionDto {
4
5
  @IsOptional()
5
6
  @IsInt()
6
7
  id: number;
8
+ @IsOptional()
9
+ @IsInt()
10
+ @ApiProperty()
11
+ userId: number;
12
+ @IsString()
13
+ @IsOptional()
14
+ @ApiProperty()
15
+ userUserKey: string;
16
+ @IsNotEmpty()
17
+ @IsOptional()
18
+ @IsString()
19
+ @ApiProperty()
20
+ threadId: string;
21
+ @IsNotEmpty()
22
+ @IsOptional()
23
+ @IsString()
24
+ @ApiProperty()
25
+ role: string;
26
+ @IsNotEmpty()
27
+ @IsOptional()
28
+ @IsString()
29
+ @ApiProperty()
30
+ message: string;
31
+ @IsOptional()
32
+ @IsString()
33
+ @ApiProperty()
34
+ contentType: string;
35
+ @IsOptional()
36
+ @IsString()
37
+ @ApiProperty()
38
+ status: string;
39
+ @IsOptional()
40
+ @IsString()
41
+ @ApiProperty()
42
+ errorMessage: string;
43
+ @IsOptional()
44
+ @IsString()
45
+ @ApiProperty()
46
+ modelUsed: string;
47
+ @IsOptional()
48
+ @IsInt()
49
+ @ApiProperty()
50
+ responseTimeMs: number;
51
+ @IsOptional()
52
+ @IsJSON()
53
+ @ApiProperty()
54
+ metadata: any;
7
55
 
8
56
  @IsOptional()
9
- @IsInt()
10
- @ApiProperty()
11
- userId: number;
12
-
13
- @IsString()
14
- @IsOptional()
15
- @ApiProperty()
16
- userUserKey: string;
17
-
18
- @IsNotEmpty()
19
- @IsOptional()
20
- @IsString()
21
- @ApiProperty()
22
- threadId: string;
23
-
24
- @IsNotEmpty()
25
- @IsOptional()
26
- @IsString()
27
- @ApiProperty()
28
- role: string;
29
-
30
- @IsNotEmpty()
31
- @IsOptional()
32
- @IsString()
33
- @ApiProperty()
34
- message: string;
35
-
36
- @IsOptional()
37
- @IsString()
38
- @ApiProperty()
39
- contentType: string;
40
-
41
- @IsOptional()
42
- @IsString()
43
- @ApiProperty()
44
- status: string;
45
-
46
- @IsOptional()
47
- @IsString()
48
- @ApiProperty()
49
- errorMessage: string;
50
-
51
- @IsOptional()
52
- @IsString()
53
- @ApiProperty()
54
- modelUsed: string;
55
-
56
- @IsOptional()
57
- @IsInt()
58
- @ApiProperty()
59
- responseTimeMs: number;
60
-
61
- @IsOptional()
62
- @IsJSON()
57
+ @IsBoolean()
63
58
  @ApiProperty()
64
- metadata: any;
59
+ isApplied: boolean;
65
60
  }
@@ -1,39 +1,34 @@
1
1
  import { CommonEntity } from 'src/entities/common.entity'
2
2
  import {Entity, JoinColumn, ManyToOne, Index, Column} from 'typeorm';
3
3
  import { User } from 'src/entities/user.entity'
4
- @Entity("ss_ai_interactions")
5
- export class AiInteraction extends CommonEntity{
6
- @Index()
7
- @ManyToOne(() => User, { onDelete: "CASCADE", nullable: false })
8
- @JoinColumn()
9
- user: User;
10
-
11
- @Index()
12
- @Column({ type: "varchar" })
13
- threadId: string;
14
-
15
- @Column({ type: "varchar" })
16
- role: string;
17
-
18
- @Column({ type: "text" })
19
- message: string;
20
-
21
- @Column({ type: "varchar", nullable: true })
22
- contentType: string;
23
4
 
24
- @Index()
25
- @Column({ type: "varchar", nullable: true })
26
- status: string;
27
-
28
- @Column({ type: "text", nullable: true })
29
- errorMessage: string;
30
-
31
- @Column({ type: "varchar", nullable: true })
32
- modelUsed: string;
33
-
34
- @Column({ type: "integer", nullable: true })
35
- responseTimeMs: number;
36
-
37
- @Column({ type: "jsonb", nullable: true })
38
- metadata: any;
5
+ @Entity("ss_ai_interactions")
6
+ export class AiInteraction extends CommonEntity {
7
+ @Index()
8
+ @ManyToOne(() => User, { onDelete: "CASCADE", nullable: false })
9
+ @JoinColumn()
10
+ user: User;
11
+ @Index()
12
+ @Column({ type: "varchar" })
13
+ threadId: string;
14
+ @Column({ type: "varchar" })
15
+ role: string;
16
+ @Column({ type: "text" })
17
+ message: string;
18
+ @Column({ type: "varchar", nullable: true })
19
+ contentType: string;
20
+ @Index()
21
+ @Column({ type: "varchar", nullable: true })
22
+ status: string;
23
+ @Column({ type: "text", nullable: true })
24
+ errorMessage: string;
25
+ @Column({ type: "varchar", nullable: true })
26
+ modelUsed: string;
27
+ @Column({ type: "integer", nullable: true })
28
+ responseTimeMs: number;
29
+ @Column({ type: "jsonb", nullable: true })
30
+ metadata: any;
31
+
32
+ @Column({ type: "boolean", nullable: true, default: false })
33
+ isApplied: boolean = false;
39
34
  }
@@ -22,4 +22,7 @@ export class DashboardQuestionSqlDatasetConfig extends CommonEntity {
22
22
  question: DashboardQuestion;
23
23
  @Column({ type: "text", nullable: true })
24
24
  options: any;
25
+ @Index({ unique: true })
26
+ @Column({ type: "varchar", nullable: true })
27
+ externalId: string;
25
28
  }
@@ -29,4 +29,7 @@ export class DashboardQuestion extends CommonEntity {
29
29
  kpiSql: string;
30
30
  @Column({ type: "integer", nullable: true })
31
31
  sequenceNumber: number;
32
+ @Index({ unique: true })
33
+ @Column({ type: "varchar", nullable: true })
34
+ externalId: string;
32
35
  }
package/src/interfaces.ts CHANGED
@@ -134,8 +134,8 @@ export interface IEntityComputedFieldProvider {
134
134
  name(): string;
135
135
  }
136
136
 
137
- export interface IEntityPreComputeFieldProvider<TTriggerEntity, TContext, TValue> extends IEntityComputedFieldProvider {
138
- preComputeValue(entity: TTriggerEntity, computedFieldMetadata: ComputedFieldMetadata<TContext>): Promise<TValue>;
137
+ export interface IEntityPreComputeFieldProvider<TTriggerEntity, TContext, TValue=void> extends IEntityComputedFieldProvider {
138
+ preComputeValue(triggerEntity: TTriggerEntity, computedFieldMetadata: ComputedFieldMetadata<TContext>): Promise<TValue>;
139
139
  }
140
140
 
141
141
  export interface IEntityPostComputeFieldProvider<TTriggerEntity, TContext> extends IEntityComputedFieldProvider {
@@ -62,7 +62,8 @@ export class TriggerMcpClientSubscriberDatabase extends DatabaseSubscriber<Trigg
62
62
  errorMessage: errorsStr,
63
63
  modelUsed: aiResponse.model,
64
64
  responseTimeMs: aiResponse.duration_ms,
65
- metadata: JSON.stringify(aiResponse)
65
+ metadata: JSON.stringify(aiResponse),
66
+ isApplied: aiInteraction.isApplied
66
67
  });
67
68
 
68
69
  // update the job entry with failure... raising an error will lead the job to be marked as failed...
@@ -80,7 +81,8 @@ export class TriggerMcpClientSubscriberDatabase extends DatabaseSubscriber<Trigg
80
81
  errorMessage: '',
81
82
  modelUsed: aiResponse.model,
82
83
  responseTimeMs: aiResponse.duration_ms,
83
- metadata: JSON.stringify(aiResponse)
84
+ metadata: JSON.stringify(aiResponse),
85
+ isApplied: aiInteraction.isApplied
84
86
  });
85
87
  }
86
88
 
@@ -28,7 +28,7 @@ export class DashboardMapper {
28
28
  chartOptions: question.chartOptions ?? null,
29
29
  labelSql: question.labelSql ?? null,
30
30
  kpiSql: question.kpiSql ?? null,
31
-
31
+ externalId: question.externalId,
32
32
  questionSqlDatasetConfigs: (question.questionSqlDatasetConfigs || []).map(config => ({
33
33
  sql: config.sql,
34
34
  datasetName: config.datasetName,
@@ -37,6 +37,7 @@ export class DashboardMapper {
37
37
  labelColumnName: config.labelColumnName,
38
38
  valueColumnName: config.valueColumnName,
39
39
  options: this.safeParseJSON(config.options, {}),
40
+ externalId: config.externalId
40
41
  }))
41
42
  }))
42
43
  };
@@ -0,0 +1,31 @@
1
+ import { Injectable, Logger } from "@nestjs/common";
2
+ import { Dashboard } from "src/entities/dashboard.entity";
3
+ import { ViewMetadata } from "src/entities/view-metadata.entity";
4
+ import { DataSource, Repository, View } from "typeorm";
5
+
6
+ @Injectable()
7
+ export class ViewMetadataRepository extends Repository<ViewMetadata> {
8
+ private readonly logger = new Logger(this.constructor.name);
9
+
10
+ constructor(
11
+ private dataSource: DataSource,
12
+ ) {
13
+ super(ViewMetadata, dataSource.createEntityManager());
14
+ }
15
+
16
+ // Custom repository methods can be added here if needed
17
+ async findByNameAndModelNameAndModuleName(name: string, modelUserKey: string, moduleUserKey: string): Promise<ViewMetadata | null> {
18
+ const viewMetadata = await this.findOne({
19
+ where: {
20
+ name,
21
+ model: {
22
+ singularName: modelUserKey,
23
+ module: {
24
+ name: moduleUserKey
25
+ }
26
+ }
27
+ }
28
+ });
29
+ return viewMetadata;
30
+ }
31
+ }
@@ -189,7 +189,7 @@ export class ModuleMetadataSeederService {
189
189
  // Email templates
190
190
  this.logger.debug(`[Start] Processing email templates for ${moduleMetadata.name}`);
191
191
  const emailTemplates: CreateEmailTemplateDto[] = overallMetadata.emailTemplates;
192
- await this.seedEmailTemplates(emailTemplates);
192
+ await this.seedEmailTemplates(emailTemplates, moduleMetadata);
193
193
  this.logger.debug(`[End] Processing email templates for ${moduleMetadata.name}`);
194
194
 
195
195
  // Sms templates
@@ -255,10 +255,11 @@ export class ModuleMetadataSeederService {
255
255
  'SavedFiltersController.partialUpdate',
256
256
  'SavedFiltersController.update',
257
257
  'SavedFiltersController.insertMany',
258
- 'SavedFiltersController.create'
258
+ 'SavedFiltersController.create',
259
+ 'AuthenticationController.logout'
259
260
  ]
260
261
  await this.roleService.addPermissionToRole('Internal User', internalRolePermission);
261
- await this.roleService.addPermissionToRole('Public', ['SettingController.wrapSettings']);
262
+ await this.roleService.addPermissionToRole('Public', ['SettingController.wrapSettings','AuthenticationController.logout']);
262
263
  this.logger.log(`All Seeders finished`);
263
264
  this.logger.log(`Newly created username is: ${usersDetail?.length > 0 ? usersDetail[0]?.username : ''} and password is ${usersDetail?.length > 0 ? usersDetail[0]?.password : ''}`);
264
265
  }
@@ -313,7 +314,7 @@ export class ModuleMetadataSeederService {
313
314
  }
314
315
  }
315
316
 
316
- async seedEmailTemplates(emailTemplates: CreateEmailTemplateDto[]) {
317
+ async seedEmailTemplates(emailTemplates: CreateEmailTemplateDto[], moduleMetadata: CreateModuleMetadataDto) {
317
318
  if (!emailTemplates) {
318
319
  return;
319
320
  }
@@ -323,19 +324,24 @@ export class ModuleMetadataSeederService {
323
324
  this.logger.log(`Found ${emailTemplate.name} email template`);
324
325
 
325
326
  // We need to load the actual template contents.
326
- // const emailTemplateFilePath = path.join(process.cwd(), emailTemplate.body);
327
-
328
- // emailTemplate.body = fs.readFileSync(emailTemplateFilePath, 'utf-8').toString()
329
- const modulePath = path.dirname(require.resolve('@solidstarters/solid-core'));
330
-
331
- // Resolve the `src` folder
332
- const seedDataPath = path.join(modulePath, '../src/seeders/seed-data/email-templates');
333
-
334
- // Example usage
335
- const filePath = path.join(seedDataPath, emailTemplate.body);
336
-
337
-
338
- emailTemplate.body = fs.readFileSync(filePath, 'utf-8').toString();
327
+ if (moduleMetadata.name === 'solid-core') {
328
+ const modulePath = path.dirname(require.resolve('@solidstarters/solid-core'));
329
+ const seedDataPath = path.join(modulePath, '../src/seeders/seed-data/email-templates');
330
+ const filePath = path.join(seedDataPath, emailTemplate.body);
331
+ this.logger.log(`Seeding email template from solid-core at path: ${filePath}`);
332
+ if (fs.existsSync(filePath)) {
333
+ emailTemplate.body = fs.readFileSync(filePath, 'utf-8').toString();
334
+ }
335
+ }
336
+ else {
337
+ // Check if file exists
338
+ const emailTemplateHandlebar = `module-metadata/${moduleMetadata.name}/email-templates/${emailTemplate.body}`
339
+ const fullPath = path.join(process.cwd(), emailTemplateHandlebar);
340
+ this.logger.log(`Seeding custom email template from consuming model at path: ${fullPath}`);
341
+ if (fs.existsSync(fullPath)) {
342
+ emailTemplate.body = fs.readFileSync(fullPath, 'utf-8').toString();
343
+ }
344
+ }
339
345
 
340
346
  // Save to DB.
341
347
  await this.emailTemplateService.removeByName(emailTemplate.name);
@@ -4736,6 +4736,31 @@
4736
4736
  "index": false,
4737
4737
  "private": false,
4738
4738
  "encrypt": false
4739
+ },
4740
+ {
4741
+ "name": "externalId",
4742
+ "displayName": "External ID",
4743
+ "type": "computed",
4744
+ "ormType": "varchar",
4745
+ "length": 128,
4746
+ "required": false,
4747
+ "unique": true,
4748
+ "index": true,
4749
+ "private": false,
4750
+ "encrypt": false,
4751
+ "isSystem": true,
4752
+ "computedFieldValueType": "string",
4753
+ "computedFieldValueProvider": "AlphaNumExternalIdComputationProvider",
4754
+ "computedFieldValueProviderCtxt": "{\"prefix\": \"DQ\"}",
4755
+ "computedFieldTriggerConfig": [
4756
+ {
4757
+ "modelName": "dashboardQuestion",
4758
+ "moduleName": "fees-portal",
4759
+ "operations": [
4760
+ "before-insert"
4761
+ ]
4762
+ }
4763
+ ]
4739
4764
  }
4740
4765
  ]
4741
4766
  },
@@ -4858,6 +4883,31 @@
4858
4883
  "index": false,
4859
4884
  "private": false,
4860
4885
  "encrypt": false
4886
+ },
4887
+ {
4888
+ "name": "externalId",
4889
+ "displayName": "External ID",
4890
+ "type": "computed",
4891
+ "ormType": "varchar",
4892
+ "length": 128,
4893
+ "required": false,
4894
+ "unique": true,
4895
+ "index": true,
4896
+ "private": false,
4897
+ "encrypt": false,
4898
+ "isSystem": true,
4899
+ "computedFieldValueType": "string",
4900
+ "computedFieldValueProvider": "AlphaNumExternalIdComputationProvider",
4901
+ "computedFieldValueProviderCtxt": "{\"prefix\": \"DQSDC\"}",
4902
+ "computedFieldTriggerConfig": [
4903
+ {
4904
+ "modelName": "dashboardQuestionSqlDatasetConfig",
4905
+ "moduleName": "fees-portal",
4906
+ "operations": [
4907
+ "before-insert"
4908
+ ]
4909
+ }
4910
+ ]
4861
4911
  }
4862
4912
  ]
4863
4913
  },
@@ -4996,6 +5046,17 @@
4996
5046
  "index": false,
4997
5047
  "private": false,
4998
5048
  "encrypt": false
5049
+ },
5050
+ {
5051
+ "name": "isApplied",
5052
+ "displayName": "Is Applied",
5053
+ "type": "boolean",
5054
+ "ormType": "boolean",
5055
+ "required": false,
5056
+ "unique": false,
5057
+ "index": false,
5058
+ "private": false,
5059
+ "encrypt": false
4999
5060
  }
5000
5061
  ]
5001
5062
  }
@@ -205,6 +205,9 @@ export class AiInteractionService extends CRUDService<AiInteraction> {
205
205
 
206
206
  // TODO: This provider to implement an interface - IMcpToolResponseHandler ... apply(aiInteraction: AiInteraction)
207
207
  // throw new Error('Method not implemented.');
208
+
209
+ // Mark the interaction as applied
210
+ await this.update(aiInteraction.id, { isApplied: true }, [], true);
208
211
 
209
212
  return handlerApplicationResponse;
210
213
  }
@@ -0,0 +1,68 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import { InjectEntityManager } from '@nestjs/typeorm';
3
+ import { ComputedFieldProvider } from 'src/decorators/computed-field-provider.decorator';
4
+ import { CommonEntity } from 'src/entities/common.entity';
5
+ import { ComputedFieldMetadata } from 'src/helpers/solid-registry';
6
+ import { IEntityPreComputeFieldProvider } from 'src/interfaces';
7
+ import { EntityManager } from 'typeorm';
8
+
9
+ export interface AlphaNumExternalIdContext {
10
+ prefix: string; // The prefix to use for the external ID
11
+ length?: number; // Optional: length of the unique code to generate, default is 5
12
+ }
13
+
14
+ @ComputedFieldProvider()
15
+ @Injectable()
16
+ export class AlphaNumExternalIdComputationProvider<T extends CommonEntity> implements IEntityPreComputeFieldProvider<T, AlphaNumExternalIdContext> {
17
+ constructor(
18
+ @InjectEntityManager()
19
+ private readonly entityManager: EntityManager
20
+ ) { }
21
+
22
+ name(): string {
23
+ return this.constructor.name;
24
+ }
25
+
26
+ help(): string {
27
+ return 'Provider used to compute external ID for a CommonEntity.';
28
+ }
29
+
30
+ async preComputeValue(triggerEntity: T, computedFieldMetadata: ComputedFieldMetadata<AlphaNumExternalIdContext>) {
31
+ const prefix = computedFieldMetadata.computedFieldValueProviderCtxt.prefix;
32
+ const codeLength = computedFieldMetadata.computedFieldValueProviderCtxt.length || 5;
33
+ const uniqueCode = await this.generateUniqueExternalId(codeLength, triggerEntity, computedFieldMetadata.fieldName);
34
+ triggerEntity[computedFieldMetadata.fieldName] = `${prefix}-${uniqueCode}`;
35
+ }
36
+
37
+ private generateRandomCode(length = 5): string {
38
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
39
+ let result = '';
40
+ for (let i = 0; i < length; i++) {
41
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
42
+ }
43
+ return result;
44
+ }
45
+
46
+ private async isExternalIdUnique(externalId: string, triggerEntity: T, fieldName: string): Promise<boolean> {
47
+ const count = await this.entityManager.count(triggerEntity.constructor.name, {
48
+ where: { [fieldName]: externalId },
49
+ });
50
+ return count === 0;
51
+ }
52
+
53
+ private async generateUniqueExternalId(codeLength: number, triggerEntity: T, fieldName: string): Promise<string> {
54
+ const maxAttempts = 10;
55
+
56
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
57
+ const newId = this.generateRandomCode(codeLength);
58
+
59
+ const isUnique = await this.isExternalIdUnique(newId, triggerEntity, fieldName);
60
+
61
+ if (isUnique) {
62
+ return newId;
63
+ }
64
+ }
65
+
66
+ throw new Error('Failed to generate a unique external ID after multiple attempts');
67
+ }
68
+ }
@@ -14,7 +14,7 @@ export interface ConcatComputedFieldContext {
14
14
 
15
15
  @ComputedFieldProvider()
16
16
  @Injectable()
17
- export class ConcatEntityComputedFieldProvider<T extends CommonEntity> implements IEntityPreComputeFieldProvider<T, ConcatComputedFieldContext, string> {
17
+ export class ConcatEntityComputedFieldProvider<T extends CommonEntity> implements IEntityPreComputeFieldProvider<T, ConcatComputedFieldContext> {
18
18
 
19
19
  name(): string {
20
20
  return "ConcatEntityComputedFieldProvider";
@@ -24,7 +24,7 @@ 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(entity: T, computedFieldMetadata: ComputedFieldMetadata<ConcatComputedFieldContext>): Promise<string> {
27
+ async preComputeValue(triggerEntity: T, computedFieldMetadata: ComputedFieldMetadata<ConcatComputedFieldContext>){
28
28
  const { computedFieldValueProviderCtxt } = computedFieldMetadata;
29
29
  const separator = computedFieldValueProviderCtxt.separator || ' '; // Default to space if no separator is provided
30
30
  const fields = computedFieldValueProviderCtxt.fields || [];
@@ -35,7 +35,7 @@ export class ConcatEntityComputedFieldProvider<T extends CommonEntity> implement
35
35
  const field = fields[i];
36
36
 
37
37
  // if slugify then each field val to be converted to a slug before concatenation
38
- let fieldVal = entity[field];
38
+ let fieldVal = triggerEntity[field];
39
39
  if (slugify && typeof fieldVal === 'string') {
40
40
  fieldVal = kebabCase(fieldVal);
41
41
  }
@@ -45,8 +45,7 @@ export class ConcatEntityComputedFieldProvider<T extends CommonEntity> implement
45
45
  }
46
46
  concatenatedString += fieldVal;
47
47
  }
48
-
49
- return concatenatedString;
48
+ triggerEntity[computedFieldMetadata.fieldName] = concatenatedString; //This set the computed value on the entity, since for pre-compute, entity and triggerEntity are the same
50
49
  }
51
50
 
52
51
  }