summaryrefslogtreecommitdiff
path: root/horizon/templatetags
diff options
context:
space:
mode:
authorGabriel Hurley <gabriel@strikeawe.com>2012-02-28 23:27:46 -0800
committerGabriel Hurley <gabriel@strikeawe.com>2012-02-29 00:20:13 -0800
commit052aa55d34a8d9ee9a58969c3a20587cac9adc04 (patch)
treec6fda0d1f8ce0ce870645cf8ba5532a7245b7fc7 /horizon/templatetags
parentfca0b641a733ff3f1b3697ca04ebffb65e6c20fa (diff)
downloadhorizon-052aa55d34a8d9ee9a58969c3a20587cac9adc04.tar.gz
Unifies the project packaging into one set of modules.
There are no longer two separate projects living inside the horizon repository. There is a single project now with a single setup.py, single README, etc. The openstack-dashboard/dashboard django project is now named "openstack_dashboard" and lives as an example project in the topmost horizon directory. The "horizon/horizon" directory has been bumped up a level and now is directly on the path when the root horizon directory is on your python path. Javascript media which the horizon module directly relies upon now ships in the horizon/static dir rather than openstack-dashboard/dashboard/static. All the corresponding setup, installation, build, and env scripts have been updated accordingly. Implements blueprint unified-packaging. Change-Id: Ieed8e3c777432cd046c3e0298869a9428756ab62
Diffstat (limited to 'horizon/templatetags')
-rw-r--r--horizon/templatetags/__init__.py0
-rw-r--r--horizon/templatetags/branding.py62
-rw-r--r--horizon/templatetags/horizon.py136
-rw-r--r--horizon/templatetags/parse_date.py77
-rw-r--r--horizon/templatetags/sizeformat.py77
-rw-r--r--horizon/templatetags/truncate_filter.py35
6 files changed, 387 insertions, 0 deletions
diff --git a/horizon/templatetags/__init__.py b/horizon/templatetags/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/horizon/templatetags/__init__.py
diff --git a/horizon/templatetags/branding.py b/horizon/templatetags/branding.py
new file mode 100644
index 000000000..a7681a5a2
--- /dev/null
+++ b/horizon/templatetags/branding.py
@@ -0,0 +1,62 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2012 Nebula, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+Template tags for customizing Horizon.
+"""
+
+from django import template
+from django.conf import settings
+
+
+register = template.Library()
+
+
+class SiteBrandingNode(template.Node):
+ def render(self, context):
+ return settings.SITE_BRANDING
+
+
+@register.tag
+def site_branding(parser, token):
+ return SiteBrandingNode()
+
+
+@register.tag
+def site_title(parser, token):
+ return settings.SITE_BRANDING
+
+
+# TODO(jeffjapan): This is just an assignment tag version of the above, replace
+# when the dashboard is upgraded to a django version that
+# supports the @assignment_tag decorator syntax instead.
+class SaveBrandingNode(template.Node):
+ def __init__(self, var_name):
+ self.var_name = var_name
+
+ def render(self, context):
+ context[self.var_name] = settings.SITE_BRANDING
+ return ""
+
+
+@register.tag
+def save_site_branding(parser, token):
+ tagname = token.contents.split()
+ return SaveBrandingNode(tagname[-1])
diff --git a/horizon/templatetags/horizon.py b/horizon/templatetags/horizon.py
new file mode 100644
index 000000000..696385593
--- /dev/null
+++ b/horizon/templatetags/horizon.py
@@ -0,0 +1,136 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 Nebula, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from __future__ import absolute_import
+
+import copy
+
+from django import template
+
+from horizon.base import Horizon
+
+
+register = template.Library()
+
+
+@register.filter
+def can_haz(user, component):
+ """
+ Checks if the given user meets the requirements for the component. This
+ includes both user roles and services in the service catalog.
+ """
+ if hasattr(user, 'roles'):
+ user_roles = set([role['name'].lower() for role in user.roles])
+ else:
+ user_roles = set([])
+ roles_statisfied = set(getattr(component, 'roles', [])) <= user_roles
+
+ if hasattr(user, 'roles'):
+ services = set([service['type'] for service in user.service_catalog])
+ else:
+ services = set([])
+ services_statisfied = set(getattr(component, 'services', [])) <= services
+
+ if roles_statisfied and services_statisfied:
+ return True
+ return False
+
+
+@register.filter
+def can_haz_list(components, user):
+ return [component for component in components if can_haz(user, component)]
+
+
+@register.inclusion_tag('horizon/_nav_list.html', takes_context=True)
+def horizon_main_nav(context):
+ """ Generates top-level dashboard navigation entries. """
+ if 'request' not in context:
+ return {}
+ current_dashboard = context['request'].horizon.get('dashboard', None)
+ dashboards = []
+ for dash in Horizon.get_dashboards():
+ if callable(dash.nav) and dash.nav(context):
+ dashboards.append(dash)
+ elif dash.nav:
+ dashboards.append(dash)
+ return {'components': dashboards,
+ 'user': context['request'].user,
+ 'current': getattr(current_dashboard, 'slug', None)}
+
+
+@register.inclusion_tag('horizon/_subnav_list.html', takes_context=True)
+def horizon_dashboard_nav(context):
+ """ Generates sub-navigation entries for the current dashboard. """
+ if 'request' not in context:
+ return {}
+ dashboard = context['request'].horizon['dashboard']
+ if isinstance(dashboard.panels, dict):
+ panels = copy.copy(dashboard.get_panels())
+ else:
+ panels = {dashboard.name: dashboard.get_panels()}
+
+ for heading, items in panels.iteritems():
+ temp_panels = []
+ for panel in items:
+ if callable(panel.nav) and panel.nav(context):
+ temp_panels.append(panel)
+ elif not callable(panel.nav) and panel.nav:
+ temp_panels.append(panel)
+ panels[heading] = temp_panels
+ non_empty_panels = dict([(k, v) for k, v in panels.items() if len(v) > 0])
+ return {'components': non_empty_panels,
+ 'user': context['request'].user,
+ 'current': context['request'].horizon['panel'].slug}
+
+
+@register.inclusion_tag('horizon/common/_progress_bar.html')
+def horizon_progress_bar(current_val, max_val):
+ """ Renders a progress bar based on parameters passed to the tag. The first
+ parameter is the current value and the second is the max value.
+
+ Example: ``{% progress_bar 25 50 %}``
+
+ This will generate a half-full progress bar.
+
+ The rendered progress bar will fill the area of its container. To constrain
+ the rendered size of the bar provide a container with appropriate width and
+ height styles.
+
+ """
+ return {'current_val': current_val,
+ 'max_val': max_val}
+
+
+class JSTemplateNode(template.Node):
+ """ Helper node for the ``jstemplate`` template tag. """
+ def __init__(self, nodelist):
+ self.nodelist = nodelist
+
+ def render(self, context, ):
+ output = self.nodelist.render(context)
+ return output.replace('[[', '{{').replace(']]', '}}')
+
+
+@register.tag
+def jstemplate(parser, token):
+ """
+ Replaces ``[[`` and ``]]`` with ``{{`` and ``}}`` to avoid conflicts
+ with Django's template engine when using any of the Mustache-based
+ templating libraries.
+ """
+ nodelist = parser.parse(('endjstemplate',))
+ parser.delete_first_token()
+ return JSTemplateNode(nodelist)
diff --git a/horizon/templatetags/parse_date.py b/horizon/templatetags/parse_date.py
new file mode 100644
index 000000000..523e6f2a9
--- /dev/null
+++ b/horizon/templatetags/parse_date.py
@@ -0,0 +1,77 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2012 Nebula, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+Template tags for parsing date strings.
+"""
+
+import datetime
+from django import template
+from dateutil import tz
+
+
+register = template.Library()
+
+
+def _parse_datetime(dtstr):
+ if not dtstr:
+ return "None"
+ fmts = ["%Y-%m-%dT%H:%M:%S.%f", "%Y-%m-%d %H:%M:%S.%f",
+ "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M:%S"]
+ for fmt in fmts:
+ try:
+ return datetime.datetime.strptime(dtstr, fmt)
+ except:
+ pass
+
+
+class ParseDateNode(template.Node):
+ def render(self, context):
+ """Turn an iso formatted time back into a datetime."""
+ if not context:
+ return "None"
+ date_obj = _parse_datetime(context)
+ return date_obj.strftime("%m/%d/%y at %H:%M:%S")
+
+
+@register.filter(name='parse_date')
+def parse_date(value):
+ return ParseDateNode().render(value)
+
+
+@register.filter(name='parse_datetime')
+def parse_datetime(value):
+ return _parse_datetime(value)
+
+
+@register.filter(name='parse_local_datetime')
+def parse_local_datetime(value):
+ dt = _parse_datetime(value)
+ local_tz = tz.tzlocal()
+ utc = tz.gettz('UTC')
+ local_dt = dt.replace(tzinfo=utc)
+ return local_dt.astimezone(local_tz)
+
+
+@register.filter(name='pretty_date')
+def pretty_date(value):
+ if not value:
+ return "None"
+ return value.strftime("%d/%m/%y at %H:%M:%S")
diff --git a/horizon/templatetags/sizeformat.py b/horizon/templatetags/sizeformat.py
new file mode 100644
index 000000000..68d7c1835
--- /dev/null
+++ b/horizon/templatetags/sizeformat.py
@@ -0,0 +1,77 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2012 Nebula, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+Template tags for displaying sizes
+"""
+
+from django import template
+from django.utils import translation
+from django.utils import formats
+
+
+register = template.Library()
+
+
+def int_format(value):
+ return int(value)
+
+
+def float_format(value):
+ return formats.number_format(round(value, 1), 0)
+
+
+def filesizeformat(bytes, filesize_number_format):
+ try:
+ bytes = float(bytes)
+ except (TypeError, ValueError, UnicodeDecodeError):
+ return translation.ungettext("%(size)d byte",
+ "%(size)d bytes", 0) % {'size': 0}
+
+ if bytes < 1024:
+ return translation.ungettext("%(size)d",
+ "%(size)d", bytes) % {'size': bytes}
+ if bytes < 1024 * 1024:
+ return translation.ugettext("%s KB") % \
+ filesize_number_format(bytes / 1024)
+ if bytes < 1024 * 1024 * 1024:
+ return translation.ugettext("%s MB") % \
+ filesize_number_format(bytes / (1024 * 1024))
+ if bytes < 1024 * 1024 * 1024 * 1024:
+ return translation.ugettext("%s GB") % \
+ filesize_number_format(bytes / (1024 * 1024 * 1024))
+ if bytes < 1024 * 1024 * 1024 * 1024 * 1024:
+ return translation.ugettext("%s TB") % \
+ filesize_number_format(bytes / (1024 * 1024 * 1024 * 1024))
+ return translation.ugettext("%s PB") % \
+ filesize_number_format(bytes / (1024 * 1024 * 1024 * 1024 * 1024))
+
+
+@register.filter(name='mbformat')
+def mbformat(mb):
+ if not mb:
+ return 0
+ return filesizeformat(mb * 1024 * 1024, int_format).replace(' ', '')
+
+
+@register.filter(name='diskgbformat')
+def diskgbformat(gb):
+ return filesizeformat(gb * 1024 * 1024 * 1024,
+ float_format).replace(' ', '')
diff --git a/horizon/templatetags/truncate_filter.py b/horizon/templatetags/truncate_filter.py
new file mode 100644
index 000000000..aca8468a1
--- /dev/null
+++ b/horizon/templatetags/truncate_filter.py
@@ -0,0 +1,35 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# Copyright 2012 Nebula, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+"""
+Template tags for truncating strings.
+"""
+
+from django import template
+
+register = template.Library()
+
+
+@register.filter("truncate")
+def truncate(value, size):
+ if len(value) > size and size > 3:
+ return value[0:(size - 3)] + '...'
+ else:
+ return value[0:size]