UNPKG

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
{ "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": "" } }