diff options
Diffstat (limited to 'gui-pdp-monitoring/src/webapp/js')
-rw-r--r-- | gui-pdp-monitoring/src/webapp/js/MonitoringChart.js | 260 | ||||
-rw-r--r-- | gui-pdp-monitoring/src/webapp/js/MonitoringConfig.js | 127 | ||||
-rw-r--r-- | gui-pdp-monitoring/src/webapp/js/MonitoringMain.js | 109 | ||||
-rw-r--r-- | gui-pdp-monitoring/src/webapp/js/MonitoringTable.js | 61 | ||||
-rw-r--r-- | gui-pdp-monitoring/src/webapp/js/MonitoringUtils.js | 416 | ||||
-rw-r--r-- | gui-pdp-monitoring/src/webapp/js/PdpEngineWorkerStatus.js | 147 | ||||
-rw-r--r-- | gui-pdp-monitoring/src/webapp/js/PdpInformation.js | 65 | ||||
-rw-r--r-- | gui-pdp-monitoring/src/webapp/js/PdpListView.js | 75 | ||||
-rw-r--r-- | gui-pdp-monitoring/src/webapp/js/PdpStatisticsSummary.js | 142 | ||||
-rw-r--r-- | gui-pdp-monitoring/src/webapp/js/__test__/MonitoringUtils.test.js | 19 |
10 files changed, 1421 insertions, 0 deletions
diff --git a/gui-pdp-monitoring/src/webapp/js/MonitoringChart.js b/gui-pdp-monitoring/src/webapp/js/MonitoringChart.js new file mode 100644 index 0000000..514446b --- /dev/null +++ b/gui-pdp-monitoring/src/webapp/js/MonitoringChart.js @@ -0,0 +1,260 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +import * as d3 from "d3"; + +/* + * Create a chart and append it to a container + */ +function createChart(data, container, title, unit, lineStroke, nodeColour) { + // Set the dimensions of the canvas + var margin = { + top : 30, + right : 20, + bottom : 30, + left : 50 + }, width = 600 - margin.left - margin.right, height = 270 - margin.top + - margin.bottom; + + // Set the ranges + var x = d3.time.scale().range([ 0, width ]); + var y = d3.scale.linear().range([ height, 0 ]); + + // Define the axes + var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(5).innerTickSize( + -height).outerTickSize(0).tickPadding(10); + + var yAxis = d3.svg.axis().scale(y).orient("left").ticks(10).innerTickSize( + -width).outerTickSize(0).tickPadding(10); + + // Define the line + var valueline = d3.svg.line().x(function(d) { + return x(d.timestamp); + }).y(function(d) { + return y(d.value); + }); + + // Add the svg canvas to the container + var svg = d3.select(container).append("svg").attr("preserveAspectRatio", + "xMinYMin meet").attr("viewBox", "0 0 600 400").classed( + "svg-content-responsive", true).append("g").attr("transform", + "translate(" + margin.left + "," + margin.top + ")"); + + // Set the unit for the value + svg.attr("unit", unit); + + // Format the data for the chart + data.forEach(function(d) { + d.timestamp = d.timestamp; + d.value = +d.value; + }); + + // Scale the range of the data + x.domain(d3.extent(data, function(d) { + return d.timestamp; + })); + y.domain([ 0, d3.max(data, function(d) { + return Math.ceil((d.value + 1) / 10) * 10; + }) ]); + + // Set the colour of the line + if (!lineStroke) { + lineStroke = "#5fbadd" + } + + // Set the colour of the circles + if (!nodeColour) { + nodeColour = "#00A9D4" + } + + // Add the valueline path + svg.append("path").attr("class", "line").data(data).attr("unit", unit) + .attr("stroke", lineStroke).attr("d", valueline(data)); + + // Add the scatterplot + svg.selectAll("circle").data(data).enter().append("circle").attr("r", 3.5) + .attr("class", "circle").attr("fill", nodeColour).attr("cx", + function(d) { + return x(d.timestamp); + }).attr("cy", function(d) { + return y(d.value); + }) + + // Apply the tooltip to each node + .on( + "mouseover", + function(d) { + d3.select("body").select(".tooltip").transition() + .duration(50).style("opacity", 1); + d3.select("body").select(".tooltip").html( + formatDate(new Date(d.timestamp)) + "<br/>" + + d.value + (unit ? " " + unit : "")) + .style("left", (d3.event.pageX) + "px").style( + "top", (d3.event.pageY - 28) + "px"); + }).on( + "mouseout", + function(d) { + d3.select("body").select(".tooltip").transition() + .duration(500).style("opacity", 0); + }); + + // Add the X Axis + svg.append("g").attr("class", "x axis").attr("transform", + "translate(0," + height + ")").call(xAxis); + + // Add the Y Axis + svg.append("g").attr("class", "y axis").call(yAxis); + + // Add the title + svg.append("text").attr("x", (width / 2)).attr("y", 0 - (margin.top / 2)) + .attr("text-anchor", "middle").style("font-size", "16px").style( + "text-decoration", "underline").text(title); + + // Add the background + svg.selectAll(".tick:not(:first-of-type) line").attr("stroke", "#777") + .attr("stroke-dasharray", "2,2"); +} + +/* + * Generates random chart data. Used when initializing the charts so that they + * are not empty on load + */ +function generateRandomData() { + var data = []; + for (var i = 0; i < 30; i++) { + data.push({ + timestamp : new Date().getTime() - (i * 5000), + value : Math.floor(Math.random() * 100) + 1 + }); + } + return data; +} + +/* + * Update a chart belonging to a specific container + */ +function updateChart(container, data, nodeColour) { + var margin = { + top : 30, + right : 20, + bottom : 30, + left : 50 + }, width = 600 - margin.left - margin.right, height = 270 - margin.top + - margin.bottom; + var parseDate = d3.time.format("%d-%b-%y").parse; + + // Format the data for the chart + data.forEach(function(d) { + d.timestamp = d.timestamp; + d.value = +d.value; + }); + + // Select the chart + var svg = d3.select(container); + + // Set the ranges + var x = d3.time.scale().range([ 0, width ]); + var y = d3.scale.linear().range([ height, 0 ]); + + // Define the axes + var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(5).innerTickSize( + -height).outerTickSize(0).tickPadding(10); + + var yAxis = d3.svg.axis().scale(y).orient("left").ticks(10).innerTickSize( + -width).outerTickSize(0).tickPadding(10); + + // Scale the range of the data + x.domain(d3.extent(data, function(d) { + return d.timestamp; + })); + y.domain([ 0, d3.max(data, function(d) { + return Math.ceil((d.value + 1) / 10) * 10; + }) ]); + + // Update the valueline path + var valueline = d3.svg.line().x(function(d) { + return x(d.timestamp); + }).y(function(d) { + return y(d.value); + }); + + var unit = svg.select(".line").attr("unit"); + + // Remove all nodes + svg.selectAll("circle").remove(); + + // Set the node colour if one is passed in + if (!nodeColour) { + nodeColour = "#00A9D4" + } + + // Make the changes + svg.select(".line").data(data) // change the line + .transition().duration(750).attr("d", valueline(data)); + svg.select(".x.axis") // change the x axis + .transition().duration(750).call(xAxis.ticks(5)); + svg.select(".y.axis") // change the y axis + .transition().duration(750).call(yAxis); + + // Redraw the nodes based on the new data + svg.select("svg").select("g").selectAll("circle").data(data).enter() + .append("circle").attr("r", 3.5).attr("class", "circle").attr( + "fill", nodeColour).attr("cx", function(d) { + return x(d.timestamp); + }).attr("cy", function(d) { + return y(d.value); + }) + + // Apply the tooltip to each node + .on( + "mouseover", + function(d) { + d3.select("body").select(".tooltip").transition() + .duration(50).style("opacity", 1); + d3.select("body").select(".tooltip").html( + formatDate(new Date(d.timestamp)) + "<br/>" + + d.value + (unit ? " " + unit : "")) + .style("left", (d3.event.pageX) + "px").style( + "top", (d3.event.pageY - 28) + "px"); + }).on( + "mouseout", + function(d) { + d3.select("body").select(".tooltip").transition() + .duration(500).style("opacity", 0); + }); + +} + +/* + * Initialize a singleton div used as a floating tooltip for all charts + */ +function initTooltip() { + d3.select("body").append("div").attr("class", "tooltip").attr("id", + "tooltip").style("opacity", 0); +} + +/* + * Format a date object to string + */ +function formatDate(date) { + return date.toLocaleString().replace(',', ''); +} + +export { initTooltip, createChart, updateChart };
\ No newline at end of file diff --git a/gui-pdp-monitoring/src/webapp/js/MonitoringConfig.js b/gui-pdp-monitoring/src/webapp/js/MonitoringConfig.js new file mode 100644 index 0000000..f929282 --- /dev/null +++ b/gui-pdp-monitoring/src/webapp/js/MonitoringConfig.js @@ -0,0 +1,127 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +// Configuration used for page layout and charts +const config = { + refresh: 5000, + restPort: 17999, + engineService: { + parent: "engineService", + tableId: "engineServicesTable", + headers: [{ + title: "Engine Service ID", + id: "engine_id" + }, { + title: "GroupName", + id: "group_name" + }, { + title: "SubGroupName", + id: "subgroup_name" + }, { + title: "HealthStatus", + id: "health_status" + }, { + title: "PdpState", + id: "pdp_state" + }, { + title: "Pap server:port", + id: "server_port" + }] + }, + engineSummary: { + parent: "engineSummary", + tableId: "engineSummaryTable", + headers: [{ + title: "Timestamp", + id: "timestamp" + }, { + title: "Sum of policy deploy", + id: "policy_deploy" + }, { + title: "Sum of policy deploy success", + id: "policy_deploy_success" + }, { + title: "Sum of policy deploy fail", + id: "policy_deploy_fail" + }, { + title: "Sum of policy executions", + id: "policy_executions" + }, { + title: "Sum of policy executions success", + id: "policy_executions_success" + }, { + title: "Sum of policy executions fail", + id: "policy_executions_fail" + }, { + title: "Up Time(ms)", + id: "up_time" + }], + chart: { + avgPolicyDurationChart: { + parent: "avgPolicyDuration", + title: "Average Policy Duration (ms)", + unit: "ms", + lineStroke: "#5FBADD", + nodeColour: "#00A9D4" + }, + } + }, + engineStatus: { + parent: "engineStatus", + tableId: "engineStatusTable", + headers: [{ + title: "Timestamp", + id: "timestamp" + }, { + title: "Engine ID", + id: "engine_id" + }, { + title: "Engine Status", + id: "engine_status" + }, { + title: "Last Message", + id: "last_message" + }, { + title: "Up Time (ms)", + id: "up_time" + }, { + title: "Policy Executions", + id: "policy_executions" + }] + }, + engineChart: { + lastPolicyDurationChart: { + parent: "lastPolicyDurationChart", + title: "Last Policy Duration (ms)", + unit: "ms", + lineStroke: "#F5A241", + nodeColour: "#F08A00" + }, + averagePolicyDurationChart: { + parent: "averagePolicyDurationChart", + title: "Average Policy Duration (ms)", + unit: "ms", + lineStroke: "#00625F", + nodeColour: "#007B78" + } + } +}; + +export { config, };
\ No newline at end of file diff --git a/gui-pdp-monitoring/src/webapp/js/MonitoringMain.js b/gui-pdp-monitoring/src/webapp/js/MonitoringMain.js new file mode 100644 index 0000000..456f3a9 --- /dev/null +++ b/gui-pdp-monitoring/src/webapp/js/MonitoringMain.js @@ -0,0 +1,109 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +import $ from "jquery"; +import { initTooltip } from "./MonitoringChart"; +import { getEngineURL, clearEngineURL, setUpPage, + removeChildrenElementsByClass, ajax_get_statistics +} from "./MonitoringUtils"; +import { setEngineServiceData } from "./PdpInformation"; +import { config } from "./MonitoringConfig"; +import { setEngineSummaryData } from "./PdpStatisticsSummary"; +import { highlightSelected } from "./PdpListView"; +import { setEngineStatusData } from "./PdpEngineWorkerStatus"; + +function servicesCallback(data){ + var engineURL = localStorage.getItem("pap-monitor-services"); + if (engineURL) { + engineURL = JSON.parse(engineURL); + if (engineURL.hostname === data.server && engineURL.port === data.port) { + setEngineServiceData(data.engineId, window.groupName, window.subGroupName, data.healthStatus, data.pdpState, data.server, data.port); + setEngineSummaryData(data.status, data.timeStamp, data.policyDeployCount, data.policyDeploySuccessCount, data.policyDeployFailCount, data.policyExecutedCount, data.policyExecutedSuccessCount, data.policyExecutedFailCount); + + if (window.engine_id === data.engineId){ + setEngineStatusData(data.status, false); + }else{ + removeChildrenElementsByClass(config.engineStatus.parent); + setEngineStatusData(data.status, true); + } + + window.engine_id = data.engineId; + + // Make content visible after data has been returned for the first time + if (!$(".content").is(':visible')) { + $(".content").fadeIn(); + } + + // Repeat the same request + setTimeout(function() { + window.servicesCall = ajax_get_statistics(window.restRootURL + "statistics/", servicesCallback, + window.services.useHttps, window.services.hostname, window.services.port, + window.services.username, window.services.password, window.id); + }, config.refresh); + } + } +} + +/* + * Called after the DOM is ready + */ +$(document).ready( + function() { + window.restRootURL = location.protocol + + "//" + + window.location.hostname + + ':' + config.restPort + + (location.pathname.endsWith("/monitoring/") ? location.pathname.substring(0, location.pathname.indexOf("monitoring/")) : location.pathname) + + "papservices/monitoring/"; + // Initialize tooltip for the charts + initTooltip(); + + // Set up the structure of the page + setUpPage(true); + + // Check cookies for engine URL + getEngineURL(); + + // Add click event to config icon for clearing engine URL + $(".ebSystemBar-config").click( + function() { + // Clear the engine URL + clearEngineURL(true); + + // Request the engine URL + getEngineURL(); + } + ); + + ['hashchange', 'load'].forEach(event => window.addEventListener(event, function() { + // Get ID from url + window.id = window.location.hash.replace('#', ''); + if (window.id !== ''){ + var arr = window.id.split("/"); + window.groupName = arr[0]; + window.subGroupName = arr[1]; + highlightSelected(window.id); + ajax_get_statistics(restRootURL + "statistics/", servicesCallback, + window.services.useHttps, window.services.hostname, window.services.port, + window.services.username, window.services.password, window.id); + } + })); + } +);
\ No newline at end of file diff --git a/gui-pdp-monitoring/src/webapp/js/MonitoringTable.js b/gui-pdp-monitoring/src/webapp/js/MonitoringTable.js new file mode 100644 index 0000000..229ef6a --- /dev/null +++ b/gui-pdp-monitoring/src/webapp/js/MonitoringTable.js @@ -0,0 +1,61 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +/* + * Create a table with given headers + */ +function createEngineTable(parent, id, tableHeaders) { + var table = createTable(id); + + var tableHead = document.createElement("thead"); + table.appendChild(tableHead); + tableHead.setAttribute("id", "engineTableHeader"); + + var tableHeaderRow = document.createElement("tr"); + tableHead.appendChild(tableHeaderRow); + tableHeaderRow.setAttribute("id", "engineTableHeaderRow"); + + for ( var t in tableHeaders) { + var tableHeader = document.createElement("th"); + tableHeaderRow.appendChild(tableHeader); + tableHeader.setAttribute("id", "engineTableHeader"); + tableHeader.appendChild(document.createTextNode(tableHeaders[t])); + } + + var tableBody = document.createElement("tbody"); + tableBody.setAttribute("id", "engineTableBody"); + table.appendChild(tableBody); + + parent.append(table); + + return table; +} + +/* + * Create a table and apply UISDK styles to it + */ +function createTable(id) { + var table = document.createElement("table"); + table.setAttribute("id", id); + table.setAttribute("class", "papTable ebTable elTablelib-Table-table ebTable_striped"); + return table; +} + +export { createEngineTable };
\ No newline at end of file diff --git a/gui-pdp-monitoring/src/webapp/js/MonitoringUtils.js b/gui-pdp-monitoring/src/webapp/js/MonitoringUtils.js new file mode 100644 index 0000000..9c6e076 --- /dev/null +++ b/gui-pdp-monitoring/src/webapp/js/MonitoringUtils.js @@ -0,0 +1,416 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +import $ from "jquery"; +import { createEngineServiceTable } from "./PdpInformation"; +import { createEngineSummaryTable } from "./PdpStatisticsSummary"; +import { RenderPdpList } from "./PdpListView"; + +/* + * Crate a dialog with input, attach it to a given parent and show an optional message + */ +function papDialogFormActivate(formParent, message) { + papUtilsRemoveElement("papDialogDiv"); + + var contentelement = document.createElement("papDialogDiv"); + var formDiv = document.createElement("div"); + var backgroundDiv = document.createElement("div"); + backgroundDiv.setAttribute("id", "papDialogDivBackground"); + backgroundDiv.setAttribute("class", "papDialogDivBackground"); + + backgroundDiv.appendChild(formDiv); + contentelement.appendChild(backgroundDiv); + formParent.appendChild(contentelement); + + formDiv.setAttribute("id", "papDialogDiv"); + formDiv.setAttribute("class", "papDialogDiv"); + + var headingSpan = document.createElement("span"); + formDiv.appendChild(headingSpan); + + headingSpan.setAttribute("class", "headingSpan"); + headingSpan.innerHTML = "PAP Configuration"; + + var form = document.createElement("papDialog"); + formDiv.appendChild(form); + + form.setAttribute("id", "papDialog"); + form.setAttribute("class", "form-style-1"); + form.setAttribute("method", "post"); + + if (message) { + var messageLI = document.createElement("li"); + messageLI.setAttribute("class", "dialogMessage"); + messageLI.innerHTML = message; + form.appendChild(messageLI); + } + + var services = localStorage.getItem("pap-monitor-services_old"); + //url + var input = createDialogList(form, "papDialogUrlInput","Pap rest baseURL:", "services_url_input", "http://localhost:12345", (services && services !== "null") ? JSON.parse(services).useHttps + "://" + JSON.parse(services).hostname + ":" + + JSON.parse(services).port : ""); + + //UserName + createDialogList(form, "papDialogUsernameInput","Pap UserName:", "services_username_input", "username", (services && services !== "null") ? JSON.parse(services).username : ""); + + //Password + createDialogList(form, "papDialogPasswordInput","Pap Password:", "services_password_input", "password", (services && services !== "null") ? JSON.parse(services).password : ""); + + //submit + var inputLI = document.createElement("li"); + form.appendChild(inputLI); + var submitInput = document.createElement("input"); + submitInput.setAttribute("id", "submit"); + submitInput.setAttribute("class", "button ebBtn"); + submitInput.setAttribute("type", "submit"); + submitInput.setAttribute("value", "Submit"); + submitInput.onclick = papDialogFormSubmitPressed; + inputLI.appendChild(submitInput); + + // Enter key press triggers submit + $(input).keyup(function(event) { + if (event.keyCode == 13) { + $(submitInput).click(); + } + }); + + input.focus(); +} + +function createDialogList(form, forA, reminder, id, placeholder, value_old){ + var diaLI = document.createElement("li"); + form.appendChild(diaLI); + + var diaLabel = document.createElement("label"); + diaLI.appendChild(diaLabel); + + diaLabel.setAttribute("for", forA); + diaLabel.innerHTML = reminder; + + var diaLabelSpan = document.createElement("span"); + diaLabel.appendChild(diaLabelSpan); + + diaLabelSpan.setAttribute("class", "required"); + diaLabelSpan.innerHTML = "*"; + + var input = document.createElement("input"); + input.setAttribute("id", id); + input.setAttribute("placeholder", placeholder); + input.value = value_old; + diaLI.appendChild(input); + return input; +} + +/* + * Create a dialog for displaying text + */ +function papTextDialogActivate(formParent, message, title) { + papUtilsRemoveElement("papDialogDiv"); + + var contentelement = document.createElement("div"); + contentelement.setAttribute("id", "papDialogDiv") + var formDiv = document.createElement("div"); + var backgroundDiv = document.createElement("div"); + backgroundDiv.setAttribute("id", "papDialogDivBackground"); + backgroundDiv.setAttribute("class", "papDialogDivBackground"); + + backgroundDiv.appendChild(formDiv); + contentelement.appendChild(backgroundDiv); + formParent.appendChild(contentelement); + + formDiv.setAttribute("id", "papErrorDialogDiv"); + formDiv.setAttribute("class", "papDialogDiv papErrorDialogDiv"); + + var headingSpan = document.createElement("span"); + formDiv.appendChild(headingSpan); + + headingSpan.setAttribute("class", "headingSpan"); + headingSpan.innerHTML = title; + + var form = document.createElement("div"); + formDiv.appendChild(form); + + form.setAttribute("id", "papDialog"); + form.setAttribute("class", "form-style-1"); + form.setAttribute("method", "post"); + + if (message) { + var messageLI = document.createElement("li"); + messageLI.setAttribute("class", "dialogMessage"); + messageLI.innerHTML = message; + form.appendChild(messageLI); + } + + var inputLI = document.createElement("li"); + form.appendChild(inputLI); + + var cancelInput = document.createElement("input"); + cancelInput.setAttribute("class", "button ebBtn"); + cancelInput.setAttribute("type", "submit"); + cancelInput.setAttribute("value", "Close"); + cancelInput.onclick = newModelFormCancelPressed; + form.appendChild(cancelInput); +} + +/* + * Create a Success dialog + */ +function papSuccessDialogActivate(formParent, message) { + papTextDialogActivate(formParent, message, "Success"); +} + +/* + * Create an Error dialog + */ +function papErrorDialogActivate(formParent, message) { + papTextDialogActivate(formParent, message, "Error"); +} + +/* + * Dialog cancel callback + */ +function newModelFormCancelPressed() { + papUtilsRemoveElement("papDialogDivBackground"); +} + +/* + * Dialog submit callback + */ +function papDialogFormSubmitPressed() { + var url = $('#services_url_input').val(); + var userName = $('#services_username_input').val(); + var passWord = $('#services_password_input').val(); + if (url.length > 0 && userName.length > 0 && passWord.length > 0) { + var engineConfig = { + useHttps : url.split(":")[0] == "https"? "https": "http", + hostname : url.split(":")[1].split("//")[1], + port : url.split(":")[2], + username : userName, + password : passWord + }; + localStorage.setItem("pap-monitor-services_old", JSON.stringify(engineConfig)); + localStorage.setItem("pap-monitor-services", JSON.stringify(engineConfig)); + papUtilsRemoveElement("papDialogDivBackground"); + getEngineURL(); + } +} + +/* + * Remove an element from the page + */ +function papUtilsRemoveElement(elementname) { + var element = document.getElementById(elementname); + if (element != null) { + element.parentNode.removeChild(element); + } +} + +function getHomepageURL() { + var homepageURL = location.protocol + + "//" + + window.location.hostname + + (location.port ? ':' + location.port : '') + + (location.pathname.endsWith("/monitoring/") ? location.pathname.substring(0, location.pathname + .indexOf("monitoring/")) : location.pathname); + location.href = homepageURL; +} + +function removeChildrenElementsByClass(className){ + var elements = document.getElementsByClassName(className); + elements[0].innerHTML = ''; +} + +/* + * Clears and resets all content on the page + */ +function setUpPage(clearPdps) { + // Hide all content + $('#content').hide(); + + // Clear each div + $('#content > div').each(function () { + $(this).empty(); + }); + + // clear hashchange + history.replaceState(null, null, ' '); + + //remove last search result of pdps. + if (clearPdps) { + removeChildrenElementsByClass('pdps__list'); + } else { + localStorage.setItem("pap-monitor-services", localStorage.getItem("pap-monitor-services_old")); + } + + // Reset trackers for tables + window.engineStatusTables = []; + + // Set up content div's + createEngineServiceTable(); + createEngineSummaryTable(); +} + +/* + * Retrieves the engine URL from the cookie. If it has not been set yet, then a + * dialog is shown asking for it + */ +function getEngineURL(message) { + // The engine URL is stored in a cookie using the key + // "pap-monitor-services" + var services = localStorage.getItem("pap-monitor-services"); + + // If an engine URL is stored in the cookie + if (services) { + // Parse the engine URL + window.services = JSON.parse(services); + + // Send a request with that engine URL + ajax_get(window.restRootURL, getPdpList, + window.services.useHttps, window.services.hostname, window.services.port, + window.services.username, window.services.password); + } else { + // Prompt for engine URL + papDialogFormActivate(document.body, message); + } +} + +/* + * Clears the cookie and reset the page + */ +function clearEngineURL(clearPdps) { + + if (typeof window.servicesCall !== "undefined") { + window.servicesCall.abort(); + } + + // Remove engine URL from cookie + localStorage.removeItem("pap-monitor-services"); + + // Reset the page + setUpPage(clearPdps); +} + +function getPdpList(data) { + const pdpArray = []; + for (let i = 0; i < data.groups.length; i++) { + var map = {}; + map.title = data.groups[i].name; + map.children = []; + (data.groups[i].pdpSubgroups).forEach((pdpSubgroup, index) => { + map.children[index] = {}; + map.children[index].title = pdpSubgroup.pdpType; + const instanceId = []; + pdpSubgroup.pdpInstances.forEach(pdpInstance => { + var instanceIdMap = {}; + instanceIdMap.title = pdpInstance.instanceId; + instanceId.push(instanceIdMap) + }); + map.children[index].children = instanceId; + }); + pdpArray.push(map); + } + RenderPdpList(pdpArray, 'pdps__list'); +} + +/* + * Send a GET request + */ +function ajax_get(requestURL, callback, useHttps, hostname, port, username, password, params, errorCallback) { + var data = { + useHttps: useHttps, + hostname: hostname, + port: port, + username: username, + password: password + }; + for (var p in params) { + data[p] = params[p]; + } + return $.ajax({ + type: 'GET', + url: requestURL, + dataType: "json", + data: data, + success: function (data, textStatus, jqXHR) { + if (callback) { + callback(data); + } + }, + error: function (jqXHR, textStatus, errorThrown) { + if (jqXHR.status == 500 || jqXHR.status == 404) { + if (jqXHR.status == 404 || jqXHR.responseText.indexOf("Request failed.") !== -1) { + clearEngineURL(true); + getEngineURL("Cannot connect to PAP"); + } else { + papErrorDialogActivate(document.body, jqXHR.responseText); + } + } + if (errorCallback) { + errorCallback(jqXHR, textStatus, errorThrown); + } + } + }); +} + +function ajax_get_statistics(requestURL, callback, useHttps, hostname, port, username, password, id, params, errorCallback) { + var data = { + useHttps: useHttps, + hostname: hostname, + port: port, + username: username, + password: password, + id: id + }; + for (var p in params) { + data[p] = params[p]; + } + return $.ajax({ + type: 'GET', + url: requestURL, + dataType: "json", + data: data, + success: function (data, textStatus, jqXHR) { + if (callback) { + callback(data); + } + }, + error: function (jqXHR, textStatus, errorThrown) { + if (jqXHR.status == 500 || jqXHR.status == 404) { + clearEngineURL(false); + papErrorDialogActivate(document.body, "Failed to get Statistics in DB."); + } + if (errorCallback) { + errorCallback(jqXHR, textStatus, errorThrown); + } + } + }); +} + +export { + removeChildrenElementsByClass, + papDialogFormActivate, + papErrorDialogActivate, + clearEngineURL, + getEngineURL, + setUpPage, + ajax_get, + ajax_get_statistics, + papUtilsRemoveElement, +};
\ No newline at end of file diff --git a/gui-pdp-monitoring/src/webapp/js/PdpEngineWorkerStatus.js b/gui-pdp-monitoring/src/webapp/js/PdpEngineWorkerStatus.js new file mode 100644 index 0000000..4ba8703 --- /dev/null +++ b/gui-pdp-monitoring/src/webapp/js/PdpEngineWorkerStatus.js @@ -0,0 +1,147 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +import $ from "jquery"; +import { createEngineTable } from "./MonitoringTable"; +import { config } from "./MonitoringConfig"; +import { createChart, updateChart } from "./MonitoringChart"; +/* + * Create an Engine Status Table and its charts + */ +function createEngineStatusTable(id, startStopStatus) { + var tableId = config.engineStatus.tableId; + var headers = config.engineStatus.headers; + + // Create a wrapper div for both the table and the charts + var wrapper = document.createElement("div"); + wrapper.setAttribute("id", id + "_wrapper"); + wrapper.setAttribute("class", "wrapper"); + $("." + config.engineStatus.parent).append(wrapper); + + // Create the table + var table = createEngineTable($(wrapper), id, headers.map(function(a) { + return a.title; + })); + var tableRow = document.createElement("tr"); + var tableData = ""; + for ( var h in headers) { + tableData += "<td id=" + tableId + "_" + headers[h].id + "></td>"; + } + tableRow.innerHTML = tableData; + // var actionTD = $(tableRow).find("#" + tableId + "_action"); + // var checked = (startStopStatus === "STOPPED") ? "checked" : ""; + var chartWrapper = document.createElement("div"); + chartWrapper.setAttribute("id", "chartWrapper"); + + $(table).children("#engineTableBody").append(tableRow); + + var expand = document.createElement("i"); + expand.setAttribute("class", "ebIcon ebIcon_rowExpanded ebIcon_large ebIcon_interactive expandIcon"); + $(expand).click(function() { + if ($(chartWrapper).is(":visible")) { + expand.setAttribute("class", "ebIcon ebIcon_rowCollapsed ebIcon_large ebIcon_interactive expandIcon"); + } else { + expand.setAttribute("class", "ebIcon ebIcon_rowExpanded ebIcon_large ebIcon_interactive expandIcon"); + } + $(chartWrapper).slideToggle(); + }.bind(window)); + $(wrapper).append(expand); + $(wrapper).append(chartWrapper); + return table; +} + +/* + * Check for any changes in the Engine Status Table data and its charts and + * update only where necessary + */ +function setEngineStatusData(engineStatusData, changed) { + var tableId = config.engineStatus.tableId; + var headers = config.engineStatus.headers.map(function(a) { + return a.id; + }); + for ( var esd in engineStatusData) { + var id = tableId + "_" + engineStatusData[esd].id; + var existingTable = undefined; + for ( var est in window.engineStatusTables) { + if (id === window.engineStatusTables[est].getAttribute("id")) { + existingTable = window.engineStatusTables[est]; + } + } + + var data = [ engineStatusData[esd].timestamp, id.split("_")[1], engineStatusData[esd].status, + engineStatusData[esd].lastMessage, engineStatusData[esd].upTime, + engineStatusData[esd].policyExecutions ]; + + var table = existingTable; + // If no table already exists for the engine, add one + if (!table || changed) { + table = createEngineStatusTable(id, engineStatusData[esd].status); + table.setAttribute("id", id); + table.style["margin-bottom"] = "10px"; + table.style.display = "inline-block"; + window.engineStatusTables.push(table); + } + + // Update data in table + for ( var h in headers) { + var td = $(table).find("#" + tableId + "_" + headers[h]); + if (td.html() !== data[h]) { + $(table).find("#" + tableId + "_" + headers[h]).html(data[h]); + } + } + + // Update charts + var wrapper = $(table).parent(); + var chartWrapper = $(wrapper).find("#chartWrapper") + + var chartConfig = config.engineChart.lastPolicyDurationChart; + var lastPolicyDurationChart = wrapper.find("#" + chartConfig.parent)[0]; + if (lastPolicyDurationChart) { + updateChart(lastPolicyDurationChart, JSON.parse(engineStatusData[esd].lastPolicyDuration), + chartConfig.nodeColour); + } else { + chartConfig = config.engineChart.lastPolicyDurationChart; + var lastPolicyDurationDiv = document.createElement("div"); + lastPolicyDurationDiv.setAttribute("id", chartConfig.parent); + lastPolicyDurationDiv.setAttribute("class", "papChart"); + createChart(JSON.parse(engineStatusData[esd].lastPolicyDuration), lastPolicyDurationDiv, + chartConfig.title, chartConfig.unit, chartConfig.lineStroke, chartConfig.nodeColour); + $(chartWrapper).append(lastPolicyDurationDiv); + } + + chartConfig = config.engineChart.averagePolicyDurationChart; + var averagePolicyDurationChart = wrapper.find("#" + chartConfig.parent)[0]; + if (averagePolicyDurationChart) { + updateChart(averagePolicyDurationChart, JSON.parse(engineStatusData[esd].averagePolicyDuration), + chartConfig.nodeColour); + } else { + chartConfig = config.engineChart.averagePolicyDurationChart; + var averagePolicyDurationDiv = document.createElement("div"); + averagePolicyDurationDiv.setAttribute("id", chartConfig.parent); + averagePolicyDurationDiv.setAttribute("class", "papChart"); + createChart(JSON.parse(engineStatusData[esd].averagePolicyDuration), averagePolicyDurationDiv, + chartConfig.title, chartConfig.unit, chartConfig.lineStroke, chartConfig.nodeColour); + $(chartWrapper).append(averagePolicyDurationDiv); + } + + } +} + +export { setEngineStatusData, };
\ No newline at end of file diff --git a/gui-pdp-monitoring/src/webapp/js/PdpInformation.js b/gui-pdp-monitoring/src/webapp/js/PdpInformation.js new file mode 100644 index 0000000..cbb71a7 --- /dev/null +++ b/gui-pdp-monitoring/src/webapp/js/PdpInformation.js @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +import $ from "jquery"; +import { config } from "./MonitoringConfig"; +import { createEngineTable } from "./MonitoringTable"; + +/* + * Create the Engine Service Table + */ +function createEngineServiceTable() { + var tableId = config.engineService.tableId; + var headers = config.engineService.headers; + var table = createEngineTable($("." + config.engineService.parent), tableId, headers.map(function(a) { + return a.title; + })); + var tableRow = document.createElement("tr"); + var tableData = ""; + for ( var h in headers) { + tableData += "<td id=" + tableId + "_" + headers[h].id + "></td>"; + } + tableRow.innerHTML = tableData; + $(table).children("#engineTableBody").append(tableRow); +} + +/* + * Check for any changes in the Engine Service Table data and update only where + * necessary + */ +function setEngineServiceData(engineId, groupName, subGroupName, healthStatus, pdpState, server, port) { + window.engineId = engineId; + var tableId = config.engineService.tableId; + var headers = config.engineService.headers.map(function(a) { + return a.id; + }); + var data = [ engineId, groupName, subGroupName, healthStatus, pdpState, server + ":" + port ]; + + var engineServiceTable = $("#engineServicesTable"); + + for ( var h in headers) { + var td = engineServiceTable.find("#" + tableId + "_" + headers[h]); + if (td.html() !== data[h]) { + engineServiceTable.find("#" + tableId + "_" + headers[h]).html(data[h]); + } + } +}; + +export { createEngineServiceTable, setEngineServiceData };
\ No newline at end of file diff --git a/gui-pdp-monitoring/src/webapp/js/PdpListView.js b/gui-pdp-monitoring/src/webapp/js/PdpListView.js new file mode 100644 index 0000000..1457a9e --- /dev/null +++ b/gui-pdp-monitoring/src/webapp/js/PdpListView.js @@ -0,0 +1,75 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +function RenderPdpList(treeArr, className) { + var $ = treeArr, + root = document.createDocumentFragment(), + childLevel = 0 + var index='' + var isNode=false + function insertChildren(parentNode, traverseArr, subGroup) { + + for(let i = 0; i < traverseArr.length; i++) { + if(parentNode === root) { + childLevel = 0 + } + var currentLi = document.createElement('li') + currentLi.setAttribute('level', childLevel) + if(traverseArr[i].children && traverseArr[i].children.length > 0) { + var title = document.createElement('div') + var triangle = document.createElement('i') + var text = document.createElement('p') + currentLi.classList.add('parentNode') + title.classList.add('title') + triangle.classList.add('triangle') + text.innerText = traverseArr[i].title + title.appendChild(triangle) + title.appendChild(text) + currentLi.appendChild(title) + childLevel++ + if(isNode) index="" + if(subGroup !== null){ + index+= subGroup+"/" + } + insertChildren(currentLi, traverseArr[i].children, traverseArr[i].title) + }else { + var a = document.createElement('a') + a.setAttribute('href',"#"+index+subGroup+"/"+traverseArr[i].title) + a.classList.add('pdps__link') + a.textContent= traverseArr[i].title + currentLi.appendChild(a) + isNode=true + } + parentNode.appendChild(currentLi) + } + } + insertChildren(root, $, null) + document.querySelector('ul.' + className + '').appendChild(root) +} + +function highlightSelected (id){ + const resultsArr = Array.from(document.querySelectorAll('.pdps__link')); + resultsArr.forEach(el => { + el.classList.remove('pdps__link--active'); + }); + document.querySelector(`.pdps__link[href*="${id}"]`).classList.add('pdps__link--active'); +}; + +export { RenderPdpList, highlightSelected, };
\ No newline at end of file diff --git a/gui-pdp-monitoring/src/webapp/js/PdpStatisticsSummary.js b/gui-pdp-monitoring/src/webapp/js/PdpStatisticsSummary.js new file mode 100644 index 0000000..4060c05 --- /dev/null +++ b/gui-pdp-monitoring/src/webapp/js/PdpStatisticsSummary.js @@ -0,0 +1,142 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +import $ from "jquery"; +import { config } from "./MonitoringConfig"; +import { createEngineTable } from "./MonitoringTable"; +import { createChart, updateChart } from "./MonitoringChart"; +import { papUtilsRemoveElement } from "./MonitoringUtils"; + +/* + * Create the Engine Service Table + */ +function createEngineSummaryTable() { + var tableId = config.engineSummary.tableId; + var headers = config.engineSummary.headers; + + // Create a wrapper div for both the table and the charts + var wrapper = document.createElement("div"); + wrapper.setAttribute("id", "engineSummary_wrapper"); + wrapper.setAttribute("class", "wrapper_borderless"); + $("." + config.engineSummary.parent).append(wrapper); + + var table = createEngineTable($(wrapper), tableId, headers.map(function(a) { + return a.title; + })); + var tableRow = document.createElement("tr"); + var tableData = ""; + for ( var h in headers) { + tableData += "<td id=" + tableId + "_" + headers[h].id + "></td>"; + } + tableRow.innerHTML = tableData; + + $(table).children("#engineTableBody").append(tableRow); + +} + +function setEngineSummaryData(data, timeStamp, policyDeployCount, policyDeploySuccessCount, policyDeployFailCount, policyExecutedCount, policyExecutedSuccessCount, policyExecutedFailCount) { + _setEngineSummaryData(timeStamp, getAvgPolicyDuration(data), policyDeployCount, policyDeploySuccessCount, policyDeployFailCount, policyExecutedCount, policyExecutedSuccessCount, policyExecutedFailCount, getUptimeOfOldestEngine(data)); +} + +/* + * Check for any changes in the Engine Summary Table data and update only where + * necessary + */ +function _setEngineSummaryData(timestamp, avgPolicyDuration, policyDeployCount, policyDeploySuccessCount, policyDeployFailCount, policyExecutedCount, policyExecutedSuccessCount, policyExecutedFailCount, upTime) { + + var tableId = config.engineSummary.tableId; + var headers = config.engineSummary.headers.map(function(a) { + return a.id; + }); + var data = [ timestamp, policyDeployCount, policyDeploySuccessCount, policyDeployFailCount, policyExecutedCount, policyExecutedSuccessCount, policyExecutedFailCount ,upTime == -1? "N/A":upTime]; + + var engineSummaryTable = $("#engineSummaryTable"); + + for ( var h in headers) { + var td = engineSummaryTable.find("#" + tableId + "_" + headers[h]); + if (td.html() !== data[h]) { + engineSummaryTable.find("#" + tableId + "_" + headers[h]).html(data[h]); + } + } + + // Update charts + var wrapper = engineSummaryTable.parent(); + var chartConfig = config.engineSummary.chart.avgPolicyDurationChart; + var avgPolicyDurationChart = wrapper.find("#" + chartConfig.parent)[0]; + if (avgPolicyDuration.length) { + if (avgPolicyDurationChart) { + updateChart(avgPolicyDurationChart, avgPolicyDuration, chartConfig.nodeColour); + } else { + var avgPolicyDurationDiv = document.createElement("div"); + avgPolicyDurationDiv.setAttribute("id", chartConfig.parent); + avgPolicyDurationDiv.setAttribute("class", "papChart_inline"); + createChart(avgPolicyDuration, avgPolicyDurationDiv, chartConfig.title, chartConfig.unit, + chartConfig.lineStroke, chartConfig.nodeColour); + $(wrapper).append(avgPolicyDurationDiv); + } + } else if (avgPolicyDurationChart){ + papUtilsRemoveElement(chartConfig.parent); + } +} + +function getUptimeOfOldestEngine(data) { + var oldestUpTime = -1; + for ( var d in data) { + if (data[d].upTime > oldestUpTime) { + oldestUpTime = data[d].upTime; + } + } + return oldestUpTime; +} + +function getSumOfPolicyExecutions(data) { + var totalPolicyExecutions = 0; + for ( var d in data) { + totalPolicyExecutions += data[d].policyExecutions; + } + return totalPolicyExecutions; +} + +function getAvgPolicyDuration(data) { + var chartData = []; + var avgPolicyDurations = []; + for ( var d in data) { + var avgPolicyDuration = JSON.parse(data[d].averagePolicyDuration); + avgPolicyDurations.push(avgPolicyDuration); + } + + if (avgPolicyDurations.length > 0) { + chartData = avgPolicyDurations[0]; + for (var i = 1; i < avgPolicyDurations.length; i++) { + var engineData = avgPolicyDurations[i]; + for ( var c in chartData) { + chartData[c].value += engineData[c].value; + } + } + } + + for ( var c2 in chartData) { + chartData[c2].value = Math.round(chartData[c2].value / data.length); + } + + return chartData; +} + +export { createEngineSummaryTable, setEngineSummaryData, };
\ No newline at end of file diff --git a/gui-pdp-monitoring/src/webapp/js/__test__/MonitoringUtils.test.js b/gui-pdp-monitoring/src/webapp/js/__test__/MonitoringUtils.test.js new file mode 100644 index 0000000..45fae79 --- /dev/null +++ b/gui-pdp-monitoring/src/webapp/js/__test__/MonitoringUtils.test.js @@ -0,0 +1,19 @@ +import $ from 'jquery'; +import { ajax_get, ajax_get_statistics } from "../MonitoringUtils"; + +$.ajax = jest.fn().mockImplementation(() => { + const fakeResponse = { + data: { + id: 1, + name: "All", + value: "Dummy Data" + } + }; + return Promise.resolve(fakeResponse); +}); + +test('ajax_get return ok', () => { + ajax_get().then(response => { + expect(response.data.id).toBe(1); + }); +});
\ No newline at end of file |