diff --git a/cylc/flow/tui/data.py b/cylc/flow/tui/data.py index 3a3ed4ee378..4d00753cf3f 100644 --- a/cylc/flow/tui/data.py +++ b/cylc/flow/tui/data.py @@ -17,7 +17,12 @@ from functools import partial from subprocess import Popen, PIPE -from cylc.flow.exceptions import ClientError +from cylc.flow.exceptions import ( + ClientError, + ClientTimeout, + WorkflowStopped, +) +from cylc.flow.network.client_factory import get_client from cylc.flow.id import Tokens from cylc.flow.tui.util import ( extract_context @@ -187,11 +192,25 @@ def generate_mutation(mutation, arguments): ''' -def list_mutations(client, selection): +def list_mutations(selection, is_running=True): + """List mutations relevant to the provided selection. + + Args: + selection: + The user selection. + is_running: + If False, then mutations which require the scheduler to be + running will be omitted. + + Note, this is only relevant for workflow nodes because if a + workflow is stopped, then any tasks within it will be removed + anyway. + + """ context = extract_context(selection) selection_type = list(context)[-1] ret = [] - if client: + if is_running: # add the online mutations ret.extend(MUTATIONS.get(selection_type, [])) # add the offline mutations @@ -232,20 +251,15 @@ def context_to_variables(context): return variables -def mutate(client, mutation, selection): +def mutate(mutation, selection): if mutation in { _mutation for section in OFFLINE_MUTATIONS.values() for _mutation in section }: offline_mutate(mutation, selection) - elif client: - online_mutate(client, mutation, selection) else: - raise Exception( - f'Cannot peform command {mutation} on a stopped workflow' - ' or invalid command.' - ) + online_mutate(mutation, selection) def online_mutate(mutation, selection): diff --git a/cylc/flow/tui/overlay.py b/cylc/flow/tui/overlay.py index f4d5ca02f94..87b544b0604 100644 --- a/cylc/flow/tui/overlay.py +++ b/cylc/flow/tui/overlay.py @@ -37,20 +37,13 @@ """ -from contextlib import suppress from functools import partial import re import sys import urwid -from cylc.flow.exceptions import ( - ClientError, - ClientTimeout, - WorkflowStopped, -) from cylc.flow.id import Tokens -from cylc.flow.network.client_factory import get_client from cylc.flow.task_state import ( TASK_STATUSES_ORDERED, TASK_STATUS_WAITING @@ -61,7 +54,6 @@ TUI ) from cylc.flow.tui.data import ( - extract_context, list_mutations, mutate, ) @@ -296,20 +288,23 @@ def context(app): """An overlay for context menus.""" value = app.tree_walker.get_focus()[0].get_node().get_value() selection = [value['id_']] # single selection ATM - context = extract_context(selection) - client = None - if 'workflow' in context: - w_id = context['workflow'][0] - with suppress(WorkflowStopped, ClientError, ClientTimeout): - client = get_client(w_id) + is_running = True + if ( + value['type_'] == 'workflow' + and value['data']['status'] not in {'running', 'paused'} + ): + # this is a stopped workflow + # => don't display mutations only valid for a running workflow + is_running = False def _mutate(mutation, _): - nonlocal app, client + nonlocal app, selection + app.open_overlay(partial(progress, text='Running Command')) try: - mutate(client, mutation, selection) - except ClientError as exc: + mutate(mutation, selection) + except Exception as exc: app.open_overlay(partial(error, text=str(exc))) else: app.close_topmost() @@ -334,7 +329,10 @@ def _mutate(mutation, _): mutation, on_press=partial(_mutate, mutation) ) - for mutation in list_mutations(client, selection) + for mutation in list_mutations( + selection, + is_running, + ) ] ) )