add Previous link to Project > Stacks table
Stack list API supports a sort direction and sort key which we can use to paginate back Following same convention as merged patch: https://review.openstack.org/#/c/91111/ Change-Id: I511d7d27a6234e1510c7fa3c7f84c007599f3721 Partially-implements: blueprint pagination-add-prev-link
This commit is contained in:
parent
26f51f864e
commit
1bde43d1c7
@ -52,7 +52,8 @@ def heatclient(request, password=None):
|
||||
return client
|
||||
|
||||
|
||||
def stacks_list(request, marker=None, paginate=False):
|
||||
def stacks_list(request, marker=None, sort_dir='desc', sort_key='created_at',
|
||||
paginate=False):
|
||||
limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
|
||||
page_size = utils.get_page_size(request)
|
||||
|
||||
@ -61,20 +62,28 @@ def stacks_list(request, marker=None, paginate=False):
|
||||
else:
|
||||
request_size = limit
|
||||
|
||||
kwargs = {}
|
||||
kwargs = {'sort_dir': sort_dir, 'sort_key': sort_key}
|
||||
if marker:
|
||||
kwargs['marker'] = marker
|
||||
|
||||
stacks_iter = heatclient(request).stacks.list(limit=request_size,
|
||||
**kwargs)
|
||||
|
||||
has_prev_data = False
|
||||
has_more_data = False
|
||||
stacks = list(stacks_iter)
|
||||
|
||||
if paginate:
|
||||
if len(stacks) > page_size:
|
||||
stacks.pop()
|
||||
has_more_data = True
|
||||
return (stacks, has_more_data)
|
||||
if marker is not None:
|
||||
has_prev_data = True
|
||||
elif sort_dir == 'asc' and marker is not None:
|
||||
has_more_data = True
|
||||
elif marker is not None:
|
||||
has_prev_data = True
|
||||
return (stacks, has_more_data, has_prev_data)
|
||||
|
||||
|
||||
def stack_delete(request, stack_id):
|
||||
|
@ -103,28 +103,31 @@ class StackTests(test.TestCase):
|
||||
@test.create_stubs({api.heat: ('stacks_list',)})
|
||||
def test_index_paginated(self):
|
||||
stacks = self.stacks.list()[:5]
|
||||
# import pdb; pdb.set_trace()
|
||||
|
||||
api.heat.stacks_list(IsA(http.HttpRequest),
|
||||
marker=None,
|
||||
paginate=True) \
|
||||
paginate=True,
|
||||
sort_dir='desc') \
|
||||
.AndReturn([stacks,
|
||||
True])
|
||||
True, True])
|
||||
api.heat.stacks_list(IsA(http.HttpRequest),
|
||||
marker=None,
|
||||
paginate=True) \
|
||||
paginate=True,
|
||||
sort_dir='desc') \
|
||||
.AndReturn([stacks[:2],
|
||||
True])
|
||||
True, True])
|
||||
api.heat.stacks_list(IsA(http.HttpRequest),
|
||||
marker=stacks[2].id,
|
||||
paginate=True) \
|
||||
paginate=True,
|
||||
sort_dir='desc') \
|
||||
.AndReturn([stacks[2:4],
|
||||
True])
|
||||
True, True])
|
||||
api.heat.stacks_list(IsA(http.HttpRequest),
|
||||
marker=stacks[4].id,
|
||||
paginate=True) \
|
||||
paginate=True,
|
||||
sort_dir='desc') \
|
||||
.AndReturn([stacks[4:],
|
||||
True])
|
||||
True, True])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:project:stacks:index')
|
||||
@ -153,6 +156,62 @@ class StackTests(test.TestCase):
|
||||
self.assertEqual(len(res.context['stacks_table'].data),
|
||||
1)
|
||||
|
||||
@override_settings(API_RESULT_PAGE_SIZE=2)
|
||||
@test.create_stubs({api.heat: ('stacks_list',)})
|
||||
def test_index_prev_paginated(self):
|
||||
stacks = self.stacks.list()[:3]
|
||||
|
||||
api.heat.stacks_list(IsA(http.HttpRequest),
|
||||
marker=None,
|
||||
paginate=True,
|
||||
sort_dir='desc') \
|
||||
.AndReturn([stacks,
|
||||
True, False])
|
||||
api.heat.stacks_list(IsA(http.HttpRequest),
|
||||
marker=None,
|
||||
paginate=True,
|
||||
sort_dir='desc') \
|
||||
.AndReturn([stacks[:2],
|
||||
True, True])
|
||||
api.heat.stacks_list(IsA(http.HttpRequest),
|
||||
marker=stacks[2].id,
|
||||
paginate=True,
|
||||
sort_dir='desc') \
|
||||
.AndReturn([stacks[2:],
|
||||
True, True])
|
||||
api.heat.stacks_list(IsA(http.HttpRequest),
|
||||
marker=stacks[2].id,
|
||||
paginate=True,
|
||||
sort_dir='asc') \
|
||||
.AndReturn([stacks[:2],
|
||||
True, True])
|
||||
self.mox.ReplayAll()
|
||||
|
||||
url = reverse('horizon:project:stacks:index')
|
||||
res = self.client.get(url)
|
||||
# get all
|
||||
self.assertEqual(len(res.context['stacks_table'].data),
|
||||
len(stacks))
|
||||
self.assertTemplateUsed(res, 'project/stacks/index.html')
|
||||
|
||||
res = self.client.get(url)
|
||||
# get first page with 2 items
|
||||
self.assertEqual(len(res.context['stacks_table'].data),
|
||||
settings.API_RESULT_PAGE_SIZE)
|
||||
|
||||
url = "%s?%s=%s" % (reverse('horizon:project:stacks:index'),
|
||||
tables.StacksTable._meta.pagination_param, stacks[2].id)
|
||||
res = self.client.get(url)
|
||||
# get second page (item 3)
|
||||
self.assertEqual(len(res.context['stacks_table'].data), 1)
|
||||
|
||||
url = "%s?%s=%s" % (reverse('horizon:project:stacks:index'),
|
||||
tables.StacksTable._meta.prev_pagination_param, stacks[2].id)
|
||||
res = self.client.get(url)
|
||||
# prev back to get first page with 2 pages
|
||||
self.assertEqual(len(res.context['stacks_table'].data),
|
||||
settings.API_RESULT_PAGE_SIZE)
|
||||
|
||||
@test.create_stubs({api.heat: ('stack_create', 'template_validate')})
|
||||
def test_launch_stack(self):
|
||||
template = self.stack_templates.first()
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
import json
|
||||
import logging
|
||||
from operator import attrgetter
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
@ -46,18 +47,34 @@ class IndexView(tables.DataTableView):
|
||||
super(IndexView, self).__init__(*args, **kwargs)
|
||||
self._more = None
|
||||
|
||||
def has_prev_data(self, table):
|
||||
return self._prev
|
||||
|
||||
def has_more_data(self, table):
|
||||
return self._more
|
||||
|
||||
def get_data(self):
|
||||
stacks = []
|
||||
marker = self.request.GET.get(
|
||||
project_tables.StacksTable._meta.pagination_param)
|
||||
prev_marker = self.request.GET.get(
|
||||
project_tables.StacksTable._meta.prev_pagination_param)
|
||||
if prev_marker is not None:
|
||||
sort_dir = 'asc'
|
||||
marker = prev_marker
|
||||
else:
|
||||
sort_dir = 'desc'
|
||||
marker = self.request.GET.get(
|
||||
project_tables.StacksTable._meta.pagination_param)
|
||||
try:
|
||||
stacks, self._more = api.heat.stacks_list(self.request,
|
||||
marker=marker,
|
||||
paginate=True)
|
||||
stacks, self._more, self._prev = api.heat.stacks_list(
|
||||
self.request,
|
||||
marker=marker,
|
||||
paginate=True,
|
||||
sort_dir=sort_dir)
|
||||
if prev_marker is not None:
|
||||
stacks = sorted(stacks, key=attrgetter('creation_time'),
|
||||
reverse=True)
|
||||
except Exception:
|
||||
self._prev = False
|
||||
self._more = False
|
||||
msg = _('Unable to retrieve stack list.')
|
||||
exceptions.handle(self.request, msg)
|
||||
|
@ -24,11 +24,144 @@ class HeatApiTests(test.APITestCase):
|
||||
|
||||
heatclient = self.stub_heatclient()
|
||||
heatclient.stacks = self.mox.CreateMockAnything()
|
||||
heatclient.stacks.list(limit=limit).AndReturn(iter(api_stacks))
|
||||
heatclient.stacks.list(limit=limit,
|
||||
sort_dir='desc',
|
||||
sort_key='created_at',) \
|
||||
.AndReturn(iter(api_stacks))
|
||||
self.mox.ReplayAll()
|
||||
stacks, has_more = api.heat.stacks_list(self.request)
|
||||
stacks, has_more, has_prev = api.heat.stacks_list(self.request)
|
||||
self.assertItemsEqual(stacks, api_stacks)
|
||||
self.assertFalse(has_more)
|
||||
self.assertFalse(has_prev)
|
||||
|
||||
@override_settings(API_RESULT_PAGE_SIZE=2)
|
||||
def test_stack_list_sort_options(self):
|
||||
# Verify that sort_dir and sort_key work
|
||||
api_stacks = self.stacks.list()
|
||||
limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
|
||||
sort_dir = 'asc'
|
||||
sort_key = 'size'
|
||||
|
||||
heatclient = self.stub_heatclient()
|
||||
heatclient.stacks = self.mox.CreateMockAnything()
|
||||
heatclient.stacks.list(limit=limit,
|
||||
sort_dir=sort_dir,
|
||||
sort_key=sort_key,) \
|
||||
.AndReturn(iter(api_stacks))
|
||||
self.mox.ReplayAll()
|
||||
|
||||
stacks, has_more, has_prev = api.heat.stacks_list(self.request,
|
||||
sort_dir=sort_dir,
|
||||
sort_key=sort_key)
|
||||
self.assertItemsEqual(stacks, api_stacks)
|
||||
self.assertFalse(has_more)
|
||||
self.assertFalse(has_prev)
|
||||
|
||||
@override_settings(API_RESULT_PAGE_SIZE=20)
|
||||
def test_stack_list_pagination_less_page_size(self):
|
||||
api_stacks = self.stacks.list()
|
||||
page_size = settings.API_RESULT_PAGE_SIZE
|
||||
sort_dir = 'desc'
|
||||
sort_key = 'created_at'
|
||||
|
||||
heatclient = self.stub_heatclient()
|
||||
heatclient.stacks = self.mox.CreateMockAnything()
|
||||
heatclient.stacks.list(limit=page_size + 1,
|
||||
sort_dir=sort_dir,
|
||||
sort_key=sort_key,) \
|
||||
.AndReturn(iter(api_stacks))
|
||||
self.mox.ReplayAll()
|
||||
|
||||
stacks, has_more, has_prev = api.heat.stacks_list(self.request,
|
||||
sort_dir=sort_dir,
|
||||
sort_key=sort_key,
|
||||
paginate=True)
|
||||
expected_stacks = api_stacks[:page_size]
|
||||
self.assertItemsEqual(stacks, expected_stacks)
|
||||
self.assertFalse(has_more)
|
||||
self.assertFalse(has_prev)
|
||||
|
||||
@override_settings(API_RESULT_PAGE_SIZE=10)
|
||||
def test_stack_list_pagination_equal_page_size(self):
|
||||
api_stacks = self.stacks.list()
|
||||
page_size = settings.API_RESULT_PAGE_SIZE
|
||||
sort_dir = 'desc'
|
||||
sort_key = 'created_at'
|
||||
|
||||
heatclient = self.stub_heatclient()
|
||||
heatclient.stacks = self.mox.CreateMockAnything()
|
||||
heatclient.stacks.list(limit=page_size + 1,
|
||||
sort_dir=sort_dir,
|
||||
sort_key=sort_key,) \
|
||||
.AndReturn(iter(api_stacks))
|
||||
self.mox.ReplayAll()
|
||||
|
||||
stacks, has_more, has_prev = api.heat.stacks_list(self.request,
|
||||
sort_dir=sort_dir,
|
||||
sort_key=sort_key,
|
||||
paginate=True)
|
||||
expected_stacks = api_stacks[:page_size]
|
||||
self.assertItemsEqual(stacks, expected_stacks)
|
||||
self.assertFalse(has_more)
|
||||
self.assertFalse(has_prev)
|
||||
|
||||
@override_settings(API_RESULT_PAGE_SIZE=2)
|
||||
def test_stack_list_pagination_marker(self):
|
||||
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 20)
|
||||
sort_dir = 'desc'
|
||||
sort_key = 'created_at'
|
||||
marker = 'nonsense'
|
||||
|
||||
api_stacks = self.stacks.list()
|
||||
|
||||
heatclient = self.stub_heatclient()
|
||||
heatclient.stacks = self.mox.CreateMockAnything()
|
||||
heatclient.stacks.list(limit=page_size + 1,
|
||||
marker=marker,
|
||||
sort_dir=sort_dir,
|
||||
sort_key=sort_key,) \
|
||||
.AndReturn(iter(api_stacks[:page_size + 1]))
|
||||
self.mox.ReplayAll()
|
||||
|
||||
stacks, has_more, has_prev = api.heat.stacks_list(self.request,
|
||||
marker=marker,
|
||||
paginate=True,
|
||||
sort_dir=sort_dir,
|
||||
sort_key=sort_key,)
|
||||
|
||||
self.assertEqual(len(stacks), page_size)
|
||||
self.assertItemsEqual(stacks, api_stacks[:page_size])
|
||||
self.assertTrue(has_more)
|
||||
self.assertTrue(has_prev)
|
||||
|
||||
@override_settings(API_RESULT_PAGE_SIZE=2)
|
||||
def test_stack_list_pagination_marker_prev(self):
|
||||
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 20)
|
||||
sort_dir = 'asc'
|
||||
sort_key = 'created_at'
|
||||
marker = 'nonsense'
|
||||
|
||||
api_stacks = self.stacks.list()
|
||||
|
||||
heatclient = self.stub_heatclient()
|
||||
heatclient.stacks = self.mox.CreateMockAnything()
|
||||
heatclient.stacks.list(limit=page_size + 1,
|
||||
marker=marker,
|
||||
sort_dir=sort_dir,
|
||||
sort_key=sort_key,) \
|
||||
.AndReturn(iter(api_stacks[:page_size + 1]))
|
||||
self.mox.ReplayAll()
|
||||
|
||||
stacks, has_more, has_prev = api.heat.stacks_list(self.request,
|
||||
marker=marker,
|
||||
paginate=True,
|
||||
sort_dir=sort_dir,
|
||||
sort_key=sort_key,)
|
||||
|
||||
self.assertEqual(len(stacks), page_size)
|
||||
self.assertItemsEqual(stacks, api_stacks[:page_size])
|
||||
self.assertTrue(has_more)
|
||||
self.assertTrue(has_prev)
|
||||
|
||||
def test_template_get(self):
|
||||
api_stacks = self.stacks.list()
|
||||
|
Loading…
Reference in New Issue
Block a user