Module: check_mk
Branch: master
Commit: d13e92c992481a2e3870af3b189dd715ef208649
URL:
http://git.mathias-kettner.de/git/?p=check_mk.git;a=commit;h=d13e92c992481a…
Author: Lars Michelsen <lm(a)mathias-kettner.de>
Date: Thu Oct 25 09:14:51 2018 +0200
Improved view filtering flexibility
Previously we had two different concepts for applying filters to views
and reports. Views could only be filtered by the filters that have
previously been configured by the view owner. In reports all available
filters for a data type could be used.
The view logic has now been changed to fit the report logic. It is now
equal to the report processing logic.
Filters now have this logic:
<ul>
<li>When you create a view without adding a filter the view will not
be filtered when accessing the view. There will be no filter dialog
offered via the GUI. New: The user may now provide a filter related
HTTP variable via URL to filter the view data.</li>
<li>To make a filter available to the user, you need to add this
filter to the view using the view editor.</li>
<li>To pre-filter a view you may add initial values to the filters
that are selected using the view editor.</li>
</ul>
This change was needed to support the configurable sidebar snapin
feature. It needs to be able to use arbitrary filters the user has
configured using the snapin.
Added some tests for the filter selection logic and cleaned up the
related functions a bit to reduce duplicated logic.
CMK-437
Change-Id: I68240571d1e2bb14859481b738fd67f58d8a4577
---
cmk/gui/views.py | 14 ++++++-------
cmk/gui/visuals.py | 41 ++++++++++++++++++++++----------------
tests/unit/cmk/gui/test_visuals.py | 26 ++++++++++++++++++++++++
3 files changed, 56 insertions(+), 25 deletions(-)
diff --git a/cmk/gui/views.py b/cmk/gui/views.py
index b92cc54..c937c7b 100644
--- a/cmk/gui/views.py
+++ b/cmk/gui/views.py
@@ -811,14 +811,14 @@ def page_view():
painter_options.load(view_name)
painter_options.update_from_url(view_name, view)
- show_view(view, True, True, True)
+ show_view(view, show_heading=True, show_buttons=True, show_footer=True)
# Display view with real data. This is *the* function everying
# is about.
def show_view(view, show_heading = False, show_buttons = True,
show_footer = True, render_function = None, only_count=False,
- all_filters_active=False, limit=None):
+ limit=None):
display_options.load_from_html()
@@ -844,15 +844,13 @@ def show_view(view, show_heading = False, show_buttons = True,
tablename = datasource["table"]
- # Filters to use in the view
- # In case of single object views, the needed filters are fixed, but not always
present
- # in context. In this case, take them from the context type definition.
- use_filters = visuals.filters_of_visual(view, datasource['infos'],
- all_filters_active,
datasource.get('link_filters', {}))
+ # Always allow the users to specify all allowed filters using the URL
+ use_filters =
visuals.filters_allowed_for_infos(datasource['infos']).values()
# Not all filters are really shown later in show_filter_form(), because filters
which
# have a hardcoded value are not changeable by the user
- show_filters = visuals.visible_filters_of_visual(view, use_filters)
+ show_filters = visuals.filters_of_visual(view, datasource['infos'],
link_filters=datasource.get('link_filters', {}))
+ show_filters = visuals.visible_filters_of_visual(view, show_filters)
# FIXME TODO HACK to make grouping single contextes possible on host/service infos
# Is hopefully cleaned up soon.
diff --git a/cmk/gui/visuals.py b/cmk/gui/visuals.py
index 0cbc55c..86c4db0 100644
--- a/cmk/gui/visuals.py
+++ b/cmk/gui/visuals.py
@@ -975,15 +975,31 @@ def show_filter(f):
def get_filter(name):
+ # type: (str) -> Type[Filter]
+ """Returns the filter object identified by the given name
+ Raises a KeyError in case a not existing filter is requested."""
return multisite_filters[name]
+
def filters_allowed_for_info(info):
+ # type (str) -> Dict[str, Type[Filter]]
+ """Returns a map of filter names and filter objects that are
registered for the given info"""
allowed = {}
for fname, filt in multisite_filters.items():
if filt.info == None or info == filt.info:
allowed[fname] = filt
return allowed
+
+def filters_allowed_for_infos(infos):
+ # type (List[str]) -> Dict[str, Type[Filter]]
+ """Same as filters_allowed_for_info() but for multiple
infos"""
+ filters = {}
+ for info in infos:
+ filters.update(filters_allowed_for_info(info))
+ return filters
+
+
# For all single_infos which are configured for a view which datasource
# does not provide these infos, try to match the keys of the single_info
# attributes to a filter which can then be used to filter the data of
@@ -1002,38 +1018,29 @@ def get_link_filter_names(visual, info_keys, link_filters):
return names
# Collects all filters to be used for the given visual
-def filters_of_visual(visual, info_keys, show_all=False, link_filters=None):
+def filters_of_visual(visual, info_keys, link_filters=None):
if link_filters is None:
link_filters = []
filters = []
- # Collect all available filters for these infos
- all_possible_filters = []
- for _filter_name, filter_ in multisite_filters.items():
- if filter_.info in info_keys:
- all_possible_filters.append(filter_)
-
for info_key in info_keys:
if info_key in visual['single_infos']:
for key in info_params(info_key):
filters.append(get_filter(key))
+ continue
- elif not show_all:
- for key, val in visual['context'].items():
- if type(val) == dict: # this is a real filter
- try:
- filters.append(get_filter(key))
- except KeyError:
- pass # Silently ignore not existing filters
+ for key, val in visual['context'].items():
+ if type(val) == dict: # this is a real filter
+ try:
+ filters.append(get_filter(key))
+ except KeyError:
+ pass # Silently ignore not existing filters
# See get_link_filter_names() comment for details
for key, dst_key in get_link_filter_names(visual, info_keys, link_filters):
filters.append(get_filter(dst_key))
- if show_all: # add *all* available filters of these infos
- filters += all_possible_filters
-
# add ubiquitary_filters that are possible for these infos
for fn in get_ubiquitary_filters():
# Disable 'wato_folder' filter, if WATO is disabled or there is a single
host view
diff --git a/tests/unit/cmk/gui/test_visuals.py b/tests/unit/cmk/gui/test_visuals.py
new file mode 100644
index 0000000..fbb2331
--- /dev/null
+++ b/tests/unit/cmk/gui/test_visuals.py
@@ -0,0 +1,26 @@
+import pytest
+
+import cmk.gui.plugins.visuals
+import cmk.gui.visuals as visuals
+
+
+def test_get_filter():
+ f = visuals.get_filter("hostregex")
+ assert isinstance(f, cmk.gui.plugins.visuals.Filter)
+
+
+def test_get_not_existing_filter():
+ with pytest.raises(KeyError):
+ visuals.get_filter("dingelig")
+
+
+def test_filters_allowed_for_info():
+ allowed = visuals.filters_allowed_for_info("host")
+ assert isinstance(allowed["host"],
cmk.gui.plugins.visuals.filters.FilterText)
+ assert "service" not in allowed
+
+
+def test_filters_allowed_for_infos():
+ allowed = visuals.filters_allowed_for_infos(["host", "service"])
+ assert isinstance(allowed["host"],
cmk.gui.plugins.visuals.filters.FilterText)
+ assert isinstance(allowed["service"],
cmk.gui.plugins.visuals.filters.FilterText)