Skip to content

Commit 8b1f95c

Browse files
authored
Merge pull request #6122 from FlowFuse/enhance-visibility-of-device-modes
Add device mode filters and badge to DevicesBrowser component
2 parents dfe83e8 + 0a3c603 commit 8b1f95c

2 files changed

Lines changed: 69 additions & 5 deletions

File tree

frontend/src/components/DevicesBrowser.vue

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,28 @@
2525
@update:sort="updateSort"
2626
>
2727
<template #actions>
28+
<ff-popover button-text="Filters" button-kind="secondary">
29+
<template #panel="{ close }">
30+
<section>
31+
<popover-item
32+
title="Fleet Mode"
33+
@click="onFilterClick('fleetMode', close)"
34+
>
35+
<template #icon>
36+
<ff-checkbox v-model="deviceModeFilters.fleetMode" style="top: -8px;" />
37+
</template>
38+
</popover-item>
39+
<popover-item
40+
title="Developer Mode"
41+
@click="onFilterClick('developerMode', close)"
42+
>
43+
<template #icon>
44+
<ff-checkbox v-model="deviceModeFilters.developerMode" style="top: -8px;" />
45+
</template>
46+
</popover-item>
47+
</section>
48+
</template>
49+
</ff-popover>
2850
<DropdownMenu v-if="hasPermission('team:device:bulk-delete', applicationContext) || hasPermission('team:device:bulk-edit', applicationContext)" :disabled="!checkedDevices?.length" data-el="bulk-actions-dropdown" buttonClass="ff-btn ff-btn--secondary" :options="bulkActionsDropdownOptions">Actions</DropdownMenu>
2951
<ff-button
3052
v-if="displayingInstance && hasPermission('project:snapshot:create', applicationContext)"
@@ -325,6 +347,7 @@ import DeviceLink from '../pages/application/components/cells/DeviceLink.vue'
325347
import Snapshot from '../pages/application/components/cells/Snapshot.vue'
326348
327349
import DeviceLastSeenCell from '../pages/device/components/DeviceLastSeenCell.vue'
350+
import DeviceModeBadge from '../pages/device/components/DeviceModeBadge.vue'
328351
import SnapshotAssignDialog from '../pages/instance/VersionHistory/Snapshots/dialogs/SnapshotAssignDialog.vue'
329352
import InstanceStatusBadge from '../pages/instance/components/InstanceStatusBadge.vue'
330353
import DeviceAssignApplicationDialog from '../pages/team/Devices/dialogs/DeviceAssignApplicationDialog.vue'
@@ -333,6 +356,9 @@ import DeviceCredentialsDialog from '../pages/team/Devices/dialogs/DeviceCredent
333356
import TeamDeviceCreateDialog from '../pages/team/Devices/dialogs/TeamDeviceCreateDialog.vue'
334357
335358
import Alerts from '../services/alerts.js'
359+
import FfPopover from '../ui-components/components/Popover.vue'
360+
import PopoverItem from '../ui-components/components/PopoverItem.vue'
361+
import FfCheckbox from '../ui-components/components/form/Checkbox.vue'
336362
337363
import { debounce } from '../utils/eventHandling.js'
338364
import { createPollTimer } from '../utils/timers.js'
@@ -346,6 +372,9 @@ const POLL_TIME = 10000
346372
export default {
347373
name: 'DevicesBrowser',
348374
components: {
375+
FfCheckbox,
376+
PopoverItem,
377+
FfPopover,
349378
ClockIcon,
350379
DeviceAssignApplicationDialog,
351380
DeviceAssignInstanceDialog,
@@ -401,7 +430,11 @@ export default {
401430
},
402431
/** @type { import('../utils/timers.js').PollTimer } */
403432
pollTimer: null,
404-
deviceEditModalOpened: false
433+
deviceEditModalOpened: false,
434+
deviceModeFilters: {
435+
fleetMode: false,
436+
developerMode: false
437+
}
405438
}
406439
},
407440
computed: {
@@ -413,6 +446,7 @@ export default {
413446
{ label: 'Remote Instance', key: 'name', sortable: !this.moreThanOnePage, component: { is: markRaw(DeviceLink) } },
414447
{ label: 'Type', key: 'type', class: ['w-48'], sortable: !this.moreThanOnePage },
415448
{ label: 'Last Seen', key: 'lastSeenAt', class: ['w-48'], sortable: !this.moreThanOnePage, component: { is: markRaw(DeviceLastSeenCell) } },
449+
{ label: 'Mode', key: 'mode', class: ['w-48'], sortable: true, component: { is: markRaw(DeviceModeBadge) } },
416450
{ label: 'Last Known Status', class: ['w-32'], component: { is: markRaw(InstanceStatusBadge), map: { instanceId: 'id' }, extraProps: { instanceType: 'device' } } }
417451
]
418452
@@ -548,12 +582,19 @@ export default {
548582
* - property: which filter row is being applied, e.g. status or lastseen
549583
* - bucket: which value of this property are we filtering on from the buckets in the status bar
550584
*/
551-
applyFilter (filter) {
585+
applyFilter (filter, shouldClearDeviceModeFilters = true) {
552586
this.filter = filter
553587
554588
if (this.unfilteredHasMoreThanOnePage) {
555589
this.doFilterServerSide()
556590
}
591+
592+
if (shouldClearDeviceModeFilters) {
593+
this.deviceModeFilters = {
594+
fleetMode: false,
595+
developerMode: false
596+
}
597+
}
557598
},
558599
559600
updateSearch (searchTerm) {
@@ -789,6 +830,29 @@ export default {
789830
}
790831
791832
return 'Unassigned'
833+
},
834+
835+
onFilterClick (filter, closeCallback) {
836+
const compare = filter === 'fleetMode' ? 'autonomous' : 'developer'
837+
this.deviceModeFilters[filter] = !this.deviceModeFilters[filter]
838+
839+
this.applyFilter(
840+
{
841+
devices: Array.from(this.devices.values())
842+
.filter((device) => !this.deviceModeFilters[filter] ? true : device.mode === compare)
843+
.map(device => device.id),
844+
property: 'mode'
845+
},
846+
false
847+
)
848+
849+
// resetting filters because we can't have multiple filters applied at once
850+
const filters = {
851+
fleetMode: false,
852+
developerMode: false
853+
}
854+
filters[filter] = this.deviceModeFilters[filter]
855+
this.deviceModeFilters = filters
792856
}
793857
}
794858
}

test/e2e/frontend/cypress/tests/devices/bulk.spec.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,9 @@ describe('FlowFuse - Devices', () => {
155155
})
156156

157157
// check the table columns for the moved devices
158-
cy.get('[data-el="devices-browser"] tbody tr').contains(deviceName1).parent().parent().find('td').eq(5).contains(options.moveTo)
159-
cy.get('[data-el="devices-browser"] tbody tr').contains(deviceName2).parent().parent().find('td').eq(5).contains(options.moveTo)
160-
cy.get('[data-el="devices-browser"] tbody tr').contains(deviceName3).parent().parent().find('td').eq(5).contains(options.moveTo)
158+
cy.get('[data-el="devices-browser"] tbody tr').contains(deviceName1).parent().parent().find('td').eq(6).contains(options.moveTo)
159+
cy.get('[data-el="devices-browser"] tbody tr').contains(deviceName2).parent().parent().find('td').eq(6).contains(options.moveTo)
160+
cy.get('[data-el="devices-browser"] tbody tr').contains(deviceName3).parent().parent().find('td').eq(6).contains(options.moveTo)
161161
})
162162
}
163163
})

0 commit comments

Comments
 (0)