[Dashboards] [ai] update dashboard tools schema and skill with correct config field names (#17180)
<img width="2560" height="1353" alt="CleanShot 2026-01-16 at 00 55 56" src="https://github.com/user-attachments/assets/c242071c-13d3-494d-bcce-9d45f36fcd77" />
This commit is contained in:
+14
-13
@@ -60,24 +60,25 @@ GRID SYSTEM:
|
||||
|
||||
WIDGET TYPES:
|
||||
|
||||
1. GRAPH with graphType "AGGREGATE" (KPI number):
|
||||
- Requires: objectMetadataId, configuration.graphType, configuration.aggregateFieldMetadataId, configuration.aggregateOperation
|
||||
- Example: { type: "GRAPH", objectMetadataId: "<opportunity-object-uuid>", configuration: { graphType: "AGGREGATE", aggregateFieldMetadataId: "<amount-field-uuid>", aggregateOperation: "SUM" } }
|
||||
1. GRAPH with configurationType "AGGREGATE_CHART" (KPI number):
|
||||
- Requires: objectMetadataId, configuration.configurationType, configuration.aggregateFieldMetadataId, configuration.aggregateOperation
|
||||
- Example: { type: "GRAPH", objectMetadataId: "<opportunity-object-uuid>", configuration: { configurationType: "AGGREGATE_CHART", aggregateFieldMetadataId: "<amount-field-uuid>", aggregateOperation: "SUM" } }
|
||||
|
||||
2. GRAPH with graphType "VERTICAL_BAR" or "HORIZONTAL_BAR":
|
||||
2. GRAPH with configurationType "BAR_CHART":
|
||||
- Additional required: configuration.primaryAxisGroupByFieldMetadataId, configuration.layout ("VERTICAL" or "HORIZONTAL")
|
||||
- Example: { type: "GRAPH", objectMetadataId: "<opportunity-object-uuid>", configuration: { configurationType: "BAR_CHART", aggregateFieldMetadataId: "<amount-field-uuid>", aggregateOperation: "COUNT", primaryAxisGroupByFieldMetadataId: "<stage-field-uuid>", layout: "VERTICAL" } }
|
||||
|
||||
3. GRAPH with configurationType "LINE_CHART":
|
||||
- Additional required: configuration.primaryAxisGroupByFieldMetadataId
|
||||
- Example: { graphType: "VERTICAL_BAR", aggregateFieldMetadataId: "<count-field-uuid>", aggregateOperation: "COUNT", primaryAxisGroupByFieldMetadataId: "<stage-field-uuid>" }
|
||||
- Example: { type: "GRAPH", objectMetadataId: "<opportunity-object-uuid>", configuration: { configurationType: "LINE_CHART", aggregateFieldMetadataId: "<amount-field-uuid>", aggregateOperation: "SUM", primaryAxisGroupByFieldMetadataId: "<created-date-field-uuid>" } }
|
||||
|
||||
3. GRAPH with graphType "LINE":
|
||||
- Same as bar charts, good for time series
|
||||
4. GRAPH with configurationType "PIE_CHART":
|
||||
- Additional required: configuration.groupByFieldMetadataId (note: different field name!)
|
||||
- Example: { type: "GRAPH", objectMetadataId: "<opportunity-object-uuid>", configuration: { configurationType: "PIE_CHART", aggregateFieldMetadataId: "<id-field-uuid>", aggregateOperation: "COUNT", groupByFieldMetadataId: "<stage-field-uuid>" } }
|
||||
|
||||
4. GRAPH with graphType "PIE":
|
||||
- Requires: objectMetadataId, aggregateFieldMetadataId, aggregateOperation, groupByFieldMetadataId
|
||||
- Example: { graphType: "PIE", aggregateFieldMetadataId: "<id-field-uuid>", aggregateOperation: "COUNT", groupByFieldMetadataId: "<stage-field-uuid>" }
|
||||
5. IFRAME: { type: "IFRAME", configuration: { configurationType: "IFRAME", url: "https://..." } }
|
||||
|
||||
5. IFRAME: { type: "IFRAME", configuration: { url: "https://..." } }
|
||||
|
||||
6. STANDALONE_RICH_TEXT: { type: "STANDALONE_RICH_TEXT", configuration: { body: "..." } }
|
||||
6. STANDALONE_RICH_TEXT: { type: "STANDALONE_RICH_TEXT", configuration: { configurationType: "STANDALONE_RICH_TEXT", body: { ... } } }
|
||||
|
||||
AGGREGATION OPERATIONS: COUNT, SUM, AVG, MIN, MAX, COUNT_EMPTY, COUNT_NOT_EMPTY`,
|
||||
inputSchema: createCompleteDashboardSchema,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { AggregateOperations } from 'src/engine/api/graphql/graphql-query-runner/constants/aggregate-operations.constant';
|
||||
import { GraphType } from 'src/engine/metadata-modules/page-layout-widget/enums/graph-type.enum';
|
||||
import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type';
|
||||
import { WidgetType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum';
|
||||
|
||||
export const gridPositionSchema = z.object({
|
||||
@@ -28,7 +28,7 @@ export const widgetTypeSchema = z.enum([
|
||||
|
||||
// Graph configuration schema for AGGREGATE type (KPI numbers)
|
||||
const aggregateChartConfigSchema = z.object({
|
||||
graphType: z.literal(GraphType.AGGREGATE_CHART),
|
||||
configurationType: z.literal(WidgetConfigurationType.AGGREGATE_CHART),
|
||||
aggregateFieldMetadataId: z
|
||||
.string()
|
||||
.uuid()
|
||||
@@ -48,7 +48,7 @@ const aggregateChartConfigSchema = z.object({
|
||||
// Graph configuration schema for BAR charts
|
||||
const barChartConfigSchema = z
|
||||
.object({
|
||||
graphType: z.literal(GraphType.BAR_CHART),
|
||||
configurationType: z.literal(WidgetConfigurationType.BAR_CHART),
|
||||
aggregateFieldMetadataId: z
|
||||
.string()
|
||||
.uuid()
|
||||
@@ -87,8 +87,6 @@ const barChartConfigSchema = z
|
||||
displayLegend: z.boolean().optional().default(true),
|
||||
layout: z
|
||||
.enum(['VERTICAL', 'HORIZONTAL'])
|
||||
.optional()
|
||||
.default('VERTICAL')
|
||||
.describe('Layout orientation for bar charts'),
|
||||
filter: z.record(z.string(), z.unknown()).optional(),
|
||||
})
|
||||
@@ -118,7 +116,7 @@ const barChartConfigSchema = z
|
||||
// Graph configuration schema for LINE charts
|
||||
const lineChartConfigSchema = z
|
||||
.object({
|
||||
graphType: z.literal(GraphType.LINE_CHART),
|
||||
configurationType: z.literal(WidgetConfigurationType.LINE_CHART),
|
||||
aggregateFieldMetadataId: z.string().uuid(),
|
||||
aggregateOperation: z.nativeEnum(AggregateOperations),
|
||||
primaryAxisGroupByFieldMetadataId: z.string().uuid(),
|
||||
@@ -176,7 +174,7 @@ const lineChartConfigSchema = z
|
||||
// Graph configuration schema for PIE charts
|
||||
const pieChartConfigSchema = z
|
||||
.object({
|
||||
graphType: z.literal(GraphType.PIE_CHART),
|
||||
configurationType: z.literal(WidgetConfigurationType.PIE_CHART),
|
||||
aggregateFieldMetadataId: z.string().uuid(),
|
||||
aggregateOperation: z.nativeEnum(AggregateOperations),
|
||||
groupByFieldMetadataId: z
|
||||
@@ -211,25 +209,37 @@ const pieChartConfigSchema = z
|
||||
|
||||
// Iframe configuration
|
||||
const iframeConfigSchema = z.object({
|
||||
url: z.string().url().describe('URL to embed'),
|
||||
configurationType: z.literal(WidgetConfigurationType.IFRAME),
|
||||
url: z.string().url().optional().describe('URL to embed'),
|
||||
});
|
||||
|
||||
// Rich text configuration
|
||||
const richTextConfigSchema = z.object({
|
||||
body: z.string().optional().describe('Rich text content'),
|
||||
configurationType: z.literal(WidgetConfigurationType.STANDALONE_RICH_TEXT),
|
||||
body: z.unknown().optional().describe('Rich text content (RichTextV2Body)'),
|
||||
});
|
||||
|
||||
export const graphConfigurationSchema = z.discriminatedUnion('graphType', [
|
||||
aggregateChartConfigSchema,
|
||||
barChartConfigSchema,
|
||||
lineChartConfigSchema,
|
||||
pieChartConfigSchema,
|
||||
]);
|
||||
export const graphConfigurationSchema = z.discriminatedUnion(
|
||||
'configurationType',
|
||||
[
|
||||
aggregateChartConfigSchema,
|
||||
barChartConfigSchema,
|
||||
lineChartConfigSchema,
|
||||
pieChartConfigSchema,
|
||||
],
|
||||
);
|
||||
|
||||
export const widgetConfigurationSchema = z
|
||||
.union([graphConfigurationSchema, iframeConfigSchema, richTextConfigSchema])
|
||||
.discriminatedUnion('configurationType', [
|
||||
aggregateChartConfigSchema,
|
||||
barChartConfigSchema,
|
||||
lineChartConfigSchema,
|
||||
pieChartConfigSchema,
|
||||
iframeConfigSchema,
|
||||
richTextConfigSchema,
|
||||
])
|
||||
.optional()
|
||||
.describe('Widget configuration - structure depends on widget type');
|
||||
|
||||
// Export enums for documentation
|
||||
export { AggregateOperations, GraphType as GraphType };
|
||||
export { AggregateOperations, WidgetConfigurationType };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { isDefined, isEmptyObject } from 'twenty-shared/utils';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { type WidgetType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum';
|
||||
@@ -24,7 +24,7 @@ const updateDashboardWidgetSchema = z.object({
|
||||
.uuid()
|
||||
.optional()
|
||||
.describe('New object metadata ID'),
|
||||
configuration: widgetConfigurationSchema,
|
||||
configuration: widgetConfigurationSchema.optional(),
|
||||
});
|
||||
|
||||
export const createUpdateDashboardWidgetTool = (
|
||||
@@ -54,7 +54,16 @@ Only provide fields you want to change - others remain unchanged.`,
|
||||
try {
|
||||
const { widgetId, ...updates } = parameters;
|
||||
const updateData = Object.fromEntries(
|
||||
Object.entries(updates).filter(([, value]) => isDefined(value)),
|
||||
Object.entries(updates).filter(([key, value]) => {
|
||||
if (!isDefined(value)) {
|
||||
return false;
|
||||
}
|
||||
if (key === 'configuration' && isEmptyObject(value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
);
|
||||
|
||||
const widget = await deps.pageLayoutWidgetService.update({
|
||||
|
||||
Reference in New Issue
Block a user