Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

260623 pagination #241

Merged
merged 10 commits into from
Jul 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 7 additions & 10 deletions dtool_lookup_gui/models/datasets.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,25 +268,22 @@ def __init__(self, uri=None, dataset_info=None):
raise ValueError('Please provide either `uri` or `dateset_info`.')

@classmethod
async def search(cls, keyword):
async def search(cls, keyword, page_number, page_size, pagination={}):
async with ConfigurationBasedLookupClient() as lookup:
datasets = await lookup.search(keyword)

datasets = await lookup.search(keyword, page_number=page_number, page_size=page_size, pagination=pagination)
return [await cls.from_lookup(lookup_dict) for lookup_dict in datasets]

@classmethod
async def query(cls, query_text):
async def query(cls, query_text, *args, **kwargs):
async with ConfigurationBasedLookupClient() as lookup:
datasets = await lookup.by_query(query_text)

datasets = await lookup.by_query(query_text, *args, **kwargs)
return [await cls.from_lookup(lookup_dict) for lookup_dict in datasets]

@classmethod
async def query_all(cls):
"""Query all datasets from lookup server."""
async def query_all(cls, page_number=1, page_size=8, pagination={}):
"""Query all datasets from the lookup server."""
async with ConfigurationBasedLookupClient() as lookup:
datasets = await lookup.all()

datasets = await lookup.all(page_number=page_number, page_size=page_size, pagination=pagination)
return [await cls.from_lookup(lookup_dict) for lookup_dict in datasets]

def __str__(self):
Expand Down
132 changes: 121 additions & 11 deletions dtool_lookup_gui/views/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

import dtool_lookup_api.core.config
from dtool_lookup_api.core.LookupClient import ConfigurationBasedLookupClient

# As of dtool-lookup-api 0.5.0, the following line still is a necessity to
# disable prompting for credentials on the command line. This behavior
# will change in future versions.
Expand Down Expand Up @@ -101,7 +102,7 @@ class MainWindow(Gtk.ApplicationWindow):

search_entry = Gtk.Template.Child()

#copy_dataset_spinner = Gtk.Template.Child()
# copy_dataset_spinner = Gtk.Template.Child()

base_uri_list_box = Gtk.Template.Child()
dataset_list_box = Gtk.Template.Child()
Expand Down Expand Up @@ -155,6 +156,20 @@ class MainWindow(Gtk.ApplicationWindow):
error_bar = Gtk.Template.Child()
error_label = Gtk.Template.Child()


first_page_button = Gtk.Template.Child()
prev_page_button = Gtk.Template.Child()
curr_page_button = Gtk.Template.Child()
next_page_advancer_button = Gtk.Template.Child()
page_advancer_button = Gtk.Template.Child()
nextoption_page_button = Gtk.Template.Child()
last_page_button = Gtk.Template.Child()

main_statusbar = Gtk.Template.Child()




def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

Expand Down Expand Up @@ -241,6 +256,10 @@ def __init__(self, *args, **kwargs):

_logger.debug(f"Constructed main window for app '{self.application.get_application_id()}'")

self.pagination = {}



# utility methods
def refresh(self):
"""Refresh view."""
Expand Down Expand Up @@ -291,18 +310,29 @@ async def _refresh_base_uri_list_box(self):
def _update_search_summary(self, datasets):
row = self.base_uri_list_box.search_results_row
total_size = sum([0 if dataset.size_int is None else dataset.size_int for dataset in datasets])
row.info_label.set_text(f'{len(datasets)} datasets, {sizeof_fmt(total_size).strip()}')
total_value = self.pagination['total']
row.info_label.set_text(f'{total_value} datasets, {sizeof_fmt(total_size).strip()}')

async def _fetch_search_results(self, keyword, on_show=None):
def _update_main_statusbar(self):
total_number = self.pagination['total']
current_page = self.pagination['page']
self.main_statusbar.push(0, f"Total Number of Dataset: {total_number}, Current page: {current_page}")

async def _fetch_search_results(self, keyword, on_show=None, page_number=1, page_size=8):
row = self.base_uri_list_box.search_results_row
row.start_spinner()
self.pagination = {} # Add pagination dictionary




try:
# datasets = await DatasetModel.search(keyword)
if keyword:
if is_valid_query(keyword):
_logger.debug("Valid query specified.")
datasets = await DatasetModel.query(keyword)
datasets = await DatasetModel.query(keyword, page_number=page_number, page_size=page_size,
pagination=self.pagination) # Pass pagination dictionary and
# page_number, page_size
else:
_logger.debug("Specified search text is not a valid query, just perform free text search.")
# NOTE: server side allows a dict with the key-value pairs
Expand All @@ -312,10 +342,13 @@ async def _fetch_search_results(self, keyword, on_show=None):
# constructs on the server side. With the special treatment
# of the 'uuid' keyword above, should we introduce similar
# options for the other available keywords?
datasets = await DatasetModel.search(keyword)
datasets = await DatasetModel.search(keyword, page_number=page_number, page_size=page_size,
pagination=self.pagination) # Pass pagination dictionary and
# page_number, page_size
else:
_logger.debug("No keyword specified, list all datasets.")
datasets = await DatasetModel.query_all()
datasets = await DatasetModel.query_all(page_number=page_number, page_size=page_size,pagination=self.pagination) # Pass pagination dictionary and


if len(datasets) > self._max_nb_datasets:
_logger.warning(
Expand All @@ -324,6 +357,7 @@ async def _fetch_search_results(self, keyword, on_show=None):
datasets = datasets[:self._max_nb_datasets] # Limit number of datasets that are shown
row.search_results = datasets # Cache datasets
self._update_search_summary(datasets)
self._update_main_statusbar()
if self.base_uri_list_box.get_selected_row() == row:
# Only update if the row is still selected
self.dataset_list_box.fill(datasets, on_show=on_show)
Expand All @@ -335,6 +369,8 @@ async def _fetch_search_results(self, keyword, on_show=None):
self.main_stack.set_visible_child(self.main_paned)
row.stop_spinner()



def _search_by_uuid(self, uuid):
search_text = dump_single_line_query_text({"uuid": uuid})
self._search_by_search_text(search_text)
Expand Down Expand Up @@ -489,7 +525,7 @@ def do_get_item(self, action, value):
dataset = self.dataset_list_box.get_selected_row().dataset

items = self._get_selected_items()
if len(items) !=1:
if len(items) != 1:
raise ValueError("Can only get one item at a time.")
item_name, item_uuid = items[0]

Expand All @@ -504,6 +540,8 @@ async def _get_item(dataset, item_uuid):

asyncio.create_task(_get_item(dataset, item_uuid))



def do_refresh_view(self, action, value):
"""Refresh view by reloading base uri list, """
self.refresh()
Expand All @@ -517,6 +555,7 @@ def on_settings_clicked(self, widget):
def on_logging_clicked(self, widget):
self.log_window.show()


@Gtk.Template.Callback()
def on_about_clicked(self, widget):
self.about_dialog.show()
Expand Down Expand Up @@ -687,6 +726,7 @@ def on_add_items_clicked(self, widget):
pass
dialog.destroy()


@Gtk.Template.Callback()
def on_manifest_row_activated(self, tree_view, path, column):
"""Handler for "row-activated" signal.
Expand All @@ -696,7 +736,7 @@ def on_manifest_row_activated(self, tree_view, path, column):
is pressed. (https://www.gnu.org/software/guile-gnome/docs/gtk/html/GtkTreeView.html)"""

items = self._get_selected_items()
if len(items) !=1:
if len(items) != 1:
raise ValueError("Can only get one item at a time.")
item_name, item_uuid = items[0]
self._show_get_item_dialog(item_name, item_uuid)
Expand Down Expand Up @@ -750,6 +790,77 @@ def on_error_bar_response(self, widget, response_id):
if response_id == Gtk.ResponseType.CLOSE:
self.error_bar.set_revealed(False)

@Gtk.Template.Callback()
def on_first_page_button_clicked(self, widget):
page_number = 1
self.pagination['page'] = page_number
asyncio.create_task(
self._fetch_search_results(keyword=None, on_show=None, page_number=page_number))
self.curr_page_button.set_label(str(page_number))
self.page_advancer_button.set_label(str(page_number - 1))
self.next_page_advancer_button.set_label(str(page_number + 1))


@Gtk.Template.Callback()
def on_nextoption_page_button_clicked(self, widget):
if self.pagination['page'] < self.pagination['last_page']:
page_number = self.pagination['page'] + 1
self.curr_page_button.set_label(str(page_number))
self.page_advancer_button.set_label(str(page_number - 1))
self.next_page_advancer_button.set_label(str(page_number + 1))
asyncio.create_task(
self._fetch_search_results(keyword=None, on_show=None, page_number=page_number))

@Gtk.Template.Callback()
def on_last_page_button_clicked(self, widget):
page_number = self.pagination['last_page']
self.curr_page_button.set_label(str(page_number))
self.page_advancer_button.set_label(str(page_number - 1))
self.next_page_advancer_button.set_label(str(page_number + 1))
asyncio.create_task(
self._fetch_search_results(keyword=None, on_show=None, page_number=page_number))

@Gtk.Template.Callback()
def on_prev_page_button_clicked(self, widget):
if self.pagination['page'] > 1:
self.pagination['page'] -= 1
page_number = self.pagination['page']
self.curr_page_button.set_label(str(page_number)) # Update curr_page_button label
self.page_advancer_button.set_label(str(page_number - 1))
self.next_page_advancer_button.set_label(str(page_number + 1))
asyncio.create_task(
self._fetch_search_results(keyword=None, on_show=None, page_number=page_number))

@Gtk.Template.Callback()
def curr_page_button_clicked(self, widget):
page_number = self.pagination['page']
asyncio.create_task(
self._fetch_search_results(keyword=None, on_show=None, page_number=page_number))
self.curr_page_button.set_label(str(page_number))
self.page_advancer_button.set_label(str(page_number - 1))
self.next_page_advancer_button.set_label(str(page_number + 1))

@Gtk.Template.Callback()
def page_advancer_button_clicked(self, widget):
page_number = self.pagination['page']
if page_number > 1:
page_number -= 1
asyncio.create_task(
self._fetch_search_results(keyword=None, on_show=None, page_number=page_number))
self.curr_page_button.set_label(str(page_number))
self.page_advancer_button.set_label(str(page_number - 1))
self.next_page_advancer_button.set_label(str(page_number + 1))

@Gtk.Template.Callback()
def next_page_advancer_button_clicked(self, widget):
if self.pagination['page'] < self.pagination['last_page']:
page_number = self.pagination['page'] + 1
asyncio.create_task(
self._fetch_search_results(keyword=None, on_show=None, page_number=page_number))
self.curr_page_button.set_label(str(page_number))
self.page_advancer_button.set_label(str(page_number - 1))
self.next_page_advancer_button.set_label(str(page_number + 1))

# @Gtk.Template.Callback(), not in .ui
def on_copy_clicked(self, widget):
async def _copy():
Expand Down Expand Up @@ -802,7 +913,6 @@ def _show_get_item_dialog(self, item_name, item_uuid):
dest_file = os.path.join(default_dir, item_name)
self.activate_action('get-item', GLib.Variant.new_string(dest_file))


# TODO: move to the model
def _add_item(self, fpath):
handle = os.path.basename(fpath)
Expand Down Expand Up @@ -895,4 +1005,4 @@ async def _compute_dependencies(self, dataset):
self.dependency_stack.set_visible_child(self.dependency_view)

def show_error(self, exception):
_logger.error(traceback.format_exc())
_logger.error(traceback.format_exc())
Loading
Loading