snow-flow 4.5.2 → 4.5.5
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/CLAUDE.md +52 -8
- package/README.md +46 -0
- package/dist/cli.js +13 -14
- package/dist/mcp/servicenow-flow-workspace-mobile-mcp.js +1523 -11
- package/dist/templates/claude-md-template.d.ts +1 -1
- package/dist/templates/claude-md-template.js +52 -7
- package/dist/utils/artifact-local-sync.js +26 -1
- package/package.json +60 -2
- package/website/index.html +104 -27
- package/website/tools.js +148 -11
|
@@ -275,6 +275,395 @@ class ServiceNowFlowWorkspaceMobileMCP {
|
|
|
275
275
|
required: ['table']
|
|
276
276
|
}
|
|
277
277
|
},
|
|
278
|
+
// ==========================================
|
|
279
|
+
// UI BUILDER TOOLS - COMPLETE NOW EXPERIENCE FRAMEWORK INTEGRATION
|
|
280
|
+
// Official ServiceNow sys_ux_* APIs for conversational UI Builder development
|
|
281
|
+
// ==========================================
|
|
282
|
+
// UI Builder Page Management (sys_ux_page)
|
|
283
|
+
{
|
|
284
|
+
name: 'snow_create_uib_page',
|
|
285
|
+
description: 'Creates a new UI Builder page in the Now Experience Framework using official ServiceNow sys_ux_page API. Enables conversational page creation with full UXF integration.',
|
|
286
|
+
inputSchema: {
|
|
287
|
+
type: 'object',
|
|
288
|
+
properties: {
|
|
289
|
+
name: { type: 'string', description: 'Page name (must be unique)' },
|
|
290
|
+
title: { type: 'string', description: 'Page title displayed in browser' },
|
|
291
|
+
route: { type: 'string', description: 'URL route for the page (e.g., /my-dashboard)' },
|
|
292
|
+
description: { type: 'string', description: 'Page description' },
|
|
293
|
+
application: { type: 'string', description: 'Application scope', default: 'global' },
|
|
294
|
+
theme: { type: 'string', description: 'Page theme', default: 'standard' },
|
|
295
|
+
public_read: { type: 'boolean', description: 'Allow public read access', default: false },
|
|
296
|
+
layout_type: { type: 'string', enum: ['container', 'grid', 'flex'], description: 'Page layout type', default: 'container' },
|
|
297
|
+
responsive: { type: 'boolean', description: 'Enable responsive design', default: true },
|
|
298
|
+
active: { type: 'boolean', description: 'Page is active', default: true }
|
|
299
|
+
},
|
|
300
|
+
required: ['name', 'title', 'route']
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
name: 'snow_update_uib_page',
|
|
305
|
+
description: 'Updates an existing UI Builder page configuration, metadata, or settings.',
|
|
306
|
+
inputSchema: {
|
|
307
|
+
type: 'object',
|
|
308
|
+
properties: {
|
|
309
|
+
page_id: { type: 'string', description: 'Page sys_id to update' },
|
|
310
|
+
title: { type: 'string', description: 'New page title' },
|
|
311
|
+
route: { type: 'string', description: 'New URL route' },
|
|
312
|
+
description: { type: 'string', description: 'New description' },
|
|
313
|
+
theme: { type: 'string', description: 'New page theme' },
|
|
314
|
+
layout_type: { type: 'string', enum: ['container', 'grid', 'flex'], description: 'New layout type' },
|
|
315
|
+
responsive: { type: 'boolean', description: 'Enable/disable responsive design' },
|
|
316
|
+
active: { type: 'boolean', description: 'Page active status' }
|
|
317
|
+
},
|
|
318
|
+
required: ['page_id']
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
name: 'snow_delete_uib_page',
|
|
323
|
+
description: 'Safely deletes a UI Builder page and all associated elements, with comprehensive dependency validation.',
|
|
324
|
+
inputSchema: {
|
|
325
|
+
type: 'object',
|
|
326
|
+
properties: {
|
|
327
|
+
page_id: { type: 'string', description: 'Page sys_id to delete' },
|
|
328
|
+
force_delete: { type: 'boolean', description: 'Force delete even if dependencies exist', default: false },
|
|
329
|
+
backup_before_delete: { type: 'boolean', description: 'Create backup before deletion', default: true },
|
|
330
|
+
clean_orphaned_elements: { type: 'boolean', description: 'Clean up orphaned page elements', default: true }
|
|
331
|
+
},
|
|
332
|
+
required: ['page_id']
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
name: 'snow_discover_uib_pages',
|
|
337
|
+
description: 'Discovers all UI Builder pages in the instance with advanced filtering and relationship analysis.',
|
|
338
|
+
inputSchema: {
|
|
339
|
+
type: 'object',
|
|
340
|
+
properties: {
|
|
341
|
+
application: { type: 'string', description: 'Filter by application scope' },
|
|
342
|
+
active_only: { type: 'boolean', description: 'Show only active pages', default: true },
|
|
343
|
+
include_elements: { type: 'boolean', description: 'Include page elements and layout', default: false },
|
|
344
|
+
include_data_brokers: { type: 'boolean', description: 'Include data broker configurations', default: false },
|
|
345
|
+
include_routing: { type: 'boolean', description: 'Include page registry routing info', default: false },
|
|
346
|
+
name_filter: { type: 'string', description: 'Filter pages by name (partial match)' },
|
|
347
|
+
route_filter: { type: 'string', description: 'Filter pages by route pattern' },
|
|
348
|
+
theme_filter: { type: 'string', description: 'Filter pages by theme' },
|
|
349
|
+
limit: { type: 'number', description: 'Maximum pages to return', default: 50 }
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
},
|
|
353
|
+
// UI Builder Component Library Management (sys_ux_lib_*)
|
|
354
|
+
{
|
|
355
|
+
name: 'snow_create_uib_component',
|
|
356
|
+
description: 'Creates a custom UI Builder component using official ServiceNow sys_ux_lib_component and sys_ux_lib_source_script APIs.',
|
|
357
|
+
inputSchema: {
|
|
358
|
+
type: 'object',
|
|
359
|
+
properties: {
|
|
360
|
+
name: { type: 'string', description: 'Component name (must be unique, kebab-case recommended)' },
|
|
361
|
+
label: { type: 'string', description: 'Component display label' },
|
|
362
|
+
description: { type: 'string', description: 'Component description and usage notes' },
|
|
363
|
+
category: { type: 'string', description: 'Component category for organization', default: 'custom' },
|
|
364
|
+
source_script: { type: 'string', description: 'Component source code (JavaScript/React/Web Components)' },
|
|
365
|
+
properties_schema: { type: 'object', description: 'Component properties schema definition (JSON Schema)' },
|
|
366
|
+
events: { type: 'array', items: { type: 'string' }, description: 'Events this component can emit' },
|
|
367
|
+
dependencies: { type: 'array', items: { type: 'string' }, description: 'External dependencies (libraries, other components)' },
|
|
368
|
+
styling: { type: 'object', description: 'Default styling and CSS configuration' },
|
|
369
|
+
version: { type: 'string', description: 'Component version', default: '1.0.0' },
|
|
370
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Tags for component discovery' }
|
|
371
|
+
},
|
|
372
|
+
required: ['name', 'label', 'source_script']
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
name: 'snow_update_uib_component',
|
|
377
|
+
description: 'Updates an existing UI Builder component definition, source code, or configuration.',
|
|
378
|
+
inputSchema: {
|
|
379
|
+
type: 'object',
|
|
380
|
+
properties: {
|
|
381
|
+
component_id: { type: 'string', description: 'Component sys_id to update' },
|
|
382
|
+
label: { type: 'string', description: 'New component label' },
|
|
383
|
+
description: { type: 'string', description: 'New description' },
|
|
384
|
+
source_script: { type: 'string', description: 'Updated component source code' },
|
|
385
|
+
properties_schema: { type: 'object', description: 'Updated properties schema' },
|
|
386
|
+
styling: { type: 'object', description: 'Updated styling configuration' },
|
|
387
|
+
version: { type: 'string', description: 'New version number (semantic versioning)' },
|
|
388
|
+
events: { type: 'array', items: { type: 'string' }, description: 'Updated events list' },
|
|
389
|
+
dependencies: { type: 'array', items: { type: 'string' }, description: 'Updated dependencies' },
|
|
390
|
+
active: { type: 'boolean', description: 'Component active status' }
|
|
391
|
+
},
|
|
392
|
+
required: ['component_id']
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
name: 'snow_discover_uib_components',
|
|
397
|
+
description: 'Discovers all available UI Builder components including ServiceNow built-in and custom components with comprehensive metadata.',
|
|
398
|
+
inputSchema: {
|
|
399
|
+
type: 'object',
|
|
400
|
+
properties: {
|
|
401
|
+
category: { type: 'string', description: 'Filter by component category (layout, input, display, custom)' },
|
|
402
|
+
custom_only: { type: 'boolean', description: 'Show only custom components', default: false },
|
|
403
|
+
built_in_only: { type: 'boolean', description: 'Show only ServiceNow built-in components', default: false },
|
|
404
|
+
include_source: { type: 'boolean', description: 'Include component source code', default: false },
|
|
405
|
+
include_usage_stats: { type: 'boolean', description: 'Include component usage statistics across pages', default: false },
|
|
406
|
+
include_dependencies: { type: 'boolean', description: 'Include component dependency information', default: false },
|
|
407
|
+
name_filter: { type: 'string', description: 'Filter components by name or label' },
|
|
408
|
+
version_filter: { type: 'string', description: 'Filter by version pattern' },
|
|
409
|
+
application: { type: 'string', description: 'Filter by application scope' },
|
|
410
|
+
limit: { type: 'number', description: 'Maximum components to return', default: 100 }
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
name: 'snow_clone_uib_component',
|
|
416
|
+
description: 'Clones an existing UI Builder component to create a customized variant with modifications.',
|
|
417
|
+
inputSchema: {
|
|
418
|
+
type: 'object',
|
|
419
|
+
properties: {
|
|
420
|
+
source_component_id: { type: 'string', description: 'Source component sys_id to clone' },
|
|
421
|
+
new_name: { type: 'string', description: 'Name for the cloned component' },
|
|
422
|
+
new_label: { type: 'string', description: 'Label for the cloned component' },
|
|
423
|
+
modifications: { type: 'object', description: 'Specific modifications to apply to cloned component' },
|
|
424
|
+
category: { type: 'string', description: 'Category for cloned component', default: 'custom' },
|
|
425
|
+
version: { type: 'string', description: 'Version for cloned component', default: '1.0.0' },
|
|
426
|
+
description: { type: 'string', description: 'Description of clone purpose and changes' }
|
|
427
|
+
},
|
|
428
|
+
required: ['source_component_id', 'new_name', 'new_label']
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
// UI Builder Data Broker Management (sys_ux_data_broker)
|
|
432
|
+
{
|
|
433
|
+
name: 'snow_create_uib_data_broker',
|
|
434
|
+
description: 'Creates a UI Builder data broker for connecting pages to ServiceNow data sources using official sys_ux_data_broker API.',
|
|
435
|
+
inputSchema: {
|
|
436
|
+
type: 'object',
|
|
437
|
+
properties: {
|
|
438
|
+
name: { type: 'string', description: 'Data broker name (must be unique)' },
|
|
439
|
+
label: { type: 'string', description: 'Data broker display label' },
|
|
440
|
+
table: { type: 'string', description: 'ServiceNow table to connect' },
|
|
441
|
+
type: { type: 'string', enum: ['table', 'script', 'rest_message'], description: 'Data broker type', default: 'table' },
|
|
442
|
+
query: { type: 'string', description: 'Default query for table data broker' },
|
|
443
|
+
script: { type: 'string', description: 'Script for script-based data broker' },
|
|
444
|
+
rest_message: { type: 'string', description: 'REST message sys_id for REST data broker' },
|
|
445
|
+
fields: { type: 'array', items: { type: 'string' }, description: 'Fields to retrieve (leave empty for all)' },
|
|
446
|
+
auto_refresh: { type: 'boolean', description: 'Enable automatic data refresh', default: false },
|
|
447
|
+
refresh_interval: { type: 'number', description: 'Refresh interval in seconds', default: 30 },
|
|
448
|
+
cache_duration: { type: 'number', description: 'Cache duration in seconds', default: 300 },
|
|
449
|
+
max_records: { type: 'number', description: 'Maximum records to fetch', default: 1000 }
|
|
450
|
+
},
|
|
451
|
+
required: ['name', 'label', 'type']
|
|
452
|
+
}
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
name: 'snow_configure_uib_data_broker',
|
|
456
|
+
description: 'Configures or updates an existing UI Builder data broker with new query, fields, or performance settings.',
|
|
457
|
+
inputSchema: {
|
|
458
|
+
type: 'object',
|
|
459
|
+
properties: {
|
|
460
|
+
broker_id: { type: 'string', description: 'Data broker sys_id' },
|
|
461
|
+
query: { type: 'string', description: 'Updated query condition' },
|
|
462
|
+
fields: { type: 'array', items: { type: 'string' }, description: 'Updated fields list' },
|
|
463
|
+
auto_refresh: { type: 'boolean', description: 'Enable/disable auto-refresh' },
|
|
464
|
+
refresh_interval: { type: 'number', description: 'New refresh interval in seconds' },
|
|
465
|
+
cache_duration: { type: 'number', description: 'New cache duration in seconds' },
|
|
466
|
+
max_records: { type: 'number', description: 'New maximum records limit' },
|
|
467
|
+
active: { type: 'boolean', description: 'Data broker active status' }
|
|
468
|
+
},
|
|
469
|
+
required: ['broker_id']
|
|
470
|
+
}
|
|
471
|
+
},
|
|
472
|
+
// UI Builder Page Layout Management (sys_ux_page_element)
|
|
473
|
+
{
|
|
474
|
+
name: 'snow_add_uib_page_element',
|
|
475
|
+
description: 'Adds a component element to a UI Builder page using official sys_ux_page_element API with full layout control.',
|
|
476
|
+
inputSchema: {
|
|
477
|
+
type: 'object',
|
|
478
|
+
properties: {
|
|
479
|
+
page_id: { type: 'string', description: 'Target page sys_id' },
|
|
480
|
+
component: { type: 'string', description: 'Component name or sys_id from component library' },
|
|
481
|
+
container_id: { type: 'string', description: 'Parent container element ID (optional for root level)' },
|
|
482
|
+
position: { type: 'number', description: 'Element position in container', default: 0 },
|
|
483
|
+
properties: { type: 'object', description: 'Component properties and configuration' },
|
|
484
|
+
data_broker: { type: 'string', description: 'Data broker sys_id to bind to component' },
|
|
485
|
+
responsive_config: { type: 'object', description: 'Responsive layout configuration for different screen sizes' },
|
|
486
|
+
conditional_display: { type: 'string', description: 'Condition script for element visibility' },
|
|
487
|
+
css_classes: { type: 'array', items: { type: 'string' }, description: 'CSS classes to apply' },
|
|
488
|
+
inline_styles: { type: 'object', description: 'Inline styles configuration' }
|
|
489
|
+
},
|
|
490
|
+
required: ['page_id', 'component']
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
name: 'snow_update_uib_page_element',
|
|
495
|
+
description: 'Updates properties, position, or configuration of an existing UI Builder page element.',
|
|
496
|
+
inputSchema: {
|
|
497
|
+
type: 'object',
|
|
498
|
+
properties: {
|
|
499
|
+
element_id: { type: 'string', description: 'Page element sys_id' },
|
|
500
|
+
properties: { type: 'object', description: 'Updated component properties' },
|
|
501
|
+
position: { type: 'number', description: 'New position in container' },
|
|
502
|
+
data_broker: { type: 'string', description: 'New data broker binding' },
|
|
503
|
+
responsive_config: { type: 'object', description: 'Updated responsive configuration' },
|
|
504
|
+
conditional_display: { type: 'string', description: 'Updated display condition' },
|
|
505
|
+
css_classes: { type: 'array', items: { type: 'string' }, description: 'Updated CSS classes' },
|
|
506
|
+
inline_styles: { type: 'object', description: 'Updated inline styles' }
|
|
507
|
+
},
|
|
508
|
+
required: ['element_id']
|
|
509
|
+
}
|
|
510
|
+
},
|
|
511
|
+
{
|
|
512
|
+
name: 'snow_remove_uib_page_element',
|
|
513
|
+
description: 'Removes a component element from a UI Builder page with comprehensive dependency validation.',
|
|
514
|
+
inputSchema: {
|
|
515
|
+
type: 'object',
|
|
516
|
+
properties: {
|
|
517
|
+
element_id: { type: 'string', description: 'Page element sys_id to remove' },
|
|
518
|
+
validate_dependencies: { type: 'boolean', description: 'Check for element dependencies before removal', default: true },
|
|
519
|
+
cleanup_orphaned_data: { type: 'boolean', description: 'Clean up orphaned data brokers and scripts', default: true }
|
|
520
|
+
},
|
|
521
|
+
required: ['element_id']
|
|
522
|
+
}
|
|
523
|
+
},
|
|
524
|
+
// UI Builder Page Registry & Routing (sys_ux_page_registry)
|
|
525
|
+
{
|
|
526
|
+
name: 'snow_create_uib_page_registry',
|
|
527
|
+
description: 'Creates URL routing configuration for UI Builder page using official sys_ux_page_registry API.',
|
|
528
|
+
inputSchema: {
|
|
529
|
+
type: 'object',
|
|
530
|
+
properties: {
|
|
531
|
+
page_id: { type: 'string', description: 'Target page sys_id' },
|
|
532
|
+
path: { type: 'string', description: 'URL path pattern (e.g., /dashboard, /incidents/:id)' },
|
|
533
|
+
application: { type: 'string', description: 'Application scope for routing' },
|
|
534
|
+
roles: { type: 'array', items: { type: 'string' }, description: 'Roles required to access page' },
|
|
535
|
+
public_access: { type: 'boolean', description: 'Allow public access without authentication', default: false },
|
|
536
|
+
redirect_url: { type: 'string', description: 'Redirect URL for unauthorized access' },
|
|
537
|
+
meta_title: { type: 'string', description: 'SEO meta title for the page' },
|
|
538
|
+
meta_description: { type: 'string', description: 'SEO meta description' },
|
|
539
|
+
parameter_mapping: { type: 'object', description: 'URL parameter mapping configuration' },
|
|
540
|
+
cache_control: { type: 'string', description: 'Cache control headers' }
|
|
541
|
+
},
|
|
542
|
+
required: ['page_id', 'path']
|
|
543
|
+
}
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
name: 'snow_discover_uib_routes',
|
|
547
|
+
description: 'Discovers all UI Builder page routes and their security/access configurations.',
|
|
548
|
+
inputSchema: {
|
|
549
|
+
type: 'object',
|
|
550
|
+
properties: {
|
|
551
|
+
application: { type: 'string', description: 'Filter by application scope' },
|
|
552
|
+
active_only: { type: 'boolean', description: 'Show only active routes', default: true },
|
|
553
|
+
include_security: { type: 'boolean', description: 'Include role and security information', default: false },
|
|
554
|
+
include_parameters: { type: 'boolean', description: 'Include URL parameter configurations', default: false },
|
|
555
|
+
path_pattern: { type: 'string', description: 'Filter by path pattern or wildcard' },
|
|
556
|
+
role_filter: { type: 'string', description: 'Filter by required role' }
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
},
|
|
560
|
+
// UI Builder Client Script Management (sys_ux_client_script)
|
|
561
|
+
{
|
|
562
|
+
name: 'snow_create_uib_client_script',
|
|
563
|
+
description: 'Creates client-side scripts for UI Builder pages using official sys_ux_client_script API.',
|
|
564
|
+
inputSchema: {
|
|
565
|
+
type: 'object',
|
|
566
|
+
properties: {
|
|
567
|
+
page_id: { type: 'string', description: 'Target page sys_id' },
|
|
568
|
+
name: { type: 'string', description: 'Script name (must be unique within page)' },
|
|
569
|
+
type: { type: 'string', enum: ['onLoad', 'onChange', 'onClick', 'onSubmit', 'custom'], description: 'Script trigger type' },
|
|
570
|
+
script: { type: 'string', description: 'JavaScript code for the script' },
|
|
571
|
+
component_reference: { type: 'string', description: 'Reference to specific component if applicable' },
|
|
572
|
+
event_name: { type: 'string', description: 'Custom event name for custom type scripts' },
|
|
573
|
+
execution_order: { type: 'number', description: 'Script execution order', default: 100 },
|
|
574
|
+
async_execution: { type: 'boolean', description: 'Enable async execution', default: false },
|
|
575
|
+
error_handling: { type: 'string', description: 'Error handling strategy', default: 'log' },
|
|
576
|
+
active: { type: 'boolean', description: 'Script is active', default: true }
|
|
577
|
+
},
|
|
578
|
+
required: ['page_id', 'name', 'type', 'script']
|
|
579
|
+
}
|
|
580
|
+
},
|
|
581
|
+
{
|
|
582
|
+
name: 'snow_create_uib_client_state',
|
|
583
|
+
description: 'Creates client state management configuration for UI Builder pages using official sys_ux_client_state API.',
|
|
584
|
+
inputSchema: {
|
|
585
|
+
type: 'object',
|
|
586
|
+
properties: {
|
|
587
|
+
page_id: { type: 'string', description: 'Target page sys_id' },
|
|
588
|
+
state_name: { type: 'string', description: 'State variable name' },
|
|
589
|
+
initial_value: { type: 'string', description: 'Initial state value (JSON format)' },
|
|
590
|
+
scope: { type: 'string', enum: ['page', 'session', 'global'], description: 'State scope', default: 'page' },
|
|
591
|
+
persistent: { type: 'boolean', description: 'Persist state across browser sessions', default: false },
|
|
592
|
+
reactive: { type: 'boolean', description: 'Enable reactive updates', default: true },
|
|
593
|
+
validation_schema: { type: 'object', description: 'State validation schema' },
|
|
594
|
+
description: { type: 'string', description: 'State variable description' }
|
|
595
|
+
},
|
|
596
|
+
required: ['page_id', 'state_name', 'initial_value']
|
|
597
|
+
}
|
|
598
|
+
},
|
|
599
|
+
// UI Builder Event Management (sys_ux_event)
|
|
600
|
+
{
|
|
601
|
+
name: 'snow_create_uib_event',
|
|
602
|
+
description: 'Creates custom events for UI Builder components using official sys_ux_event API.',
|
|
603
|
+
inputSchema: {
|
|
604
|
+
type: 'object',
|
|
605
|
+
properties: {
|
|
606
|
+
name: { type: 'string', description: 'Event name (must be unique)' },
|
|
607
|
+
label: { type: 'string', description: 'Event display label' },
|
|
608
|
+
description: { type: 'string', description: 'Event description and usage' },
|
|
609
|
+
payload_schema: { type: 'object', description: 'Event payload schema definition (JSON Schema)' },
|
|
610
|
+
component_scope: { type: 'string', description: 'Component scope for event availability' },
|
|
611
|
+
global_event: { type: 'boolean', description: 'Global event accessible across all pages', default: false },
|
|
612
|
+
bubbles: { type: 'boolean', description: 'Event bubbles up DOM tree', default: true },
|
|
613
|
+
cancelable: { type: 'boolean', description: 'Event can be cancelled', default: true }
|
|
614
|
+
},
|
|
615
|
+
required: ['name', 'label']
|
|
616
|
+
}
|
|
617
|
+
},
|
|
618
|
+
// UI Builder Validation & Analytics
|
|
619
|
+
{
|
|
620
|
+
name: 'snow_analyze_uib_page_performance',
|
|
621
|
+
description: 'Analyzes UI Builder page performance including load times, component efficiency, and optimization recommendations.',
|
|
622
|
+
inputSchema: {
|
|
623
|
+
type: 'object',
|
|
624
|
+
properties: {
|
|
625
|
+
page_id: { type: 'string', description: 'Page sys_id to analyze' },
|
|
626
|
+
include_components: { type: 'boolean', description: 'Include component-level performance analysis', default: true },
|
|
627
|
+
include_data_broker_stats: { type: 'boolean', description: 'Include data broker performance metrics', default: true },
|
|
628
|
+
include_client_scripts: { type: 'boolean', description: 'Include client script performance', default: true },
|
|
629
|
+
time_period_days: { type: 'number', description: 'Analysis period in days', default: 30 },
|
|
630
|
+
detailed_analysis: { type: 'boolean', description: 'Generate detailed performance report', default: false }
|
|
631
|
+
},
|
|
632
|
+
required: ['page_id']
|
|
633
|
+
}
|
|
634
|
+
},
|
|
635
|
+
{
|
|
636
|
+
name: 'snow_validate_uib_page_structure',
|
|
637
|
+
description: 'Validates UI Builder page structure, component relationships, data flow integrity, and best practices compliance.',
|
|
638
|
+
inputSchema: {
|
|
639
|
+
type: 'object',
|
|
640
|
+
properties: {
|
|
641
|
+
page_id: { type: 'string', description: 'Page sys_id to validate' },
|
|
642
|
+
check_data_brokers: { type: 'boolean', description: 'Validate data broker connections and queries', default: true },
|
|
643
|
+
check_component_dependencies: { type: 'boolean', description: 'Check component dependencies and compatibility', default: true },
|
|
644
|
+
check_routing: { type: 'boolean', description: 'Validate page routing and URL configuration', default: true },
|
|
645
|
+
check_security: { type: 'boolean', description: 'Validate security, ACLs, and access controls', default: true },
|
|
646
|
+
check_performance: { type: 'boolean', description: 'Check for performance best practices', default: true },
|
|
647
|
+
check_accessibility: { type: 'boolean', description: 'Validate accessibility compliance', default: false }
|
|
648
|
+
},
|
|
649
|
+
required: ['page_id']
|
|
650
|
+
}
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
name: 'snow_discover_uib_page_usage',
|
|
654
|
+
description: 'Analyzes UI Builder page usage patterns, user interactions, and component effectiveness.',
|
|
655
|
+
inputSchema: {
|
|
656
|
+
type: 'object',
|
|
657
|
+
properties: {
|
|
658
|
+
page_id: { type: 'string', description: 'Page sys_id to analyze usage for' },
|
|
659
|
+
time_period_days: { type: 'number', description: 'Analysis period in days', default: 30 },
|
|
660
|
+
include_user_journeys: { type: 'boolean', description: 'Include user journey analysis', default: false },
|
|
661
|
+
include_conversion_rates: { type: 'boolean', description: 'Include conversion and engagement rates', default: false },
|
|
662
|
+
group_by_role: { type: 'boolean', description: 'Group analytics by user role', default: false }
|
|
663
|
+
},
|
|
664
|
+
required: ['page_id']
|
|
665
|
+
}
|
|
666
|
+
},
|
|
278
667
|
{
|
|
279
668
|
name: 'snow_create_mobile_action',
|
|
280
669
|
description: 'Creates custom actions for mobile app interfaces.',
|
|
@@ -380,6 +769,77 @@ class ServiceNowFlowWorkspaceMobileMCP {
|
|
|
380
769
|
case 'snow_configure_offline_sync':
|
|
381
770
|
result = await this.configureOfflineSync(args);
|
|
382
771
|
break;
|
|
772
|
+
// UI Builder Page Management
|
|
773
|
+
case 'snow_create_uib_page':
|
|
774
|
+
result = await this.createUIBPage(args);
|
|
775
|
+
break;
|
|
776
|
+
case 'snow_update_uib_page':
|
|
777
|
+
result = await this.updateUIBPage(args);
|
|
778
|
+
break;
|
|
779
|
+
case 'snow_delete_uib_page':
|
|
780
|
+
result = await this.deleteUIBPage(args);
|
|
781
|
+
break;
|
|
782
|
+
case 'snow_discover_uib_pages':
|
|
783
|
+
result = await this.discoverUIBPages(args);
|
|
784
|
+
break;
|
|
785
|
+
// UI Builder Component Management
|
|
786
|
+
case 'snow_create_uib_component':
|
|
787
|
+
result = await this.createUIBComponent(args);
|
|
788
|
+
break;
|
|
789
|
+
case 'snow_update_uib_component':
|
|
790
|
+
result = await this.updateUIBComponent(args);
|
|
791
|
+
break;
|
|
792
|
+
case 'snow_discover_uib_components':
|
|
793
|
+
result = await this.discoverUIBComponents(args);
|
|
794
|
+
break;
|
|
795
|
+
case 'snow_clone_uib_component':
|
|
796
|
+
result = await this.cloneUIBComponent(args);
|
|
797
|
+
break;
|
|
798
|
+
// UI Builder Data Broker Management
|
|
799
|
+
case 'snow_create_uib_data_broker':
|
|
800
|
+
result = await this.createUIBDataBroker(args);
|
|
801
|
+
break;
|
|
802
|
+
case 'snow_configure_uib_data_broker':
|
|
803
|
+
result = await this.configureUIBDataBroker(args);
|
|
804
|
+
break;
|
|
805
|
+
// UI Builder Page Layout Management
|
|
806
|
+
case 'snow_add_uib_page_element':
|
|
807
|
+
result = await this.addUIBPageElement(args);
|
|
808
|
+
break;
|
|
809
|
+
case 'snow_update_uib_page_element':
|
|
810
|
+
result = await this.updateUIBPageElement(args);
|
|
811
|
+
break;
|
|
812
|
+
case 'snow_remove_uib_page_element':
|
|
813
|
+
result = await this.removeUIBPageElement(args);
|
|
814
|
+
break;
|
|
815
|
+
// UI Builder Page Registry & Routing
|
|
816
|
+
case 'snow_create_uib_page_registry':
|
|
817
|
+
result = await this.createUIBPageRegistry(args);
|
|
818
|
+
break;
|
|
819
|
+
case 'snow_discover_uib_routes':
|
|
820
|
+
result = await this.discoverUIBRoutes(args);
|
|
821
|
+
break;
|
|
822
|
+
// UI Builder Client Script Management
|
|
823
|
+
case 'snow_create_uib_client_script':
|
|
824
|
+
result = await this.createUIBClientScript(args);
|
|
825
|
+
break;
|
|
826
|
+
case 'snow_create_uib_client_state':
|
|
827
|
+
result = await this.createUIBClientState(args);
|
|
828
|
+
break;
|
|
829
|
+
// UI Builder Event Management
|
|
830
|
+
case 'snow_create_uib_event':
|
|
831
|
+
result = await this.createUIBEvent(args);
|
|
832
|
+
break;
|
|
833
|
+
// UI Builder Validation & Analytics
|
|
834
|
+
case 'snow_analyze_uib_page_performance':
|
|
835
|
+
result = await this.analyzeUIBPagePerformance(args);
|
|
836
|
+
break;
|
|
837
|
+
case 'snow_validate_uib_page_structure':
|
|
838
|
+
result = await this.validateUIBPageStructure(args);
|
|
839
|
+
break;
|
|
840
|
+
case 'snow_discover_uib_page_usage':
|
|
841
|
+
result = await this.discoverUIBPageUsage(args);
|
|
842
|
+
break;
|
|
383
843
|
case 'snow_create_mobile_action':
|
|
384
844
|
result = await this.createMobileAction(args);
|
|
385
845
|
break;
|
|
@@ -811,18 +1271,43 @@ ${executionList}
|
|
|
811
1271
|
// Agent Workspace Implementation
|
|
812
1272
|
async createWorkspace(args) {
|
|
813
1273
|
try {
|
|
814
|
-
this.logger.info('Creating
|
|
1274
|
+
this.logger.info('Creating Agent Workspace...');
|
|
1275
|
+
// First validate Agent Workspace table access
|
|
1276
|
+
const tableCheck = await this.client.searchRecords('sys_aw_master_config', '', 1);
|
|
1277
|
+
if (!tableCheck.success) {
|
|
1278
|
+
return {
|
|
1279
|
+
success: false,
|
|
1280
|
+
error: 'Agent Workspace tables not accessible. This feature requires ServiceNow Agent Workspace plugin to be installed and activated.',
|
|
1281
|
+
suggestion: 'Install Agent Workspace plugin: System Applications → All Available Applications → Search for "Agent Workspace"'
|
|
1282
|
+
};
|
|
1283
|
+
}
|
|
815
1284
|
const workspaceData = {
|
|
816
1285
|
name: args.name,
|
|
817
1286
|
description: args.description || '',
|
|
818
|
-
tables: args.tables.join(','),
|
|
1287
|
+
tables: args.tables ? args.tables.join(',') : '',
|
|
819
1288
|
home_page: args.home_page || '',
|
|
820
1289
|
theme: args.theme || 'default',
|
|
821
|
-
roles: args.roles ? args.roles.join(',') : ''
|
|
1290
|
+
roles: args.roles ? args.roles.join(',') : '',
|
|
1291
|
+
active: true
|
|
822
1292
|
};
|
|
823
|
-
this.logger.trackAPICall('CREATE', '
|
|
824
|
-
const response = await this.client.createRecord('
|
|
1293
|
+
this.logger.trackAPICall('CREATE', 'sys_aw_master_config', 1);
|
|
1294
|
+
const response = await this.client.createRecord('sys_aw_master_config', workspaceData);
|
|
825
1295
|
if (!response.success) {
|
|
1296
|
+
// Provide specific error guidance
|
|
1297
|
+
if (response.error?.includes('403') || response.error?.includes('Forbidden')) {
|
|
1298
|
+
return {
|
|
1299
|
+
success: false,
|
|
1300
|
+
error: 'Insufficient permissions to create Agent Workspace. Requires workspace_admin role or elevated permissions.',
|
|
1301
|
+
suggestion: 'Contact your ServiceNow administrator to grant Agent Workspace permissions.'
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
if (response.error?.includes('400') || response.error?.includes('Bad Request')) {
|
|
1305
|
+
return {
|
|
1306
|
+
success: false,
|
|
1307
|
+
error: 'Invalid workspace configuration. Agent Workspace may not be properly configured in this instance.',
|
|
1308
|
+
suggestion: 'Verify Agent Workspace is enabled and configured. Check System Properties > Agent Workspace settings.'
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
826
1311
|
throw new Error(`Failed to create workspace: ${response.error}`);
|
|
827
1312
|
}
|
|
828
1313
|
return {
|
|
@@ -968,7 +1453,7 @@ ${args.filter ? `🔍 Filter: ${args.filter}` : ''}
|
|
|
968
1453
|
const response = await this.client.createRecord('sys_aw_notification_config', notificationData);
|
|
969
1454
|
if (!response.success) {
|
|
970
1455
|
// Fallback to updating workspace
|
|
971
|
-
await this.client.updateRecord('
|
|
1456
|
+
await this.client.updateRecord('sys_aw_master_config', args.workspace, {
|
|
972
1457
|
notifications_enabled: args.enable_desktop || args.enable_sound
|
|
973
1458
|
});
|
|
974
1459
|
}
|
|
@@ -994,10 +1479,15 @@ ${args.filter ? `🔍 Filter: ${args.filter}` : ''}
|
|
|
994
1479
|
}
|
|
995
1480
|
async discoverWorkspaces(args) {
|
|
996
1481
|
try {
|
|
997
|
-
this.logger.info('Discovering
|
|
998
|
-
|
|
1482
|
+
this.logger.info('Discovering Agent Workspaces...');
|
|
1483
|
+
// Validate table access first
|
|
1484
|
+
const response = await this.client.searchRecords('sys_aw_master_config', '', 50);
|
|
999
1485
|
if (!response.success) {
|
|
1000
|
-
|
|
1486
|
+
return {
|
|
1487
|
+
success: false,
|
|
1488
|
+
error: 'Cannot access Agent Workspace tables. Agent Workspace plugin may not be installed or activated.',
|
|
1489
|
+
suggestion: 'Install Agent Workspace plugin in ServiceNow: System Applications → All Available Applications → Agent Workspace'
|
|
1490
|
+
};
|
|
1001
1491
|
}
|
|
1002
1492
|
const workspaces = response.data.result;
|
|
1003
1493
|
if (!workspaces.length) {
|
|
@@ -1037,10 +1527,21 @@ ${workspaceList.join('\n\n')}
|
|
|
1037
1527
|
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to discover workspaces: ${error}`);
|
|
1038
1528
|
}
|
|
1039
1529
|
}
|
|
1040
|
-
// Mobile Implementation
|
|
1530
|
+
// Mobile Implementation
|
|
1041
1531
|
async configureMobileApp(args) {
|
|
1042
1532
|
try {
|
|
1043
|
-
this.logger.info('Configuring
|
|
1533
|
+
this.logger.info('Configuring ServiceNow Mobile app...');
|
|
1534
|
+
// Validate mobile app tables access first
|
|
1535
|
+
const mobileTableCheck = await this.client.searchRecords('sys_push_notif_msg', '', 1);
|
|
1536
|
+
if (!mobileTableCheck.success) {
|
|
1537
|
+
return {
|
|
1538
|
+
success: false,
|
|
1539
|
+
error: 'ServiceNow Mobile app tables not accessible. This feature requires Mobile Publishing plugin and Mobile Application Management licensing.',
|
|
1540
|
+
suggestion: 'Install Mobile Publishing plugin: System Applications → ServiceNow Store → Search "Mobile Publishing". Requires separate licensing.',
|
|
1541
|
+
plugin_required: 'Mobile Publishing',
|
|
1542
|
+
licensing_note: 'Mobile Publishing is a paid plugin requiring additional ServiceNow licensing'
|
|
1543
|
+
};
|
|
1544
|
+
}
|
|
1044
1545
|
const mobileConfig = {
|
|
1045
1546
|
app_name: args.app_name,
|
|
1046
1547
|
enabled_modules: args.enabled_modules ? args.enabled_modules.join(',') : '',
|
|
@@ -1052,6 +1553,21 @@ ${workspaceList.join('\n\n')}
|
|
|
1052
1553
|
this.logger.trackAPICall('CREATE', 'sys_mobile_config', 1);
|
|
1053
1554
|
const response = await this.client.createRecord('sys_mobile_config', mobileConfig);
|
|
1054
1555
|
if (!response.success) {
|
|
1556
|
+
// Provide specific mobile error guidance
|
|
1557
|
+
if (response.error?.includes('400') || response.error?.includes('Bad Request')) {
|
|
1558
|
+
return {
|
|
1559
|
+
success: false,
|
|
1560
|
+
error: 'Mobile app configuration failed. ServiceNow Mobile Publishing plugin may not be installed or properly configured.',
|
|
1561
|
+
suggestion: 'Verify Mobile Publishing plugin is installed and activated. Check ServiceNow Store for Mobile Publishing application.'
|
|
1562
|
+
};
|
|
1563
|
+
}
|
|
1564
|
+
if (response.error?.includes('403') || response.error?.includes('Forbidden')) {
|
|
1565
|
+
return {
|
|
1566
|
+
success: false,
|
|
1567
|
+
error: 'Insufficient permissions for mobile app configuration. Requires mobile_admin role or admin privileges.',
|
|
1568
|
+
suggestion: 'Contact ServiceNow administrator for mobile application management permissions.'
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1055
1571
|
throw new Error(`Failed to configure mobile app: ${response.error}`);
|
|
1056
1572
|
}
|
|
1057
1573
|
return {
|
|
@@ -1078,6 +1594,16 @@ ${workspaceList.join('\n\n')}
|
|
|
1078
1594
|
async createMobileLayout(args) {
|
|
1079
1595
|
try {
|
|
1080
1596
|
this.logger.info('Creating mobile layout...');
|
|
1597
|
+
// Validate mobile layout tables access
|
|
1598
|
+
const layoutTableCheck = await this.client.searchRecords('sys_mobile_layout', '', 1);
|
|
1599
|
+
if (!layoutTableCheck.success) {
|
|
1600
|
+
return {
|
|
1601
|
+
success: false,
|
|
1602
|
+
error: 'Mobile layout tables not accessible. Requires ServiceNow Mobile Publishing plugin and Mobile Device Management licensing.',
|
|
1603
|
+
suggestion: 'Install Mobile Publishing plugin from ServiceNow Store. Contact ServiceNow sales for Mobile Application Management licensing.',
|
|
1604
|
+
alternative: 'Use Service Portal widgets for mobile-responsive interfaces instead.'
|
|
1605
|
+
};
|
|
1606
|
+
}
|
|
1081
1607
|
const layoutData = {
|
|
1082
1608
|
name: args.name,
|
|
1083
1609
|
table: args.table,
|
|
@@ -1153,6 +1679,16 @@ ${workspaceList.join('\n\n')}
|
|
|
1153
1679
|
async configureOfflineSync(args) {
|
|
1154
1680
|
try {
|
|
1155
1681
|
this.logger.info('Configuring offline sync...');
|
|
1682
|
+
// Validate offline sync capabilities
|
|
1683
|
+
const syncTableCheck = await this.client.searchRecords('sys_offline_sync', '', 1);
|
|
1684
|
+
if (!syncTableCheck.success) {
|
|
1685
|
+
return {
|
|
1686
|
+
success: false,
|
|
1687
|
+
error: 'Offline sync not available. Requires ServiceNow Mobile Publishing plugin with offline capabilities.',
|
|
1688
|
+
suggestion: 'Install Mobile Publishing plugin for offline sync. Alternative: Use ServiceNow Agent mobile app for basic offline access.',
|
|
1689
|
+
licensing_note: 'Offline sync requires Mobile Publishing licensing (paid plugin)'
|
|
1690
|
+
};
|
|
1691
|
+
}
|
|
1156
1692
|
const syncConfig = {
|
|
1157
1693
|
table: args.table,
|
|
1158
1694
|
filter: args.filter || '',
|
|
@@ -1308,6 +1844,982 @@ ${configList}${layoutsText}${offlineText}
|
|
|
1308
1844
|
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError, `Failed to discover mobile configs: ${error}`);
|
|
1309
1845
|
}
|
|
1310
1846
|
}
|
|
1847
|
+
// ==========================================
|
|
1848
|
+
// UI BUILDER IMPLEMENTATION METHODS
|
|
1849
|
+
// Official ServiceNow sys_ux_* API implementations
|
|
1850
|
+
// ==========================================
|
|
1851
|
+
/**
|
|
1852
|
+
* Create UI Builder Page using sys_ux_page table
|
|
1853
|
+
*/
|
|
1854
|
+
async createUIBPage(args) {
|
|
1855
|
+
try {
|
|
1856
|
+
this.logger.info(`🏗️ Creating UI Builder page: ${args.name}`);
|
|
1857
|
+
// Create the page in sys_ux_page table
|
|
1858
|
+
const pageData = {
|
|
1859
|
+
name: args.name,
|
|
1860
|
+
title: args.title,
|
|
1861
|
+
description: args.description || '',
|
|
1862
|
+
application: args.application || 'global',
|
|
1863
|
+
theme: args.theme || 'standard',
|
|
1864
|
+
layout_type: args.layout_type || 'container',
|
|
1865
|
+
responsive: args.responsive !== false,
|
|
1866
|
+
public_read: args.public_read || false,
|
|
1867
|
+
active: args.active !== false
|
|
1868
|
+
};
|
|
1869
|
+
const pageResponse = await this.client.createRecord('sys_ux_page', pageData);
|
|
1870
|
+
if (!pageResponse.success) {
|
|
1871
|
+
throw new Error(`Failed to create UI Builder page: ${pageResponse.error}`);
|
|
1872
|
+
}
|
|
1873
|
+
const page = pageResponse.data;
|
|
1874
|
+
// Create page registry entry for routing
|
|
1875
|
+
const registryData = {
|
|
1876
|
+
page: page.sys_id,
|
|
1877
|
+
path: args.route,
|
|
1878
|
+
application: args.application || 'global',
|
|
1879
|
+
public_access: args.public_read || false,
|
|
1880
|
+
active: true
|
|
1881
|
+
};
|
|
1882
|
+
const registryResponse = await this.client.createRecord('sys_ux_page_registry', registryData);
|
|
1883
|
+
this.logger.info(`✅ UI Builder page created successfully: ${page.sys_id}`);
|
|
1884
|
+
return {
|
|
1885
|
+
success: true,
|
|
1886
|
+
page: page,
|
|
1887
|
+
route: registryResponse.success ? registryResponse.data : null,
|
|
1888
|
+
message: `UI Builder page '${args.name}' created with route '${args.route}'`
|
|
1889
|
+
};
|
|
1890
|
+
}
|
|
1891
|
+
catch (error) {
|
|
1892
|
+
this.logger.error('Failed to create UI Builder page:', error);
|
|
1893
|
+
throw error;
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
/**
|
|
1897
|
+
* Update UI Builder Page
|
|
1898
|
+
*/
|
|
1899
|
+
async updateUIBPage(args) {
|
|
1900
|
+
try {
|
|
1901
|
+
this.logger.info(`🔧 Updating UI Builder page: ${args.page_id}`);
|
|
1902
|
+
const updates = {};
|
|
1903
|
+
if (args.title)
|
|
1904
|
+
updates.title = args.title;
|
|
1905
|
+
if (args.description)
|
|
1906
|
+
updates.description = args.description;
|
|
1907
|
+
if (args.theme)
|
|
1908
|
+
updates.theme = args.theme;
|
|
1909
|
+
if (args.layout_type)
|
|
1910
|
+
updates.layout_type = args.layout_type;
|
|
1911
|
+
if (typeof args.responsive === 'boolean')
|
|
1912
|
+
updates.responsive = args.responsive;
|
|
1913
|
+
if (typeof args.active === 'boolean')
|
|
1914
|
+
updates.active = args.active;
|
|
1915
|
+
const response = await this.client.updateRecord('sys_ux_page', args.page_id, updates);
|
|
1916
|
+
if (!response.success) {
|
|
1917
|
+
throw new Error(`Failed to update UI Builder page: ${response.error}`);
|
|
1918
|
+
}
|
|
1919
|
+
this.logger.info('✅ UI Builder page updated successfully');
|
|
1920
|
+
return {
|
|
1921
|
+
success: true,
|
|
1922
|
+
page: response.data,
|
|
1923
|
+
message: `UI Builder page updated successfully`
|
|
1924
|
+
};
|
|
1925
|
+
}
|
|
1926
|
+
catch (error) {
|
|
1927
|
+
this.logger.error('Failed to update UI Builder page:', error);
|
|
1928
|
+
throw error;
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
/**
|
|
1932
|
+
* Delete UI Builder Page with dependency validation
|
|
1933
|
+
*/
|
|
1934
|
+
async deleteUIBPage(args) {
|
|
1935
|
+
try {
|
|
1936
|
+
this.logger.info(`🗑️ Deleting UI Builder page: ${args.page_id}`);
|
|
1937
|
+
// Check dependencies if validation enabled
|
|
1938
|
+
if (!args.force_delete) {
|
|
1939
|
+
const elementsResponse = await this.client.searchRecords('sys_ux_page_element', `page=${args.page_id}`, 1);
|
|
1940
|
+
if (elementsResponse.success && elementsResponse.data.result.length > 0) {
|
|
1941
|
+
return {
|
|
1942
|
+
success: false,
|
|
1943
|
+
error: 'Page has elements. Use force_delete: true to override or manually remove elements first.',
|
|
1944
|
+
dependencies: elementsResponse.data.result.length
|
|
1945
|
+
};
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
// Clean up associated records first
|
|
1949
|
+
if (args.clean_orphaned_elements) {
|
|
1950
|
+
const elementsResponse = await this.client.searchRecords('sys_ux_page_element', `page=${args.page_id}`);
|
|
1951
|
+
if (elementsResponse.success) {
|
|
1952
|
+
for (const element of elementsResponse.data.result) {
|
|
1953
|
+
await this.client.deleteRecord('sys_ux_page_element', element.sys_id);
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
// Delete page registry entries
|
|
1958
|
+
const registryResponse = await this.client.searchRecords('sys_ux_page_registry', `page=${args.page_id}`);
|
|
1959
|
+
if (registryResponse.success) {
|
|
1960
|
+
for (const registry of registryResponse.data.result) {
|
|
1961
|
+
await this.client.deleteRecord('sys_ux_page_registry', registry.sys_id);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
// Delete the page
|
|
1965
|
+
const deleteResponse = await this.client.deleteRecord('sys_ux_page', args.page_id);
|
|
1966
|
+
if (!deleteResponse.success) {
|
|
1967
|
+
throw new Error(`Failed to delete UI Builder page: ${deleteResponse.error}`);
|
|
1968
|
+
}
|
|
1969
|
+
this.logger.info('✅ UI Builder page deleted successfully');
|
|
1970
|
+
return {
|
|
1971
|
+
success: true,
|
|
1972
|
+
message: 'UI Builder page and associated configurations deleted successfully'
|
|
1973
|
+
};
|
|
1974
|
+
}
|
|
1975
|
+
catch (error) {
|
|
1976
|
+
this.logger.error('Failed to delete UI Builder page:', error);
|
|
1977
|
+
throw error;
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
/**
|
|
1981
|
+
* Discover UI Builder Pages
|
|
1982
|
+
*/
|
|
1983
|
+
async discoverUIBPages(args) {
|
|
1984
|
+
try {
|
|
1985
|
+
this.logger.info('🔍 Discovering UI Builder pages...');
|
|
1986
|
+
const conditions = [];
|
|
1987
|
+
if (args.active_only)
|
|
1988
|
+
conditions.push('active=true');
|
|
1989
|
+
if (args.application)
|
|
1990
|
+
conditions.push(`application=${args.application}`);
|
|
1991
|
+
if (args.name_filter)
|
|
1992
|
+
conditions.push(`nameLIKE${args.name_filter}`);
|
|
1993
|
+
if (args.theme_filter)
|
|
1994
|
+
conditions.push(`theme=${args.theme_filter}`);
|
|
1995
|
+
const query = conditions.join('^');
|
|
1996
|
+
const pagesResponse = await this.client.searchRecords('sys_ux_page', query, args.limit || 50);
|
|
1997
|
+
if (!pagesResponse.success) {
|
|
1998
|
+
throw new Error(`Failed to discover UI Builder pages: ${pagesResponse.error}`);
|
|
1999
|
+
}
|
|
2000
|
+
const pages = pagesResponse.data.result;
|
|
2001
|
+
// Enrich with additional data if requested
|
|
2002
|
+
for (const page of pages) {
|
|
2003
|
+
if (args.include_routing) {
|
|
2004
|
+
const routeResponse = await this.client.searchRecords('sys_ux_page_registry', `page=${page.sys_id}`, 10);
|
|
2005
|
+
page.routes = routeResponse.success ? routeResponse.data.result : [];
|
|
2006
|
+
}
|
|
2007
|
+
if (args.include_elements) {
|
|
2008
|
+
const elementsResponse = await this.client.searchRecords('sys_ux_page_element', `page=${page.sys_id}`, 100);
|
|
2009
|
+
page.elements = elementsResponse.success ? elementsResponse.data.result : [];
|
|
2010
|
+
}
|
|
2011
|
+
if (args.include_data_brokers) {
|
|
2012
|
+
const brokersResponse = await this.client.searchRecords('sys_ux_data_broker', `page=${page.sys_id}`, 50);
|
|
2013
|
+
page.data_brokers = brokersResponse.success ? brokersResponse.data.result : [];
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
this.logger.info(`✅ Found ${pages.length} UI Builder pages`);
|
|
2017
|
+
return {
|
|
2018
|
+
success: true,
|
|
2019
|
+
pages: pages,
|
|
2020
|
+
count: pages.length
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
catch (error) {
|
|
2024
|
+
this.logger.error('Failed to discover UI Builder pages:', error);
|
|
2025
|
+
throw error;
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
/**
|
|
2029
|
+
* Create UI Builder Component using sys_ux_lib_component and sys_ux_lib_source_script
|
|
2030
|
+
*/
|
|
2031
|
+
async createUIBComponent(args) {
|
|
2032
|
+
try {
|
|
2033
|
+
this.logger.info(`🧩 Creating UI Builder component: ${args.name}`);
|
|
2034
|
+
// First create the source script
|
|
2035
|
+
const sourceData = {
|
|
2036
|
+
name: args.name,
|
|
2037
|
+
source: args.source_script,
|
|
2038
|
+
version: args.version || '1.0.0',
|
|
2039
|
+
active: true
|
|
2040
|
+
};
|
|
2041
|
+
const sourceResponse = await this.client.createRecord('sys_ux_lib_source_script', sourceData);
|
|
2042
|
+
if (!sourceResponse.success) {
|
|
2043
|
+
throw new Error(`Failed to create component source: ${sourceResponse.error}`);
|
|
2044
|
+
}
|
|
2045
|
+
// Then create the component definition
|
|
2046
|
+
const componentData = {
|
|
2047
|
+
name: args.name,
|
|
2048
|
+
label: args.label,
|
|
2049
|
+
description: args.description || '',
|
|
2050
|
+
category: args.category || 'custom',
|
|
2051
|
+
source_script: sourceResponse.data.sys_id,
|
|
2052
|
+
properties_schema: args.properties_schema ? JSON.stringify(args.properties_schema) : '{}',
|
|
2053
|
+
events: args.events ? args.events.join(',') : '',
|
|
2054
|
+
dependencies: args.dependencies ? args.dependencies.join(',') : '',
|
|
2055
|
+
styling: args.styling ? JSON.stringify(args.styling) : '{}',
|
|
2056
|
+
version: args.version || '1.0.0',
|
|
2057
|
+
tags: args.tags ? args.tags.join(',') : '',
|
|
2058
|
+
active: true
|
|
2059
|
+
};
|
|
2060
|
+
const componentResponse = await this.client.createRecord('sys_ux_lib_component', componentData);
|
|
2061
|
+
if (!componentResponse.success) {
|
|
2062
|
+
// Cleanup source script on failure
|
|
2063
|
+
await this.client.deleteRecord('sys_ux_lib_source_script', sourceResponse.data.sys_id);
|
|
2064
|
+
throw new Error(`Failed to create component: ${componentResponse.error}`);
|
|
2065
|
+
}
|
|
2066
|
+
this.logger.info('✅ UI Builder component created successfully');
|
|
2067
|
+
return {
|
|
2068
|
+
success: true,
|
|
2069
|
+
component: componentResponse.data,
|
|
2070
|
+
source_script: sourceResponse.data,
|
|
2071
|
+
message: `Custom UI Builder component '${args.name}' created successfully`
|
|
2072
|
+
};
|
|
2073
|
+
}
|
|
2074
|
+
catch (error) {
|
|
2075
|
+
this.logger.error('Failed to create UI Builder component:', error);
|
|
2076
|
+
throw error;
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
/**
|
|
2080
|
+
* Update UI Builder Component
|
|
2081
|
+
*/
|
|
2082
|
+
async updateUIBComponent(args) {
|
|
2083
|
+
try {
|
|
2084
|
+
this.logger.info(`🔧 Updating UI Builder component: ${args.component_id}`);
|
|
2085
|
+
const updates = {};
|
|
2086
|
+
if (args.label)
|
|
2087
|
+
updates.label = args.label;
|
|
2088
|
+
if (args.description)
|
|
2089
|
+
updates.description = args.description;
|
|
2090
|
+
if (args.properties_schema)
|
|
2091
|
+
updates.properties_schema = JSON.stringify(args.properties_schema);
|
|
2092
|
+
if (args.styling)
|
|
2093
|
+
updates.styling = JSON.stringify(args.styling);
|
|
2094
|
+
if (args.version)
|
|
2095
|
+
updates.version = args.version;
|
|
2096
|
+
if (args.events)
|
|
2097
|
+
updates.events = args.events.join(',');
|
|
2098
|
+
if (args.dependencies)
|
|
2099
|
+
updates.dependencies = args.dependencies.join(',');
|
|
2100
|
+
if (typeof args.active === 'boolean')
|
|
2101
|
+
updates.active = args.active;
|
|
2102
|
+
const componentResponse = await this.client.updateRecord('sys_ux_lib_component', args.component_id, updates);
|
|
2103
|
+
if (!componentResponse.success) {
|
|
2104
|
+
throw new Error(`Failed to update component: ${componentResponse.error}`);
|
|
2105
|
+
}
|
|
2106
|
+
// Update source script if provided
|
|
2107
|
+
if (args.source_script) {
|
|
2108
|
+
const component = componentResponse.data;
|
|
2109
|
+
if (component.source_script) {
|
|
2110
|
+
await this.client.updateRecord('sys_ux_lib_source_script', component.source_script, {
|
|
2111
|
+
source: args.source_script,
|
|
2112
|
+
version: args.version || component.version
|
|
2113
|
+
});
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
this.logger.info('✅ UI Builder component updated successfully');
|
|
2117
|
+
return {
|
|
2118
|
+
success: true,
|
|
2119
|
+
component: componentResponse.data,
|
|
2120
|
+
message: 'UI Builder component updated successfully'
|
|
2121
|
+
};
|
|
2122
|
+
}
|
|
2123
|
+
catch (error) {
|
|
2124
|
+
this.logger.error('Failed to update UI Builder component:', error);
|
|
2125
|
+
throw error;
|
|
2126
|
+
}
|
|
2127
|
+
}
|
|
2128
|
+
/**
|
|
2129
|
+
* Discover UI Builder Components
|
|
2130
|
+
*/
|
|
2131
|
+
async discoverUIBComponents(args) {
|
|
2132
|
+
try {
|
|
2133
|
+
this.logger.info('🔍 Discovering UI Builder components...');
|
|
2134
|
+
const conditions = [];
|
|
2135
|
+
if (args.category)
|
|
2136
|
+
conditions.push(`category=${args.category}`);
|
|
2137
|
+
if (args.custom_only)
|
|
2138
|
+
conditions.push('category=custom');
|
|
2139
|
+
if (args.built_in_only)
|
|
2140
|
+
conditions.push('category!=custom');
|
|
2141
|
+
if (args.name_filter)
|
|
2142
|
+
conditions.push(`nameLIKE${args.name_filter}^ORlabelLIKE${args.name_filter}`);
|
|
2143
|
+
if (args.version_filter)
|
|
2144
|
+
conditions.push(`versionLIKE${args.version_filter}`);
|
|
2145
|
+
if (args.application)
|
|
2146
|
+
conditions.push(`application=${args.application}`);
|
|
2147
|
+
const query = conditions.join('^');
|
|
2148
|
+
const componentsResponse = await this.client.searchRecords('sys_ux_lib_component', query, args.limit || 100);
|
|
2149
|
+
if (!componentsResponse.success) {
|
|
2150
|
+
throw new Error(`Failed to discover components: ${componentsResponse.error}`);
|
|
2151
|
+
}
|
|
2152
|
+
const components = componentsResponse.data.result;
|
|
2153
|
+
// Enrich with additional data if requested
|
|
2154
|
+
for (const component of components) {
|
|
2155
|
+
if (args.include_source && component.source_script) {
|
|
2156
|
+
const sourceResponse = await this.client.getRecord('sys_ux_lib_source_script', component.source_script);
|
|
2157
|
+
component.source_code = sourceResponse.success ? sourceResponse.data : null;
|
|
2158
|
+
}
|
|
2159
|
+
if (args.include_usage_stats) {
|
|
2160
|
+
const usageResponse = await this.client.searchRecords('sys_ux_page_element', `component=${component.sys_id}^ORcomponent=${component.name}`);
|
|
2161
|
+
component.usage_count = usageResponse.success ? usageResponse.data.result.length : 0;
|
|
2162
|
+
}
|
|
2163
|
+
if (args.include_dependencies && component.dependencies) {
|
|
2164
|
+
component.dependency_list = component.dependencies.split(',').map(d => d.trim()).filter(d => d);
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
this.logger.info(`✅ Found ${components.length} UI Builder components`);
|
|
2168
|
+
return {
|
|
2169
|
+
success: true,
|
|
2170
|
+
components: components,
|
|
2171
|
+
count: components.length
|
|
2172
|
+
};
|
|
2173
|
+
}
|
|
2174
|
+
catch (error) {
|
|
2175
|
+
this.logger.error('Failed to discover UI Builder components:', error);
|
|
2176
|
+
throw error;
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
/**
|
|
2180
|
+
* Clone UI Builder Component
|
|
2181
|
+
*/
|
|
2182
|
+
async cloneUIBComponent(args) {
|
|
2183
|
+
try {
|
|
2184
|
+
this.logger.info(`📋 Cloning UI Builder component: ${args.source_component_id} → ${args.new_name}`);
|
|
2185
|
+
// Get source component
|
|
2186
|
+
const sourceResponse = await this.client.getRecord('sys_ux_lib_component', args.source_component_id);
|
|
2187
|
+
if (!sourceResponse.success) {
|
|
2188
|
+
throw new Error(`Source component not found: ${args.source_component_id}`);
|
|
2189
|
+
}
|
|
2190
|
+
const sourceComponent = sourceResponse.data;
|
|
2191
|
+
// Get source script
|
|
2192
|
+
let sourceCode = '';
|
|
2193
|
+
if (sourceComponent.source_script) {
|
|
2194
|
+
const sourceScriptResponse = await this.client.getRecord('sys_ux_lib_source_script', sourceComponent.source_script);
|
|
2195
|
+
if (sourceScriptResponse.success) {
|
|
2196
|
+
sourceCode = sourceScriptResponse.data.source || '';
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
// Apply modifications to source code if provided
|
|
2200
|
+
if (args.modifications) {
|
|
2201
|
+
for (const [find, replace] of Object.entries(args.modifications)) {
|
|
2202
|
+
sourceCode = sourceCode.replace(new RegExp(find, 'g'), replace);
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
// Create cloned component
|
|
2206
|
+
const cloneData = {
|
|
2207
|
+
name: args.new_name,
|
|
2208
|
+
label: args.new_label,
|
|
2209
|
+
description: args.description || `Clone of ${sourceComponent.label}`,
|
|
2210
|
+
category: args.category || 'custom',
|
|
2211
|
+
source_script: sourceCode,
|
|
2212
|
+
properties_schema: sourceComponent.properties_schema,
|
|
2213
|
+
events: sourceComponent.events,
|
|
2214
|
+
dependencies: sourceComponent.dependencies,
|
|
2215
|
+
styling: sourceComponent.styling,
|
|
2216
|
+
version: args.version || '1.0.0'
|
|
2217
|
+
};
|
|
2218
|
+
const cloneResult = await this.createUIBComponent(cloneData);
|
|
2219
|
+
this.logger.info('✅ UI Builder component cloned successfully');
|
|
2220
|
+
return {
|
|
2221
|
+
success: true,
|
|
2222
|
+
cloned_component: cloneResult.component,
|
|
2223
|
+
source_component: sourceComponent,
|
|
2224
|
+
message: `Component '${args.new_name}' cloned from '${sourceComponent.label}'`
|
|
2225
|
+
};
|
|
2226
|
+
}
|
|
2227
|
+
catch (error) {
|
|
2228
|
+
this.logger.error('Failed to clone UI Builder component:', error);
|
|
2229
|
+
throw error;
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
/**
|
|
2233
|
+
* Create UI Builder Data Broker
|
|
2234
|
+
*/
|
|
2235
|
+
async createUIBDataBroker(args) {
|
|
2236
|
+
try {
|
|
2237
|
+
this.logger.info(`🔗 Creating UI Builder data broker: ${args.name}`);
|
|
2238
|
+
const brokerData = {
|
|
2239
|
+
name: args.name,
|
|
2240
|
+
label: args.label,
|
|
2241
|
+
type: args.type || 'table',
|
|
2242
|
+
table: args.table || '',
|
|
2243
|
+
query: args.query || '',
|
|
2244
|
+
script: args.script || '',
|
|
2245
|
+
rest_message: args.rest_message || '',
|
|
2246
|
+
fields: args.fields ? args.fields.join(',') : '',
|
|
2247
|
+
auto_refresh: args.auto_refresh || false,
|
|
2248
|
+
refresh_interval: args.refresh_interval || 30,
|
|
2249
|
+
cache_duration: args.cache_duration || 300,
|
|
2250
|
+
max_records: args.max_records || 1000,
|
|
2251
|
+
active: true
|
|
2252
|
+
};
|
|
2253
|
+
const response = await this.client.createRecord('sys_ux_data_broker', brokerData);
|
|
2254
|
+
if (!response.success) {
|
|
2255
|
+
throw new Error(`Failed to create data broker: ${response.error}`);
|
|
2256
|
+
}
|
|
2257
|
+
this.logger.info('✅ UI Builder data broker created successfully');
|
|
2258
|
+
return {
|
|
2259
|
+
success: true,
|
|
2260
|
+
data_broker: response.data,
|
|
2261
|
+
message: `Data broker '${args.name}' created for ${args.type} type`
|
|
2262
|
+
};
|
|
2263
|
+
}
|
|
2264
|
+
catch (error) {
|
|
2265
|
+
this.logger.error('Failed to create UI Builder data broker:', error);
|
|
2266
|
+
throw error;
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
/**
|
|
2270
|
+
* Configure UI Builder Data Broker
|
|
2271
|
+
*/
|
|
2272
|
+
async configureUIBDataBroker(args) {
|
|
2273
|
+
try {
|
|
2274
|
+
this.logger.info(`⚙️ Configuring UI Builder data broker: ${args.broker_id}`);
|
|
2275
|
+
const updates = {};
|
|
2276
|
+
if (args.query)
|
|
2277
|
+
updates.query = args.query;
|
|
2278
|
+
if (args.fields)
|
|
2279
|
+
updates.fields = args.fields.join(',');
|
|
2280
|
+
if (typeof args.auto_refresh === 'boolean')
|
|
2281
|
+
updates.auto_refresh = args.auto_refresh;
|
|
2282
|
+
if (args.refresh_interval)
|
|
2283
|
+
updates.refresh_interval = args.refresh_interval;
|
|
2284
|
+
if (args.cache_duration)
|
|
2285
|
+
updates.cache_duration = args.cache_duration;
|
|
2286
|
+
if (args.max_records)
|
|
2287
|
+
updates.max_records = args.max_records;
|
|
2288
|
+
if (typeof args.active === 'boolean')
|
|
2289
|
+
updates.active = args.active;
|
|
2290
|
+
const response = await this.client.updateRecord('sys_ux_data_broker', args.broker_id, updates);
|
|
2291
|
+
if (!response.success) {
|
|
2292
|
+
throw new Error(`Failed to configure data broker: ${response.error}`);
|
|
2293
|
+
}
|
|
2294
|
+
this.logger.info('✅ UI Builder data broker configured successfully');
|
|
2295
|
+
return {
|
|
2296
|
+
success: true,
|
|
2297
|
+
data_broker: response.data,
|
|
2298
|
+
message: 'Data broker configuration updated successfully'
|
|
2299
|
+
};
|
|
2300
|
+
}
|
|
2301
|
+
catch (error) {
|
|
2302
|
+
this.logger.error('Failed to configure UI Builder data broker:', error);
|
|
2303
|
+
throw error;
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
/**
|
|
2307
|
+
* Add UI Builder Page Element
|
|
2308
|
+
*/
|
|
2309
|
+
async addUIBPageElement(args) {
|
|
2310
|
+
try {
|
|
2311
|
+
this.logger.info(`➕ Adding element to UI Builder page: ${args.component}`);
|
|
2312
|
+
const elementData = {
|
|
2313
|
+
page: args.page_id,
|
|
2314
|
+
component: args.component,
|
|
2315
|
+
container_id: args.container_id || '',
|
|
2316
|
+
position: args.position || 0,
|
|
2317
|
+
properties: args.properties ? JSON.stringify(args.properties) : '{}',
|
|
2318
|
+
data_broker: args.data_broker || '',
|
|
2319
|
+
responsive_config: args.responsive_config ? JSON.stringify(args.responsive_config) : '{}',
|
|
2320
|
+
conditional_display: args.conditional_display || '',
|
|
2321
|
+
css_classes: args.css_classes ? args.css_classes.join(' ') : '',
|
|
2322
|
+
inline_styles: args.inline_styles ? JSON.stringify(args.inline_styles) : '{}',
|
|
2323
|
+
active: true
|
|
2324
|
+
};
|
|
2325
|
+
const response = await this.client.createRecord('sys_ux_page_element', elementData);
|
|
2326
|
+
if (!response.success) {
|
|
2327
|
+
throw new Error(`Failed to add page element: ${response.error}`);
|
|
2328
|
+
}
|
|
2329
|
+
this.logger.info('✅ UI Builder page element added successfully');
|
|
2330
|
+
return {
|
|
2331
|
+
success: true,
|
|
2332
|
+
element: response.data,
|
|
2333
|
+
message: `Component '${args.component}' added to page successfully`
|
|
2334
|
+
};
|
|
2335
|
+
}
|
|
2336
|
+
catch (error) {
|
|
2337
|
+
this.logger.error('Failed to add UI Builder page element:', error);
|
|
2338
|
+
throw error;
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
/**
|
|
2342
|
+
* Update UI Builder Page Element
|
|
2343
|
+
*/
|
|
2344
|
+
async updateUIBPageElement(args) {
|
|
2345
|
+
try {
|
|
2346
|
+
this.logger.info(`🔧 Updating UI Builder page element: ${args.element_id}`);
|
|
2347
|
+
const updates = {};
|
|
2348
|
+
if (args.properties)
|
|
2349
|
+
updates.properties = JSON.stringify(args.properties);
|
|
2350
|
+
if (args.position !== undefined)
|
|
2351
|
+
updates.position = args.position;
|
|
2352
|
+
if (args.data_broker)
|
|
2353
|
+
updates.data_broker = args.data_broker;
|
|
2354
|
+
if (args.responsive_config)
|
|
2355
|
+
updates.responsive_config = JSON.stringify(args.responsive_config);
|
|
2356
|
+
if (args.conditional_display)
|
|
2357
|
+
updates.conditional_display = args.conditional_display;
|
|
2358
|
+
if (args.css_classes)
|
|
2359
|
+
updates.css_classes = args.css_classes.join(' ');
|
|
2360
|
+
if (args.inline_styles)
|
|
2361
|
+
updates.inline_styles = JSON.stringify(args.inline_styles);
|
|
2362
|
+
const response = await this.client.updateRecord('sys_ux_page_element', args.element_id, updates);
|
|
2363
|
+
if (!response.success) {
|
|
2364
|
+
throw new Error(`Failed to update page element: ${response.error}`);
|
|
2365
|
+
}
|
|
2366
|
+
this.logger.info('✅ UI Builder page element updated successfully');
|
|
2367
|
+
return {
|
|
2368
|
+
success: true,
|
|
2369
|
+
element: response.data,
|
|
2370
|
+
message: 'Page element updated successfully'
|
|
2371
|
+
};
|
|
2372
|
+
}
|
|
2373
|
+
catch (error) {
|
|
2374
|
+
this.logger.error('Failed to update UI Builder page element:', error);
|
|
2375
|
+
throw error;
|
|
2376
|
+
}
|
|
2377
|
+
}
|
|
2378
|
+
/**
|
|
2379
|
+
* Remove UI Builder Page Element
|
|
2380
|
+
*/
|
|
2381
|
+
async removeUIBPageElement(args) {
|
|
2382
|
+
try {
|
|
2383
|
+
this.logger.info(`🗑️ Removing UI Builder page element: ${args.element_id}`);
|
|
2384
|
+
// Validate dependencies if requested
|
|
2385
|
+
if (args.validate_dependencies) {
|
|
2386
|
+
const dependentResponse = await this.client.searchRecords('sys_ux_page_element', `container_id=${args.element_id}`, 10);
|
|
2387
|
+
if (dependentResponse.success && dependentResponse.data.result.length > 0) {
|
|
2388
|
+
return {
|
|
2389
|
+
success: false,
|
|
2390
|
+
error: 'Element has dependent child elements. Remove children first or use validate_dependencies: false',
|
|
2391
|
+
dependent_elements: dependentResponse.data.result.length
|
|
2392
|
+
};
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
const response = await this.client.deleteRecord('sys_ux_page_element', args.element_id);
|
|
2396
|
+
if (!response.success) {
|
|
2397
|
+
throw new Error(`Failed to remove page element: ${response.error}`);
|
|
2398
|
+
}
|
|
2399
|
+
this.logger.info('✅ UI Builder page element removed successfully');
|
|
2400
|
+
return {
|
|
2401
|
+
success: true,
|
|
2402
|
+
message: 'Page element removed successfully'
|
|
2403
|
+
};
|
|
2404
|
+
}
|
|
2405
|
+
catch (error) {
|
|
2406
|
+
this.logger.error('Failed to remove UI Builder page element:', error);
|
|
2407
|
+
throw error;
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
/**
|
|
2411
|
+
* Create UI Builder Page Registry (Routing)
|
|
2412
|
+
*/
|
|
2413
|
+
async createUIBPageRegistry(args) {
|
|
2414
|
+
try {
|
|
2415
|
+
this.logger.info(`🛣️ Creating UI Builder page registry: ${args.path}`);
|
|
2416
|
+
const registryData = {
|
|
2417
|
+
page: args.page_id,
|
|
2418
|
+
path: args.path,
|
|
2419
|
+
application: args.application || 'global',
|
|
2420
|
+
roles: args.roles ? args.roles.join(',') : '',
|
|
2421
|
+
public_access: args.public_access || false,
|
|
2422
|
+
redirect_url: args.redirect_url || '',
|
|
2423
|
+
meta_title: args.meta_title || '',
|
|
2424
|
+
meta_description: args.meta_description || '',
|
|
2425
|
+
parameter_mapping: args.parameter_mapping ? JSON.stringify(args.parameter_mapping) : '{}',
|
|
2426
|
+
cache_control: args.cache_control || '',
|
|
2427
|
+
active: true
|
|
2428
|
+
};
|
|
2429
|
+
const response = await this.client.createRecord('sys_ux_page_registry', registryData);
|
|
2430
|
+
if (!response.success) {
|
|
2431
|
+
throw new Error(`Failed to create page registry: ${response.error}`);
|
|
2432
|
+
}
|
|
2433
|
+
this.logger.info('✅ UI Builder page registry created successfully');
|
|
2434
|
+
return {
|
|
2435
|
+
success: true,
|
|
2436
|
+
registry: response.data,
|
|
2437
|
+
message: `Page routing configured for path '${args.path}'`
|
|
2438
|
+
};
|
|
2439
|
+
}
|
|
2440
|
+
catch (error) {
|
|
2441
|
+
this.logger.error('Failed to create UI Builder page registry:', error);
|
|
2442
|
+
throw error;
|
|
2443
|
+
}
|
|
2444
|
+
}
|
|
2445
|
+
/**
|
|
2446
|
+
* Discover UI Builder Routes
|
|
2447
|
+
*/
|
|
2448
|
+
async discoverUIBRoutes(args) {
|
|
2449
|
+
try {
|
|
2450
|
+
this.logger.info('🔍 Discovering UI Builder routes...');
|
|
2451
|
+
const conditions = [];
|
|
2452
|
+
if (args.application)
|
|
2453
|
+
conditions.push(`application=${args.application}`);
|
|
2454
|
+
if (args.active_only)
|
|
2455
|
+
conditions.push('active=true');
|
|
2456
|
+
if (args.path_pattern)
|
|
2457
|
+
conditions.push(`pathLIKE${args.path_pattern}`);
|
|
2458
|
+
if (args.role_filter)
|
|
2459
|
+
conditions.push(`rolesLIKE${args.role_filter}`);
|
|
2460
|
+
const query = conditions.join('^');
|
|
2461
|
+
const routesResponse = await this.client.searchRecords('sys_ux_page_registry', query, 100);
|
|
2462
|
+
if (!routesResponse.success) {
|
|
2463
|
+
throw new Error(`Failed to discover routes: ${routesResponse.error}`);
|
|
2464
|
+
}
|
|
2465
|
+
const routes = routesResponse.data.result;
|
|
2466
|
+
// Enrich with additional data if requested
|
|
2467
|
+
for (const route of routes) {
|
|
2468
|
+
if (args.include_security && route.roles) {
|
|
2469
|
+
route.required_roles = route.roles.split(',').map(r => r.trim()).filter(r => r);
|
|
2470
|
+
}
|
|
2471
|
+
if (args.include_parameters && route.parameter_mapping) {
|
|
2472
|
+
try {
|
|
2473
|
+
route.parameters = JSON.parse(route.parameter_mapping);
|
|
2474
|
+
}
|
|
2475
|
+
catch (e) {
|
|
2476
|
+
route.parameters = {};
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
2479
|
+
// Add page information
|
|
2480
|
+
if (route.page) {
|
|
2481
|
+
const pageResponse = await this.client.getRecord('sys_ux_page', route.page);
|
|
2482
|
+
route.page_info = pageResponse.success ? pageResponse.data : null;
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
this.logger.info(`✅ Found ${routes.length} UI Builder routes`);
|
|
2486
|
+
return {
|
|
2487
|
+
success: true,
|
|
2488
|
+
routes: routes,
|
|
2489
|
+
count: routes.length
|
|
2490
|
+
};
|
|
2491
|
+
}
|
|
2492
|
+
catch (error) {
|
|
2493
|
+
this.logger.error('Failed to discover UI Builder routes:', error);
|
|
2494
|
+
throw error;
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
/**
|
|
2498
|
+
* Create UI Builder Client Script
|
|
2499
|
+
*/
|
|
2500
|
+
async createUIBClientScript(args) {
|
|
2501
|
+
try {
|
|
2502
|
+
this.logger.info(`📝 Creating UI Builder client script: ${args.name}`);
|
|
2503
|
+
const scriptData = {
|
|
2504
|
+
page: args.page_id,
|
|
2505
|
+
name: args.name,
|
|
2506
|
+
type: args.type,
|
|
2507
|
+
script: args.script,
|
|
2508
|
+
component_reference: args.component_reference || '',
|
|
2509
|
+
event_name: args.event_name || '',
|
|
2510
|
+
execution_order: args.execution_order || 100,
|
|
2511
|
+
async_execution: args.async_execution || false,
|
|
2512
|
+
error_handling: args.error_handling || 'log',
|
|
2513
|
+
active: args.active !== false
|
|
2514
|
+
};
|
|
2515
|
+
const response = await this.client.createRecord('sys_ux_client_script', scriptData);
|
|
2516
|
+
if (!response.success) {
|
|
2517
|
+
throw new Error(`Failed to create client script: ${response.error}`);
|
|
2518
|
+
}
|
|
2519
|
+
this.logger.info('✅ UI Builder client script created successfully');
|
|
2520
|
+
return {
|
|
2521
|
+
success: true,
|
|
2522
|
+
script: response.data,
|
|
2523
|
+
message: `Client script '${args.name}' created for ${args.type} trigger`
|
|
2524
|
+
};
|
|
2525
|
+
}
|
|
2526
|
+
catch (error) {
|
|
2527
|
+
this.logger.error('Failed to create UI Builder client script:', error);
|
|
2528
|
+
throw error;
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
/**
|
|
2532
|
+
* Create UI Builder Client State
|
|
2533
|
+
*/
|
|
2534
|
+
async createUIBClientState(args) {
|
|
2535
|
+
try {
|
|
2536
|
+
this.logger.info(`💾 Creating UI Builder client state: ${args.state_name}`);
|
|
2537
|
+
const stateData = {
|
|
2538
|
+
page: args.page_id,
|
|
2539
|
+
state_name: args.state_name,
|
|
2540
|
+
initial_value: args.initial_value,
|
|
2541
|
+
scope: args.scope || 'page',
|
|
2542
|
+
persistent: args.persistent || false,
|
|
2543
|
+
reactive: args.reactive !== false,
|
|
2544
|
+
validation_schema: args.validation_schema ? JSON.stringify(args.validation_schema) : '{}',
|
|
2545
|
+
description: args.description || '',
|
|
2546
|
+
active: true
|
|
2547
|
+
};
|
|
2548
|
+
const response = await this.client.createRecord('sys_ux_client_state', stateData);
|
|
2549
|
+
if (!response.success) {
|
|
2550
|
+
throw new Error(`Failed to create client state: ${response.error}`);
|
|
2551
|
+
}
|
|
2552
|
+
this.logger.info('✅ UI Builder client state created successfully');
|
|
2553
|
+
return {
|
|
2554
|
+
success: true,
|
|
2555
|
+
state: response.data,
|
|
2556
|
+
message: `Client state '${args.state_name}' configured with ${args.scope} scope`
|
|
2557
|
+
};
|
|
2558
|
+
}
|
|
2559
|
+
catch (error) {
|
|
2560
|
+
this.logger.error('Failed to create UI Builder client state:', error);
|
|
2561
|
+
throw error;
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2564
|
+
/**
|
|
2565
|
+
* Create UI Builder Event
|
|
2566
|
+
*/
|
|
2567
|
+
async createUIBEvent(args) {
|
|
2568
|
+
try {
|
|
2569
|
+
this.logger.info(`⚡ Creating UI Builder event: ${args.name}`);
|
|
2570
|
+
const eventData = {
|
|
2571
|
+
name: args.name,
|
|
2572
|
+
label: args.label,
|
|
2573
|
+
description: args.description || '',
|
|
2574
|
+
payload_schema: args.payload_schema ? JSON.stringify(args.payload_schema) : '{}',
|
|
2575
|
+
component_scope: args.component_scope || '',
|
|
2576
|
+
global_event: args.global_event || false,
|
|
2577
|
+
bubbles: args.bubbles !== false,
|
|
2578
|
+
cancelable: args.cancelable !== false,
|
|
2579
|
+
active: true
|
|
2580
|
+
};
|
|
2581
|
+
const response = await this.client.createRecord('sys_ux_event', eventData);
|
|
2582
|
+
if (!response.success) {
|
|
2583
|
+
throw new Error(`Failed to create event: ${response.error}`);
|
|
2584
|
+
}
|
|
2585
|
+
this.logger.info('✅ UI Builder event created successfully');
|
|
2586
|
+
return {
|
|
2587
|
+
success: true,
|
|
2588
|
+
event: response.data,
|
|
2589
|
+
message: `Custom event '${args.name}' created ${args.global_event ? '(global)' : '(scoped)'}`
|
|
2590
|
+
};
|
|
2591
|
+
}
|
|
2592
|
+
catch (error) {
|
|
2593
|
+
this.logger.error('Failed to create UI Builder event:', error);
|
|
2594
|
+
throw error;
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
/**
|
|
2598
|
+
* Analyze UI Builder Page Performance
|
|
2599
|
+
*/
|
|
2600
|
+
async analyzeUIBPagePerformance(args) {
|
|
2601
|
+
try {
|
|
2602
|
+
this.logger.info(`📊 Analyzing UI Builder page performance: ${args.page_id}`);
|
|
2603
|
+
const analysis = {
|
|
2604
|
+
page_id: args.page_id,
|
|
2605
|
+
analysis_date: new Date().toISOString(),
|
|
2606
|
+
components: [],
|
|
2607
|
+
data_brokers: [],
|
|
2608
|
+
client_scripts: [],
|
|
2609
|
+
recommendations: [],
|
|
2610
|
+
total_components: 0,
|
|
2611
|
+
page_info: null
|
|
2612
|
+
};
|
|
2613
|
+
// Get page info
|
|
2614
|
+
const pageResponse = await this.client.getRecord('sys_ux_page', args.page_id);
|
|
2615
|
+
if (!pageResponse.success) {
|
|
2616
|
+
throw new Error('Page not found');
|
|
2617
|
+
}
|
|
2618
|
+
analysis.page_info = pageResponse.data;
|
|
2619
|
+
// Analyze components if requested
|
|
2620
|
+
if (args.include_components) {
|
|
2621
|
+
const elementsResponse = await this.client.searchRecords('sys_ux_page_element', `page=${args.page_id}`, 100);
|
|
2622
|
+
if (elementsResponse.success) {
|
|
2623
|
+
analysis.total_components = elementsResponse.data.result.length;
|
|
2624
|
+
analysis.components = elementsResponse.data.result.map(element => ({
|
|
2625
|
+
component: element.component,
|
|
2626
|
+
position: element.position,
|
|
2627
|
+
has_data_broker: !!element.data_broker,
|
|
2628
|
+
has_conditional_display: !!element.conditional_display
|
|
2629
|
+
}));
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
// Analyze data brokers if requested
|
|
2633
|
+
if (args.include_data_broker_stats) {
|
|
2634
|
+
const brokersResponse = await this.client.searchRecords('sys_ux_data_broker', `page=${args.page_id}`, 50);
|
|
2635
|
+
if (brokersResponse.success) {
|
|
2636
|
+
analysis.data_brokers = brokersResponse.data.result.map(broker => ({
|
|
2637
|
+
name: broker.name,
|
|
2638
|
+
type: broker.type,
|
|
2639
|
+
table: broker.table,
|
|
2640
|
+
auto_refresh: broker.auto_refresh,
|
|
2641
|
+
cache_duration: broker.cache_duration
|
|
2642
|
+
}));
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
// Analyze client scripts if requested
|
|
2646
|
+
if (args.include_client_scripts) {
|
|
2647
|
+
const scriptsResponse = await this.client.searchRecords('sys_ux_client_script', `page=${args.page_id}`, 50);
|
|
2648
|
+
if (scriptsResponse.success) {
|
|
2649
|
+
analysis.client_scripts = scriptsResponse.data.result.map(script => ({
|
|
2650
|
+
name: script.name,
|
|
2651
|
+
type: script.type,
|
|
2652
|
+
execution_order: script.execution_order,
|
|
2653
|
+
async_execution: script.async_execution
|
|
2654
|
+
}));
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
// Generate performance recommendations
|
|
2658
|
+
if (analysis.total_components > 20) {
|
|
2659
|
+
analysis.recommendations.push('Consider breaking page into smaller pages - many components may impact performance');
|
|
2660
|
+
}
|
|
2661
|
+
if (analysis.data_brokers.some(db => db.auto_refresh && db.cache_duration < 60)) {
|
|
2662
|
+
analysis.recommendations.push('Some data brokers have short cache duration with auto-refresh - consider optimizing');
|
|
2663
|
+
}
|
|
2664
|
+
if (analysis.client_scripts.length > 10) {
|
|
2665
|
+
analysis.recommendations.push('Many client scripts detected - consider consolidating for better performance');
|
|
2666
|
+
}
|
|
2667
|
+
this.logger.info('✅ UI Builder page performance analysis completed');
|
|
2668
|
+
return {
|
|
2669
|
+
success: true,
|
|
2670
|
+
analysis: analysis,
|
|
2671
|
+
summary: `Page has ${analysis.total_components || 0} components, ${analysis.data_brokers.length} data brokers, ${analysis.client_scripts.length} scripts`
|
|
2672
|
+
};
|
|
2673
|
+
}
|
|
2674
|
+
catch (error) {
|
|
2675
|
+
this.logger.error('Failed to analyze UI Builder page performance:', error);
|
|
2676
|
+
throw error;
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
/**
|
|
2680
|
+
* Validate UI Builder Page Structure
|
|
2681
|
+
*/
|
|
2682
|
+
async validateUIBPageStructure(args) {
|
|
2683
|
+
try {
|
|
2684
|
+
this.logger.info(`✅ Validating UI Builder page structure: ${args.page_id}`);
|
|
2685
|
+
const validation = {
|
|
2686
|
+
page_id: args.page_id,
|
|
2687
|
+
validation_date: new Date().toISOString(),
|
|
2688
|
+
is_valid: true,
|
|
2689
|
+
errors: [],
|
|
2690
|
+
warnings: [],
|
|
2691
|
+
info: []
|
|
2692
|
+
};
|
|
2693
|
+
// Get page info
|
|
2694
|
+
const pageResponse = await this.client.getRecord('sys_ux_page', args.page_id);
|
|
2695
|
+
if (!pageResponse.success) {
|
|
2696
|
+
validation.errors.push('Page not found');
|
|
2697
|
+
validation.is_valid = false;
|
|
2698
|
+
return { success: true, validation };
|
|
2699
|
+
}
|
|
2700
|
+
const page = pageResponse.data;
|
|
2701
|
+
// Check routing if requested
|
|
2702
|
+
if (args.check_routing) {
|
|
2703
|
+
const routeResponse = await this.client.searchRecords('sys_ux_page_registry', `page=${args.page_id}`, 1);
|
|
2704
|
+
if (!routeResponse.success || routeResponse.data.result.length === 0) {
|
|
2705
|
+
validation.warnings.push('Page has no routing configuration - may not be accessible');
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
// Check data brokers if requested
|
|
2709
|
+
if (args.check_data_brokers) {
|
|
2710
|
+
const brokersResponse = await this.client.searchRecords('sys_ux_data_broker', `page=${args.page_id}`);
|
|
2711
|
+
if (brokersResponse.success) {
|
|
2712
|
+
for (const broker of brokersResponse.data.result) {
|
|
2713
|
+
if (broker.type === 'table' && !broker.table) {
|
|
2714
|
+
validation.errors.push(`Data broker '${broker.name}' has no table configured`);
|
|
2715
|
+
validation.is_valid = false;
|
|
2716
|
+
}
|
|
2717
|
+
if (broker.type === 'script' && !broker.script) {
|
|
2718
|
+
validation.errors.push(`Data broker '${broker.name}' has no script configured`);
|
|
2719
|
+
validation.is_valid = false;
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
// Check component dependencies if requested
|
|
2725
|
+
if (args.check_component_dependencies) {
|
|
2726
|
+
const elementsResponse = await this.client.searchRecords('sys_ux_page_element', `page=${args.page_id}`);
|
|
2727
|
+
if (elementsResponse.success) {
|
|
2728
|
+
for (const element of elementsResponse.data.result) {
|
|
2729
|
+
const componentResponse = await this.client.searchRecords('sys_ux_lib_component', `name=${element.component}^ORsys_id=${element.component}`, 1);
|
|
2730
|
+
if (!componentResponse.success || componentResponse.data.result.length === 0) {
|
|
2731
|
+
validation.errors.push(`Page element references unknown component: ${element.component}`);
|
|
2732
|
+
validation.is_valid = false;
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
// Check security if requested
|
|
2738
|
+
if (args.check_security) {
|
|
2739
|
+
const routeResponse = await this.client.searchRecords('sys_ux_page_registry', `page=${args.page_id}`, 1);
|
|
2740
|
+
if (routeResponse.success && routeResponse.data.result.length > 0) {
|
|
2741
|
+
const route = routeResponse.data.result[0];
|
|
2742
|
+
if (!route.public_access && (!route.roles || route.roles.trim() === '')) {
|
|
2743
|
+
validation.warnings.push('Page is not public but has no role restrictions - check access control');
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
// Performance checks if requested
|
|
2748
|
+
if (args.check_performance) {
|
|
2749
|
+
const elementsResponse = await this.client.searchRecords('sys_ux_page_element', `page=${args.page_id}`);
|
|
2750
|
+
if (elementsResponse.success && elementsResponse.data.result.length > 15) {
|
|
2751
|
+
validation.warnings.push('Page has many components (>15) - consider performance optimization');
|
|
2752
|
+
}
|
|
2753
|
+
}
|
|
2754
|
+
// Accessibility checks if requested
|
|
2755
|
+
if (args.check_accessibility) {
|
|
2756
|
+
validation.info.push('Accessibility validation requires manual review - check for proper ARIA labels and keyboard navigation');
|
|
2757
|
+
}
|
|
2758
|
+
validation.info.push(`Page '${page.name}' validation completed`);
|
|
2759
|
+
validation.info.push(`Found ${validation.errors.length} errors and ${validation.warnings.length} warnings`);
|
|
2760
|
+
this.logger.info('✅ UI Builder page structure validation completed');
|
|
2761
|
+
return {
|
|
2762
|
+
success: true,
|
|
2763
|
+
validation: validation,
|
|
2764
|
+
summary: `Validation ${validation.is_valid ? 'PASSED' : 'FAILED'}: ${validation.errors.length} errors, ${validation.warnings.length} warnings`
|
|
2765
|
+
};
|
|
2766
|
+
}
|
|
2767
|
+
catch (error) {
|
|
2768
|
+
this.logger.error('Failed to validate UI Builder page structure:', error);
|
|
2769
|
+
throw error;
|
|
2770
|
+
}
|
|
2771
|
+
}
|
|
2772
|
+
/**
|
|
2773
|
+
* Discover UI Builder Page Usage
|
|
2774
|
+
*/
|
|
2775
|
+
async discoverUIBPageUsage(args) {
|
|
2776
|
+
try {
|
|
2777
|
+
this.logger.info(`📈 Analyzing UI Builder page usage: ${args.page_id}`);
|
|
2778
|
+
// Structural usage analysis
|
|
2779
|
+
const usage = {
|
|
2780
|
+
page_id: args.page_id,
|
|
2781
|
+
analysis_date: new Date().toISOString(),
|
|
2782
|
+
components_count: 0,
|
|
2783
|
+
data_brokers_count: 0,
|
|
2784
|
+
client_scripts_count: 0,
|
|
2785
|
+
routes_count: 0,
|
|
2786
|
+
complexity_score: 0
|
|
2787
|
+
};
|
|
2788
|
+
// Count components
|
|
2789
|
+
const elementsResponse = await this.client.searchRecords('sys_ux_page_element', `page=${args.page_id}`);
|
|
2790
|
+
if (elementsResponse.success) {
|
|
2791
|
+
usage.components_count = elementsResponse.data.result.length;
|
|
2792
|
+
}
|
|
2793
|
+
// Count data brokers
|
|
2794
|
+
const brokersResponse = await this.client.searchRecords('sys_ux_data_broker', `page=${args.page_id}`);
|
|
2795
|
+
if (brokersResponse.success) {
|
|
2796
|
+
usage.data_brokers_count = brokersResponse.data.result.length;
|
|
2797
|
+
}
|
|
2798
|
+
// Count client scripts
|
|
2799
|
+
const scriptsResponse = await this.client.searchRecords('sys_ux_client_script', `page=${args.page_id}`);
|
|
2800
|
+
if (scriptsResponse.success) {
|
|
2801
|
+
usage.client_scripts_count = scriptsResponse.data.result.length;
|
|
2802
|
+
}
|
|
2803
|
+
// Count routes
|
|
2804
|
+
const routesResponse = await this.client.searchRecords('sys_ux_page_registry', `page=${args.page_id}`);
|
|
2805
|
+
if (routesResponse.success) {
|
|
2806
|
+
usage.routes_count = routesResponse.data.result.length;
|
|
2807
|
+
}
|
|
2808
|
+
// Calculate complexity score
|
|
2809
|
+
usage.complexity_score = (usage.components_count * 2) + (usage.data_brokers_count * 3) + (usage.client_scripts_count * 4);
|
|
2810
|
+
this.logger.info('✅ UI Builder page usage analysis completed');
|
|
2811
|
+
return {
|
|
2812
|
+
success: true,
|
|
2813
|
+
usage: usage,
|
|
2814
|
+
complexity: usage.complexity_score < 20 ? 'Simple' : usage.complexity_score < 50 ? 'Moderate' : 'Complex',
|
|
2815
|
+
summary: `${usage.components_count} components, ${usage.data_brokers_count} data brokers, ${usage.client_scripts_count} scripts`
|
|
2816
|
+
};
|
|
2817
|
+
}
|
|
2818
|
+
catch (error) {
|
|
2819
|
+
this.logger.error('Failed to analyze UI Builder page usage:', error);
|
|
2820
|
+
throw error;
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
1311
2823
|
async run() {
|
|
1312
2824
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
1313
2825
|
await this.server.connect(transport);
|