remove support for resizing
This commit is contained in:
parent
faa5c73145
commit
893eb384f1
|
@ -125,7 +125,7 @@ cn: regular1
|
|||
gidNumber: 20002
|
||||
|
||||
dn: uid=exec1,ou=People,dc=csclub,dc=internal
|
||||
cn: Regular One
|
||||
cn: Exec One
|
||||
userPassword: {SASL}exec1@CSCLUB.INTERNAL
|
||||
loginShell: /bin/bash
|
||||
homeDirectory: /users/exec1
|
||||
|
|
|
@ -47,201 +47,6 @@ objectClass: top
|
|||
uid: regular2
|
||||
mail: regular2@uwaterloo.internal
|
||||
|
||||
dn: uid=exec1,ou=UWLDAP,dc=csclub,dc=internal
|
||||
displayName: Exec One
|
||||
givenName: Exec
|
||||
sn: One
|
||||
cn: Exec One
|
||||
ou: MAT/Mathematics Computer Science
|
||||
mailLocalAddress: exec1@uwaterloo.internal
|
||||
objectClass: inetLocalMailRecipient
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: exec1
|
||||
mail: exec1@uwaterloo.internal
|
||||
|
||||
dn: uid=exec2,ou=UWLDAP,dc=csclub,dc=internal
|
||||
displayName: Exec Two
|
||||
givenName: Exec
|
||||
sn: Two
|
||||
cn: Exec Two
|
||||
ou: MAT/Mathematics Computer Science
|
||||
mailLocalAddress: exec2@uwaterloo.internal
|
||||
objectClass: inetLocalMailRecipient
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: exec2
|
||||
mail: exec2@uwaterloo.internal
|
||||
|
||||
dn: uid=ctdalek,ou=UWLDAP,dc=csclub,dc=internal
|
||||
displayName: Calum Dalek
|
||||
givenName: Calum
|
||||
sn: Dalek
|
||||
cn: Calum Dalek
|
||||
ou: MAT/Mathematics Computer Science
|
||||
mailLocalAddress: ctdalek@uwaterloo.internal
|
||||
objectClass: inetLocalMailRecipient
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: ctdalek
|
||||
mail: ctdalek@uwaterloo.internal
|
||||
|
||||
dn: uid=regular1,ou=UWLDAP,dc=csclub,dc=internal
|
||||
displayName: Regular One
|
||||
givenName: Regular
|
||||
sn: One
|
||||
cn: Regular One
|
||||
ou: MAT/Mathematics Computer Science
|
||||
mailLocalAddress: regular1@uwaterloo.internal
|
||||
objectClass: inetLocalMailRecipient
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: regular1
|
||||
mail: regular1@uwaterloo.internal
|
||||
|
||||
dn: uid=regular2,ou=UWLDAP,dc=csclub,dc=internal
|
||||
displayName: Regular Two
|
||||
givenName: Regular
|
||||
sn: Two
|
||||
cn: Regular Two
|
||||
ou: MAT/Mathematics Computer Science
|
||||
mailLocalAddress: regular2@uwaterloo.internal
|
||||
objectClass: inetLocalMailRecipient
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: regular2
|
||||
mail: regular2@uwaterloo.internal
|
||||
|
||||
dn: uid=exec1,ou=UWLDAP,dc=csclub,dc=internal
|
||||
displayName: Exec One
|
||||
givenName: Exec
|
||||
sn: One
|
||||
cn: Exec One
|
||||
ou: MAT/Mathematics Computer Science
|
||||
mailLocalAddress: exec1@uwaterloo.internal
|
||||
objectClass: inetLocalMailRecipient
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: exec1
|
||||
mail: exec1@uwaterloo.internal
|
||||
|
||||
dn: uid=ctdalek,ou=UWLDAP,dc=csclub,dc=internal
|
||||
displayName: Calum Dalek
|
||||
givenName: Calum
|
||||
sn: Dalek
|
||||
cn: Calum Dalek
|
||||
ou: MAT/Mathematics Computer Science
|
||||
mailLocalAddress: ctdalek@uwaterloo.internal
|
||||
objectClass: inetLocalMailRecipient
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: ctdalek
|
||||
mail: ctdalek@uwaterloo.internal
|
||||
|
||||
dn: uid=regular1,ou=UWLDAP,dc=csclub,dc=internal
|
||||
displayName: Regular One
|
||||
givenName: Regular
|
||||
sn: One
|
||||
cn: Regular One
|
||||
ou: MAT/Mathematics Computer Science
|
||||
mailLocalAddress: regular1@uwaterloo.internal
|
||||
objectClass: inetLocalMailRecipient
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: regular1
|
||||
mail: regular1@uwaterloo.internal
|
||||
|
||||
dn: uid=regular2,ou=UWLDAP,dc=csclub,dc=internal
|
||||
displayName: Regular Two
|
||||
givenName: Regular
|
||||
sn: Two
|
||||
cn: Regular Two
|
||||
ou: MAT/Mathematics Computer Science
|
||||
mailLocalAddress: regular2@uwaterloo.internal
|
||||
objectClass: inetLocalMailRecipient
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: regular2
|
||||
mail: regular2@uwaterloo.internal
|
||||
|
||||
dn: uid=exec1,ou=UWLDAP,dc=csclub,dc=internal
|
||||
displayName: Exec One
|
||||
givenName: Exec
|
||||
sn: One
|
||||
cn: Exec One
|
||||
ou: MAT/Mathematics Computer Science
|
||||
mailLocalAddress: exec1@uwaterloo.internal
|
||||
objectClass: inetLocalMailRecipient
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: exec1
|
||||
mail: exec1@uwaterloo.internal
|
||||
|
||||
dn: uid=ctdalek,ou=UWLDAP,dc=csclub,dc=internal
|
||||
displayName: Calum Dalek
|
||||
givenName: Calum
|
||||
sn: Dalek
|
||||
cn: Calum Dalek
|
||||
ou: MAT/Mathematics Computer Science
|
||||
mailLocalAddress: ctdalek@uwaterloo.internal
|
||||
objectClass: inetLocalMailRecipient
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: ctdalek
|
||||
mail: ctdalek@uwaterloo.internal
|
||||
|
||||
dn: uid=regular1,ou=UWLDAP,dc=csclub,dc=internal
|
||||
displayName: Regular One
|
||||
givenName: Regular
|
||||
sn: One
|
||||
cn: Regular One
|
||||
ou: MAT/Mathematics Computer Science
|
||||
mailLocalAddress: regular1@uwaterloo.internal
|
||||
objectClass: inetLocalMailRecipient
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: regular1
|
||||
mail: regular1@uwaterloo.internal
|
||||
|
||||
dn: uid=regular2,ou=UWLDAP,dc=csclub,dc=internal
|
||||
displayName: Regular Two
|
||||
givenName: Regular
|
||||
sn: Two
|
||||
cn: Regular Two
|
||||
ou: MAT/Mathematics Computer Science
|
||||
mailLocalAddress: regular2@uwaterloo.internal
|
||||
objectClass: inetLocalMailRecipient
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: organizationalPerson
|
||||
objectClass: person
|
||||
objectClass: top
|
||||
uid: regular2
|
||||
mail: regular2@uwaterloo.internal
|
||||
|
||||
dn: uid=regular3,ou=UWLDAP,dc=csclub,dc=internal
|
||||
displayName: Regular Three
|
||||
givenName: Regular
|
||||
|
|
|
@ -12,11 +12,9 @@ class CeoFrame(Frame):
|
|||
height,
|
||||
width,
|
||||
model,
|
||||
name, # key in model.viewdata
|
||||
name,
|
||||
on_load=None,
|
||||
title=None,
|
||||
save_data=False, # whether to save widget state for resizing
|
||||
has_dynamic_layouts=False, # whether layouts are created on load
|
||||
escape_on_q=False, # whether to quit when 'q' is pressed
|
||||
):
|
||||
super().__init__(
|
||||
|
@ -28,70 +26,46 @@ class CeoFrame(Frame):
|
|||
title=title,
|
||||
on_load=self._ceoframe_on_load,
|
||||
)
|
||||
self._save_data = save_data
|
||||
self._extra_on_load = on_load
|
||||
self._custom_on_load = on_load
|
||||
self._model = model
|
||||
self._name = name
|
||||
self._has_dynamic_layouts = has_dynamic_layouts
|
||||
# If a view has a custom on_load function, all layouts should
|
||||
# be created on load (*not* in the constructor)
|
||||
self._has_dynamic_layouts = on_load is not None
|
||||
self._quit_keys = [Screen.KEY_ESCAPE]
|
||||
if escape_on_q:
|
||||
self._quit_keys.append(ord('q'))
|
||||
# sanity check
|
||||
if save_data:
|
||||
assert name in model.viewdata
|
||||
# child classes may override this as a last resort
|
||||
self.do_not_reload = False
|
||||
self.skip_reload = False
|
||||
|
||||
def _ceoframe_on_load(self):
|
||||
if self.do_not_reload:
|
||||
self.do_not_reload = False
|
||||
if self.skip_reload:
|
||||
self.skip_reload = False
|
||||
return
|
||||
self.do_not_reload = True
|
||||
if self._has_dynamic_layouts:
|
||||
# We arrive here after a user pressed 'Back' then 'Next'.
|
||||
# The data may have changed, so we need to redraw everything,
|
||||
# via self._extra_on_load().
|
||||
self.clear_layouts()
|
||||
if self._model.title is not None:
|
||||
self.title = self._model.title
|
||||
self._model.title = None
|
||||
if self._save_data:
|
||||
# restore the saved input fields' values
|
||||
self.data = self._model.viewdata[self._name]
|
||||
if self._extra_on_load is not None:
|
||||
self._extra_on_load()
|
||||
|
||||
def _ceoframe_on_unload(self):
|
||||
"""
|
||||
This should be called just after the screen gets resized,
|
||||
but before the new scenes are constructed.
|
||||
The idea is to save the user's data in the input fields
|
||||
so that we can restore them in the new scenes.
|
||||
"""
|
||||
if not self._save_data:
|
||||
return
|
||||
self.save()
|
||||
self._model.viewdata[self._name] = self.data
|
||||
if self._has_dynamic_layouts and self._model.nav_direction == 'forward':
|
||||
# We arrive here after a user pressed 'Back' then 'Next',
|
||||
# or after we returned to the Welcome screen.
|
||||
# The data may have changed, so we need to redraw everything,
|
||||
# via self._custom_on_load().
|
||||
self.clear_layouts()
|
||||
self._custom_on_load()
|
||||
|
||||
# may be overridden by child classes
|
||||
def _ceoframe_on_reset(self):
|
||||
"""
|
||||
This needs to be called whenever we return to the home screen
|
||||
This is called whenever we return to the home screen
|
||||
after some kind of operation was completed.
|
||||
Currently this is called from Model.reset().
|
||||
This is called from Model.reset().
|
||||
"""
|
||||
# We want a fresh slate once we return to the home screen, so we
|
||||
# want on_load() to be called for the scenes.
|
||||
self.do_not_reload = False
|
||||
if self._has_dynamic_layouts:
|
||||
# We don't want layouts to accumulate.
|
||||
self.clear_layouts()
|
||||
# Reset input fields to ''.
|
||||
# This is causing an Exception to be raised...
|
||||
# self.save()
|
||||
# self.data = {key: '' for key in self.data}
|
||||
|
||||
def clear_layouts(self):
|
||||
# OK so this a *really* bad thing to do, since we're reaching
|
||||
# into the private variables of a third-party library.
|
||||
# Unfortunately asciimatics doesn't allow us to clear the layouts
|
||||
# of an existing frame, and we need this to be able to re-use
|
||||
# frames which create layouts dynamically.
|
||||
self._layouts.clear()
|
||||
|
||||
def force_update(self):
|
||||
|
@ -126,12 +100,14 @@ class CeoFrame(Frame):
|
|||
layout.add_widget(Divider())
|
||||
|
||||
def _back():
|
||||
self._model.nav_direction = 'backward'
|
||||
last_scene = self._model.scene_stack.pop()
|
||||
if last_scene == 'Welcome':
|
||||
self._model.reset()
|
||||
raise NextScene(last_scene)
|
||||
|
||||
def _next():
|
||||
self._model.nav_direction = 'forward'
|
||||
if on_next_excl is not None:
|
||||
on_next_excl()
|
||||
return
|
||||
|
|
|
@ -8,7 +8,6 @@ class ConfirmView(CeoFrame):
|
|||
super().__init__(
|
||||
screen, height, width, model, 'Confirm',
|
||||
on_load=self._confirmview_on_load, title='Confirmation',
|
||||
has_dynamic_layouts=True,
|
||||
escape_on_q=True,
|
||||
)
|
||||
|
||||
|
@ -46,6 +45,11 @@ class ConfirmView(CeoFrame):
|
|||
kwargs['on_next_excl'] = self._next
|
||||
self.add_buttons(**kwargs)
|
||||
self.fix()
|
||||
# OK so there's some weird bug somewhere which causes the buttons to be unselectable
|
||||
# if we add a new user, return to the Welcome screen, then try to renew a user.
|
||||
# This is a workaround for that.
|
||||
self.skip_reload = True
|
||||
self.reset()
|
||||
|
||||
def _next(self):
|
||||
self.flash_message('Sending request...', force_update=True)
|
||||
|
|
|
@ -9,7 +9,6 @@ class ErrorView(CeoFrame):
|
|||
super().__init__(
|
||||
screen, height, width, model, 'Error',
|
||||
on_load=self._errorview_on_load, title='Error',
|
||||
has_dynamic_layouts=True,
|
||||
)
|
||||
|
||||
def _errorview_on_load(self):
|
||||
|
|
|
@ -1,16 +1,10 @@
|
|||
from copy import deepcopy
|
||||
|
||||
from zope import component
|
||||
|
||||
from ceo_common.interfaces import IConfig
|
||||
|
||||
|
||||
class Model:
|
||||
"""A convenient place to store View data persistently."""
|
||||
|
||||
def __init__(self):
|
||||
cfg = component.getUtility(IConfig)
|
||||
|
||||
self.screen = None
|
||||
self.views = []
|
||||
self.title = None
|
||||
|
@ -18,69 +12,13 @@ class Model:
|
|||
self.result_view_name = None
|
||||
self.txn_view_name = None
|
||||
self.error_message = None
|
||||
# View-specific data, to be used when e.g. resizing the window.
|
||||
# For the views where save_data=True was passed to the CeoFrame
|
||||
# constructor, the keys correspond to the names of text fields.
|
||||
self.nav_direction = 'forward'
|
||||
# View-specific data
|
||||
self._initial_viewdata = {
|
||||
'AddUser': {
|
||||
'uid': '',
|
||||
'cn': '',
|
||||
'program': '',
|
||||
'forwarding_address': '',
|
||||
'num_terms': '1',
|
||||
},
|
||||
'RenewUser': {
|
||||
'uid': '',
|
||||
'num_terms': '1',
|
||||
},
|
||||
'Transaction': {
|
||||
'op_layout': None,
|
||||
'msg_layout': None,
|
||||
'labels': {},
|
||||
'status': 'not started',
|
||||
},
|
||||
'GetUser': {
|
||||
'uid': '',
|
||||
},
|
||||
'ResetPassword': {
|
||||
'uid': '',
|
||||
},
|
||||
'ChangeLoginShell': {
|
||||
'uid': '',
|
||||
'login_shell': '',
|
||||
},
|
||||
'SetForwardingAddresses': {
|
||||
'uid': '',
|
||||
'forwarding_addresses': [''],
|
||||
},
|
||||
'AddGroup': {
|
||||
'cn': '',
|
||||
'description': '',
|
||||
},
|
||||
'GetGroup': {
|
||||
'cn': '',
|
||||
},
|
||||
'AddMemberToGroup': {
|
||||
'cn': '',
|
||||
'uid': '',
|
||||
'subscribe': True,
|
||||
},
|
||||
'RemoveMemberFromGroup': {
|
||||
'cn': '',
|
||||
'uid': '',
|
||||
'unsubscribe': True,
|
||||
},
|
||||
'CreateDatabase': {
|
||||
'uid': '',
|
||||
},
|
||||
'ResetDatabasePassword': {
|
||||
'uid': '',
|
||||
},
|
||||
# This one needs to be filled in dynamically
|
||||
'SetPositions': {},
|
||||
}
|
||||
for pos in cfg.get('positions_available'):
|
||||
self._initial_viewdata[pos] = ''
|
||||
self.viewdata = deepcopy(self._initial_viewdata)
|
||||
# data which is shared between multiple views
|
||||
self.is_club_rep = False
|
||||
|
|
|
@ -10,7 +10,6 @@ class ResultView(CeoFrame):
|
|||
super().__init__(
|
||||
screen, height, width, model, 'Result',
|
||||
on_load=self._resultview_on_load, title='Result',
|
||||
has_dynamic_layouts=True,
|
||||
escape_on_q=True,
|
||||
)
|
||||
|
||||
|
|
|
@ -15,10 +15,9 @@ class TransactionView(CeoFrame):
|
|||
super().__init__(
|
||||
screen, height, width, model, 'Transaction',
|
||||
on_load=self._txnview_on_load, title='Running Transaction',
|
||||
has_dynamic_layouts=True,
|
||||
)
|
||||
# map operation names to label widgets
|
||||
self._labels = model.viewdata['Transaction']['labels']
|
||||
self._labels = {}
|
||||
|
||||
def _add_buttons(self):
|
||||
layout = Layout([100])
|
||||
|
@ -28,10 +27,6 @@ class TransactionView(CeoFrame):
|
|||
layout = Layout([1, 1])
|
||||
self.add_layout(layout)
|
||||
self._next_btn = Button('Next', self._next)
|
||||
# we don't want to disable the button if the txn completed
|
||||
# and the user just resized the window
|
||||
if self._model.viewdata['Transaction']['status'] != 'completed':
|
||||
self._next_btn.disabled = True
|
||||
layout.add_widget(self._next_btn, 1)
|
||||
|
||||
def _add_blank_line(self):
|
||||
|
@ -39,47 +34,30 @@ class TransactionView(CeoFrame):
|
|||
self._op_layout.add_widget(Label(''), 2)
|
||||
|
||||
def _txnview_on_load(self):
|
||||
d = self._model.viewdata['Transaction']
|
||||
if d['op_layout'] is None:
|
||||
first_time = True
|
||||
self._op_layout = Layout([12, 1, 10])
|
||||
self.add_layout(self._op_layout)
|
||||
# store the layouts so that we can re-use them when the screen
|
||||
# gets resized
|
||||
d['op_layout'] = self._op_layout
|
||||
for _ in range(2):
|
||||
self._add_blank_line()
|
||||
for operation in self._model.operations:
|
||||
desc = op_desc[operation]
|
||||
self._op_layout.add_widget(Label(desc + '...', align='>'), 0)
|
||||
desc_label = Label('', align='<')
|
||||
self._op_layout.add_widget(desc_label, 2)
|
||||
self._labels[operation] = desc_label
|
||||
self._op_layout = Layout([12, 1, 10])
|
||||
self.add_layout(self._op_layout)
|
||||
# store the layouts so that we can re-use them when the screen
|
||||
# gets resized
|
||||
for _ in range(2):
|
||||
self._add_blank_line()
|
||||
# this is the where success/failure messages etc. get placed
|
||||
self._msg_layout = Layout([100])
|
||||
self.add_layout(self._msg_layout)
|
||||
d['msg_layout'] = self._msg_layout
|
||||
else:
|
||||
# we arrive here when the screen has been resized
|
||||
first_time = False
|
||||
# restore the layouts which we saved
|
||||
self._op_layout = d['op_layout']
|
||||
self.add_layout(self._op_layout)
|
||||
self._msg_layout = d['msg_layout']
|
||||
self.add_layout(self._msg_layout)
|
||||
for operation in self._model.operations:
|
||||
desc = op_desc[operation]
|
||||
self._op_layout.add_widget(Label(desc + '...', align='>'), 0)
|
||||
desc_label = Label('', align='<')
|
||||
self._op_layout.add_widget(desc_label, 2)
|
||||
self._labels[operation] = desc_label
|
||||
self._add_blank_line()
|
||||
# this is the where success/failure messages etc. get placed
|
||||
self._msg_layout = Layout([100])
|
||||
self.add_layout(self._msg_layout)
|
||||
# fill up the rest of the space
|
||||
self.add_layout(Layout([100], fill_frame=True))
|
||||
|
||||
self._add_buttons()
|
||||
self.fix()
|
||||
# only send the API request the first time we arrive at this
|
||||
# scene, not when the screen gets resized
|
||||
if first_time:
|
||||
Thread(target=self._do_txn).start()
|
||||
Thread(target=self._do_txn).start()
|
||||
|
||||
def _do_txn(self):
|
||||
self._model.viewdata['Transaction']['status'] = 'in progress'
|
||||
resp = self._model.deferred_req()
|
||||
handler = TUIStreamResponseHandler(
|
||||
model=self._model,
|
||||
|
@ -99,10 +77,8 @@ class TransactionView(CeoFrame):
|
|||
# If we don't reset, the button isn't selectable, even though we
|
||||
# enabled it.
|
||||
# We don't want to reload, though (which reset() will trigger).
|
||||
self.do_not_reload = True
|
||||
self.skip_reload = True
|
||||
self.reset()
|
||||
# save the fact that the transaction is completed
|
||||
self._model.viewdata['Transaction']['status'] = 'completed'
|
||||
|
||||
def _next(self):
|
||||
self._model.reset()
|
||||
|
|
|
@ -8,7 +8,6 @@ class CreateDatabaseView(CeoFrame):
|
|||
def __init__(self, screen, width, height, model):
|
||||
super().__init__(
|
||||
screen, height, width, model, 'CreateDatabase',
|
||||
save_data=True,
|
||||
)
|
||||
layout = Layout([100], fill_frame=True)
|
||||
self.add_layout(layout)
|
||||
|
@ -19,6 +18,10 @@ class CreateDatabaseView(CeoFrame):
|
|||
on_next=self._next)
|
||||
self.fix()
|
||||
|
||||
def _ceoframe_on_reset(self):
|
||||
super()._ceoframe_on_reset()
|
||||
self._username.value = None
|
||||
|
||||
def _target(self):
|
||||
username = self._username.value
|
||||
db_type = self._model.db_type
|
||||
|
|
|
@ -8,7 +8,6 @@ class ResetDatabasePasswordView(CeoFrame):
|
|||
def __init__(self, screen, width, height, model):
|
||||
super().__init__(
|
||||
screen, height, width, model, 'ResetDatabasePassword',
|
||||
save_data=True,
|
||||
)
|
||||
layout = Layout([100], fill_frame=True)
|
||||
self.add_layout(layout)
|
||||
|
@ -19,6 +18,10 @@ class ResetDatabasePasswordView(CeoFrame):
|
|||
on_next=self._next)
|
||||
self.fix()
|
||||
|
||||
def _ceoframe_on_reset(self):
|
||||
super()._ceoframe_on_reset()
|
||||
self._username.value = None
|
||||
|
||||
def _target(self):
|
||||
username = self._username.value
|
||||
db_type = self._model.db_type
|
||||
|
|
|
@ -9,7 +9,6 @@ class AddGroupView(CeoFrame):
|
|||
def __init__(self, screen, width, height, model):
|
||||
super().__init__(
|
||||
screen, height, width, model, 'AddGroup',
|
||||
save_data=True,
|
||||
)
|
||||
layout = Layout([100], fill_frame=True)
|
||||
self.add_layout(layout)
|
||||
|
@ -23,6 +22,11 @@ class AddGroupView(CeoFrame):
|
|||
next_scene='Confirm', on_next=self._next)
|
||||
self.fix()
|
||||
|
||||
def _ceoframe_on_reset(self):
|
||||
super()._ceoframe_on_reset()
|
||||
self._cn.value = None
|
||||
self._description.value = None
|
||||
|
||||
def _next(self):
|
||||
cn = self._cn.value
|
||||
description = self._description.value
|
||||
|
|
|
@ -9,7 +9,6 @@ class AddMemberToGroupView(CeoFrame):
|
|||
def __init__(self, screen, width, height, model):
|
||||
super().__init__(
|
||||
screen, height, width, model, 'AddMemberToGroup',
|
||||
save_data=True,
|
||||
)
|
||||
layout = Layout([100], fill_frame=True)
|
||||
self.add_layout(layout)
|
||||
|
@ -28,6 +27,12 @@ class AddMemberToGroupView(CeoFrame):
|
|||
next_scene='Confirm', on_next=self._next)
|
||||
self.fix()
|
||||
|
||||
def _ceoframe_on_reset(self):
|
||||
super()._ceoframe_on_reset()
|
||||
self._cn.value = None
|
||||
self._username.value = None
|
||||
self._checkbox.value = True
|
||||
|
||||
def _next(self):
|
||||
cn = self._cn.value
|
||||
uid = self._username.value
|
||||
|
|
|
@ -8,7 +8,6 @@ class GetGroupView(CeoFrame):
|
|||
def __init__(self, screen, width, height, model):
|
||||
super().__init__(
|
||||
screen, height, width, model, 'GetGroup',
|
||||
save_data=True,
|
||||
)
|
||||
layout = Layout([100], fill_frame=True)
|
||||
self.add_layout(layout)
|
||||
|
@ -21,9 +20,12 @@ class GetGroupView(CeoFrame):
|
|||
next_scene='GetGroupResult', on_next=self._next)
|
||||
self.fix()
|
||||
|
||||
def _ceoframe_on_reset(self):
|
||||
super()._ceoframe_on_reset()
|
||||
self._cn.value = None
|
||||
|
||||
def _next(self):
|
||||
cn = self._cn.value
|
||||
self._model.viewdata['GetGroup']['cn'] = cn
|
||||
self.flash_message('Looking up group...', force_update=True)
|
||||
try:
|
||||
self._model.resp = http_get(f'/api/groups/{cn}')
|
||||
|
|
|
@ -9,7 +9,6 @@ class RemoveMemberFromGroupView(CeoFrame):
|
|||
def __init__(self, screen, width, height, model):
|
||||
super().__init__(
|
||||
screen, height, width, model, 'RemoveMemberFromGroup',
|
||||
save_data=True,
|
||||
)
|
||||
layout = Layout([100], fill_frame=True)
|
||||
self.add_layout(layout)
|
||||
|
@ -28,6 +27,11 @@ class RemoveMemberFromGroupView(CeoFrame):
|
|||
next_scene='Confirm', on_next=self._next)
|
||||
self.fix()
|
||||
|
||||
def _ceoframe_on_reset(self):
|
||||
super()._ceoframe_on_reset()
|
||||
self._cn.value = None
|
||||
self._username.value = None
|
||||
|
||||
def _next(self):
|
||||
cn = self._cn.value
|
||||
uid = self._username.value
|
||||
|
|
|
@ -12,7 +12,6 @@ class AddUserView(CeoFrame):
|
|||
def __init__(self, screen, width, height, model):
|
||||
super().__init__(
|
||||
screen, height, width, model, 'AddUser',
|
||||
save_data=True,
|
||||
)
|
||||
self._username_changed = False
|
||||
|
||||
|
@ -33,6 +32,7 @@ class AddUserView(CeoFrame):
|
|||
self._num_terms = Text(
|
||||
"Number of terms:", "num_terms",
|
||||
validator=lambda s: s.isdigit() and s[0] != '0')
|
||||
self._num_terms.value = '1'
|
||||
layout.add_widget(self._num_terms)
|
||||
|
||||
self.add_flash_message_layout()
|
||||
|
@ -41,6 +41,14 @@ class AddUserView(CeoFrame):
|
|||
next_scene='Confirm', on_next=self._next)
|
||||
self.fix()
|
||||
|
||||
def _ceoframe_on_reset(self):
|
||||
super()._ceoframe_on_reset()
|
||||
self._username.value = None
|
||||
self._full_name.value = None
|
||||
self._program.value = None
|
||||
self._forwarding_address.value = None
|
||||
self._num_terms.value = '1'
|
||||
|
||||
def _on_username_change(self):
|
||||
self._username_changed = True
|
||||
|
||||
|
|
|
@ -10,7 +10,6 @@ class ChangeLoginShellView(CeoFrame):
|
|||
def __init__(self, screen, width, height, model):
|
||||
super().__init__(
|
||||
screen, height, width, model, 'ChangeLoginShell',
|
||||
save_data=True,
|
||||
)
|
||||
self._username_changed = False
|
||||
|
||||
|
@ -31,6 +30,11 @@ class ChangeLoginShellView(CeoFrame):
|
|||
next_scene='Confirm', on_next=self._next)
|
||||
self.fix()
|
||||
|
||||
def _ceoframe_on_reset(self):
|
||||
super()._ceoframe_on_reset()
|
||||
self._username.value = None
|
||||
self._login_shell.value = None
|
||||
|
||||
# TODO: deduplicate this from AddUserView
|
||||
def _on_username_change(self):
|
||||
self._username_changed = True
|
||||
|
|
|
@ -8,7 +8,6 @@ class GetUserView(CeoFrame):
|
|||
def __init__(self, screen, width, height, model):
|
||||
super().__init__(
|
||||
screen, height, width, model, 'GetUser',
|
||||
save_data=True,
|
||||
)
|
||||
layout = Layout([100], fill_frame=True)
|
||||
self.add_layout(layout)
|
||||
|
@ -21,6 +20,10 @@ class GetUserView(CeoFrame):
|
|||
next_scene='GetUserResult', on_next=self._next)
|
||||
self.fix()
|
||||
|
||||
def _ceoframe_on_reset(self):
|
||||
super()._ceoframe_on_reset()
|
||||
self._username.value = None
|
||||
|
||||
def _next(self):
|
||||
uid = self._username.value
|
||||
self.flash_message('Looking up user...', force_update=True)
|
||||
|
|
|
@ -9,7 +9,6 @@ class RenewUserView(CeoFrame):
|
|||
def __init__(self, screen, width, height, model):
|
||||
super().__init__(
|
||||
screen, height, width, model, 'RenewUser',
|
||||
save_data=True,
|
||||
)
|
||||
self._model = model
|
||||
|
||||
|
@ -20,6 +19,7 @@ class RenewUserView(CeoFrame):
|
|||
self._num_terms = Text(
|
||||
"Number of terms:", "num_terms",
|
||||
validator=lambda s: s.isdigit() and s[0] != '0')
|
||||
self._num_terms.value = '1'
|
||||
layout.add_widget(self._num_terms)
|
||||
|
||||
self.add_flash_message_layout()
|
||||
|
@ -28,6 +28,11 @@ class RenewUserView(CeoFrame):
|
|||
next_scene='Confirm', on_next=self._next)
|
||||
self.fix()
|
||||
|
||||
def _ceoframe_on_reset(self):
|
||||
super()._ceoframe_on_reset()
|
||||
self._username.value = None
|
||||
self._num_terms.value = '1'
|
||||
|
||||
def _next(self):
|
||||
uid = self._username.value
|
||||
self.flash_message('Looking up user...', force_update=True)
|
||||
|
|
|
@ -8,7 +8,6 @@ class ResetPasswordView(CeoFrame):
|
|||
def __init__(self, screen, width, height, model):
|
||||
super().__init__(
|
||||
screen, height, width, model, 'ResetPassword',
|
||||
save_data=True,
|
||||
)
|
||||
layout = Layout([100], fill_frame=True)
|
||||
self.add_layout(layout)
|
||||
|
@ -21,6 +20,10 @@ class ResetPasswordView(CeoFrame):
|
|||
next_scene='Confirm', on_next=self._next)
|
||||
self.fix()
|
||||
|
||||
def _ceoframe_on_reset(self):
|
||||
super()._ceoframe_on_reset()
|
||||
self._username.value = None
|
||||
|
||||
def _next(self):
|
||||
uid = self._username.value
|
||||
self._model.viewdata['ResetPassword']['uid'] = uid
|
||||
|
|
|
@ -10,7 +10,6 @@ class SetForwardingAddressesView(CeoFrame):
|
|||
def __init__(self, screen, width, height, model):
|
||||
super().__init__(
|
||||
screen, height, width, model, 'SetForwardingAddresses',
|
||||
save_data=True,
|
||||
)
|
||||
self._username_changed = False
|
||||
|
||||
|
@ -34,6 +33,11 @@ class SetForwardingAddressesView(CeoFrame):
|
|||
next_scene='Confirm', on_next=self._next)
|
||||
self.fix()
|
||||
|
||||
def _ceoframe_on_reset(self):
|
||||
super()._ceoframe_on_reset()
|
||||
self._username.value = None
|
||||
self._forwarding_addresses.value = None
|
||||
|
||||
# TODO: deduplicate this from AddUserView
|
||||
def _on_username_change(self):
|
||||
self._username_changed = True
|
||||
|
|
|
@ -27,25 +27,9 @@ class GetPositionsView(CeoFrame):
|
|||
super().__init__(
|
||||
screen, height, width, model, 'GetPositions',
|
||||
escape_on_q=True,
|
||||
on_load=self._on_load)
|
||||
|
||||
cfg = component.getUtility(IConfig)
|
||||
avail = cfg.get('positions_available')
|
||||
|
||||
layout = Layout([100])
|
||||
self.add_layout(layout)
|
||||
layout.add_widget(Label(''))
|
||||
|
||||
self._main_layout = Layout([10, 1, 10], fill_frame=True)
|
||||
self.add_layout(self._main_layout)
|
||||
|
||||
on_load=self._on_load
|
||||
)
|
||||
self._position_widgets = {}
|
||||
for pos in avail:
|
||||
self._position_widgets[pos] = self._add_pair(position_names[pos], '')
|
||||
|
||||
self.add_flash_message_layout()
|
||||
self.add_buttons(back_btn=True)
|
||||
self.fix()
|
||||
|
||||
def _add_blank_line(self):
|
||||
self._main_layout.add_widget(Label(' ', 0))
|
||||
|
@ -59,6 +43,23 @@ class GetPositionsView(CeoFrame):
|
|||
return value_widget
|
||||
|
||||
def _on_load(self):
|
||||
cfg = component.getUtility(IConfig)
|
||||
avail = cfg.get('positions_available')
|
||||
|
||||
layout = Layout([100])
|
||||
self.add_layout(layout)
|
||||
layout.add_widget(Label(''))
|
||||
|
||||
self._main_layout = Layout([10, 1, 10], fill_frame=True)
|
||||
self.add_layout(self._main_layout)
|
||||
|
||||
for pos in avail:
|
||||
self._position_widgets[pos] = self._add_pair(position_names[pos], '')
|
||||
|
||||
self.add_flash_message_layout()
|
||||
self.add_buttons(back_btn=True)
|
||||
self.fix()
|
||||
|
||||
def target():
|
||||
self.flash_message('Looking up positions...')
|
||||
try:
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
from threading import Thread
|
||||
|
||||
from asciimatics.widgets import Layout, Label, Text
|
||||
from zope import component
|
||||
|
||||
|
@ -14,16 +12,18 @@ class SetPositionsView(CeoFrame):
|
|||
def __init__(self, screen, width, height, model):
|
||||
super().__init__(
|
||||
screen, height, width, model, 'SetPositions',
|
||||
save_data=True)
|
||||
)
|
||||
cfg = component.getUtility(IConfig)
|
||||
avail = cfg.get('positions_available')
|
||||
required = cfg.get('positions_required')
|
||||
|
||||
layout = Layout([100], fill_frame=True)
|
||||
self.add_layout(layout)
|
||||
self._widgets = []
|
||||
for pos in avail:
|
||||
suffix = ' (*)' if pos in required else ''
|
||||
widget = Text(position_names[pos] + suffix, pos)
|
||||
self._widgets.append(widget)
|
||||
layout.add_widget(widget)
|
||||
|
||||
layout = Layout([100])
|
||||
|
@ -36,11 +36,16 @@ class SetPositionsView(CeoFrame):
|
|||
next_scene='Confirm', on_next=self._next)
|
||||
self.fix()
|
||||
|
||||
def _ceoframe_on_reset(self):
|
||||
super()._ceoframe_on_reset()
|
||||
for widget in self._widgets:
|
||||
widget.value = None
|
||||
|
||||
def _next(self):
|
||||
self.save()
|
||||
body = {pos: username for pos, username in self.data.items() if username}
|
||||
|
||||
self._model.deferred_req = defer(http_post, f'/api/positions', json=body)
|
||||
self._model.deferred_req = defer(http_post, '/api/positions', json=body)
|
||||
self._model.operations = UpdateMemberPositionsTransaction.operations
|
||||
self._model.confirm_lines = [
|
||||
"The positions will be updated as follows:",
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
from asciimatics.exceptions import ResizeScreenError
|
||||
|
@ -37,10 +38,6 @@ views = []
|
|||
|
||||
def screen_wrapper(screen, last_scene, model):
|
||||
global views
|
||||
# unload the old views
|
||||
for name, view in views:
|
||||
if hasattr(view, '_ceoframe_on_unload'):
|
||||
view._ceoframe_on_unload()
|
||||
width = min(screen.width, 90)
|
||||
height = min(screen.height, 24)
|
||||
views = [
|
||||
|
@ -83,9 +80,10 @@ def screen_wrapper(screen, last_scene, model):
|
|||
def main():
|
||||
last_scene = None
|
||||
model = Model()
|
||||
while True:
|
||||
try:
|
||||
Screen.wrapper(screen_wrapper, arguments=[last_scene, model])
|
||||
sys.exit(0)
|
||||
except ResizeScreenError as e:
|
||||
last_scene = e.scene
|
||||
try:
|
||||
Screen.wrapper(screen_wrapper, arguments=[last_scene, model])
|
||||
sys.exit(0)
|
||||
except ResizeScreenError:
|
||||
os.system('reset')
|
||||
print('Unfortunately, ceo does not currently support dynamic resizing.')
|
||||
sys.exit(1)
|
||||
|
|
|
@ -144,7 +144,7 @@ def generic_handle_stream_response(
|
|||
"""
|
||||
if resp.status_code != 200:
|
||||
handler.handle_non_200(resp)
|
||||
return
|
||||
return [{'status': 'error'}]
|
||||
handler.begin()
|
||||
idx = 0
|
||||
data = []
|
||||
|
@ -153,7 +153,7 @@ def generic_handle_stream_response(
|
|||
data.append(d)
|
||||
if d['status'] == 'aborted':
|
||||
handler.handle_aborted(d['error'])
|
||||
return
|
||||
return data
|
||||
elif d['status'] == 'completed':
|
||||
while idx < len(operations):
|
||||
handler.handle_skipped_operation()
|
||||
|
|
Loading…
Reference in New Issue