From 2d3f25e57fe5010222b67ccde9a7676878209a11 Mon Sep 17 00:00:00 2001
From: Ronnie Dutta <61982285+MetRonnie@users.noreply.github.com>
Date: Mon, 6 Oct 2025 14:56:40 +0100
Subject: [PATCH 01/10] Fix hit area of task/job icons
---
src/components/cylc/table/Table.vue | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/src/components/cylc/table/Table.vue b/src/components/cylc/table/Table.vue
index 3f66c3ff1..87df61e4a 100644
--- a/src/components/cylc/table/Table.vue
+++ b/src/components/cylc/table/Table.vue
@@ -33,14 +33,14 @@ along with this program. If not, see .
:class="{ 'flow-none': isFlowNone(item.task.node.flowNums) }"
:data-cy-task-name="item.task.name"
>
-
+
-
+
.
>
-
+
- #{{ job.node.submitNum }}
+ #{{ job.node.submitNum }}
|
{{ job.node.platform }} |
@@ -288,6 +288,11 @@ const taskRunTimes = computed(() => new Map(
])
))
+const jobIconParentProps = {
+ class: ['d-flex', 'align-center'],
+ style: { width: '2em' },
+}
+
const itemsPerPageOptions = [
{ value: 10, title: '10' },
{ value: 20, title: '20' },
From ddbbb1abf9559bcbbdfb3327b0753d7a4a29c0bb Mon Sep 17 00:00:00 2001
From: Ronnie Dutta <61982285+MetRonnie@users.noreply.github.com>
Date: Mon, 6 Oct 2025 15:00:05 +0100
Subject: [PATCH 02/10] Replace task state icons with badges in sidebar
---
src/components/cylc/TaskStateBadge.vue | 45 ++++++
src/components/cylc/WarningIcon.vue | 4 +-
src/components/cylc/tree/GScanTreeItem.vue | 57 ++-----
src/components/cylc/workspace/Toolbar.vue | 2 +-
src/styles/cylc/_job.scss | 172 ++++++++-------------
tests/e2e/specs/userprofile.cy.js | 16 +-
6 files changed, 137 insertions(+), 159 deletions(-)
create mode 100644 src/components/cylc/TaskStateBadge.vue
diff --git a/src/components/cylc/TaskStateBadge.vue b/src/components/cylc/TaskStateBadge.vue
new file mode 100644
index 000000000..d5efc3fda
--- /dev/null
+++ b/src/components/cylc/TaskStateBadge.vue
@@ -0,0 +1,45 @@
+
+
+
+
+ {{ value > 99 ? '99+' : value }}
+
+
+
+
diff --git a/src/components/cylc/WarningIcon.vue b/src/components/cylc/WarningIcon.vue
index 51eeeb6f3..ef06b6013 100644
--- a/src/components/cylc/WarningIcon.vue
+++ b/src/components/cylc/WarningIcon.vue
@@ -26,9 +26,8 @@ along with this program. If not, see
.
.
@click="deactivate"
@click.prevent
style="
- vertical-align: middle;
cursor: pointer;
"
:style="[workflow.node.logRecords?.length ? {opacity: 1} : {opacity: 0.3}]"
diff --git a/src/components/cylc/tree/GScanTreeItem.vue b/src/components/cylc/tree/GScanTreeItem.vue
index eca4b386a..f76f09612 100644
--- a/src/components/cylc/tree/GScanTreeItem.vue
+++ b/src/components/cylc/tree/GScanTreeItem.vue
@@ -47,37 +47,22 @@ along with this program. If not, see .
-
-
-
-
-
-
-
-
-
-
- {{ descendantTaskInfo.stateTotals[state] ?? 0 }} {{ state }}. Recent {{ state }} tasks:
-
-
- {{ task }}
-
-
-
+
+
+
+
@@ -95,7 +80,7 @@ along with this program. If not, see
.
diff --git a/src/components/cylc/tree/GScanTreeItem.vue b/src/components/cylc/tree/GScanTreeItem.vue
index e2112828b..1acd495bd 100644
--- a/src/components/cylc/tree/GScanTreeItem.vue
+++ b/src/components/cylc/tree/GScanTreeItem.vue
@@ -18,7 +18,7 @@ along with this program. If not, see
.
@@ -47,16 +47,12 @@ along with this program. If not, see .
-
-
-
+
.
-
diff --git a/src/services/mock/json/workflows/one.json b/src/services/mock/json/workflows/one.json
index 49273f25a..784b2ac56 100644
--- a/src/services/mock/json/workflows/one.json
+++ b/src/services/mock/json/workflows/one.json
@@ -23,14 +23,14 @@
"latestStateTasks": {
"submitted": [],
"running": [
- "checkpoint"
+ "20000102T0000Z/checkpoint"
],
"succeeded": [
- "eventually_succeeded",
- "succeeded"
+ "20000102T0000Z/eventually_succeeded",
+ "20000102T0000Z/succeeded"
],
"failed": [
- "failed"
+ "20000102T0000Z/failed"
]
}
},
diff --git a/tests/unit/components/cylc/tree/treeitem.vue.spec.js b/tests/unit/components/cylc/tree/treeitem.vue.spec.js
index 168f94277..3a3c0cf70 100644
--- a/tests/unit/components/cylc/tree/treeitem.vue.spec.js
+++ b/tests/unit/components/cylc/tree/treeitem.vue.spec.js
@@ -152,12 +152,12 @@ describe('GScanTreeItem', () => {
}
})
it('combines all descendant tasks', () => {
- expect(wrapper.vm.descendantTaskInfo.latestTasks.submitted.length).to.equal(10)
- expect(wrapper.vm.descendantTaskInfo.latestTasks.running.length).to.equal(10)
+ expect(wrapper.vm.statesInfo.latestTasks.submitted.length).to.equal(10)
+ expect(wrapper.vm.statesInfo.latestTasks.running.length).to.equal(10)
})
it('combines all descendant task totals', () => {
- expect(wrapper.vm.descendantTaskInfo.stateTotals.submitted).to.equal(5)
- expect(wrapper.vm.descendantTaskInfo.stateTotals.running).to.equal(12)
+ expect(wrapper.vm.statesInfo.stateTotals.submitted).to.equal(5)
+ expect(wrapper.vm.statesInfo.stateTotals.running).to.equal(12)
})
it('collapses to the lowest only-child', () => {
expect(wrapper.vm.node.id).to.equal('~cylc/double/mid')
From 266038f5ea41519090e7b32a338934975a188dab Mon Sep 17 00:00:00 2001
From: Ronnie Dutta <61982285+MetRonnie@users.noreply.github.com>
Date: Wed, 5 Nov 2025 17:37:28 +0000
Subject: [PATCH 08/10] Include preparing tasks in submitted task state badge
total
---
src/components/cylc/TaskStateBadge.vue | 10 ++++++++--
src/components/cylc/tree/GScanTreeItem.vue | 10 +++++++---
tests/unit/components/cylc/tree/treeitem.vue.spec.js | 2 +-
3 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/src/components/cylc/TaskStateBadge.vue b/src/components/cylc/TaskStateBadge.vue
index 8aadc322e..2283b0357 100644
--- a/src/components/cylc/TaskStateBadge.vue
+++ b/src/components/cylc/TaskStateBadge.vue
@@ -25,7 +25,7 @@
location="top"
:open-delay="400"
>
- {{ value }} {{ state }} task{{ value > 1 ? 's': '' }}.
+ {{ value }} {{ displayName }} task{{ value > 1 ? 's': '' }}.
Latest:
diff --git a/src/components/cylc/tree/GScanTreeItem.vue b/src/components/cylc/tree/GScanTreeItem.vue
index 1acd495bd..a865faf77 100644
--- a/src/components/cylc/tree/GScanTreeItem.vue
+++ b/src/components/cylc/tree/GScanTreeItem.vue
@@ -117,12 +117,16 @@ function getStatesInfo (node, stateTotals = {}, latestTasks = {}) {
// the non-zero state totals from this node with all the others from the tree
for (const state of taskStatesOrdered) {
- const nodeTotal = node.node.stateTotals[state]
+ let nodeTotal = node.node.stateTotals[state]
+ const nodeLatestTasks = Array.from(node.node.latestStateTasks?.[state] ?? [])
+ if (state === TaskState.SUBMITTED.name) { // include preparing tasks
+ nodeTotal += node.node.stateTotals.preparing
+ nodeLatestTasks.push(...(node.node.latestStateTasks?.preparing ?? []))
+ }
if (nodeTotal) {
stateTotals[state] = (stateTotals[state] ?? 0) + nodeTotal
}
- const nodeLatestTasks = node.node.latestStateTasks?.[state]
- if (nodeLatestTasks?.length) {
+ if (nodeLatestTasks.length) {
latestTasks[state] = [
...(latestTasks[state] ?? []),
...nodeLatestTasks,
diff --git a/tests/unit/components/cylc/tree/treeitem.vue.spec.js b/tests/unit/components/cylc/tree/treeitem.vue.spec.js
index 3a3c0cf70..4e82c7249 100644
--- a/tests/unit/components/cylc/tree/treeitem.vue.spec.js
+++ b/tests/unit/components/cylc/tree/treeitem.vue.spec.js
@@ -152,7 +152,7 @@ describe('GScanTreeItem', () => {
}
})
it('combines all descendant tasks', () => {
- expect(wrapper.vm.statesInfo.latestTasks.submitted.length).to.equal(10)
+ expect(wrapper.vm.statesInfo.latestTasks.submitted.length).to.equal(20)
expect(wrapper.vm.statesInfo.latestTasks.running.length).to.equal(10)
})
it('combines all descendant task totals', () => {
From 8f947c84a889548b0df4bd41fecdb7e4a827784a Mon Sep 17 00:00:00 2001
From: Ronnie Dutta <61982285+MetRonnie@users.noreply.github.com>
Date: Thu, 6 Nov 2025 13:24:52 +0000
Subject: [PATCH 09/10] Tweak task state badge border thickness
---
src/styles/cylc/_job.scss | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/styles/cylc/_job.scss b/src/styles/cylc/_job.scss
index a0d286fbb..7c653f05b 100644
--- a/src/styles/cylc/_job.scss
+++ b/src/styles/cylc/_job.scss
@@ -34,10 +34,11 @@ $cjob: ".c-job .job rect";
.task-state-badge {
font-size: 0.7em;
- height: 1.8em;
- min-width: 1.8em;
- border-radius: 1.8em;
- border: 2px solid;
+ $height: 1.8em;
+ height: $height;
+ min-width: $height;
+ border-radius: $height;
+ border: 0.2em solid;
margin: 0 0.1em;
line-height: normal;
}
From 6cd68ef90554f38947205398eb177da90f62143e Mon Sep 17 00:00:00 2001
From: Ronnie Dutta <61982285+MetRonnie@users.noreply.github.com>
Date: Wed, 12 Nov 2025 12:17:40 +0000
Subject: [PATCH 10/10] Only show latest state tasks for workflows, not
workflow dirs/groups
We cannot show the true latest tasks for groups, and it is unclear what workflow each task belongs to
---
src/components/cylc/TaskStateBadge.vue | 10 +++-------
src/components/cylc/tree/GScanTreeItem.vue | 18 ++++++++++--------
.../components/cylc/tree/treeitem.vue.spec.js | 5 ++---
3 files changed, 15 insertions(+), 18 deletions(-)
diff --git a/src/components/cylc/TaskStateBadge.vue b/src/components/cylc/TaskStateBadge.vue
index 2283b0357..d8e62c380 100644
--- a/src/components/cylc/TaskStateBadge.vue
+++ b/src/components/cylc/TaskStateBadge.vue
@@ -26,11 +26,11 @@
:open-delay="400"
>
{{ value }} {{ displayName }} task{{ value > 1 ? 's': '' }}.
-
+
Latest:
{{ task }}
@@ -56,10 +56,6 @@ const props = defineProps({
type: Array,
default: () => [],
},
- maxLatestTasks: {
- type: Number,
- default: 5,
- },
})
const displayName = computed(
diff --git a/src/components/cylc/tree/GScanTreeItem.vue b/src/components/cylc/tree/GScanTreeItem.vue
index a865faf77..5a75ae078 100644
--- a/src/components/cylc/tree/GScanTreeItem.vue
+++ b/src/components/cylc/tree/GScanTreeItem.vue
@@ -99,11 +99,13 @@ const taskStatesOrdered = [
/**
* Get aggregated task state totals for all descendents of a node.
*
+ * Also get latest state tasks for workflow nodes.
+ *
* @param {Object} node
* @param {Record} stateTotals - Accumulator for state totals.
- * @param {Record} latestTasks - Accumulator for latest tasks.
*/
-function getStatesInfo (node, stateTotals = {}, latestTasks = {}) {
+function getStatesInfo (node, stateTotals = {}) {
+ const latestTasks = {}
// if we aren't at the end of the node tree, continue recurse until we hit something other then a workflow part
if (node.type === 'workflow-part' && node.children) {
// at every branch, recurse all child nodes except stopped workflows
@@ -118,19 +120,19 @@ function getStatesInfo (node, stateTotals = {}, latestTasks = {}) {
// the non-zero state totals from this node with all the others from the tree
for (const state of taskStatesOrdered) {
let nodeTotal = node.node.stateTotals[state]
- const nodeLatestTasks = Array.from(node.node.latestStateTasks?.[state] ?? [])
+ let nodeLatestTasks = node.node.latestStateTasks?.[state] ?? []
if (state === TaskState.SUBMITTED.name) { // include preparing tasks
nodeTotal += node.node.stateTotals.preparing
- nodeLatestTasks.push(...(node.node.latestStateTasks?.preparing ?? []))
+ nodeLatestTasks = [
+ ...nodeLatestTasks,
+ ...(node.node.latestStateTasks?.preparing ?? []),
+ ].slice(0, 5) // limit to 5 latest (submitted tasks take priority)
}
if (nodeTotal) {
stateTotals[state] = (stateTotals[state] ?? 0) + nodeTotal
}
if (nodeLatestTasks.length) {
- latestTasks[state] = [
- ...(latestTasks[state] ?? []),
- ...nodeLatestTasks,
- ].sort().reverse() // cycle point descending order
+ latestTasks[state] = nodeLatestTasks
}
}
}
diff --git a/tests/unit/components/cylc/tree/treeitem.vue.spec.js b/tests/unit/components/cylc/tree/treeitem.vue.spec.js
index 4e82c7249..b7ca95c48 100644
--- a/tests/unit/components/cylc/tree/treeitem.vue.spec.js
+++ b/tests/unit/components/cylc/tree/treeitem.vue.spec.js
@@ -151,9 +151,8 @@ describe('GScanTreeItem', () => {
filteredOutNodesCache: new WeakMap(),
}
})
- it('combines all descendant tasks', () => {
- expect(wrapper.vm.statesInfo.latestTasks.submitted.length).to.equal(20)
- expect(wrapper.vm.statesInfo.latestTasks.running.length).to.equal(10)
+ it('does not combine descendant latest state tasks', () => {
+ expect(wrapper.vm.statesInfo.latestTasks).to.deep.equal({})
})
it('combines all descendant task totals', () => {
expect(wrapper.vm.statesInfo.stateTotals.submitted).to.equal(5)