diff options
author | Lin Hua Cheng <lin-hua.cheng@hp.com> | 2013-08-19 09:44:12 -0700 |
---|---|---|
committer | Lin Hua Cheng <lin-hua.cheng@hp.com> | 2013-08-20 11:08:43 -0700 |
commit | 7f51d554019e02269ebda98f1d097e89862c8da0 (patch) | |
tree | 63cfae6b0634a847ecd574612d8216be535aa4d4 /openstack_dashboard/dashboards/project/containers | |
parent | c17a29390d482768e5baebe800ebcf62e5972a92 (diff) | |
download | horizon-7f51d554019e02269ebda98f1d097e89862c8da0.tar.gz |
Display the container and object metadata
Display some of the useful metadata information from swift:
Container Details - Container Name, Object Count, Size
Object Details - Name, Hash, Content Type, Last Modified, Size
Change-Id: I6611cab08946a81624176c1836ceadaf16a68e45
Implements: blueprint swift-display-metadata
Diffstat (limited to 'openstack_dashboard/dashboards/project/containers')
8 files changed, 189 insertions, 3 deletions
diff --git a/openstack_dashboard/dashboards/project/containers/tables.py b/openstack_dashboard/dashboards/project/containers/tables.py index ccb9d1bfd..9757a7746 100644 --- a/openstack_dashboard/dashboards/project/containers/tables.py +++ b/openstack_dashboard/dashboards/project/containers/tables.py @@ -36,6 +36,13 @@ def wrap_delimiter(name): return name +class ViewContainer(tables.LinkAction): + name = "view" + verbose_name = _("View Details") + url = "horizon:project:containers:container_detail" + classes = ("ajax-modal", "btn-view") + + class DeleteContainer(tables.DeleteAction): data_type_singular = _("Container") data_type_plural = _("Containers") @@ -127,11 +134,23 @@ class ContainersTable(tables.DataTable): name = "containers" verbose_name = _("Containers") table_actions = (CreateContainer,) - row_actions = (DeleteContainer,) + row_actions = (ViewContainer, DeleteContainer,) browser_table = "navigation" footer = False +class ViewObject(tables.LinkAction): + name = "view" + verbose_name = _("View Details") + url = "horizon:project:containers:object_detail" + classes = ("ajax-modal", "btn-view") + + def get_link_url(self, obj): + container_name = self.table.kwargs['container_name'] + return reverse(self.url, args=(http.urlquote(container_name), + http.urlquote(obj.name))) + + class DeleteObject(tables.DeleteAction): name = "delete_object" data_type_singular = _("Object") @@ -235,7 +254,7 @@ class ObjectsTable(tables.DataTable): verbose_name = _("Objects") table_actions = (ObjectFilterAction, UploadObject, DeleteMultipleObjects) - row_actions = (DownloadObject, CopyObject, DeleteObject) + row_actions = (DownloadObject, CopyObject, ViewObject, DeleteObject) data_types = ("subfolders", "objects") browser_table = "content" footer = False diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/_container_detail.html b/openstack_dashboard/dashboards/project/containers/templates/containers/_container_detail.html new file mode 100644 index 000000000..691731df0 --- /dev/null +++ b/openstack_dashboard/dashboards/project/containers/templates/containers/_container_detail.html @@ -0,0 +1,22 @@ +{% extends "horizon/common/_modal.html" %} +{% load i18n %} +{% load url from future %} + +{% block modal-header %}{% trans "Container Details" %}{% endblock %} + +{% block modal-body %} +<div class="info row-fluid detail clearfix"> + <dl> + <dt>{% trans "Container Name" %}</dt> + <dd>{{ container.name }}</dd> + <dt>{% trans "Object Count" %}</dt> + <dd>{{ container.container_object_count }}</dd> + <dt>{% trans "Size" %}</dt> + <dd>{{ container.container_bytes_used|filesizeformat }}</dd> + </dl> +</div> +{% endblock %} + +{% block modal-footer %} + <a href="{% url 'horizon:project:containers:index' %}" class="btn secondary cancel close">{% trans "Close" %}</a> +{% endblock %}
\ No newline at end of file diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/_object_detail.html b/openstack_dashboard/dashboards/project/containers/templates/containers/_object_detail.html new file mode 100644 index 000000000..cd07538cd --- /dev/null +++ b/openstack_dashboard/dashboards/project/containers/templates/containers/_object_detail.html @@ -0,0 +1,26 @@ +{% extends "horizon/common/_modal.html" %} +{% load i18n %} +{% load url from future %} + +{% block modal-header %}{% trans "Object Details" %}{% endblock %} + +{% block modal-body %} +<div class="info row-fluid detail"> + <dl> + <dt>{% trans "Name" %}</dt> + <dd>{{ object.name }}</dd> + <dt>{% trans "Hash" %}</dt> + <dd>{{ object.etag }}</dd> + <dt>{% trans "Content Type" %}</dt> + <dd>{{ object.content_type }}</dd> + <dt>{% trans "Last Modified" %}</dt> + <dd>{{ object.timestamp|parse_isotime }}</dd> + <dt>{% trans "Size" %}</dt> + <dd>{{ object.bytes|filesizeformat }}</dd> + </dl> +</div> +{% endblock %} + +{% block modal-footer %} + <a href="{% url 'horizon:project:containers:index' %}" class="btn secondary cancel close">{% trans "Close" %}</a> +{% endblock %}
\ No newline at end of file diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/container_detail.html b/openstack_dashboard/dashboards/project/containers/templates/containers/container_detail.html new file mode 100644 index 000000000..6fa77c384 --- /dev/null +++ b/openstack_dashboard/dashboards/project/containers/templates/containers/container_detail.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Container Details" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("Container Details") %} +{% endblock page_header %} + +{% block main %} + {% include 'project/containers/_container_detail.html' %} +{% endblock %} + diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/object_detail.html b/openstack_dashboard/dashboards/project/containers/templates/containers/object_detail.html new file mode 100644 index 000000000..7174389c8 --- /dev/null +++ b/openstack_dashboard/dashboards/project/containers/templates/containers/object_detail.html @@ -0,0 +1,12 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Object Details" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("Object Details") %} +{% endblock page_header %} + +{% block main %} + {% include 'project/containers/_object_detail.html' %} +{% endblock %} + diff --git a/openstack_dashboard/dashboards/project/containers/tests.py b/openstack_dashboard/dashboards/project/containers/tests.py index 193bb0e0c..36ea84ad3 100644 --- a/openstack_dashboard/dashboards/project/containers/tests.py +++ b/openstack_dashboard/dashboards/project/containers/tests.py @@ -237,3 +237,39 @@ class SwiftTests(test.TestCase): index_url = reverse('horizon:project:containers:index', args=[wrap_delimiter(container_2.name)]) self.assertRedirectsNoFollow(res, index_url) + + @test.create_stubs({api.swift: ('swift_get_container', )}) + def test_view_container(self): + container = self.containers.first() + + api.swift.swift_get_container(IsA(http.HttpRequest), + container.name) \ + .AndReturn(container) + self.mox.ReplayAll() + + view_url = reverse('horizon:project:containers:container_detail', + args=[container.name]) + res = self.client.get(view_url) + + self.assertTemplateUsed(res, + 'project/containers/container_detail.html') + self.assertContains(res, container.name, 1, 200) + + @test.create_stubs({api.swift: ('swift_get_object', )}) + def test_view_object(self): + container = self.containers.first() + obj = self.objects.first() + + api.swift.swift_get_object(IsA(http.HttpRequest), + container.name, + obj.name) \ + .AndReturn(obj) + self.mox.ReplayAll() + + view_url = reverse('horizon:project:containers:object_detail', + args=[container.name, obj.name]) + res = self.client.get(view_url) + + self.assertTemplateUsed(res, + 'project/containers/object_detail.html') + self.assertContains(res, obj.name, 1, 200) diff --git a/openstack_dashboard/dashboards/project/containers/urls.py b/openstack_dashboard/dashboards/project/containers/urls.py index 46c71cc73..dc93a212d 100644 --- a/openstack_dashboard/dashboards/project/containers/urls.py +++ b/openstack_dashboard/dashboards/project/containers/urls.py @@ -22,9 +22,13 @@ from django.conf.urls.defaults import patterns from django.conf.urls.defaults import url from openstack_dashboard.dashboards.project.containers.views import \ + ContainerDetailView +from openstack_dashboard.dashboards.project.containers.views import \ ContainerView from openstack_dashboard.dashboards.project.containers.views import CopyView from openstack_dashboard.dashboards.project.containers.views import CreateView +from openstack_dashboard.dashboards.project.containers.views import \ + ObjectDetailView from openstack_dashboard.dashboards.project.containers.views import UploadView @@ -39,6 +43,15 @@ urlpatterns = patterns(VIEW_MOD, CreateView.as_view(), name='create'), + url(r'^(?P<container_name>.+?)/(?P<subfolder_path>(.+/)+)' + '?container_detail$', + ContainerDetailView.as_view(), + name='container_detail'), + + url(r'^(?P<container_name>[^/]+)/(?P<object_path>.+)/object_detail$', + ObjectDetailView.as_view(), + name='object_detail'), + url(r'^(?P<container_name>.+?)/(?P<subfolder_path>(.+/)+)?upload$', UploadView.as_view(), name='object_upload'), @@ -51,5 +64,5 @@ urlpatterns = patterns(VIEW_MOD, url(r'^(?P<container_name>[^/]+)/(?P<object_path>.+)/download$', 'object_download', - name='object_download') + name='object_download'), ) diff --git a/openstack_dashboard/dashboards/project/containers/views.py b/openstack_dashboard/dashboards/project/containers/views.py index 674eaf699..a27e64164 100644 --- a/openstack_dashboard/dashboards/project/containers/views.py +++ b/openstack_dashboard/dashboards/project/containers/views.py @@ -25,6 +25,7 @@ Views for managing Swift containers. from django.core.urlresolvers import reverse from django import http from django.utils.translation import ugettext_lazy as _ +from django.views import generic from horizon import browsers from horizon import exceptions @@ -226,3 +227,48 @@ class CopyView(forms.ModalFormView): context['container_name'] = self.kwargs["container_name"] context['object_name'] = self.kwargs["object_name"] return context + + +class ContainerDetailView(forms.ModalFormMixin, generic.TemplateView): + template_name = 'project/containers/container_detail.html' + + def get_object(self): + if not hasattr(self, "_object"): + try: + self._object = api.swift.swift_get_container( + self.request, + self.kwargs["container_name"]) + except Exception: + redirect = reverse("horizon:project:containers:index") + exceptions.handle(self.request, + _('Unable to retrieve details.'), + redirect=redirect) + return self._object + + def get_context_data(self, **kwargs): + context = super(ContainerDetailView, self).get_context_data(**kwargs) + context['container'] = self.get_object() + return context + + +class ObjectDetailView(forms.ModalFormMixin, generic.TemplateView): + template_name = 'project/containers/object_detail.html' + + def get_object(self): + if not hasattr(self, "_object"): + try: + self._object = api.swift.swift_get_object( + self.request, + self.kwargs["container_name"], + self.kwargs["object_path"]) + except Exception: + redirect = reverse("horizon:project:containers:index") + exceptions.handle(self.request, + _('Unable to retrieve details.'), + redirect=redirect) + return self._object + + def get_context_data(self, **kwargs): + context = super(ObjectDetailView, self).get_context_data(**kwargs) + context['object'] = self.get_object() + return context |