diff --git a/ceo/tui/CeoFrame.py b/ceo/tui/CeoFrame.py index 96778fd..39f357d 100644 --- a/ceo/tui/CeoFrame.py +++ b/ceo/tui/CeoFrame.py @@ -1,5 +1,5 @@ from asciimatics.exceptions import NextScene -from asciimatics.widgets import Frame, Layout, Divider, Button +from asciimatics.widgets import Frame, Layout, Divider, Button, Label class CeoFrame(Frame): @@ -54,7 +54,7 @@ class CeoFrame(Frame): def add_buttons( self, back_btn=False, back_btn_text='Back', - next_scene=None, next_scene_text='Next', on_next=None, + next_scene=None, next_btn_text='Next', on_next=None, on_next_excl=None, ): """ @@ -81,12 +81,30 @@ class CeoFrame(Frame): return if on_next is not None: on_next() - self._model.scene_stack.append(self._name) - raise NextScene(next_scene) + self.go_to_next_scene(next_scene) layout = Layout([1, 1]) self.add_layout(layout) if back_btn: layout.add_widget(Button(back_btn_text, _back), 0) if next_scene is not None or on_next_excl is not None: - layout.add_widget(Button(next_scene_text, _next), 1) + layout.add_widget(Button(next_btn_text, _next), 1) + + def go_to_next_scene(self, next_scene: str): + self._model.scene_stack.append(self._name) + raise NextScene(next_scene) + + def add_flash_message_layout(self): + layout = Layout([100]) + self.add_layout(layout) + self._status_label = Label('') + layout.add_widget(self._status_label) + + def flash_message(self, msg: str, force_update: bool = False): + self._status_label.text = msg + if force_update: + self._model.screen.force_update() + self._model.screen.draw_next_frame() + + def clear_flash_message(self): + self.flash_message('') diff --git a/ceo/tui/ConfirmView.py b/ceo/tui/ConfirmView.py index 8574643..34646cd 100644 --- a/ceo/tui/ConfirmView.py +++ b/ceo/tui/ConfirmView.py @@ -34,11 +34,21 @@ class ConfirmView(CeoFrame): # fill the rest of the space self.add_layout(Layout([100], fill_frame=True)) + kwargs = { + 'back_btn': True, 'back_btn_text': 'No', 'next_btn_text': 'Yes', + } if self._model.operations is not None: - next_scene = 'Transaction' + kwargs['next_scene'] = 'Transaction' else: - next_scene = 'Result' - self.add_buttons( - back_btn=True, back_btn_text='No', - next_scene=next_scene, next_scene_text='Yes') + self.add_flash_message_layout() + kwargs['on_next_excl'] = self._next + self.add_buttons(**kwargs) self.fix() + + def _next(self): + self.flash_message('Sending request...', force_update=True) + try: + self._model.deferred_req_resp = self._model.deferred_req() + finally: + self.clear_flash_message() + self.go_to_next_scene('Result') diff --git a/ceo/tui/Model.py b/ceo/tui/Model.py index 793ce32..aaf0bd3 100644 --- a/ceo/tui/Model.py +++ b/ceo/tui/Model.py @@ -36,6 +36,7 @@ class Model: self.confirm_lines = None self.operations = None self.deferred_req = None + self.deferred_req_resp = None def reset(self): self.viewdata = deepcopy(self._initial_viewdata) @@ -43,6 +44,7 @@ class Model: self.confirm_lines = None self.operations = None self.deferred_req = None + self.deferred_req_resp = None self.title = None self.error_message = None self.scene_stack.clear() diff --git a/ceo/tui/ResultView.py b/ceo/tui/ResultView.py index a22a1df..24bbaeb 100644 --- a/ceo/tui/ResultView.py +++ b/ceo/tui/ResultView.py @@ -1,7 +1,5 @@ -from threading import Thread - from asciimatics.exceptions import NextScene -from asciimatics.widgets import Layout, Label, Button, Divider +from asciimatics.widgets import Layout, Label import requests from .CeoFrame import CeoFrame @@ -13,54 +11,32 @@ class ResultView(CeoFrame): screen, height, width, model, 'Result', on_load=self._resultview_on_load, title='Result', ) - layout = Layout([1, 10]) - self.add_layout(layout) - layout.add_widget(Label(''), 1) - self._status_label = Label('Sending request... ') - layout.add_widget(self._status_label, 1) - layout.add_widget(Label(''), 1) self._summary_layout = Layout([1, 10], fill_frame=True) self.add_layout(self._summary_layout) + self._show_msg() - self._add_buttons() - self.fix() - - def _add_buttons(self): - layout = Layout([100]) - self.add_layout(layout) - layout.add_widget(Divider()) - - layout = Layout([1, 1]) - self.add_layout(layout) - self._next_btn = Button('Next', self._next) - self._next_btn.disabled = True - layout.add_widget(self._next_btn, 1) - - def _show_msg(self, text: str = ''): - for line in text.splitlines(): - self._summary_layout.add_widget(Label(line), 1) - - # override this method in child classes if desired - def show_result(self, resp: requests.Response): - self._show_msg('The operation was successfully performed.') - - def _resultview_on_load(self): - def target(): - try: - resp = self._model.deferred_req() - self._status_label.text += 'Done.' - self._next_btn.disabled = False - if resp.status_code != 200: - self._show_msg('An error occurred:') - self._show_msg(resp.text.rstrip()) - return - self.show_result(resp) - finally: - self.fix() - self.reset() - self._model.screen.force_update() - Thread(target=target).start() + self.add_buttons(on_next_excl=self._next) def _next(self): self._model.reset() raise NextScene('Welcome') + + def _show_msg(self, text: str = '\n', center=False): + for line in text.splitlines(): + align = '^' if center else '<' + self._summary_layout.add_widget(Label(line, align=align), 1) + + # override this method in child classes if desired + def show_result(self, resp: requests.Response): + self._show_msg('The operation was successfully performed.', center=True) + + def _resultview_on_load(self): + resp = self._model.deferred_req_resp + try: + if resp.status_code != 200: + self._show_msg('An error occurred:') + self._show_msg(resp.text.rstrip()) + return + self.show_result(resp) + finally: + self.fix() diff --git a/ceo/tui/WelcomeView.py b/ceo/tui/WelcomeView.py index 2cab71f..ba57b1d 100644 --- a/ceo/tui/WelcomeView.py +++ b/ceo/tui/WelcomeView.py @@ -18,7 +18,7 @@ class WelcomeView(Frame): ('Add club rep', 'AddUser'), ('Renew member', 'RenewUser'), ('Renew club rep', 'RenewUser'), - ('Get user info', 'GetUserInfo'), + ('Get user info', 'GetUser'), ('Reset password', 'ResetPassword'), ('Modify user', 'ModifyUser'), ] diff --git a/ceo/tui/members/AddUserView.py b/ceo/tui/members/AddUserView.py index 782c4cd..8bde496 100644 --- a/ceo/tui/members/AddUserView.py +++ b/ceo/tui/members/AddUserView.py @@ -1,6 +1,6 @@ from threading import Thread -from asciimatics.widgets import Layout, Text, Label +from asciimatics.widgets import Layout, Text from ...term_utils import get_terms_for_new_user from ...utils import http_get, http_post, defer, user_dict_kv, \ @@ -35,11 +35,7 @@ class AddUserView(CeoFrame): validator=lambda s: s.isdigit() and s[0] != '0') layout.add_widget(self._num_terms) - layout = Layout([100]) - self.add_layout(layout) - self._status_label = Label('') - layout.add_widget(self._status_label) - + self.add_flash_message_layout() self.add_buttons( back_btn=True, next_scene='Confirm', on_next=self._next) @@ -58,7 +54,7 @@ class AddUserView(CeoFrame): Thread(target=self._get_uwldap_info, args=[username]).start() def _get_uwldap_info(self, username): - self._status_label.text = 'Looking up user...' + self.flash_message('Looking up user...') try: resp = http_get('/api/uwldap/' + username) if resp.status_code != 200: @@ -70,7 +66,7 @@ class AddUserView(CeoFrame): if data.get('mail_local_addresses'): self._forwarding_address.value = data['mail_local_addresses'][0] finally: - self._status_label.text = '' + self.clear_flash_message() def _next(self): body = { diff --git a/ceo/tui/members/RenewUserView.py b/ceo/tui/members/RenewUserView.py index 70aa1f9..95c0775 100644 --- a/ceo/tui/members/RenewUserView.py +++ b/ceo/tui/members/RenewUserView.py @@ -22,11 +22,7 @@ class RenewUserView(CeoFrame): validator=lambda s: s.isdigit() and s[0] != '0') layout.add_widget(self._num_terms) - layout = Layout([100]) - self.add_layout(layout) - self._status_label = Label('') - layout.add_widget(self._status_label) - + self.add_flash_message_layout() self.add_buttons( back_btn=True, next_scene='Confirm', on_next=self._next) @@ -34,16 +30,16 @@ class RenewUserView(CeoFrame): def _next(self): uid = self._username.value - self._status_label.text = 'Looking up user...' - self._model.screen.force_update() - self._model.screen.draw_next_frame() - new_terms = get_terms_for_renewal( - uid, - int(self._num_terms.value), - self._model.is_club_rep, - self._model, - ) - self._status_label.text = '' + self.flash_message('Looking up user...', force_update=True) + try: + new_terms = get_terms_for_renewal( + uid, + int(self._num_terms.value), + self._model.is_club_rep, + self._model, + ) + finally: + self.clear_flash_message() body = {'uid': uid} if self._model.is_club_rep: