Merge branch '21121-cluster-activity' refs #21121
[arvados.git] / sdk / python / arvados / _internal / report_template.py
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: Apache-2.0
4
5 try:
6     from html import escape
7 except ImportError:
8     from cgi import escape
9
10 import json
11 from typing import ItemsView
12
13 class ReportTemplate(object):
14     """Base class for HTML reports produced by Arvados reporting tools.
15
16     Used by crunchstat-summary and cluster-activity.
17
18     """
19
20     STYLE = '''
21     <style>
22         body {
23           background: #fafafa;
24           font-family: "Roboto", "Helvetica", "Arial", sans-serif;
25           font-size: 0.875rem;
26           color: rgba(0, 0, 0, 0.87);
27           font-weight: 400;
28         }
29         .card {
30           background: #ffffff;
31           box-shadow: 0px 1px 5px 0px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 3px 1px -2px rgba(0,0,0,0.12);
32           border-radius: 4px;
33           margin: 20px;
34         }
35         .content {
36           padding: 2px 16px 8px 16px;
37         }
38         table {
39           border-spacing: 0px;
40         }
41         tr {
42           height: 36px;
43           text-align: left;
44         }
45         th {
46           padding-right: 4em;
47           border-top: 1px solid rgba(224, 224, 224, 1);
48         }
49         td {
50           padding-right: 2em;
51           border-top: 1px solid rgba(224, 224, 224, 1);
52         }
53         #chart {
54           margin-left: -20px;
55         }
56     </style>
57     '''
58
59     def __init__(self, label):
60         self.label = label
61         self.cards = []
62
63     def cardlist(self, items):
64         if not isinstance(items, list):
65             items = [items]
66
67         return "\n".join(
68                 """
69                 <div class="card">
70                   <div class="content">
71 {}
72                   </div>
73                 </div>""".format(i) for i in items)
74
75     def html(self):
76         return '''<!doctype html>
77 <html>
78   <head>
79     <title>{label}</title>
80
81 {js}
82
83 {style}
84
85 {header}
86
87   </head>
88
89   <body>
90   <div class="card">
91     <div class="content">
92       <h1>{label}</h1>
93     </div>
94   </div>
95
96 {cards}
97
98   </body>
99 </html>
100         '''.format(label=escape(self.label),
101                    js=self.js(),
102                    style=self.style(),
103                    header=self.headHTML(),
104                    cards=self.cardlist(self.cards))
105
106     def js(self):
107         return ''
108
109     def style(self):
110         return self.STYLE
111
112     def headHTML(self):
113         """Return extra HTML text to include in HEAD."""
114         return ''