Skip to content

Commit 9ff12c7

Browse files
authored
Add a job details menu to the log view (#2265)
* Move job details to its own table component * Add job info menu to log view * Fix tree item line-height regression * Simplify presentation of non-custom-output messages in tree view job leaf table
1 parent eb46e02 commit 9ff12c7

File tree

14 files changed

+316
-202
lines changed

14 files changed

+316
-202
lines changed

changes.d/2265.feat.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improved the legibility of job details in the tree view and added a job details menu to the log view.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<!--
2+
Copyright (C) NIWA & British Crown (Met Office) & Contributors.
3+
4+
This program is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
-->
17+
18+
<template>
19+
<v-table data-cy="job-details">
20+
<thead v-if="$slots.header">
21+
<tr>
22+
<th colspan="2">
23+
<slot name="header"></slot>
24+
</th>
25+
</tr>
26+
</thead>
27+
<tbody>
28+
<tr>
29+
<td>State</td>
30+
<td>{{ node.state }}</td>
31+
</tr>
32+
<tr>
33+
<td>Platform</td>
34+
<td>{{ node.platform }}</td>
35+
</tr>
36+
<tr>
37+
<td>Job ID</td>
38+
<td>{{ node.jobId }}</td>
39+
</tr>
40+
<tr>
41+
<td>Job runner</td>
42+
<td>{{ node.jobRunnerName }}</td>
43+
</tr>
44+
<tr>
45+
<td>Submitted time</td>
46+
<td>{{ node.submittedTime }}</td>
47+
</tr>
48+
<tr>
49+
<td>Started time</td>
50+
<td>{{ node.startedTime }}</td>
51+
</tr>
52+
<tr>
53+
<td>Finished time</td>
54+
<td>{{ node.finishedTime }}</td>
55+
</tr>
56+
<tr v-if="meanElapsedTime">
57+
<td>Mean run time</td>
58+
<td>{{ formatDuration(meanElapsedTime) }}</td>
59+
</tr>
60+
</tbody>
61+
</v-table>
62+
</template>
63+
64+
<script setup>
65+
import { formatDuration } from '@/utils/tasks'
66+
67+
defineProps({
68+
node: {
69+
type: Object,
70+
required: true,
71+
},
72+
meanElapsedTime: {
73+
type: Number,
74+
},
75+
})
76+
</script>
77+
78+
<style scoped>
79+
table td:first-of-type {
80+
font-weight: 500;
81+
cursor: default;
82+
}
83+
</style>

src/components/cylc/tree/JobDetails.vue

Lines changed: 0 additions & 131 deletions
This file was deleted.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<!--
2+
Copyright (C) NIWA & British Crown (Met Office) & Contributors.
3+
4+
This program is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
-->
17+
18+
<template>
19+
<div
20+
:id="`${node.id}-job-details`"
21+
class="node leaf job-details mb-2"
22+
>
23+
<div class="arrow-up" :style="leafTriangleStyle"></div>
24+
<div class="leaf-data pa-2 rounded-lg">
25+
<v-defaults-provider :defaults="defaults">
26+
<JobDetailsTable
27+
:node="node.node"
28+
:mean-elapsed-time="meanElapsedTime"
29+
class="bg-transparent"
30+
/>
31+
<v-table
32+
v-if="customOutputs?.length"
33+
class="outputs mt-2 bg-white"
34+
>
35+
<thead>
36+
<tr>
37+
<th>Custom output</th>
38+
<th>Message</th>
39+
</tr>
40+
</thead>
41+
<tbody>
42+
<tr
43+
v-for="customOutput of customOutputs"
44+
:key="customOutput.label"
45+
>
46+
<td>{{ customOutput.isMessage ? '--' : customOutput.label }}</td>
47+
<td>{{ customOutput.message }}</td>
48+
</tr>
49+
</tbody>
50+
</v-table>
51+
</v-defaults-provider>
52+
</div>
53+
</div>
54+
</template>
55+
56+
<script setup>
57+
import { computed } from 'vue'
58+
import { getIndent } from '@/components/cylc/tree/util'
59+
import { jobMessageOutputs } from '@/utils/tasks'
60+
import JobDetailsTable from '@/components/cylc/common/JobDetails.vue'
61+
62+
const props = defineProps({
63+
node: {
64+
type: Object,
65+
required: true,
66+
},
67+
/** Indent level */
68+
depth: {
69+
type: Number,
70+
required: true,
71+
},
72+
meanElapsedTime: {
73+
type: Number,
74+
},
75+
density: {
76+
type: String,
77+
default: 'compact'
78+
}
79+
})
80+
81+
/** Make the job details triangle point to the job icon */
82+
const leafTriangleStyle = computed(() => ({
83+
'margin-left': getIndent(props.depth),
84+
}))
85+
86+
const defaults = computed(() => ({
87+
VTable: {
88+
density: props.density,
89+
hover: true,
90+
}
91+
}))
92+
93+
const customOutputs = computed(() => jobMessageOutputs(props.node))
94+
</script>

src/components/cylc/tree/TreeItem.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
121121
:key="`${customOutput.label}-${index}`"
122122
:class="customOutput.isMessage ? 'bg-light-grey text-black' : 'bg-grey text-white'"
123123
class="message-output"
124+
v-tooltip="customOutput.isMessage ? `Task message: ${customOutput.message}` : customOutput.message"
124125
>
125-
{{ customOutput.label }}
126-
<v-tooltip :text="customOutput.message"/>
126+
{{ customOutput.isMessage ? customOutput.message : customOutput.label }}
127127
</v-chip>
128128
<v-chip
129129
v-if="jobMessageOutputs.length > 5"
@@ -148,7 +148,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
148148
<slot name="child">
149149
<!-- Need v-if to prevent render of fallback content when slot is provided but is empty -->
150150
<template v-if="!$slots.child">
151-
<JobDetails
151+
<JobLeaf
152152
v-if="node.type === 'job'"
153153
v-bind="{ node, meanElapsedTime }"
154154
:depth="depth + 1"
@@ -175,7 +175,7 @@ import {
175175
} from '@mdi/js'
176176
import Task from '@/components/cylc/Task.vue'
177177
import Job from '@/components/cylc/Job.vue'
178-
import JobDetails from '@/components/cylc/tree/JobDetails.vue'
178+
import JobLeaf from '@/components/cylc/tree/JobLeaf.vue'
179179
import {
180180
jobMessageOutputs,
181181
latestJob,
@@ -193,7 +193,7 @@ export default {
193193
FlowNumsChip,
194194
Task,
195195
Job,
196-
JobDetails,
196+
JobLeaf,
197197
},
198198
199199
props: {

src/services/mock/json/index.cjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const taskProxy = require('./taskProxy.json')
2020
const familyProxy = require('./familyProxy.json')
2121
const { one, workflows, Workflow } = require('./workflows/index.cjs')
2222
const { LogData } = require('./logData.cjs')
23-
const { LogFiles, JobState } = require('./logFiles.cjs')
23+
const { LogFiles, Jobs } = require('./logFiles.cjs')
2424
const analysisQuery = require('./analysisQuery.json')
2525
const ganttQuery = require('./ganttQuery.json')
2626
const InfoViewSubscription = require('./infoView.json')
@@ -31,7 +31,7 @@ module.exports = {
3131
familyProxy,
3232
LogData,
3333
LogFiles,
34-
JobState,
34+
Jobs,
3535
App: workflows,
3636
Workflow,
3737
GraphIQLTest: one,

src/services/mock/json/logFiles.cjs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const LogFiles = async ({ id }) => {
5555
*
5656
* @param {{ id: string }} variables
5757
*/
58-
const JobState = async ({ id, workflowId }) => {
58+
const Jobs = async ({ id, workflowId }) => {
5959
if (!workflowId.startsWith('~')) {
6060
workflowId = `~user/${workflowId}`
6161
}
@@ -65,17 +65,17 @@ const JobState = async ({ id, workflowId }) => {
6565
).replace(
6666
/\/(\d+)$/, (match, p1) => `/${parseInt(p1)}` // strips leading zeroes
6767
)
68-
const { state } = deltas?.added?.jobs?.find((job) => job.id.includes(searchID)) ?? {}
68+
const node = deltas?.added?.jobs?.find((job) => job.id.includes(searchID)) ?? {}
6969
await simulatedDelay(500)
7070
return {
7171
data: {
72-
jobs: state ? [{ id, state }] : []
72+
jobs: node.state ? [{ id, ...node }] : []
7373
}
7474
}
7575
}
7676

7777
module.exports = {
78-
JobState,
78+
Jobs,
7979
LogFiles,
8080
deletedFile,
8181
jobLogFiles,

0 commit comments

Comments
 (0)