Skip to content

Commit

Permalink
Redirect on graph click (allegro#2999)
Browse files Browse the repository at this point in the history
  • Loading branch information
xliiv authored Mar 31, 2017
1 parent ded7f0e commit 9c79164
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 18 deletions.
23 changes: 22 additions & 1 deletion src/ralph/admin/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,28 @@ def _check_absolute_url(self, cls, model):
return []


class RalphAdminMixin(RalphAutocompleteMixin):
class DashboardChangelistMixin(object):

def _is_graph_preview_view(self, request):
return request.GET.get('graph-query', '')

def changelist_view(self, request, extra_context=None):
extra_context['is_graph_preview_view'] = self._is_graph_preview_view(
request
)
return super().changelist_view(request, extra_context)

def get_list_filter(self, request):
from ralph.dashboards.admin_filters import ByGraphFilter
filters = super().get_list_filter(request) or []
is_graph_model = getattr(self.model, '_allow_in_dashboard', False)
if is_graph_model and ByGraphFilter not in filters:
filters.append(ByGraphFilter)

return filters


class RalphAdminMixin(DashboardChangelistMixin, RalphAutocompleteMixin):
"""Ralph admin mixin."""

list_views = None
Expand Down
24 changes: 14 additions & 10 deletions src/ralph/admin/templates/admin/partials/filters.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@
<div class="small-2 columns sidebar actions-and-filters">
{% admin_actions %}
<div class="filters">
<h4>Filters</h4>
<div class="filter-container">
{% if is_popup %}
<input type="hidden" name="_popup" value="1" />
{% endif %}
{% for spec in cl.filter_specs %}
{% admin_list_filter cl spec %}
{% endfor %}
</div>
<input type="button" class="button" id="filter-button" value="Filter" />
{% if not is_graph_preview_view %}
<h4>Filters</h4>
<div class="filter-container">
{% if is_popup %}
<input type="hidden" name="_popup" value="1" />
{% endif %}
{% for spec in cl.filter_specs %}
{% admin_list_filter cl spec %}
{% endfor %}
</div>
<input type="button" class="button" id="filter-button" value="Filter" />
{% else %}
This is a graph preview. Filters are disabled.
{% endif %}
</div>
</div>
34 changes: 34 additions & 0 deletions src/ralph/dashboards/admin_filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from django.contrib import admin
from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext_lazy as _

from ralph.dashboards.models import Graph
from ralph.dashboards.renderers import GRAPH_QUERY_SEP


class ByGraphFilter(admin.SimpleListFilter):
title = _('Graph ID')
parameter_name = 'graph-query'
sep = GRAPH_QUERY_SEP
template = 'admin/filters/by-graph.html'

def lookups(self, request, model_admin):
return (
('', ''),
)

def tokenize(self, query_value):
return query_value.split(self.sep) if self.sep in query_value else (
None, None
)

def queryset(self, request, queryset):
graph_pk, graph_item = self.tokenize(self.value() or '')
if graph_pk and graph_item:
graph = get_object_or_404(Graph, pk=graph_pk)
queryset = graph.apply_parital_filtering(queryset)
queryset = queryset.filter(
**{graph.params['labels']: graph_item}
)

return queryset
20 changes: 13 additions & 7 deletions src/ralph/dashboards/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,21 +55,27 @@ def pop_annotate_filters(self, filters):
annotate_filters.update({key: filters.pop(key)})
return annotate_filters

def get_data(self):
model = self.model.model_class()
model_manager = model._default_manager
aggregate_type = AggregateType.from_id(self.aggregate_type)
queryset = model_manager.all()
def apply_parital_filtering(self, queryset):
filters = self.params.get('filters', None)
excludes = self.params.get('excludes', None)
annotate_filters = {}
if filters:
annotate_filters = self.pop_annotate_filters(filters)
queryset = FilterParser(queryset, filters).get_queryset()
if excludes:
queryset = FilterParser(
queryset, excludes, exclude_mode=True
).get_queryset()
return queryset

def get_data(self):
model = self.model.model_class()
model_manager = model._default_manager
aggregate_type = AggregateType.from_id(self.aggregate_type)
queryset = self.apply_parital_filtering(model_manager.all())
annotate_filters = {}
annotate_filters = self.pop_annotate_filters(
self.params.get('filters', None)
)

aggregate_func = aggregate_type.aggregate_func
queryset = queryset.values(
self.params['labels']
Expand Down
43 changes: 43 additions & 0 deletions src/ralph/dashboards/renderers.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import json
from urllib.parse import urlencode

from django.core.urlresolvers import reverse
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe


GRAPH_QUERY_SEP = '|'


class ChartistGraphRenderer(object):
"""Renderer for Chartist.js."""
func = None
Expand All @@ -14,6 +19,7 @@ class ChartistGraphRenderer(object):
'chartPadding': 20,
}
plugins = {'ctBarLabels': {}}
graph_query_sep = GRAPH_QUERY_SEP

def __init__(self, model):
self.model = model
Expand All @@ -34,13 +40,50 @@ def get_options(self, data=None):
options.update(self.options)
return options

def _labels2urls(self, content_type, graph_id, labels):
base_url = reverse(
"admin:%s_%s_changelist" % (
content_type.app_label, content_type.model
)
)
urls = []
for label in labels:
url = '?'.join([
base_url,
urlencode({
'graph-query': self.graph_query_sep.join([
str(graph_id), label
])
}),
])
urls.append(url)

return urls

def _series_with_urls(self, series, urls):
series_with_urls = []
for value, url in zip(series, urls):
series_with_urls.append({
'value': value,
'meta': {
'clickUrl': url,
}
})
return series_with_urls

def render(self, context):
if not context:
context = {}
error = None
data = {}
try:
data = self.model.get_data()
click_urls = self._labels2urls(
self.model.model, self.model.id, data['labels']
)
data['series'] = self._series_with_urls(
data['series'], click_urls
)
except Exception as e:
error = str(e)
finally:
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,31 @@ <h3>{{ graph.name }}</h3>
{% for plugin, options in plugins.items %}
Chartist.plugins.{{ plugin }}({{ options }})(graph);
{% endfor %}

graph.on("created", function () {
function gotUrl(meta) {
return ('clickUrl' in meta) ? true : false;
}

function redirectOnClick(item) {
var meta = Chartist.deserialize(item.getAttribute("ct:meta"));
if (meta && gotUrl(meta)) {
window.location = meta.clickUrl;
}
}

var clickable = jQuery('.ct-point, .ct-bar, .ct-pie', '.ct-series');
clickable.each(function() {
jQuery(this).on('click', function() {
redirectOnClick(event.target);
});

if (gotUrl(Chartist.deserialize(this.getAttribute("ct:meta")))) {
jQuery(this).css('cursor', 'pointer')
}
});
});

});
}(ralph.jQuery))
</script>

0 comments on commit 9c79164

Please sign in to comment.