diff --git a/apps/settings/src/components/AuthToken.spec.ts b/apps/settings/src/components/AuthToken.spec.ts index ca63bf77a76..ad561894ec8 100644 --- a/apps/settings/src/components/AuthToken.spec.ts +++ b/apps/settings/src/components/AuthToken.spec.ts @@ -16,10 +16,16 @@ vi.hoisted(() => { import type { IToken } from '../store/authtoken.ts' +// Mock @nextcloud/dialogs so the wipe action's showConfirmation call resolves +// synchronously in tests. Hoisted so it's installed before AuthToken.vue imports. +const showConfirmationMock = vi.hoisted(() => vi.fn()) +vi.mock('@nextcloud/dialogs', () => ({ + showConfirmation: showConfirmationMock, +})) + import NcNoteCard from '@nextcloud/vue/components/NcNoteCard' import AuthToken from './AuthToken.vue' import AuthTokenDeleteDialog from './AuthTokenDeleteDialog.vue' -import AuthTokenWipeDialog from './AuthTokenWipeDialog.vue' import { TokenType, useAuthTokenStore } from '../store/authtoken.ts' import { detect } from '../utils/userAgentDetect.ts' @@ -143,33 +149,27 @@ describe('AuthToken wipe flow', () => { vi.clearAllMocks() }) - it('does not call wipeToken when the wipe action is triggered (dialog opens first)', async () => { + it('does not call wipeToken when the user rejects the confirmation', async () => { + showConfirmationMock.mockResolvedValueOnce(false) const token = makeToken() const wrapper = mountAuthToken(token) const store = useAuthTokenStore() - ;(wrapper.vm as unknown as { wipe: () => void }).wipe() - await wrapper.vm.$nextTick() + await (wrapper.vm as unknown as { wipe: () => Promise }).wipe() - const dialog = wrapper.findComponent(AuthTokenWipeDialog) - expect(dialog.exists()).toBe(true) - expect(dialog.props('open')).toBe(true) + expect(showConfirmationMock).toHaveBeenCalledTimes(1) expect(store.wipeToken).not.toHaveBeenCalled() }) - it('calls wipeToken only after the dialog emits confirm', async () => { + it('calls wipeToken when the user accepts the confirmation', async () => { + showConfirmationMock.mockResolvedValueOnce(true) const token = makeToken() const wrapper = mountAuthToken(token) const store = useAuthTokenStore() - ;(wrapper.vm as unknown as { wipe: () => void }).wipe() - await wrapper.vm.$nextTick() - - const dialog = wrapper.findComponent(AuthTokenWipeDialog) - dialog.vm.$emit('confirm') - dialog.vm.$emit('update:open', false) - await wrapper.vm.$nextTick() + await (wrapper.vm as unknown as { wipe: () => Promise }).wipe() + expect(showConfirmationMock).toHaveBeenCalledTimes(1) expect(store.wipeToken).toHaveBeenCalledTimes(1) expect(store.wipeToken).toHaveBeenCalledWith(token) }) diff --git a/apps/settings/src/components/AuthToken.vue b/apps/settings/src/components/AuthToken.vue index f89e3c5a874..59f733f59c1 100644 --- a/apps/settings/src/components/AuthToken.vue +++ b/apps/settings/src/components/AuthToken.vue @@ -87,11 +87,6 @@ :token="token" :open.sync="deleteDialogOpen" @confirm="confirmDelete" /> - @@ -100,6 +95,7 @@ import type { PropType } from 'vue' import type { IToken } from '../store/authtoken.ts' import { mdiAndroid, mdiAppleIos, mdiAppleSafari, mdiCellphone, mdiCheck, mdiFirefox, mdiGoogleChrome, mdiKeyOutline, mdiMicrosoftEdge, mdiMonitor, mdiTablet, mdiWeb } from '@mdi/js' +import { showConfirmation } from '@nextcloud/dialogs' import { translate as t } from '@nextcloud/l10n' import { defineComponent } from 'vue' import NcActionButton from '@nextcloud/vue/components/NcActionButton' @@ -110,7 +106,6 @@ import NcDateTime from '@nextcloud/vue/components/NcDateTime' import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper' import NcTextField from '@nextcloud/vue/components/NcTextField' import AuthTokenDeleteDialog from './AuthTokenDeleteDialog.vue' -import AuthTokenWipeDialog from './AuthTokenWipeDialog.vue' import { TokenType, useAuthTokenStore } from '../store/authtoken.ts' import { detect } from '../utils/userAgentDetect.ts' @@ -137,7 +132,6 @@ export default defineComponent({ name: 'AuthToken', components: { AuthTokenDeleteDialog, - AuthTokenWipeDialog, NcActions, NcActionButton, NcActionCheckbox, @@ -166,7 +160,6 @@ export default defineComponent({ newName: '', oldName: '', deleteDialogOpen: false, - wipeDialogOpen: false, mdiCheck, TokenType, } @@ -306,13 +299,18 @@ export default defineComponent({ this.authTokenStore.renameToken(this.token, this.newName) }, - wipe() { + async wipe() { this.actionOpen = false - this.wipeDialogOpen = true - }, - - confirmWipe() { - this.authTokenStore.wipeToken(this.token) + const confirmed = await showConfirmation({ + name: t('settings', 'Confirm wipe'), + text: t('settings', 'Do you really want to wipe your data from this device?'), + labelConfirm: t('settings', 'Wipe device'), + labelReject: t('settings', 'Cancel'), + severity: 'warning', + }) + if (confirmed) { + this.authTokenStore.wipeToken(this.token) + } }, }, }) diff --git a/apps/settings/src/components/AuthTokenWipeDialog.vue b/apps/settings/src/components/AuthTokenWipeDialog.vue deleted file mode 100644 index 559e3acda8e..00000000000 --- a/apps/settings/src/components/AuthTokenWipeDialog.vue +++ /dev/null @@ -1,54 +0,0 @@ - - - - -