snow-flow 2.10.0 → 3.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.
Files changed (64) hide show
  1. package/.mcp.json +13 -141
  2. package/.mcp.json.template +11 -25
  3. package/README.md +18 -0
  4. package/claude-flow +81 -0
  5. package/claude-flow.bat +18 -0
  6. package/claude-flow.config.json +20 -0
  7. package/claude-flow.ps1 +24 -0
  8. package/dist/agents/index.d.ts +3 -10
  9. package/dist/agents/index.js +10 -50
  10. package/dist/agents/queen-agent.d.ts +0 -2
  11. package/dist/agents/queen-agent.js +25 -42
  12. package/dist/cli.js +1 -1
  13. package/dist/mcp/servicenow-automation-mcp.js +10 -10
  14. package/dist/mcp/servicenow-deployment-mcp.js +1050 -169
  15. package/dist/mcp/servicenow-development-assistant-mcp.js +13 -65
  16. package/dist/mcp/servicenow-integration-mcp.js +10 -10
  17. package/dist/mcp/servicenow-machine-learning-mcp.js +15 -15
  18. package/dist/mcp/servicenow-operations-mcp.js +23 -23
  19. package/dist/mcp/servicenow-platform-development-mcp.js +9 -9
  20. package/dist/mcp/servicenow-reporting-analytics-mcp.js +11 -11
  21. package/dist/mcp/servicenow-security-compliance-mcp.js +11 -11
  22. package/dist/mcp/servicenow-update-set-mcp.js +9 -9
  23. package/dist/mcp/shared/reliable-memory-manager.d.ts +78 -0
  24. package/dist/mcp/shared/reliable-memory-manager.js +268 -0
  25. package/dist/mcp/snow-flow-mcp.js +341 -87
  26. package/dist/queen/agent-factory.d.ts +4 -2
  27. package/dist/queen/agent-factory.js +72 -25
  28. package/dist/services/tensorflow-ml-service.d.ts +105 -0
  29. package/dist/services/tensorflow-ml-service.js +456 -0
  30. package/dist/services/widget-deployment-service.d.ts +107 -0
  31. package/dist/services/widget-deployment-service.js +332 -0
  32. package/dist/utils/file-storage-fallback.d.ts +62 -0
  33. package/dist/utils/file-storage-fallback.js +289 -0
  34. package/dist/utils/mcp-server-manager.js +4 -7
  35. package/dist/utils/mcp-singleton-enforcer.d.ts +7 -1
  36. package/dist/utils/mcp-singleton-enforcer.js +28 -4
  37. package/dist/utils/mcp-timeout-fix.d.ts +10 -1
  38. package/dist/utils/mcp-timeout-fix.js +80 -6
  39. package/memory/agents/README.md +31 -0
  40. package/memory/claude-flow-data.json +1 -1
  41. package/memory/sessions/README.md +1 -1
  42. package/package.json +4 -2
  43. package/src/agents/README.md +192 -0
  44. package/src/health/README.md +161 -0
  45. package/src/memory/README.md +240 -0
  46. package/src/queen/README.md +403 -0
  47. package/src/schemas/deployment.schema.json +58 -0
  48. package/src/schemas/flow.schema.json +79 -0
  49. package/src/schemas/widget.schema.json +72 -0
  50. package/src/templates/base/application.template.json +45 -0
  51. package/src/templates/base/business_rule.template.json +33 -0
  52. package/src/templates/base/script_include.template.json +18 -0
  53. package/src/templates/base/table.template.json +64 -0
  54. package/src/templates/base/widget.template.json +25 -0
  55. package/src/templates/patterns/composite.incident-management.template.json +140 -0
  56. package/src/templates/patterns/widget.dashboard.template.json +238 -0
  57. package/src/templates/patterns/widget.datatable.template.json +292 -0
  58. package/dist/mcp/servicenow-graph-memory-mcp.js +0 -728
  59. package/servicenow/widgets/openai_incident_classifier/client_controller.js +0 -284
  60. package/servicenow/widgets/openai_incident_classifier/server_script.js +0 -314
  61. package/servicenow/widgets/openai_incident_classifier/style.css +0 -354
  62. package/servicenow/widgets/openai_incident_classifier/template.html +0 -167
  63. package/servicenow/widgets/openai_incident_classifier/widget.json +0 -86
  64. package/test-ml-improvements.sh +0 -76
@@ -0,0 +1,238 @@
1
+ {
2
+ "type": "widget",
3
+ "name": "Dashboard Widget Template",
4
+ "description": "Template for creating dashboard widgets with charts and metrics",
5
+ "category": "patterns/dashboard",
6
+ "config": {
7
+ "name": "{{WIDGET_NAME|custom_dashboard}}",
8
+ "id": "{{WIDGET_ID|custom_dashboard}}",
9
+ "instance_id": "{{INSTANCE_ID|dashboard_}}",
10
+ "data": {
11
+ "title": "{{WIDGET_TITLE|Dashboard}}",
12
+ "short_description": "{{WIDGET_DESCRIPTION|Real-time dashboard with key metrics}}",
13
+ "roles": "{{WIDGET_ROLES|}}"
14
+ },
15
+ "options": [
16
+ {
17
+ "name": "refresh_interval",
18
+ "section": "Behavior",
19
+ "label": "Refresh Interval (seconds)",
20
+ "type": "integer",
21
+ "value": "30",
22
+ "help": "How often to refresh the dashboard data"
23
+ },
24
+ {
25
+ "name": "color_scheme",
26
+ "section": "Appearance",
27
+ "label": "Color Scheme",
28
+ "type": "choice",
29
+ "value": "default",
30
+ "choices": [
31
+ {"label": "Default", "value": "default"},
32
+ {"label": "Dark", "value": "dark"},
33
+ {"label": "High Contrast", "value": "high-contrast"}
34
+ ]
35
+ },
36
+ {
37
+ "name": "chart_type",
38
+ "section": "Appearance",
39
+ "label": "Default Chart Type",
40
+ "type": "choice",
41
+ "value": "bar",
42
+ "choices": [
43
+ {"label": "Bar Chart", "value": "bar"},
44
+ {"label": "Line Chart", "value": "line"},
45
+ {"label": "Pie Chart", "value": "pie"},
46
+ {"label": "Donut Chart", "value": "donut"}
47
+ ]
48
+ }
49
+ ],
50
+ "html": [
51
+ "<div class=\"dashboard-widget\" ng-class=\"{'dark-theme': options.color_scheme === 'dark', 'high-contrast': options.color_scheme === 'high-contrast'}\">",
52
+ " <div class=\"dashboard-header\">",
53
+ " <h2 class=\"dashboard-title\">{{data.title}}</h2>",
54
+ " <div class=\"dashboard-controls\">",
55
+ " <button class=\"btn btn-sm\" ng-click=\"c.refresh()\" title=\"Refresh\">",
56
+ " <i class=\"fa fa-refresh\" ng-class=\"{'fa-spin': c.loading}\"></i>",
57
+ " </button>",
58
+ " <button class=\"btn btn-sm\" ng-click=\"c.toggleFullscreen()\" title=\"Fullscreen\">",
59
+ " <i class=\"fa\" ng-class=\"c.fullscreen ? 'fa-compress' : 'fa-expand'\"></i>",
60
+ " </button>",
61
+ " </div>",
62
+ " </div>",
63
+ " ",
64
+ " <div class=\"dashboard-metrics\" ng-if=\"!c.loading\">",
65
+ " <div class=\"metric-card\" ng-repeat=\"metric in c.metrics\">",
66
+ " <div class=\"metric-value\" ng-style=\"{'color': metric.color}\">{{metric.value}}</div>",
67
+ " <div class=\"metric-label\">{{metric.label}}</div>",
68
+ " <div class=\"metric-trend\" ng-if=\"metric.trend\">",
69
+ " <i class=\"fa\" ng-class=\"metric.trend > 0 ? 'fa-arrow-up text-success' : 'fa-arrow-down text-danger'\"></i>",
70
+ " <span>{{metric.trend}}%</span>",
71
+ " </div>",
72
+ " </div>",
73
+ " </div>",
74
+ " ",
75
+ " <div class=\"dashboard-charts\" ng-if=\"!c.loading\">",
76
+ " <div class=\"chart-container\" ng-repeat=\"chart in c.charts\">",
77
+ " <h3>{{chart.title}}</h3>",
78
+ " <canvas id=\"chart-{{$index}}\" width=\"400\" height=\"200\"></canvas>",
79
+ " </div>",
80
+ " </div>",
81
+ " ",
82
+ " <div class=\"dashboard-loading\" ng-if=\"c.loading\">",
83
+ " <i class=\"fa fa-spinner fa-spin fa-3x\"></i>",
84
+ " <p>Loading dashboard data...</p>",
85
+ " </div>",
86
+ "</div>"
87
+ ],
88
+ "css": [
89
+ ".dashboard-widget {",
90
+ " padding: 20px;",
91
+ " background: #fff;",
92
+ " border-radius: 8px;",
93
+ " box-shadow: 0 2px 4px rgba(0,0,0,0.1);",
94
+ "}",
95
+ "",
96
+ ".dashboard-widget.dark-theme {",
97
+ " background: #1a1a1a;",
98
+ " color: #fff;",
99
+ "}",
100
+ "",
101
+ ".dashboard-widget.high-contrast {",
102
+ " border: 2px solid #000;",
103
+ "}",
104
+ "",
105
+ ".dashboard-header {",
106
+ " display: flex;",
107
+ " justify-content: space-between;",
108
+ " align-items: center;",
109
+ " margin-bottom: 20px;",
110
+ "}",
111
+ "",
112
+ ".dashboard-title {",
113
+ " margin: 0;",
114
+ " font-size: 24px;",
115
+ " font-weight: 600;",
116
+ "}",
117
+ "",
118
+ ".dashboard-controls button {",
119
+ " margin-left: 10px;",
120
+ "}",
121
+ "",
122
+ ".dashboard-metrics {",
123
+ " display: grid;",
124
+ " grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));",
125
+ " gap: 20px;",
126
+ " margin-bottom: 30px;",
127
+ "}",
128
+ "",
129
+ ".metric-card {",
130
+ " background: #f5f5f5;",
131
+ " padding: 20px;",
132
+ " border-radius: 8px;",
133
+ " text-align: center;",
134
+ " transition: transform 0.2s;",
135
+ "}",
136
+ "",
137
+ ".dark-theme .metric-card {",
138
+ " background: #2a2a2a;",
139
+ "}",
140
+ "",
141
+ ".metric-card:hover {",
142
+ " transform: translateY(-2px);",
143
+ " box-shadow: 0 4px 8px rgba(0,0,0,0.1);",
144
+ "}",
145
+ "",
146
+ ".metric-value {",
147
+ " font-size: 36px;",
148
+ " font-weight: bold;",
149
+ " margin-bottom: 5px;",
150
+ "}",
151
+ "",
152
+ ".metric-label {",
153
+ " font-size: 14px;",
154
+ " color: #666;",
155
+ " text-transform: uppercase;",
156
+ "}",
157
+ "",
158
+ ".dark-theme .metric-label {",
159
+ " color: #999;",
160
+ "}",
161
+ "",
162
+ ".metric-trend {",
163
+ " margin-top: 10px;",
164
+ " font-size: 14px;",
165
+ "}",
166
+ "",
167
+ ".dashboard-charts {",
168
+ " display: grid;",
169
+ " grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));",
170
+ " gap: 30px;",
171
+ "}",
172
+ "",
173
+ ".chart-container {",
174
+ " background: #f9f9f9;",
175
+ " padding: 20px;",
176
+ " border-radius: 8px;",
177
+ "}",
178
+ "",
179
+ ".dark-theme .chart-container {",
180
+ " background: #2a2a2a;",
181
+ "}",
182
+ "",
183
+ ".dashboard-loading {",
184
+ " text-align: center;",
185
+ " padding: 60px 20px;",
186
+ " color: #666;",
187
+ "}",
188
+ "",
189
+ ".dark-theme .dashboard-loading {",
190
+ " color: #999;",
191
+ "}",
192
+ "",
193
+ "@media (max-width: 768px) {",
194
+ " .dashboard-metrics {",
195
+ " grid-template-columns: 1fr;",
196
+ " }",
197
+ " .dashboard-charts {",
198
+ " grid-template-columns: 1fr;",
199
+ " }",
200
+ "}"
201
+ ],
202
+ "client_controller": "{{CLIENT_CONTROLLER|dashboard_controller}}",
203
+ "script": "{{SERVER_SCRIPT|dashboard_server_script}}",
204
+ "link_function": "{{LINK_FUNCTION|}}",
205
+ "demo_data": {
206
+ "metrics": [
207
+ {"label": "Total Items", "value": "1,234", "color": "#007bff", "trend": 12},
208
+ {"label": "Active Users", "value": "456", "color": "#28a745", "trend": 5},
209
+ {"label": "Pending Tasks", "value": "78", "color": "#ffc107", "trend": -3},
210
+ {"label": "Completed", "value": "89%", "color": "#17a2b8", "trend": 2}
211
+ ],
212
+ "charts": [
213
+ {
214
+ "title": "Weekly Trend",
215
+ "type": "line",
216
+ "data": {
217
+ "labels": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
218
+ "datasets": [{
219
+ "label": "Items",
220
+ "data": [65, 59, 80, 81, 56, 55, 40]
221
+ }]
222
+ }
223
+ }
224
+ ]
225
+ }
226
+ },
227
+ "variables": {
228
+ "WIDGET_NAME": "custom_dashboard",
229
+ "WIDGET_ID": "custom_dashboard",
230
+ "INSTANCE_ID": "dashboard_",
231
+ "WIDGET_TITLE": "Dashboard",
232
+ "WIDGET_DESCRIPTION": "Real-time dashboard with key metrics",
233
+ "WIDGET_ROLES": "",
234
+ "CLIENT_CONTROLLER": "function($scope, $http, $timeout) {\n var c = this;\n \n c.loading = true;\n c.fullscreen = false;\n c.metrics = [];\n c.charts = [];\n \n c.refresh = function() {\n c.loading = true;\n c.server.get({\n action: 'get_dashboard_data'\n }).then(function(response) {\n c.metrics = response.data.metrics || [];\n c.charts = response.data.charts || [];\n c.loading = false;\n \n // Render charts\n $timeout(function() {\n c.renderCharts();\n }, 100);\n });\n };\n \n c.renderCharts = function() {\n c.charts.forEach(function(chart, index) {\n var ctx = document.getElementById('chart-' + index);\n if (ctx) {\n new Chart(ctx.getContext('2d'), {\n type: c.options.chart_type || chart.type || 'bar',\n data: chart.data,\n options: {\n responsive: true,\n maintainAspectRatio: false\n }\n });\n }\n });\n };\n \n c.toggleFullscreen = function() {\n c.fullscreen = !c.fullscreen;\n // Implement fullscreen logic\n };\n \n // Initial load\n c.refresh();\n \n // Auto-refresh\n if (c.options.refresh_interval > 0) {\n var refreshTimer = $timeout(function refresh() {\n c.refresh();\n refreshTimer = $timeout(refresh, c.options.refresh_interval * 1000);\n }, c.options.refresh_interval * 1000);\n \n $scope.$on('$destroy', function() {\n $timeout.cancel(refreshTimer);\n });\n }\n}",
235
+ "SERVER_SCRIPT": "(function() {\n try {\n data.metrics = [];\n data.charts = [];\n gs.log('Dashboard widget server script started', 'dashboard_widget');\n \n if (input && input.action === 'get_dashboard_data') {\n // Example: Fetch incident metrics\n var gr = new GlideRecord('incident');\n gr.addQuery('active', 'true'); // ✅ FIXED: Use string instead of boolean\n gr.query();\n \n var totalCount = gr.getRowCount();\n gs.log('Found ' + totalCount + ' active incidents', 'dashboard_widget');\n \n // Get priority breakdown\n var priorities = {};\n gr = new GlideRecord('incident');\n gr.addQuery('active', 'true'); // ✅ FIXED: Use string instead of boolean\n gr.query();\n \n while (gr.next()) {\n var priority = gr.getValue('priority') || 'undefined';\n priorities[priority] = (priorities[priority] || 0) + 1;\n }\n \n // Build metrics\n data.metrics = [\n {\n label: 'Total Incidents',\n value: totalCount.toString(),\n color: '#007bff',\n trend: 5\n },\n {\n label: 'High Priority',\n value: (priorities['1'] || 0).toString(),\n color: '#dc3545',\n trend: -2\n },\n {\n label: 'Medium Priority',\n value: (priorities['2'] || 0).toString(),\n color: '#ffc107',\n trend: 3\n },\n {\n label: 'Low Priority',\n value: (priorities['3'] || 0).toString(),\n color: '#28a745',\n trend: 1\n }\n ];\n \n // Build chart data\n data.charts = [\n {\n title: 'Incidents by Priority',\n type: 'bar',\n data: {\n labels: ['High', 'Medium', 'Low'],\n datasets: [{\n label: 'Incidents',\n data: [\n priorities['1'] || 0,\n priorities['2'] || 0,\n priorities['3'] || 0\n ],\n backgroundColor: ['#dc3545', '#ffc107', '#28a745']\n }]\n }\n }\n ];\n \n gs.log('Dashboard data prepared successfully', 'dashboard_widget');\n }\n } catch (error) {\n gs.error('Dashboard widget error: ' + error.message, 'dashboard_widget');\n data.error = 'Error loading dashboard: ' + error.message;\n data.success = false;\n }\n})()",
236
+ "LINK_FUNCTION": ""
237
+ }
238
+ }
@@ -0,0 +1,292 @@
1
+ {
2
+ "type": "widget",
3
+ "name": "Data Table Widget Template",
4
+ "description": "Template for creating data table widgets with sorting, filtering, and pagination",
5
+ "category": "patterns/datatable",
6
+ "config": {
7
+ "name": "{{WIDGET_NAME|data_table}}",
8
+ "id": "{{WIDGET_ID|data_table}}",
9
+ "instance_id": "{{INSTANCE_ID|table_}}",
10
+ "data": {
11
+ "title": "{{WIDGET_TITLE|Data Table}}",
12
+ "short_description": "{{WIDGET_DESCRIPTION|Interactive data table with advanced features}}",
13
+ "roles": "{{WIDGET_ROLES|}}"
14
+ },
15
+ "options": [
16
+ {
17
+ "name": "table_name",
18
+ "section": "Data",
19
+ "label": "Table",
20
+ "type": "reference",
21
+ "value": "{{TABLE_NAME|incident}}",
22
+ "ed": "sys_db_object",
23
+ "help": "Select the table to display data from"
24
+ },
25
+ {
26
+ "name": "max_records",
27
+ "section": "Data",
28
+ "label": "Maximum Records",
29
+ "type": "integer",
30
+ "value": "100",
31
+ "help": "Maximum number of records to display"
32
+ },
33
+ {
34
+ "name": "enable_filter",
35
+ "section": "Features",
36
+ "label": "Enable Filtering",
37
+ "type": "boolean",
38
+ "value": "true"
39
+ },
40
+ {
41
+ "name": "enable_export",
42
+ "section": "Features",
43
+ "label": "Enable Export",
44
+ "type": "boolean",
45
+ "value": "true"
46
+ },
47
+ {
48
+ "name": "enable_inline_edit",
49
+ "section": "Features",
50
+ "label": "Enable Inline Editing",
51
+ "type": "boolean",
52
+ "value": "false"
53
+ },
54
+ {
55
+ "name": "row_actions",
56
+ "section": "Features",
57
+ "label": "Row Actions",
58
+ "type": "json",
59
+ "value": "[{\"label\":\"View\",\"action\":\"view\",\"icon\":\"eye\"},{\"label\":\"Edit\",\"action\":\"edit\",\"icon\":\"pencil\"}]"
60
+ }
61
+ ],
62
+ "html": [
63
+ "<div class=\"data-table-widget\">",
64
+ " <div class=\"table-header\">",
65
+ " <h2 class=\"table-title\">{{data.title}}</h2>",
66
+ " <div class=\"table-controls\">",
67
+ " <div class=\"search-box\" ng-if=\"options.enable_filter\">",
68
+ " <i class=\"fa fa-search\"></i>",
69
+ " <input type=\"text\" ng-model=\"c.searchTerm\" ng-change=\"c.filterData()\" placeholder=\"Search...\">",
70
+ " </div>",
71
+ " <button class=\"btn btn-primary\" ng-if=\"options.enable_export\" ng-click=\"c.exportData()\">",
72
+ " <i class=\"fa fa-download\"></i> Export",
73
+ " </button>",
74
+ " </div>",
75
+ " </div>",
76
+ " ",
77
+ " <div class=\"table-container\" ng-if=\"!c.loading\">",
78
+ " <table class=\"table table-striped table-hover\">",
79
+ " <thead>",
80
+ " <tr>",
81
+ " <th ng-repeat=\"column in c.columns\" ng-click=\"c.sort(column.field)\" class=\"sortable\">",
82
+ " {{column.label}}",
83
+ " <i class=\"fa fa-sort\" ng-if=\"c.sortField !== column.field\"></i>",
84
+ " <i class=\"fa fa-sort-asc\" ng-if=\"c.sortField === column.field && c.sortDirection === 'asc'\"></i>",
85
+ " <i class=\"fa fa-sort-desc\" ng-if=\"c.sortField === column.field && c.sortDirection === 'desc'\"></i>",
86
+ " </th>",
87
+ " <th ng-if=\"c.rowActions.length > 0\">Actions</th>",
88
+ " </tr>",
89
+ " </thead>",
90
+ " <tbody>",
91
+ " <tr ng-repeat=\"row in c.displayData\">",
92
+ " <td ng-repeat=\"column in c.columns\">",
93
+ " <span ng-if=\"!c.isEditing(row, column)\" ng-click=\"c.startEdit(row, column)\">",
94
+ " {{c.getCellValue(row, column)}}",
95
+ " </span>",
96
+ " <input ng-if=\"c.isEditing(row, column)\" ",
97
+ " type=\"text\" ",
98
+ " ng-model=\"row[column.field]\" ",
99
+ " ng-blur=\"c.saveEdit(row, column)\"",
100
+ " ng-keypress=\"c.handleEditKeypress($event, row, column)\">",
101
+ " </td>",
102
+ " <td ng-if=\"c.rowActions.length > 0\" class=\"actions-cell\">",
103
+ " <button ng-repeat=\"action in c.rowActions\" ",
104
+ " class=\"btn btn-sm btn-default\" ",
105
+ " ng-click=\"c.performAction(action, row)\"",
106
+ " title=\"{{action.label}}\">",
107
+ " <i class=\"fa fa-{{action.icon}}\"></i>",
108
+ " </button>",
109
+ " </td>",
110
+ " </tr>",
111
+ " </tbody>",
112
+ " </table>",
113
+ " </div>",
114
+ " ",
115
+ " <div class=\"table-pagination\" ng-if=\"c.totalPages > 1\">",
116
+ " <button class=\"btn btn-sm\" ng-click=\"c.previousPage()\" ng-disabled=\"c.currentPage === 1\">",
117
+ " <i class=\"fa fa-chevron-left\"></i>",
118
+ " </button>",
119
+ " <span class=\"page-info\">Page {{c.currentPage}} of {{c.totalPages}}</span>",
120
+ " <button class=\"btn btn-sm\" ng-click=\"c.nextPage()\" ng-disabled=\"c.currentPage === c.totalPages\">",
121
+ " <i class=\"fa fa-chevron-right\"></i>",
122
+ " </button>",
123
+ " </div>",
124
+ " ",
125
+ " <div class=\"table-loading\" ng-if=\"c.loading\">",
126
+ " <i class=\"fa fa-spinner fa-spin fa-3x\"></i>",
127
+ " <p>Loading data...</p>",
128
+ " </div>",
129
+ "</div>"
130
+ ],
131
+ "css": [
132
+ ".data-table-widget {",
133
+ " background: #fff;",
134
+ " border-radius: 8px;",
135
+ " box-shadow: 0 2px 4px rgba(0,0,0,0.1);",
136
+ " overflow: hidden;",
137
+ "}",
138
+ "",
139
+ ".table-header {",
140
+ " display: flex;",
141
+ " justify-content: space-between;",
142
+ " align-items: center;",
143
+ " padding: 20px;",
144
+ " border-bottom: 1px solid #e0e0e0;",
145
+ "}",
146
+ "",
147
+ ".table-title {",
148
+ " margin: 0;",
149
+ " font-size: 20px;",
150
+ " font-weight: 600;",
151
+ "}",
152
+ "",
153
+ ".table-controls {",
154
+ " display: flex;",
155
+ " align-items: center;",
156
+ " gap: 15px;",
157
+ "}",
158
+ "",
159
+ ".search-box {",
160
+ " position: relative;",
161
+ " display: flex;",
162
+ " align-items: center;",
163
+ "}",
164
+ "",
165
+ ".search-box i {",
166
+ " position: absolute;",
167
+ " left: 10px;",
168
+ " color: #666;",
169
+ "}",
170
+ "",
171
+ ".search-box input {",
172
+ " padding: 8px 8px 8px 35px;",
173
+ " border: 1px solid #ddd;",
174
+ " border-radius: 4px;",
175
+ " width: 250px;",
176
+ "}",
177
+ "",
178
+ ".table-container {",
179
+ " overflow-x: auto;",
180
+ "}",
181
+ "",
182
+ "table {",
183
+ " width: 100%;",
184
+ " border-collapse: collapse;",
185
+ "}",
186
+ "",
187
+ "th {",
188
+ " background: #f5f5f5;",
189
+ " padding: 12px;",
190
+ " text-align: left;",
191
+ " font-weight: 600;",
192
+ " color: #333;",
193
+ " white-space: nowrap;",
194
+ "}",
195
+ "",
196
+ "th.sortable {",
197
+ " cursor: pointer;",
198
+ " user-select: none;",
199
+ "}",
200
+ "",
201
+ "th.sortable:hover {",
202
+ " background: #e8e8e8;",
203
+ "}",
204
+ "",
205
+ "th i {",
206
+ " margin-left: 5px;",
207
+ " color: #999;",
208
+ "}",
209
+ "",
210
+ "td {",
211
+ " padding: 12px;",
212
+ " border-bottom: 1px solid #f0f0f0;",
213
+ "}",
214
+ "",
215
+ "td input {",
216
+ " width: 100%;",
217
+ " padding: 4px 8px;",
218
+ " border: 1px solid #007bff;",
219
+ " border-radius: 4px;",
220
+ "}",
221
+ "",
222
+ "tr:hover {",
223
+ " background: #f9f9f9;",
224
+ "}",
225
+ "",
226
+ ".actions-cell {",
227
+ " white-space: nowrap;",
228
+ "}",
229
+ "",
230
+ ".actions-cell button {",
231
+ " margin-right: 5px;",
232
+ "}",
233
+ "",
234
+ ".table-pagination {",
235
+ " display: flex;",
236
+ " justify-content: center;",
237
+ " align-items: center;",
238
+ " padding: 20px;",
239
+ " gap: 15px;",
240
+ " border-top: 1px solid #e0e0e0;",
241
+ "}",
242
+ "",
243
+ ".page-info {",
244
+ " color: #666;",
245
+ "}",
246
+ "",
247
+ ".table-loading {",
248
+ " text-align: center;",
249
+ " padding: 60px 20px;",
250
+ " color: #666;",
251
+ "}",
252
+ "",
253
+ "@media (max-width: 768px) {",
254
+ " .table-header {",
255
+ " flex-direction: column;",
256
+ " align-items: flex-start;",
257
+ " gap: 15px;",
258
+ " }",
259
+ " ",
260
+ " .search-box input {",
261
+ " width: 200px;",
262
+ " }",
263
+ "}"
264
+ ],
265
+ "client_controller": "{{CLIENT_CONTROLLER|datatable_controller}}",
266
+ "script": "{{SERVER_SCRIPT|datatable_server_script}}",
267
+ "link_function": "{{LINK_FUNCTION|}}",
268
+ "demo_data": {
269
+ "columns": [
270
+ {"field": "number", "label": "Number"},
271
+ {"field": "short_description", "label": "Description"},
272
+ {"field": "priority", "label": "Priority"},
273
+ {"field": "state", "label": "State"}
274
+ ],
275
+ "data": [
276
+ {"number": "INC0001", "short_description": "Sample incident", "priority": "High", "state": "Open"}
277
+ ]
278
+ }
279
+ },
280
+ "variables": {
281
+ "WIDGET_NAME": "data_table",
282
+ "WIDGET_ID": "data_table",
283
+ "INSTANCE_ID": "table_",
284
+ "WIDGET_TITLE": "Data Table",
285
+ "WIDGET_DESCRIPTION": "Interactive data table with advanced features",
286
+ "WIDGET_ROLES": "",
287
+ "TABLE_NAME": "incident",
288
+ "CLIENT_CONTROLLER": "function($scope, $http, $timeout) {\n var c = this;\n \n c.loading = true;\n c.data = [];\n c.displayData = [];\n c.columns = [];\n c.searchTerm = '';\n c.sortField = null;\n c.sortDirection = 'asc';\n c.currentPage = 1;\n c.pageSize = 20;\n c.totalPages = 1;\n c.editingCell = null;\n c.rowActions = [];\n \n // Parse row actions from options\n try {\n c.rowActions = JSON.parse(c.options.row_actions || '[]');\n } catch(e) {\n c.rowActions = [];\n }\n \n c.getData = function() {\n c.loading = true;\n c.server.get({\n action: 'get_table_data',\n table: c.options.table_name,\n max_records: c.options.max_records\n }).then(function(response) {\n c.columns = response.data.columns || [];\n c.data = response.data.data || [];\n c.filterData();\n c.loading = false;\n });\n };\n \n c.filterData = function() {\n var filtered = c.data;\n \n if (c.searchTerm) {\n filtered = c.data.filter(function(row) {\n return Object.values(row).some(function(value) {\n return String(value).toLowerCase().includes(c.searchTerm.toLowerCase());\n });\n });\n }\n \n // Apply sorting\n if (c.sortField) {\n filtered.sort(function(a, b) {\n var aVal = a[c.sortField] || '';\n var bVal = b[c.sortField] || '';\n var result = aVal < bVal ? -1 : aVal > bVal ? 1 : 0;\n return c.sortDirection === 'desc' ? -result : result;\n });\n }\n \n // Apply pagination\n c.totalPages = Math.ceil(filtered.length / c.pageSize);\n var start = (c.currentPage - 1) * c.pageSize;\n c.displayData = filtered.slice(start, start + c.pageSize);\n };\n \n c.sort = function(field) {\n if (c.sortField === field) {\n c.sortDirection = c.sortDirection === 'asc' ? 'desc' : 'asc';\n } else {\n c.sortField = field;\n c.sortDirection = 'asc';\n }\n c.filterData();\n };\n \n c.previousPage = function() {\n if (c.currentPage > 1) {\n c.currentPage--;\n c.filterData();\n }\n };\n \n c.nextPage = function() {\n if (c.currentPage < c.totalPages) {\n c.currentPage++;\n c.filterData();\n }\n };\n \n c.getCellValue = function(row, column) {\n var value = row[column.field];\n // Format based on field type\n if (column.type === 'date') {\n return value ? new Date(value).toLocaleDateString() : '';\n }\n return value || '';\n };\n \n c.isEditing = function(row, column) {\n return c.options.enable_inline_edit && \n c.editingCell && \n c.editingCell.row === row && \n c.editingCell.column === column;\n };\n \n c.startEdit = function(row, column) {\n if (c.options.enable_inline_edit) {\n c.editingCell = {row: row, column: column};\n }\n };\n \n c.saveEdit = function(row, column) {\n c.editingCell = null;\n // Save to server\n c.server.get({\n action: 'update_record',\n table: c.options.table_name,\n sys_id: row.sys_id,\n field: column.field,\n value: row[column.field]\n });\n };\n \n c.handleEditKeypress = function(event, row, column) {\n if (event.keyCode === 13) { // Enter key\n c.saveEdit(row, column);\n }\n };\n \n c.performAction = function(action, row) {\n switch(action.action) {\n case 'view':\n window.open('/' + c.options.table_name + '.do?sys_id=' + row.sys_id, '_blank');\n break;\n case 'edit':\n window.open('/' + c.options.table_name + '.do?sys_id=' + row.sys_id + '&sysparm_view=edit', '_blank');\n break;\n default:\n // Custom action\n $scope.$emit('widget-action', {action: action, row: row});\n }\n };\n \n c.exportData = function() {\n var csv = c.columns.map(function(col) { return col.label; }).join(',') + '\\n';\n c.displayData.forEach(function(row) {\n csv += c.columns.map(function(col) {\n var val = row[col.field] || '';\n return '\"' + String(val).replace(/\"/g, '\"\"') + '\"';\n }).join(',') + '\\n';\n });\n \n var blob = new Blob([csv], {type: 'text/csv'});\n var url = window.URL.createObjectURL(blob);\n var a = document.createElement('a');\n a.href = url;\n a.download = c.data.title + '.csv';\n a.click();\n };\n \n // Initial load\n c.getData();\n}",
289
+ "SERVER_SCRIPT": "(function() {\n try {\n data.columns = [];\n data.data = [];\n gs.log('DataTable widget server script started', 'datatable_widget');\n \n if (input && input.action === 'get_table_data') {\n var tableName = input.table || 'incident';\n var maxRecords = parseInt(input.max_records) || 100;\n \n gs.log('Getting table data: table=' + tableName + ', maxRecords=' + maxRecords, 'datatable_widget');\n \n // Get table metadata\n var fields = [];\n var gd = new GlideRecord('sys_dictionary');\n gd.addQuery('name', tableName);\n gd.addQuery('internal_type', '!=', 'collection');\n gd.orderBy('column_label');\n gd.setLimit(10); // Limit columns for performance\n gd.query();\n \n while (gd.next()) {\n if (gd.element && !gd.element.startsWith('sys_')) {\n fields.push({\n field: gd.element.toString(),\n label: gd.column_label.toString() || gd.element.toString(),\n type: gd.internal_type.toString()\n });\n }\n }\n \n // Default fields if none found\n if (fields.length === 0) {\n fields = [\n {field: 'number', label: 'Number', type: 'string'},\n {field: 'short_description', label: 'Short Description', type: 'string'},\n {field: 'sys_created_on', label: 'Created', type: 'glide_date_time'}\n ];\n gs.log('Using default fields for table: ' + tableName, 'datatable_widget');\n }\n \n data.columns = fields;\n gs.log('Found ' + fields.length + ' columns for table', 'datatable_widget');\n \n // Get table data\n var gr = new GlideRecord(tableName);\n gr.orderByDesc('sys_created_on');\n gr.setLimit(maxRecords);\n gr.query();\n \n var recordCount = 0;\n while (gr.next()) {\n var row = {sys_id: gr.getUniqueValue()};\n fields.forEach(function(field) {\n row[field.field] = gr.getDisplayValue(field.field) || '';\n });\n data.data.push(row);\n recordCount++;\n }\n \n gs.log('Retrieved ' + recordCount + ' records from ' + tableName, 'datatable_widget');\n \n } else if (input && input.action === 'update_record') {\n // ✅ FIXED: Enhanced update with validation and error handling\n if (!input.table || !input.sys_id || !input.field) {\n throw new Error('Missing required parameters for update: table, sys_id, field');\n }\n \n gs.log('Updating record: table=' + input.table + ', sys_id=' + input.sys_id + ', field=' + input.field, 'datatable_widget');\n \n var gr = new GlideRecord(input.table);\n if (gr.get(input.sys_id)) {\n gr.setValue(input.field, input.value || '');\n gr.update();\n data.success = true;\n data.message = 'Record updated successfully';\n gs.log('Record updated successfully', 'datatable_widget');\n } else {\n data.success = false;\n data.error = 'Record not found: ' + input.sys_id;\n gs.warn('Record not found for update: ' + input.sys_id, 'datatable_widget');\n }\n }\n } catch (error) {\n gs.error('DataTable widget error: ' + error.message, 'datatable_widget');\n data.error = 'Error processing request: ' + error.message;\n data.success = false;\n }\n})()",
290
+ "LINK_FUNCTION": ""
291
+ }
292
+ }