From 104f652f34963375969cd20180e4de1a973ff04f Mon Sep 17 00:00:00 2001 From: nikunj2512 Date: Fri, 14 Nov 2014 14:13:40 +0530 Subject: [PATCH] Create a "Identity Projects details" page This patch add the detail page for the "Projects" (Identity -> Projects) table/resource. So when user clicks on the project name, it will show the drill down details to the end user. Change-Id: I00589f139570758f5645e7862de36487ca844b34 Closes-bug: #1380600 --- .../dashboards/identity/projects/tables.py | 1 + .../templates/projects/_detail_overview.html | 19 ++++++++++++ .../projects/templates/projects/detail.html | 16 ++++++++++ .../dashboards/identity/projects/tests.py | 31 +++++++++++++++++++ .../dashboards/identity/projects/urls.py | 2 ++ .../dashboards/identity/projects/views.py | 26 ++++++++++++++++ 6 files changed, 95 insertions(+) create mode 100644 openstack_dashboard/dashboards/identity/projects/templates/projects/_detail_overview.html create mode 100644 openstack_dashboard/dashboards/identity/projects/templates/projects/detail.html diff --git a/openstack_dashboard/dashboards/identity/projects/tables.py b/openstack_dashboard/dashboards/identity/projects/tables.py index 5a38aa4720..5abcea5a2e 100644 --- a/openstack_dashboard/dashboards/identity/projects/tables.py +++ b/openstack_dashboard/dashboards/identity/projects/tables.py @@ -223,6 +223,7 @@ class UpdateCell(tables.UpdateAction): class TenantsTable(tables.DataTable): name = tables.Column('name', verbose_name=_('Name'), + link=("horizon:identity:projects:detail"), form_field=forms.CharField(max_length=64), update_action=UpdateCell) description = tables.Column(lambda obj: getattr(obj, 'description', None), diff --git a/openstack_dashboard/dashboards/identity/projects/templates/projects/_detail_overview.html b/openstack_dashboard/dashboards/identity/projects/templates/projects/_detail_overview.html new file mode 100644 index 0000000000..a700c3d550 --- /dev/null +++ b/openstack_dashboard/dashboards/identity/projects/templates/projects/_detail_overview.html @@ -0,0 +1,19 @@ +{% load i18n %} + +

{% trans "Project Overview" %}

+ +
+

{% trans "Information" %}

+
+
+
{% trans "Project Name" %}
+
{{ project.name }}
+
{% trans "Project ID" %}
+
{{ project.id }}
+
{% trans "Enabled" %}
+
{{ project.enabled }}
+
{% trans "Description" %}
+
{{ project.description|default:_("None") }}
+
+
+ diff --git a/openstack_dashboard/dashboards/identity/projects/templates/projects/detail.html b/openstack_dashboard/dashboards/identity/projects/templates/projects/detail.html new file mode 100644 index 0000000000..8cb3590d69 --- /dev/null +++ b/openstack_dashboard/dashboards/identity/projects/templates/projects/detail.html @@ -0,0 +1,16 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Project Details" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=page_title %} +{% endblock page_header %} + +{% block main %} +
+
+ {% include "identity/projects/_detail_overview.html" %} +
+
+{% endblock %} + diff --git a/openstack_dashboard/dashboards/identity/projects/tests.py b/openstack_dashboard/dashboards/identity/projects/tests.py index bf8d6ae197..c20222a2c2 100644 --- a/openstack_dashboard/dashboards/identity/projects/tests.py +++ b/openstack_dashboard/dashboards/identity/projects/tests.py @@ -46,6 +46,7 @@ from socket import timeout as socket_timeout # noqa INDEX_URL = reverse('horizon:identity:projects:index') USER_ROLE_PREFIX = workflows.PROJECT_GROUP_MEMBER_SLUG + "_role_" GROUP_ROLE_PREFIX = workflows.PROJECT_USER_MEMBER_SLUG + "_role_" +PROJECT_DETAIL_URL = reverse('horizon:identity:projects:detail', args=[1]) class TenantsViewTests(test.BaseAdminViewTests): @@ -1639,6 +1640,36 @@ class UsageViewTests(test.BaseAdminViewTests): self.assertContains(res, '%s\r\n' % hdr) +class DetailProjectViewTests(test.BaseAdminViewTests): + @test.create_stubs({api.keystone: ('tenant_get',)}) + def test_detail_view(self): + project = self.tenants.first() + + api.keystone.tenant_get(IsA(http.HttpRequest), self.tenant.id) \ + .AndReturn(project) + self.mox.ReplayAll() + + res = self.client.get(PROJECT_DETAIL_URL, args=[project.id]) + + self.assertTemplateUsed(res, 'identity/projects/detail.html') + self.assertEqual(res.context['project'].name, project.name) + self.assertEqual(res.context['project'].id, project.id) + self.assertContains(res, "Project Details: %s" % project.name, + 1, 200) + + @test.create_stubs({api.keystone: ('tenant_get',)}) + def test_detail_view_with_exception(self): + project = self.tenants.first() + + api.keystone.tenant_get(IsA(http.HttpRequest), self.tenant.id) \ + .AndRaise(self.exceptions.keystone) + self.mox.ReplayAll() + + res = self.client.get(PROJECT_DETAIL_URL, args=[project.id]) + + self.assertRedirectsNoFollow(res, INDEX_URL) + + @unittest.skipUnless(os.environ.get('WITH_SELENIUM', False), "The WITH_SELENIUM env variable is not set.") class SeleniumTests(test.SeleniumAdminTestCase): diff --git a/openstack_dashboard/dashboards/identity/projects/urls.py b/openstack_dashboard/dashboards/identity/projects/urls.py index 20937f5fdf..6528a267cb 100644 --- a/openstack_dashboard/dashboards/identity/projects/urls.py +++ b/openstack_dashboard/dashboards/identity/projects/urls.py @@ -30,4 +30,6 @@ urlpatterns = patterns( views.UpdateProjectView.as_view(), name='update'), url(r'^(?P[^/]+)/usage/$', views.ProjectUsageView.as_view(), name='usage'), + url(r'^(?P[^/]+)/detail/$', + views.DetailProjectView.as_view(), name='detail'), ) diff --git a/openstack_dashboard/dashboards/identity/projects/views.py b/openstack_dashboard/dashboards/identity/projects/views.py index 4d8c3e9d06..e122a4c6fa 100644 --- a/openstack_dashboard/dashboards/identity/projects/views.py +++ b/openstack_dashboard/dashboards/identity/projects/views.py @@ -18,6 +18,7 @@ from django.core.urlresolvers import reverse from django.utils.translation import ugettext_lazy as _ +from django.views import generic from horizon import exceptions from horizon import messages @@ -203,3 +204,28 @@ class UpdateProjectView(workflows.WorkflowView): _('Unable to retrieve project details.'), redirect=reverse(INDEX_URL)) return initial + + +class DetailProjectView(generic.TemplateView): + template_name = 'identity/projects/detail.html' + + def get_context_data(self, **kwargs): + context = super(DetailProjectView, self).get_context_data(**kwargs) + project = self.get_data() + table = project_tables.TenantsTable(self.request) + context["project"] = project + context["page_title"] = _("Project Details: %s") % project.name + context["url"] = reverse(INDEX_URL) + context["actions"] = table.render_row_actions(project) + return context + + @memoized.memoized_method + def get_data(self): + try: + project_id = self.kwargs['project_id'] + project = api.keystone.tenant_get(self.request, project_id) + except Exception: + exceptions.handle(self.request, + _('Unable to retrieve project details.'), + redirect=reverse(INDEX_URL)) + return project