@solidstarters/solid-core 1.2.138 → 1.2.140
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/dist/helpers/field-crud-managers/ManyToOneRelationFieldCrudManager.d.ts +1 -1
- package/dist/helpers/field-crud-managers/ManyToOneRelationFieldCrudManager.d.ts.map +1 -1
- package/dist/helpers/field-crud-managers/ManyToOneRelationFieldCrudManager.js +4 -4
- package/dist/helpers/field-crud-managers/ManyToOneRelationFieldCrudManager.js.map +1 -1
- package/dist/services/crud.service.d.ts +1 -0
- package/dist/services/crud.service.d.ts.map +1 -1
- package/dist/services/crud.service.js +12 -4
- package/dist/services/crud.service.js.map +1 -1
- package/dist/services/mcp-tool-response-handlers/mcp-tool-response-handler-factory.service.d.ts +1 -1
- package/dist/services/mcp-tool-response-handlers/mcp-tool-response-handler-factory.service.d.ts.map +1 -1
- package/dist/services/mcp-tool-response-handlers/mcp-tool-response-handler-factory.service.js +1 -2
- package/dist/services/mcp-tool-response-handlers/mcp-tool-response-handler-factory.service.js.map +1 -1
- package/dist/services/mcp-tool-response-handlers/solid-add-field-mcp-tool-response-handler.service.d.ts +16 -0
- package/dist/services/mcp-tool-response-handlers/solid-add-field-mcp-tool-response-handler.service.d.ts.map +1 -0
- package/dist/services/mcp-tool-response-handlers/solid-add-field-mcp-tool-response-handler.service.js +48 -0
- package/dist/services/mcp-tool-response-handlers/solid-add-field-mcp-tool-response-handler.service.js.map +1 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-mcp-tool-response-handler.service.d.ts +12 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-mcp-tool-response-handler.service.d.ts.map +1 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-mcp-tool-response-handler.service.js +38 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-mcp-tool-response-handler.service.js.map +1 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-question-mcp-tool-response-handler.service.d.ts +12 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-question-mcp-tool-response-handler.service.d.ts.map +1 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-question-mcp-tool-response-handler.service.js +37 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-question-mcp-tool-response-handler.service.js.map +1 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-question-sql-dataset-config-mcp-tool-response-handler.service.d.ts +12 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-question-sql-dataset-config-mcp-tool-response-handler.service.d.ts.map +1 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-question-sql-dataset-config-mcp-tool-response-handler.service.js +38 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-question-sql-dataset-config-mcp-tool-response-handler.service.js.map +1 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-widget-mcp-tool-response-handler.service.d.ts +12 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-widget-mcp-tool-response-handler.service.d.ts.map +1 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-widget-mcp-tool-response-handler.service.js +38 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-dashboard-widget-mcp-tool-response-handler.service.js.map +1 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-model-with-fields-mcp-tool-response-handler.service.d.ts +16 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-model-with-fields-mcp-tool-response-handler.service.d.ts.map +1 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-model-with-fields-mcp-tool-response-handler.service.js +47 -0
- package/dist/services/mcp-tool-response-handlers/solid-create-model-with-fields-mcp-tool-response-handler.service.js.map +1 -0
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +15 -3
- package/dist/solid-core.module.js.map +1 -1
- package/dist/subscribers/dashboard.subscriber.d.ts.map +1 -1
- package/dist/subscribers/dashboard.subscriber.js +1 -1
- package/dist/subscribers/dashboard.subscriber.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/helpers/field-crud-managers/ManyToOneRelationFieldCrudManager.ts +6 -5
- package/src/services/crud.service.ts +14 -4
- package/src/services/mcp-tool-response-handlers/mcp-tool-response-handler-factory.service.ts +2 -4
- package/src/services/mcp-tool-response-handlers/solid-add-field-mcp-tool-response-handler.service.ts +56 -0
- package/src/services/mcp-tool-response-handlers/solid-create-dashboard-mcp-tool-response-handler.service.ts +39 -0
- package/src/services/mcp-tool-response-handlers/solid-create-dashboard-question-mcp-tool-response-handler.service.ts +38 -0
- package/src/services/mcp-tool-response-handlers/solid-create-dashboard-question-sql-dataset-config-mcp-tool-response-handler.service.ts +40 -0
- package/src/services/mcp-tool-response-handlers/solid-create-dashboard-widget-mcp-tool-response-handler.service.ts +39 -0
- package/src/services/mcp-tool-response-handlers/solid-create-model-with-fields-mcp-tool-response-handler.service.ts +46 -0
- package/src/solid-core.module.ts +16 -4
- package/src/subscribers/dashboard.subscriber.ts +1 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidstarters/solid-core",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.140",
|
|
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",
|
|
@@ -9,9 +9,10 @@ export interface ManyToOneRelationFieldOptions {
|
|
|
9
9
|
required: boolean | undefined | null;
|
|
10
10
|
relationCoModelSingularName: string | undefined | null;
|
|
11
11
|
fieldName: string | undefined | null;
|
|
12
|
-
modelUserKeyFieldName: string | undefined | null;
|
|
12
|
+
// modelUserKeyFieldName: string | undefined | null;
|
|
13
13
|
modelSingularName: string | undefined | null;
|
|
14
14
|
entityManager: EntityManager;
|
|
15
|
+
relationCoModelUserKeyFieldName: string | undefined | null;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
// This implementation is meant to be used for many-to-one relation field
|
|
@@ -50,8 +51,8 @@ export class ManyToOneRelationFieldCrudManager implements FieldCrudManager {
|
|
|
50
51
|
private applyUserKeyFormatValidations(fieldUserKey: string): ValidationError[] {
|
|
51
52
|
const errors: ValidationError[] = [];
|
|
52
53
|
!isString(fieldUserKey) ? errors.push({ field: this.options.fieldName, error: 'Field is not a string' }) : "no errors";
|
|
53
|
-
if (isEmpty(this.options.
|
|
54
|
-
errors.push({ field: this.options.fieldName, error: `UserKey field name is not defined in the model ${this.options.
|
|
54
|
+
if (isEmpty(this.options.relationCoModelUserKeyFieldName)) {
|
|
55
|
+
errors.push({ field: this.options.fieldName, error: `UserKey field name is not defined in the model ${this.options.relationCoModelSingularName}` });
|
|
55
56
|
}
|
|
56
57
|
return errors;
|
|
57
58
|
}
|
|
@@ -72,9 +73,9 @@ export class ManyToOneRelationFieldCrudManager implements FieldCrudManager {
|
|
|
72
73
|
}
|
|
73
74
|
}
|
|
74
75
|
else {
|
|
75
|
-
dto[this.options.fieldName] = await this.options.entityManager.getRepository(entityTarget).findOneBy({ [this.options.
|
|
76
|
+
dto[this.options.fieldName] = await this.options.entityManager.getRepository(entityTarget).findOneBy({ [this.options.relationCoModelUserKeyFieldName]: fieldUserKeyValue });
|
|
76
77
|
if (this.options.required && isEmpty(dto[this.options.fieldName])) {
|
|
77
|
-
throw new Error(`ManyToOneRelationFieldCrudManager: Record with userKey: ${this.options.
|
|
78
|
+
throw new Error(`ManyToOneRelationFieldCrudManager: Record with userKey: ${this.options.relationCoModelUserKeyFieldName}: ${fieldUserKeyValue} not found in ${this.options.relationCoModelSingularName}`);
|
|
78
79
|
}
|
|
79
80
|
}
|
|
80
81
|
|
|
@@ -111,7 +111,7 @@ export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDt
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
private async validateAndTransformDto(field: FieldMetadata, dto: any, files: Express.Multer.File[], hasMediaFields: boolean, isPartialUpdate: boolean = false, isUpdate: boolean = false) {
|
|
114
|
-
const fieldManager: FieldCrudManager = this.fieldCrudManager(field, this.entityManager, isPartialUpdate, isUpdate);
|
|
114
|
+
const fieldManager: FieldCrudManager = await this.fieldCrudManager(field, this.entityManager, isPartialUpdate, isUpdate);
|
|
115
115
|
const validationErrors = fieldManager.validate(dto, files);
|
|
116
116
|
const errors = (validationErrors instanceof Promise) ? await validationErrors : validationErrors;
|
|
117
117
|
if (errors.length > 0) {
|
|
@@ -259,7 +259,7 @@ export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDt
|
|
|
259
259
|
}
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
-
private fieldCrudManager(fieldMetadata: FieldMetadata, entityManager: EntityManager, isPartialUpdate: boolean = false, isUpdate: boolean = false)
|
|
262
|
+
private async fieldCrudManager(fieldMetadata: FieldMetadata, entityManager: EntityManager, isPartialUpdate: boolean = false, isUpdate: boolean = false) {
|
|
263
263
|
const commonOptions = { required: fieldMetadata.required && !isPartialUpdate, fieldName: fieldMetadata.name, isUpdate };
|
|
264
264
|
switch (fieldMetadata.type) {
|
|
265
265
|
case SolidFieldType.shortText: {
|
|
@@ -326,11 +326,13 @@ export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDt
|
|
|
326
326
|
case SolidFieldType.relation: {
|
|
327
327
|
// Identify if the field is for the inverse side or not
|
|
328
328
|
if (fieldMetadata.relationType === RelationType.manyToOne) {
|
|
329
|
+
const relationCoModelUserKeyFieldName = await this.getUserKeyFieldNameForModel(fieldMetadata.relationCoModelSingularName);
|
|
329
330
|
const manyToOneOptions: ManyToOneRelationFieldOptions = {
|
|
330
331
|
...commonOptions,
|
|
331
332
|
relationCoModelSingularName: fieldMetadata.relationCoModelSingularName,
|
|
332
|
-
modelUserKeyFieldName: fieldMetadata.model.userKeyField?.name,
|
|
333
|
+
// modelUserKeyFieldName: fieldMetadata.model.userKeyField?.name,
|
|
333
334
|
modelSingularName: fieldMetadata.model.singularName,
|
|
335
|
+
relationCoModelUserKeyFieldName: relationCoModelUserKeyFieldName,
|
|
334
336
|
entityManager,
|
|
335
337
|
}
|
|
336
338
|
return new ManyToOneRelationFieldCrudManager(manyToOneOptions);
|
|
@@ -677,7 +679,7 @@ export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDt
|
|
|
677
679
|
|
|
678
680
|
// Process each field
|
|
679
681
|
for (const field of model.fields) {
|
|
680
|
-
const fieldManager: FieldCrudManager = this.fieldCrudManager(field, this.entityManager);
|
|
682
|
+
const fieldManager: FieldCrudManager = await this.fieldCrudManager(field, this.entityManager);
|
|
681
683
|
const validationErrors = await fieldManager.validate(createDto, files);
|
|
682
684
|
if (validationErrors.length > 0) {
|
|
683
685
|
throw new BadRequestException(`Validation errors in ${field.name} are invalid: ${validationErrors.map(e => e.error).join(', ')}`);
|
|
@@ -871,5 +873,13 @@ export class CRUDService<T> { // Add two generic value i.e Person,CreatePersonDt
|
|
|
871
873
|
|
|
872
874
|
return this.getFieldMetadataRecursively(remainingParts, relationCoModel.fields);
|
|
873
875
|
}
|
|
876
|
+
|
|
877
|
+
async getUserKeyFieldNameForModel(modelSingularName: string): Promise<string> {
|
|
878
|
+
const model = await this.modelMetadataService.findOneBySingularName(modelSingularName, ['userKeyField']);
|
|
879
|
+
if (!model) {
|
|
880
|
+
throw new BadRequestException(`Model ${modelSingularName} not found`);
|
|
881
|
+
}
|
|
882
|
+
return model.userKeyField?.name || '';
|
|
883
|
+
}
|
|
874
884
|
}
|
|
875
885
|
|
package/src/services/mcp-tool-response-handlers/mcp-tool-response-handler-factory.service.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { Logger } from '@nestjs/common';
|
|
2
|
-
import { Injectable } from '@nestjs/common';
|
|
1
|
+
import { Injectable, Logger } from '@nestjs/common';
|
|
3
2
|
|
|
4
|
-
import { QueueMessage, QueuePublisher } from 'src/interfaces/mq';
|
|
5
3
|
import { classify } from '@angular-devkit/core/src/utils/strings';
|
|
6
|
-
import { SolidIntrospectService } from '../solid-introspect.service';
|
|
7
4
|
import { IMcpToolResponseHandler } from 'src/interfaces';
|
|
5
|
+
import { SolidIntrospectService } from '../solid-introspect.service';
|
|
8
6
|
|
|
9
7
|
|
|
10
8
|
@Injectable()
|
package/src/services/mcp-tool-response-handlers/solid-add-field-mcp-tool-response-handler.service.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Injectable } from "@nestjs/common";
|
|
2
|
+
import { UpdateModelMetaDataDto } from "src/dtos/update-model-metadata.dto";
|
|
3
|
+
import { AiInteraction } from "src/entities/ai-interaction.entity";
|
|
4
|
+
import { FieldMetadata } from "src/entities/field-metadata.entity";
|
|
5
|
+
import { SolidRegistry } from "src/helpers/solid-registry";
|
|
6
|
+
import { IMcpToolResponseHandler } from "../../interfaces";
|
|
7
|
+
import { FieldMetadataService } from "../field-metadata.service";
|
|
8
|
+
import { ModelMetadataService } from "../model-metadata.service";
|
|
9
|
+
|
|
10
|
+
@Injectable()
|
|
11
|
+
// solid_add_field
|
|
12
|
+
export class SolidAddFieldMcpToolResponseHandler implements IMcpToolResponseHandler {
|
|
13
|
+
|
|
14
|
+
constructor(
|
|
15
|
+
private readonly modelMetadataService: ModelMetadataService,
|
|
16
|
+
private readonly fieldMetadataService: FieldMetadataService,
|
|
17
|
+
private readonly solidRegistry: SolidRegistry,
|
|
18
|
+
) {
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async apply(aiInteraction: AiInteraction) {
|
|
22
|
+
// const aiResponse = JSON.parse(aiInteraction.message);
|
|
23
|
+
const escapedMessage = aiInteraction.message.replace(/\\'/g, "'");
|
|
24
|
+
const aiResponse = JSON.parse(escapedMessage);
|
|
25
|
+
|
|
26
|
+
const { modelUserKey, fieldSchema } = aiResponse;
|
|
27
|
+
|
|
28
|
+
// TODO: Validate if another field with same name exists, if it does then raise an error...
|
|
29
|
+
|
|
30
|
+
// TODO: load the model with the fields.
|
|
31
|
+
const modelMetadata = await this.modelMetadataService.findOneByUserKey(modelUserKey, ['fields']);
|
|
32
|
+
if (!modelMetadata) {
|
|
33
|
+
throw new Error(`Model with user key ${modelUserKey} not found.`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Add the fieldSchema to the model fields array
|
|
37
|
+
fieldSchema['modelId'] = modelMetadata.id;
|
|
38
|
+
modelMetadata.fields.push(fieldSchema as FieldMetadata);
|
|
39
|
+
|
|
40
|
+
const modelObj = await this.modelMetadataService.update(modelMetadata.id, modelMetadata as unknown as UpdateModelMetaDataDto);
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
// This creates the module-metadata.json file....
|
|
44
|
+
// const modelObj = await this.fieldMetadataService.create(fieldSchema as CreateFieldMetadataDto);
|
|
45
|
+
|
|
46
|
+
// Now we need to run solid seed & then solid refresh-model --name <module-name>
|
|
47
|
+
await this.modelMetadataService.handleGenerateCode({ modelId: modelMetadata.id });
|
|
48
|
+
|
|
49
|
+
// TODO: decide on some shape to return hre...
|
|
50
|
+
return {
|
|
51
|
+
seedingRequired: true,
|
|
52
|
+
serverRebooting: true,
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Injectable } from "@nestjs/common";
|
|
2
|
+
import { plainToInstance } from "class-transformer";
|
|
3
|
+
import { CreateDashboardDto } from "src/dtos/create-dashboard.dto";
|
|
4
|
+
import { AiInteraction } from "src/entities/ai-interaction.entity";
|
|
5
|
+
import { IMcpToolResponseHandler } from "../../interfaces";
|
|
6
|
+
import { DashboardService } from "../dashboard.service";
|
|
7
|
+
|
|
8
|
+
@Injectable()
|
|
9
|
+
export class SolidCreateDashboardMcpToolResponseHandler implements IMcpToolResponseHandler {
|
|
10
|
+
|
|
11
|
+
constructor(
|
|
12
|
+
private readonly dashboardService: DashboardService,
|
|
13
|
+
) {
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async apply(aiInteraction: AiInteraction) {
|
|
17
|
+
const escapedMessage = aiInteraction.message.replace(/\\'/g, "'");
|
|
18
|
+
const aiResponseMessage = JSON.parse(escapedMessage);
|
|
19
|
+
|
|
20
|
+
// const aiResponse = JSON.parse(aiInteraction.message);
|
|
21
|
+
|
|
22
|
+
//FIXME: Replace \' with ' in the response, since the AI response seems to contain \' which is invalid JSON.
|
|
23
|
+
// This is a workaround for now, until we find a better solution.
|
|
24
|
+
// const aiResponseMessageReplaced = aiResponse['message'].replace(/\\'/g, "'");
|
|
25
|
+
|
|
26
|
+
const dashboardDto = plainToInstance(CreateDashboardDto, aiResponseMessage);
|
|
27
|
+
dashboardDto['layoutJson'] = JSON.stringify(dashboardDto['layoutJson']);
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
const dashboard = await this.dashboardService.create(dashboardDto, []);
|
|
31
|
+
|
|
32
|
+
// TODO: decide on some shape to return hre...
|
|
33
|
+
return {
|
|
34
|
+
seedingRequired: false,
|
|
35
|
+
serverRebooting: false,
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Injectable } from "@nestjs/common";
|
|
2
|
+
import { plainToInstance } from "class-transformer";
|
|
3
|
+
import { CreateDashboardQuestionDto } from "src/dtos/create-dashboard-question.dto";
|
|
4
|
+
import { AiInteraction } from "src/entities/ai-interaction.entity";
|
|
5
|
+
import { IMcpToolResponseHandler } from "../../interfaces";
|
|
6
|
+
import { DashboardQuestionService } from "../dashboard-question.service";
|
|
7
|
+
|
|
8
|
+
@Injectable()
|
|
9
|
+
export class SolidCreateDashboardQuestionMcpToolResponseHandler implements IMcpToolResponseHandler {
|
|
10
|
+
|
|
11
|
+
constructor(
|
|
12
|
+
private readonly dashboardQuestionService: DashboardQuestionService,
|
|
13
|
+
) {
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async apply(aiInteraction: AiInteraction) {
|
|
17
|
+
const escapedMessage = aiInteraction.message.replace(/\\'/g, "'");
|
|
18
|
+
const aiResponseMessage = JSON.parse(escapedMessage);
|
|
19
|
+
|
|
20
|
+
//FIXME: Replace \' with ' in the response, since the AI response seems to contain \' which is invalid JSON.
|
|
21
|
+
// This is a workaround for now, until we find a better solution.
|
|
22
|
+
// const aiResponseMessageReplaced = aiResponseMessage['message'].replace(/\\'/g, "'");
|
|
23
|
+
// const dashboardUserKey = aiResponseMessageReplaced['dashboardUserKey'];
|
|
24
|
+
// if (!dashboardUserKey) {
|
|
25
|
+
// throw new Error("Dashboard User Key is required to create a Dashboard Question.");
|
|
26
|
+
// }
|
|
27
|
+
const dashboardQuestionDto = plainToInstance(CreateDashboardQuestionDto, aiResponseMessage);
|
|
28
|
+
|
|
29
|
+
const dashboardQuestion = await this.dashboardQuestionService.create(dashboardQuestionDto, []);
|
|
30
|
+
|
|
31
|
+
// TODO: decide on some shape to return hre...
|
|
32
|
+
return {
|
|
33
|
+
seedingRequired: false,
|
|
34
|
+
serverRebooting: false,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Injectable } from "@nestjs/common";
|
|
2
|
+
import { plainToInstance } from "class-transformer";
|
|
3
|
+
import { AiInteraction } from "src/entities/ai-interaction.entity";
|
|
4
|
+
import { IMcpToolResponseHandler } from "../../interfaces";
|
|
5
|
+
import { DashboardQuestionSqlDatasetConfigService } from "../dashboard-question-sql-dataset-config.service";
|
|
6
|
+
import { CreateDashboardQuestionSqlDatasetConfigDto } from "src/dtos/create-dashboard-question-sql-dataset-config.dto";
|
|
7
|
+
|
|
8
|
+
@Injectable()
|
|
9
|
+
export class SolidCreateDashboardQuestionSqlDatasetConfigMcpToolResponseHandler implements IMcpToolResponseHandler {
|
|
10
|
+
|
|
11
|
+
constructor(
|
|
12
|
+
private readonly dashboardQuestionSqlDatasetConfigService: DashboardQuestionSqlDatasetConfigService,
|
|
13
|
+
) {
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async apply(aiInteraction: AiInteraction) {
|
|
17
|
+
// const aiResponse = JSON.parse(aiInteraction.message);
|
|
18
|
+
const escapedMessage = aiInteraction.message.replace(/\\'/g, "'");
|
|
19
|
+
const aiResponseMessage = JSON.parse(escapedMessage);
|
|
20
|
+
|
|
21
|
+
// FIXME: Replace \' with ' in the response, since the AI response seems to contain \' which is invalid JSON.
|
|
22
|
+
// This is a workaround for now, until we find a better solution.
|
|
23
|
+
// const aiResponseMessageReplaced = aiResponse['message'].replace(/\\'/g, "'");
|
|
24
|
+
// const dashboardUserKey = aiResponseMessageReplaced['dashboardUserKey'];
|
|
25
|
+
// if (!dashboardUserKey) {
|
|
26
|
+
// throw new Error("Dashboard User Key is required to create a Dashboard Question.");
|
|
27
|
+
// }
|
|
28
|
+
const dto = plainToInstance(CreateDashboardQuestionSqlDatasetConfigDto, aiResponseMessage);
|
|
29
|
+
dto['options'] = JSON.stringify(dto['options']);
|
|
30
|
+
|
|
31
|
+
const dashboardQuestion = await this.dashboardQuestionSqlDatasetConfigService.create(dto, []);
|
|
32
|
+
|
|
33
|
+
// TODO: decide on some shape to return hre...
|
|
34
|
+
return {
|
|
35
|
+
seedingRequired: false,
|
|
36
|
+
serverRebooting: false,
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Injectable } from "@nestjs/common";
|
|
2
|
+
import { plainToInstance } from "class-transformer";
|
|
3
|
+
import { CreateDashboardQuestionDto } from "src/dtos/create-dashboard-question.dto";
|
|
4
|
+
import { AiInteraction } from "src/entities/ai-interaction.entity";
|
|
5
|
+
import { IMcpToolResponseHandler } from "../../interfaces";
|
|
6
|
+
import { DashboardQuestionService } from "../dashboard-question.service";
|
|
7
|
+
|
|
8
|
+
@Injectable()
|
|
9
|
+
export class SolidCreateDashboardWidgetMcpToolResponseHandler implements IMcpToolResponseHandler {
|
|
10
|
+
|
|
11
|
+
constructor(
|
|
12
|
+
private readonly dashboardQuestionService: DashboardQuestionService,
|
|
13
|
+
) {
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async apply(aiInteraction: AiInteraction) {
|
|
17
|
+
const escapedMessage = aiInteraction.message.replace(/\\'/g, "'");
|
|
18
|
+
const aiResponseMessage = JSON.parse(escapedMessage);
|
|
19
|
+
|
|
20
|
+
//FIXME: Replace \' with ' in the response, since the AI response seems to contain \' which is invalid JSON.
|
|
21
|
+
// This is a workaround for now, until we find a better solution.
|
|
22
|
+
// const aiResponseMessageReplaced = aiResponseMessage['message'].replace(/\\'/g, "'");
|
|
23
|
+
// const dashboardUserKey = aiResponseMessageReplaced['dashboardUserKey'];
|
|
24
|
+
// if (!dashboardUserKey) {
|
|
25
|
+
// throw new Error("Dashboard User Key is required to create a Dashboard Question.");
|
|
26
|
+
// }
|
|
27
|
+
const dashboardQuestionDto = plainToInstance(CreateDashboardQuestionDto, aiResponseMessage);
|
|
28
|
+
dashboardQuestionDto['questionSqlDatasetConfigsCommand'] = "update";
|
|
29
|
+
|
|
30
|
+
const dashboardQuestion = await this.dashboardQuestionService.create(dashboardQuestionDto, []);
|
|
31
|
+
|
|
32
|
+
// TODO: decide on some shape to return hre...
|
|
33
|
+
return {
|
|
34
|
+
seedingRequired: false,
|
|
35
|
+
serverRebooting: false,
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Injectable } from "@nestjs/common";
|
|
2
|
+
import { IMcpToolResponseHandler } from "../../interfaces";
|
|
3
|
+
import { AiInteraction } from "src/entities/ai-interaction.entity";
|
|
4
|
+
import { SolidRegistry } from "src/helpers/solid-registry";
|
|
5
|
+
import { ModelMetadataService } from "../model-metadata.service";
|
|
6
|
+
import { CreateModelMetadataDto } from "src/dtos/create-model-metadata.dto";
|
|
7
|
+
import { ModuleMetadataService } from "../module-metadata.service";
|
|
8
|
+
|
|
9
|
+
@Injectable()
|
|
10
|
+
export class SolidCreateModelWithFieldsMcpToolResponseHandler implements IMcpToolResponseHandler {
|
|
11
|
+
|
|
12
|
+
constructor(
|
|
13
|
+
private readonly moduleMetadataService: ModuleMetadataService,
|
|
14
|
+
private readonly modelMetadataService: ModelMetadataService,
|
|
15
|
+
private readonly solidRegistry: SolidRegistry,
|
|
16
|
+
) {
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async apply(aiInteraction: AiInteraction) {
|
|
20
|
+
// const aiResponse = JSON.parse(aiInteraction.message);
|
|
21
|
+
const escapedMessage = aiInteraction.message.replace(/\\'/g, "'");
|
|
22
|
+
const aiResponse = JSON.parse(escapedMessage);
|
|
23
|
+
|
|
24
|
+
const { moduleUserKey, modelSchema } = aiResponse;
|
|
25
|
+
const moduleMetadata = await this.moduleMetadataService.findOneByUserKey(moduleUserKey);
|
|
26
|
+
if (!moduleMetadata) {
|
|
27
|
+
throw new Error(`Module with user key ${moduleUserKey} not found.`);
|
|
28
|
+
}
|
|
29
|
+
modelSchema['moduleId'] = moduleMetadata.id;
|
|
30
|
+
|
|
31
|
+
// TODO: Validate if another model with same name exists, if it does then raise an error...
|
|
32
|
+
|
|
33
|
+
// This creates the module-metadata.json file....
|
|
34
|
+
const modelObj = await this.modelMetadataService.create(modelSchema as CreateModelMetadataDto);
|
|
35
|
+
|
|
36
|
+
// Now we need to run solid seed & then solid refresh-model --name <module-name>
|
|
37
|
+
await this.modelMetadataService.handleGenerateCode({ modelId: modelObj.id });
|
|
38
|
+
|
|
39
|
+
// TODO: decide on some shape to return hre...
|
|
40
|
+
return {
|
|
41
|
+
seedingRequired: true,
|
|
42
|
+
serverRebooting: true,
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}
|
package/src/solid-core.module.ts
CHANGED
|
@@ -203,6 +203,7 @@ import { ChatterMessageDetailsService } from './services/chatter-message-details
|
|
|
203
203
|
import { ChatterMessageService } from './services/chatter-message.service';
|
|
204
204
|
import { ConcatComputedFieldProvider } from './services/computed-fields/concat-computed-field-provider.service';
|
|
205
205
|
import { ConcatEntityComputedFieldProvider } from './services/computed-fields/entity/concat-entity-computed-field-provider.service';
|
|
206
|
+
import { CRUDService } from './services/crud.service';
|
|
206
207
|
import { CsvService } from './services/csv.service';
|
|
207
208
|
import { DashboardQuestionSqlDatasetConfigService } from './services/dashboard-question-sql-dataset-config.service';
|
|
208
209
|
import { DashboardQuestionService } from './services/dashboard-question.service';
|
|
@@ -216,6 +217,11 @@ import { ExportTransactionService } from './services/export-transaction.service'
|
|
|
216
217
|
import { ImportTransactionErrorLogService } from './services/import-transaction-error-log.service';
|
|
217
218
|
import { ImportTransactionService } from './services/import-transaction.service';
|
|
218
219
|
import { LocaleService } from './services/locale.service';
|
|
220
|
+
import { McpToolResponseHandlerFactory } from './services/mcp-tool-response-handlers/mcp-tool-response-handler-factory.service';
|
|
221
|
+
import { SolidCreateDashboardMcpToolResponseHandler } from './services/mcp-tool-response-handlers/solid-create-dashboard-mcp-tool-response-handler.service';
|
|
222
|
+
import { SolidCreateDashboardQuestionMcpToolResponseHandler } from './services/mcp-tool-response-handlers/solid-create-dashboard-question-mcp-tool-response-handler.service';
|
|
223
|
+
import { SolidCreateDashboardQuestionSqlDatasetConfigMcpToolResponseHandler } from './services/mcp-tool-response-handlers/solid-create-dashboard-question-sql-dataset-config-mcp-tool-response-handler.service';
|
|
224
|
+
import { SolidCreateModuleMcpToolResponseHandler } from './services/mcp-tool-response-handlers/solid-create-module-mcp-tool-response-handler.service';
|
|
219
225
|
import { FileS3StorageProvider } from './services/mediaStorageProviders/file-s3-storage-provider';
|
|
220
226
|
import { FileStorageProvider } from './services/mediaStorageProviders/file-storage-provider';
|
|
221
227
|
import { ChartJsSqlDataProvider } from './services/question-data-providers/chartjs-sql-data-provider.service';
|
|
@@ -246,9 +252,9 @@ import { DashboardVariableSubscriber } from './subscribers/dashboard-variable.su
|
|
|
246
252
|
import { DashboardSubscriber } from './subscribers/dashboard.subscriber';
|
|
247
253
|
import { SecurityRuleSubscriber } from './subscribers/security-rule.subscriber';
|
|
248
254
|
import { ViewMetadataSubsciber } from './subscribers/view-metadata.subscriber';
|
|
249
|
-
import {
|
|
250
|
-
import {
|
|
251
|
-
import {
|
|
255
|
+
import { SolidCreateDashboardWidgetMcpToolResponseHandler } from './services/mcp-tool-response-handlers/solid-create-dashboard-widget-mcp-tool-response-handler.service';
|
|
256
|
+
import { SolidCreateModelWithFieldsMcpToolResponseHandler } from './services/mcp-tool-response-handlers/solid-create-model-with-fields-mcp-tool-response-handler.service';
|
|
257
|
+
import { SolidAddFieldMcpToolResponseHandler } from './services/mcp-tool-response-handlers/solid-add-field-mcp-tool-response-handler.service';
|
|
252
258
|
|
|
253
259
|
|
|
254
260
|
@Global()
|
|
@@ -419,7 +425,7 @@ import { SolidCreateModuleMcpToolResponseHandler } from './services/mcp-tool-res
|
|
|
419
425
|
SmsTemplateService,
|
|
420
426
|
EmailTemplateService,
|
|
421
427
|
PublisherFactory,
|
|
422
|
-
|
|
428
|
+
|
|
423
429
|
McpToolResponseHandlerFactory,
|
|
424
430
|
SolidCreateModuleMcpToolResponseHandler,
|
|
425
431
|
|
|
@@ -528,6 +534,12 @@ import { SolidCreateModuleMcpToolResponseHandler } from './services/mcp-tool-res
|
|
|
528
534
|
DashboardVariableSubscriber,
|
|
529
535
|
DashboardQuestionSubscriber,
|
|
530
536
|
DashboardQuestionSqlDatasetConfigSubscriber,
|
|
537
|
+
SolidCreateDashboardMcpToolResponseHandler,
|
|
538
|
+
SolidCreateDashboardQuestionMcpToolResponseHandler,
|
|
539
|
+
SolidCreateDashboardQuestionSqlDatasetConfigMcpToolResponseHandler,
|
|
540
|
+
SolidCreateDashboardWidgetMcpToolResponseHandler,
|
|
541
|
+
SolidCreateModelWithFieldsMcpToolResponseHandler,
|
|
542
|
+
SolidAddFieldMcpToolResponseHandler,
|
|
531
543
|
],
|
|
532
544
|
exports: [
|
|
533
545
|
ModuleMetadataService,
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { Injectable, Logger } from '@nestjs/common';
|
|
2
2
|
import { InjectDataSource } from "@nestjs/typeorm";
|
|
3
|
-
import * as fs from 'fs/promises'; // Use the Promise-based version of fs for async/await
|
|
4
3
|
import { Dashboard } from 'src/entities/dashboard.entity';
|
|
5
4
|
import { ModuleMetadataHelperService } from "src/helpers/module-metadata-helper.service";
|
|
6
|
-
import { DashboardMapper } from 'src/mappers/dashboard-mapper';
|
|
7
5
|
import { DashboardService } from 'src/services/dashboard.service';
|
|
8
6
|
import { DataSource, EntityManager, EntitySubscriberInterface, InsertEvent, UpdateEvent } from "typeorm";
|
|
9
7
|
|
|
@@ -49,7 +47,7 @@ export class DashboardSubscriber implements EntitySubscriberInterface<Dashboard>
|
|
|
49
47
|
// Load the dashboard with module relation populated
|
|
50
48
|
const populatedDashboard = await entityManager.findOne(Dashboard, {
|
|
51
49
|
where: { id: dashboard.id },
|
|
52
|
-
relations: ['module'],
|
|
50
|
+
relations: ['module','dashboardVariables', 'questions', 'questions.questionSqlDatasetConfigs'],
|
|
53
51
|
});
|
|
54
52
|
|
|
55
53
|
if (!populatedDashboard) {
|