snow-flow
Version:
Snow-Flow v3.2.0: Complete ServiceNow Enterprise Suite with 180+ MCP Tools. ATF Testing, Knowledge Management, Service Catalog, Change Management with CAB scheduling, Virtual Agent chatbots with NLU, Performance Analytics KPIs, Flow Designer automation, A
238 lines • 11.4 kB
JSON
{
"type": "widget",
"name": "Dashboard Widget Template",
"description": "Template for creating dashboard widgets with charts and metrics",
"category": "patterns/dashboard",
"config": {
"name": "{{WIDGET_NAME|custom_dashboard}}",
"id": "{{WIDGET_ID|custom_dashboard}}",
"instance_id": "{{INSTANCE_ID|dashboard_}}",
"data": {
"title": "{{WIDGET_TITLE|Dashboard}}",
"short_description": "{{WIDGET_DESCRIPTION|Real-time dashboard with key metrics}}",
"roles": "{{WIDGET_ROLES|}}"
},
"options": [
{
"name": "refresh_interval",
"section": "Behavior",
"label": "Refresh Interval (seconds)",
"type": "integer",
"value": "30",
"help": "How often to refresh the dashboard data"
},
{
"name": "color_scheme",
"section": "Appearance",
"label": "Color Scheme",
"type": "choice",
"value": "default",
"choices": [
{"label": "Default", "value": "default"},
{"label": "Dark", "value": "dark"},
{"label": "High Contrast", "value": "high-contrast"}
]
},
{
"name": "chart_type",
"section": "Appearance",
"label": "Default Chart Type",
"type": "choice",
"value": "bar",
"choices": [
{"label": "Bar Chart", "value": "bar"},
{"label": "Line Chart", "value": "line"},
{"label": "Pie Chart", "value": "pie"},
{"label": "Donut Chart", "value": "donut"}
]
}
],
"html": [
"<div class=\"dashboard-widget\" ng-class=\"{'dark-theme': options.color_scheme === 'dark', 'high-contrast': options.color_scheme === 'high-contrast'}\">",
" <div class=\"dashboard-header\">",
" <h2 class=\"dashboard-title\">{{data.title}}</h2>",
" <div class=\"dashboard-controls\">",
" <button class=\"btn btn-sm\" ng-click=\"c.refresh()\" title=\"Refresh\">",
" <i class=\"fa fa-refresh\" ng-class=\"{'fa-spin': c.loading}\"></i>",
" </button>",
" <button class=\"btn btn-sm\" ng-click=\"c.toggleFullscreen()\" title=\"Fullscreen\">",
" <i class=\"fa\" ng-class=\"c.fullscreen ? 'fa-compress' : 'fa-expand'\"></i>",
" </button>",
" </div>",
" </div>",
" ",
" <div class=\"dashboard-metrics\" ng-if=\"!c.loading\">",
" <div class=\"metric-card\" ng-repeat=\"metric in c.metrics\">",
" <div class=\"metric-value\" ng-style=\"{'color': metric.color}\">{{metric.value}}</div>",
" <div class=\"metric-label\">{{metric.label}}</div>",
" <div class=\"metric-trend\" ng-if=\"metric.trend\">",
" <i class=\"fa\" ng-class=\"metric.trend > 0 ? 'fa-arrow-up text-success' : 'fa-arrow-down text-danger'\"></i>",
" <span>{{metric.trend}}%</span>",
" </div>",
" </div>",
" </div>",
" ",
" <div class=\"dashboard-charts\" ng-if=\"!c.loading\">",
" <div class=\"chart-container\" ng-repeat=\"chart in c.charts\">",
" <h3>{{chart.title}}</h3>",
" <canvas id=\"chart-{{$index}}\" width=\"400\" height=\"200\"></canvas>",
" </div>",
" </div>",
" ",
" <div class=\"dashboard-loading\" ng-if=\"c.loading\">",
" <i class=\"fa fa-spinner fa-spin fa-3x\"></i>",
" <p>Loading dashboard data...</p>",
" </div>",
"</div>"
],
"css": [
".dashboard-widget {",
" padding: 20px;",
" background: #fff;",
" border-radius: 8px;",
" box-shadow: 0 2px 4px rgba(0,0,0,0.1);",
"}",
"",
".dashboard-widget.dark-theme {",
" background: #1a1a1a;",
" color: #fff;",
"}",
"",
".dashboard-widget.high-contrast {",
" border: 2px solid #000;",
"}",
"",
".dashboard-header {",
" display: flex;",
" justify-content: space-between;",
" align-items: center;",
" margin-bottom: 20px;",
"}",
"",
".dashboard-title {",
" margin: 0;",
" font-size: 24px;",
" font-weight: 600;",
"}",
"",
".dashboard-controls button {",
" margin-left: 10px;",
"}",
"",
".dashboard-metrics {",
" display: grid;",
" grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));",
" gap: 20px;",
" margin-bottom: 30px;",
"}",
"",
".metric-card {",
" background: #f5f5f5;",
" padding: 20px;",
" border-radius: 8px;",
" text-align: center;",
" transition: transform 0.2s;",
"}",
"",
".dark-theme .metric-card {",
" background: #2a2a2a;",
"}",
"",
".metric-card:hover {",
" transform: translateY(-2px);",
" box-shadow: 0 4px 8px rgba(0,0,0,0.1);",
"}",
"",
".metric-value {",
" font-size: 36px;",
" font-weight: bold;",
" margin-bottom: 5px;",
"}",
"",
".metric-label {",
" font-size: 14px;",
" color: #666;",
" text-transform: uppercase;",
"}",
"",
".dark-theme .metric-label {",
" color: #999;",
"}",
"",
".metric-trend {",
" margin-top: 10px;",
" font-size: 14px;",
"}",
"",
".dashboard-charts {",
" display: grid;",
" grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));",
" gap: 30px;",
"}",
"",
".chart-container {",
" background: #f9f9f9;",
" padding: 20px;",
" border-radius: 8px;",
"}",
"",
".dark-theme .chart-container {",
" background: #2a2a2a;",
"}",
"",
".dashboard-loading {",
" text-align: center;",
" padding: 60px 20px;",
" color: #666;",
"}",
"",
".dark-theme .dashboard-loading {",
" color: #999;",
"}",
"",
"@media (max-width: 768px) {",
" .dashboard-metrics {",
" grid-template-columns: 1fr;",
" }",
" .dashboard-charts {",
" grid-template-columns: 1fr;",
" }",
"}"
],
"client_controller": "{{CLIENT_CONTROLLER|dashboard_controller}}",
"script": "{{SERVER_SCRIPT|dashboard_server_script}}",
"link_function": "{{LINK_FUNCTION|}}",
"demo_data": {
"metrics": [
{"label": "Total Items", "value": "1,234", "color": "#007bff", "trend": 12},
{"label": "Active Users", "value": "456", "color": "#28a745", "trend": 5},
{"label": "Pending Tasks", "value": "78", "color": "#ffc107", "trend": -3},
{"label": "Completed", "value": "89%", "color": "#17a2b8", "trend": 2}
],
"charts": [
{
"title": "Weekly Trend",
"type": "line",
"data": {
"labels": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
"datasets": [{
"label": "Items",
"data": [65, 59, 80, 81, 56, 55, 40]
}]
}
}
]
}
},
"variables": {
"WIDGET_NAME": "custom_dashboard",
"WIDGET_ID": "custom_dashboard",
"INSTANCE_ID": "dashboard_",
"WIDGET_TITLE": "Dashboard",
"WIDGET_DESCRIPTION": "Real-time dashboard with key metrics",
"WIDGET_ROLES": "",
"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}",
"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})()",
"LINK_FUNCTION": ""
}
}