diff --git a/src/App.css b/src/App.css index f61edad..7cfd460 100644 --- a/src/App.css +++ b/src/App.css @@ -53,5 +53,5 @@ license that can be found in the LICENSE file. color:#6e6e6e; font-size: 20px; width: 100%; - padding-top: 5%; + padding-top: 1%; } \ No newline at end of file diff --git a/src/components/Dashboard.js b/src/components/Dashboard.js index 732a69e..f214ac6 100644 --- a/src/components/Dashboard.js +++ b/src/components/Dashboard.js @@ -26,6 +26,7 @@ const huskyCIAnalysisRoute = `${huskyCIAPIAddress}/stats/analysis`; const huskyCILanguageRoute = `${huskyCIAPIAddress}/stats/language`; const huskyCIContainerRoute = `${huskyCIAPIAddress}/stats/container`; const huskyCIRepositoryRoute = `${huskyCIAPIAddress}/stats/repository`; +const huskyCIHistoryAnalysisRoute = `${huskyCIAPIAddress}/stats/historyanalysis?time_range=today`; const huskyCISeverityRoute = `${huskyCIAPIAddress}/stats/severity`; const colorBlue = "#4fc0e8"; @@ -75,6 +76,58 @@ class Dashboard extends Component { snackOpen: false, variantValue: "", snackMessage: "", + passingList: [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + failingList: [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], }; this.timeoutID = 0; this.refreshCharts(); @@ -95,6 +148,8 @@ class Dashboard extends Component { this.openSnack("error", "Service is unavailable"); return response.status; } + + // get authors metrics if (huskyRoute === huskyCIAuthorRoute) { response.json().then(authorResultJSON => { if (Array.isArray(authorResultJSON) && authorResultJSON.length) { @@ -106,6 +161,8 @@ class Dashboard extends Component { } }); } + + // get Analysis metrics + Results graph if (huskyRoute === huskyCIAnalysisRoute) { response.json().then(analysisResultJSON => { let [ @@ -147,6 +204,98 @@ class Dashboard extends Component { } }); } + + // get History graph + if (huskyRoute === huskyCIHistoryAnalysisRoute) { + response.json().then(historyResultJSON => { + const [newPassingList, newFailingList] = [ + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + ]; + + Object.keys(historyResultJSON).forEach(key => { + const rawDateJSON = Date.parse(historyResultJSON[key].date); + const hour = new Date(rawDateJSON).getHours(); + + historyResultJSON[key].results.forEach(currentResult => { + if (currentResult.result === "passed") { + newPassingList[hour] = currentResult.count; + } + + if (currentResult.result === "failed") { + newFailingList[hour] = currentResult.count; + } + }); + }); + + const { passingList } = this.state; + const { failingList } = this.state; + + if (!_.isEqual(passingList, newPassingList)) { + this.setState({ + passingList: newPassingList, + }); + } + + if (!_.isEqual(failingList, newFailingList)) { + this.setState({ + failingList: newFailingList, + }); + } + }); + } + + // get languages graph if (huskyRoute === huskyCILanguageRoute) { let [ numGolangResult, @@ -181,6 +330,8 @@ class Dashboard extends Component { } }); } + + // get severity graph if (huskyRoute === huskyCISeverityRoute) { let [numNosec, numLow, numMedium, numHigh] = [0, 0, 0, 0]; response.json().then(severityResultJSON => { @@ -210,6 +361,8 @@ class Dashboard extends Component { } }); } + + // get container graph if (huskyRoute === huskyCIContainerRoute) { let [ numGosecResult, @@ -254,6 +407,8 @@ class Dashboard extends Component { } }); } + + // get repositories metrics if (huskyRoute === huskyCIRepositoryRoute) { let newRepositoryResult = 0; response.json().then(repositoryResultJSON => { @@ -264,8 +419,10 @@ class Dashboard extends Component { } }); } + return response.status; }) + .catch(() => { this.openSnack("error", "Service is unavailable"); return 500; @@ -295,6 +452,7 @@ class Dashboard extends Component { huskyCILanguageRoute, huskyCISeverityRoute, huskyCIRepositoryRoute, + huskyCIHistoryAnalysisRoute, ]; huskyCIRoutes.map(async huskyRoute => { const status = await this.callHuskyAPI(huskyRoute); @@ -332,7 +490,7 @@ class Dashboard extends Component { const numWarningFound = [resultsAnalysis.warning]; const numPassedFound = [resultsAnalysis.passed]; const numErrorFound = [resultsAnalysis.error]; - const infoAnalysis = { + const infoStatus = { labels: ["Failed", "Warning", "Passed", "Error"], datasets: [ { @@ -375,14 +533,88 @@ class Dashboard extends Component { }; const { numAuthors } = this.state; - const { numAnalysis } = this.state; - const { repositories } = this.state; - - const { snackOpen } = this.state; const { variantValue } = this.state; + const { snackOpen } = this.state; const { snackMessage } = this.state; + const { failingList } = this.state; + const { passingList } = this.state; + + const infoHistoryAnalysis = { + labels: [ + "00:00h", + "01:00h", + "02:00h", + "03:00h", + "04:00h", + "05:00h", + "06:00h", + "07:00h", + "08:00h", + "09:00h", + "10:00h", + "11:00h", + "12:00h", + "13:00h", + "14:00h", + "15:00h", + "16:00h", + "17:00h", + "18:00h", + "19:00h", + "20:00h", + "21:00h", + "22:00h", + "23:00h", + ], + datasets: [ + { + label: "Passing Analyses", + fill: false, + lineTension: 0.1, + borderWidth: 5, + backgroundColor: colorGreen, + borderColor: colorGreenHover, + borderCapStyle: "butt", + borderDash: [], + borderDashOffset: 0.0, + borderJoinStyle: "miter", + pointBorderColor: colorGreenHover, + pointBackgroundColor: "#fff", + pointBorderWidth: 4, + pointHoverRadius: 5, + pointHoverBackgroundColor: colorGreen, + pointHoverBorderColor: colorGreenHover, + pointHoverBorderWidth: 4, + pointRadius: 3, + pointHitRadius: 10, + data: passingList, + }, + { + label: "Failing Analyses", + fill: false, + lineTension: 0.1, + borderWidth: 5, + backgroundColor: colorRed, + borderColor: colorRedHover, + borderCapStyle: "butt", + borderDash: [], + borderDashOffset: 0.0, + borderJoinStyle: "miter", + pointBorderColor: colorRedHover, + pointBackgroundColor: "#fff", + pointBorderWidth: 4, + pointHoverRadius: 5, + pointHoverBackgroundColor: colorRed, + pointHoverBorderColor: colorRedHover, + pointHoverBorderWidth: 4, + pointRadius: 3, + pointHitRadius: 10, + data: failingList, + }, + ], + }; return (
@@ -398,9 +630,15 @@ class Dashboard extends Component { + + + + + + - + diff --git a/src/components/Graph.js b/src/components/Graph.js index d2c2637..11d378b 100644 --- a/src/components/Graph.js +++ b/src/components/Graph.js @@ -1,5 +1,5 @@ import { Paper } from "@material-ui/core"; -import { Bar, Doughnut, Pie } from "react-chartjs-2"; +import { Bar, Doughnut, Pie, Line } from "react-chartjs-2"; import PropTypes from "prop-types"; import React from "react"; @@ -30,10 +30,26 @@ const dounghnutChartDefaultOptions = { }, }; +const lineChartDefaultOptions = { + legend: { + display: true, + }, + scales: { + yAxes: [ + { + ticks: { + min: 0, + }, + }, + ], + }, +}; + const GraphType = { Pie: "Pie", Doughnut: "Doughnut", Bar: "Bar", + Line: "Line", }; const asDoughnut = ({ @@ -42,13 +58,19 @@ const asDoughnut = ({ height, options = dounghnutChartDefaultOptions, }) => ; + const asPie = ({ data, width, height, options = pieChartDefaultOptions }) => ( ); + const asBar = ({ data, width, height, options = barChartDefaultOptions }) => ( ); +const asLine = ({ data, width, height, options = lineChartDefaultOptions }) => ( + +); + const renderGraph = props => { switch (props.type) { case GraphType.Bar: @@ -57,6 +79,8 @@ const renderGraph = props => { return asDoughnut({ ...props }); case GraphType.Pie: return asPie({ ...props }); + case GraphType.Line: + return asLine({ ...props }); default: return asBar({ ...props }); }