Skip to content

Commit ed792df

Browse files
authored
Add Pie chart widget and fix chart config (#21)
1 parent e1fc5c7 commit ed792df

8 files changed

+290
-75
lines changed

chart/chart.html

+59-13
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,35 @@
2222
function (WidgetHelpers, Services, context) {
2323
WidgetHelpers.IncludeWidgetStyles();
2424
VSS.register("GHAzDoWidget.Chart", function () {
25+
async function renderTrendLine(organization, projectName, repoId, $container, chartService) {
26+
consoleLog('renderTrendLine');
27+
try {
28+
// get the trend data for alerts first
29+
const alertTrendLines = await getAlertsTrendLines(organization, projectName, repoId)
30+
consoleLog('Dependencies AlertTrend: ' + JSON.stringify(alertTrendLines.dependencyAlertsTrend));
31+
consoleLog('Code scanning AlertTrend: ' + JSON.stringify(alertTrendLines.codeAlertsTrend));
32+
consoleLog('Secrets AlertTrend: ' + JSON.stringify(alertTrendLines.secretAlertsTrend));
33+
34+
createChart($container, chartService, alertTrendLines);
35+
}
36+
catch (err) {
37+
consoleLog(`Error loading the alerts trend: ${err}`);
38+
}
39+
}
40+
41+
async function renderPieChart(organization, projectName, repoId, $container, chartService, alertType) {
42+
consoleLog('renderPieChart');
43+
try {
44+
// get the trend data for alerts first
45+
const alertSeverityCount = await getAlertSeverityCounts(organization, projectName, repoId, alertType);
46+
47+
createPieChart($container, chartService, alertSeverityCount);
48+
}
49+
catch (err) {
50+
consoleLog(`Error loading the alerts pie: ${err}`);
51+
}
52+
}
53+
2554
return {
2655
load: async function(widgetSettings) {
2756
return Services.ChartsService.getService().then(async function(chartService){
@@ -49,25 +78,42 @@
4978
let repoId
5079
// init empty object first
5180
let alertTrendLines = {secretAlertTrend: [], dependencyAlertTrend: [], codeAlertsTrend: []};
81+
let chartType = 1;
82+
let alertTypeConfig = 1;
83+
if (data && data.chartType && data.chartType !== "") {
84+
chartType = data.chartType;
85+
consoleLog('loaded chartType from widgetSettings: ' + chartType);
86+
}
87+
else {
88+
consoleLog('chartType is not set, using default value: ' + chartType);
89+
}
90+
91+
if (data && data.alertType) {
92+
alertTypeConfig = data.alertType;
93+
consoleLog('loaded alertType from widgetSettings: ' + alertTypeConfig);
94+
}
95+
5296
if (data && data.repo && data.repo !== "") {
5397
repoName = data.repo;
5498
repoId = data.repoId;
55-
consoleLog('loaded repoName from widgetSettings: ' + repoName);
5699

57-
$title.text(`Advanced Security Alerts Trend`)
58100
$container.text(`${data.repo}`)
59101

60-
try {
61-
// get the trend data for alerts first
62-
alertTrendLines = await getAlertsTrendLines(organization, projectName, repoId)
63-
consoleLog('Dependencies AlertTrend: ' + JSON.stringify(alertTrendLines.dependencyAlertsTrend));
64-
consoleLog('Code scanning AlertTrend: ' + JSON.stringify(alertTrendLines.codeAlertsTrend));
65-
consoleLog('Secrets AlertTrend: ' + JSON.stringify(alertTrendLines.secretAlertsTrend));
66-
67-
createChart($container, chartService, alertTrendLines);
68-
}
69-
catch (err) {
70-
consoleLog(`Error loading the alerts trend: ${err}`);
102+
switch (chartType) {
103+
case "2":
104+
try {
105+
const alertType = GetAlertTypeFromValue(alertTypeConfig);
106+
$title.text(`${alertType.display} Alerts by Severity`)
107+
renderPieChart(organization, projectName, repoId, $container, chartService, alertType);
108+
}
109+
catch (err) {
110+
consoleLog(`Error loading the alerts pie: ${err}`);
111+
}
112+
break;
113+
default:
114+
$title.text(`Advanced Security Alerts Trend`)
115+
renderTrendLine(organization, projectName, repoId, $container, chartService);
116+
break;
71117
}
72118
}
73119
else {

chart/chart.js

+38-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,43 @@ async function createChart($container, chartService, alertTrendLines){
3535
chartService.createChart($container, chartOptions);
3636
}
3737
catch (err) {
38-
console.log(`Error creating chart: ${err}`);
38+
console.log(`Error creating line chart: ${err}`);
39+
}
40+
}
41+
42+
async function createPieChart($container, chartService, alertSeverityCount) {
43+
// convert alertSeverityCount to two arrays, one for the labels and one for the data
44+
consoleLog(`createPieChart for alertSeverityCount: ${JSON.stringify(alertSeverityCount)}`);
45+
const labels = [];
46+
const data = [];
47+
for (const index in alertSeverityCount) {
48+
const item = alertSeverityCount[index];
49+
labels.push(item.severity);
50+
data.push(item.count);
51+
}
52+
53+
var chartOptions = {
54+
"hostOptions": {
55+
"height": "290",
56+
"width": "300"
57+
},
58+
"chartType": "pie",
59+
"series": [{
60+
"data": data
61+
}],
62+
"xAxis": {
63+
"labelValues": labels
64+
},
65+
"specializedOptions": {
66+
"showLabels": "true",
67+
"size": 200
68+
}
69+
};
70+
71+
try {
72+
chartService.createChart($container, chartOptions);
73+
}
74+
catch (err) {
75+
console.log(`Error creating pie chart: ${err}`);
3976
}
4077
}

chart/configuration_2x2.html

+97-49
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<html xmlns="http://www.w3.org/1999/xhtml">
33
<head>
44
<script src="../lib/VSS.SDK.min.js"></script>
5+
<script src="../library.js"></script>
56
<link rel="stylesheet" href="../styles.css" />
67

78
<script type="text/javascript">
@@ -13,22 +14,47 @@
1314
VSS.require(["VSS/Service", "TFS/Dashboards/WidgetHelpers", "VSS/Context", "TFS/VersionControl/GitRestClient"],
1415
function (Service, WidgetHelpers, context, GitWebApi) {
1516
VSS.register("GHAzDoWidget.Chart.Configuration", function () {
16-
var $repoDropdown = $("#repo-dropdown");
17-
18-
async function getRepos() {
19-
try {
20-
const webContext = VSS.getWebContext();
21-
const project = webContext.project;
22-
23-
// todo: load the available repos in this project
24-
const gitClient = Service.getClient(GitWebApi.GitHttpClient);
25-
repos = await gitClient.getRepositories(project.name);
26-
console.log(`Found these repos: ${JSON.stringify(repos)}`);
27-
return repos;
17+
const $repoDropdown = $("#repo-dropdown");
18+
const $chartTypeDropdown = $("#chart-type");
19+
const $alertTypeDropdown = $("#alert-type");
20+
21+
function reloadWidget(widgetConfigurationContext) {
22+
const customSettings = getSettings();
23+
var eventName = WidgetHelpers.WidgetEvent.ConfigurationChange;
24+
var eventArgs = WidgetHelpers.WidgetEvent.Args(customSettings);
25+
widgetConfigurationContext.notify(eventName, eventArgs);
26+
}
27+
28+
function getSettings() {
29+
if (repos) {
30+
// find the repo with this name
31+
const repo = repos.find(r => r.name === $repoDropdown.val());
32+
33+
if (repo) {
34+
var customSettings = {
35+
data: JSON.stringify({
36+
repo: $repoDropdown.val(),
37+
repoId: repo.id,
38+
chartType: $chartTypeDropdown.val(),
39+
alertType: $alertTypeDropdown.val()
40+
})
41+
};
42+
return customSettings;
43+
}
2844
}
29-
catch (err) {
30-
console.log(`Error loading the available repos: ${err}`);
31-
return [];
45+
46+
return {};
47+
}
48+
49+
function reloadChartOptions() {
50+
const chartType = $chartTypeDropdown.val();
51+
if (chartType === "1") {
52+
// trend line
53+
$("#alertTypePanel").hide();
54+
}
55+
else if (chartType === "2") {
56+
// pie chart
57+
$("#alertTypePanel").show();
3258
}
3359
}
3460

@@ -37,7 +63,7 @@
3763
var settings = JSON.parse(widgetSettings.customSettings.data);
3864
console.log(`Loading the Chart.2x2 settings with ${JSON.stringify(settings)}`)
3965

40-
const repos = await getRepos();
66+
const repos = await getRepos(VSS, Service, GitWebApi);
4167
// add all repos as selection options to the dropdown
4268
if (repos) {
4369
// add a top option to select no repo
@@ -54,39 +80,35 @@
5480
$repoDropdown.val(settings.repo);
5581
}
5682

57-
$repoDropdown.on("change", function () {
58-
let repo;
59-
if (repos) {
60-
// find the repo with this name
61-
repo = repos.find(r => r.name === $repoDropdown.val());
62-
}
83+
if (settings && settings.chartType) {
84+
// select the chartType that was saved in the settings
85+
$chartTypeDropdown.val(settings.chartType);
86+
}
6387

64-
var customSettings = {
65-
data: JSON.stringify({
66-
repo: $repoDropdown.val(),
67-
repoId: repo.id
68-
})
69-
};
70-
var eventName = WidgetHelpers.WidgetEvent.ConfigurationChange;
71-
var eventArgs = WidgetHelpers.WidgetEvent.Args(customSettings);
72-
widgetConfigurationContext.notify(eventName, eventArgs);
88+
if (settings && settings.alertType) {
89+
// select the alertType that was saved in the settings
90+
$alertTypeDropdown.val(settings.alertType);
91+
}
92+
93+
// register a change event handler for the dropdowns
94+
$repoDropdown.on("change", function () {
95+
reloadWidget(widgetConfigurationContext)
96+
});
97+
98+
$chartTypeDropdown.on("change", function () {
99+
reloadWidget(widgetConfigurationContext)
100+
reloadChartOptions();
101+
});
102+
103+
$alertTypeDropdown.on("change", function () {
104+
reloadWidget(widgetConfigurationContext)
73105
});
74106

75107
return WidgetHelpers.WidgetStatusHelper.Success();
76108
},
77109
onSave: async function() {
78-
const repos = await getRepos();
79-
let repo;
80-
if (repos) {
81-
// find the repo with this name
82-
repo = repos.find(r => r.name === $repoDropdown.val());
83-
}
84-
var customSettings = {
85-
data: JSON.stringify({
86-
repo: $repoDropdown.val(),
87-
repoId: repo.id
88-
})
89-
};
110+
const customSettings = getSettings();
111+
90112
console.log(`Saving the Chart.2x2 settings with ${JSON.stringify(customSettings)}`)
91113
return WidgetHelpers.WidgetConfigurationSave.Valid(customSettings);
92114
}
@@ -98,12 +120,38 @@
98120
</head>
99121
<body>
100122
<div class="container">
101-
<fieldset>
102-
<label class="label">Repository: </label>
103-
<select id="repo-dropdown" style="margin-top:10px">
104-
<!-- todo: dynamically load the available repos in this project-->
105-
</select>
106-
</fieldset>
123+
<table class="ghazdo-table">
124+
<tr>
125+
<td>
126+
<label class="label">Repository: </label>
127+
</td>
128+
<td>
129+
<select id="repo-dropdown" class="dropdown" style="margin-top:10px"></select>
130+
</td>
131+
</tr>
132+
<tr>
133+
<td>
134+
<label class="label">Chart type: </label>
135+
</td>
136+
<td>
137+
<select id="chart-type" class="dropdown">
138+
<option value="1">Trend line</option>
139+
<option value="2">Pie chart</option>
140+
</select>
141+
</td>
142+
</tr>
143+
<tr id="alertTypePanel">
144+
<td>
145+
<label class="label">Alert type: </label>
146+
</td>
147+
<td>
148+
<select id="alert-type" class="dropdown">
149+
<option value="1">Dependency</option>
150+
<option value="2">Secret</option>
151+
<option value="3">Code</option>
152+
</select>
153+
</td>
154+
</table>
107155
</div>
108156
</body>
109157
</html>

0 commit comments

Comments
 (0)