Skip to content

Commit

Permalink
Tui 1.0
Browse files Browse the repository at this point in the history
* Move the updater into another process.
  This removes the limitation that caused Tui to crash with active workflows.
  Closes cylc#3527
* Add multi-workflow capability.
  Closes cylc#3464
* Add visual regression testing framework.
  Closes cylc#3530
  • Loading branch information
oliver-sanders committed Sep 14, 2023
1 parent 63ceffb commit 6a35418
Show file tree
Hide file tree
Showing 14 changed files with 1,531 additions and 428 deletions.
1 change: 1 addition & 0 deletions cylc/flow/option_parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
)

WORKFLOW_ID_ARG_DOC = ('WORKFLOW', 'Workflow ID')
OPT_WORKFLOW_ID_ARG_DOC = ('[WORKFLOW]', 'Workflow ID')
WORKFLOW_ID_MULTI_ARG_DOC = ('WORKFLOW ...', 'Workflow ID(s)')
WORKFLOW_ID_OR_PATH_ARG_DOC = ('WORKFLOW | PATH', 'Workflow ID or path')
ID_MULTI_ARG_DOC = ('ID ...', 'Workflow/Cycle/Family/Task ID(s)')
Expand Down
81 changes: 56 additions & 25 deletions cylc/flow/scripts/tui.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,35 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""cylc tui WORKFLOW
"""cylc tui [WORKFLOW]
View and control running workflows in the terminal.
(Tui = Terminal User Interface)
WARNING: Tui is experimental and may break with large flows.
An upcoming change to the way Tui receives data from the scheduler will make it
much more efficient in the future.
Tui allows you to monitor and interact with workflows in a manner similar
to the GUI.
Press "h" whilst running Tui to bring up the help screen, use the arrow
keys to navigage.
"""
# TODO: remove this warning once Tui is delta-driven
# https://github.com/cylc/cylc-flow/issues/3527

from getpass import getuser
from textwrap import indent
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Optional
from urwid import html_fragment

from cylc.flow.exceptions import InputError
from cylc.flow.id import Tokens
from cylc.flow.id_cli import parse_id
from cylc.flow.option_parsers import (
WORKFLOW_ID_ARG_DOC,
OPT_WORKFLOW_ID_ARG_DOC,
CylcOptionParser as COP,
)
from cylc.flow.terminal import cli_function
from cylc.flow.tui import TUI
from cylc.flow.tui.util import suppress_logging
from cylc.flow.tui.app import (
TuiApp,
TREE_EXPAND_DEPTH
Expand All @@ -55,7 +60,7 @@
def get_option_parser() -> COP:
parser = COP(
__doc__,
argdoc=[WORKFLOW_ID_ARG_DOC],
argdoc=[OPT_WORKFLOW_ID_ARG_DOC],
# auto_add=False, NOTE: at present auto_add can not be turned off
color=False
)
Expand All @@ -80,32 +85,58 @@ def get_option_parser() -> COP:
action='store',
default='80,24'
)
parser.add_option(
'--single-workflow', '-s',
help=(
'Only show a single workflow rather than all workflows'
),
action='store_true',
default=False,
)

return parser


@cli_function(get_option_parser)
def main(_, options: 'Values', workflow_id: str) -> None:
workflow_id, *_ = parse_id(
workflow_id,
constraint='workflows',
def configure_screenshot(v_term_size):
screen = html_fragment.HtmlGenerator()
screen.set_terminal_properties(256)
screen.register_palette(TuiApp.palette)
html_fragment.screenshot_init(
[tuple(map(int, v_term_size.split(',')))],
[]
)
return screen, html_fragment


@cli_function(get_option_parser)
def main(_, options: 'Values', workflow_id: Optional[str] = None) -> None:
if options.single_workflow and not workflow_id:
raise InputError('--single-workflow requires a workflow ID')

# get workflow ID if specified
if workflow_id:
workflow_id, *_ = parse_id(
workflow_id,
constraint='workflows',
)
tokens = Tokens(workflow_id)
workflow_id = tokens.duplicate(user=getuser()).id

# configure Tui
screen = None
html_fragment = None
if options.display == 'html':
TREE_EXPAND_DEPTH[0] = -1 # expand tree fully
screen = html_fragment.HtmlGenerator()
screen.set_terminal_properties(256)
screen.register_palette(TuiApp.palette)
html_fragment.screenshot_init(
[tuple(map(int, options.v_term_size.split(',')))],
[]
)
screen, html_fragment = configure_screenshot(options.v_term_size)

# start Tui
try:
TuiApp(workflow_id, screen=screen).main()
with suppress_logging():
TuiApp(screen=screen).main(
workflow_id,
options.single_workflow,
)

if options.display == 'html':
for fragment in html_fragment.screenshot_collect():
print(fragment)
print(html_fragment.screenshot_collect()[-1])
except KeyboardInterrupt:
pass
3 changes: 0 additions & 3 deletions cylc/flow/tui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,3 @@ def list_groups(self):
if binding['group'] == name
]
)


BINDINGS = Bindings()
Loading

0 comments on commit 6a35418

Please sign in to comment.