Skip to content

Commit 1cb0769

Browse files
SimpleTree: a simple view a functional documentation
* A new bare-bones live tree view not available in production mode. * Indended to serve as documentation and a guide for future view development.
1 parent e39a121 commit 1cb0769

File tree

3 files changed

+262
-5
lines changed

3 files changed

+262
-5
lines changed

src/store/workflows.module.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -519,7 +519,7 @@ const mutations = {
519519
UPDATE: update,
520520
UPDATE_DELTAS (state, updated) {
521521
// eslint-disable-next-line no-console
522-
console.log('@ UPDATE')
522+
// console.log('@ UPDATE')
523523
for (const updatedValue of Object.values(pick(updated, KEYS))) {
524524
const items = isArray(updatedValue) ? updatedValue : [updatedValue]
525525
for (const updatedData of items) {
@@ -529,7 +529,7 @@ const mutations = {
529529
}
530530
}
531531
// eslint-disable-next-line no-console
532-
console.log('@@')
532+
// console.log('@@')
533533
},
534534
// remove an ID
535535
REMOVE: remove,

src/views/SimpleTree.vue

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
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+
<!--
19+
This is a bare-bones text-based tree view that displays live workflow data.
20+
21+
It is intended to serve as a basis for future live-view development and to
22+
serve as functional documentation for view writing.
23+
24+
NOTE:
25+
This view is not available in "production" mode.
26+
-->
27+
28+
<template>
29+
<div class="c-simple-tree">
30+
<!-- Iterate over the root nodes. -->
31+
<ul
32+
v-for="node of workflows"
33+
:key="node.id"
34+
>
35+
<li>
36+
<b>{{ node.id }}</b>
37+
<!-- Then iterate over the children of those nodes.
38+
39+
NOTE:
40+
"node.children" is always present on a node so you shouldn't have to
41+
do "node.children || []" here.
42+
NOTE:
43+
"node.id" is a good choice for the ":key" as every node in the store
44+
has a unique ID.
45+
-->
46+
<ul
47+
v-for="node1 of node.children"
48+
:key="node1.id"
49+
>
50+
<li>
51+
<!-- "node.name" is always provided for all nodes. Use this NOT
52+
node.node.name to save requesting unnecessary data -->
53+
<span class="name">{{ node1.name }}</span>
54+
<!-- Attributes requested in the QUERY will be available in
55+
"node.node".
56+
57+
NOTE:
58+
The data store promises to make this information available but
59+
doesn't make any promises about when it will make this available.
60+
Just because a node exists in the store doesn't mean it will have
61+
all of the data you requested, yet. Code defensibly in
62+
anticipation of "undefined" keys.
63+
-->
64+
<span class="state">{{ node1.node.state }}</span>
65+
<!-- Then keep iterating down the tree.
66+
67+
NOTE:
68+
We would normally use a recursive component to do this as we
69+
don't know how deep the tree is going to be, however, to keep
70+
this simple we will just hardcode it.
71+
-->
72+
<ul
73+
v-for="node2 of node1.children"
74+
:key="node2.id"
75+
>
76+
<li>
77+
<span class="name">{{ node2.name }}</span>
78+
<span class="state">{{ node2.node.state }}</span>
79+
<ul
80+
v-for="node3 of node2.children"
81+
:key="node3.id"
82+
>
83+
<li>
84+
<span class="name">{{ node3.name }}</span>
85+
<span class="state">{{ node3.node.state }}</span>
86+
<ul
87+
v-for="node4 of node3.children"
88+
:key="node4.id"
89+
>
90+
<li>
91+
<span class="name">{{ node4.name }}</span>
92+
<span class="state">{{ node4.node.state }}</span>
93+
</li>
94+
</ul>
95+
</li>
96+
</ul>
97+
</li>
98+
</ul>
99+
</li>
100+
</ul>
101+
</li>
102+
</ul>
103+
</div>
104+
</template>
105+
106+
<script>
107+
import gql from 'graphql-tag'
108+
import { mapState, mapGetters } from 'vuex'
109+
import pageMixin from '@/mixins/index'
110+
import graphqlMixin from '@/mixins/graphql'
111+
import subscriptionViewMixin from '@/mixins/subscriptionView'
112+
import subscriptionComponentMixin from '@/mixins/subscriptionComponent'
113+
import SubscriptionQuery from '@/model/SubscriptionQuery.model'
114+
import { mdiTree } from '@mdi/js'
115+
116+
// Any fields that our view will use (e.g. TaskProxy.status) must be requested
117+
// in the query.
118+
// Most of this is just boilerplate the important thing is the three declarations
119+
// at the end.
120+
const QUERY = gql`
121+
subscription SimpleTreeSubscription ($workflowId: ID) {
122+
deltas(workflows: [$workflowId]) {
123+
...Deltas
124+
}
125+
}
126+
127+
fragment Deltas on Deltas {
128+
added {
129+
...AddedDelta
130+
}
131+
updated (stripNull: true) {
132+
...UpdatedDelta
133+
}
134+
pruned {
135+
...PrunedDelta
136+
}
137+
}
138+
139+
fragment AddedDelta on Added {
140+
taskProxies {
141+
...TaskProxyData
142+
}
143+
jobs {
144+
...JobData
145+
}
146+
}
147+
148+
fragment UpdatedDelta on Updated {
149+
taskProxies {
150+
...TaskProxyData
151+
}
152+
jobs {
153+
...JobData
154+
}
155+
}
156+
157+
# We must list all of the types we request data for here to enable automatic
158+
# hosekeeping.
159+
fragment PrunedDelta on Pruned {
160+
workflow
161+
taskProxies
162+
jobs
163+
}
164+
165+
# We must always request the "id" for ALL types.
166+
# The only field this view requires beyond that is the status.
167+
fragment TaskProxyData on TaskProxy {
168+
id
169+
state
170+
}
171+
172+
# Same for jobs.
173+
fragment JobData on Job {
174+
id
175+
state
176+
}
177+
`
178+
179+
export default {
180+
// These mixins enable various functionalities.
181+
mixins: [
182+
pageMixin,
183+
graphqlMixin,
184+
subscriptionComponentMixin,
185+
subscriptionViewMixin
186+
],
187+
188+
// This defines the component name, must be HTML safe.
189+
name: 'SimpleTree',
190+
191+
// This sets the page title.
192+
metaInfo () {
193+
return {
194+
title: this.getPageTitle('App.workflow', { name: this.workflowName })
195+
}
196+
},
197+
198+
// The view must provide a title and icon for display purposes.
199+
data () {
200+
return {
201+
widget: {
202+
title: 'simple tree',
203+
icon: mdiTree
204+
}
205+
}
206+
},
207+
208+
computed: {
209+
// This gives us direct access to the data store if we need it:
210+
...mapState('workflows', ['cylcTree']),
211+
212+
// This gives us a convenient way to filter for the nodes we want from the
213+
// store:
214+
...mapGetters('workflows', ['getNodes']),
215+
216+
// List of workflow IDs we are displaying.
217+
// NOTE: Write all views to be multi-workflow capable.
218+
// NOTE: workflowId is provided by a mixin.
219+
workflowIDs () {
220+
return [this.workflowId]
221+
},
222+
223+
// Get workflow nodes from the store.
224+
workflows () {
225+
// This returns all nodes of type "workflow" with ids which are in
226+
// this.workflowIDs
227+
return this.getNodes('workflow', this.workflowIDs)
228+
},
229+
230+
// This registers the query with the WorkflowService, once registered, the
231+
// WorkflowService promises to make the data defined by the query available
232+
// in the store and to keep it up to date.
233+
query () {
234+
return new SubscriptionQuery(QUERY, this.variables, 'workflow', [])
235+
}
236+
}
237+
238+
}
239+
</script>
240+
241+
<style lang="scss">
242+
.c-simple-tree {
243+
.state:before {
244+
content: ' ';
245+
}
246+
.state {
247+
color: grey;
248+
}
249+
}
250+
</style>

src/views/Workflow.vue

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,16 +97,23 @@ export default {
9797
TreeView,
9898
TableView,
9999
GraphView
100-
]
100+
],
101+
// environment e.g. 'PRODUCTION'
102+
environment: process.env.VUE_APP_SERVICES === 'offline' ? 'OFFLINE' : process.env.NODE_ENV.toUpperCase()
101103
}),
102104
created () {
103105
// We need to load each view used by this view/component.
104106
// See "local-registration" in Vue.js documentation.
105107
this.views.forEach(view => {
106108
this.$options.components[view.name] = view
107109
})
108-
},
109-
computed: {
110+
111+
if (this.environment !== 'PRODUCTION') {
112+
// dynamically load development views that we don't want in production
113+
import('@/views/SimpleTree').then((SimpleTreeView) => {
114+
this.views.push(SimpleTreeView.default)
115+
})
116+
}
110117
},
111118
beforeRouteEnter (to, from, next) {
112119
next(vm => {

0 commit comments

Comments
 (0)