@solidstarters/solid-core 1.2.139 → 1.2.141
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/repository/view-metadata.repository.d.ts +9 -0
- package/dist/repository/view-metadata.repository.d.ts.map +1 -0
- package/dist/repository/view-metadata.repository.js +42 -0
- package/dist/repository/view-metadata.repository.js.map +1 -0
- package/dist/seeders/module-metadata-seeder.service.d.ts +1 -1
- package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.js +22 -8
- package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
- package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts +14 -0
- package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.d.ts.map +1 -0
- package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js +66 -0
- package/dist/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.js.map +1 -0
- 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 +25 -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 +114 -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/services/mcp-tool-response-handlers/solid-save-model-layout-mcp-tool-response-handler.service.d.ts +12 -0
- package/dist/services/mcp-tool-response-handlers/solid-save-model-layout-mcp-tool-response-handler.service.d.ts.map +1 -0
- package/dist/services/mcp-tool-response-handlers/solid-save-model-layout-mcp-tool-response-handler.service.js +36 -0
- package/dist/services/mcp-tool-response-handlers/solid-save-model-layout-mcp-tool-response-handler.service.js.map +1 -0
- package/dist/services/view-metadata.service.d.ts +3 -2
- package/dist/services/view-metadata.service.d.ts.map +1 -1
- package/dist/services/view-metadata.service.js +2 -3
- package/dist/services/view-metadata.service.js.map +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +19 -3
- package/dist/solid-core.module.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/repository/view-metadata.repository.ts +31 -0
- package/src/seeders/module-metadata-seeder.service.ts +23 -17
- package/src/services/computed-fields/entity/alpha-num-external-id-computed-field-provider.ts +70 -0
- 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 +113 -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/services/mcp-tool-response-handlers/solid-save-model-layout-mcp-tool-response-handler.service.ts +34 -0
- package/src/services/view-metadata.service.ts +3 -2
- package/src/solid-core.module.ts +20 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solidstarters/solid-core",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.141",
|
|
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",
|
|
@@ -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
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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);
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Injectable } from '@nestjs/common';
|
|
2
|
+
import { InjectEntityManager } from '@nestjs/typeorm';
|
|
3
|
+
import { ComputedFieldProvider } from 'src/decorators/computed-field-provider.decorator';
|
|
4
|
+
import { ComputedFieldMetadata } from 'src/helpers/solid-registry';
|
|
5
|
+
import { IEntityPreComputeFieldProvider } from 'src/interfaces';
|
|
6
|
+
// import {
|
|
7
|
+
// ComputedFieldMetadata,
|
|
8
|
+
// ComputedFieldProvider,
|
|
9
|
+
// IEntityPreComputeFieldProvider,
|
|
10
|
+
// } from '@solidstarters/solid-core';
|
|
11
|
+
import { EntityManager } from 'typeorm';
|
|
12
|
+
// import { Agreement } from '../entities/agreement.entity';
|
|
13
|
+
|
|
14
|
+
@ComputedFieldProvider()
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class AgreementIdComputationProvider implements IEntityPreComputeFieldProvider<any, any, string> {
|
|
17
|
+
constructor(
|
|
18
|
+
@InjectEntityManager()
|
|
19
|
+
private readonly entityManager: EntityManager
|
|
20
|
+
) { }
|
|
21
|
+
|
|
22
|
+
generateRandomCode(length = 5): string {
|
|
23
|
+
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
24
|
+
let result = '';
|
|
25
|
+
for (let i = 0; i < length; i++) {
|
|
26
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async isAgreementIdUnique(agreementId: string): Promise<boolean> {
|
|
32
|
+
// const count = await this.entityManager.count(Agreement, {
|
|
33
|
+
// where: { agreementId },
|
|
34
|
+
// });
|
|
35
|
+
// return count === 0;
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async generateUniqueAgreementId(codeLength: number): Promise<string> {
|
|
40
|
+
const maxAttempts = 10;
|
|
41
|
+
|
|
42
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
43
|
+
const newId = this.generateRandomCode(codeLength);
|
|
44
|
+
|
|
45
|
+
const isUnique = await this.isAgreementIdUnique(newId);
|
|
46
|
+
|
|
47
|
+
if (isUnique) {
|
|
48
|
+
return newId;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
throw new Error('Failed to generate a unique agreement ID after multiple attempts');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async preComputeValue(triggerEntity: any, computedFieldMetadata: ComputedFieldMetadata<any>): Promise<string> {
|
|
56
|
+
const prefix = computedFieldMetadata.computedFieldValueProviderCtxt['prefix'];
|
|
57
|
+
const codeLength = computedFieldMetadata.computedFieldValueProviderCtxt['length'] || 5;
|
|
58
|
+
const uniqueCode = await this.generateUniqueAgreementId(codeLength);
|
|
59
|
+
return `${prefix}-${uniqueCode}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
name(): string {
|
|
63
|
+
return 'AgreementIdComputationProvider';
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
help(): string {
|
|
67
|
+
return 'Provider used to compute values for the agreement id field on save.';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
}
|
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,113 @@
|
|
|
1
|
+
import { Injectable } from "@nestjs/common";
|
|
2
|
+
import { plainToInstance } from "class-transformer";
|
|
3
|
+
import { CreateDashboardDto } from "src/dtos/create-dashboard.dto";
|
|
4
|
+
import { UpdateMenuItemMetadataDto } from "src/dtos/update-menu-item-metadata.dto";
|
|
5
|
+
import { AiInteraction } from "src/entities/ai-interaction.entity";
|
|
6
|
+
import { Dashboard } from "src/entities/dashboard.entity";
|
|
7
|
+
import { IMcpToolResponseHandler } from "../../interfaces";
|
|
8
|
+
import { ActionMetadataService } from "../action-metadata.service";
|
|
9
|
+
import { DashboardService } from "../dashboard.service";
|
|
10
|
+
import { MenuItemMetadataService } from "../menu-item-metadata.service";
|
|
11
|
+
import { ModelMetadataService } from "../model-metadata.service";
|
|
12
|
+
import { ModuleMetadataService } from "../module-metadata.service";
|
|
13
|
+
import { RoleMetadataService } from "../role-metadata.service";
|
|
14
|
+
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class SolidCreateDashboardMcpToolResponseHandler implements IMcpToolResponseHandler {
|
|
17
|
+
|
|
18
|
+
constructor(
|
|
19
|
+
private readonly dashboardService: DashboardService,
|
|
20
|
+
private readonly actionMetadataService: ActionMetadataService,
|
|
21
|
+
private readonly menuItemMetadataService: MenuItemMetadataService,
|
|
22
|
+
private readonly moduleMetadataService: ModuleMetadataService,
|
|
23
|
+
private readonly modelMetadataService: ModelMetadataService,
|
|
24
|
+
private readonly roleService: RoleMetadataService, // Assuming roleService is a Mongoose model, adjust as necessary
|
|
25
|
+
) {
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async apply(aiInteraction: AiInteraction) {
|
|
29
|
+
const escapedMessage = aiInteraction.message.replace(/\\'/g, "'");
|
|
30
|
+
const aiResponseMessage = JSON.parse(escapedMessage);
|
|
31
|
+
|
|
32
|
+
const { dashboardDto, dashboard } = await this.createDashboard(aiResponseMessage);
|
|
33
|
+
|
|
34
|
+
const { moduleUserKey, actionMetadataEntity } = await this.createActionMetadataEntry(dashboardDto, dashboard);
|
|
35
|
+
|
|
36
|
+
await this.createMenuItemEntry(dashboard, moduleUserKey, actionMetadataEntity);
|
|
37
|
+
|
|
38
|
+
// TODO: decide on some shape to return hre...
|
|
39
|
+
return {
|
|
40
|
+
seedingRequired: false,
|
|
41
|
+
serverRebooting: false,
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
private async createMenuItemEntry(dashboard: Dashboard, moduleUserKey: string, actionMetadataEntity: any) {
|
|
47
|
+
const menuData = {
|
|
48
|
+
displayName: dashboard.displayName || dashboard.name,
|
|
49
|
+
name: `${moduleUserKey}-${dashboard.name}-dashboard-menu-item`,
|
|
50
|
+
sequenceNumber: 1,
|
|
51
|
+
actionUserKey: actionMetadataEntity.name,
|
|
52
|
+
moduleUserKey: moduleUserKey,
|
|
53
|
+
parentMenuItemUserKey: '',
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const adminRole = await this.roleService.findRoleByName('Admin');
|
|
57
|
+
const specifiedRoles = menuData['roles'];
|
|
58
|
+
|
|
59
|
+
// If the developer has specified roles, then resolve them, making sure that admin role is also given.
|
|
60
|
+
const specifiedRoleObjects = [adminRole];
|
|
61
|
+
if (specifiedRoles) {
|
|
62
|
+
for (let i = 0; i < specifiedRoles.length; i++) {
|
|
63
|
+
const specifiedRole = specifiedRoles[i];
|
|
64
|
+
const specifiedRoleObject = await this.roleService.findRoleByName(specifiedRole);
|
|
65
|
+
if (!specifiedRoleObject) {
|
|
66
|
+
throw new Error(`Invalid role: (${specifiedRole}) specified against menu with display name ${menuData.displayName}.`);
|
|
67
|
+
}
|
|
68
|
+
specifiedRoleObjects.push(specifiedRoleObject);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
menuData['roles'] = specifiedRoleObjects;
|
|
73
|
+
menuData['action'] = await this.actionMetadataService.findOneByUserKey(menuData.actionUserKey);
|
|
74
|
+
menuData['module'] = await this.moduleMetadataService.findOneByUserKey(menuData.moduleUserKey);
|
|
75
|
+
|
|
76
|
+
if (menuData.parentMenuItemUserKey) {
|
|
77
|
+
menuData['parentMenuItem'] = await this.menuItemMetadataService.findOneByUserKey(menuData.parentMenuItemUserKey);
|
|
78
|
+
} else {
|
|
79
|
+
menuData['parentMenuItem'] = null;
|
|
80
|
+
}
|
|
81
|
+
await this.menuItemMetadataService.upsert(menuData as unknown as UpdateMenuItemMetadataDto);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private async createActionMetadataEntry(dashboardDto: CreateDashboardDto, dashboard: Dashboard) {
|
|
85
|
+
const moduleUserKey = dashboardDto.moduleUserKey;
|
|
86
|
+
const actionMetadata = {
|
|
87
|
+
name: `${dashboard.name}-view`,
|
|
88
|
+
displayName: dashboard.displayName || dashboard.name,
|
|
89
|
+
type: 'custom',
|
|
90
|
+
domain: "{}",
|
|
91
|
+
context: "{}",
|
|
92
|
+
customComponent: `/admin/core/${moduleUserKey}/dashboards?dashboardName=${dashboard.name}`,
|
|
93
|
+
customIsModal: true,
|
|
94
|
+
serverEndpoint: '',
|
|
95
|
+
moduleUserKey: moduleUserKey,
|
|
96
|
+
modelUserKey: '',
|
|
97
|
+
viewUserKey: `${dashboard.name}-view`,
|
|
98
|
+
};
|
|
99
|
+
actionMetadata['module'] = await this.moduleMetadataService.findOneByUserKey(actionMetadata.moduleUserKey);
|
|
100
|
+
if (actionMetadata.modelUserKey) {
|
|
101
|
+
actionMetadata['model'] = await this.modelMetadataService.findOneByUserKey(actionMetadata.modelUserKey);
|
|
102
|
+
}
|
|
103
|
+
const actionMetadataEntity = await this.actionMetadataService.upsert(actionMetadata);
|
|
104
|
+
return { moduleUserKey, actionMetadataEntity };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private async createDashboard(aiResponseMessage: any) {
|
|
108
|
+
const dashboardDto = plainToInstance(CreateDashboardDto, aiResponseMessage);
|
|
109
|
+
dashboardDto['layoutJson'] = JSON.stringify(dashboardDto['layoutJson']);
|
|
110
|
+
const dashboard = await this.dashboardService.create(dashboardDto, []);
|
|
111
|
+
return { dashboardDto, dashboard };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Injectable } from "@nestjs/common";
|
|
2
|
+
import { AiInteraction } from "src/entities/ai-interaction.entity";
|
|
3
|
+
import { ViewMetadataRepository } from "src/repository/view-metadata.repository";
|
|
4
|
+
import { IMcpToolResponseHandler } from "../../interfaces";
|
|
5
|
+
|
|
6
|
+
@Injectable()
|
|
7
|
+
export class SolidCreateModelLayoutMcpToolResponseHandler implements IMcpToolResponseHandler {
|
|
8
|
+
|
|
9
|
+
constructor(
|
|
10
|
+
private readonly viewMetadataRepository: ViewMetadataRepository,
|
|
11
|
+
) {
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async apply(aiInteraction: AiInteraction) {
|
|
15
|
+
const aiResponse = JSON.parse(aiInteraction.message);
|
|
16
|
+
|
|
17
|
+
// Get the data for resolving the view metadata
|
|
18
|
+
const {name, modelUserKey, moduleUserKey, layout} = aiResponse;
|
|
19
|
+
|
|
20
|
+
// Fetch the view metadata for the given model and module and the view name
|
|
21
|
+
const viewMetadata = await this.viewMetadataRepository.findByNameAndModelNameAndModuleName(name, modelUserKey, moduleUserKey);
|
|
22
|
+
|
|
23
|
+
viewMetadata.layout = JSON.stringify(layout);
|
|
24
|
+
// Save the updated view metadata
|
|
25
|
+
await this.viewMetadataRepository.save(viewMetadata);
|
|
26
|
+
|
|
27
|
+
// TODO: decide on some shape to return hre...
|
|
28
|
+
return {
|
|
29
|
+
seedingRequired: false,
|
|
30
|
+
serverRebooting: false,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
}
|
|
@@ -20,6 +20,7 @@ import { ViewMetadata } from '../entities/view-metadata.entity';
|
|
|
20
20
|
import { ActionMetadataService } from './action-metadata.service';
|
|
21
21
|
import { SolidIntrospectService } from './solid-introspect.service';
|
|
22
22
|
import { UserViewMetadataService } from './user-view-metadata.service';
|
|
23
|
+
import { ViewMetadataRepository } from 'src/repository/view-metadata.repository';
|
|
23
24
|
|
|
24
25
|
@Injectable()
|
|
25
26
|
export class ViewMetadataService extends CRUDService<ViewMetadata> {
|
|
@@ -35,8 +36,8 @@ export class ViewMetadataService extends CRUDService<ViewMetadata> {
|
|
|
35
36
|
readonly userViewMetadataService: UserViewMetadataService,
|
|
36
37
|
@InjectEntityManager()
|
|
37
38
|
readonly entityManager: EntityManager,
|
|
38
|
-
@InjectRepository(ViewMetadata, 'default')
|
|
39
|
-
readonly repo:
|
|
39
|
+
// @InjectRepository(ViewMetadata, 'default')
|
|
40
|
+
readonly repo: ViewMetadataRepository,
|
|
40
41
|
@InjectRepository(FieldMetadata)
|
|
41
42
|
private readonly fieldMetadataRepo: Repository<FieldMetadata>,
|
|
42
43
|
@InjectRepository(ModelMetadata)
|
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,11 @@ 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';
|
|
258
|
+
import { ViewMetadataRepository } from './repository/view-metadata.repository';
|
|
259
|
+
import { SolidCreateModelLayoutMcpToolResponseHandler } from './services/mcp-tool-response-handlers/solid-save-model-layout-mcp-tool-response-handler.service';
|
|
252
260
|
|
|
253
261
|
|
|
254
262
|
@Global()
|
|
@@ -419,7 +427,7 @@ import { SolidCreateModuleMcpToolResponseHandler } from './services/mcp-tool-res
|
|
|
419
427
|
SmsTemplateService,
|
|
420
428
|
EmailTemplateService,
|
|
421
429
|
PublisherFactory,
|
|
422
|
-
|
|
430
|
+
|
|
423
431
|
McpToolResponseHandlerFactory,
|
|
424
432
|
SolidCreateModuleMcpToolResponseHandler,
|
|
425
433
|
|
|
@@ -528,6 +536,14 @@ import { SolidCreateModuleMcpToolResponseHandler } from './services/mcp-tool-res
|
|
|
528
536
|
DashboardVariableSubscriber,
|
|
529
537
|
DashboardQuestionSubscriber,
|
|
530
538
|
DashboardQuestionSqlDatasetConfigSubscriber,
|
|
539
|
+
SolidCreateDashboardMcpToolResponseHandler,
|
|
540
|
+
SolidCreateDashboardQuestionMcpToolResponseHandler,
|
|
541
|
+
SolidCreateDashboardQuestionSqlDatasetConfigMcpToolResponseHandler,
|
|
542
|
+
SolidCreateDashboardWidgetMcpToolResponseHandler,
|
|
543
|
+
SolidCreateModelWithFieldsMcpToolResponseHandler,
|
|
544
|
+
SolidAddFieldMcpToolResponseHandler,
|
|
545
|
+
ViewMetadataRepository,
|
|
546
|
+
SolidCreateModelLayoutMcpToolResponseHandler,
|
|
531
547
|
],
|
|
532
548
|
exports: [
|
|
533
549
|
ModuleMetadataService,
|