21121: Add comments
[arvados.git] / tools / cluster-activity / arvados_cluster_activity / reportchart.py
1 #!/usr/bin/env python3
2 # Copyright (C) The Arvados Authors. All rights reserved.
3 #
4 # SPDX-License-Identifier: AGPL-3.0
5
6 import json
7 import pkg_resources
8 from datetime import datetime
9 from arvados._internal.report_template import ReportTemplate
10
11 sortablecss = """
12 <style>
13 @charset "UTF-8";
14 .sortable thead th:not(.no-sort) {
15   cursor: pointer;
16 }
17 .sortable thead th:not(.no-sort)::after, .sortable thead th:not(.no-sort)::before {
18   transition: color 0.1s ease-in-out;
19   font-size: 1.2em;
20   color: transparent;
21 }
22 .sortable thead th:not(.no-sort)::after {
23   margin-left: 3px;
24   content: "▸";
25 }
26 .sortable thead th:not(.no-sort):hover::after {
27   color: inherit;
28 }
29 .sortable thead th:not(.no-sort)[aria-sort=descending]::after {
30   color: inherit;
31   content: "▾";
32 }
33 .sortable thead th:not(.no-sort)[aria-sort=ascending]::after {
34   color: inherit;
35   content: "▴";
36 }
37 .sortable thead th:not(.no-sort).indicator-left::after {
38   content: "";
39 }
40 .sortable thead th:not(.no-sort).indicator-left::before {
41   margin-right: 3px;
42   content: "▸";
43 }
44 .sortable thead th:not(.no-sort).indicator-left:hover::before {
45   color: inherit;
46 }
47 .sortable thead th:not(.no-sort).indicator-left[aria-sort=descending]::before {
48   color: inherit;
49   content: "▾";
50 }
51 .sortable thead th:not(.no-sort).indicator-left[aria-sort=ascending]::before {
52   color: inherit;
53   content: "▴";
54 }
55
56 table.aggtable td:nth-child(2) {
57   text-align: right;
58 }
59
60 table.active-projects td:nth-child(4),
61 table.active-projects td:nth-child(5) {
62   text-align: right;
63   padding-right: 6em;
64 }
65
66 table.single-project td:nth-child(3),
67 table.single-project td:nth-child(4) {
68   text-align: right;
69   padding-right: 6em;
70 }
71
72 table.active-projects th:nth-child(4),
73 table.active-projects th:nth-child(5) {
74   text-align: left;
75 }
76
77 table.project td:nth-child(3),
78 table.project td:nth-child(4),
79 table.project td:nth-child(5),
80 table.project td:nth-child(6),
81 table.project td:nth-child(7) {
82   text-align: right;
83   padding-right: 6em;
84 }
85
86 table.project th:nth-child(3),
87 table.project th:nth-child(4),
88 table.project th:nth-child(5),
89 table.project th:nth-child(6),
90 table.project th:nth-child(7) {
91   text-align: left;
92 }
93 </style>
94 """
95
96 def date_export(item):
97     if isinstance(item, datetime):
98         return """@new Date("{}")@""".format(item.strftime("%Y-%m-%dT%H:%M:%SZ"))
99
100 class ReportChart(ReportTemplate):
101     CSS = 'https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.min.css'
102     JSLIB = 'https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.min.js'
103     JSASSETS = ['synchronizer.js', 'dygraphs.js', 'sortable.js']
104
105     def __init__(self, label, cards, graphs):
106         super(ReportChart, self).__init__(label)
107         self.cards = cards
108         self.graphs = graphs
109
110     def sections(self):
111         return [
112             {
113                 'label': k[0],
114                 'charts': [self.chartdata(k, v)]
115             }
116             for k,v in self.graphs.items()]
117
118     def chartdata(self, label, stats):
119         return {
120             'data': stats,
121             'options': {
122                 'legend': 'always',
123                 'connectSeparatedPoints': True,
124                 'labels': ['date', label[1]],
125                 'includeZero': True,
126                 'title': label[0]
127             },
128         }
129
130     def js(self):
131         return '''
132         <script type="text/javascript" src="{jslib}"></script>
133         <script type="text/javascript">
134         var chartdata = {chartdata};\n{jsassets}
135         </script>'''.format(
136             jslib=self.JSLIB,
137             chartdata=json.dumps(self.sections(), default=date_export).replace('"@', '').replace('@"', '').replace('\\"', '"'),
138             jsassets='\n'.join([pkg_resources.resource_string('arvados_cluster_activity', jsa).decode('utf-8') for jsa in self.JSASSETS]))
139
140     def style(self):
141         return '\n'.join((super().style(),
142                          sortablecss,
143                          '<link rel="stylesheet" href="{}">\n'.format(self.CSS)))