Add ticket and note panes to new TUI

This commit is contained in:
2Shirt 2023-06-17 19:53:05 -07:00
parent 9b51bcbdc3
commit 0bcdde0ffb
Signed by: 2Shirt
GPG key ID: 152FAC923B0E132C
5 changed files with 102 additions and 41 deletions

View file

@ -1104,8 +1104,10 @@ class State():
# Write to progress file # Write to progress file
self.progress_out.write_text('\n'.join(report), encoding='utf-8', errors='ignore') self.progress_out.write_text('\n'.join(report), encoding='utf-8', errors='ignore')
def update_top_panes(self) -> None: def update_top_panes(self, note_lines: list | None = None) -> None:
"""(Re)create top source/destination panes.""" """(Re)create top source/destination panes."""
if not note_lines:
note_lines = []
source_exists = True source_exists = True
source_str = '' source_str = ''
dest_exists = True dest_exists = True
@ -1173,27 +1175,27 @@ class State():
dest_str, dest_str,
) )
# Bail if ticket not selected
if not self.ost:
return
# Ticket Details # Ticket Details
# TODO: Fixme self.ui.reset_subtitle_pane()
if self.ost and self.ost.ticket_id: if self.ost.ticket_id and not self.ui.layout['Subtitle']['Panes']:
text = ansi.color_string( self.ui.add_subtitle_pane(
[ ansi.color_string(
self.ost.ticket_name, [f'#{self.ost.ticket_id}', str(self.ost.ticket_name)],
' ' if self.ost.note else '\n', [None, 'CYAN'],
f'Ticket #{self.ost.ticket_id}', ),
f'\n{self.ost.note.splitlines()[0]}' if self.ost.note else '', str(self.ost.ticket_subject),
],
['CYAN', None, None, 'YELLOW'],
sep='',
) )
if self.panes.get('Ticket', None):
tmux.respawn_pane(self.panes['Ticket'], text=text) # Tech note
else: note_lines = self.ost.note.replace('...', '').splitlines()
self.panes['Ticket'] = tmux.split_window( if note_lines:
behind=True, self.ui.add_subtitle_pane(
lines=2, ansi.color_string('Tech Note', 'YELLOW'),
text=text, ' | '.join(note_lines),
vertical=True,
) )
@ -1910,6 +1912,7 @@ def main() -> None:
main_menu.actions[menus.MENU_ACTIONS[2]]['Separator'] = True main_menu.actions[menus.MENU_ACTIONS[2]]['Separator'] = True
else: else:
main_menu.actions['Add tech note']['Separator'] = True main_menu.actions['Add tech note']['Separator'] = True
state.update_top_panes()
try: try:
state.init_recovery(args) state.init_recovery(args)
except (FileNotFoundError, std.GenericAbort): except (FileNotFoundError, std.GenericAbort):
@ -1937,10 +1940,10 @@ def main() -> None:
# Tech note # Tech note
if 'tech note' in selection[0]: if 'tech note' in selection[0]:
state.ost.add_note( note_lines = state.ost.add_note(
'Please enter any additional information about this recovery', 'Please enter any additional information about this recovery',
) )
state.update_top_panes() state.update_top_panes(note_lines=note_lines)
# Start over # Start over
if 'Fresh start' in selection[0]: if 'Fresh start' in selection[0]:

View file

@ -144,6 +144,7 @@ class State():
# Reset objects # Reset objects
self.disks.clear() self.disks.clear()
self.test_groups.clear() self.test_groups.clear()
self.ui.remove_all_subtitle_panes()
# osTicket # osTicket
self.ost.init() self.ost.init()
@ -859,7 +860,12 @@ def print_countdown(proc, seconds) -> None:
print('') print('')
def run_diags(state, menu, quick_mode=False, test_mode=False) -> None: def run_diags(
state: State,
menu: cli.Menu,
quick_mode: bool = False,
test_mode: bool = False,
) -> None:
"""Run selected diagnostics.""" """Run selected diagnostics."""
aborted = False aborted = False
atexit.register(state.save_debug_reports) atexit.register(state.save_debug_reports)
@ -878,15 +884,24 @@ def run_diags(state, menu, quick_mode=False, test_mode=False) -> None:
# Update top_text # Update top_text
if state.ost.ticket_id: if state.ost.ticket_id:
state.top_text += cli.color_string( state.ui.add_subtitle_pane(
[f' #{state.ost.ticket_id}', state.ost.ticket_name], cli.color_string(
[None, 'CYAN'], [f'#{state.ost.ticket_id}', str(state.ost.ticket_name)],
) [None, 'CYAN'],
),
str(state.ost.ticket_subject),
)
# Add note # Add note
if (state.ost.ticket_id if (state.ost.ticket_id
and menu.toggles['osTicket Tech Note']['Selected']): and menu.toggles['osTicket Tech Note']['Selected']):
state.ost.add_note() note_lines = state.ost.add_note()
if note_lines:
state.ui.add_subtitle_pane(
cli.color_string('Tech Note', 'YELLOW'),
' | '.join(note_lines),
)
# Run tests # Run tests
for group in state.test_groups: for group in state.test_groups:
@ -927,6 +942,7 @@ def run_diags(state, menu, quick_mode=False, test_mode=False) -> None:
hw_osticket.update_checkboxes(state, NUM_DISK_TESTS) hw_osticket.update_checkboxes(state, NUM_DISK_TESTS)
# Done # Done
state.ui.remove_all_subtitle_panes()
state.save_debug_reports() state.save_debug_reports()
atexit.unregister(state.save_debug_reports) atexit.unregister(state.save_debug_reports)
if quick_mode: if quick_mode:

View file

@ -38,11 +38,12 @@ class osTicket():
def __init__(self): def __init__(self):
self.db_connection = None self.db_connection = None
self.db_cursor = None self.db_cursor = None
self.disabled = False self.disabled: bool = False
self.errors = False self.errors: bool = False
self.note = None self.note: str = ''
self.ticket_id = None self.ticket_id: int | None = None
self.ticket_name = None self.ticket_name: str | None = None
self.ticket_subject: str | None = None
# Ensure connection is closed atexit # Ensure connection is closed atexit
atexit.register(self._disconnect) atexit.register(self._disconnect)
@ -162,7 +163,7 @@ class osTicket():
LOG.error('Ticket ID not set') LOG.error('Ticket ID not set')
raise RuntimeError('Ticket ID not set') raise RuntimeError('Ticket ID not set')
def add_note(self, prompt=None): def add_note(self, prompt: str = 'Add note') -> list[str]:
"""Add note to be included in osTicket replies.""" """Add note to be included in osTicket replies."""
lines = [] lines = []
if not prompt: if not prompt:
@ -175,18 +176,21 @@ class osTicket():
# Get note # Get note
while True: while True:
text = cli.input_text('> ') text = cli.input_text('> ', allow_empty=True)
if not text: if not text:
break break
lines.append(text.strip()) lines.append(text.strip())
# Save note # Save note
if lines: if lines:
self.note = lines.pop(0) self.note = lines[0]
for line in lines: for line in lines[1:]:
self.note += f'\n...{line}' self.note += f'\n...{line}'
else: else:
self.note = None self.note = ''
# Done
return lines
def init(self): def init(self):
"""Revert to defaults.""" """Revert to defaults."""
@ -314,6 +318,7 @@ class osTicket():
if cli.ask('Is this correct?'): if cli.ask('Is this correct?'):
self.ticket_id = _id self.ticket_id = _id
self.ticket_name = _name self.ticket_name = _name
self.ticket_subject = _subject
# Done # Done
self._disconnect() self._disconnect()

View file

@ -67,7 +67,7 @@ def fix_layout(
# Calculate constraints # Calculate constraints
avail_horizontal, avail_vertical = get_window_size() avail_horizontal, avail_vertical = get_window_size()
avail_vertical -= layout['Current'].get('height', 0) avail_vertical -= layout['Current'].get('height', 0)
for group in ('Title', 'Info'): for group in ('Title', 'Subtitle', 'Info'):
if not layout[group]['Panes']: if not layout[group]['Panes']:
continue continue
avail_vertical -= layout[group].get('height', 0) + 1 avail_vertical -= layout[group].get('height', 0) + 1
@ -95,7 +95,7 @@ def fix_layout(
) )
for group, data in layout.items(): for group, data in layout.items():
num_panes = len(data['Panes']) num_panes = len(data['Panes'])
if num_panes < 2 or group not in ('Title', 'Info'): if num_panes < 2 or group not in ('Title', 'Subtitle', 'Info'):
continue continue
avail_horizontal -= (num_panes - 1) avail_horizontal -= (num_panes - 1)
pane_width, remainder = divmod(avail_horizontal, num_panes) pane_width, remainder = divmod(avail_horizontal, num_panes)

View file

@ -19,6 +19,7 @@ TMUX_SIDE_WIDTH = 21
TMUX_TITLE_HEIGHT = 2 TMUX_TITLE_HEIGHT = 2
TMUX_LAYOUT = { # NOTE: This needs to be in order from top to bottom TMUX_LAYOUT = { # NOTE: This needs to be in order from top to bottom
'Title': {'Panes': [], 'height': TMUX_TITLE_HEIGHT}, 'Title': {'Panes': [], 'height': TMUX_TITLE_HEIGHT},
'Subtitle': {'Panes': [], 'height': TMUX_TITLE_HEIGHT},
'Info': {'Panes': []}, 'Info': {'Panes': []},
'Current': {'Panes': [environ.get('TMUX_PANE', None)]}, 'Current': {'Panes': [environ.get('TMUX_PANE', None)]},
'Workers': {'Panes': []}, 'Workers': {'Panes': []},
@ -115,6 +116,29 @@ class TUI():
# Add pane # Add pane
self.layout['Title']['Panes'].append(tmux.split_window(**tmux_args)) self.layout['Title']['Panes'].append(tmux.split_window(**tmux_args))
def add_subtitle_pane(self, line1: str, line2: str) -> None:
"""Add pane to subtitle row."""
lines = [line1, line2]
tmux_args = {
'behind': True,
'lines': TMUX_TITLE_HEIGHT,
'target_id': None,
'text': '\n'.join(lines),
'vertical': True,
}
if self.layout['Subtitle']['Panes']:
tmux_args.update({
'behind': False,
'percent': 50,
'target_id': self.layout['Subtitle']['Panes'][-1],
'text': '\n'.join(lines),
'vertical': False,
})
tmux_args.pop('lines')
# Add pane
self.layout['Subtitle']['Panes'].append(tmux.split_window(**tmux_args))
def add_worker_pane( def add_worker_pane(
self, self,
lines: int | None = None, lines: int | None = None,
@ -216,6 +240,12 @@ class TUI():
self.layout['Info']['Panes'].clear() self.layout['Info']['Panes'].clear()
tmux.kill_pane(*panes) tmux.kill_pane(*panes)
def remove_all_subtitle_panes(self) -> None:
"""Remove all subtitle panes and update layout."""
panes = self.layout['Subtitle']['Panes'].copy()
self.layout['Subtitle']['Panes'].clear()
tmux.kill_pane(*panes)
def remove_all_worker_panes(self) -> None: def remove_all_worker_panes(self) -> None:
"""Remove all worker panes and update layout.""" """Remove all worker panes and update layout."""
self.layout['Workers'].pop('height', None) self.layout['Workers'].pop('height', None)
@ -237,6 +267,13 @@ class TUI():
self.layout['Title']['Panes'] = panes[:1] self.layout['Title']['Panes'] = panes[:1]
self.set_title(line1, line2, colors) self.set_title(line1, line2, colors)
def reset_subtitle_pane(self) -> None:
"""Remove all extra subtitle panes and update layout."""
panes = self.layout['Subtitle']['Panes'].copy()
if len(panes) > 1:
tmux.kill_pane(*panes[1:])
self.layout['Subtitle']['Panes'] = panes[:1]
def set_current_pane_height(self, height: int) -> None: def set_current_pane_height(self, height: int) -> None:
"""Set current pane height and update layout.""" """Set current pane height and update layout."""
self.layout['Current']['height'] = height self.layout['Current']['height'] = height
@ -318,7 +355,7 @@ def fix_layout(layout, forced: bool = False) -> None:
pass pass
# Update "group" panes widths # Update "group" panes widths
for group in ('Title', 'Info'): for group in ('Title', 'Subtitle', 'Info'):
num_panes = len(layout[group]['Panes']) num_panes = len(layout[group]['Panes'])
if num_panes <= 1: if num_panes <= 1:
continue continue