Module: check_mk
Branch: master
Commit: db236cf960439407a3dc40fb49b28dd9efbfcac6
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=db236cf9604394…
Author: Mathias Kettner <mk(a)mathias-kettner.de>
Date: Fri May 15 14:19:18 2015 +0200
Matrix layout: fix CSV export, fix minority detection
---
web/htdocs/htmllib.py | 3 ++-
web/htdocs/table.py | 2 +-
web/htdocs/views.py | 20 +++++++++++---
web/plugins/views/layouts.py | 57 ++++++++++++++++++++++++++++++++++-----
web/plugins/views/webservice.py | 6 +----
5 files changed, 72 insertions(+), 16 deletions(-)
diff --git a/web/htdocs/htmllib.py b/web/htdocs/htmllib.py
index 54f763a..e66d913 100644
--- a/web/htdocs/htmllib.py
+++ b/web/htdocs/htmllib.py
@@ -968,6 +968,7 @@ class html:
self.write('<a target="_top" href="%s"><img
class=statusicon src="images/status_pageurl.png"
title="%s"></a>\n' % \
("index.py?" + self.urlencode_vars([("start_url",
self.makeuri([]))]), _("URL to this page including sidebar")))
+ # TODO: Move this away from here. Make a context button. The view should handle
this
if self.myfile == "view" and self.var('mode') !=
'availability':
self.write('<a target="_top" href="%s">' \
'<img class=statusicon
src="images/status_download_csv.png" title="%s"></a>\n' %
\
@@ -1447,7 +1448,7 @@ class html:
if y == -1:
break
ht = ht[0:x] + ht[y+1:]
- return ht
+ return ht.replace(" ", " ")
def strip_scripts(self, ht):
while True:
diff --git a/web/htdocs/table.py b/web/htdocs/table.py
index b45fe4a..7470435 100644
--- a/web/htdocs/table.py
+++ b/web/htdocs/table.py
@@ -318,7 +318,7 @@ def end():
odd = "even"
for nr, (row, css, state, fixed) in enumerate(rows):
if do_csv:
- html.write(csv_separator.join([ html.strip_tags(cell_content) for
cell_content, css_classes, colspan in row ]))
+ html.write(csv_separator.join([html.strip_tags(cell_content) for
cell_content, css_classes, colspan in row ]))
html.write("\n")
else: # HTML output
diff --git a/web/htdocs/views.py b/web/htdocs/views.py
index 6971260..e140c36 100644
--- a/web/htdocs/views.py
+++ b/web/htdocs/views.py
@@ -1113,15 +1113,22 @@ def show_view(view, show_heading = False, show_buttons = True,
# always needed. In case of an embedded view in the reporting this
# field is simply missing, because the rendering is done by the
# report itself.
+ # TODO: CSV export should be handled by the layouts. It cannot
+ # be done generic in most cases
if html.output_format == "html":
if "layout" in view:
layout = multisite_layouts[view["layout"]]
else:
layout = None
else:
- layout = multisite_layouts.get(html.output_format)
- if not layout:
- layout = multisite_layouts["json"]
+ if "layout" in view and "csv_export" in
multisite_layouts[view["layout"]]:
+ multisite_layouts[view["layout"]]["csv_export"](rows,
view, group_painters, painters)
+ return
+ else:
+ # Generic layout of export
+ layout = multisite_layouts.get(html.output_format)
+ if not layout:
+ layout = multisite_layouts["json"]
# Until now no single byte of HTML code has been output.
# Now let's render the view. The render_function will be
@@ -2438,6 +2445,13 @@ def ajax_inv_render_tree():
else:
render_inv_subtree_container(hostname, tree_id, invpath, node)
+def output_csv_headers(view):
+ html.req.content_type = "text/csv; charset=UTF-8"
+ filename = '%s-%s.csv' % (view['name'],
time.strftime('%Y-%m-%d_%H-%M-%S', time.localtime(time.time())))
+ if type(filename) == unicode:
+ filename = filename.encode("utf-8")
+ html.req.headers_out['Content-Disposition'] = 'Attachment;
filename=%s' % filename
+
#.
# .--Icon Selector-------------------------------------------------------.
# | ___ ____ _ _ |
diff --git a/web/plugins/views/layouts.py b/web/plugins/views/layouts.py
index a2a6eab..2f3ab9d 100644
--- a/web/plugins/views/layouts.py
+++ b/web/plugins/views/layouts.py
@@ -571,7 +571,7 @@ def render_matrix(rows, view, group_painters, painters, num_columns,
_ignore_sho
html.write("<td class=cell><table>")
for painter_nr, p in enumerate(painters[1:]):
tdclass, content = prepare_paint(p, cell_row)
- gv = group_value(cell_row, [p])[0]
+ gv = group_value(cell_row, [p])
majority_value = row_majorities[row_id].get(painter_nr, None)
if majority_value != None and majority_value != gv:
tdclass += " minority"
@@ -587,6 +587,47 @@ def render_matrix(rows, view, group_painters, painters, num_columns,
_ignore_sho
html.write("</table>")
+def csv_export_matrix(rows, view, group_painters, painters):
+ output_csv_headers(view)
+
+ groups, unique_row_ids, matrix_cells = list(create_matrices(rows, group_painters,
painters, num_columns=None))[0]
+
+ table.begin(output_format="csv")
+ for painter_nr, painter in enumerate(group_painters):
+ table.row()
+ table.cell("", painter[0]["title"])
+ for group, group_row in groups:
+ tdclass, content = prepare_paint(painter, group_row)
+ table.cell("", content)
+
+ for row_id in unique_row_ids:
+ # Omit rows where all cells have the same values
+ if config.matrix_omit_uniform_lines:
+ at_least_one_different = False
+ for counts in value_counts[row_id].values():
+ if len(counts) > 1:
+ at_least_one_different = True
+ break
+ if not at_least_one_different:
+ continue
+
+ table.row()
+ tdclass, content = prepare_paint(painters[0], matrix_cells[row_id].values()[0])
+ table.cell("", content)
+
+ for group_id, group_row in groups:
+ table.cell("")
+ cell_row = matrix_cells[row_id].get(group_id)
+ if cell_row != None:
+ for painter_nr, p in enumerate(painters[1:]):
+ tdclass, content = prepare_paint(p, cell_row)
+ if painter_nr:
+ html.write(",")
+ html.write(content)
+
+ table.end()
+
+
def matrix_find_majorities(rows, painters, for_header):
counts = {} # dict row_id -> painter_nr -> value -> count
@@ -609,13 +650,16 @@ def matrix_find_majorities(rows, painters, for_header):
maj_entry = majorities.setdefault(row_id, {})
for painter_nr, painter_entry in row_entry.items():
maj_value = None
- max_count = 0
+ max_count = 0 # Absolute maximum count
+ max_non_unique = 0 # maximum count, but maybe non unique
for value, count in painter_entry.items():
- if count == max_count:
- maj_value = None # No majority
- elif count > max_count and count >= 2:
+ if count > max_non_unique and count >= 2:
maj_value = value
+ max_non_unique = count
max_count = count
+ elif count == max_non_unique:
+ maj_value = None
+ max_count = None
maj_entry[painter_nr] = maj_value
@@ -647,7 +691,7 @@ def create_matrices(rows, group_painters, painters, num_columns):
group_id = group_value(row, group_painters)
if group_id != last_group_id:
col_num += 1
- if col_num > num_columns:
+ if num_columns != None and col_num > num_columns:
yield (groups, unique_row_ids, matrix_cells)
groups = []
unique_row_ids = [] # not a set, but a list. Need to keep sort order!
@@ -674,6 +718,7 @@ def create_matrices(rows, group_painters, painters, num_columns):
multisite_layouts["matrix"] = {
"title" : _("Matrix"),
"render" : render_matrix,
+ "csv_export" : csv_export_matrix,
"group" : True,
"checkboxes" : False,
}
diff --git a/web/plugins/views/webservice.py b/web/plugins/views/webservice.py
index 6ca0251..ceae7d7 100644
--- a/web/plugins/views/webservice.py
+++ b/web/plugins/views/webservice.py
@@ -137,11 +137,7 @@ multisite_layouts["jsonp"] = {
def render_csv(rows, view, group_painters, painters, num_columns, show_checkboxes, export
= False):
if export:
- html.req.content_type = "text/csv; charset=UTF-8"
- filename = '%s-%s.csv' % (view['name'],
time.strftime('%Y-%m-%d_%H-%M-%S', time.localtime(time.time())))
- if type(filename) == unicode:
- filename = filename.encode("utf-8")
- html.req.headers_out['Content-Disposition'] = 'Attachment;
filename=%s' % filename
+ output_csv_headers(view)
csv_separator = html.var("csv_separator", ";")
first = True