From 21463e59eeab9d859fd6c12966ee86c248f64266 Mon Sep 17 00:00:00 2001 From: Felix Gateru Date: Fri, 8 Mar 2024 11:55:22 -0500 Subject: [PATCH] MG-164 - Add input validation to chart modals (#193) * Add input validation Signed-off-by: felix.gateru * Solve conflicts Signed-off-by: felix.gateru * Make uuid pattern accessible to all modals Signed-off-by: felix.gateru * Add max date time Signed-off-by: felix.gateru * Add aggregation to modals Signed-off-by: felix.gateru * Change update interval pattern Signed-off-by: felix.gateru * Make interval pattern global Signed-off-by: felix.gateru * Add aggregation to charts Signed-off-by: felix.gateru * Remove vestigial code Signed-off-by: felix.gateru --------- Signed-off-by: felix.gateru --- ui/service.go | 18 +++-- ui/web/static/js/dashboard.js | 25 +++++++ ui/web/templates/charts/alarmcountmodal.html | 34 ++++++++-- ui/web/templates/charts/alarmstablemodal.html | 33 +++++++-- .../templates/charts/arealinechartmodal.html | 66 +++++++++++++++--- ui/web/templates/charts/barchartmodal.html | 65 +++++++++++++++--- ui/web/templates/charts/donutmodal.html | 55 +++++++++++++-- .../templates/charts/doublebarchartmodal.html | 65 +++++++++++++++--- .../charts/dynamicdatachartmodal.html | 66 +++++++++++++++--- .../templates/charts/entitiestablemodal.html | 33 +++++++-- ui/web/templates/charts/entitycountmodal.html | 29 ++++++-- ui/web/templates/charts/gaugemodal.html | 29 ++++++-- .../charts/horizontalbarchartmodal.html | 56 ++++++++++++++-- ui/web/templates/charts/labelmodal.html | 32 +++++++-- ui/web/templates/charts/linechartmodal.html | 65 +++++++++++++++--- .../templates/charts/multibarchartmodal.html | 55 +++++++++++++-- ui/web/templates/charts/multigaugemodal.html | 29 ++++++-- .../charts/multiplelinechartmodal.html | 67 ++++++++++++++++--- ui/web/templates/charts/piechartmodal.html | 55 +++++++++++++-- ui/web/templates/charts/progressbarmodal.html | 29 ++++++-- .../templates/charts/shareddatasetmodal.html | 65 +++++++++++++++--- ui/web/templates/charts/speedgaugemodal.html | 29 ++++++-- .../charts/stackedlinechartmodal.html | 65 +++++++++++++++--- ui/web/templates/charts/stepchartmodal.html | 65 +++++++++++++++--- ui/web/templates/charts/tempgaugemodal.html | 29 ++++++-- ui/web/templates/charts/valuecardmodal.html | 33 +++++++-- ui/web/templates/dashboard.html | 48 ++++++------- 27 files changed, 1060 insertions(+), 180 deletions(-) diff --git a/ui/service.go b/ui/service.go index 1a343487a..4222a16fd 100644 --- a/ui/service.go +++ b/ui/service.go @@ -232,6 +232,8 @@ var ( domainRelations = []string{"administrator", "editor", "viewer", "member"} groupRelations = []string{"administrator", "editor", "viewer"} statusOptions = []string{"all", "enabled", "disabled"} + uuidPattern = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$" + intervalPattern = "^([0-9][0-9]*[smhd])$" ) // Service specifies service API. @@ -2560,12 +2562,14 @@ func (us *uiService) ViewDashboard(s Session, dashboardID string) ([]byte, error } data := struct { - NavbarActive string - CollapseActive string - Charts []Item - Dashboard Dashboard - Breadcrumbs []breadcrumb - Session Session + NavbarActive string + CollapseActive string + Charts []Item + Dashboard Dashboard + Breadcrumbs []breadcrumb + Session Session + UUIDPattern string + IntervalPattern string }{ dashboardsActive, dashboardsActive, @@ -2573,6 +2577,8 @@ func (us *uiService) ViewDashboard(s Session, dashboardID string) ([]byte, error dashboard, crumbs, s, + uuidPattern, + intervalPattern, } if err := us.tpls.ExecuteTemplate(&btpl, "dashboard", data); err != nil { diff --git a/ui/web/static/js/dashboard.js b/ui/web/static/js/dashboard.js index 0379f7c35..dca5eec00 100644 --- a/ui/web/static/js/dashboard.js +++ b/ui/web/static/js/dashboard.js @@ -336,3 +336,28 @@ function updateMetadata(layout, savedMetadata) { } return upMetadata; } + +// Set dynamic parameters for all the modals +document.addEventListener("DOMContentLoaded", function () { + // Get the current formatted date and time + function formatDateTime(date) { + let formatted = new Date(date.getTime() - date.getTimezoneOffset() * 60000) + .toISOString() + .slice(0, 16); + return formatted; + } + + let now = new Date(); + let formattedNow = formatDateTime(now); + let startTimes = document.querySelectorAll("#start-time"); + let stopTimes = document.querySelectorAll("#stop-time"); + + // Set the max attribute for the start and stop times + startTimes.forEach(function (startTime) { + startTime.setAttribute("max", formattedNow); + }); + + stopTimes.forEach(function (stopTime) { + stopTime.setAttribute("max", formattedNow); + }); +}); diff --git a/ui/web/templates/charts/alarmcountmodal.html b/ui/web/templates/charts/alarmcountmodal.html index 5ca7f5b1b..b7066f851 100644 --- a/ui/web/templates/charts/alarmcountmodal.html +++ b/ui/web/templates/charts/alarmcountmodal.html @@ -28,23 +28,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -61,22 +65,26 @@ +
Please enter a valid interval
@@ -87,7 +95,12 @@ {{ end }} diff --git a/ui/web/templates/charts/alarmstablemodal.html b/ui/web/templates/charts/alarmstablemodal.html index 2ff5d365a..fa2ad41fa 100644 --- a/ui/web/templates/charts/alarmstablemodal.html +++ b/ui/web/templates/charts/alarmstablemodal.html @@ -28,23 +28,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -61,22 +65,26 @@ +
Please enter a valid interval
@@ -87,7 +95,12 @@ {{ end }} diff --git a/ui/web/templates/charts/arealinechartmodal.html b/ui/web/templates/charts/arealinechartmodal.html index 28cf4a0e7..df220333f 100644 --- a/ui/web/templates/charts/arealinechartmodal.html +++ b/ui/web/templates/charts/arealinechartmodal.html @@ -68,23 +68,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -116,6 +120,7 @@ id="start-time" required /> +
@@ -124,18 +129,32 @@ class="form-control mb-3" name="stopTime" id="stop-time" + required />
- + +
Please enter a valid interval
+
+
+ +
@@ -180,13 +199,15 @@ @@ -196,7 +217,12 @@ {{ end }} diff --git a/ui/web/templates/charts/barchartmodal.html b/ui/web/templates/charts/barchartmodal.html index a75825209..9f6ecb9c1 100644 --- a/ui/web/templates/charts/barchartmodal.html +++ b/ui/web/templates/charts/barchartmodal.html @@ -67,23 +67,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -105,6 +109,7 @@ id="start-time" required /> +
@@ -113,18 +118,32 @@ class="form-control mb-3" name="stopTime" id="stop-time" + required />
- + +
Please enter a valid interval
+
+
+ +
@@ -172,7 +191,6 @@ name="seriesName" id="series-name" placeholder="Enter the series name eg. temperature" - required /> @@ -180,13 +198,15 @@ @@ -196,7 +216,12 @@ {{ end }} diff --git a/ui/web/templates/charts/donutmodal.html b/ui/web/templates/charts/donutmodal.html index edb4cc598..ba5c16667 100644 --- a/ui/web/templates/charts/donutmodal.html +++ b/ui/web/templates/charts/donutmodal.html @@ -67,22 +67,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -95,6 +100,30 @@ required />
+
+ + +
Please enter a valid interval
+
+
+ + +
@@ -129,13 +157,15 @@ @@ -145,7 +175,12 @@ {{ end }} diff --git a/ui/web/templates/charts/doublebarchartmodal.html b/ui/web/templates/charts/doublebarchartmodal.html index d2b92e88f..9775bda3e 100644 --- a/ui/web/templates/charts/doublebarchartmodal.html +++ b/ui/web/templates/charts/doublebarchartmodal.html @@ -68,23 +68,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -116,6 +120,7 @@ id="start-time" required /> +
@@ -124,18 +129,32 @@ class="form-control mb-3" name="stopTime" id="stop-time" + required />
- + +
Please enter a valid interval
+
+
+ +
@@ -183,7 +202,6 @@ name="seriesName" id="series-name" placeholder="Enter the series name eg. thing1, thing2" - required /> @@ -191,13 +209,15 @@ @@ -207,7 +227,12 @@ {{ end }} diff --git a/ui/web/templates/charts/dynamicdatachartmodal.html b/ui/web/templates/charts/dynamicdatachartmodal.html index 997ebc51b..21d25add7 100644 --- a/ui/web/templates/charts/dynamicdatachartmodal.html +++ b/ui/web/templates/charts/dynamicdatachartmodal.html @@ -67,23 +67,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -115,6 +119,7 @@ id="start-time" required /> +
@@ -123,18 +128,32 @@ class="form-control mb-3" name="stopTime" id="stop-time" + required />
- + +
Please enter a valid interval
+
+
+ +
@@ -192,7 +211,6 @@ name="lineDataSeriesName" id="lineDataSeriesName" placeholder="Enter the series name eg. temperature" - required />
@@ -203,7 +221,6 @@ name="barDataSeriesName" id="barDataSeriesName" placeholder="Enter the series name eg. humidity" - required />
@@ -211,13 +228,15 @@ @@ -229,7 +248,12 @@ document .getElementById("create-dynamicDataChart-button") .addEventListener("click", function () { - let form = document.getElementById("create-dynamicDataChart-form"); + const form = document.getElementById("create-dynamicDataChart-form"); + if (!form.checkValidity()) { + form.classList.add("was-validated"); + return; + } + // Create an object to store the form data let chartData = {}; let formData = new FormData(form); @@ -237,11 +261,33 @@ chartData[pair[0]] = pair[1]; } + if (chartData.stopTime <= chartData.startTime) { + const invalidTimeFeedback = form.querySelector(".invalid-time"); + invalidTimeFeedback.innerHTML = "Stop time should be greater than start time"; + invalidTimeFeedback.style.color = "red"; + const invalidTimeInput = form.querySelector("#stop-time"); + invalidTimeInput.classList.remove("was-validated"); + invalidTimeInput.classList.add("is-invalid"); + return; + } + var widgetID = "dynamicDataChart-" + Date.now(); chartData["Type"] = "dynamicDataChart"; addWidget(chartData, widgetID); metadataBuffer[widgetID] = chartData; + + form.reset(); + form.classList.remove("was-validated"); + bootstrap.Modal.getInstance(document.getElementById("dynamicDataChartModal")).hide(); }); + + document.getElementById("close-dynamicDataChart-button").addEventListener("click", function () { + const form = document.getElementById("create-dynamicDataChart-form"); + form.querySelector(".invalid-time").innerHTML = ""; + form.querySelector("#stop-time").classList.remove("is-invalid"); + form.reset(); + form.classList.remove("was-validated"); + }); {{ end }} diff --git a/ui/web/templates/charts/entitiestablemodal.html b/ui/web/templates/charts/entitiestablemodal.html index 656fff90f..4d345db17 100644 --- a/ui/web/templates/charts/entitiestablemodal.html +++ b/ui/web/templates/charts/entitiestablemodal.html @@ -28,23 +28,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -61,22 +65,26 @@ +
Please enter a valid interval
@@ -87,7 +95,12 @@ {{ end }} diff --git a/ui/web/templates/charts/entitycountmodal.html b/ui/web/templates/charts/entitycountmodal.html index 0e83dac26..92ba84573 100644 --- a/ui/web/templates/charts/entitycountmodal.html +++ b/ui/web/templates/charts/entitycountmodal.html @@ -28,33 +28,39 @@ +
Please enter a valid uuid
- + +
Please enter a valid uuid
@@ -66,6 +72,11 @@ // entity count form document.getElementById("create-entityCount-button").addEventListener("click", function () { let form = document.getElementById("create-entityCount-form"); + if (!form.checkValidity()) { + form.classList.add("was-validated"); + return; + } + // Create an object to store the form data let chartData = {}; let formData = new FormData(form); @@ -78,6 +89,16 @@ chartData["Type"] = "entityCount"; addWidget(chartData, widgetID); metadataBuffer[widgetID] = chartData; + + form.reset(); + form.classList.remove("was-validated"); + bootstrap.Modal.getInstance(document.getElementById("entityCountModal")).hide(); + }); + + document.getElementById("close-entityCount-button").addEventListener("click", function () { + const form = document.getElementById("create-entityCount-form"); + form.reset(); + form.classList.remove("was-validated"); }); {{ end }} diff --git a/ui/web/templates/charts/gaugemodal.html b/ui/web/templates/charts/gaugemodal.html index ee3aafa62..3d55784de 100644 --- a/ui/web/templates/charts/gaugemodal.html +++ b/ui/web/templates/charts/gaugemodal.html @@ -68,23 +68,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -152,13 +156,15 @@
@@ -167,7 +173,12 @@ {{ end }} diff --git a/ui/web/templates/charts/horizontalbarchartmodal.html b/ui/web/templates/charts/horizontalbarchartmodal.html index 3793ec8ba..5d5a6c9a0 100644 --- a/ui/web/templates/charts/horizontalbarchartmodal.html +++ b/ui/web/templates/charts/horizontalbarchartmodal.html @@ -67,22 +67,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -64,7 +71,12 @@ {{ end }} diff --git a/ui/web/templates/charts/linechartmodal.html b/ui/web/templates/charts/linechartmodal.html index 6f01643d6..1b1fcf95e 100644 --- a/ui/web/templates/charts/linechartmodal.html +++ b/ui/web/templates/charts/linechartmodal.html @@ -68,23 +68,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -106,6 +110,7 @@ id="start-time" required /> +
@@ -114,18 +119,32 @@ class="form-control mb-3" name="stopTime" id="stop-time" + required />
- + +
Please enter a valid interval
+
+
+ +
@@ -173,7 +192,6 @@ name="seriesName" id="series-name" placeholder="Enter the series name eg. temperature" - required />
@@ -198,13 +216,15 @@
@@ -214,7 +234,12 @@ {{ end }} diff --git a/ui/web/templates/charts/multibarchartmodal.html b/ui/web/templates/charts/multibarchartmodal.html index b4d7dfedb..127322a07 100644 --- a/ui/web/templates/charts/multibarchartmodal.html +++ b/ui/web/templates/charts/multibarchartmodal.html @@ -68,22 +68,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -96,6 +101,30 @@ required />
+
+ + +
Please enter a valid interval
+
+
+ + +
@@ -150,13 +178,15 @@ @@ -166,7 +196,12 @@ {{ end }} diff --git a/ui/web/templates/charts/multigaugemodal.html b/ui/web/templates/charts/multigaugemodal.html index 03b2c3eed..58d00c398 100644 --- a/ui/web/templates/charts/multigaugemodal.html +++ b/ui/web/templates/charts/multigaugemodal.html @@ -68,23 +68,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -152,13 +156,15 @@
@@ -168,7 +174,12 @@ {{ end }} diff --git a/ui/web/templates/charts/multiplelinechartmodal.html b/ui/web/templates/charts/multiplelinechartmodal.html index 9b165dab9..106aca350 100644 --- a/ui/web/templates/charts/multiplelinechartmodal.html +++ b/ui/web/templates/charts/multiplelinechartmodal.html @@ -67,23 +67,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -95,6 +100,30 @@ required />
+
+ + +
Please enter a valid interval
+
+
+ + +
@@ -129,13 +157,15 @@ @@ -145,7 +175,12 @@ {{ end }} diff --git a/ui/web/templates/charts/progressbarmodal.html b/ui/web/templates/charts/progressbarmodal.html index 820dd58f9..ada7e2b45 100644 --- a/ui/web/templates/charts/progressbarmodal.html +++ b/ui/web/templates/charts/progressbarmodal.html @@ -67,23 +67,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -151,13 +155,15 @@
@@ -167,7 +173,12 @@ {{ end }} diff --git a/ui/web/templates/charts/shareddatasetmodal.html b/ui/web/templates/charts/shareddatasetmodal.html index e79a0285b..7d80e4078 100644 --- a/ui/web/templates/charts/shareddatasetmodal.html +++ b/ui/web/templates/charts/shareddatasetmodal.html @@ -67,23 +67,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -115,6 +119,7 @@ id="start-time" required /> +
@@ -123,18 +128,32 @@ class="form-control mb-3" name="stopTime" id="stop-time" + required />
- + +
Please enter a valid interval
+
+
+ +
@@ -182,7 +201,6 @@ name="seriesName" id="series-name" placeholder="Enter the four series names eg. temperature, voltage,.." - required /> @@ -190,13 +208,15 @@ @@ -206,7 +226,12 @@ {{ end }} diff --git a/ui/web/templates/charts/speedgaugemodal.html b/ui/web/templates/charts/speedgaugemodal.html index 840dd38eb..835fcf02c 100644 --- a/ui/web/templates/charts/speedgaugemodal.html +++ b/ui/web/templates/charts/speedgaugemodal.html @@ -67,23 +67,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -151,13 +155,15 @@
@@ -167,7 +173,12 @@ {{ end }} diff --git a/ui/web/templates/charts/stackedlinechartmodal.html b/ui/web/templates/charts/stackedlinechartmodal.html index 49a2842d9..1d4bc3cff 100644 --- a/ui/web/templates/charts/stackedlinechartmodal.html +++ b/ui/web/templates/charts/stackedlinechartmodal.html @@ -68,23 +68,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -106,6 +110,7 @@ id="start-time" required /> +
@@ -114,18 +119,32 @@ class="form-control mb-3" name="stopTime" id="stop-time" + required />
- + +
Please enter a valid interval
+
+
+ +
@@ -173,7 +192,6 @@ name="seriesName" id="series-name" placeholder="Enter the series name eg. temperature, voltage" - required />
@@ -194,13 +212,15 @@
@@ -212,7 +232,12 @@ document .getElementById("create-stackedLineChart-button") .addEventListener("click", function () { - let form = document.getElementById("create-stackedLineChart-form"); + const form = document.getElementById("create-stackedLineChart-form"); + if (!form.checkValidity()) { + form.classList.add("was-validated"); + return; + } + // Create an object to store the form data let chartData = {}; let formData = new FormData(form); @@ -220,11 +245,33 @@ chartData[pair[0]] = pair[1]; } + if (chartData.stopTime <= chartData.startTime) { + const invalidTimeFeedback = form.querySelector(".invalid-time"); + invalidTimeFeedback.innerHTML = "Stop time should be greater than start time"; + invalidTimeFeedback.style.color = "red"; + const invalidTimeInput = form.querySelector("#stop-time"); + invalidTimeInput.classList.remove("was-validated"); + invalidTimeInput.classList.add("is-invalid"); + return; + } + var widgetID = "stackedLineChart-" + Date.now(); chartData["Type"] = "stackedLineChart"; addWidget(chartData, widgetID); metadataBuffer[widgetID] = chartData; + + form.reset(); + form.classList.remove("was-validated"); + bootstrap.Modal.getInstance(document.getElementById("stackedLineChartModal")).hide(); }); + + document.getElementById("close-stackedLineChart-button").addEventListener("click", function () { + const form = document.getElementById("create-stackedLineChart-form"); + form.querySelector(".invalid-time").innerHTML = ""; + form.querySelector("#stop-time").classList.remove("is-invalid"); + form.reset(); + form.classList.remove("was-validated"); + }); {{ end }} diff --git a/ui/web/templates/charts/stepchartmodal.html b/ui/web/templates/charts/stepchartmodal.html index 51a4112b9..277b9e793 100644 --- a/ui/web/templates/charts/stepchartmodal.html +++ b/ui/web/templates/charts/stepchartmodal.html @@ -67,23 +67,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -106,6 +110,7 @@ required />
+
Step Chart class="form-control mb-3" name="stopTime" id="stop-time" + required />
- + +
Please enter a valid interval
+
+
+ +
@@ -172,7 +191,6 @@ name="seriesName" id="series-name" placeholder="Enter the series name eg. temperature,voltage" - required />
@@ -193,13 +211,15 @@
@@ -209,7 +229,12 @@ {{ end }} diff --git a/ui/web/templates/charts/tempgaugemodal.html b/ui/web/templates/charts/tempgaugemodal.html index 92a6eee0d..0919dd2c2 100644 --- a/ui/web/templates/charts/tempgaugemodal.html +++ b/ui/web/templates/charts/tempgaugemodal.html @@ -67,23 +67,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -151,13 +155,15 @@
@@ -167,7 +173,12 @@ {{ end }} diff --git a/ui/web/templates/charts/valuecardmodal.html b/ui/web/templates/charts/valuecardmodal.html index a9f2fc8d4..762de3c10 100644 --- a/ui/web/templates/charts/valuecardmodal.html +++ b/ui/web/templates/charts/valuecardmodal.html @@ -67,23 +67,27 @@ +
Please enter a valid uuid
+
Please enter a valid uuid
@@ -100,12 +104,14 @@ +
Please enter a valid interval
@@ -150,13 +156,15 @@ @@ -166,7 +174,12 @@ {{ end }} diff --git a/ui/web/templates/dashboard.html b/ui/web/templates/dashboard.html index bfaf7f1e4..0a80b9088 100644 --- a/ui/web/templates/dashboard.html +++ b/ui/web/templates/dashboard.html @@ -95,30 +95,30 @@
Widgets
- {{ template "gaugemodal" }} - {{ template "linechartmodal" }} - {{ template "barchartmodal" }} - {{ template "piechartmodal" }} - {{ template "donutmodal" }} - {{ template "speedgaugemodal" }} - {{ template "tempgaugemodal" }} - {{ template "stackedlinechartmodal" }} - {{ template "arealinechartmodal" }} - {{ template "horizontalbarchartmodal" }} - {{ template "dynamicdatachartmodal" }} - {{ template "doublebarchartmodal" }} - {{ template "multiplelinechartmodal" }} - {{ template "stepchartmodal" }} - {{ template "multigaugemodal" }} - {{ template "multibarchartmodal" }} - {{ template "shareddatasetmodal" }} - {{ template "valuecardmodal" }} - {{ template "alarmcountmodal" }} - {{ template "alarmstablemodal" }} - {{ template "entitiestablemodal" }} - {{ template "entitycountmodal" }} - {{ template "progressbarmodal" }} - {{ template "labelmodal" }} + {{ template "gaugemodal" . }} + {{ template "linechartmodal" . }} + {{ template "barchartmodal" . }} + {{ template "piechartmodal" . }} + {{ template "donutmodal" . }} + {{ template "speedgaugemodal" . }} + {{ template "tempgaugemodal" . }} + {{ template "stackedlinechartmodal" . }} + {{ template "arealinechartmodal" . }} + {{ template "horizontalbarchartmodal" . }} + {{ template "dynamicdatachartmodal" . }} + {{ template "doublebarchartmodal" . }} + {{ template "multiplelinechartmodal" . }} + {{ template "stepchartmodal" . }} + {{ template "multigaugemodal" . }} + {{ template "multibarchartmodal" . }} + {{ template "shareddatasetmodal" . }} + {{ template "valuecardmodal" . }} + {{ template "alarmcountmodal" . }} + {{ template "alarmstablemodal" . }} + {{ template "entitiestablemodal" . }} + {{ template "entitycountmodal" . }} + {{ template "progressbarmodal" . }} + {{ template "labelmodal" . }}