Skip to content

Commit 4b799cc

Browse files
authored
Added Pagination support to Bots Page (google#1982)
1. Add pagination support to bots page. 1. Requests for search and page change will be using AJAX. Added a JsonHandler in page handler. 2. Search shifted from on-browser to server side using keywords present in name. (Due to this, the existing builds' heartbeats data should be modified as a new attribute is added to Heartbeat model, provided a script for this in the migrations) 3. Added new test for changed APIs. Screenshot: ![bots to send](https://user-images.githubusercontent.com/30122295/90531746-13187200-e194-11ea-9cab-80abb90038a9.png)
1 parent 8f1da98 commit 4b799cc

File tree

8 files changed

+371
-97
lines changed

8 files changed

+371
-97
lines changed

src/appengine/handlers/bots.py

Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,24 @@
1515

1616
import datetime
1717

18+
from flask import request
19+
1820
from base import tasks
1921
from base import utils
2022
from datastore import data_types
2123
from datastore import ndb_utils
2224
from handlers import base_handler_flask
25+
from libs import filters
2326
from libs import handler_flask
2427
from libs import helpers
28+
from libs.query import datastore_query
29+
30+
PAGE_SIZE = 10
31+
MORE_LIMIT = 50 - PAGE_SIZE # exactly 5 pages
32+
33+
FILTERS = [
34+
filters.Keyword([], 'keywords', 'q'),
35+
]
2536

2637

2738
def _get_alive_cutoff():
@@ -61,31 +72,29 @@ def _convert_heartbeats_to_dicts(heartbeats):
6172
return result
6273

6374

64-
def _get_host_workers_heartbeats():
65-
"""Return host worker heartbeats."""
66-
page_size = 30
67-
68-
query = data_types.HostWorkerAssignment.query()
69-
cursor = None
75+
def get_results():
76+
"""Get results for the bots page."""
77+
# Return bots sorted alphabetically by bot_name
78+
query = datastore_query.Query(data_types.Heartbeat)
79+
query.order('bot_name', is_desc=False)
80+
params = dict(request.iterparams())
81+
filters.add(query, params, FILTERS)
7082

71-
while True:
72-
results, cursor, more = query.fetch_page(page_size, start_cursor=cursor)
73-
key_ids = [assignment.key.id() for assignment in results]
74-
if not key_ids:
75-
break
83+
page = helpers.cast(request.get('page', 1), int, "'page' is not an int.")
84+
items, total_pages, total_items, has_more = query.fetch_page(
85+
page=page, page_size=PAGE_SIZE, projection=None, more_limit=MORE_LIMIT)
86+
items = _convert_heartbeats_to_dicts(items)
87+
helpers.log('Bots', helpers.VIEW_OPERATION)
7688

77-
worker_mapping = dict(
78-
(assignment.key.id(), assignment.worker_name) for assignment in results)
79-
80-
for heartbeat in data_types.Heartbeat.query(
81-
data_types.Heartbeat.bot_name.IN(key_ids)):
82-
heartbeat.bot_name = '{host_name} ({worker_name})'.format(
83-
host_name=heartbeat.bot_name,
84-
worker_name=worker_mapping[heartbeat.bot_name])
85-
yield heartbeat
86-
87-
if not more:
88-
break
89+
result = {
90+
'hasMore': has_more,
91+
'items': items,
92+
'page': page,
93+
'pageSize': PAGE_SIZE,
94+
'totalItems': total_items,
95+
'totalPages': total_pages,
96+
}
97+
return result, params
8998

9099

91100
class Handler(base_handler_flask.Handler):
@@ -96,17 +105,25 @@ class Handler(base_handler_flask.Handler):
96105
@handler_flask.check_user_access(need_privileged_access=False)
97106
def get(self):
98107
"""Render the bot list HTML."""
99-
if utils.is_oss_fuzz():
100-
heartbeats = _get_host_workers_heartbeats()
101-
else:
102-
heartbeats = ndb_utils.get_all_from_model(data_types.Heartbeat)
103-
104-
bots = _convert_heartbeats_to_dicts(heartbeats)
108+
result, params = get_results()
105109
return self.render('bots.html', {
106-
'bots': bots,
110+
'result': result,
111+
'params': params,
107112
})
108113

109114

115+
class JsonHandler(base_handler_flask.Handler):
116+
"""Handler that gets the bots when user clicks on next page."""
117+
118+
@handler_flask.post(handler_flask.JSON, handler_flask.JSON)
119+
@handler_flask.check_admin_access_if_oss_fuzz
120+
@handler_flask.check_user_access(need_privileged_access=False)
121+
def post(self):
122+
"""Get and render the bots in JSON."""
123+
result, _ = get_results()
124+
return self.render_json(result)
125+
126+
110127
class DeadBotsHandler(base_handler_flask.Handler):
111128
"""Output dead bots as json."""
112129

src/appengine/index.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,3 +555,8 @@ indexes:
555555
properties:
556556
- name: keywords
557557
- name: name
558+
559+
- kind: Heartbeat
560+
properties:
561+
- name: keywords
562+
- name: bot_name

0 commit comments

Comments
 (0)