summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--reports/site_media/bcfg2_base.css26
-rw-r--r--src/lib/Bcfg2/Server/Reports/reports/templates/clients/detailed-list.html2
-rw-r--r--src/lib/Bcfg2/Server/Reports/reports/templates/clients/index.html40
-rw-r--r--src/lib/Bcfg2/Server/Reports/reports/templates/widgets/interaction_list.inc2
-rw-r--r--src/lib/Bcfg2/Server/Reports/reports/templatetags/bcfg2_tags.py69
5 files changed, 98 insertions, 41 deletions
diff --git a/reports/site_media/bcfg2_base.css b/reports/site_media/bcfg2_base.css
index d8066277c..d74c1b618 100644
--- a/reports/site_media/bcfg2_base.css
+++ b/reports/site_media/bcfg2_base.css
@@ -103,14 +103,36 @@ ul.menu-level2 {
bottom: 0px;
right: 0px;
}
-
-.dirty-lineitem {
+/*
+ * slightly-dirty: node is < 33% dirty
+ */
+.slightly-dirty-lineitem {
background: #FFAAAA;
}
+.slightly-dirty-lineitem a {
+ color: #10324b;
+ text-decoration: none;
+}
+/*
+ * dirty: node is >= 33% dirty but < 66% dirty
+ */
+.dirty-lineitem {
+ background: #FF7777;
+}
.dirty-lineitem a {
color: #10324b;
text-decoration: none;
}
+/*
+ * very-dirty: node is >= 66% dirty
+ */
+.very-dirty-lineitem {
+ background: #FF4444;
+}
+.very-dirty-lineitem a {
+ color: #10324b;
+ text-decoration: none;
+}
.clean-lineitem {
background: #AAFFBB;
}
diff --git a/src/lib/Bcfg2/Server/Reports/reports/templates/clients/detailed-list.html b/src/lib/Bcfg2/Server/Reports/reports/templates/clients/detailed-list.html
index 0c1fae8d5..84ac71d92 100644
--- a/src/lib/Bcfg2/Server/Reports/reports/templates/clients/detailed-list.html
+++ b/src/lib/Bcfg2/Server/Reports/reports/templates/clients/detailed-list.html
@@ -23,7 +23,7 @@
<tr class='{% cycle listview,listview_alt %}'>
<td class='left_column'><a href='{% url Bcfg2.Server.Reports.reports.views.client_detail hostname=entry.client.name, pk=entry.id %}'>{{ entry.client.name }}</a></td>
<td class='right_column' style='width:75px'><a href='{% add_url_filter state=entry.state %}'
- {% ifequal entry.state 'dirty' %}class='dirty-lineitem'{% endifequal %}>{{ entry.state }}</a></td>
+ class='{{entry|determine_client_state}}'>{{ entry.state }}</a></td>
<td class='right_column_narrow'>{{ entry.goodcount }}</td>
<td class='right_column_narrow'>{{ entry.bad_entry_count }}</td>
<td class='right_column_narrow'>{{ entry.modified_entry_count }}</td>
diff --git a/src/lib/Bcfg2/Server/Reports/reports/templates/clients/index.html b/src/lib/Bcfg2/Server/Reports/reports/templates/clients/index.html
index e0c0d2d7a..134e237d6 100644
--- a/src/lib/Bcfg2/Server/Reports/reports/templates/clients/index.html
+++ b/src/lib/Bcfg2/Server/Reports/reports/templates/clients/index.html
@@ -1,4 +1,5 @@
{% extends "base-timeview.html" %}
+{% load bcfg2_tags %}
{% block extra_header_info %}
{% endblock%}
@@ -8,27 +9,26 @@
{% block pagebanner %}Clients - Grid View{% endblock %}
{% block content %}
-
{% if inter_list %}
- <table class='grid-view' align='center'>
+ <table class='grid-view' align='center'>
{% for inter in inter_list %}
- {% if forloop.first %}<tr>{% endif %}
- <td class="{{inter.state}}-lineitem">
- <a href="{% spaceless %}{% if not timestamp %}
- {% url reports_client_detail inter.client.name %}
- {% else %}
- {% url reports_client_detail_pk inter.client.name,inter.id %}
- {% endif %}
- {% endspaceless %}">{{ inter.client.name }}</a>
- </td>
- {% if forloop.last %}
- </tr>
- {% else %}
- {% if forloop.counter|divisibleby:"4" %}</tr><tr>{% endif %}
- {% endif %}
- {% endfor %}
- </table>
-{% else %}
- <p>No client records are available.</p>
+ {% if forloop.first %}<tr>{% endif %}
+ <td class='{{ inter|determine_client_state }}'>
+ <a href="{% spaceless %}
+ {% if not timestamp %}
+ {% url reports_client_detail inter.client.name %}
+ {% else %}
+ {% url reports_client_detail_pk inter.client.name,inter.id %}
+ {% endif %}
+ {% endspaceless %}">{{ inter.client.name }}</a>
+ </td>
+ {% if forloop.last %}
+ </tr>
+ {% else %}
+ {% if forloop.counter|divisibleby:"4" %}</tr><tr>{% endif %}
+ {% endif %}
+ {% endfor %}
+ </table>
+{% else %}<p>No client records are available.</p>
{% endif %}
{% endblock %}
diff --git a/src/lib/Bcfg2/Server/Reports/reports/templates/widgets/interaction_list.inc b/src/lib/Bcfg2/Server/Reports/reports/templates/widgets/interaction_list.inc
index 8f2dec1dc..6fe7e6547 100644
--- a/src/lib/Bcfg2/Server/Reports/reports/templates/widgets/interaction_list.inc
+++ b/src/lib/Bcfg2/Server/Reports/reports/templates/widgets/interaction_list.inc
@@ -20,7 +20,7 @@
<td class='right_column_wide'><a href='{% add_url_filter hostname=entry.client.name %}'>{{ entry.client.name }}</a></td>
{% endif %}
<td class='right_column' style='width:75px'><a href='{% add_url_filter state=entry.state %}'
- {% ifequal entry.state 'dirty' %}class='dirty-lineitem'{% endifequal %}>{{ entry.state }}</a></td>
+ class='{{entry|determine_client_state}}'>{{ entry.state }}</a></td>
<td class='right_column_narrow'>{{ entry.goodcount }}</td>
<td class='right_column_narrow'>{{ entry.bad_entry_count }}</td>
<td class='right_column_narrow'>{{ entry.modified_entry_count }}</td>
diff --git a/src/lib/Bcfg2/Server/Reports/reports/templatetags/bcfg2_tags.py b/src/lib/Bcfg2/Server/Reports/reports/templatetags/bcfg2_tags.py
index 21c35270b..ac63cda3e 100644
--- a/src/lib/Bcfg2/Server/Reports/reports/templatetags/bcfg2_tags.py
+++ b/src/lib/Bcfg2/Server/Reports/reports/templatetags/bcfg2_tags.py
@@ -1,7 +1,8 @@
import sys
from django import template
-from django.core.urlresolvers import resolve, reverse, Resolver404, NoReverseMatch
+from django.core.urlresolvers import resolve, reverse, \
+ Resolver404, NoReverseMatch
from django.utils.encoding import smart_unicode, smart_str
from datetime import datetime, timedelta
from Bcfg2.Server.Reports.utils import filter_list
@@ -10,13 +11,14 @@ register = template.Library()
__PAGE_NAV_LIMITS__ = (10, 25, 50, 100)
+
@register.inclusion_tag('widgets/page_bar.html', takes_context=True)
def page_navigator(context):
"""
Creates paginated links.
- Expects the context to be a RequestContext and views.prepare_paginated_list()
- to have populated page information.
+ Expects the context to be a RequestContext and
+ views.prepare_paginated_list() to have populated page information.
"""
fragment = dict()
try:
@@ -69,17 +71,19 @@ def page_navigator(context):
pager = []
for page in range(pager_start, int(pager_end) + 1):
kwargs['page_number'] = page
- pager.append( (page, reverse(view, args=args, kwargs=kwargs)) )
+ pager.append((page, reverse(view, args=args, kwargs=kwargs)))
kwargs['page_number'] = 1
page_limits = []
for limit in __PAGE_NAV_LIMITS__:
kwargs['page_limit'] = limit
- page_limits.append( (limit, reverse(view, args=args, kwargs=kwargs)) )
+ page_limits.append((limit,
+ reverse(view, args=args, kwargs=kwargs)))
# resolver doesn't like this
del kwargs['page_number']
del kwargs['page_limit']
- page_limits.append( ('all', reverse(view, args=args, kwargs=kwargs) + "|all") )
+ page_limits.append(('all',
+ reverse(view, args=args, kwargs=kwargs) + "|all"))
fragment['pager'] = pager
fragment['page_limits'] = page_limits
@@ -96,6 +100,7 @@ def page_navigator(context):
fragment['path'] = path
return fragment
+
@register.inclusion_tag('widgets/filter_bar.html', takes_context=True)
def filter_navigator(context):
try:
@@ -113,13 +118,15 @@ def filter_navigator(context):
if filter in kwargs:
myargs = kwargs.copy()
del myargs[filter]
- filters.append( (filter, reverse(view, args=args, kwargs=myargs) ) )
+ filters.append((filter,
+ reverse(view, args=args, kwargs=myargs)))
filters.sort(lambda x, y: cmp(x[0], y[0]))
- return { 'filters': filters }
+ return {'filters': filters}
except (Resolver404, NoReverseMatch, ValueError, KeyError):
pass
return dict()
+
def _subtract_or_na(mdict, x, y):
"""
Shortcut for build_metric_list
@@ -129,29 +136,31 @@ def _subtract_or_na(mdict, x, y):
except:
return "n/a"
+
@register.filter
def build_metric_list(mdict):
"""
Create a list of metric table entries
- Moving this here it simplify the view. Should really handle the case where these
- are missing...
+ Moving this here to simplify the view.
+ Should really handle the case where these are missing...
"""
td_list = []
# parse
- td_list.append( _subtract_or_na(mdict, 'config_parse', 'config_download'))
+ td_list.append(_subtract_or_na(mdict, 'config_parse', 'config_download'))
#probe
- td_list.append( _subtract_or_na(mdict, 'probe_upload', 'start'))
+ td_list.append(_subtract_or_na(mdict, 'probe_upload', 'start'))
#inventory
- td_list.append( _subtract_or_na(mdict, 'inventory', 'initialization'))
+ td_list.append(_subtract_or_na(mdict, 'inventory', 'initialization'))
#install
- td_list.append( _subtract_or_na(mdict, 'install', 'inventory'))
+ td_list.append(_subtract_or_na(mdict, 'install', 'inventory'))
#cfg download & parse
- td_list.append( _subtract_or_na(mdict, 'config_parse', 'probe_upload'))
+ td_list.append(_subtract_or_na(mdict, 'config_parse', 'probe_upload'))
#total
- td_list.append( _subtract_or_na(mdict, 'finished', 'start'))
+ td_list.append(_subtract_or_na(mdict, 'finished', 'start'))
return td_list
+
@register.filter
def isstale(timestamp, entry_max=None):
"""
@@ -164,6 +173,7 @@ def isstale(timestamp, entry_max=None):
entry_max = datetime.now()
return entry_max - timestamp > timedelta(hours=24)
+
@register.filter
def sort_interactions_by_name(value):
"""
@@ -173,6 +183,7 @@ def sort_interactions_by_name(value):
inters.sort(lambda a, b: cmp(a.client.name, b.client.name))
return inters
+
class AddUrlFilter(template.Node):
def __init__(self, filter_name, filter_value):
self.filter_name = filter_name
@@ -198,7 +209,7 @@ class AddUrlFilter(template.Node):
link = reverse(view, args=args, kwargs=kwargs)
except NoReverseMatch:
link = reverse(self.fallback_view, args=None,
- kwargs={ filter_name: filter_value })
+ kwargs={filter_name: filter_value})
except NoReverseMatch:
rm = sys.exc_info()[1]
raise rm
@@ -206,6 +217,7 @@ class AddUrlFilter(template.Node):
pass
return link
+
@register.tag
def add_url_filter(parser, token):
"""
@@ -229,6 +241,7 @@ def add_url_filter(parser, token):
return AddUrlFilter(filter_name, filter_value)
+
@register.filter
def sortwell(value):
"""
@@ -241,6 +254,7 @@ def sortwell(value):
configItems.sort(lambda x, y: cmp(x.entry.kind, y.entry.kind))
return configItems
+
class MediaTag(template.Node):
def __init__(self, filter_value):
self.filter_value = filter_value
@@ -261,6 +275,7 @@ class MediaTag(template.Node):
pass
return "%s/%s" % (base, self.filter_value)
+
@register.tag
def to_media_url(parser, token):
"""
@@ -276,3 +291,23 @@ def to_media_url(parser, token):
return MediaTag(filter_value)
+@register.filter
+def determine_client_state(entry):
+ """
+ Determine client state.
+
+ This is used to determine whether a client is reporting clean or
+ dirty. If the client is reporting dirty, this will figure out just
+ _how_ dirty and adjust the color accordingly.
+ """
+ if entry.state == 'clean':
+ return "clean-lineitem"
+
+ bad_percentage = 100 * (float(entry.badcount()) / entry.totalcount)
+ if bad_percentage < 33:
+ thisdirty = "slightly-dirty-lineitem"
+ elif bad_percentage < 66:
+ thisdirty = "dirty-lineitem"
+ else:
+ thisdirty = "very-dirty-lineitem"
+ return thisdirty