@cplace/test-mcp-server 0.1.14 → 1.0.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 +275 -75
- package/dist/api.d.ts +4 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js.map +1 -1
- package/dist/conditional-registration.d.ts.map +1 -1
- package/dist/conditional-registration.js +21 -3
- package/dist/conditional-registration.js.map +1 -1
- package/dist/index.js +82 -99
- package/dist/index.js.map +1 -1
- package/dist/preference-file.d.ts +16 -0
- package/dist/preference-file.d.ts.map +1 -0
- package/dist/preference-file.js +133 -0
- package/dist/preference-file.js.map +1 -0
- package/dist/profiles.d.ts +1 -3
- package/dist/profiles.d.ts.map +1 -1
- package/dist/profiles.js +60 -107
- package/dist/profiles.js.map +1 -1
- package/dist/searchConversion.d.ts.map +1 -1
- package/dist/searchConversion.js +18 -5
- package/dist/searchConversion.js.map +1 -1
- package/dist/searchSchema.d.ts +25 -25
- package/dist/searchSchema.d.ts.map +1 -1
- package/dist/searchSchema.js +5 -5
- package/dist/searchSchema.js.map +1 -1
- package/dist/token-hashing.d.ts +3 -0
- package/dist/token-hashing.d.ts.map +1 -0
- package/dist/token-hashing.js +18 -0
- package/dist/token-hashing.js.map +1 -0
- package/dist/tool-metadata.d.ts +2 -0
- package/dist/tool-metadata.d.ts.map +1 -0
- package/dist/tool-metadata.js +43 -0
- package/dist/tool-metadata.js.map +1 -0
- package/dist/tools/change-listeners.d.ts +30 -0
- package/dist/tools/change-listeners.d.ts.map +1 -1
- package/dist/tools/change-listeners.js +24 -18
- package/dist/tools/change-listeners.js.map +1 -1
- package/dist/tools/common-schemas.d.ts +2 -0
- package/dist/tools/common-schemas.d.ts.map +1 -1
- package/dist/tools/common-schemas.js +16 -0
- package/dist/tools/common-schemas.js.map +1 -1
- package/dist/tools/csv-export.d.ts +1849 -0
- package/dist/tools/csv-export.d.ts.map +1 -0
- package/dist/tools/csv-export.js +61 -0
- package/dist/tools/csv-export.js.map +1 -0
- package/dist/tools/generic-layouts.d.ts +332 -0
- package/dist/tools/generic-layouts.d.ts.map +1 -0
- package/dist/tools/generic-layouts.js +490 -0
- package/dist/tools/generic-layouts.js.map +1 -0
- package/dist/tools/get-operations.d.ts +16 -0
- package/dist/tools/get-operations.d.ts.map +1 -0
- package/dist/tools/get-operations.js +63 -0
- package/dist/tools/get-operations.js.map +1 -0
- package/dist/tools/pages.d.ts +55 -0
- package/dist/tools/pages.d.ts.map +1 -1
- package/dist/tools/pages.js +217 -209
- package/dist/tools/pages.js.map +1 -1
- package/dist/tools/ppt-export-schemas.d.ts +16 -16
- package/dist/tools/ppt-export.d.ts +1493 -0
- package/dist/tools/ppt-export.d.ts.map +1 -1
- package/dist/tools/ppt-export.js +23 -17
- package/dist/tools/ppt-export.js.map +1 -1
- package/dist/tools/profile-management.d.ts +20 -0
- package/dist/tools/profile-management.d.ts.map +1 -0
- package/dist/tools/profile-management.js +250 -0
- package/dist/tools/profile-management.js.map +1 -0
- package/dist/tools/references.d.ts +36 -0
- package/dist/tools/references.d.ts.map +1 -1
- package/dist/tools/references.js +48 -45
- package/dist/tools/references.js.map +1 -1
- package/dist/tools/richstring-widgets.d.ts +51 -0
- package/dist/tools/richstring-widgets.d.ts.map +1 -0
- package/dist/tools/richstring-widgets.js +173 -0
- package/dist/tools/richstring-widgets.js.map +1 -0
- package/dist/tools/schedule.d.ts +14 -0
- package/dist/tools/schedule.d.ts.map +1 -1
- package/dist/tools/schedule.js +7 -3
- package/dist/tools/schedule.js.map +1 -1
- package/dist/tools/script-logs.d.ts +29 -0
- package/dist/tools/script-logs.d.ts.map +1 -0
- package/dist/tools/script-logs.js +144 -0
- package/dist/tools/script-logs.js.map +1 -0
- package/dist/tools/search.d.ts +1870 -0
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +49 -75
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/system.d.ts +2 -1
- package/dist/tools/system.d.ts.map +1 -1
- package/dist/tools/system.js +68 -2
- package/dist/tools/system.js.map +1 -1
- package/dist/tools/type-layouts.d.ts +37 -0
- package/dist/tools/type-layouts.d.ts.map +1 -1
- package/dist/tools/type-layouts.js +57 -11
- package/dist/tools/type-layouts.js.map +1 -1
- package/dist/tools/type-management.d.ts +134 -0
- package/dist/tools/type-management.d.ts.map +1 -0
- package/dist/tools/{workspace.js → type-management.js} +67 -307
- package/dist/tools/type-management.js.map +1 -0
- package/dist/tools/users.d.ts +19 -0
- package/dist/tools/users.d.ts.map +1 -1
- package/dist/tools/users.js +14 -28
- package/dist/tools/users.js.map +1 -1
- package/dist/tools/validators.d.ts +28 -0
- package/dist/tools/validators.d.ts.map +1 -1
- package/dist/tools/validators.js +21 -15
- package/dist/tools/validators.js.map +1 -1
- package/dist/tools/version-check.d.ts +4 -0
- package/dist/tools/version-check.d.ts.map +1 -0
- package/dist/tools/version-check.js +107 -0
- package/dist/tools/version-check.js.map +1 -0
- package/dist/tools/version-history.d.ts +48 -0
- package/dist/tools/version-history.d.ts.map +1 -1
- package/dist/tools/version-history.js +39 -29
- package/dist/tools/version-history.js.map +1 -1
- package/dist/tools/widgets.d.ts +182 -0
- package/dist/tools/widgets.d.ts.map +1 -1
- package/dist/tools/widgets.js +213 -590
- package/dist/tools/widgets.js.map +1 -1
- package/dist/tools/workflow-scripts.d.ts +40 -0
- package/dist/tools/workflow-scripts.d.ts.map +1 -0
- package/dist/tools/workflow-scripts.js +186 -0
- package/dist/tools/workflow-scripts.js.map +1 -0
- package/dist/tools/workflow.d.ts +70 -0
- package/dist/tools/workflow.d.ts.map +1 -0
- package/dist/tools/workflow.js +259 -0
- package/dist/tools/workflow.js.map +1 -0
- package/dist/tools/workspace-admin.d.ts +40 -0
- package/dist/tools/workspace-admin.d.ts.map +1 -0
- package/dist/tools/workspace-admin.js +125 -0
- package/dist/tools/workspace-admin.js.map +1 -0
- package/dist/tools/workspace-core.d.ts +45 -0
- package/dist/tools/workspace-core.d.ts.map +1 -0
- package/dist/tools/workspace-core.js +153 -0
- package/dist/tools/workspace-core.js.map +1 -0
- package/dist/types.d.ts +3 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/url-parsing.d.ts +6 -0
- package/dist/url-parsing.d.ts.map +1 -0
- package/dist/url-parsing.js +25 -0
- package/dist/url-parsing.js.map +1 -0
- package/dist/utils/dateValidation.d.ts +5 -0
- package/dist/utils/dateValidation.d.ts.map +1 -0
- package/dist/utils/dateValidation.js +57 -0
- package/dist/utils/dateValidation.js.map +1 -0
- package/dist/utils.js +7 -7
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
- package/dist/tools/workspace.d.ts +0 -4
- package/dist/tools/workspace.d.ts.map +0 -1
- package/dist/tools/workspace.js.map +0 -1
package/dist/tools/widgets.js
CHANGED
|
@@ -2,8 +2,14 @@ import { z } from "zod";
|
|
|
2
2
|
import { debugLogWithTag } from "../logger.js";
|
|
3
3
|
import { transformMultiplicityToBoolean } from '../utils.js';
|
|
4
4
|
import { PositionSchema, WIDGET_CONFIG_DESCRIPTION } from './common-schemas.js';
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
const TOOL_LIST_WIDGET_DEFINITIONS = 'cplace_list_widget_definitions';
|
|
6
|
+
const TOOL_GET_WIDGET_DEFINITION = 'cplace_get_widget_definition';
|
|
7
|
+
const TOOL_GET_WIDGET_DETAILS = 'cplace_get_widget_details';
|
|
8
|
+
const TOOL_GET_EMBEDDED_LAYOUT = 'cplace_get_embedded_layout';
|
|
9
|
+
const TOOL_ADD_WIDGET_TO_EMBEDDED_LAYOUT = 'cplace_add_widget_to_embedded_layout';
|
|
10
|
+
const TOOL_REMOVE_WIDGET_FROM_EMBEDDED_LAYOUT = 'cplace_remove_widget_from_embedded_layout';
|
|
11
|
+
export const WIDGET_TOOL_DEFINITIONS = {
|
|
12
|
+
[TOOL_LIST_WIDGET_DEFINITIONS]: {
|
|
7
13
|
description: "Get a list of all available widget definitions in the system that support the specified embedding context, with their basic metadata including names, descriptions, and apps",
|
|
8
14
|
inputSchema: {
|
|
9
15
|
embeddingContext: z.enum(["AS_WIDGET", "INSIDE_RICHSTRING", "INSIDE_WIDGET"]).default("AS_WIDGET").describe(`Filter widgets by embedding context support:
|
|
@@ -12,7 +18,109 @@ export function registerWidgetTools(server, client) {
|
|
|
12
18
|
- INSIDE_WIDGET: Widgets that can be embedded inside other widgets without frame`)
|
|
13
19
|
},
|
|
14
20
|
annotations: { title: "List Widget Definitions" }
|
|
15
|
-
},
|
|
21
|
+
},
|
|
22
|
+
[TOOL_GET_WIDGET_DEFINITION]: {
|
|
23
|
+
description: "Get detailed widget configuration schema.\n\n🔍 ALWAYS USE BEFORE ADDING/CONFIGURING WIDGETS to understand:\n- Required vs optional attributes\n- Correct attribute names (often not intuitive!)\n- Expected data types and formats\n- Available enumeration values\n\nCOMMON GOTCHAS:\n- Bar charts use 'attributeName' not 'attribute'\n- Connected charts need 'tableWidgetId' to link to tables\n- Attribute names often need single quotes: \"'cf.cplace.myAttribute'\"\n- LocalizedString format: {\"en\": \"English\", \"de\": \"German\"}\n\nWidget kinds: 'cf.platform.connectedBarChart', 'cf.platform.wiki', etc.",
|
|
24
|
+
inputSchema: {
|
|
25
|
+
widgetKind: z.string().describe("The widget kind identifier (e.g., 'cf.cplace.platform.table', 'cf.platform.wiki')")
|
|
26
|
+
},
|
|
27
|
+
annotations: { title: "Get Widget Definition Details" }
|
|
28
|
+
},
|
|
29
|
+
[TOOL_GET_WIDGET_DETAILS]: {
|
|
30
|
+
description: "Get detailed configuration for a specific widget within a page layout. Use this after cplace_get_page_layout_overview to examine specific widget configurations.",
|
|
31
|
+
inputSchema: {
|
|
32
|
+
pageUID: z.string().describe("The unique identifier (UID) of the page containing the widget"),
|
|
33
|
+
widgetId: z.string().describe("The unique widget identifier from the layout (e.g., 'id_123', 'id_456')")
|
|
34
|
+
},
|
|
35
|
+
annotations: { title: "Get Widget Details" }
|
|
36
|
+
},
|
|
37
|
+
[TOOL_GET_EMBEDDED_LAYOUT]: {
|
|
38
|
+
description: "Get embedded widget layout structure for page or type. Retrieves the widget layout structure of embedded widgets within container widgets like AttributesGroup widgets.",
|
|
39
|
+
inputSchema: {
|
|
40
|
+
context: z.union([
|
|
41
|
+
z.object({
|
|
42
|
+
type: z.literal("page"),
|
|
43
|
+
pageUID: z.string().describe("Page UID (e.g., 'page/abc123')"),
|
|
44
|
+
containerWidgetId: z.string().describe("Container widget ID (e.g., 'id_abc123')"),
|
|
45
|
+
layoutAttributeName: z.string().describe("Layout attribute name (e.g., 'detailsLayout')")
|
|
46
|
+
}),
|
|
47
|
+
z.object({
|
|
48
|
+
type: z.literal("type"),
|
|
49
|
+
workspaceId: z.string().describe("Workspace ID (e.g., 'workspace123')"),
|
|
50
|
+
typeInternalName: z.string().describe("Type internal name (e.g., 'cf.example.myType')"),
|
|
51
|
+
alternativeLayoutName: z.string().optional().describe("Alternative layout name (optional)"),
|
|
52
|
+
containerWidgetId: z.string().describe("Container widget ID (e.g., 'id_abc123')"),
|
|
53
|
+
layoutAttributeName: z.string().describe("Layout attribute name (e.g., 'detailsLayout')")
|
|
54
|
+
})
|
|
55
|
+
]).describe("Embedded layout target - specify whether operating on page or type embedded layout")
|
|
56
|
+
},
|
|
57
|
+
annotations: { title: "Get Embedded Layout" }
|
|
58
|
+
},
|
|
59
|
+
[TOOL_ADD_WIDGET_TO_EMBEDDED_LAYOUT]: {
|
|
60
|
+
description: "Add widget to page or type embedded layout. Enables adding widgets to nested layouts like those within AttributesGroup widgets.",
|
|
61
|
+
inputSchema: {
|
|
62
|
+
context: z.union([
|
|
63
|
+
z.object({
|
|
64
|
+
type: z.literal("page"),
|
|
65
|
+
pageUID: z.string().describe("Page UID (e.g., 'page/abc123')"),
|
|
66
|
+
containerWidgetId: z.string().describe("Container widget ID (e.g., 'id_abc123')"),
|
|
67
|
+
layoutAttributeName: z.string().describe("Layout attribute name (e.g., 'detailsLayout')")
|
|
68
|
+
}),
|
|
69
|
+
z.object({
|
|
70
|
+
type: z.literal("type"),
|
|
71
|
+
workspaceId: z.string().describe("Workspace ID (e.g., 'workspace123')"),
|
|
72
|
+
typeInternalName: z.string().describe("Type internal name (e.g., 'cf.example.myType')"),
|
|
73
|
+
alternativeLayoutName: z.string().optional().describe("Alternative layout name (optional)"),
|
|
74
|
+
containerWidgetId: z.string().describe("Container widget ID (e.g., 'id_abc123')"),
|
|
75
|
+
layoutAttributeName: z.string().describe("Layout attribute name (e.g., 'detailsLayout')")
|
|
76
|
+
})
|
|
77
|
+
]).describe("Embedded layout target - specify whether operating on page or type embedded layout"),
|
|
78
|
+
widgetType: z.string().describe("Widget type identifier (e.g., 'cf.cplace.platform.table', 'cf.platform.wiki')"),
|
|
79
|
+
position: PositionSchema,
|
|
80
|
+
configuration: z.record(z.any()).optional().describe(WIDGET_CONFIG_DESCRIPTION)
|
|
81
|
+
},
|
|
82
|
+
annotations: { title: "Add Widget to Embedded Layout" }
|
|
83
|
+
},
|
|
84
|
+
[TOOL_REMOVE_WIDGET_FROM_EMBEDDED_LAYOUT]: {
|
|
85
|
+
description: "Remove widget from page or type embedded layout. Enables removing widgets from nested layouts like those within AttributesGroup widgets.",
|
|
86
|
+
inputSchema: {
|
|
87
|
+
context: z.union([
|
|
88
|
+
z.object({
|
|
89
|
+
type: z.literal("page"),
|
|
90
|
+
pageUID: z.string().describe("Page UID (e.g., 'page/abc123')"),
|
|
91
|
+
containerWidgetId: z.string().describe("Container widget ID (e.g., 'id_abc123')"),
|
|
92
|
+
layoutAttributeName: z.string().describe("Layout attribute name (e.g., 'detailsLayout')")
|
|
93
|
+
}),
|
|
94
|
+
z.object({
|
|
95
|
+
type: z.literal("type"),
|
|
96
|
+
workspaceId: z.string().describe("Workspace ID (e.g., 'workspace123')"),
|
|
97
|
+
typeInternalName: z.string().describe("Type internal name (e.g., 'cf.example.myType')"),
|
|
98
|
+
alternativeLayoutName: z.string().optional().describe("Alternative layout name (optional)"),
|
|
99
|
+
containerWidgetId: z.string().describe("Container widget ID (e.g., 'id_abc123')"),
|
|
100
|
+
layoutAttributeName: z.string().describe("Layout attribute name (e.g., 'detailsLayout')")
|
|
101
|
+
})
|
|
102
|
+
]).describe("Embedded layout target - specify whether operating on page or type embedded layout"),
|
|
103
|
+
widgetId: z.string().describe("The ID of the existing widget to remove from the embedded layout")
|
|
104
|
+
},
|
|
105
|
+
annotations: { title: "Remove Widget from Embedded Layout" }
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
export function registerWidgetTools(server, client) {
|
|
109
|
+
const WIDGET_ATTRIBUTE_ENHANCEMENTS = {
|
|
110
|
+
'cf.cplace.platform.attributesGroup': {
|
|
111
|
+
'cf.cplace.platform.attributesGroup.pageSelection': {
|
|
112
|
+
validValues: {
|
|
113
|
+
'embedding': 'Use the current embedding page (the page containing this widget)',
|
|
114
|
+
'parent': 'Use the parent page of the embedding page',
|
|
115
|
+
'absolute': 'Use an absolute page reference (requires cf.cplace.platform.attributesGroup.absoluteSelection)',
|
|
116
|
+
'relative': 'Use a relative reference through an attribute (requires cf.cplace.platform.attributesGroup.relativeSelection)'
|
|
117
|
+
},
|
|
118
|
+
defaultValue: 'embedding',
|
|
119
|
+
note: 'This attribute determines which page\'s attributes are displayed in the widget'
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
server.registerTool(TOOL_LIST_WIDGET_DEFINITIONS, WIDGET_TOOL_DEFINITIONS[TOOL_LIST_WIDGET_DEFINITIONS], async ({ embeddingContext = "AS_WIDGET" }) => {
|
|
16
124
|
debugLogWithTag('WIDGETS', `Starting widget definitions list request with embeddingContext: ${embeddingContext}`);
|
|
17
125
|
try {
|
|
18
126
|
const result = await client.makeApiRequest('json/widget-definitions', 'GET', { embeddingContext });
|
|
@@ -31,27 +139,7 @@ export function registerWidgetTools(server, client) {
|
|
|
31
139
|
};
|
|
32
140
|
}
|
|
33
141
|
});
|
|
34
|
-
|
|
35
|
-
'cf.cplace.platform.attributesGroup': {
|
|
36
|
-
'cf.cplace.platform.attributesGroup.pageSelection': {
|
|
37
|
-
validValues: {
|
|
38
|
-
'embedding': 'Use the current embedding page (the page containing this widget)',
|
|
39
|
-
'parent': 'Use the parent page of the embedding page',
|
|
40
|
-
'absolute': 'Use an absolute page reference (requires cf.cplace.platform.attributesGroup.absoluteSelection)',
|
|
41
|
-
'relative': 'Use a relative reference through an attribute (requires cf.cplace.platform.attributesGroup.relativeSelection)'
|
|
42
|
-
},
|
|
43
|
-
defaultValue: 'embedding',
|
|
44
|
-
note: 'This attribute determines which page\'s attributes are displayed in the widget'
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
};
|
|
48
|
-
server.registerTool("cplace_get_widget_definition", {
|
|
49
|
-
description: "Get detailed widget configuration schema.\n\n🔍 ALWAYS USE BEFORE ADDING/CONFIGURING WIDGETS to understand:\n- Required vs optional attributes\n- Correct attribute names (often not intuitive!)\n- Expected data types and formats\n- Available enumeration values\n\nCOMMON GOTCHAS:\n- Bar charts use 'attributeName' not 'attribute'\n- Connected charts need 'tableWidgetId' to link to tables\n- Attribute names often need single quotes: \"'cf.cplace.myAttribute'\"\n- LocalizedString format: {\"en\": \"English\", \"de\": \"German\"}\n\nWidget kinds: 'cf.platform.connectedBarChart', 'cf.platform.wiki', etc.",
|
|
50
|
-
inputSchema: {
|
|
51
|
-
widgetKind: z.string().describe("The widget kind identifier (e.g., 'cf.cplace.platform.table', 'cf.platform.wiki')")
|
|
52
|
-
},
|
|
53
|
-
annotations: { title: "Get Widget Definition Details" }
|
|
54
|
-
}, async ({ widgetKind }) => {
|
|
142
|
+
server.registerTool(TOOL_GET_WIDGET_DEFINITION, WIDGET_TOOL_DEFINITIONS[TOOL_GET_WIDGET_DEFINITION], async ({ widgetKind }) => {
|
|
55
143
|
debugLogWithTag('WIDGETS', `Starting widget definition request for: ${widgetKind}`);
|
|
56
144
|
try {
|
|
57
145
|
const result = await client.makeApiRequest('json/widget-definition', 'GET', { widgetKind });
|
|
@@ -84,53 +172,7 @@ export function registerWidgetTools(server, client) {
|
|
|
84
172
|
};
|
|
85
173
|
}
|
|
86
174
|
});
|
|
87
|
-
server.registerTool(
|
|
88
|
-
description: "Get the high-level layout structure of a page including rows, columns, and widget summaries. Provides an overview of the page layout grid without detailed widget configurations.",
|
|
89
|
-
inputSchema: {
|
|
90
|
-
pageUID: z.string().describe("The unique identifier (UID) of the page to get layout for, e.g. 'page/kkt8ol745jqur4581kelm5ply'")
|
|
91
|
-
},
|
|
92
|
-
annotations: { title: "Get Page Layout Overview" }
|
|
93
|
-
}, async ({ pageUID }) => {
|
|
94
|
-
debugLogWithTag('LAYOUT', `Starting page layout overview request for: ${pageUID}`);
|
|
95
|
-
try {
|
|
96
|
-
const result = await client.makeApiRequest('json/pageLayout', 'GET', { pageUID });
|
|
97
|
-
const overview = {
|
|
98
|
-
rows: result.rows?.map((row, rowIndex) => ({
|
|
99
|
-
rowIndex,
|
|
100
|
-
columns: row.columns?.map((column, colIndex) => ({
|
|
101
|
-
columnIndex: colIndex,
|
|
102
|
-
proportion: column.proportion,
|
|
103
|
-
widgets: column.widgets?.map((widget) => ({
|
|
104
|
-
id: widget.id,
|
|
105
|
-
widgetType: widget.widgetType,
|
|
106
|
-
configurationCount: widget.configuration?.length || 0
|
|
107
|
-
})) || []
|
|
108
|
-
})) || []
|
|
109
|
-
})) || []
|
|
110
|
-
};
|
|
111
|
-
debugLogWithTag('LAYOUT', `Retrieved page layout overview for: ${pageUID}`);
|
|
112
|
-
return {
|
|
113
|
-
content: [{ type: "text", text: JSON.stringify(overview, null, 2) }]
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
catch (error) {
|
|
117
|
-
return {
|
|
118
|
-
content: [{
|
|
119
|
-
type: "text",
|
|
120
|
-
text: `Error retrieving page layout overview for ${pageUID}: ${error instanceof Error ? error.message : String(error)}`
|
|
121
|
-
}],
|
|
122
|
-
isError: true
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
server.registerTool("cplace_get_widget_details", {
|
|
127
|
-
description: "Get detailed configuration for a specific widget within a page layout. Use this after cplace_get_page_layout_overview to examine specific widget configurations.",
|
|
128
|
-
inputSchema: {
|
|
129
|
-
pageUID: z.string().describe("The unique identifier (UID) of the page containing the widget"),
|
|
130
|
-
widgetId: z.string().describe("The unique widget identifier from the layout (e.g., 'id_123', 'id_456')")
|
|
131
|
-
},
|
|
132
|
-
annotations: { title: "Get Widget Details" }
|
|
133
|
-
}, async ({ pageUID, widgetId }) => {
|
|
175
|
+
server.registerTool(TOOL_GET_WIDGET_DETAILS, WIDGET_TOOL_DEFINITIONS[TOOL_GET_WIDGET_DETAILS], async ({ pageUID, widgetId }) => {
|
|
134
176
|
debugLogWithTag('LAYOUT', `Starting widget details request for widget ${widgetId} in page ${pageUID}`);
|
|
135
177
|
try {
|
|
136
178
|
const result = await client.makeApiRequest('json/pageLayout', 'GET', { pageUID });
|
|
@@ -159,582 +201,163 @@ export function registerWidgetTools(server, client) {
|
|
|
159
201
|
};
|
|
160
202
|
}
|
|
161
203
|
debugLogWithTag('LAYOUT', `Retrieved widget details for: ${widgetId} in page`);
|
|
162
|
-
return {
|
|
163
|
-
content: [{ type: "text", text: JSON.stringify(foundWidget, null, 2) }]
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
catch (error) {
|
|
167
|
-
return {
|
|
168
|
-
content: [{
|
|
169
|
-
type: "text",
|
|
170
|
-
text: `Error retrieving widget details for ${widgetId} in page ${pageUID}: ${error instanceof Error ? error.message : String(error)}`
|
|
171
|
-
}],
|
|
172
|
-
isError: true
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
});
|
|
176
|
-
server.registerTool("cplace_add_widget_to_layout", {
|
|
177
|
-
description: "Add a new widget to a page layout at a specific position.\n\n⚠️ REQUIRED BEFORE USE:\n- ALWAYS call cplace_get_widget_definition FIRST to understand required fields\n- Many widgets have non-obvious required attributes that will cause validation errors\n- Widget configurations must match the schema exactly\n\nCRITICAL BEHAVIOR:\n- Row creation: ❌ NOT automatic - use cplace_add_row_to_page_layout to create rows first\n- Column creation: ❌ NOT automatic - columnIndex only references existing columns\n- Invalid columnIndex: Falls back to last existing column (no error)\n\nTO CREATE SIDE-BY-SIDE LAYOUTS:\n1. First use cplace_add_row_to_page_layout to create multi-column structure\n2. Then add widgets to the created columns\n\nEXAMPLES:\n- Add to new row 0: Creates single-column row, widget goes to column 0\n- Add to column 1 when only column 0 exists: Widget goes to column 0 (fallback)\n- Add to pre-created 6/6 row: Works correctly if columns exist\n\nTIP: Always check current layout with cplace_get_page_layout_overview before adding widgets.\n\nSupports both page-level layouts (default) and embedded layouts within container widgets like AttributesGroup.",
|
|
178
|
-
inputSchema: {
|
|
179
|
-
pageUID: z.string().describe("The unique identifier (UID) of the page to add the widget to"),
|
|
180
|
-
widgetType: z.string().describe("The widget type identifier (e.g., 'cf.cplace.platform.table', 'cf.platform.wiki', 'cf.platform.singleAttribute')"),
|
|
181
|
-
configuration: z.record(z.any()).optional().describe(`${WIDGET_CONFIG_DESCRIPTION}
|
|
182
|
-
|
|
183
|
-
WIDGET-SPECIFIC PATTERNS:
|
|
184
|
-
- Connected widgets (bar/pie charts): Use 'tableWidgetId' to connect to existing table widget
|
|
185
|
-
Example: {'tableWidgetId': 'id_abc123', 'title': {'en': 'Chart Title'}}
|
|
186
|
-
- Attribute widgets: Use 'cf.platform.quotedAttributeName' with single quotes
|
|
187
|
-
Example: {'cf.platform.quotedAttributeName': "'cf.cplace.myAttribute'", 'cf.platform.withLabel': true}
|
|
188
|
-
- Search widgets: Use 'search' with JSON search string
|
|
189
|
-
Example: {'search': '{"filters":[{"types":["test.project"]}]}', 'title': {'en': 'Results'}}
|
|
190
|
-
|
|
191
|
-
For embedded attribute widgets: {'cf.platform.quotedAttributeName': "'cf.cplace.myAttribute'", 'cf.platform.withLabel': true}`),
|
|
192
|
-
position: PositionSchema.extend({}).describe("Grid position where the widget should be added"),
|
|
193
|
-
layoutContext: z.enum(["page", "widget"]).default("page").describe("Layout context: 'page' for page-level layout (default), 'widget' for embedded layout within a container widget"),
|
|
194
|
-
containerWidgetId: z.string().optional().describe("Required when layoutContext is 'widget'. The unique identifier of the container widget (e.g., AttributesGroup widget) that contains the embedded layout to modify"),
|
|
195
|
-
layoutAttributeName: z.string().optional().describe("Optional layout attribute name for embedded layouts. If not provided, it will be auto-detected based on the container widget type")
|
|
196
|
-
},
|
|
197
|
-
annotations: { title: "Add Widget to Layout" }
|
|
198
|
-
}, async ({ pageUID, widgetType, configuration, position, layoutContext = "page", containerWidgetId, layoutAttributeName }) => {
|
|
199
|
-
debugLogWithTag('LAYOUT_MODIFY', `Starting add widget operation: ${widgetType} to ${layoutContext === "widget" ? "embedded layout in container " + containerWidgetId : "page layout"} ${pageUID} at position ${JSON.stringify(position)}`);
|
|
200
|
-
try {
|
|
201
|
-
if (layoutContext === "widget") {
|
|
202
|
-
if (!containerWidgetId) {
|
|
203
|
-
return {
|
|
204
|
-
content: [{ type: "text", text: "containerWidgetId is required when layoutContext is 'widget'" }]
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
debugLogWithTag('LAYOUT_MODIFY', `Adding to embedded layout in container widget: ${containerWidgetId}`);
|
|
208
|
-
}
|
|
209
|
-
const operation = {
|
|
210
|
-
type: "ADD",
|
|
211
|
-
widgetType,
|
|
212
|
-
position: {
|
|
213
|
-
rowIndex: position.rowIndex,
|
|
214
|
-
columnIndex: position.columnIndex,
|
|
215
|
-
widgetIndex: position.widgetIndex
|
|
216
|
-
}
|
|
217
|
-
};
|
|
218
|
-
if (configuration && Object.keys(configuration).length > 0) {
|
|
219
|
-
operation.configuration = configuration;
|
|
220
|
-
debugLogWithTag('LAYOUT_MODIFY', `Including configuration: ${JSON.stringify(Object.keys(configuration))}`);
|
|
221
|
-
}
|
|
222
|
-
const requestBody = {
|
|
223
|
-
pageUID,
|
|
224
|
-
layoutContext,
|
|
225
|
-
operation
|
|
226
|
-
};
|
|
227
|
-
if (layoutContext === "widget") {
|
|
228
|
-
requestBody.containerWidgetId = containerWidgetId;
|
|
229
|
-
if (layoutAttributeName) {
|
|
230
|
-
requestBody.layoutAttributeName = layoutAttributeName;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
debugLogWithTag('LAYOUT_MODIFY', `Request body: ${JSON.stringify(requestBody, null, 2)}`);
|
|
234
|
-
const result = await client.makeApiRequest('json/pageLayout', 'PATCH', undefined, requestBody);
|
|
235
|
-
debugLogWithTag('LAYOUT_MODIFY', `Successfully added widget ${widgetType} to page ${pageUID}`);
|
|
236
|
-
const response = {
|
|
237
|
-
operation: "ADD_WIDGET",
|
|
238
|
-
status: "SUCCESS",
|
|
239
|
-
pageUID,
|
|
240
|
-
widgetType,
|
|
241
|
-
position,
|
|
242
|
-
layoutContext,
|
|
243
|
-
...(layoutContext === "widget" && containerWidgetId && { containerWidgetId }),
|
|
244
|
-
message: layoutContext === "widget"
|
|
245
|
-
? "Widget added successfully to embedded layout"
|
|
246
|
-
: "Widget added successfully"
|
|
247
|
-
};
|
|
248
|
-
return {
|
|
249
|
-
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
catch (error) {
|
|
253
|
-
debugLogWithTag('LAYOUT_MODIFY', `Error adding widget: ${error instanceof Error ? error.message : String(error)}`);
|
|
254
|
-
const errorResponse = {
|
|
255
|
-
operation: "ADD_WIDGET",
|
|
256
|
-
status: "ERROR",
|
|
257
|
-
pageUID,
|
|
258
|
-
widgetType,
|
|
259
|
-
position,
|
|
260
|
-
layoutContext,
|
|
261
|
-
...(layoutContext === "widget" && containerWidgetId && { containerWidgetId }),
|
|
262
|
-
error: error instanceof Error ? error.message : String(error),
|
|
263
|
-
message: "Failed to add widget"
|
|
264
|
-
};
|
|
265
|
-
return {
|
|
266
|
-
content: [{ type: "text", text: JSON.stringify(errorResponse, null, 2) }],
|
|
267
|
-
isError: true
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
});
|
|
271
|
-
server.registerTool("cplace_remove_widget_from_layout", {
|
|
272
|
-
description: "Remove an existing widget from a page layout",
|
|
273
|
-
inputSchema: {
|
|
274
|
-
pageUID: z.string().describe("The unique identifier (UID) of the page containing the widget"),
|
|
275
|
-
widgetId: z.string().describe("The unique identifier of the widget to remove")
|
|
276
|
-
},
|
|
277
|
-
annotations: { title: "Remove Widget from Layout" }
|
|
278
|
-
}, async ({ pageUID, widgetId }) => {
|
|
279
|
-
debugLogWithTag('LAYOUT_MODIFY', `Starting remove widget operation: ${widgetId} from page ${pageUID}`);
|
|
280
|
-
try {
|
|
281
|
-
const requestBody = {
|
|
282
|
-
pageUID,
|
|
283
|
-
operation: {
|
|
284
|
-
type: "REMOVE",
|
|
285
|
-
widgetId
|
|
286
|
-
}
|
|
287
|
-
};
|
|
288
|
-
debugLogWithTag('LAYOUT_MODIFY', `Request body: ${JSON.stringify(requestBody, null, 2)}`);
|
|
289
|
-
const result = await client.makeApiRequest('json/pageLayout', 'PATCH', undefined, requestBody);
|
|
290
|
-
debugLogWithTag('LAYOUT_MODIFY', `Successfully removed widget ${widgetId} from page ${pageUID}`);
|
|
291
204
|
const response = {
|
|
292
|
-
operation: "REMOVE_WIDGET",
|
|
293
|
-
status: "SUCCESS",
|
|
294
|
-
pageUID,
|
|
295
205
|
widgetId,
|
|
296
|
-
message: "Widget removed successfully"
|
|
297
|
-
};
|
|
298
|
-
return {
|
|
299
|
-
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
catch (error) {
|
|
303
|
-
debugLogWithTag('LAYOUT_MODIFY', `Error removing widget: ${error instanceof Error ? error.message : String(error)}`);
|
|
304
|
-
const errorResponse = {
|
|
305
|
-
operation: "REMOVE_WIDGET",
|
|
306
|
-
status: "ERROR",
|
|
307
206
|
pageUID,
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
message: "Failed to remove widget"
|
|
311
|
-
};
|
|
312
|
-
return {
|
|
313
|
-
content: [{ type: "text", text: JSON.stringify(errorResponse, null, 2) }],
|
|
314
|
-
isError: true
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
});
|
|
318
|
-
server.registerTool("cplace_update_widget_in_layout", {
|
|
319
|
-
description: "Modify widget configuration or display properties.\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.",
|
|
320
|
-
inputSchema: {
|
|
321
|
-
pageUID: z.string().describe("The unique identifier (UID) of the page containing the widget"),
|
|
322
|
-
widgetId: z.string().describe("The unique identifier of the widget to update"),
|
|
323
|
-
newConfiguration: z.record(z.any()).optional().describe(`Updated widget configuration as key-value pairs (optional). ${WIDGET_CONFIG_DESCRIPTION}`),
|
|
324
|
-
collapsed: z.boolean().optional().describe("Widget collapse state (optional)")
|
|
325
|
-
},
|
|
326
|
-
annotations: { title: "Update Widget in Layout" }
|
|
327
|
-
}, async ({ pageUID, widgetId, newConfiguration, collapsed }) => {
|
|
328
|
-
debugLogWithTag('LAYOUT_MODIFY', `Starting update widget operation: ${widgetId} in page ${pageUID}`);
|
|
329
|
-
try {
|
|
330
|
-
const operation = {
|
|
331
|
-
type: "UPDATE",
|
|
332
|
-
widgetId
|
|
333
|
-
};
|
|
334
|
-
if (newConfiguration && Object.keys(newConfiguration).length > 0) {
|
|
335
|
-
operation.newConfiguration = newConfiguration;
|
|
336
|
-
debugLogWithTag('LAYOUT_MODIFY', `Including new configuration: ${JSON.stringify(Object.keys(newConfiguration))}`);
|
|
337
|
-
}
|
|
338
|
-
if (collapsed !== undefined) {
|
|
339
|
-
operation.collapsed = collapsed;
|
|
340
|
-
debugLogWithTag('LAYOUT_MODIFY', `Setting collapsed state to: ${collapsed}`);
|
|
341
|
-
}
|
|
342
|
-
if (!operation.newConfiguration && operation.collapsed === undefined) {
|
|
343
|
-
return {
|
|
344
|
-
content: [{ type: "text", text: "No updates specified. At least one of newConfiguration or collapsed must be provided." }]
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
const requestBody = {
|
|
348
|
-
pageUID,
|
|
349
|
-
operation
|
|
350
|
-
};
|
|
351
|
-
debugLogWithTag('LAYOUT_MODIFY', `Request body: ${JSON.stringify(requestBody, null, 2)}`);
|
|
352
|
-
const result = await client.makeApiRequest('json/pageLayout', 'PATCH', undefined, requestBody);
|
|
353
|
-
debugLogWithTag('LAYOUT_MODIFY', `Successfully updated widget ${widgetId} in page ${pageUID}`);
|
|
354
|
-
const response = {
|
|
355
|
-
operation: "UPDATE_WIDGET",
|
|
356
|
-
status: "SUCCESS",
|
|
357
|
-
pageUID,
|
|
358
|
-
widgetId,
|
|
359
|
-
message: "Widget updated successfully"
|
|
360
|
-
};
|
|
361
|
-
return {
|
|
362
|
-
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
catch (error) {
|
|
366
|
-
debugLogWithTag('LAYOUT_MODIFY', `Error updating widget: ${error instanceof Error ? error.message : String(error)}`);
|
|
367
|
-
const errorResponse = {
|
|
368
|
-
operation: "UPDATE_WIDGET",
|
|
369
|
-
status: "ERROR",
|
|
370
|
-
pageUID,
|
|
371
|
-
widgetId,
|
|
372
|
-
error: error instanceof Error ? error.message : String(error),
|
|
373
|
-
message: "Failed to update widget"
|
|
374
|
-
};
|
|
375
|
-
return {
|
|
376
|
-
content: [{ type: "text", text: JSON.stringify(errorResponse, null, 2) }],
|
|
377
|
-
isError: true
|
|
378
|
-
};
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
|
-
server.registerTool("cplace_move_widget_in_layout", {
|
|
382
|
-
description: "Relocate a widget to a different position in the layout.\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_get_widget_details to check if configuration was preserved\n3. If lost, use cplace_update_widget_in_layout 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.",
|
|
383
|
-
inputSchema: {
|
|
384
|
-
pageUID: z.string().describe("The unique identifier (UID) of the page containing the widget"),
|
|
385
|
-
widgetId: z.string().describe("The unique identifier of the widget to move"),
|
|
386
|
-
newPosition: PositionSchema.extend({}).describe("Target grid position for the widget")
|
|
387
|
-
},
|
|
388
|
-
annotations: { title: "Move Widget in Layout" }
|
|
389
|
-
}, async ({ pageUID, widgetId, newPosition }) => {
|
|
390
|
-
debugLogWithTag('LAYOUT_MODIFY', `Starting move widget operation: ${widgetId} in page ${pageUID} to position ${JSON.stringify(newPosition)}`);
|
|
391
|
-
try {
|
|
392
|
-
const requestBody = {
|
|
393
|
-
pageUID,
|
|
394
|
-
operation: {
|
|
395
|
-
type: "MOVE",
|
|
396
|
-
widgetId,
|
|
397
|
-
newPosition: {
|
|
398
|
-
rowIndex: newPosition.rowIndex,
|
|
399
|
-
columnIndex: newPosition.columnIndex,
|
|
400
|
-
widgetIndex: newPosition.widgetIndex
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
};
|
|
404
|
-
debugLogWithTag('LAYOUT_MODIFY', `Request body: ${JSON.stringify(requestBody, null, 2)}`);
|
|
405
|
-
const result = await client.makeApiRequest('json/pageLayout', 'PATCH', undefined, requestBody);
|
|
406
|
-
debugLogWithTag('LAYOUT_MODIFY', `Successfully moved widget ${widgetId} in page ${pageUID}`);
|
|
407
|
-
let newWidgetId = widgetId;
|
|
408
|
-
let widgetIdChanged = false;
|
|
409
|
-
try {
|
|
410
|
-
const layoutString = result.result;
|
|
411
|
-
const layout = JSON.parse(layoutString);
|
|
412
|
-
if (layout.rows && layout.rows[newPosition.rowIndex]) {
|
|
413
|
-
const targetRow = layout.rows[newPosition.rowIndex];
|
|
414
|
-
if (targetRow.columns && targetRow.columns[newPosition.columnIndex]) {
|
|
415
|
-
const targetColumn = targetRow.columns[newPosition.columnIndex];
|
|
416
|
-
if (targetColumn.widgets && targetColumn.widgets[newPosition.widgetIndex]) {
|
|
417
|
-
const movedWidget = targetColumn.widgets[newPosition.widgetIndex];
|
|
418
|
-
if (movedWidget.id && movedWidget.id !== widgetId) {
|
|
419
|
-
newWidgetId = movedWidget.id;
|
|
420
|
-
widgetIdChanged = true;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
catch (parseError) {
|
|
427
|
-
debugLogWithTag('LAYOUT_MODIFY', `Could not parse layout to detect ID change: ${parseError}`);
|
|
428
|
-
}
|
|
429
|
-
const response = {
|
|
430
|
-
operation: "MOVE_WIDGET",
|
|
431
|
-
status: "SUCCESS",
|
|
432
|
-
pageUID,
|
|
433
|
-
oldWidgetId: widgetId,
|
|
434
|
-
newWidgetId,
|
|
435
|
-
newPosition,
|
|
436
|
-
widgetIdChanged,
|
|
437
|
-
message: widgetIdChanged
|
|
438
|
-
? "Widget moved successfully - widget ID changed, please update any references"
|
|
439
|
-
: "Widget moved successfully"
|
|
207
|
+
widget: foundWidget,
|
|
208
|
+
validationStatus: foundWidget.validationStatus || null
|
|
440
209
|
};
|
|
441
210
|
return {
|
|
442
211
|
content: [{ type: "text", text: JSON.stringify(response, null, 2) }]
|
|
443
212
|
};
|
|
444
213
|
}
|
|
445
|
-
catch (error) {
|
|
446
|
-
debugLogWithTag('LAYOUT_MODIFY', `Error moving widget: ${error instanceof Error ? error.message : String(error)}`);
|
|
447
|
-
const errorResponse = {
|
|
448
|
-
operation: "MOVE_WIDGET",
|
|
449
|
-
status: "ERROR",
|
|
450
|
-
pageUID,
|
|
451
|
-
oldWidgetId: widgetId,
|
|
452
|
-
newPosition,
|
|
453
|
-
error: error instanceof Error ? error.message : String(error),
|
|
454
|
-
message: "Failed to move widget"
|
|
455
|
-
};
|
|
456
|
-
return {
|
|
457
|
-
content: [{ type: "text", text: JSON.stringify(errorResponse, null, 2) }],
|
|
458
|
-
isError: true
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
});
|
|
462
|
-
server.registerTool("cplace_get_embedded_layout", {
|
|
463
|
-
description: "Get the widget layout structure of an embedded widget within a container widget on a specific page. This endpoint accesses nested widget layouts embedded within other widgets, such as AttributesGroup widgets.",
|
|
464
|
-
inputSchema: {
|
|
465
|
-
pageUID: z.string().describe("The unique identifier (UID) of the page containing the container widget"),
|
|
466
|
-
containerWidgetId: z.string().describe("The ID of the container widget that contains the embedded layout"),
|
|
467
|
-
layoutAttributeName: z.string().describe("The name of the attribute that defines the embedded layout structure")
|
|
468
|
-
},
|
|
469
|
-
annotations: { title: "Get Embedded Layout" }
|
|
470
|
-
}, async ({ pageUID, containerWidgetId, layoutAttributeName }) => {
|
|
471
|
-
debugLogWithTag('EMBEDDED_LAYOUT', `Starting embedded widget layout request for container ${containerWidgetId} in page ${pageUID}`);
|
|
472
|
-
try {
|
|
473
|
-
const result = await client.makeApiRequest('json/page/embeddedWidgetLayout', 'GET', {
|
|
474
|
-
pageUID,
|
|
475
|
-
containerWidgetId,
|
|
476
|
-
layoutAttributeName
|
|
477
|
-
});
|
|
478
|
-
debugLogWithTag('EMBEDDED_LAYOUT', `Retrieved embedded widget layout for container: ${containerWidgetId}`);
|
|
479
|
-
return {
|
|
480
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
481
|
-
};
|
|
482
|
-
}
|
|
483
214
|
catch (error) {
|
|
484
215
|
return {
|
|
485
216
|
content: [{
|
|
486
217
|
type: "text",
|
|
487
|
-
text: `Error retrieving
|
|
218
|
+
text: `Error retrieving widget details for ${widgetId} in page ${pageUID}: ${error instanceof Error ? error.message : String(error)}`
|
|
488
219
|
}],
|
|
489
220
|
isError: true
|
|
490
221
|
};
|
|
491
222
|
}
|
|
492
223
|
});
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
pageUID: z.string().describe("
|
|
497
|
-
containerWidgetId: z.string().describe("
|
|
498
|
-
layoutAttributeName: z.string().describe("
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
layoutAttributeName,
|
|
522
|
-
operation
|
|
523
|
-
};
|
|
524
|
-
debugLogWithTag('EMBEDDED_LAYOUT_ADD', `Request body: ${JSON.stringify(requestBody, null, 2)}`);
|
|
525
|
-
const result = await client.makeApiRequest('json/page/embeddedWidgetLayout', 'PATCH', undefined, requestBody);
|
|
526
|
-
debugLogWithTag('EMBEDDED_LAYOUT_ADD', `Successfully added widget ${widgetType} to embedded layout`);
|
|
527
|
-
const response = {
|
|
528
|
-
operation: "ADD_EMBEDDED_WIDGET",
|
|
529
|
-
status: "SUCCESS",
|
|
530
|
-
pageUID,
|
|
531
|
-
containerWidgetId,
|
|
532
|
-
layoutAttributeName,
|
|
533
|
-
widgetType,
|
|
534
|
-
position,
|
|
535
|
-
message: "Widget added successfully to embedded layout"
|
|
536
|
-
};
|
|
224
|
+
const EmbeddedLayoutContextSchema = z.union([
|
|
225
|
+
z.object({
|
|
226
|
+
type: z.literal("page"),
|
|
227
|
+
pageUID: z.string().describe("Page UID (e.g., 'page/abc123')"),
|
|
228
|
+
containerWidgetId: z.string().describe("Container widget ID (e.g., 'id_abc123')"),
|
|
229
|
+
layoutAttributeName: z.string().describe("Layout attribute name (e.g., 'detailsLayout')")
|
|
230
|
+
}),
|
|
231
|
+
z.object({
|
|
232
|
+
type: z.literal("type"),
|
|
233
|
+
workspaceId: z.string().describe("Workspace ID (e.g., 'workspace123')"),
|
|
234
|
+
typeInternalName: z.string().describe("Type internal name (e.g., 'cf.example.myType')"),
|
|
235
|
+
alternativeLayoutName: z.string().optional().describe("Alternative layout name (optional)"),
|
|
236
|
+
containerWidgetId: z.string().describe("Container widget ID (e.g., 'id_abc123')"),
|
|
237
|
+
layoutAttributeName: z.string().describe("Layout attribute name (e.g., 'detailsLayout')")
|
|
238
|
+
})
|
|
239
|
+
]).describe("Embedded layout target - specify whether operating on page or type embedded layout");
|
|
240
|
+
function determineEmbeddedApiEndpoint(context) {
|
|
241
|
+
return context.type === "page"
|
|
242
|
+
? "json/page/embeddedWidgetLayout"
|
|
243
|
+
: "json/type/embeddedWidgetLayout";
|
|
244
|
+
}
|
|
245
|
+
function buildEmbeddedRequestParams(context, additionalParams = {}) {
|
|
246
|
+
const commonParams = {
|
|
247
|
+
containerWidgetId: context.containerWidgetId,
|
|
248
|
+
layoutAttributeName: context.layoutAttributeName,
|
|
249
|
+
...additionalParams
|
|
250
|
+
};
|
|
251
|
+
if (context.type === "page") {
|
|
537
252
|
return {
|
|
538
|
-
|
|
253
|
+
pageUID: context.pageUID,
|
|
254
|
+
...commonParams
|
|
539
255
|
};
|
|
540
256
|
}
|
|
541
|
-
|
|
542
|
-
debugLogWithTag('EMBEDDED_LAYOUT_ADD', `Error adding widget to embedded layout: ${error instanceof Error ? error.message : String(error)}`);
|
|
543
|
-
const errorResponse = {
|
|
544
|
-
operation: "ADD_EMBEDDED_WIDGET",
|
|
545
|
-
status: "ERROR",
|
|
546
|
-
pageUID,
|
|
547
|
-
containerWidgetId,
|
|
548
|
-
layoutAttributeName,
|
|
549
|
-
widgetType,
|
|
550
|
-
position,
|
|
551
|
-
error: error instanceof Error ? error.message : String(error),
|
|
552
|
-
message: "Failed to add widget to embedded layout"
|
|
553
|
-
};
|
|
257
|
+
else {
|
|
554
258
|
return {
|
|
555
|
-
|
|
556
|
-
|
|
259
|
+
workspaceId: context.workspaceId,
|
|
260
|
+
typeInternalName: context.typeInternalName,
|
|
261
|
+
...(context.alternativeLayoutName && { alternativeLayoutName: context.alternativeLayoutName }),
|
|
262
|
+
...commonParams
|
|
557
263
|
};
|
|
558
264
|
}
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
layoutAttributeName: z.string().describe("The name of the attribute that defines the embedded layout structure"),
|
|
566
|
-
widgetId: z.string().describe("The ID of the existing widget to remove from the embedded layout")
|
|
567
|
-
},
|
|
568
|
-
annotations: { title: "Remove Widget from Embedded Layout" }
|
|
569
|
-
}, async ({ pageUID, containerWidgetId, layoutAttributeName, widgetId }) => {
|
|
570
|
-
debugLogWithTag('EMBEDDED_LAYOUT_REMOVE', `Starting remove widget from embedded layout: ${widgetId} from container ${containerWidgetId} in page ${pageUID}`);
|
|
265
|
+
}
|
|
266
|
+
function normalizeEmbeddedResponse(result, operation) {
|
|
267
|
+
const operationVerb = operation === "ADD" ? "added" : "removed";
|
|
268
|
+
return `Widget ${operationVerb} successfully`;
|
|
269
|
+
}
|
|
270
|
+
server.registerTool(TOOL_GET_EMBEDDED_LAYOUT, WIDGET_TOOL_DEFINITIONS[TOOL_GET_EMBEDDED_LAYOUT], async ({ context }) => {
|
|
571
271
|
try {
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
type: "REMOVE",
|
|
578
|
-
widgetId
|
|
579
|
-
}
|
|
580
|
-
};
|
|
581
|
-
debugLogWithTag('EMBEDDED_LAYOUT_REMOVE', `Request body: ${JSON.stringify(requestBody, null, 2)}`);
|
|
582
|
-
const result = await client.makeApiRequest('json/page/embeddedWidgetLayout', 'PATCH', undefined, requestBody);
|
|
583
|
-
debugLogWithTag('EMBEDDED_LAYOUT_REMOVE', `Successfully removed widget ${widgetId} from embedded layout`);
|
|
584
|
-
const response = {
|
|
585
|
-
operation: "REMOVE_EMBEDDED_WIDGET",
|
|
586
|
-
status: "SUCCESS",
|
|
587
|
-
pageUID,
|
|
588
|
-
containerWidgetId,
|
|
589
|
-
layoutAttributeName,
|
|
590
|
-
widgetId,
|
|
591
|
-
message: "Widget removed successfully from embedded layout"
|
|
592
|
-
};
|
|
272
|
+
debugLogWithTag('EMBEDDED_LAYOUT', `Getting embedded layout for ${context.type} context: ${JSON.stringify({ context, endpoint: determineEmbeddedApiEndpoint(context) })}`);
|
|
273
|
+
const endpoint = determineEmbeddedApiEndpoint(context);
|
|
274
|
+
const requestParams = buildEmbeddedRequestParams(context);
|
|
275
|
+
const result = await client.makeApiRequest(endpoint, 'GET', requestParams);
|
|
276
|
+
debugLogWithTag('EMBEDDED_LAYOUT', `Successfully retrieved embedded layout for ${context.type} context: ${JSON.stringify({ context, hasResult: !!result })}`);
|
|
593
277
|
return {
|
|
594
|
-
content: [{
|
|
278
|
+
content: [{
|
|
279
|
+
type: "text",
|
|
280
|
+
text: typeof result === 'string' ? result : JSON.stringify(result, null, 2)
|
|
281
|
+
}]
|
|
595
282
|
};
|
|
596
283
|
}
|
|
597
284
|
catch (error) {
|
|
598
|
-
debugLogWithTag('
|
|
599
|
-
const errorResponse = {
|
|
600
|
-
operation: "REMOVE_EMBEDDED_WIDGET",
|
|
601
|
-
status: "ERROR",
|
|
602
|
-
pageUID,
|
|
603
|
-
containerWidgetId,
|
|
604
|
-
layoutAttributeName,
|
|
605
|
-
widgetId,
|
|
606
|
-
error: error instanceof Error ? error.message : String(error),
|
|
607
|
-
message: "Failed to remove widget from embedded layout"
|
|
608
|
-
};
|
|
285
|
+
debugLogWithTag('EMBEDDED_LAYOUT', `Failed to get embedded layout for ${context.type} context: ${JSON.stringify({ context, error: error instanceof Error ? error.message : String(error) })}`);
|
|
609
286
|
return {
|
|
610
|
-
content: [{
|
|
287
|
+
content: [{
|
|
288
|
+
type: "text",
|
|
289
|
+
text: `Failed to get embedded layout: ${error instanceof Error ? error.message : String(error)}`
|
|
290
|
+
}],
|
|
611
291
|
isError: true
|
|
612
292
|
};
|
|
613
293
|
}
|
|
614
294
|
});
|
|
615
|
-
server.registerTool(
|
|
616
|
-
description: "Remove all empty rows from a page layout, effectively compacting the layout by keeping only rows that contain widgets. This operation automatically identifies and removes rows where all columns have no widgets while preserving the order and content of non-empty rows and maintaining all widget configurations and positions.",
|
|
617
|
-
inputSchema: {
|
|
618
|
-
pageUID: z.string().describe("The unique identifier (UID) of the page to compact the layout for")
|
|
619
|
-
},
|
|
620
|
-
annotations: { title: "Compact Page Layout" }
|
|
621
|
-
}, async ({ pageUID }) => {
|
|
622
|
-
debugLogWithTag('LAYOUT_MODIFY', `Starting compact layout operation for page ${pageUID}`);
|
|
295
|
+
server.registerTool(TOOL_ADD_WIDGET_TO_EMBEDDED_LAYOUT, WIDGET_TOOL_DEFINITIONS[TOOL_ADD_WIDGET_TO_EMBEDDED_LAYOUT], async ({ context, widgetType, position, configuration }) => {
|
|
623
296
|
try {
|
|
297
|
+
debugLogWithTag('EMBEDDED_LAYOUT_ADD', `Adding widget to ${context.type} embedded layout: ${JSON.stringify({ context, widgetType, position, hasConfiguration: !!configuration })}`);
|
|
298
|
+
const endpoint = determineEmbeddedApiEndpoint(context);
|
|
299
|
+
const requestParams = buildEmbeddedRequestParams(context);
|
|
300
|
+
const operationType = "ADD";
|
|
624
301
|
const requestBody = {
|
|
625
|
-
|
|
302
|
+
...requestParams,
|
|
626
303
|
operation: {
|
|
627
|
-
type:
|
|
304
|
+
type: operationType,
|
|
305
|
+
widgetType,
|
|
306
|
+
position,
|
|
307
|
+
...(configuration && Object.keys(configuration).length > 0 && { configuration })
|
|
628
308
|
}
|
|
629
309
|
};
|
|
630
|
-
debugLogWithTag('
|
|
631
|
-
const result = await client.makeApiRequest(
|
|
632
|
-
debugLogWithTag('
|
|
633
|
-
let emptyRowsRemoved = 0;
|
|
634
|
-
try {
|
|
635
|
-
const originalLayoutResult = await client.makeApiRequest('json/pageLayout', 'GET', { pageUID });
|
|
636
|
-
const originalLayout = JSON.parse(originalLayoutResult.result || '{}');
|
|
637
|
-
const originalRowCount = originalLayout.rows ? originalLayout.rows.length : 0;
|
|
638
|
-
const compactedLayoutString = result.result;
|
|
639
|
-
const compactedLayout = JSON.parse(compactedLayoutString);
|
|
640
|
-
const compactedRowCount = compactedLayout.rows ? compactedLayout.rows.length : 0;
|
|
641
|
-
emptyRowsRemoved = Math.max(0, originalRowCount - compactedRowCount);
|
|
642
|
-
}
|
|
643
|
-
catch (parseError) {
|
|
644
|
-
debugLogWithTag('LAYOUT_MODIFY', `Could not calculate compaction statistics: ${parseError}`);
|
|
645
|
-
}
|
|
646
|
-
const response = {
|
|
647
|
-
operation: "COMPACT_LAYOUT",
|
|
648
|
-
status: "SUCCESS",
|
|
649
|
-
pageUID,
|
|
650
|
-
emptyRowsRemoved,
|
|
651
|
-
message: emptyRowsRemoved > 0
|
|
652
|
-
? `Layout compacted successfully - removed ${emptyRowsRemoved} empty row${emptyRowsRemoved === 1 ? '' : 's'}`
|
|
653
|
-
: "Layout was already compact - no empty rows found"
|
|
654
|
-
};
|
|
310
|
+
debugLogWithTag('EMBEDDED_LAYOUT_ADD', `Sending ADD request to ${endpoint}: ${JSON.stringify({ context, operationType, requestBodyKeys: Object.keys(requestBody) })}`);
|
|
311
|
+
const result = await client.makeApiRequest(endpoint, 'PATCH', undefined, requestBody);
|
|
312
|
+
debugLogWithTag('EMBEDDED_LAYOUT_ADD', `Successfully added widget to ${context.type} embedded layout: ${JSON.stringify({ context, widgetType, success: true })}`);
|
|
655
313
|
return {
|
|
656
|
-
content: [{
|
|
314
|
+
content: [{
|
|
315
|
+
type: "text",
|
|
316
|
+
text: normalizeEmbeddedResponse(result, "ADD")
|
|
317
|
+
}]
|
|
657
318
|
};
|
|
658
319
|
}
|
|
659
320
|
catch (error) {
|
|
660
|
-
debugLogWithTag('
|
|
661
|
-
const errorResponse = {
|
|
662
|
-
operation: "COMPACT_LAYOUT",
|
|
663
|
-
status: "ERROR",
|
|
664
|
-
pageUID,
|
|
665
|
-
error: error instanceof Error ? error.message : String(error),
|
|
666
|
-
message: "Failed to compact layout"
|
|
667
|
-
};
|
|
321
|
+
debugLogWithTag('EMBEDDED_LAYOUT_ADD', `Failed to add widget to ${context.type} embedded layout: ${JSON.stringify({ context, widgetType, error: error instanceof Error ? error.message : String(error) })}`);
|
|
668
322
|
return {
|
|
669
|
-
content: [{
|
|
323
|
+
content: [{
|
|
324
|
+
type: "text",
|
|
325
|
+
text: `Failed to add widget: ${error instanceof Error ? error.message : String(error)}`
|
|
326
|
+
}],
|
|
670
327
|
isError: true
|
|
671
328
|
};
|
|
672
329
|
}
|
|
673
330
|
});
|
|
674
|
-
server.registerTool(
|
|
675
|
-
description: "Create a new row with specific column layout in a page layout.\n\n⭐ ESSENTIAL FOR MULTI-COLUMN LAYOUTS ⭐\nThis is the ONLY way to create multi-column structures. Widget placement alone cannot create columns.\n\nCOMMON WORKFLOW:\n1. Use this tool to create desired column structure (e.g., [6,6] for side-by-side)\n2. Use cplace_add_widget_to_layout to place widgets in the columns\n3. Use cplace_compact_page_layout to remove any empty rows\n\nROW INSERTION BEHAVIOR:\n- rowIndex < existing rows: Inserts and shifts others down\n- rowIndex >= existing rows: Appends at end\n\nCOLUMN PROPORTIONS (must sum to 12):\n- [12]: Single full-width column\n- [6, 6]: Two equal columns (most common for side-by-side)\n- [4, 4, 4]: Three equal columns\n- [3, 9]: Sidebar + main content\n- [2, 8, 2]: Content with sidebars",
|
|
676
|
-
inputSchema: {
|
|
677
|
-
pageUID: z.string().describe("The unique identifier (UID) of the page to add the row to"),
|
|
678
|
-
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."),
|
|
679
|
-
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)")
|
|
680
|
-
},
|
|
681
|
-
annotations: { title: "Add Row to Page Layout" }
|
|
682
|
-
}, async ({ pageUID, rowIndex, columnProportions }) => {
|
|
683
|
-
debugLogWithTag('LAYOUT_MODIFY', `Starting add row operation: row ${rowIndex} with proportions ${JSON.stringify(columnProportions)} to page ${pageUID}`);
|
|
331
|
+
server.registerTool(TOOL_REMOVE_WIDGET_FROM_EMBEDDED_LAYOUT, WIDGET_TOOL_DEFINITIONS[TOOL_REMOVE_WIDGET_FROM_EMBEDDED_LAYOUT], async ({ context, widgetId }) => {
|
|
684
332
|
try {
|
|
333
|
+
debugLogWithTag('EMBEDDED_LAYOUT_REMOVE', `Removing widget from ${context.type} embedded layout: ${JSON.stringify({ context, widgetId })}`);
|
|
334
|
+
const endpoint = determineEmbeddedApiEndpoint(context);
|
|
335
|
+
const requestParams = buildEmbeddedRequestParams(context);
|
|
336
|
+
const operationType = "REMOVE";
|
|
685
337
|
const requestBody = {
|
|
686
|
-
|
|
338
|
+
...requestParams,
|
|
687
339
|
operation: {
|
|
688
|
-
type:
|
|
689
|
-
|
|
690
|
-
columnProportions
|
|
691
|
-
}
|
|
692
|
-
};
|
|
693
|
-
debugLogWithTag('LAYOUT_MODIFY', `Request body: ${JSON.stringify(requestBody, null, 2)}`);
|
|
694
|
-
const result = await client.makeApiRequest('json/pageLayout', 'PATCH', undefined, requestBody);
|
|
695
|
-
debugLogWithTag('LAYOUT_MODIFY', `Successfully added row ${rowIndex} with ${columnProportions.length} columns to page ${pageUID}`);
|
|
696
|
-
const columnsCreated = columnProportions.length;
|
|
697
|
-
const columnSum = columnProportions.reduce((sum, prop) => sum + prop, 0);
|
|
698
|
-
let insertionType = "appended";
|
|
699
|
-
try {
|
|
700
|
-
const layoutString = result.result;
|
|
701
|
-
const layout = JSON.parse(layoutString);
|
|
702
|
-
if (layout.rows && layout.rows.length > rowIndex + 1) {
|
|
703
|
-
insertionType = "inserted";
|
|
340
|
+
type: operationType,
|
|
341
|
+
widgetId
|
|
704
342
|
}
|
|
705
|
-
}
|
|
706
|
-
catch (parseError) {
|
|
707
|
-
debugLogWithTag('LAYOUT_MODIFY', `Could not determine insertion type: ${parseError}`);
|
|
708
|
-
}
|
|
709
|
-
const response = {
|
|
710
|
-
operation: "ADD_ROW",
|
|
711
|
-
status: "SUCCESS",
|
|
712
|
-
pageUID,
|
|
713
|
-
rowIndex,
|
|
714
|
-
columnProportions,
|
|
715
|
-
columnsCreated,
|
|
716
|
-
insertionType,
|
|
717
|
-
message: insertionType === "inserted"
|
|
718
|
-
? `Row added successfully at index ${rowIndex} with ${columnsCreated} column${columnsCreated === 1 ? '' : 's'} [${columnProportions.join(',')}]`
|
|
719
|
-
: `Row added successfully at end with ${columnsCreated} column${columnsCreated === 1 ? '' : 's'} [${columnProportions.join(',')}]`
|
|
720
343
|
};
|
|
344
|
+
debugLogWithTag('EMBEDDED_LAYOUT_REMOVE', `Sending REMOVE request to ${endpoint}: ${JSON.stringify({ context, operationType, widgetId })}`);
|
|
345
|
+
const result = await client.makeApiRequest(endpoint, 'PATCH', undefined, requestBody);
|
|
346
|
+
debugLogWithTag('EMBEDDED_LAYOUT_REMOVE', `Successfully removed widget from ${context.type} embedded layout: ${JSON.stringify({ context, widgetId, success: true })}`);
|
|
721
347
|
return {
|
|
722
|
-
content: [{
|
|
348
|
+
content: [{
|
|
349
|
+
type: "text",
|
|
350
|
+
text: normalizeEmbeddedResponse(result, "REMOVE")
|
|
351
|
+
}]
|
|
723
352
|
};
|
|
724
353
|
}
|
|
725
354
|
catch (error) {
|
|
726
|
-
debugLogWithTag('
|
|
727
|
-
const errorResponse = {
|
|
728
|
-
operation: "ADD_ROW",
|
|
729
|
-
status: "ERROR",
|
|
730
|
-
pageUID,
|
|
731
|
-
rowIndex,
|
|
732
|
-
columnProportions,
|
|
733
|
-
error: error instanceof Error ? error.message : String(error),
|
|
734
|
-
message: "Failed to add row"
|
|
735
|
-
};
|
|
355
|
+
debugLogWithTag('EMBEDDED_LAYOUT_REMOVE', `Failed to remove widget from ${context.type} embedded layout: ${JSON.stringify({ context, widgetId, error: error instanceof Error ? error.message : String(error) })}`);
|
|
736
356
|
return {
|
|
737
|
-
content: [{
|
|
357
|
+
content: [{
|
|
358
|
+
type: "text",
|
|
359
|
+
text: `Failed to remove widget: ${error instanceof Error ? error.message : String(error)}`
|
|
360
|
+
}],
|
|
738
361
|
isError: true
|
|
739
362
|
};
|
|
740
363
|
}
|