Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@
"ecmaVersion": 2022,
"sourceType": "module"
},
"settings": {
"import/resolver": {
"webpack": {
"config": "config/webpack.config.js"
},
"node": {
"extensions": [".js", ".vue"]
}
}
},
"rules": {
// plugin:vue
"vue/html-indent": ["warn", 4],
Expand All @@ -85,7 +95,12 @@
"vue/component-definition-name-casing": "off",

// plugin:promise
"promise/always-return": "off" // common Vue.js pattern
"promise/always-return": "off", // common Vue.js pattern

// Frontend runs through webpack, not Node — n's Node.js-based resolution
// does not understand webpack aliases (@/) or .vue file resolution
"n/no-missing-import": "off",
"n/no-missing-require": "off"
}
},

Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/DevicesBrowser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,8 @@ import DevicesStatusBar from './charts/DeviceStatusBar.vue'
import AddDeviceToGroupDialog from './dialogs/device-group-management/AddDeviceToGroupDialog.vue'
import RemoveDeviceFromGroupDialog from './dialogs/device-group-management/RemoveDeviceFromGroupDialog.vue'

import { useUxDialogStore } from '@/stores/ux-dialog.js'

const POLL_TIME = 10000

export default {
Expand Down Expand Up @@ -459,8 +461,8 @@ export default {
computed: {
...mapState('account', ['team', 'teamMembership']),
...mapState('ux/tours', ['tours']),
...mapState('ux/dialog', ['dialog']),
...mapGetters('account', ['featuresCheck']),
dialog () { return useUxDialogStore().dialog },
Comment thread
n-lark marked this conversation as resolved.
Outdated
columns () {
const columns = [
{ label: 'Remote Instance', key: 'name', sortable: !this.moreThanOnePage, component: { is: markRaw(DeviceLink) } },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,8 @@

<script>
import { ChipIcon } from '@heroicons/vue/outline'
import { mapActions, mapState } from 'vuex'

import ApplicationAPI from '../../../api/application.js'
import { useUxDialogStore } from '@/stores/ux-dialog.js'
import { pluralize } from '../../../composables/String.js'
import FfLoading from '../../Loading.vue'
import NoticeBanner from '../../notices/NoticeBanner.vue'
Expand Down Expand Up @@ -119,7 +118,7 @@ export default {
}
},
computed: {
...mapState('ux/dialog', ['dialog']),
dialog () { return useUxDialogStore().dialog },
Comment thread
cstns marked this conversation as resolved.
Outdated
application () {
if (!this.devicesBelongToSameApplication) return null

Expand Down Expand Up @@ -199,7 +198,7 @@ export default {
},
methods: {
pluralize,
...mapActions('ux/dialog', ['setDisablePrimary']),
setDisablePrimary (value) { useUxDialogStore().setDisablePrimary(value) },
async getDeviceGroups (application) {
this.loading = true
return ApplicationAPI.getDeviceGroups(application.id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@
</template>

<script>
import { mapState } from 'vuex'

import { pluralize } from '../../../../composables/String.js'

import FfDataTable from '../../../../ui-components/components/data-table/DataTable.vue'
import Accordion from '../../../Accordion.vue'

import { useUxDialogStore } from '@/stores/ux-dialog.js'

export default {
name: 'device-list',
components: {
Expand All @@ -50,7 +51,7 @@ export default {
},
emits: ['selection-removed'],
computed: {
...mapState('ux/dialog', ['dialog']),
dialog () { return useUxDialogStore().dialog },
columns () {
return [
{ label: 'Name', key: 'name', class: ['flex-grow'], sortable: true },
Expand Down
17 changes: 7 additions & 10 deletions frontend/src/mixins/Dialog.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import { mapActions, mapState } from 'vuex'

import dialog from '../services/dialog.js'

import { useUxDialogStore } from '@/stores/ux-dialog.js'

export default {
computed: {
...mapState('ux/dialog', ['dialog'])
dialog () { return useUxDialogStore().dialog }
Comment thread
cstns marked this conversation as resolved.
Outdated
},
methods: {
...mapActions('ux/dialog', ['clearDialog']),
...mapActions('ux/dialog', {
handleDialog: 'showDialogHandlers'
}),
clearDialog (cancelled = false) {
useUxDialogStore().clearDialog(cancelled)
},
showDialogHandler (msg, onConfirm, onCancel) {
return this.handleDialog({
payload: msg, onConfirm, onCancel
})
return useUxDialogStore().showDialogHandlers({ payload: msg, onConfirm, onCancel })
}
},
mounted () {
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/store/modules/account/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { getTeamProperty } from '../../../composables/TeamProperties.js'
import router from '../../../routes.js'
import product from '../../../services/product.js'

import { useUxDialogStore } from '@/stores/ux-dialog.js'

// initial state
const initialState = () => ({
// Runtime settings
Expand Down Expand Up @@ -512,7 +514,7 @@ const actions = {
// Reset migrated Pinia stores — uncomment each line as its store is migrated
const pinia = getActivePinia()
if (pinia) {
// Task 1: useUxDialogStore().$reset()
useUxDialogStore().$reset()
// Task 2: useUxToursStore().$reset()
// Task 3: useUxNavigationStore().$reset()
// Task 4: useUxDrawersStore().$reset()
Expand Down
101 changes: 0 additions & 101 deletions frontend/src/store/modules/ux/dialog/index.js

This file was deleted.

3 changes: 1 addition & 2 deletions frontend/src/store/modules/ux/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import QueueIcon from '../../../components/icons/Queue.js'
import { hasALowerOrEqualTeamRoleThan, hasAMinimumTeamRoleOf, hasPermission } from '../../../composables/Permissions.js'
import { Roles } from '../../../utils/roles.js'

import dialog from './dialog/index.js'
import drawers from './drawers/index.js'
import tours from './tours/index.js'

Expand Down Expand Up @@ -514,7 +513,7 @@ const actions = {

export default {
namespaced: true,
modules: { dialog, drawers, tours },
modules: { drawers, tours },
state,
initialState: initialState(),
getters,
Expand Down
1 change: 1 addition & 0 deletions frontend/src/stores/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
// Barrel export — add store exports here as each task is merged
export { useUxDialogStore } from './ux-dialog.js'
61 changes: 61 additions & 0 deletions frontend/src/stores/ux-dialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { defineStore } from 'pinia'

const initialDialogState = () => ({
boxClass: null,
Comment thread
cstns marked this conversation as resolved.
Outdated
cancelLabel: null,
canBeCanceled: true,
confirmLabel: null,
contentClass: '',
disablePrimary: false,
header: null,
html: null,
is: null,
kind: null,
onCancel: null,
onConfirm: null,
subHeader: null,
text: null,
textLines: null,
notices: []
})

export const useUxDialogStore = defineStore('ux-dialog', {
state: () => ({
dialog: initialDialogState()
}),
actions: {
clearDialog (cancelled = false) {
if (cancelled) {
this.dialog.onCancel?.()
}
this.dialog = initialDialogState()
},
showDialogHandlers ({ payload, onConfirm, onCancel }) {
this.clearDialog(false)

if (typeof payload === 'string') {
this.dialog.content = payload
} else {
this.dialog.header = payload.header
this.dialog.text = payload.text
this.dialog.textLines = payload.text?.split('\n')
this.dialog.html = payload.html
this.dialog.is = payload.is ?? undefined
this.dialog.confirmLabel = payload.confirmLabel
this.dialog.cancelLabel = payload.cancelLabel
this.dialog.kind = payload.kind
this.dialog.disablePrimary = payload.disablePrimary
this.dialog.notices = payload.notices
if (Object.prototype.hasOwnProperty.call(payload, 'canBeCanceled')) {
this.dialog.canBeCanceled = payload.canBeCanceled
}
this.dialog.boxClass = payload.boxClass
}
this.dialog.onConfirm = onConfirm
this.dialog.onCancel = onCancel
},
setDisablePrimary (value) {
this.dialog.disablePrimary = value
}
}
})
57 changes: 57 additions & 0 deletions frontend/src/stores/ux-dialog.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// frontend/src/tests/stores/ux-dialog.spec.js
import { createPinia, setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'

import { useUxDialogStore } from '@/stores/ux-dialog.js'

describe('ux-dialog store', () => {
beforeEach(() => {
setActivePinia(createPinia())
})

it('initializes with empty dialog state', () => {
const store = useUxDialogStore()
expect(store.dialog.header).toBeNull()
expect(store.dialog.text).toBeNull()
})

it('showDialogHandlers sets dialog properties from object payload', () => {
const store = useUxDialogStore()
const onConfirm = vi.fn()
store.showDialogHandlers({
payload: { header: 'Delete?', text: 'This cannot be undone.', kind: 'danger' },
onConfirm
})
expect(store.dialog.header).toBe('Delete?')
expect(store.dialog.kind).toBe('danger')
expect(store.dialog.onConfirm).toBe(onConfirm)
})

it('showDialogHandlers splits text into textLines', () => {
const store = useUxDialogStore()
store.showDialogHandlers({ payload: { text: 'Line 1\nLine 2' }, onConfirm: vi.fn() })
expect(store.dialog.textLines).toEqual(['Line 1', 'Line 2'])
})

it('clearDialog resets all dialog state', () => {
const store = useUxDialogStore()
store.dialog.header = 'Test'
store.clearDialog()
expect(store.dialog.header).toBeNull()
})

it('clearDialog(true) calls onCancel before resetting', () => {
const store = useUxDialogStore()
const onCancel = vi.fn()
store.dialog.onCancel = onCancel
store.clearDialog(true)
expect(onCancel).toHaveBeenCalledOnce()
expect(store.dialog.header).toBeNull()
})

it('setDisablePrimary updates the flag', () => {
const store = useUxDialogStore()
store.setDisablePrimary(true)
expect(store.dialog.disablePrimary).toBe(true)
})
})
Loading
Loading