Implement "filter first" for identity panels
Implemented the "filter first" for the following identity panels: - Users - Groups - Roles - Projects The functionality helps horizon not to hang and timeout when there is a large set of identity resources to display. It can be turned on and off easily. In a subsequent patch set the same functionality will be added to other identity views such as Project > Manage Members Change-Id: I6e569712fb5159552a27271837cf2629059f5894
This commit is contained in:
parent
590c3f0038
commit
33fcd95caf
@ -308,3 +308,10 @@ class GroupsViewTests(test.BaseAdminViewTests):
|
|||||||
|
|
||||||
self.assertRedirectsNoFollow(res, GROUP_MANAGE_URL)
|
self.assertRedirectsNoFollow(res, GROUP_MANAGE_URL)
|
||||||
self.assertMessageCount(success=1)
|
self.assertMessageCount(success=1)
|
||||||
|
|
||||||
|
@test.update_settings(FILTER_DATA_FIRST={'identity.groups': True})
|
||||||
|
def test_index_with_filter_first(self):
|
||||||
|
res = self.client.get(GROUPS_INDEX_URL)
|
||||||
|
self.assertTemplateUsed(res, constants.GROUPS_INDEX_VIEW_TEMPLATE)
|
||||||
|
groups = res.context['table'].data
|
||||||
|
self.assertItemsEqual(groups, [])
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.core.urlresolvers import reverse_lazy
|
from django.core.urlresolvers import reverse_lazy
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
@ -37,12 +38,28 @@ class IndexView(tables.DataTableView):
|
|||||||
template_name = constants.GROUPS_INDEX_VIEW_TEMPLATE
|
template_name = constants.GROUPS_INDEX_VIEW_TEMPLATE
|
||||||
page_title = _("Groups")
|
page_title = _("Groups")
|
||||||
|
|
||||||
|
def needs_filter_first(self, table):
|
||||||
|
return self._needs_filter_first
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
groups = []
|
groups = []
|
||||||
domain_id = api.keystone.get_effective_domain_id(self.request)
|
|
||||||
filters = self.get_filters()
|
filters = self.get_filters()
|
||||||
|
self._needs_filter_first = False
|
||||||
|
|
||||||
if policy.check((("identity", "identity:list_groups"),),
|
if policy.check((("identity", "identity:list_groups"),),
|
||||||
self.request):
|
self.request):
|
||||||
|
|
||||||
|
# If filter_first is set and if there are not other filters
|
||||||
|
# selected, then search criteria must be provided and
|
||||||
|
# return an empty list
|
||||||
|
filter_first = getattr(settings, 'FILTER_DATA_FIRST', {})
|
||||||
|
if filter_first.get('identity.groups', False) \
|
||||||
|
and len(filters) == 0:
|
||||||
|
self._needs_filter_first = True
|
||||||
|
return groups
|
||||||
|
|
||||||
|
domain_id = api.keystone.get_effective_domain_id(self.request)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
groups = api.keystone.group_list(self.request,
|
groups = api.keystone.group_list(self.request,
|
||||||
domain=domain_id,
|
domain=domain_id,
|
||||||
|
@ -97,6 +97,13 @@ class TenantsViewTests(test.BaseAdminViewTests):
|
|||||||
self.assertItemsEqual(res.context['table'].data, domain_tenants)
|
self.assertItemsEqual(res.context['table'].data, domain_tenants)
|
||||||
self.assertContains(res, "<em>test_domain:</em>")
|
self.assertContains(res, "<em>test_domain:</em>")
|
||||||
|
|
||||||
|
@test.update_settings(FILTER_DATA_FIRST={'identity.projects': True})
|
||||||
|
def test_index_with_filter_first(self):
|
||||||
|
res = self.client.get(INDEX_URL)
|
||||||
|
self.assertTemplateUsed(res, 'identity/projects/index.html')
|
||||||
|
projects = res.context['table'].data
|
||||||
|
self.assertItemsEqual(projects, [])
|
||||||
|
|
||||||
|
|
||||||
class ProjectsViewNonAdminTests(test.TestCase):
|
class ProjectsViewNonAdminTests(test.TestCase):
|
||||||
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
|
@override_settings(POLICY_CHECK_FUNCTION='openstack_auth.policy.check')
|
||||||
|
@ -71,6 +71,9 @@ class IndexView(tables.DataTableView):
|
|||||||
template_name = 'identity/projects/index.html'
|
template_name = 'identity/projects/index.html'
|
||||||
page_title = _("Projects")
|
page_title = _("Projects")
|
||||||
|
|
||||||
|
def needs_filter_first(self, table):
|
||||||
|
return self._needs_filter_first
|
||||||
|
|
||||||
def has_more_data(self, table):
|
def has_more_data(self, table):
|
||||||
return self._more
|
return self._more
|
||||||
|
|
||||||
@ -80,8 +83,22 @@ class IndexView(tables.DataTableView):
|
|||||||
project_tables.TenantsTable._meta.pagination_param, None)
|
project_tables.TenantsTable._meta.pagination_param, None)
|
||||||
self._more = False
|
self._more = False
|
||||||
filters = self.get_filters()
|
filters = self.get_filters()
|
||||||
|
|
||||||
|
self._needs_filter_first = False
|
||||||
|
|
||||||
if policy.check((("identity", "identity:list_projects"),),
|
if policy.check((("identity", "identity:list_projects"),),
|
||||||
self.request):
|
self.request):
|
||||||
|
|
||||||
|
# If filter_first is set and if there are not other filters
|
||||||
|
# selected, then search criteria must be provided and
|
||||||
|
# return an empty list
|
||||||
|
filter_first = getattr(settings, 'FILTER_DATA_FIRST', {})
|
||||||
|
if filter_first.get('identity.projects', False) and len(
|
||||||
|
filters) == 0:
|
||||||
|
self._needs_filter_first = True
|
||||||
|
self._more = False
|
||||||
|
return tenants
|
||||||
|
|
||||||
domain_context = api.keystone.get_effective_domain_id(self.request)
|
domain_context = api.keystone.get_effective_domain_id(self.request)
|
||||||
try:
|
try:
|
||||||
tenants, self._more = api.keystone.tenant_list(
|
tenants, self._more = api.keystone.tenant_list(
|
||||||
|
@ -120,3 +120,10 @@ class RolesViewTests(test.BaseAdminViewTests):
|
|||||||
res = self.client.post(ROLES_INDEX_URL, formData)
|
res = self.client.post(ROLES_INDEX_URL, formData)
|
||||||
|
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
|
|
||||||
|
@test.update_settings(FILTER_DATA_FIRST={'identity.roles': True})
|
||||||
|
def test_index_with_filter_first(self):
|
||||||
|
res = self.client.get(ROLES_INDEX_URL)
|
||||||
|
self.assertTemplateUsed(res, INDEX_TEMPLATE)
|
||||||
|
roles = res.context['table'].data
|
||||||
|
self.assertItemsEqual(roles, [])
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.core.urlresolvers import reverse_lazy
|
from django.core.urlresolvers import reverse_lazy
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
@ -35,11 +36,26 @@ class IndexView(tables.DataTableView):
|
|||||||
table_class = project_tables.RolesTable
|
table_class = project_tables.RolesTable
|
||||||
page_title = _("Roles")
|
page_title = _("Roles")
|
||||||
|
|
||||||
|
def needs_filter_first(self, table):
|
||||||
|
return self._needs_filter_first
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
roles = []
|
roles = []
|
||||||
filters = self.get_filters()
|
filters = self.get_filters()
|
||||||
|
|
||||||
|
self._needs_filter_first = False
|
||||||
|
|
||||||
if policy.check((("identity", "identity:list_roles"),),
|
if policy.check((("identity", "identity:list_roles"),),
|
||||||
self.request):
|
self.request):
|
||||||
|
|
||||||
|
# If filter_first is set and if there are not other filters
|
||||||
|
# selected, then search criteria must be provided
|
||||||
|
# and return an empty list
|
||||||
|
filter_first = getattr(settings, 'FILTER_DATA_FIRST', {})
|
||||||
|
if filter_first.get('identity.roles', False) and len(filters) == 0:
|
||||||
|
self._needs_filter_first = True
|
||||||
|
return roles
|
||||||
|
|
||||||
try:
|
try:
|
||||||
roles = api.keystone.role_list(self.request,
|
roles = api.keystone.role_list(self.request,
|
||||||
filters=filters)
|
filters=filters)
|
||||||
|
@ -963,6 +963,13 @@ class UsersViewTests(test.BaseAdminViewTests):
|
|||||||
|
|
||||||
self.assertNoFormErrors(res)
|
self.assertNoFormErrors(res)
|
||||||
|
|
||||||
|
@test.update_settings(FILTER_DATA_FIRST={'identity.users': True})
|
||||||
|
def test_index_with_filter_first(self):
|
||||||
|
res = self.client.get(USERS_INDEX_URL)
|
||||||
|
self.assertTemplateUsed(res, 'identity/users/index.html')
|
||||||
|
users = res.context['table'].data
|
||||||
|
self.assertItemsEqual(users, [])
|
||||||
|
|
||||||
|
|
||||||
class SeleniumTests(test.SeleniumAdminTestCase):
|
class SeleniumTests(test.SeleniumAdminTestCase):
|
||||||
def _get_default_domain(self):
|
def _get_default_domain(self):
|
||||||
|
@ -49,11 +49,26 @@ class IndexView(tables.DataTableView):
|
|||||||
template_name = 'identity/users/index.html'
|
template_name = 'identity/users/index.html'
|
||||||
page_title = _("Users")
|
page_title = _("Users")
|
||||||
|
|
||||||
|
def needs_filter_first(self, table):
|
||||||
|
return self._needs_filter_first
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
users = []
|
users = []
|
||||||
filters = self.get_filters()
|
filters = self.get_filters()
|
||||||
|
|
||||||
|
self._needs_filter_first = False
|
||||||
|
|
||||||
if policy.check((("identity", "identity:list_users"),),
|
if policy.check((("identity", "identity:list_users"),),
|
||||||
self.request):
|
self.request):
|
||||||
|
|
||||||
|
# If filter_first is set and if there are not other filters
|
||||||
|
# selected, then search criteria must be provided
|
||||||
|
# and return an empty list
|
||||||
|
filter_first = getattr(settings, 'FILTER_DATA_FIRST', {})
|
||||||
|
if filter_first.get('identity.users', False) and len(filters) == 0:
|
||||||
|
self._needs_filter_first = True
|
||||||
|
return users
|
||||||
|
|
||||||
domain_context = api.keystone.get_effective_domain_id(self.request)
|
domain_context = api.keystone.get_effective_domain_id(self.request)
|
||||||
try:
|
try:
|
||||||
users = api.keystone.user_list(self.request,
|
users = api.keystone.user_list(self.request,
|
||||||
|
@ -800,7 +800,11 @@ REST_API_REQUIRED_SETTINGS = ['OPENSTACK_HYPERVISOR_FEATURES',
|
|||||||
# 'admin.images': False,
|
# 'admin.images': False,
|
||||||
# 'admin.networks': False,
|
# 'admin.networks': False,
|
||||||
# 'admin.routers': False,
|
# 'admin.routers': False,
|
||||||
# 'admin.volumes': False
|
# 'admin.volumes': False,
|
||||||
|
# 'identity.users': False,
|
||||||
|
# 'identity.projects': False,
|
||||||
|
# 'identity.groups': False,
|
||||||
|
# 'identity.roles': False
|
||||||
#}
|
#}
|
||||||
|
|
||||||
# Dict used to restrict user private subnet cidr range.
|
# Dict used to restrict user private subnet cidr range.
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Implements the "filter first" functionality for identity panels
|
||||||
|
such as projects, users, groups and roles. The filter first
|
||||||
|
functionality is described in <https://blueprints.launchpad.net/horizon/+spec/admin-views-filter-first>`
|
Loading…
x
Reference in New Issue
Block a user