@cplace/test-mcp-server 1.2.0 → 1.3.0
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/README.md +4 -18
- package/dist/api.d.ts +1 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +50 -0
- package/dist/api.js.map +1 -1
- package/dist/conditional-registration.js +3 -3
- package/dist/conditional-registration.js.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/profiles.js +2 -2
- package/dist/profiles.js.map +1 -1
- package/dist/searchConversion.js +1 -1
- package/dist/searchConversion.js.map +1 -1
- package/dist/searchSchema.d.ts.map +1 -1
- package/dist/searchSchema.js.map +1 -1
- package/dist/tool-metadata.js +3 -3
- package/dist/tool-metadata.js.map +1 -1
- package/dist/tools/board-widget.js +1 -1
- package/dist/tools/board-widget.js.map +1 -1
- package/dist/tools/common-schemas.d.ts +0 -227
- package/dist/tools/common-schemas.d.ts.map +1 -1
- package/dist/tools/common-schemas.js +0 -67
- package/dist/tools/common-schemas.js.map +1 -1
- package/dist/tools/layout-script.d.ts +166 -0
- package/dist/tools/layout-script.d.ts.map +1 -0
- package/dist/tools/layout-script.js +474 -0
- package/dist/tools/layout-script.js.map +1 -0
- package/dist/tools/type-layouts.d.ts +0 -11
- package/dist/tools/type-layouts.d.ts.map +1 -1
- package/dist/tools/type-layouts.js +0 -31
- package/dist/tools/type-layouts.js.map +1 -1
- package/dist/tools/type-management.d.ts +9 -3
- package/dist/tools/type-management.d.ts.map +1 -1
- package/dist/tools/type-management.js +12 -8
- package/dist/tools/type-management.js.map +1 -1
- package/dist/tools/widgets.d.ts +0 -161
- package/dist/tools/widgets.d.ts.map +1 -1
- package/dist/tools/widgets.js +0 -275
- package/dist/tools/widgets.js.map +1 -1
- package/dist/tools/workspace-admin.d.ts.map +1 -1
- package/dist/tools/workspace-admin.js +7 -11
- package/dist/tools/workspace-admin.js.map +1 -1
- package/dist/widget-specifications/cf.cplace.cboard.main.board/_implementation.md +1 -1
- package/dist/widget-specifications/cf.cplace.platform.attributesGroup/layout.md +1 -6
- package/dist/widget-specifications/cf.cplace.platform.connectedAttributesGroup/cf.cplace.platform.attributesGroup.layout.md +1 -6
- package/dist/widget-specifications/cf.cplace.visualizations.scriptingHighcharts/tableWidgetId.md +1 -1
- package/package.json +1 -1
- package/dist/tools/generic-layouts.d.ts +0 -400
- package/dist/tools/generic-layouts.d.ts.map +0 -1
- package/dist/tools/generic-layouts.js +0 -785
- package/dist/tools/generic-layouts.js.map +0 -1
|
@@ -1,785 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { debugLogWithTag } from "../logger.js";
|
|
3
|
-
import { PositionSchema, WIDGET_CONFIG_DESCRIPTION } from './common-schemas.js';
|
|
4
|
-
export const LayoutContextSchema = z.union([
|
|
5
|
-
z.object({
|
|
6
|
-
type: z.literal("page"),
|
|
7
|
-
pageUID: z.string().describe("Page UID (e.g., 'page/abc123')")
|
|
8
|
-
}),
|
|
9
|
-
z.object({
|
|
10
|
-
type: z.literal("type"),
|
|
11
|
-
workspaceId: z.string().describe("Workspace ID (e.g., 'workspace123')"),
|
|
12
|
-
typeInternalName: z.string().describe("Type internal name (e.g., 'cf.example.myType')"),
|
|
13
|
-
alternativeLayoutName: z.string().optional().describe("Alternative layout name (optional)")
|
|
14
|
-
})
|
|
15
|
-
]).describe("Layout target - specify whether operating on page or type layout");
|
|
16
|
-
const TOOL_LAYOUT_GET_OVERVIEW = 'cplace_layout_get_overview';
|
|
17
|
-
const TOOL_LAYOUT_ADD_WIDGET = 'cplace_layout_add_widget';
|
|
18
|
-
const TOOL_LAYOUT_REMOVE_WIDGET = 'cplace_layout_remove_widget';
|
|
19
|
-
const TOOL_LAYOUT_ADD_ROW = 'cplace_layout_add_row';
|
|
20
|
-
const TOOL_LAYOUT_GET_WIDGET_DETAILS = 'cplace_layout_get_widget_details';
|
|
21
|
-
const TOOL_LAYOUT_UPDATE_WIDGET = 'cplace_layout_update_widget';
|
|
22
|
-
const TOOL_LAYOUT_MOVE_WIDGET = 'cplace_layout_move_widget';
|
|
23
|
-
const TOOL_LAYOUT_COMPACT = 'cplace_layout_compact';
|
|
24
|
-
const TOOL_LAYOUT_REMOVE_ROW = 'cplace_layout_remove_row';
|
|
25
|
-
const TOOL_LAYOUT_CLEAR = 'cplace_layout_clear';
|
|
26
|
-
export const GENERIC_LAYOUT_TOOL_DEFINITIONS = {
|
|
27
|
-
[TOOL_LAYOUT_GET_OVERVIEW]: {
|
|
28
|
-
description: "Get layout structure for page or type. Provides an overview of the layout grid including rows, columns, and widget summaries for both page and type layouts.",
|
|
29
|
-
inputSchema: {
|
|
30
|
-
context: LayoutContextSchema
|
|
31
|
-
},
|
|
32
|
-
annotations: { title: "Get Layout Overview" }
|
|
33
|
-
},
|
|
34
|
-
[TOOL_LAYOUT_ADD_WIDGET]: {
|
|
35
|
-
description: `Add widget to page or type layout. Works with both page and type layouts using the same interface and behavior.
|
|
36
|
-
|
|
37
|
-
⚠️ REQUIRED BEFORE USE:
|
|
38
|
-
- ALWAYS call cplace_get_widget_definition FIRST to understand required fields
|
|
39
|
-
- Many widgets have non-obvious required attributes that will cause validation errors
|
|
40
|
-
- Widget configurations must match the schema exactly
|
|
41
|
-
- VERIFY APP DEPENDENCY: Check widget's requiredApp is installed in the workspace using cplace_list_workspace_apps. Widgets with uninstalled requiredApp will fail.
|
|
42
|
-
|
|
43
|
-
CRITICAL BEHAVIOR:
|
|
44
|
-
- Row creation: ❌ NOT automatic - use cplace_layout_add_row to create rows first
|
|
45
|
-
- Column creation: ❌ NOT automatic - columnIndex only references existing columns
|
|
46
|
-
- Invalid columnIndex: Falls back to last existing column (no error)
|
|
47
|
-
|
|
48
|
-
TO CREATE SIDE-BY-SIDE LAYOUTS:
|
|
49
|
-
1. First use cplace_layout_add_row to create multi-column structure
|
|
50
|
-
2. Then add widgets to the created columns
|
|
51
|
-
|
|
52
|
-
EXAMPLES:
|
|
53
|
-
- Add to new row 0: Creates single-column row, widget goes to column 0
|
|
54
|
-
- Add to column 1 when only column 0 exists: Widget goes to column 0 (fallback)
|
|
55
|
-
- Add to pre-created 6/6 row: Works correctly if columns exist
|
|
56
|
-
|
|
57
|
-
TIP: Always check current layout with cplace_layout_get_overview before adding widgets.`,
|
|
58
|
-
inputSchema: {
|
|
59
|
-
context: LayoutContextSchema,
|
|
60
|
-
widgetType: z.string().describe("Widget type identifier (e.g., 'cf.cplace.platform.table', 'cf.platform.wiki')"),
|
|
61
|
-
position: PositionSchema,
|
|
62
|
-
configuration: z.record(z.any()).optional().describe(`${WIDGET_CONFIG_DESCRIPTION}
|
|
63
|
-
|
|
64
|
-
WIDGET-SPECIFIC PATTERNS:
|
|
65
|
-
- Connected widgets (bar/pie charts): Use 'tableWidgetId' to connect to existing table widget
|
|
66
|
-
Example: {'tableWidgetId': 'id_abc123', 'title': {'en': 'Chart Title'}}
|
|
67
|
-
- Attribute widgets: Use 'cf.platform.quotedAttributeName' with single quotes
|
|
68
|
-
Example: {'cf.platform.quotedAttributeName': "'cf.cplace.myAttribute'", 'cf.platform.withLabel': true}
|
|
69
|
-
- Search widgets: Use 'search' with JSON search string
|
|
70
|
-
Example: {'search': '{"filters":[{"types":["test.project"]}]}', 'title': {'en': 'Results'}}`)
|
|
71
|
-
},
|
|
72
|
-
annotations: { title: "Add Widget to Layout" }
|
|
73
|
-
},
|
|
74
|
-
[TOOL_LAYOUT_REMOVE_WIDGET]: {
|
|
75
|
-
description: "Remove widget from page or type layout. Works with both page and type layouts using the same interface.",
|
|
76
|
-
inputSchema: {
|
|
77
|
-
context: LayoutContextSchema,
|
|
78
|
-
widgetId: z.string().describe("The unique identifier of the widget to remove")
|
|
79
|
-
},
|
|
80
|
-
annotations: { title: "Remove Widget from Layout" }
|
|
81
|
-
},
|
|
82
|
-
[TOOL_LAYOUT_ADD_ROW]: {
|
|
83
|
-
description: "Add row structure to page or type layout. Creates new row with specific column layout. Essential for multi-column structures as widget placement alone cannot create columns.",
|
|
84
|
-
inputSchema: {
|
|
85
|
-
context: LayoutContextSchema,
|
|
86
|
-
rowIndex: z.number().min(0).describe("Row index where to insert the new row (0-based). If rowIndex >= current row count, adds at the end. Otherwise, inserts at position and shifts existing rows down."),
|
|
87
|
-
columnProportions: z.array(z.number().min(1)).min(1).describe("Array of column width proportions that must sum to 12 (Bootstrap grid system). Examples: [12] (single column), [6,6] (two equal columns), [4,4,4] (three equal columns), [3,9] (sidebar + main)")
|
|
88
|
-
},
|
|
89
|
-
annotations: { title: "Add Row to Layout" }
|
|
90
|
-
},
|
|
91
|
-
[TOOL_LAYOUT_GET_WIDGET_DETAILS]: {
|
|
92
|
-
description: "Get detailed widget configuration from page or type layout. Extracts specific widget information from the layout structure.",
|
|
93
|
-
inputSchema: {
|
|
94
|
-
context: LayoutContextSchema,
|
|
95
|
-
widgetId: z.string().describe("The unique widget identifier to get details for")
|
|
96
|
-
},
|
|
97
|
-
annotations: { title: "Get Widget Details from Layout" }
|
|
98
|
-
},
|
|
99
|
-
[TOOL_LAYOUT_UPDATE_WIDGET]: {
|
|
100
|
-
description: "Update widget configuration or collapse state in page or type layout. Allows modification of widget properties and display settings.\n\nUSE CASES:\n- Restore configuration after widget moves (configurations may be lost during moves)\n- Update widget connections (e.g., change tableWidgetId after layout modifications)\n- Modify display properties (titles, collapse state, etc.)\n\nTIP: Widget IDs may change after layout operations - always use current IDs from latest layout overview retrieved via cplace_layout_get_overview.",
|
|
101
|
-
inputSchema: {
|
|
102
|
-
context: LayoutContextSchema,
|
|
103
|
-
widgetId: z.string().describe("The unique identifier of the widget to update"),
|
|
104
|
-
newConfiguration: z.record(z.any()).optional().describe(`Updated widget configuration as key-value pairs (optional). ${WIDGET_CONFIG_DESCRIPTION}`),
|
|
105
|
-
collapsed: z.boolean().optional().describe("Widget collapse state (optional)")
|
|
106
|
-
},
|
|
107
|
-
annotations: { title: "Update Widget in Layout" }
|
|
108
|
-
},
|
|
109
|
-
[TOOL_LAYOUT_MOVE_WIDGET]: {
|
|
110
|
-
description: "Move widget to different position in page or type layout. Relocates widget to specified grid position.\n\nMOVE BEHAVIOR:\n- ✅ Can move between existing rows and columns\n- ❌ Cannot create new columns (only references existing ones)\n- Invalid columnIndex: Falls back to last column in target row\n\nCRITICAL WARNINGS:\n- Widget configurations may be LOST during moves\n- Widget IDs may CHANGE - always get new IDs from response\n- Connected widgets (charts) may lose their tableWidgetId references\n\nPOST-MOVE CHECKLIST:\n1. Get new widget ID from response\n2. Use cplace_layout_get_widget_details to check if configuration was preserved\n3. If lost, use cplace_layout_update_widget to restore configuration\n4. Update any widgets that referenced the moved widget's old ID\n\nTIP: For complex layouts, consider removing and re-adding widgets instead of moving.",
|
|
111
|
-
inputSchema: {
|
|
112
|
-
context: LayoutContextSchema,
|
|
113
|
-
widgetId: z.string().describe("The unique identifier of the widget to move"),
|
|
114
|
-
newPosition: PositionSchema
|
|
115
|
-
},
|
|
116
|
-
annotations: { title: "Move Widget in Layout" }
|
|
117
|
-
},
|
|
118
|
-
[TOOL_LAYOUT_COMPACT]: {
|
|
119
|
-
description: "Remove empty rows from page or type layout. Compacts the layout by keeping only rows that contain widgets while preserving order and configurations.",
|
|
120
|
-
inputSchema: {
|
|
121
|
-
context: LayoutContextSchema
|
|
122
|
-
},
|
|
123
|
-
annotations: { title: "Compact Layout" }
|
|
124
|
-
},
|
|
125
|
-
[TOOL_LAYOUT_REMOVE_ROW]: {
|
|
126
|
-
description: `Remove all widgets from a specific row in a page or type layout.
|
|
127
|
-
|
|
128
|
-
Orchestrates multiple operations: get layout overview → remove each widget in the row (sequentially) → compact layout.
|
|
129
|
-
|
|
130
|
-
BEHAVIOR:
|
|
131
|
-
- Removes all widgets in the specified row by index (0-based)
|
|
132
|
-
- Widgets are removed sequentially for safety
|
|
133
|
-
- Layout is compacted after removal to remove empty row
|
|
134
|
-
- If some widgets fail to remove, continues with remaining widgets and reports partial success
|
|
135
|
-
|
|
136
|
-
RESPONSE:
|
|
137
|
-
- SUCCESS: All widgets removed successfully
|
|
138
|
-
- PARTIAL_SUCCESS: Some widgets removed, some failed (includes failure details)
|
|
139
|
-
- ERROR: Row not found or complete failure
|
|
140
|
-
|
|
141
|
-
TIP: Use cplace_layout_get_overview first to see row indices and widget counts.`,
|
|
142
|
-
inputSchema: {
|
|
143
|
-
context: LayoutContextSchema,
|
|
144
|
-
rowIndex: z.number().min(0).describe("The 0-based index of the row to remove widgets from")
|
|
145
|
-
},
|
|
146
|
-
annotations: { title: "Remove Row from Layout" }
|
|
147
|
-
},
|
|
148
|
-
[TOOL_LAYOUT_CLEAR]: {
|
|
149
|
-
description: `Remove all widgets from a page or type layout.
|
|
150
|
-
|
|
151
|
-
Orchestrates multiple operations: get layout overview → remove each widget (sequentially) → compact layout.
|
|
152
|
-
|
|
153
|
-
⚠️ SAFETY: Requires confirmClear: true to prevent accidental clearing.
|
|
154
|
-
|
|
155
|
-
BEHAVIOR:
|
|
156
|
-
- Removes ALL widgets from the entire layout
|
|
157
|
-
- Widgets are removed sequentially for safety
|
|
158
|
-
- Layout is compacted after removal
|
|
159
|
-
- If some widgets fail to remove, continues with remaining widgets and reports partial success
|
|
160
|
-
|
|
161
|
-
RESPONSE:
|
|
162
|
-
- SUCCESS: All widgets removed successfully
|
|
163
|
-
- PARTIAL_SUCCESS: Some widgets removed, some failed (includes failure details)
|
|
164
|
-
- ERROR: Confirmation not provided or complete failure
|
|
165
|
-
|
|
166
|
-
TIP: Use cplace_layout_get_overview first to review layout contents before clearing.`,
|
|
167
|
-
inputSchema: {
|
|
168
|
-
context: LayoutContextSchema,
|
|
169
|
-
confirmClear: z.boolean().describe("Must be true to confirm clearing the layout. Prevents accidental clearing.")
|
|
170
|
-
},
|
|
171
|
-
annotations: { title: "Clear Layout" }
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
function determineApiEndpoint(context, _operation) {
|
|
175
|
-
const baseEndpoint = context.type === "page" ? "json/pageLayout" : "json/typeLayout";
|
|
176
|
-
return baseEndpoint;
|
|
177
|
-
}
|
|
178
|
-
function buildRequestParams(context, additionalParams = {}) {
|
|
179
|
-
if (context.type === "page") {
|
|
180
|
-
return { pageUID: context.pageUID, ...additionalParams };
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
return {
|
|
184
|
-
workspaceId: context.workspaceId,
|
|
185
|
-
typeInternalName: context.typeInternalName,
|
|
186
|
-
...(context.alternativeLayoutName && { alternativeLayoutName: context.alternativeLayoutName }),
|
|
187
|
-
...additionalParams
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
async function handleLayoutOperation(client, context, operation, params = {}) {
|
|
192
|
-
const endpoint = determineApiEndpoint(context, operation);
|
|
193
|
-
const requestParams = buildRequestParams(context, params);
|
|
194
|
-
debugLogWithTag('LAYOUT', `${operation} operation on ${context.type} layout via ${endpoint}`);
|
|
195
|
-
if (operation === 'getOverview') {
|
|
196
|
-
return await client.makeApiRequest(endpoint, 'GET', requestParams);
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
const requestBody = {
|
|
200
|
-
...requestParams,
|
|
201
|
-
operation: { type: operation, ...params }
|
|
202
|
-
};
|
|
203
|
-
return await client.makeApiRequest(endpoint, 'PATCH', undefined, requestBody);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
function mapOperationName(context, operation) {
|
|
207
|
-
const operationMapping = {
|
|
208
|
-
page: {
|
|
209
|
-
'add_widget': 'ADD',
|
|
210
|
-
'remove_widget': 'REMOVE',
|
|
211
|
-
'update_widget': 'UPDATE',
|
|
212
|
-
'move_widget': 'MOVE',
|
|
213
|
-
'add_row': 'ADD_ROW',
|
|
214
|
-
'compact': 'COMPACT'
|
|
215
|
-
},
|
|
216
|
-
type: {
|
|
217
|
-
'add_widget': 'ADD',
|
|
218
|
-
'remove_widget': 'REMOVE',
|
|
219
|
-
'update_widget': 'UPDATE',
|
|
220
|
-
'move_widget': 'MOVE',
|
|
221
|
-
'add_row': 'ADD',
|
|
222
|
-
'compact': 'COMPACT'
|
|
223
|
-
}
|
|
224
|
-
};
|
|
225
|
-
const contextMapping = operationMapping[context.type];
|
|
226
|
-
return contextMapping[operation] || operation;
|
|
227
|
-
}
|
|
228
|
-
function getWidgetIdsInRow(row) {
|
|
229
|
-
const widgetIds = [];
|
|
230
|
-
for (const column of row.columns || []) {
|
|
231
|
-
for (const widget of column.widgets || []) {
|
|
232
|
-
if (widget.id) {
|
|
233
|
-
widgetIds.push(widget.id);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
return widgetIds;
|
|
238
|
-
}
|
|
239
|
-
function getAllWidgetIds(rows) {
|
|
240
|
-
const widgetIds = [];
|
|
241
|
-
for (const row of rows || []) {
|
|
242
|
-
widgetIds.push(...getWidgetIdsInRow(row));
|
|
243
|
-
}
|
|
244
|
-
return widgetIds;
|
|
245
|
-
}
|
|
246
|
-
export function registerLayoutTools(server, client) {
|
|
247
|
-
server.registerTool(TOOL_LAYOUT_GET_OVERVIEW, GENERIC_LAYOUT_TOOL_DEFINITIONS[TOOL_LAYOUT_GET_OVERVIEW], async ({ context }) => {
|
|
248
|
-
debugLogWithTag('LAYOUT', `Starting layout overview request for ${context.type} layout`);
|
|
249
|
-
try {
|
|
250
|
-
const result = await handleLayoutOperation(client, context, 'getOverview');
|
|
251
|
-
const overview = {
|
|
252
|
-
context,
|
|
253
|
-
rows: result.rows?.map((row, rowIndex) => ({
|
|
254
|
-
rowIndex,
|
|
255
|
-
columns: row.columns?.map((column, colIndex) => ({
|
|
256
|
-
columnIndex: colIndex,
|
|
257
|
-
proportion: column.proportion,
|
|
258
|
-
widgets: column.widgets?.map((widget) => ({
|
|
259
|
-
id: widget.id,
|
|
260
|
-
widgetType: widget.widgetType,
|
|
261
|
-
configurationCount: widget.configuration?.length || 0,
|
|
262
|
-
validationStatus: widget.validationStatus || null
|
|
263
|
-
})) || []
|
|
264
|
-
})) || []
|
|
265
|
-
})) || []
|
|
266
|
-
};
|
|
267
|
-
debugLogWithTag('LAYOUT', `Retrieved ${context.type} layout overview successfully`);
|
|
268
|
-
return {
|
|
269
|
-
content: [{ type: "text", text: JSON.stringify(overview, null, 2) }]
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
catch (error) {
|
|
273
|
-
debugLogWithTag('LAYOUT', `Error getting layout overview: ${error instanceof Error ? error.message : String(error)}`);
|
|
274
|
-
return {
|
|
275
|
-
content: [{
|
|
276
|
-
type: "text",
|
|
277
|
-
text: `Error getting ${context.type} layout overview: ${error instanceof Error ? error.message : String(error)}`
|
|
278
|
-
}],
|
|
279
|
-
isError: true
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
});
|
|
283
|
-
server.registerTool(TOOL_LAYOUT_ADD_WIDGET, GENERIC_LAYOUT_TOOL_DEFINITIONS[TOOL_LAYOUT_ADD_WIDGET], async ({ context, widgetType, position, configuration }) => {
|
|
284
|
-
debugLogWithTag('LAYOUT', `Adding widget ${widgetType} to ${context.type} layout`);
|
|
285
|
-
try {
|
|
286
|
-
const operationType = mapOperationName(context, 'add_widget');
|
|
287
|
-
const operationParams = {
|
|
288
|
-
widgetType,
|
|
289
|
-
position: {
|
|
290
|
-
rowIndex: position.rowIndex,
|
|
291
|
-
columnIndex: position.columnIndex,
|
|
292
|
-
widgetIndex: position.widgetIndex
|
|
293
|
-
}
|
|
294
|
-
};
|
|
295
|
-
if (configuration && Object.keys(configuration).length > 0) {
|
|
296
|
-
operationParams.configuration = configuration;
|
|
297
|
-
debugLogWithTag('LAYOUT', `Including configuration: ${JSON.stringify(Object.keys(configuration))}`);
|
|
298
|
-
}
|
|
299
|
-
const result = await handleLayoutOperation(client, context, operationType, operationParams);
|
|
300
|
-
debugLogWithTag('LAYOUT', `Successfully added widget to ${context.type} layout`);
|
|
301
|
-
const response = {
|
|
302
|
-
operation: "ADD",
|
|
303
|
-
status: "SUCCESS",
|
|
304
|
-
context,
|
|
305
|
-
widgetType,
|
|
306
|
-
position,
|
|
307
|
-
validationStatus: result.status || null,
|
|
308
|
-
validationDetails: result.validationDetails || null,
|
|
309
|
-
message: `Widget added successfully to ${context.type} layout`
|
|
310
|
-
};
|
|
311
|
-
return {
|
|
312
|
-
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
catch (error) {
|
|
316
|
-
debugLogWithTag('LAYOUT', `Error adding widget: ${error instanceof Error ? error.message : String(error)}`);
|
|
317
|
-
const errorResponse = {
|
|
318
|
-
operation: "ADD",
|
|
319
|
-
status: "ERROR",
|
|
320
|
-
context,
|
|
321
|
-
widgetType,
|
|
322
|
-
position,
|
|
323
|
-
error: error instanceof Error ? error.message : String(error),
|
|
324
|
-
message: `Failed to add widget to ${context.type} layout`
|
|
325
|
-
};
|
|
326
|
-
return {
|
|
327
|
-
content: [{ type: "text", text: JSON.stringify(errorResponse, null, 2) }],
|
|
328
|
-
isError: true
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
server.registerTool(TOOL_LAYOUT_REMOVE_WIDGET, GENERIC_LAYOUT_TOOL_DEFINITIONS[TOOL_LAYOUT_REMOVE_WIDGET], async ({ context, widgetId }) => {
|
|
333
|
-
debugLogWithTag('LAYOUT', `Removing widget ${widgetId} from ${context.type} layout`);
|
|
334
|
-
try {
|
|
335
|
-
const operationType = mapOperationName(context, 'remove_widget');
|
|
336
|
-
await handleLayoutOperation(client, context, operationType, { widgetId });
|
|
337
|
-
debugLogWithTag('LAYOUT', `Successfully removed widget from ${context.type} layout`);
|
|
338
|
-
const response = {
|
|
339
|
-
operation: "REMOVE",
|
|
340
|
-
status: "SUCCESS",
|
|
341
|
-
context,
|
|
342
|
-
widgetId,
|
|
343
|
-
message: `Widget removed successfully from ${context.type} layout`
|
|
344
|
-
};
|
|
345
|
-
return {
|
|
346
|
-
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
catch (error) {
|
|
350
|
-
debugLogWithTag('LAYOUT', `Error removing widget: ${error instanceof Error ? error.message : String(error)}`);
|
|
351
|
-
const errorResponse = {
|
|
352
|
-
operation: "REMOVE",
|
|
353
|
-
status: "ERROR",
|
|
354
|
-
context,
|
|
355
|
-
widgetId,
|
|
356
|
-
error: error instanceof Error ? error.message : String(error),
|
|
357
|
-
message: `Failed to remove widget from ${context.type} layout`
|
|
358
|
-
};
|
|
359
|
-
return {
|
|
360
|
-
content: [{ type: "text", text: JSON.stringify(errorResponse, null, 2) }],
|
|
361
|
-
isError: true
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
});
|
|
365
|
-
server.registerTool(TOOL_LAYOUT_ADD_ROW, GENERIC_LAYOUT_TOOL_DEFINITIONS[TOOL_LAYOUT_ADD_ROW], async ({ context, rowIndex, columnProportions }) => {
|
|
366
|
-
debugLogWithTag('LAYOUT', `Adding row ${rowIndex} with proportions ${JSON.stringify(columnProportions)} to ${context.type} layout`);
|
|
367
|
-
try {
|
|
368
|
-
const operationType = mapOperationName(context, 'add_row');
|
|
369
|
-
await handleLayoutOperation(client, context, operationType, {
|
|
370
|
-
rowIndex,
|
|
371
|
-
columnProportions
|
|
372
|
-
});
|
|
373
|
-
debugLogWithTag('LAYOUT', `Successfully added row to ${context.type} layout`);
|
|
374
|
-
const response = {
|
|
375
|
-
operation: "ADD_ROW",
|
|
376
|
-
status: "SUCCESS",
|
|
377
|
-
context,
|
|
378
|
-
rowIndex,
|
|
379
|
-
columnProportions,
|
|
380
|
-
columnsCreated: columnProportions.length,
|
|
381
|
-
message: `Row added successfully to ${context.type} layout with ${columnProportions.length} column${columnProportions.length === 1 ? '' : 's'} [${columnProportions.join(',')}]`
|
|
382
|
-
};
|
|
383
|
-
return {
|
|
384
|
-
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
catch (error) {
|
|
388
|
-
debugLogWithTag('LAYOUT', `Error adding row: ${error instanceof Error ? error.message : String(error)}`);
|
|
389
|
-
const errorResponse = {
|
|
390
|
-
operation: "ADD_ROW",
|
|
391
|
-
status: "ERROR",
|
|
392
|
-
context,
|
|
393
|
-
rowIndex,
|
|
394
|
-
columnProportions,
|
|
395
|
-
error: error instanceof Error ? error.message : String(error),
|
|
396
|
-
message: `Failed to add row to ${context.type} layout`
|
|
397
|
-
};
|
|
398
|
-
return {
|
|
399
|
-
content: [{ type: "text", text: JSON.stringify(errorResponse, null, 2) }],
|
|
400
|
-
isError: true
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
});
|
|
404
|
-
server.registerTool(TOOL_LAYOUT_GET_WIDGET_DETAILS, GENERIC_LAYOUT_TOOL_DEFINITIONS[TOOL_LAYOUT_GET_WIDGET_DETAILS], async ({ context, widgetId }) => {
|
|
405
|
-
debugLogWithTag('LAYOUT', `Getting widget details for ${widgetId} from ${context.type} layout`);
|
|
406
|
-
try {
|
|
407
|
-
const layoutResult = await handleLayoutOperation(client, context, 'getOverview');
|
|
408
|
-
let foundWidget = null;
|
|
409
|
-
const findWidget = (rows) => {
|
|
410
|
-
for (const row of rows || []) {
|
|
411
|
-
for (const column of row.columns || []) {
|
|
412
|
-
for (const widget of column.widgets || []) {
|
|
413
|
-
if (widget.id === widgetId) {
|
|
414
|
-
return widget;
|
|
415
|
-
}
|
|
416
|
-
if (widget.widgetsLayout?.rows) {
|
|
417
|
-
const nestedWidget = findWidget(widget.widgetsLayout.rows);
|
|
418
|
-
if (nestedWidget)
|
|
419
|
-
return nestedWidget;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
return null;
|
|
425
|
-
};
|
|
426
|
-
foundWidget = findWidget(layoutResult.rows);
|
|
427
|
-
if (!foundWidget) {
|
|
428
|
-
return {
|
|
429
|
-
content: [{ type: "text", text: `Widget with ID ${widgetId} not found in ${context.type} layout` }]
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
debugLogWithTag('LAYOUT', `Retrieved widget details for: ${widgetId} from ${context.type} layout`);
|
|
433
|
-
const response = {
|
|
434
|
-
context,
|
|
435
|
-
widgetId,
|
|
436
|
-
widget: foundWidget,
|
|
437
|
-
validationStatus: foundWidget.validationStatus || null
|
|
438
|
-
};
|
|
439
|
-
return {
|
|
440
|
-
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
441
|
-
};
|
|
442
|
-
}
|
|
443
|
-
catch (error) {
|
|
444
|
-
debugLogWithTag('LAYOUT', `Error getting widget details: ${error instanceof Error ? error.message : String(error)}`);
|
|
445
|
-
return {
|
|
446
|
-
content: [{
|
|
447
|
-
type: "text",
|
|
448
|
-
text: `Error getting widget details from ${context.type} layout: ${error instanceof Error ? error.message : String(error)}`
|
|
449
|
-
}],
|
|
450
|
-
isError: true
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
|
-
});
|
|
454
|
-
server.registerTool(TOOL_LAYOUT_UPDATE_WIDGET, GENERIC_LAYOUT_TOOL_DEFINITIONS[TOOL_LAYOUT_UPDATE_WIDGET], async ({ context, widgetId, newConfiguration, collapsed }) => {
|
|
455
|
-
debugLogWithTag('LAYOUT', `Updating widget ${widgetId} in ${context.type} layout`);
|
|
456
|
-
try {
|
|
457
|
-
const operationType = mapOperationName(context, 'update_widget');
|
|
458
|
-
const operationParams = {
|
|
459
|
-
widgetId
|
|
460
|
-
};
|
|
461
|
-
if (newConfiguration && Object.keys(newConfiguration).length > 0) {
|
|
462
|
-
operationParams.newConfiguration = newConfiguration;
|
|
463
|
-
debugLogWithTag('LAYOUT', `Including new configuration: ${JSON.stringify(Object.keys(newConfiguration))}`);
|
|
464
|
-
}
|
|
465
|
-
if (collapsed !== undefined) {
|
|
466
|
-
operationParams.collapsed = collapsed;
|
|
467
|
-
debugLogWithTag('LAYOUT', `Setting collapsed state to: ${collapsed}`);
|
|
468
|
-
}
|
|
469
|
-
if (!operationParams.newConfiguration && operationParams.collapsed === undefined) {
|
|
470
|
-
return {
|
|
471
|
-
content: [{ type: "text", text: "No updates specified. At least one of newConfiguration or collapsed must be provided." }]
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
const result = await handleLayoutOperation(client, context, operationType, operationParams);
|
|
475
|
-
debugLogWithTag('LAYOUT', `Successfully updated widget in ${context.type} layout`);
|
|
476
|
-
const response = {
|
|
477
|
-
operation: "UPDATE",
|
|
478
|
-
status: "SUCCESS",
|
|
479
|
-
context,
|
|
480
|
-
widgetId,
|
|
481
|
-
validationStatus: result.status || null,
|
|
482
|
-
validationDetails: result.validationDetails || null,
|
|
483
|
-
message: `Widget updated successfully in ${context.type} layout`
|
|
484
|
-
};
|
|
485
|
-
return {
|
|
486
|
-
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
487
|
-
};
|
|
488
|
-
}
|
|
489
|
-
catch (error) {
|
|
490
|
-
debugLogWithTag('LAYOUT', `Error updating widget: ${error instanceof Error ? error.message : String(error)}`);
|
|
491
|
-
const errorResponse = {
|
|
492
|
-
operation: "UPDATE",
|
|
493
|
-
status: "ERROR",
|
|
494
|
-
context,
|
|
495
|
-
widgetId,
|
|
496
|
-
error: error instanceof Error ? error.message : String(error),
|
|
497
|
-
message: `Failed to update widget in ${context.type} layout`
|
|
498
|
-
};
|
|
499
|
-
return {
|
|
500
|
-
content: [{ type: "text", text: JSON.stringify(errorResponse, null, 2) }],
|
|
501
|
-
isError: true
|
|
502
|
-
};
|
|
503
|
-
}
|
|
504
|
-
});
|
|
505
|
-
server.registerTool(TOOL_LAYOUT_MOVE_WIDGET, GENERIC_LAYOUT_TOOL_DEFINITIONS[TOOL_LAYOUT_MOVE_WIDGET], async ({ context, widgetId, newPosition }) => {
|
|
506
|
-
debugLogWithTag('LAYOUT', `Moving widget ${widgetId} in ${context.type} layout to position ${JSON.stringify(newPosition)}`);
|
|
507
|
-
try {
|
|
508
|
-
const operationType = mapOperationName(context, 'move_widget');
|
|
509
|
-
const operationParams = {
|
|
510
|
-
widgetId,
|
|
511
|
-
newPosition: {
|
|
512
|
-
rowIndex: newPosition.rowIndex,
|
|
513
|
-
columnIndex: newPosition.columnIndex,
|
|
514
|
-
widgetIndex: newPosition.widgetIndex
|
|
515
|
-
}
|
|
516
|
-
};
|
|
517
|
-
await handleLayoutOperation(client, context, operationType, operationParams);
|
|
518
|
-
debugLogWithTag('LAYOUT', `Successfully moved widget in ${context.type} layout`);
|
|
519
|
-
const response = {
|
|
520
|
-
operation: "MOVE",
|
|
521
|
-
status: "SUCCESS",
|
|
522
|
-
context,
|
|
523
|
-
oldWidgetId: widgetId,
|
|
524
|
-
newPosition,
|
|
525
|
-
message: `Widget moved successfully in ${context.type} layout`
|
|
526
|
-
};
|
|
527
|
-
return {
|
|
528
|
-
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
catch (error) {
|
|
532
|
-
debugLogWithTag('LAYOUT', `Error moving widget: ${error instanceof Error ? error.message : String(error)}`);
|
|
533
|
-
const errorResponse = {
|
|
534
|
-
operation: "MOVE",
|
|
535
|
-
status: "ERROR",
|
|
536
|
-
context,
|
|
537
|
-
oldWidgetId: widgetId,
|
|
538
|
-
newPosition,
|
|
539
|
-
error: error instanceof Error ? error.message : String(error),
|
|
540
|
-
message: `Failed to move widget in ${context.type} layout`
|
|
541
|
-
};
|
|
542
|
-
return {
|
|
543
|
-
content: [{ type: "text", text: JSON.stringify(errorResponse, null, 2) }],
|
|
544
|
-
isError: true
|
|
545
|
-
};
|
|
546
|
-
}
|
|
547
|
-
});
|
|
548
|
-
server.registerTool(TOOL_LAYOUT_COMPACT, GENERIC_LAYOUT_TOOL_DEFINITIONS[TOOL_LAYOUT_COMPACT], async ({ context }) => {
|
|
549
|
-
debugLogWithTag('LAYOUT', `Compacting ${context.type} layout`);
|
|
550
|
-
try {
|
|
551
|
-
const operationType = mapOperationName(context, 'compact');
|
|
552
|
-
await handleLayoutOperation(client, context, operationType);
|
|
553
|
-
debugLogWithTag('LAYOUT', `Successfully compacted ${context.type} layout`);
|
|
554
|
-
const response = {
|
|
555
|
-
operation: "COMPACT_LAYOUT",
|
|
556
|
-
status: "SUCCESS",
|
|
557
|
-
context,
|
|
558
|
-
message: `Layout compacted successfully - empty rows removed from ${context.type} layout`
|
|
559
|
-
};
|
|
560
|
-
return {
|
|
561
|
-
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
562
|
-
};
|
|
563
|
-
}
|
|
564
|
-
catch (error) {
|
|
565
|
-
debugLogWithTag('LAYOUT', `Error compacting layout: ${error instanceof Error ? error.message : String(error)}`);
|
|
566
|
-
const errorResponse = {
|
|
567
|
-
operation: "COMPACT_LAYOUT",
|
|
568
|
-
status: "ERROR",
|
|
569
|
-
context,
|
|
570
|
-
error: error instanceof Error ? error.message : String(error),
|
|
571
|
-
message: `Failed to compact ${context.type} layout`
|
|
572
|
-
};
|
|
573
|
-
return {
|
|
574
|
-
content: [{ type: "text", text: JSON.stringify(errorResponse, null, 2) }],
|
|
575
|
-
isError: true
|
|
576
|
-
};
|
|
577
|
-
}
|
|
578
|
-
});
|
|
579
|
-
server.registerTool(TOOL_LAYOUT_REMOVE_ROW, GENERIC_LAYOUT_TOOL_DEFINITIONS[TOOL_LAYOUT_REMOVE_ROW], async ({ context, rowIndex }) => {
|
|
580
|
-
debugLogWithTag('LAYOUT', `Starting remove row ${rowIndex} from ${context.type} layout`);
|
|
581
|
-
try {
|
|
582
|
-
const layoutResult = await handleLayoutOperation(client, context, 'getOverview');
|
|
583
|
-
const rows = layoutResult.rows || [];
|
|
584
|
-
if (rowIndex >= rows.length) {
|
|
585
|
-
const errorResponse = {
|
|
586
|
-
operation: "REMOVE_ROW",
|
|
587
|
-
status: "ERROR",
|
|
588
|
-
context,
|
|
589
|
-
rowIndex,
|
|
590
|
-
error: `Row index ${rowIndex} does not exist. Layout has ${rows.length} row(s) (indices 0-${rows.length - 1}).`,
|
|
591
|
-
message: `Invalid row index for ${context.type} layout`
|
|
592
|
-
};
|
|
593
|
-
return {
|
|
594
|
-
content: [{ type: "text", text: JSON.stringify(errorResponse, null, 2) }],
|
|
595
|
-
isError: true
|
|
596
|
-
};
|
|
597
|
-
}
|
|
598
|
-
const widgetIds = getWidgetIdsInRow(rows[rowIndex]);
|
|
599
|
-
if (widgetIds.length === 0) {
|
|
600
|
-
debugLogWithTag('LAYOUT', `Row ${rowIndex} has no widgets, compacting layout`);
|
|
601
|
-
await handleLayoutOperation(client, context, mapOperationName(context, 'compact'));
|
|
602
|
-
const response = {
|
|
603
|
-
operation: "REMOVE_ROW",
|
|
604
|
-
status: "SUCCESS",
|
|
605
|
-
context,
|
|
606
|
-
rowIndex,
|
|
607
|
-
widgetsRemoved: 0,
|
|
608
|
-
widgetsFailed: 0,
|
|
609
|
-
compacted: true,
|
|
610
|
-
message: `Row ${rowIndex} was already empty. Layout compacted.`
|
|
611
|
-
};
|
|
612
|
-
return {
|
|
613
|
-
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
614
|
-
};
|
|
615
|
-
}
|
|
616
|
-
debugLogWithTag('LAYOUT', `Found ${widgetIds.length} widgets to remove from row ${rowIndex}`);
|
|
617
|
-
const removeResults = [];
|
|
618
|
-
const operationType = mapOperationName(context, 'remove_widget');
|
|
619
|
-
for (const widgetId of widgetIds) {
|
|
620
|
-
try {
|
|
621
|
-
await handleLayoutOperation(client, context, operationType, { widgetId });
|
|
622
|
-
removeResults.push({ widgetId, success: true });
|
|
623
|
-
debugLogWithTag('LAYOUT', `Removed widget ${widgetId}`);
|
|
624
|
-
}
|
|
625
|
-
catch (error) {
|
|
626
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
627
|
-
removeResults.push({ widgetId, success: false, error: errorMsg });
|
|
628
|
-
debugLogWithTag('LAYOUT', `Failed to remove widget ${widgetId}: ${errorMsg}`);
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
let compacted = false;
|
|
632
|
-
try {
|
|
633
|
-
await handleLayoutOperation(client, context, mapOperationName(context, 'compact'));
|
|
634
|
-
compacted = true;
|
|
635
|
-
debugLogWithTag('LAYOUT', `Layout compacted successfully`);
|
|
636
|
-
}
|
|
637
|
-
catch (error) {
|
|
638
|
-
debugLogWithTag('LAYOUT', `Failed to compact layout: ${error instanceof Error ? error.message : String(error)}`);
|
|
639
|
-
}
|
|
640
|
-
const successCount = removeResults.filter(r => r.success).length;
|
|
641
|
-
const failedCount = removeResults.filter(r => !r.success).length;
|
|
642
|
-
const failedWidgets = removeResults.filter(r => !r.success);
|
|
643
|
-
const isPartialSuccess = failedCount > 0 && successCount > 0;
|
|
644
|
-
const isCompleteFailure = failedCount > 0 && successCount === 0;
|
|
645
|
-
const response = {
|
|
646
|
-
operation: "REMOVE_ROW",
|
|
647
|
-
status: isCompleteFailure ? "ERROR" : (isPartialSuccess ? "PARTIAL_SUCCESS" : "SUCCESS"),
|
|
648
|
-
context,
|
|
649
|
-
rowIndex,
|
|
650
|
-
widgetsRemoved: successCount,
|
|
651
|
-
widgetsFailed: failedCount,
|
|
652
|
-
compacted,
|
|
653
|
-
message: isCompleteFailure
|
|
654
|
-
? `Failed to remove any widgets from row ${rowIndex}`
|
|
655
|
-
: isPartialSuccess
|
|
656
|
-
? `Removed ${successCount} of ${widgetIds.length} widgets from row ${rowIndex}. ${failedCount} failed.`
|
|
657
|
-
: `Removed ${successCount} widget(s) from row ${rowIndex}`
|
|
658
|
-
};
|
|
659
|
-
if (failedWidgets.length > 0) {
|
|
660
|
-
response.failedWidgets = failedWidgets;
|
|
661
|
-
}
|
|
662
|
-
debugLogWithTag('LAYOUT', `Remove row complete: ${successCount} removed, ${failedCount} failed`);
|
|
663
|
-
return {
|
|
664
|
-
content: [{ type: "text", text: JSON.stringify(response, null, 2) }],
|
|
665
|
-
...(isPartialSuccess || isCompleteFailure ? { isError: true } : {})
|
|
666
|
-
};
|
|
667
|
-
}
|
|
668
|
-
catch (error) {
|
|
669
|
-
debugLogWithTag('LAYOUT', `Error removing row: ${error instanceof Error ? error.message : String(error)}`);
|
|
670
|
-
const errorResponse = {
|
|
671
|
-
operation: "REMOVE_ROW",
|
|
672
|
-
status: "ERROR",
|
|
673
|
-
context,
|
|
674
|
-
rowIndex,
|
|
675
|
-
error: error instanceof Error ? error.message : String(error),
|
|
676
|
-
message: `Failed to remove row from ${context.type} layout`
|
|
677
|
-
};
|
|
678
|
-
return {
|
|
679
|
-
content: [{ type: "text", text: JSON.stringify(errorResponse, null, 2) }],
|
|
680
|
-
isError: true
|
|
681
|
-
};
|
|
682
|
-
}
|
|
683
|
-
});
|
|
684
|
-
server.registerTool(TOOL_LAYOUT_CLEAR, GENERIC_LAYOUT_TOOL_DEFINITIONS[TOOL_LAYOUT_CLEAR], async ({ context, confirmClear }) => {
|
|
685
|
-
debugLogWithTag('LAYOUT', `Starting clear ${context.type} layout (confirmClear: ${confirmClear})`);
|
|
686
|
-
if (confirmClear !== true) {
|
|
687
|
-
const errorResponse = {
|
|
688
|
-
operation: "CLEAR_LAYOUT",
|
|
689
|
-
status: "ERROR",
|
|
690
|
-
context,
|
|
691
|
-
error: "Safety check failed: confirmClear must be true to clear the layout",
|
|
692
|
-
message: "Set confirmClear: true to confirm you want to remove ALL widgets from this layout"
|
|
693
|
-
};
|
|
694
|
-
return {
|
|
695
|
-
content: [{ type: "text", text: JSON.stringify(errorResponse, null, 2) }],
|
|
696
|
-
isError: true
|
|
697
|
-
};
|
|
698
|
-
}
|
|
699
|
-
try {
|
|
700
|
-
const layoutResult = await handleLayoutOperation(client, context, 'getOverview');
|
|
701
|
-
const widgetIds = getAllWidgetIds(layoutResult.rows || []);
|
|
702
|
-
if (widgetIds.length === 0) {
|
|
703
|
-
debugLogWithTag('LAYOUT', `Layout is already empty, compacting`);
|
|
704
|
-
await handleLayoutOperation(client, context, mapOperationName(context, 'compact'));
|
|
705
|
-
const response = {
|
|
706
|
-
operation: "CLEAR_LAYOUT",
|
|
707
|
-
status: "SUCCESS",
|
|
708
|
-
context,
|
|
709
|
-
widgetsRemoved: 0,
|
|
710
|
-
widgetsFailed: 0,
|
|
711
|
-
compacted: true,
|
|
712
|
-
message: `Layout was already empty. Layout compacted.`
|
|
713
|
-
};
|
|
714
|
-
return {
|
|
715
|
-
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
716
|
-
};
|
|
717
|
-
}
|
|
718
|
-
debugLogWithTag('LAYOUT', `Found ${widgetIds.length} widgets to remove`);
|
|
719
|
-
const removeResults = [];
|
|
720
|
-
const operationType = mapOperationName(context, 'remove_widget');
|
|
721
|
-
for (const widgetId of widgetIds) {
|
|
722
|
-
try {
|
|
723
|
-
await handleLayoutOperation(client, context, operationType, { widgetId });
|
|
724
|
-
removeResults.push({ widgetId, success: true });
|
|
725
|
-
debugLogWithTag('LAYOUT', `Removed widget ${widgetId}`);
|
|
726
|
-
}
|
|
727
|
-
catch (error) {
|
|
728
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
729
|
-
removeResults.push({ widgetId, success: false, error: errorMsg });
|
|
730
|
-
debugLogWithTag('LAYOUT', `Failed to remove widget ${widgetId}: ${errorMsg}`);
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
let compacted = false;
|
|
734
|
-
try {
|
|
735
|
-
await handleLayoutOperation(client, context, mapOperationName(context, 'compact'));
|
|
736
|
-
compacted = true;
|
|
737
|
-
debugLogWithTag('LAYOUT', `Layout compacted successfully`);
|
|
738
|
-
}
|
|
739
|
-
catch (error) {
|
|
740
|
-
debugLogWithTag('LAYOUT', `Failed to compact layout: ${error instanceof Error ? error.message : String(error)}`);
|
|
741
|
-
}
|
|
742
|
-
const successCount = removeResults.filter(r => r.success).length;
|
|
743
|
-
const failedCount = removeResults.filter(r => !r.success).length;
|
|
744
|
-
const failedWidgets = removeResults.filter(r => !r.success);
|
|
745
|
-
const isPartialSuccess = failedCount > 0 && successCount > 0;
|
|
746
|
-
const isCompleteFailure = failedCount > 0 && successCount === 0;
|
|
747
|
-
const response = {
|
|
748
|
-
operation: "CLEAR_LAYOUT",
|
|
749
|
-
status: isCompleteFailure ? "ERROR" : (isPartialSuccess ? "PARTIAL_SUCCESS" : "SUCCESS"),
|
|
750
|
-
context,
|
|
751
|
-
widgetsRemoved: successCount,
|
|
752
|
-
widgetsFailed: failedCount,
|
|
753
|
-
compacted,
|
|
754
|
-
message: isCompleteFailure
|
|
755
|
-
? `Failed to remove any widgets from layout`
|
|
756
|
-
: isPartialSuccess
|
|
757
|
-
? `Removed ${successCount} of ${widgetIds.length} widgets. ${failedCount} failed.`
|
|
758
|
-
: `Cleared layout: removed ${successCount} widget(s)`
|
|
759
|
-
};
|
|
760
|
-
if (failedWidgets.length > 0) {
|
|
761
|
-
response.failedWidgets = failedWidgets;
|
|
762
|
-
}
|
|
763
|
-
debugLogWithTag('LAYOUT', `Clear layout complete: ${successCount} removed, ${failedCount} failed`);
|
|
764
|
-
return {
|
|
765
|
-
content: [{ type: "text", text: JSON.stringify(response, null, 2) }],
|
|
766
|
-
...(isPartialSuccess || isCompleteFailure ? { isError: true } : {})
|
|
767
|
-
};
|
|
768
|
-
}
|
|
769
|
-
catch (error) {
|
|
770
|
-
debugLogWithTag('LAYOUT', `Error clearing layout: ${error instanceof Error ? error.message : String(error)}`);
|
|
771
|
-
const errorResponse = {
|
|
772
|
-
operation: "CLEAR_LAYOUT",
|
|
773
|
-
status: "ERROR",
|
|
774
|
-
context,
|
|
775
|
-
error: error instanceof Error ? error.message : String(error),
|
|
776
|
-
message: `Failed to clear ${context.type} layout`
|
|
777
|
-
};
|
|
778
|
-
return {
|
|
779
|
-
content: [{ type: "text", text: JSON.stringify(errorResponse, null, 2) }],
|
|
780
|
-
isError: true
|
|
781
|
-
};
|
|
782
|
-
}
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
|
-
//# sourceMappingURL=generic-layouts.js.map
|