Skip to content

Commit 12a868d

Browse files
committed
Improve polling management and state handling across device-related components
- Refactor `RemoteInstanceEditorWrapper.vue`: Replace conditional logic with a `switch` statement for clarity in `computedStatus`. - Enhance `DeviceHelper.js`: Add detailed polling control functions (`startPolling`, `stopPolling`, `pausePolling`, `resumePolling`) and refine polling state logic. - Update `Editor/index.vue`: Dynamically manage polling based on route and device state, ensuring polling consistency and better resource optimization.
1 parent 5bf1ee3 commit 12a868d

3 files changed

Lines changed: 103 additions & 69 deletions

File tree

frontend/src/components/immersive-editor/RemoteInstanceEditorWrapper.vue

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,15 @@ export default {
4747
this.device.editor.connected
4848
},
4949
computedStatus () {
50-
if (!this.device || !this.isEditorAvailable) {
51-
// forces the loading animation while loading
50+
switch (true) {
51+
case !this.device:
52+
case !this.isEditorAvailable:
53+
case this.device?.status === 'stopped':
54+
// forces the loading animation
5255
return 'loading'
56+
default:
57+
return this.device.status
5358
}
54-
55-
return this.device.status
5659
}
5760
}
5861
}

frontend/src/composables/DeviceHelper.js

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import semver from 'semver'
22
import { computed, ref } from 'vue'
3-
import { useRoute, useRouter } from 'vue-router'
3+
import { useRouter } from 'vue-router'
44
import { useStore } from 'vuex'
55

66
import deviceApi from '../api/devices.js'
@@ -23,12 +23,16 @@ const deviceTransitionStates = [
2323

2424
export function useDeviceHelper () {
2525
const $store = useStore()
26-
const $route = useRoute()
2726
const $router = useRouter()
2827

2928
let deviceStateMutator = null
3029
const device = ref(null)
31-
const pollTimer = createPollTimer(pollDevice, POLL_TIME, false)
30+
const pollTimer = createPollTimer(onPoll, POLL_TIME, false)
31+
32+
// duplicated functionality because the pollTimer is not reactive
33+
const isPolling = ref(false)
34+
35+
const isInTransitionState = computed(() => deviceTransitionStates.includes(device.value.status))
3236

3337
const agentSupportsDeviceAccess = computed(() =>
3438
device.value?.agentVersion && semver.gte(device.value?.agentVersion, '0.8.0')
@@ -37,6 +41,37 @@ export function useDeviceHelper () {
3741
device.value?.agentVersion && semver.gte(device.value?.agentVersion, '2.3.0')
3842
)
3943

44+
function startPolling () {
45+
isPolling.value = true
46+
pollTimer.start()
47+
}
48+
49+
function stopPolling () {
50+
isPolling.value = false
51+
pollTimer.stop()
52+
}
53+
54+
function resumePolling () {
55+
isPolling.value = true
56+
pollTimer.resume()
57+
}
58+
59+
function pausePolling () {
60+
isPolling.value = false
61+
pollTimer.pause()
62+
}
63+
64+
async function onPoll () {
65+
try {
66+
return await fetchDevice()
67+
} catch (err) {
68+
if (err.response?.status === 404) {
69+
stopPolling()
70+
}
71+
throw err
72+
}
73+
}
74+
4075
function preActionChecks (message) {
4176
if (device.value.agentVersion && !agentSupportsActions.value) {
4277
// if agent version is present but is less than required version, show warning and halt
@@ -77,53 +112,24 @@ export function useDeviceHelper () {
77112
}
78113
}
79114

80-
function bindDevice (binding) {
115+
function bindDevice (binding, shouldStartPolling = false) {
81116
device.value = binding
82117
deviceStateMutator = new DeviceStateMutator(binding)
118+
if (shouldStartPolling) { startPolling() }
83119
}
84120

85121
async function fetchDevice (deviceId = null) {
86122
try {
87123
device.value = await deviceApi.getDevice(deviceId || device.value?.id)
88124
} catch (err) {
89125
if (err.status === 403) {
90-
stopPoling()
126+
stopPolling()
91127

92128
return $router.push({ name: 'device-overview' })
93129
}
94130
}
95131
}
96132

97-
async function pollDevice () {
98-
// Only refresh device via the timer if we are on the overview page, developer mode page
99-
// the device status is empty or the device is in a transition state
100-
// This is to prevent settings pages from refreshing the device state while modifying settings
101-
// See `watch: { device: { handler () ... in pages/device/Settings/General.vue for why that happens
102-
const settingsPages = ['device-overview', 'device-developer-mode']
103-
try {
104-
switch (true) {
105-
case settingsPages.includes($route.name):
106-
case typeof device.value?.status === 'undefined':
107-
case deviceTransitionStates.includes(device.value?.status):
108-
await fetchDevice()
109-
break
110-
default:
111-
}
112-
} catch (err) {
113-
if (err.response.status === 404) {
114-
stopPoling()
115-
}
116-
}
117-
}
118-
119-
function startPoling () {
120-
pollTimer.start()
121-
}
122-
123-
function stopPoling () {
124-
pollTimer.stop()
125-
}
126-
127133
function showDeleteDialog () {
128134
Dialog.show({
129135
header: 'Delete Device',
@@ -147,11 +153,15 @@ export function useDeviceHelper () {
147153
agentSupportsDeviceAccess,
148154
agentSupportsActions,
149155
device,
150-
restartDevice,
156+
isPolling,
157+
isInTransitionState,
151158
bindDevice,
159+
startPolling,
160+
stopPolling,
161+
pausePolling,
162+
resumePolling,
163+
restartDevice,
152164
fetchDevice,
153-
showDeleteDialog,
154-
startPoling,
155-
stopPoling
165+
showDeleteDialog
156166
}
157167
}

frontend/src/pages/device/Editor/index.vue

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,13 @@ export default {
123123
bindDevice,
124124
fetchDevice,
125125
restartDevice,
126-
startPoling: startDevicePolling,
127126
showDeleteDialog: showDeleteDeviceDialog,
128-
stopPoling
127+
isPolling,
128+
isInTransitionState: isDeviceInTransitionState,
129+
startPolling,
130+
stopPolling,
131+
resumePolling,
132+
pausePolling
129133
} = useDeviceHelper()
130134
131135
return {
@@ -147,16 +151,15 @@ export default {
147151
restartDevice,
148152
bindDevice,
149153
fetchDevice,
150-
startDevicePolling,
151-
stopPoling,
154+
isPolling,
155+
isDeviceInTransitionState,
156+
startPolling,
157+
stopPolling,
158+
resumePolling,
159+
pausePolling,
152160
showDeleteDeviceDialog
153161
}
154162
},
155-
data () {
156-
return {
157-
mounted: false
158-
}
159-
},
160163
computed: {
161164
...mapState('account', ['features']),
162165
...mapGetters('account', ['featuresCheck']),
@@ -263,18 +266,19 @@ export default {
263266
264267
},
265268
watch: {
266-
device (device) {
267-
if (device && this.isEditorAvailable) {
268-
this.setContextDevice(device)
269-
this.bindDevice(device)
270-
271-
if (!this.mounted) {
272-
this.runInitialTease()
269+
'$route.name': 'handlePolling',
270+
device: {
271+
deep: true,
272+
handler (device) {
273+
if (device && this.isEditorAvailable) {
274+
this.setContextDevice(device)
275+
this.bindDevice(device, true)
276+
this.handlePolling()
277+
} else {
278+
this.$router.push({ name: 'device-overview' })
279+
.then(() => Alerts.emit('Unable to connect to the Remote Instance', 'warning'))
280+
.catch(e => e)
273281
}
274-
} else {
275-
this.$router.push({ name: 'device-overview' })
276-
.then(() => Alerts.emit('Unable to connect to the Remote Instance', 'warning'))
277-
.catch(e => e)
278282
}
279283
}
280284
},
@@ -297,22 +301,39 @@ export default {
297301
maxWidthRatio: DRAWER_MAX_WIDTH_RATIO
298302
})
299303
})
304+
.then(() => {
305+
this.runInitialTease()
306+
})
300307
.catch(err => err)
301308
},
309+
unmounted () {
310+
this.stopPolling()
311+
},
302312
methods: {
303313
...mapActions('context', { setContextDevice: 'setDevice' }),
304314
loadDevice: async function () {
305315
await this.fetchDevice(this.$route.params.id)
306-
307-
this.startDevicePolling()
308-
309-
this.mounted = true
310-
311-
// todo we first need to get the device and set the team afterwards
312316
await this.$store.dispatch('account/setTeam', this.device.team.slug)
313317
},
314318
showConfirmDeleteDialog () {
315319
this.showDeleteDeviceDialog()
320+
},
321+
handlePolling () {
322+
const pollingRoutes = [
323+
'device-editor-overview',
324+
'device-editor-developer-mode'
325+
]
326+
327+
switch (true) {
328+
case typeof this.device?.status === 'undefined':
329+
case this.device?.status === 'stopped':
330+
case this.isDeviceInTransitionState:
331+
case pollingRoutes.includes(this.$route.name):
332+
this.resumePolling()
333+
break
334+
default:
335+
this.pausePolling()
336+
}
316337
}
317338
}
318339
}

0 commit comments

Comments
 (0)