diff --git a/cylc/flow/tui/app.py b/cylc/flow/tui/app.py index eb9f8dec09c..63814bcac79 100644 --- a/cylc/flow/tui/app.py +++ b/cylc/flow/tui/app.py @@ -250,6 +250,7 @@ class TuiApp: ('header', 'dark gray', BACK), ('header_key', 'dark gray, bold', BACK), ('overlay', 'black', 'light gray'), + ('diminished', 'dark gray', BACK), # cylc logo colours ('R', 'light red, bold', BACK), ('Y', 'yellow, bold', BACK), diff --git a/cylc/flow/tui/data.py b/cylc/flow/tui/data.py index a6cd60c6bb9..97d5c36982c 100644 --- a/cylc/flow/tui/data.py +++ b/cylc/flow/tui/data.py @@ -47,6 +47,7 @@ isHeld isQueued isRunahead + flowNums firstParent { id name @@ -116,6 +117,7 @@ 'trigger', 'poll', 'set', + 'remove', ], 'job': [ 'kill', diff --git a/cylc/flow/tui/overlay.py b/cylc/flow/tui/overlay.py index b4759e27e78..fc893990478 100644 --- a/cylc/flow/tui/overlay.py +++ b/cylc/flow/tui/overlay.py @@ -59,6 +59,7 @@ ) from cylc.flow.tui.util import ( ListBoxPlus, + format_flow_nums, get_task_icon, get_text_dimensions, ) @@ -154,7 +155,7 @@ def filter_task_state(app): checkboxes = [ urwid.CheckBox( - get_task_icon(state) + get_task_icon(state, colour='overlay') + [' ' + state], state=is_on, on_state_change=partial(_toggle_filter, app, 'tasks', state) @@ -237,7 +238,7 @@ def help_info(app): for state in TASK_STATUSES_ORDERED: items.append( urwid.Text( - get_task_icon(state) + get_task_icon(state, colour='overlay') + [' ', state] ) ) @@ -245,19 +246,27 @@ def help_info(app): items.append(urwid.Text('Special States:')) items.append( urwid.Text( - get_task_icon(TASK_STATUS_WAITING, is_held=True) + get_task_icon(TASK_STATUS_WAITING, is_held=True, colour='overlay') + [' ', 'held'] ) ) items.append( urwid.Text( - get_task_icon(TASK_STATUS_WAITING, is_queued=True) + get_task_icon( + TASK_STATUS_WAITING, + is_queued=True, + colour='overlay', + ) + [' ', 'queued'] ) ) items.append( urwid.Text( - get_task_icon(TASK_STATUS_WAITING, is_runahead=True) + get_task_icon( + TASK_STATUS_WAITING, + is_runahead=True, + colour='overlay', + ) + [' ', 'runahead'] ) ) @@ -317,11 +326,36 @@ def _mutate(mutation, _): # determine the ID to display for the context menu display_id = _get_display_id(value['id_']) + header = [f'id: {display_id}'] + attrs = [] + + # workflow state info + if value['data'].get('status'): + attrs.append(value['data']['status']) + + # task state info + if value['data'].get('state'): + attrs.append( + value['data']['state'] + + ( + ' (held)' if value['data'].get('isHeld') + else ' (queued)' if value['data'].get('isQueued') + else '(runahead)' if value['data'].get('isRunahead') + else '' + ) + ) + + # task flow info + if value['data'].get('flowNums', '[1]') != '[1]': + attrs.append(f'flows={format_flow_nums(value["data"]["flowNums"])}') + + if attrs: + header.append(', '.join(attrs)) widget = urwid.ListBox( urwid.SimpleFocusListWalker( [ - urwid.Text(f'id: {display_id}'), + urwid.Text('\n'.join(header)), urwid.Divider(), urwid.Text('Action'), urwid.Button( diff --git a/cylc/flow/tui/util.py b/cylc/flow/tui/util.py index d0ea2a651c6..7950d9c87ec 100644 --- a/cylc/flow/tui/util.py +++ b/cylc/flow/tui/util.py @@ -26,6 +26,7 @@ import urwid from cylc.flow import LOG +from cylc.flow.flow_mgr import stringify_flow_nums from cylc.flow.id import Tokens from cylc.flow.task_state import ( TASK_STATUS_RUNNING @@ -36,6 +37,7 @@ TASK_ICONS, TASK_MODIFIERS ) +from cylc.flow.util import deserialise_set from cylc.flow.wallclock import get_unix_time_from_time_string @@ -69,8 +71,9 @@ def get_task_icon( is_held=False, is_queued=False, is_runahead=False, + colour='body', start_time=None, - mean_time=None + mean_time=None, ): """Return a Unicode string to represent a task. @@ -83,6 +86,9 @@ def get_task_icon( True if the task is queued. is_runahead (bool): True if the task is runahead limited. + colour (str): + Set the icon colour. If not provided, the default foreground text + colour will be used. start_time (str): Start date time string. mean_time (int): @@ -95,11 +101,11 @@ def get_task_icon( """ ret = [] if is_held: - ret.append(TASK_MODIFIERS['held']) + ret.append((colour, TASK_MODIFIERS['held'])) elif is_runahead: - ret.append(TASK_MODIFIERS['runahead']) + ret.append((colour, TASK_MODIFIERS['runahead'])) elif is_queued: - ret.append(TASK_MODIFIERS['queued']) + ret.append((colour, TASK_MODIFIERS['queued'])) if ( status == TASK_STATUS_RUNNING and start_time @@ -115,7 +121,7 @@ def get_task_icon( status = f'{TASK_STATUS_RUNNING}:25' else: status = f'{TASK_STATUS_RUNNING}:0' - ret.append(TASK_ICONS[status]) + ret.append((colour, TASK_ICONS[status])) return ret @@ -517,12 +523,20 @@ def _render_task(node, data): start_time = first_child.get_value()['data']['startedTime'] mean_time = data['task']['meanElapsedTime'] + if data['flowNums'] == '[]': + # grey out no-flow tasks + colour = 'diminished' + else: + # default foreground colour for everything else + colour = 'body' + # the task icon ret = get_task_icon( data['state'], is_held=data['isHeld'], is_queued=data['isQueued'], is_runahead=data['isRunahead'], + colour=colour, start_time=start_time, mean_time=mean_time ) @@ -534,7 +548,7 @@ def _render_task(node, data): ret += [(f'job_{state}', f'{JOB_ICON}'), ' '] # the task name - ret.append(f'{data["name"]}') + ret.append((colour, f'{data["name"]}')) return ret @@ -690,3 +704,16 @@ def keypress(self, size, key): target = new_target else: return super().keypress(size, key) + + +def format_flow_nums(serialised_flow_nums: str) -> str: + """Return a user-facing representation of task serialised flow nums. + + Examples: + >>> format_flow_nums('[1,2]') + '1,2' + >>> format_flow_nums('[]') + 'None' + + """ + return stringify_flow_nums(deserialise_set(serialised_flow_nums)) or 'None' diff --git a/tests/integration/tui/screenshots/test_auto_expansion.later-time.html b/tests/integration/tui/screenshots/test_auto_expansion.later-time.html index 6e6490ebc05..b774fae1541 100644 --- a/tests/integration/tui/screenshots/test_auto_expansion.later-time.html +++ b/tests/integration/tui/screenshots/test_auto_expansion.later-time.html @@ -2,12 +2,12 @@ - ~cylc - one - paused 1■ - - ● 1 - ● b - - ̿○ 2 - - ̿○ A - ̿○ a - ○ b + - ● 1 + ● b + - ̿○ 2 + - ̿○ A + ̿○ a + ○ b diff --git a/tests/integration/tui/screenshots/test_auto_expansion.on-load.html b/tests/integration/tui/screenshots/test_auto_expansion.on-load.html index d8f3ca712b8..4b251ff117e 100644 --- a/tests/integration/tui/screenshots/test_auto_expansion.on-load.html +++ b/tests/integration/tui/screenshots/test_auto_expansion.on-load.html @@ -2,10 +2,10 @@ - ~cylc - one - paused - - ̿○ 1 - - ̿○ A - ̿○ a - ○ b + - ̿○ 1 + - ̿○ A + ̿○ a + ○ b diff --git a/tests/integration/tui/screenshots/test_navigation.cursor-at-bottom-of-screen.html b/tests/integration/tui/screenshots/test_navigation.cursor-at-bottom-of-screen.html index c25e28ebd11..a0f6aa7a3e4 100644 --- a/tests/integration/tui/screenshots/test_navigation.cursor-at-bottom-of-screen.html +++ b/tests/integration/tui/screenshots/test_navigation.cursor-at-bottom-of-screen.html @@ -2,15 +2,15 @@ - ~cylc - one - paused - - ̿○ 1 - + ̿○ A - - ̿○ B - - ̿○ B1 - ̿○ b11 - ̿○ b12 - - ̿○ B2 - ̿○ b21 - ̿○ b22 + - ̿○ 1 + + ̿○ A + - ̿○ B + - ̿○ B1 + ̿○ b11 + ̿○ b12 + - ̿○ B2 + ̿○ b21 + ̿○ b22 diff --git a/tests/integration/tui/screenshots/test_navigation.family-A-collapsed.html b/tests/integration/tui/screenshots/test_navigation.family-A-collapsed.html index 4c988d41792..0fa35b40141 100644 --- a/tests/integration/tui/screenshots/test_navigation.family-A-collapsed.html +++ b/tests/integration/tui/screenshots/test_navigation.family-A-collapsed.html @@ -2,15 +2,15 @@ - ~cylc - one - paused - - ̿○ 1 - + ̿○ A - - ̿○ B - - ̿○ B1 - ̿○ b11 - ̿○ b12 - - ̿○ B2 - ̿○ b21 - ̿○ b22 + - ̿○ 1 + + ̿○ A + - ̿○ B + - ̿○ B1 + ̿○ b11 + ̿○ b12 + - ̿○ B2 + ̿○ b21 + ̿○ b22 diff --git a/tests/integration/tui/screenshots/test_navigation.workflow-expanded.html b/tests/integration/tui/screenshots/test_navigation.workflow-expanded.html index e91225fef23..427d67b21be 100644 --- a/tests/integration/tui/screenshots/test_navigation.workflow-expanded.html +++ b/tests/integration/tui/screenshots/test_navigation.workflow-expanded.html @@ -2,17 +2,17 @@ - ~cylc - one - paused - - ̿○ 1 - - ̿○ A - ̿○ a1 - ̿○ a2 - - ̿○ B - - ̿○ B1 - ̿○ b11 - ̿○ b12 - - ̿○ B2 - ̿○ b21 - ̿○ b22 + - ̿○ 1 + - ̿○ A + ̿○ a1 + ̿○ a2 + - ̿○ B + - ̿○ B1 + ̿○ b11 + ̿○ b12 + - ̿○ B2 + ̿○ b21 + ̿○ b22 diff --git a/tests/integration/tui/screenshots/test_offline_mutation.clean-command-error.html b/tests/integration/tui/screenshots/test_offline_mutation.clean-command-error.html index 88defab9486..1592ee2e0f6 100644 --- a/tests/integration/tui/screenshots/test_offline_mutation.clean-command-error.html +++ b/tests/integration/tui/screenshots/test_offline_mutation.clean-command-error.html @@ -1,15 +1,15 @@
Cylc Tui work┌────┌────────────────────────────────────────────────┐ │ id│ Error │ -- ~cylc │ │ │ - + one - stop│ Ac│ Error in command cylc clean --yes one │ - │ < │ mock-stderr │ +- ~cylc │ st│ │ + + one - stop│ │ Error in command cylc clean --yes one │ + │ Ac│ mock-stderr │ + │ < │ │ │ │ │ │ < │ │ │ < │ │ │ < │ │ │ < │ │ │ │ │ - │ │ │ │ │ │ quit: q help: │ q t│ q to close │ome End filter tasks: T└────└────────────────────────────────────────────────┘ diff --git a/tests/integration/tui/screenshots/test_offline_mutation.clean-mutation-selected.html b/tests/integration/tui/screenshots/test_offline_mutation.clean-mutation-selected.html index 5590254a28d..982759fd480 100644 --- a/tests/integration/tui/screenshots/test_offline_mutation.clean-mutation-selected.html +++ b/tests/integration/tui/screenshots/test_offline_mutation.clean-mutation-selected.html @@ -1,7 +1,8 @@Cylc Tui work┌────────────────────────────────────────────────┐ │ id: ~cylc/one │ -- ~cylc │ │ - + one - stop│ Action │ +- ~cylc │ stopped │ + + one - stop│ │ + │ Action │ │ < (cancel) > │ │ │ │ < clean > │ @@ -9,7 +10,6 @@ │ < play > │ │ < reinstall-reload > │ │ │ - │ │ │ │ quit: q help: │ q to close │↥ ↧ Home End filter tasks: T└────────────────────────────────────────────────┘ diff --git a/tests/integration/tui/screenshots/test_online_mutation.command-failed-client-error.html b/tests/integration/tui/screenshots/test_online_mutation.command-failed-client-error.html index 895856c6ea2..106c447e62f 100644 --- a/tests/integration/tui/screenshots/test_online_mutation.command-failed-client-error.html +++ b/tests/integration/tui/screenshots/test_online_mutation.command-failed-client-error.html @@ -1,10 +1,10 @@Cylc Tui work┌────┌────────────────────────────────────────────────┐ │ id│ Error │ -- ~cylc │ │ │ - - one - paus│ Ac│ Error connecting to workflow: mock error │ - - ̿○ 1 │ < │ │ - ̿○ on│ │ │ - │ < │ │ +- ~cylc │ wa│ │ + - one - paus│ │ Error connecting to workflow: mock error │ + - ̿○ 1 │ Ac│ │ + ̿○ on│ < │ │ + │ │ │ │ < │ │ │ < │ │ │ < │ │ diff --git a/tests/integration/tui/screenshots/test_online_mutation.command-failed-workflow-stopped.html b/tests/integration/tui/screenshots/test_online_mutation.command-failed-workflow-stopped.html index 6f9954926ef..6d9a1f40eab 100644 --- a/tests/integration/tui/screenshots/test_online_mutation.command-failed-workflow-stopped.html +++ b/tests/integration/tui/screenshots/test_online_mutation.command-failed-workflow-stopped.html @@ -1,10 +1,10 @@Cylc Tui work┌────┌────────────────────────────────────────────────┐ │ id│ Error │ -- ~cylc │ │ │ - - one - paus│ Ac│ Cannot peform command hold on a stopped │ - - ̿○ 1 │ < │ workflow │ - ̿○ on│ │ │ - │ < │ │ +- ~cylc │ wa│ │ + - one - paus│ │ Cannot peform command hold on a stopped │ + - ̿○ 1 │ Ac│ workflow │ + ̿○ on│ < │ │ + │ │ │ │ < │ │ │ < │ │ │ < │ │ diff --git a/tests/integration/tui/screenshots/test_online_mutation.hold-mutation-selected.html b/tests/integration/tui/screenshots/test_online_mutation.hold-mutation-selected.html index 8bfe41ea904..f1624ddc0ca 100644 --- a/tests/integration/tui/screenshots/test_online_mutation.hold-mutation-selected.html +++ b/tests/integration/tui/screenshots/test_online_mutation.hold-mutation-selected.html @@ -1,15 +1,15 @@Cylc Tui work┌────────────────────────────────────────────────┐ │ id: 1/one │ -- ~cylc │ │ - - one - paus│ Action │ - - ̿○ 1 │ < (cancel) > │ - ̿○ on│ │ +- ~cylc │ waiting (queued) │ + - one - paus│ │ + - ̿○ 1 │ Action │ + ̿○ on│ < (cancel) > │ + │ │ │ < hold > │ │ < kill > │ │ < log > │ │ < poll > │ │ < release > │ - │ < set > │ │ │ quit: q help: │ q to close │↥ ↧ Home End filter tasks: T└────────────────────────────────────────────────┘ diff --git a/tests/integration/tui/screenshots/test_online_mutation.task-selected.html b/tests/integration/tui/screenshots/test_online_mutation.task-selected.html index df7a917ff60..4c06cd4eca3 100644 --- a/tests/integration/tui/screenshots/test_online_mutation.task-selected.html +++ b/tests/integration/tui/screenshots/test_online_mutation.task-selected.html @@ -2,8 +2,8 @@ - ~cylc - one - paused - - ̿○ 1 - ̿○ one + - ̿○ 1 + ̿○ one diff --git a/tests/integration/tui/screenshots/test_restart_reconnect.1-workflow-running.html b/tests/integration/tui/screenshots/test_restart_reconnect.1-workflow-running.html index aabddcc9cf6..56cc2d76af3 100644 --- a/tests/integration/tui/screenshots/test_restart_reconnect.1-workflow-running.html +++ b/tests/integration/tui/screenshots/test_restart_reconnect.1-workflow-running.html @@ -2,8 +2,8 @@ - ~cylc - one - paused - - ̿○ 1 - ̿○ one + - ̿○ 1 + ̿○ one diff --git a/tests/integration/tui/screenshots/test_restart_reconnect.3-workflow-restarted.html b/tests/integration/tui/screenshots/test_restart_reconnect.3-workflow-restarted.html index aabddcc9cf6..56cc2d76af3 100644 --- a/tests/integration/tui/screenshots/test_restart_reconnect.3-workflow-restarted.html +++ b/tests/integration/tui/screenshots/test_restart_reconnect.3-workflow-restarted.html @@ -2,8 +2,8 @@ - ~cylc - one - paused - - ̿○ 1 - ̿○ one + - ̿○ 1 + ̿○ one diff --git a/tests/integration/tui/screenshots/test_set_mutation.set-command-selected.html b/tests/integration/tui/screenshots/test_set_mutation.set-command-selected.html index 8f27deac20e..5b1eb3492c5 100644 --- a/tests/integration/tui/screenshots/test_set_mutation.set-command-selected.html +++ b/tests/integration/tui/screenshots/test_set_mutation.set-command-selected.html @@ -1,14 +1,14 @@Cylc Tui work┌────────────────────────────────────────────────┐ - │ id: 1/a │ -- ~cylc │ │ - - one - paus│ Action │ - - ̿○ 1 │ < (cancel) > │ - ̿○ a │ │ - ○ z │ < hold > │ - │ < kill > │ + │ │ +- ~cylc │ Action │ + - one - paus│ < (cancel) > │ + - ̿○ 1 │ │ + ̿○ a │ < hold > │ + ○ z │ < kill > │ │ < log > │ │ < poll > │ │ < release > │ + │ < remove > │ │ < set > │ │ │ quit: q help: │ q to close │↥ ↧ Home End diff --git a/tests/integration/tui/screenshots/test_set_mutation.task-state-updated.html b/tests/integration/tui/screenshots/test_set_mutation.task-state-updated.html index b99e16cf6ea..818e423fecf 100644 --- a/tests/integration/tui/screenshots/test_set_mutation.task-state-updated.html +++ b/tests/integration/tui/screenshots/test_set_mutation.task-state-updated.html @@ -2,9 +2,9 @@ - ~cylc - one - paused 1■ - - ̿○ 1 - ● a - ̿○ z + - ̿○ 1 + ● a + ̿○ z diff --git a/tests/integration/tui/screenshots/test_show.fail.html b/tests/integration/tui/screenshots/test_show.fail.html index 66a4836bc01..35efaf63f78 100644 --- a/tests/integration/tui/screenshots/test_show.fail.html +++ b/tests/integration/tui/screenshots/test_show.fail.html @@ -2,14 +2,15 @@ │ Error │ - ~cylc │ │ - one - paused │ :( │ - - ̿○ 1 │ │ - ̿○ foo │ │ + - ̿○ 1 │ │ + ̿○ foo │ │ │ │ │ │ │ │ │ │ ┌────│ │ │ id│ │ + │ wa│ │ │ │ │ │ Ac│ │ │ < │ │ @@ -22,8 +23,7 @@ │ < │ │ │ < │ │ │ < │ │ - │ │ │ - │ │ │ + │ < │ │ │ │ │ │ │ │ │ q t│ │ diff --git a/tests/integration/tui/screenshots/test_show.success.html b/tests/integration/tui/screenshots/test_show.success.html index 7f1caebe49d..c0aaf20a9e7 100644 --- a/tests/integration/tui/screenshots/test_show.success.html +++ b/tests/integration/tui/screenshots/test_show.success.html @@ -2,8 +2,8 @@ - ~cylc - one - paused - - ̿○ 1 - ̿○ foo + - ̿○ 1 + ̿○ foo diff --git a/tests/integration/tui/screenshots/test_subscribe_unsubscribe.subscribed.html b/tests/integration/tui/screenshots/test_subscribe_unsubscribe.subscribed.html index 7d190cb6f4d..0de8198a3b9 100644 --- a/tests/integration/tui/screenshots/test_subscribe_unsubscribe.subscribed.html +++ b/tests/integration/tui/screenshots/test_subscribe_unsubscribe.subscribed.html @@ -2,8 +2,8 @@ - ~cylc - one - paused - - ̿○ 1 - ̿○ one + - ̿○ 1 + ̿○ one diff --git a/tests/integration/tui/screenshots/test_task_states.filter-not-waiting-or-expired.html b/tests/integration/tui/screenshots/test_task_states.filter-not-waiting-or-expired.html index 8cc7056da94..a843a299268 100644 --- a/tests/integration/tui/screenshots/test_task_states.filter-not-waiting-or-expired.html +++ b/tests/integration/tui/screenshots/test_task_states.filter-not-waiting-or-expired.html @@ -3,18 +3,18 @@ - ~cylc - test_task_states - paused 1■ 1■ 1■ 1■ 1■ - - ̿⊗ 1 - - ̿● X - ̿● a - - ̿⊗ Y - ̿⊗ b - - ̎⊘ 2 - - ̿⊙ X - ̿⊙ a - - ̎⊘ Y - - ̎⊘ Y1 - ̎⊘ c - ̎⊙ b + - ̿⊗ 1 + - ̿● X + ̿● a + - ̿⊗ Y + ̿⊗ b + - ̎⊘ 2 + - ̿⊙ X + ̿⊙ a + - ̎⊘ Y + - ̎⊘ Y1 + ̎⊘ c + ̎⊙ b diff --git a/tests/integration/tui/screenshots/test_task_states.filter-not-waiting.html b/tests/integration/tui/screenshots/test_task_states.filter-not-waiting.html index f2ba4116623..39bfe584e69 100644 --- a/tests/integration/tui/screenshots/test_task_states.filter-not-waiting.html +++ b/tests/integration/tui/screenshots/test_task_states.filter-not-waiting.html @@ -3,20 +3,20 @@ - ~cylc - test_task_states - paused 1■ 1■ 1■ 1■ 1■ - - ̿⊗ 1 - - ̿● X - ̿● a - - ̿⊗ Y - - ◌ Y1 - ◌ c - ̿⊗ b - - ̎⊘ 2 - - ̿⊙ X - ̿⊙ a - - ̎⊘ Y - - ̎⊘ Y1 - ̎⊘ c - ̎⊙ b + - ̿⊗ 1 + - ̿● X + ̿● a + - ̿⊗ Y + - ◌ Y1 + ◌ c + ̿⊗ b + - ̎⊘ 2 + - ̿⊙ X + ̿⊙ a + - ̎⊘ Y + - ̎⊘ Y1 + ̎⊘ c + ̎⊙ b diff --git a/tests/integration/tui/screenshots/test_task_states.filter-submitted.html b/tests/integration/tui/screenshots/test_task_states.filter-submitted.html index 2cf989253d4..167154ef701 100644 --- a/tests/integration/tui/screenshots/test_task_states.filter-submitted.html +++ b/tests/integration/tui/screenshots/test_task_states.filter-submitted.html @@ -3,9 +3,9 @@ - ~cylc - test_task_states - paused 1■ 1■ 1■ 1■ 1■ - - ̎⊘ 2 - - ̿⊙ X - ̿⊙ a + - ̎⊘ 2 + - ̿⊙ X + ̿⊙ a diff --git a/tests/integration/tui/screenshots/test_task_states.filter-waiting-or-expired.html b/tests/integration/tui/screenshots/test_task_states.filter-waiting-or-expired.html index e97bf21bcd2..991f5dcbbb3 100644 --- a/tests/integration/tui/screenshots/test_task_states.filter-waiting-or-expired.html +++ b/tests/integration/tui/screenshots/test_task_states.filter-waiting-or-expired.html @@ -3,17 +3,17 @@ - ~cylc - test_task_states - paused 1■ 1■ 1■ 1■ 1■ - - ̿⊗ 1 - - ̿⊗ Y - - ◌ Y1 - ◌ c - - ̊○ 3 - - ̊○ X - ̊○ a - - ̊○ Y - - ̊○ Y1 - ̊○ c - ̊○ b + - ̿⊗ 1 + - ̿⊗ Y + - ◌ Y1 + ◌ c + - ̊○ 3 + - ̊○ X + ̊○ a + - ̊○ Y + - ̊○ Y1 + ̊○ c + ̊○ b diff --git a/tests/integration/tui/screenshots/test_task_states.unfiltered.html b/tests/integration/tui/screenshots/test_task_states.unfiltered.html index 5b6312dddc7..8dd4f63b86b 100644 --- a/tests/integration/tui/screenshots/test_task_states.unfiltered.html +++ b/tests/integration/tui/screenshots/test_task_states.unfiltered.html @@ -2,27 +2,27 @@ - ~cylc - test_task_states - paused 1■ 1■ 1■ 1■ 1■ - - ̿⊗ 1 - - ̿● X - ̿● a - - ̿⊗ Y - - ◌ Y1 - ◌ c - ̿⊗ b - - ̎⊘ 2 - - ̿⊙ X - ̿⊙ a - - ̎⊘ Y - - ̎⊘ Y1 - ̎⊘ c - ̎⊙ b - - ̊○ 3 - - ̊○ X - ̊○ a - - ̊○ Y - - ̊○ Y1 - ̊○ c - ̊○ b + - ̿⊗ 1 + - ̿● X + ̿● a + - ̿⊗ Y + - ◌ Y1 + ◌ c + ̿⊗ b + - ̎⊘ 2 + - ̿⊙ X + ̿⊙ a + - ̎⊘ Y + - ̎⊘ Y1 + ̎⊘ c + ̎⊙ b + - ̊○ 3 + - ̊○ X + ̊○ a + - ̊○ Y + - ̊○ Y1 + ̊○ c + ̊○ b diff --git a/tests/integration/tui/test_app.py b/tests/integration/tui/test_app.py index bc38ef52fdb..3e909a3370a 100644 --- a/tests/integration/tui/test_app.py +++ b/tests/integration/tui/test_app.py @@ -27,6 +27,7 @@ TASK_STATUS_SUBMITTED, TASK_STATUS_SUBMIT_FAILED, TASK_STATUS_SUCCEEDED, + TASK_STATUS_WAITING, ) from cylc.flow.workflow_status import StopMode @@ -430,3 +431,89 @@ async def test_restart_reconnect(one_conf, flow, scheduler, start, rakiura): '3-workflow-restarted', 'the restarted workflow should be expanded', ) + + +async def test_states(flow, scheduler, start, rakiura): + """It should dim no-flow tasks and display state summary in context menus. + """ + id_ = flow( + { + 'scheduling': { + 'graph': { + 'R1': 'a & b & c', + }, + }, + }, + name='one', + ) + from cylc.flow.scheduler import Scheduler + schd: Scheduler = scheduler(id_) + + async with start(schd): + a = schd.pool.get_task(IntegerPoint('1'), 'a') + b = schd.pool.get_task(IntegerPoint('1'), 'b') + c = schd.pool.get_task(IntegerPoint('1'), 'c') + assert a and b and c + + # set task flow numbers + assert a.flow_nums == {1} + b.flow_nums = {1,2} + c.flow_nums = {} + + # set task state + a.state_reset(TASK_STATUS_SUCCEEDED, is_held=True) + b.state_reset(TASK_STATUS_WAITING, is_queued=True) + c.state_reset(TASK_STATUS_WAITING, is_queued=False, is_runahead=True) + + # update data store + for task in (a, b, c): + schd.data_store_mgr.delta_task_state(task) + schd.data_store_mgr.delta_task_flow_nums(task) + await schd.update_data_structure() + + with rakiura(schd.tokens.id, size='80,15') as rk: + rk.compare_screenshot( + 'on-load', + 'the workflow should be expanded,' + ' no-flow task 1/c should be dimmed' + ) + + # workflow node + rk.user_input('down', 'enter') + rk.compare_screenshot( + 'workflow-context--paused', + 'the workflow should show as paused in the context menu', + ) + + # cycle: 1 + rk.user_input('q', 'down', 'enter') + rk.compare_screenshot( + 'cycle-context--waiting', + 'the cycle should show as waiting in the context menu' + + + ) + + # task:a + rk.user_input('q', 'down', 'enter') + rk.compare_screenshot( + 'task-context--succeeded+held', + 'the task should show as succeeded+held in the context menu,' + ' no flow numbers should be displayed', + ) + + # task:b + rk.user_input('q', 'down', 'enter') + rk.compare_screenshot( + 'task-context--waiting+queued', + 'the task should show as waiting+queued in the context menu,' + ' the flow numbers 1,2 should be displayed', + ) + + # task:c + rk.user_input('q', 'down', 'enter') + rk.compare_screenshot( + 'task-context--waiting+runahead', + 'the task should show as waiting+runahead in the context menu,' + ' the task should be marked as flows=None' + ) diff --git a/tests/integration/tui/test_mutations.py b/tests/integration/tui/test_mutations.py index b87622bca5f..4daa93e000e 100644 --- a/tests/integration/tui/test_mutations.py +++ b/tests/integration/tui/test_mutations.py @@ -253,7 +253,7 @@ async def test_set_mutation( rk.force_update() # select the "set" mutation - rk.user_input(*(('down',) * 6)) # 6th command down + rk.user_input(*(('down',) * 7)) # 7th command down rk.compare_screenshot( # take a screenshot to ensure we have focused on the mutation diff --git a/tests/integration/tui/test_show.py b/tests/integration/tui/test_show.py index 063fd4b8781..d4242d93f63 100644 --- a/tests/integration/tui/test_show.py +++ b/tests/integration/tui/test_show.py @@ -48,7 +48,7 @@ async def test_show(flow, scheduler, start, rakiura, monkeypatch): rk.user_input('down', 'down', 'enter') # select the "show" context option - rk.user_input(*(['down'] * 7), 'enter') + rk.user_input(*(['down'] * 8), 'enter') rk.compare_screenshot( 'success', 'the show output should be displayed', @@ -63,7 +63,7 @@ def cli_cmd_fail(*args, **kwargs): ) # select the "show" context option - rk.user_input('q', 'enter', *(['down'] * 7), 'enter') + rk.user_input('q', 'enter', *(['down'] * 8), 'enter') rk.compare_screenshot( 'fail', 'the error should be displayed', diff --git a/tests/unit/tui/test_overlay.py b/tests/unit/tui/test_overlay.py index 013e8480c21..5f5d77e6d4a 100644 --- a/tests/unit/tui/test_overlay.py +++ b/tests/unit/tui/test_overlay.py @@ -62,7 +62,8 @@ def test_interface(overlay_functions): 'id_': '~u/a', 'type_': 'workflow', 'data': { - 'status': WorkflowStatus.RUNNING, + 'status': + WorkflowStatus.RUNNING.value, }, } ) diff --git a/tests/unit/tui/test_util.py b/tests/unit/tui/test_util.py index 2b3231e0f7e..9cdac6d6035 100644 --- a/tests/unit/tui/test_util.py +++ b/tests/unit/tui/test_util.py @@ -36,7 +36,7 @@ ) -def testrender_node__job_info(): +def test_render_node__job_info(): """It renders job information nodes.""" assert render_node( None, @@ -48,7 +48,7 @@ def testrender_node__job_info(): ] -def testrender_node__job(): +def test_render_node__job(): """It renders job nodes.""" assert render_node( None, @@ -60,7 +60,7 @@ def testrender_node__job(): ] -def testrender_node__task__succeeded(): +def test_render_node__task__succeeded(): """It renders tasks.""" node = Mock() node.get_child_node = lambda _: None @@ -71,17 +71,18 @@ def testrender_node__task__succeeded(): 'state': 'succeeded', 'isHeld': False, 'isQueued': False, - 'isRunahead': False + 'isRunahead': False, + 'flowNums': '[1]', }, 'task' ) == [ - TASK_ICONS['succeeded'], + ('body', TASK_ICONS['succeeded']), ' ', - 'foo' + ('body', 'foo'), ] -def testrender_node__task__running(): +def test_render_node__task__running(): """It renders running tasks.""" child = Mock() child.get_value = lambda: {'data': { @@ -98,19 +99,20 @@ def testrender_node__task__running(): 'isHeld': False, 'isQueued': False, 'isRunahead': False, + 'flowNums': '[1]', 'task': {'meanElapsedTime': 100} }, 'task' ) == [ - TASK_ICONS['running'], + ('body', TASK_ICONS['running']), ' ', ('job_running', JOB_ICON), ' ', - 'foo' + ('body', 'foo'), ] -def testrender_node__family(): +def test_render_node__family(): """It renders families.""" assert render_node( None, @@ -123,13 +125,13 @@ def testrender_node__family(): }, 'family' ) == [ - [TASK_ICONS['succeeded']], + [('body', TASK_ICONS['succeeded'])], ' ', 'myid' ] -def testrender_node__cycle_point(): +def test_render_node__cycle_point(): """It renders cycle points.""" assert render_node( None, @@ -172,12 +174,18 @@ def test_get_task_icon( datetime.utcnow() - timedelta(seconds=start_offset) ) assert ( - get_task_icon( - status, is_held=is_held, is_queued=is_queued, - is_runahead=is_runahead, start_time=start_time, - mean_time=mean_time + ( + get_task_icon( + status, + is_held=is_held, + is_queued=is_queued, + is_runahead=is_runahead, + colour='custom', + start_time=start_time, + mean_time=mean_time, + ) ) - ) == expected + ) == [('custom', char) for char in expected] def test_compute_tree():