Skip to content

Commit 994f773

Browse files
authored
Visual update of scores on analysis tab. (#1419)
* Visual update of scores on analysis tab. * Switching to thin line. * Code review updates
1 parent dcc180c commit 994f773

14 files changed

+896
-213
lines changed

app/lib/frontend/color.dart

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
/// Represents an RGBA color code.
6+
class Color {
7+
static const black = const Color(0, 0, 0);
8+
static const blue = const Color(0, 0, 255);
9+
static const green = const Color(0, 255, 0);
10+
static const peach = const Color(255, 229, 180);
11+
static const red = const Color(255, 0, 0);
12+
static const silver = const Color(192, 192, 192);
13+
static const slateGray = const Color(112, 128, 144);
14+
static const white = const Color(255, 255, 255);
15+
16+
final int r;
17+
final int g;
18+
final int b;
19+
final double a;
20+
21+
const Color(this.r, this.g, this.b, [this.a = 1.0]);
22+
23+
Color change({int r, int g, int b, double a}) =>
24+
new Color(r ?? this.r, g ?? this.g, b ?? this.b, a ?? this.a);
25+
26+
Color interpolateTo(Color to, double value) {
27+
final red = ((to.r - r) * value).round() + r;
28+
final green = ((to.g - g) * value).round() + g;
29+
final blue = ((to.b - b) * value).round() + b;
30+
final alpha = ((to.a - a) * value) + a;
31+
return new Color(red, green, blue, alpha);
32+
}
33+
34+
Color multipleValues(double value) {
35+
return change(
36+
r: (r * value).round(),
37+
g: (g * value).round(),
38+
b: (b * value).round(),
39+
);
40+
}
41+
42+
@override
43+
String toString() => a == 1.0
44+
? 'rgb($r, $g, $b)'
45+
: 'rgba($r, $g, $b, ${a.toStringAsFixed(4)})';
46+
}
47+
48+
/// Represents the selection of colors that will be used to draw a specific shape.
49+
class Brush {
50+
final Color background;
51+
final Color color;
52+
final Color shadow;
53+
54+
const Brush({this.background, this.color, this.shadow});
55+
56+
Brush interpolateTo(Brush to, double value) {
57+
return new Brush(
58+
background: background.interpolateTo(to.background, value),
59+
color: color.interpolateTo(to.color, value),
60+
shadow: shadow.interpolateTo(to.shadow, value),
61+
);
62+
}
63+
64+
Brush change({Color background, Color color, Color shadow}) {
65+
return new Brush(
66+
background: background ?? this.background,
67+
color: color ?? this.color,
68+
shadow: shadow ?? this.shadow);
69+
}
70+
}
71+
72+
/// A semi-transparent black for using as a non-intrusive shadow.
73+
final _blackShadow = Color.black.change(a: 0.5);
74+
75+
/// Color to use when the analysis/score is missing (skipped or not done yet).
76+
final _scoreBoxMissing = new Color(204, 204, 204);
77+
78+
/// Color to use when the analysis result was top of the range (70+).
79+
final _scoreBoxSolid = new Color(1, 117, 194);
80+
81+
/// Color to use when the analysis result was in the middle of the range (40-70)
82+
final _scoreBoxGood = new Color(0, 196, 179);
83+
84+
/// Color to use when the analysis result was in the lower range (0-40)
85+
final _scoreBoxRotten = new Color(187, 36, 0);
86+
87+
/// The default set of colors to use.
88+
final _defaultBrush = new Brush(
89+
background: _scoreBoxMissing, color: Color.white, shadow: _blackShadow);
90+
91+
/// Get the [Brush] that will be used to render the overall score progress bar.
92+
Brush overallScoreBrush(double score) {
93+
if (score == null) {
94+
return _defaultBrush;
95+
}
96+
if (score <= 0.4) {
97+
return _defaultBrush.change(background: _scoreBoxRotten);
98+
}
99+
if (score <= 0.7) {
100+
return _defaultBrush.change(background: _scoreBoxGood);
101+
}
102+
return _defaultBrush.change(background: _scoreBoxSolid);
103+
}
104+
105+
/// Get the [Brush] that will be used to render the generic score progress bars
106+
/// (e.g. popularity or health score).
107+
Brush genericScoreBrush(double score) {
108+
if (score == null) {
109+
return _defaultBrush;
110+
}
111+
final bg = Color.slateGray.interpolateTo(Color.silver, score);
112+
return _defaultBrush.change(background: bg);
113+
}

app/lib/frontend/templates.dart

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import '../shared/search_service.dart' show SearchQuery, serializeSearchOrder;
2020
import '../shared/urls.dart' as urls;
2121
import '../shared/utils.dart';
2222

23+
import 'color.dart';
2324
import 'model_properties.dart' show Author;
2425
import 'models.dart';
2526
import 'static_files.dart';
@@ -276,10 +277,7 @@ class TemplateService {
276277
'has_dev': devDeps.isNotEmpty,
277278
'dev': devDeps,
278279
},
279-
'health': _formatScore(extract?.health),
280-
'maintenance': _formatScore(extract?.maintenance),
281-
'popularity': _formatScore(extract?.popularity),
282-
'score_box_html': _renderScoreBox(analysisStatus, extract?.overallScore),
280+
'score_bars': _renderScoreBars(extract),
283281
};
284282

285283
return _renderTemplate('pkg/analysis_tab', data);
@@ -420,6 +418,34 @@ class TemplateService {
420418
return values;
421419
}
422420

421+
Map<String, dynamic> _renderScoreBars(AnalysisExtract extract) {
422+
String renderScoreBar(double score, Brush brush) {
423+
return _renderTemplate('pkg/score_bar', {
424+
'percent': _formatScore(score ?? 0.0),
425+
'score': _formatScore(score),
426+
'background': brush.background.toString(),
427+
'color': brush.color.toString(),
428+
'shadow': brush.shadow.toString(),
429+
});
430+
}
431+
432+
final analysisSkipped = _isAnalysisSkipped(extract?.analysisStatus);
433+
final healthScore = extract?.health;
434+
final maintenanceScore = extract?.maintenance;
435+
final popularityScore = extract?.popularity;
436+
final overallScore = analysisSkipped ? null : extract?.overallScore ?? 0.0;
437+
return {
438+
'health_html':
439+
renderScoreBar(healthScore, genericScoreBrush(healthScore)),
440+
'maintenance_html':
441+
renderScoreBar(maintenanceScore, genericScoreBrush(maintenanceScore)),
442+
'popularity_html':
443+
renderScoreBar(popularityScore, genericScoreBrush(popularityScore)),
444+
'overall_html':
445+
renderScoreBar(overallScore, overallScoreBrush(overallScore)),
446+
};
447+
}
448+
423449
String _renderLicenses(String baseUrl, List<LicenseFile> licenses) {
424450
if (licenses == null || licenses.isEmpty) return null;
425451
return licenses.map((license) {
@@ -835,10 +861,12 @@ String _getAuthorsHtml(List<String> authors) {
835861
}).join('<br/>');
836862
}
837863

864+
bool _isAnalysisSkipped(AnalysisStatus status) =>
865+
status == AnalysisStatus.outdated || status == AnalysisStatus.discontinued;
866+
838867
String _renderScoreBox(AnalysisStatus status, double overallScore,
839868
{bool isNewPackage, String package}) {
840-
final skippedAnalysis = status == AnalysisStatus.outdated ||
841-
status == AnalysisStatus.discontinued;
869+
final skippedAnalysis = _isAnalysisSkipped(status);
842870
final score = skippedAnalysis ? null : overallScore;
843871
final String formattedScore = _formatScore(score);
844872
final String scoreClass = _classifyScore(score);

app/test/frontend/golden/analysis_tab_aborted.html

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,3 @@
1-
<h2>Analysis</h2>
2-
3-
<p>
4-
We analyzed this package on Dec 18, 2017, and provided a score, details, and suggestions below.
5-
Analysis was completed with status <i>aborted</i> using:
6-
</p>
7-
8-
<ul>
9-
<li>Dart: </li>
10-
<li>pana: 0.8.0</li>
11-
12-
</ul>
13-
14-
<hr />
15-
16-
<h4>Scores</h4>
17-
181
<table id='scores-table'>
192
<tr>
203
<td class="score-name">
@@ -26,8 +9,19 @@ <h4>Scores</h4>
269
</div>
2710
</div>
2811
</td>
29-
<td class="score-value">--</td>
30-
<td class="score-range">/ 100</td>
12+
<td class="score-value">
13+
14+
<div class="score-percent-row">
15+
<div class="score-percent" style="left: 0%;">--</div>
16+
</div>
17+
18+
<div class="score-progress-row">
19+
<div class="score-progress-frame">
20+
<div class="score-progress" style="width: 0%; background: rgb(204, 204, 204);"></div>
21+
</div>
22+
</div>
23+
24+
</td>
3125
</tr>
3226
<tr>
3327
<td class="score-name">
@@ -39,8 +33,17 @@ <h4>Scores</h4>
3933
</div>
4034
</div>
4135
</td>
42-
<td class="score-value">--</td>
43-
<td class="score-range">/ 100</td>
36+
<td class="score-value">
37+
<div class="score-percent-row">
38+
<div class="score-percent" style="left: 0%;">--</div>
39+
</div>
40+
41+
<div class="score-progress-row">
42+
<div class="score-progress-frame">
43+
<div class="score-progress" style="width: 0%; background: rgb(204, 204, 204);"></div>
44+
</div>
45+
</div>
46+
</td>
4447
</tr>
4548
<tr>
4649
<td class="score-name">
@@ -52,24 +55,56 @@ <h4>Scores</h4>
5255
</div>
5356
</div>
5457
</td>
55-
<td class="score-value">--</td>
56-
<td class="score-range">/ 100</td>
58+
<td class="score-value">
59+
<div class="score-percent-row">
60+
<div class="score-percent" style="left: 0%;">--</div>
61+
</div>
62+
63+
<div class="score-progress-row">
64+
<div class="score-progress-frame">
65+
<div class="score-progress" style="width: 0%; background: rgb(204, 204, 204);"></div>
66+
</div>
67+
</div>
68+
</td>
5769
</tr>
5870
<tr>
5971
<td class="score-name">
6072
<div class="tooltip-base hoverable">
61-
<span class="tooltip-dotted"><b>Overall score:</b></span>
73+
<span class="tooltip-dotted"><b>Overall:</b></span>
6274
<div class="tooltip-content">
6375
Weighted score of the above.
6476
<a href="/help#overall-score">[more]</a>
6577
</div>
6678
</div>
6779
</td>
68-
<td><div class="score-box"><span class="number -missing" title="Awaiting analysis to complete.">--</span></div></td>
80+
<td>
81+
<div class="score-percent-row">
82+
<div class="score-percent" style="left: 0%;">0</div>
83+
</div>
84+
85+
<div class="score-progress-row">
86+
<div class="score-progress-frame">
87+
<div class="score-progress" style="width: 0%; background: rgb(187, 36, 0);"></div>
88+
</div>
89+
</div>
90+
</td>
6991
</tr>
7092
</table>
7193

72-
Learn more about <a href="/help#scoring">scoring</a>.
94+
<div style="text-align: right; font-size: 10pt;">Learn more about <a href="/help#scoring">scoring</a>.</div>
95+
96+
<hr />
97+
98+
<p>
99+
We analyzed this package on Dec 18, 2017, and provided a score, details, and suggestions below.
100+
Analysis was completed with status <i>aborted</i> using:
101+
</p>
102+
103+
<ul>
104+
<li>Dart: </li>
105+
<li>pana: 0.8.0</li>
106+
107+
</ul>
73108

74109
<h4>Platforms</h4>
75110

0 commit comments

Comments
 (0)