Skip to content

Commit 87e7fcd

Browse files
committed
Convert more stuff to TypeScript
1 parent 559ef09 commit 87e7fcd

File tree

7 files changed

+131
-93
lines changed

7 files changed

+131
-93
lines changed

src/components/cylc/SVGTask.vue

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -246,34 +246,35 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
246246
</g>
247247
</template>
248248

249-
<script setup>
249+
<script setup lang="ts">
250250
import { computed, inject, ref } from 'vue'
251251
import { TaskState } from '@/model/TaskState.model'
252+
import { animResetKey } from '@/utils/injectionKeys'
253+
254+
interface Props {
255+
task: any
256+
/**
257+
* The start time as an ISO8601 date-time string in expanded format
258+
* e.g. 2022-10-26T13:43:45Z
259+
*
260+
* TODO: aim to remove this in due course
261+
* (we should be able to obtain this directly from the task)
262+
*/
263+
startTime?: string
264+
/**
265+
* Scale the size of the task state modifier
266+
*/
267+
modifierSize?: number
268+
}
252269
253-
const props = defineProps({
254-
task: {
255-
required: true
256-
},
257-
startTime: {
258-
// The start time as an ISO8601 date-time string in expanded format
259-
// e.g. 2022-10-26T13:43:45Z
260-
// TODO: aim to remove this in due course
261-
// (we should be able to obtain this directly from the task)
262-
type: String,
263-
required: false
264-
},
265-
modifierSize: {
266-
// Scale the size of the task state modifier
267-
type: Number,
268-
default: 0.7
269-
},
270+
const props = withDefaults(defineProps<Props>(), {
271+
modifierSize: 0.7
270272
})
271273
272274
/**
273-
* @type {import('vue').Ref<number>}
274275
* @see @/components/cylc/workspace/Widget.vue
275276
*/
276-
const animResetTime = inject('animResetTime', () => ref(0), true)
277+
const animResetTime = inject(animResetKey, () => ref(0), true)
277278
278279
const runningStyle = computed(() => {
279280
if (

src/components/cylc/workspace/Lumino.vue

Lines changed: 37 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
2424
:id="id"
2525
>
2626
<component
27-
:is="props.allViews.get(name).component"
27+
:is="props.allViews.get(name)!.component"
2828
:workflow-name="workflowName"
29-
v-model:initial-options="views.get(id).initialOptions"
29+
v-model:initial-options="views.get(id)!.initialOptions"
3030
class="h-100"
3131
/>
3232
</WidgetComponent>
3333
</template>
3434

35-
<script setup>
35+
<script setup lang="ts">
3636
import {
3737
nextTick,
3838
onBeforeUnmount,
@@ -45,8 +45,14 @@ import WidgetComponent from '@/components/cylc/workspace/Widget.vue'
4545
import LuminoWidget from '@/components/cylc/workspace/lumino-widget'
4646
import { BoxPanel, DockPanel, Widget } from '@lumino/widgets'
4747
import { when } from '@/utils'
48-
import { useDefaultView } from '@/views/views'
49-
import { eventBus } from '@/services/eventBus'
48+
import {
49+
useDefaultView,
50+
type CylcView
51+
} from '@/views/views'
52+
import {
53+
eventBus,
54+
type AddViewEvent
55+
} from '@/services/eventBus'
5056
5157
/*
5258
* A component to wrap the Lumino application.
@@ -58,47 +64,25 @@ import { eventBus } from '@/services/eventBus'
5864
* works, but there could be alternative approaches too.
5965
*/
6066
61-
/**
62-
* Mitt event for adding a view to the workspace.
63-
* @typedef {Object} AddViewEvent
64-
* @property {string} name - the view to add
65-
* @property {Record<string,*>} initialOptions - prop passed to the view component
66-
*/
67-
6867
const $store = useStore()
6968
70-
const props = defineProps({
71-
workflowName: {
72-
type: String,
73-
required: true
74-
},
75-
/**
76-
* All possible view component classes that can be rendered
77-
*
78-
* @type {Map<string, import('@/views/views').CylcView>}
79-
*/
80-
allViews: {
81-
type: Map,
82-
required: true
83-
},
84-
})
69+
const props = defineProps<{
70+
workflowName: string
71+
/** All possible view component classes that can be rendered */
72+
allViews: Map<string, CylcView>
73+
}>()
8574
8675
const emit = defineEmits([
8776
'emptied'
8877
])
8978
90-
/**
91-
* Template ref
92-
* @type {import('vue').Ref<HTMLElement>}
93-
*/
94-
const mainDiv = ref(null)
79+
/** Template ref */
80+
const mainDiv = ref<HTMLElement>()
9581
9682
/**
9783
* Mapping of widget ID to the name of view component and its initialOptions prop.
98-
*
99-
* @type {import('vue').Ref<Map<string, AddViewEvent>>}
10084
*/
101-
const views = ref(new Map())
85+
const views = ref(new Map<string, AddViewEvent>())
10286
10387
const defaultView = useDefaultView()
10488
@@ -113,11 +97,14 @@ const resizeObserver = new ResizeObserver(() => {
11397
boxPanel.update()
11498
})
11599
116-
onMounted(() => {
100+
when(mainDiv, (div) => {
117101
// Attach box panel to DOM:
118-
Widget.attach(boxPanel, mainDiv.value)
102+
Widget.attach(boxPanel, div)
119103
// Watch for resize of the main element to trigger relayout:
120-
resizeObserver.observe(mainDiv.value)
104+
resizeObserver.observe(div)
105+
})
106+
107+
onMounted(() => {
121108
eventBus.on('add-view', addView)
122109
eventBus.on('lumino:deleted', onWidgetDeleted)
123110
getLayout(props.workflowName)
@@ -135,13 +122,13 @@ onBeforeUnmount(() => {
135122
136123
/**
137124
* Create a widget and add it to the dock.
138-
*
139-
* @param {AddViewEvent} event
140-
* @param {boolean} onTop
141125
*/
142-
const addView = ({ name, initialOptions = {} }, onTop = true) => {
126+
const addView = (
127+
{ name, initialOptions = {} }: AddViewEvent,
128+
onTop: boolean = true
129+
) => {
143130
const id = uniqueId('widget')
144-
const luminoWidget = new LuminoWidget(id, startCase(name), /* closable */ true)
131+
const luminoWidget = new LuminoWidget(id, startCase(name))
145132
dockPanel.addWidget(luminoWidget, { mode: 'tab-after' })
146133
// give time for Lumino's widget DOM element to be created
147134
nextTick(() => {
@@ -164,10 +151,8 @@ const closeAllViews = () => {
164151
/**
165152
* Get the saved layout (if there is one) for the given workflow,
166153
* else add the default view.
167-
*
168-
* @param {string} workflowName
169154
*/
170-
const getLayout = (workflowName) => {
155+
const getLayout = (workflowName: string) => {
171156
restoreLayout(workflowName) || addView({ name: defaultView.value })
172157
}
173158
@@ -185,10 +170,9 @@ const saveLayout = () => {
185170
/**
186171
* Restore the layout for this workflow from the store, if it was saved.
187172
*
188-
* @param {string} workflowName
189-
* @returns {boolean} true if the layout was restored, false otherwise
173+
* @returns true if the layout was restored, false otherwise
190174
*/
191-
const restoreLayout = (workflowName) => {
175+
const restoreLayout = (workflowName: string): boolean => {
192176
const stored = $store.state.app.workspaceLayouts.get(workflowName)
193177
if (stored) {
194178
dockPanel.restoreLayout(stored.layout)
@@ -205,9 +189,9 @@ const restoreLayout = (workflowName) => {
205189
/**
206190
* Save & close the current layout and open the one for the given workflow.
207191
*
208-
* @param {string} workflowName
192+
* @param workflowName
209193
*/
210-
const changeLayout = (workflowName) => {
194+
const changeLayout = (workflowName: string) => {
211195
saveLayout()
212196
closeAllViews()
213197
// Wait if necessary for the workflowName prop to be updated to the new value:
@@ -220,9 +204,9 @@ const changeLayout = (workflowName) => {
220204
/**
221205
* React to a deleted event.
222206
*
223-
* @param {string} id - widget ID
207+
* @param id - widget ID
224208
*/
225-
const onWidgetDeleted = (id) => {
209+
const onWidgetDeleted = (id: string) => {
226210
views.value.delete(id)
227211
if (!views.value.size) {
228212
emit('emptied')

src/components/cylc/workspace/Widget.vue

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
2424
</Teleport>
2525
</template>
2626

27-
<script setup>
27+
<script setup lang="ts">
2828
import { onBeforeUnmount, provide, readonly, ref } from 'vue'
2929
import { eventBus } from '@/services/eventBus'
30+
import { animResetKey } from '@/utils/injectionKeys'
3031
31-
const props = defineProps({
32-
id: {
33-
type: String,
34-
required: true,
35-
},
36-
})
32+
const props = defineProps<{
33+
id: string
34+
}>()
3735
3836
/**
3937
* Ref used to indicate to children that the widget has become unhidden, and
@@ -45,13 +43,17 @@ const props = defineProps({
4543
* @see https://stackoverflow.com/a/37671302/3217306
4644
*/
4745
const animResetTime = ref(Date.now())
48-
provide('animResetTime', readonly(animResetTime))
46+
provide(animResetKey, readonly(animResetTime))
4947
50-
eventBus.on(`lumino:show:${props.id}`, () => {
51-
animResetTime.value = Date.now()
52-
})
48+
function onWidgetShow (id: string) {
49+
if (id === props.id) {
50+
animResetTime.value = Date.now()
51+
}
52+
}
53+
54+
eventBus.on('lumino:show', onWidgetShow)
5355
5456
onBeforeUnmount(() => {
55-
eventBus.off(`lumino:show:${props.id}`)
57+
eventBus.off('lumino:show', onWidgetShow)
5658
})
5759
</script>

src/components/cylc/workspace/lumino-widget.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export default class LuminoWidget extends Widget {
8585

8686
onAfterShow (msg: Message) {
8787
// Emit an event so that the Vue component knows that this widget is visible again
88-
eventBus.emit(`lumino:show:${this.id}`)
88+
eventBus.emit('lumino:show', this.id)
8989
super.onAfterShow(msg)
9090
}
9191
}

src/services/eventBus.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,34 @@
1717

1818
import mitt from 'mitt'
1919

20+
/**
21+
* Mitt event for adding a view to the workspace.
22+
*/
23+
export interface AddViewEvent {
24+
/** The view to add */
25+
name: string
26+
/** Prop passed to the view component */
27+
initialOptions?: Record<string, unknown>
28+
}
29+
30+
/**
31+
* Mitt event for showing the mutations menu.
32+
*/
33+
export interface ShowMutationsMenuEvent {
34+
node: any, // TODO
35+
target: HTMLElement,
36+
}
37+
38+
type Events = {
39+
'add-view': AddViewEvent,
40+
'show-mutations-menu': ShowMutationsMenuEvent,
41+
'lumino:deleted': string,
42+
'lumino:show': string,
43+
}
44+
2045
/**
2146
* Global event bus for the app.
2247
*
2348
* @see https://github.com/developit/mitt
2449
*/
25-
export const eventBus = mitt()
50+
export const eventBus = mitt<Events>()

src/utils/index.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ import {
2626
*
2727
* Immediate by default.
2828
*/
29-
export function when (
30-
source: WatchSource<boolean>,
31-
callback: () => void,
29+
export function when<T> (
30+
source: WatchSource<T>,
31+
callback: (value: NonNullable<T>) => unknown,
3232
options: WatchOptions = {}
3333
): void {
3434
const unwatch = watch(
3535
source,
36-
(ready) => {
37-
if (ready) {
36+
(value) => {
37+
if (value) {
3838
unwatch()
39-
callback()
39+
callback(value)
4040
}
4141
},
4242
{ immediate: true, ...options }

src/utils/injectionKeys.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
import {
19+
type InjectionKey,
20+
type Ref,
21+
} from 'vue'
22+
23+
// Place to define keys for provide/inject in Vue components
24+
// @see https://vuejs.org/guide/typescript/composition-api.html#typing-provide-inject
25+
26+
export const animResetKey = Symbol('time of animation reset') as InjectionKey<Ref<number>>

0 commit comments

Comments
 (0)