refactor: adjust code for breaking changes in `@nextcloud/dialogs` v7

Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
pull/57129/head
Ferdinand Thiessen 2025-10-13 17:39:08 +07:00
parent 2662901d92
commit a3871346e1
12 changed files with 123 additions and 118 deletions

@ -65,11 +65,11 @@
</template> </template>
<script> <script>
import axios from '@nextcloud/axios'
import { DialogBuilder, showError } from '@nextcloud/dialogs'
import { loadState } from '@nextcloud/initial-state' import { loadState } from '@nextcloud/initial-state'
import { DialogBuilder, DialogSeverity, showError } from '@nextcloud/dialogs'
import { generateOcsUrl } from '@nextcloud/router' import { generateOcsUrl } from '@nextcloud/router'
import { confirmPassword } from '@nextcloud/password-confirmation' import { confirmPassword } from '@nextcloud/password-confirmation'
import axios from '@nextcloud/axios'
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch' import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
import NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection' import NcSettingsSection from '@nextcloud/vue/components/NcSettingsSection'
@ -114,10 +114,8 @@ export default {
const dialog = new DialogBuilder(t('federatedfilesharing', 'Confirm data upload to lookup server')) const dialog = new DialogBuilder(t('federatedfilesharing', 'Confirm data upload to lookup server'))
await dialog await dialog
.setSeverity(DialogSeverity.Warning) .setSeverity('warning')
.setText( .setText(t('federatedfilesharing', 'When enabled, all account properties (e.g. email address) with scope visibility set to "published", will be automatically synced and transmitted to an external system and made available in a public, global address book.'))
t('federatedfilesharing', 'When enabled, all account properties (e.g. email address) with scope visibility set to "published", will be automatically synced and transmitted to an external system and made available in a public, global address book.'),
)
.addButton({ .addButton({
callback: () => this.setLookupServerUploadEnabled(false), callback: () => this.setLookupServerUploadEnabled(false),
label: t('federatedfilesharing', 'Disable upload'), label: t('federatedfilesharing', 'Disable upload'),
@ -147,9 +145,8 @@ export default {
const dialog = new DialogBuilder(t('federatedfilesharing', 'Confirm querying lookup server')) const dialog = new DialogBuilder(t('federatedfilesharing', 'Confirm querying lookup server'))
await dialog await dialog
.setSeverity(DialogSeverity.Warning) .setSeverity('warning')
.setText( .setText(t('federatedfilesharing', 'When enabled, the search input when creating shares will be sent to an external system that provides a public and global address book.')
t('federatedfilesharing', 'When enabled, the search input when creating shares will be sent to an external system that provides a public and global address book.')
+ t('federatedfilesharing', 'This is used to retrieve the federated cloud ID to make federated sharing easier.') + t('federatedfilesharing', 'This is used to retrieve the federated cloud ID to make federated sharing easier.')
+ t('federatedfilesharing', 'Moreover, email addresses of users might be sent to that system in order to verify them.'), + t('federatedfilesharing', 'Moreover, email addresses of users might be sent to that system in order to verify them.'),
) )

@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
import { spawnDialog } from '@nextcloud/dialogs' import { spawnDialog } from '@nextcloud/vue/functions/dialog'
import RemoteShareDialog from '../components/RemoteShareDialog.vue' import RemoteShareDialog from '../components/RemoteShareDialog.vue'
/** /**

@ -4,7 +4,8 @@
*/ */
import type { Node } from '@nextcloud/files' import type { Node } from '@nextcloud/files'
import { spawnDialog } from '@nextcloud/dialogs'
import { spawnDialog } from '@nextcloud/vue/functions/dialog'
import NewNodeDialog from '../components/NewNodeDialog.vue' import NewNodeDialog from '../components/NewNodeDialog.vue'
interface ILabels { interface ILabels {

@ -4,80 +4,79 @@
--> -->
<template> <template>
<div :id="containerId"> <div :id="containerId" />
<FilePicker v-bind="filepickerOptions" @close="onClose" />
</div>
</template> </template>
<script lang="ts"> <script setup lang="ts">
import type { Node as NcNode } from '@nextcloud/files'
import type { IFilePickerButton } from '@nextcloud/dialogs' import type { IFilePickerButton } from '@nextcloud/dialogs'
import type { Node as NcNode } from '@nextcloud/files'
import { FilePickerVue as FilePicker } from '@nextcloud/dialogs/filepicker.js' import { FilePickerBuilder } from '@nextcloud/dialogs'
import { translate as t } from '@nextcloud/l10n' import { t } from '@nextcloud/l10n'
import { defineComponent } from 'vue' import { generateUrl } from '@nextcloud/router'
import { generateFileUrl } from '../../../files_sharing/src/utils/generateUrl' import { onMounted } from 'vue'
import logger from '../logger.ts'
export default defineComponent({ defineProps<{
name: 'FileReferencePickerElement', providerId: string
components: { accessible: boolean
FilePicker, }>()
},
props: {
providerId: {
type: String,
required: true,
},
accessible: {
type: Boolean,
default: false,
},
},
computed: {
containerId() {
return `filepicker-${Math.random().toString(36).slice(7)}`
},
filepickerOptions() {
return {
allowPickDirectory: true,
buttons: this.buttonFactory,
container: `#${this.containerId}`,
multiselect: false,
name: t('files', 'Select file or folder to link to'),
}
},
},
methods: {
t,
buttonFactory(selected: NcNode[]): IFilePickerButton[] { const emit = defineEmits<{
const buttons = [] as IFilePickerButton[] (e: 'submit', url: string): void
if (selected.length === 0) { (e: 'cancel'): void
return [] }>()
}
const node = selected.at(0)
if (node.path === '/') {
return [] // Do not allow selecting the users root folder
}
buttons.push({
label: t('files', 'Choose {file}', { file: node.displayname }),
type: 'primary',
callback: this.onClose,
})
return buttons
},
onClose(nodes?: NcNode[]) { const containerId = `filepicker-${Math.random().toString(36).slice(7)}`
if (nodes === undefined || nodes.length === 0) {
this.$emit('cancel')
} else {
this.onSubmit(nodes[0])
}
},
onSubmit(node: NcNode) { const filePicker = new FilePickerBuilder(t('files', 'Select file or folder to link to'))
this.$emit('submit', generateFileUrl(node.fileid!)) .allowDirectories(true)
}, .setButtonFactory(buttonFactory)
}, .setContainer(`#${containerId}`)
.setMultiSelect(false)
.build()
onMounted(async () => {
try {
const [node] = await filePicker.pickNodes()
onSubmit(node)
} catch (error) {
logger.debug('Aborted picking nodes:', { error })
emit('cancel')
}
}) })
/**
* Get buttons for the file picker dialog
*
* @param selected - currently selected nodes
*/
function buttonFactory(selected: NcNode[]): IFilePickerButton[] {
const buttons = [] as IFilePickerButton[]
const node = selected[0]
if (node === undefined) {
return []
}
if (node.path === '/') {
return [] // Do not allow selecting the users root folder
}
buttons.push({
label: t('files', 'Choose {file}', { file: node.displayname }),
variant: 'primary',
callback: () => {}, // handled by the pickNodes method
})
return buttons
}
/**
* @param node - selected node
*/
function onSubmit(node: NcNode) {
const url = new URL(window.location.href)
url.pathname = generateUrl('/f/{fileId}', { fileId: node.fileid! })
url.search = ''
emit('submit', url.href)
}
</script> </script>

@ -50,13 +50,14 @@
import type { TemplateFile } from '../types.ts' import type { TemplateFile } from '../types.ts'
import { getCurrentUser } from '@nextcloud/auth' import { getCurrentUser } from '@nextcloud/auth'
import { showError, spawnDialog } from '@nextcloud/dialogs' import { showError } from '@nextcloud/dialogs'
import { emit } from '@nextcloud/event-bus' import { emit } from '@nextcloud/event-bus'
import { File, Node } from '@nextcloud/files' import { File, Node } from '@nextcloud/files'
import { getClient, getRootPath, resultToNode, getDefaultPropfind } from '@nextcloud/files/dav' import { getClient, getRootPath, resultToNode, getDefaultPropfind } from '@nextcloud/files/dav'
import { translate as t } from '@nextcloud/l10n' import { translate as t } from '@nextcloud/l10n'
import { generateRemoteUrl } from '@nextcloud/router' import { generateRemoteUrl } from '@nextcloud/router'
import { normalize, extname, join } from 'path' import { spawnDialog } from '@nextcloud/vue/functions/dialog'
import { extname, join, normalize } from 'path'
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import { createFromTemplate, getTemplates, getTemplateFields } from '../services/Templates.js' import { createFromTemplate, getTemplates, getTemplateFields } from '../services/Templates.js'

@ -7,15 +7,15 @@ import type { AxiosResponse } from '@nextcloud/axios'
import type { Node } from '@nextcloud/files' import type { Node } from '@nextcloud/files'
import type { StorageConfig } from '../services/externalStorage' import type { StorageConfig } from '../services/externalStorage'
import LoginSvg from '@mdi/svg/svg/login.svg?raw'
import axios from '@nextcloud/axios'
import { showError, showSuccess } from '@nextcloud/dialogs'
import { DefaultType, FileAction } from '@nextcloud/files'
import { t } from '@nextcloud/l10n'
import { addPasswordConfirmationInterceptors, PwdConfirmationMode } from '@nextcloud/password-confirmation' import { addPasswordConfirmationInterceptors, PwdConfirmationMode } from '@nextcloud/password-confirmation'
import { generateUrl } from '@nextcloud/router' import { generateUrl } from '@nextcloud/router'
import { showError, showSuccess, spawnDialog } from '@nextcloud/dialogs' import { spawnDialog } from '@nextcloud/vue/functions/dialog'
import { translate as t } from '@nextcloud/l10n'
import axios from '@nextcloud/axios'
import LoginSvg from '@mdi/svg/svg/login.svg?raw'
import Vue, { defineAsyncComponent } from 'vue' import Vue, { defineAsyncComponent } from 'vue'
import { FileAction, DefaultType } from '@nextcloud/files'
import { STORAGE_STATUS, isMissingAuthConfig } from '../utils/credentialsUtils' import { STORAGE_STATUS, isMissingAuthConfig } from '../utils/credentialsUtils'
import { isNodeExternalStorage } from '../utils/externalStorageUtils' import { isNodeExternalStorage } from '../utils/externalStorageUtils'

@ -2,15 +2,16 @@
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
import type { Entry, Folder, Node } from '@nextcloud/files'
import type { NewMenuEntry, Folder, Node } from '@nextcloud/files'
import { t } from '@nextcloud/l10n'
import { isPublicShare } from '@nextcloud/sharing/public'
import { spawnDialog } from '@nextcloud/vue/functions/dialog'
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'
import { spawnDialog } from '@nextcloud/dialogs'
import { translate as t } from '@nextcloud/l10n'
import FileUploadSvg from '@mdi/svg/svg/file-upload-outline.svg?raw' import FileUploadSvg from '@mdi/svg/svg/file-upload-outline.svg?raw'
import Config from '../services/ConfigService' import Config from '../services/ConfigService'
import { isPublicShare } from '@nextcloud/sharing/public'
const sharingConfig = new Config() const sharingConfig = new Config()
const NewFileRequestDialogVue = defineAsyncComponent(() => import('../components/NewFileRequestDialog.vue')) const NewFileRequestDialogVue = defineAsyncComponent(() => import('../components/NewFileRequestDialog.vue'))
@ -39,4 +40,4 @@ export const entry = {
content, content,
}) })
}, },
} as Entry } as NewMenuEntry

@ -2,16 +2,14 @@
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
import type { Node, View, Folder } from '@nextcloud/files'
import type { Folder, Node, View } from '@nextcloud/files'
import { getDialogBuilder } from '@nextcloud/dialogs'
import { emit } from '@nextcloud/event-bus' import { emit } from '@nextcloud/event-bus'
import { FileListAction } from '@nextcloud/files' import { FileListAction } from '@nextcloud/files'
import { loadState } from '@nextcloud/initial-state' import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n' import { t } from '@nextcloud/l10n'
import {
DialogSeverity,
getDialogBuilder,
} from '@nextcloud/dialogs'
import { emptyTrash } from '../services/api.ts' import { emptyTrash } from '../services/api.ts'
import { TRASHBIN_VIEW_ID } from '../files_views/trashbinView.ts' import { TRASHBIN_VIEW_ID } from '../files_views/trashbinView.ts'
@ -41,18 +39,18 @@ export const emptyTrashAction = new FileListAction({
async exec(view: View, nodes: Node[]): Promise<null> { async exec(view: View, nodes: Node[]): Promise<null> {
const askConfirmation = new Promise<boolean>((resolve) => { const askConfirmation = new Promise<boolean>((resolve) => {
const dialog = getDialogBuilder(t('files_trashbin', 'Confirm permanent deletion')) const dialog = getDialogBuilder(t('files_trashbin', 'Confirm permanent deletion'))
.setSeverity(DialogSeverity.Warning) .setSeverity('warning')
// TODO Add note for groupfolders // TODO Add note for groupfolders
.setText(t('files_trashbin', 'Are you sure you want to permanently delete all files and folders in the trash? This cannot be undone.')) .setText(t('files_trashbin', 'Are you sure you want to permanently delete all files and folders in the trash? This cannot be undone.'))
.setButtons([ .setButtons([
{ {
label: t('files_trashbin', 'Cancel'), label: t('files_trashbin', 'Cancel'),
type: 'secondary', variant: 'secondary',
callback: () => resolve(false), callback: () => resolve(false),
}, },
{ {
label: t('files_trashbin', 'Empty deleted files'), label: t('files_trashbin', 'Empty deleted files'),
type: 'error', variant: 'error',
callback: () => resolve(true), callback: () => resolve(true),
}, },
]) ])

@ -5,15 +5,17 @@
<script setup lang="ts"> <script setup lang="ts">
import type { OCSResponse } from '@nextcloud/typings/ocs' import type { OCSResponse } from '@nextcloud/typings/ocs'
import { showError, spawnDialog } from '@nextcloud/dialogs'
import axios from '@nextcloud/axios'
import { showError } from '@nextcloud/dialogs'
import { loadState } from '@nextcloud/initial-state' import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n' import { t } from '@nextcloud/l10n'
import { confirmPassword } from '@nextcloud/password-confirmation' import { confirmPassword } from '@nextcloud/password-confirmation'
import { generateOcsUrl } from '@nextcloud/router' import { generateOcsUrl } from '@nextcloud/router'
import { spawnDialog } from '@nextcloud/vue/functions/dialog'
import { ref } from 'vue' import { ref } from 'vue'
import { textExistingFilesNotEncrypted } from './sharedTexts.ts' import { textExistingFilesNotEncrypted } from './sharedTexts.ts'
import axios from '@nextcloud/axios'
import logger from '../../logger.ts' import logger from '../../logger.ts'
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch' import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'

@ -2,13 +2,14 @@
* SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later * SPDX-License-Identifier: AGPL-3.0-or-later
*/ */
import { Permission, type Node } from '@nextcloud/files'
import { defineAsyncComponent } from 'vue' import type { Node } from '@nextcloud/files'
import { FileAction } from '@nextcloud/files'
import { isPublicShare } from '@nextcloud/sharing/public' import { FileAction, Permission } from '@nextcloud/files'
import { spawnDialog } from '@nextcloud/dialogs'
import { t } from '@nextcloud/l10n' import { t } from '@nextcloud/l10n'
import { isPublicShare } from '@nextcloud/sharing/public'
import { spawnDialog } from '@nextcloud/vue/functions/dialog'
import { defineAsyncComponent } from 'vue'
import TagMultipleSvg from '@mdi/svg/svg/tag-multiple-outline.svg?raw' import TagMultipleSvg from '@mdi/svg/svg/tag-multiple-outline.svg?raw'

@ -10,10 +10,9 @@ import $ from 'jquery'
import IconMove from '@mdi/svg/svg/folder-move.svg?raw' import IconMove from '@mdi/svg/svg/folder-move.svg?raw'
import IconCopy from '@mdi/svg/svg/folder-multiple-outline.svg?raw' import IconCopy from '@mdi/svg/svg/folder-multiple-outline.svg?raw'
import { DialogBuilder, FilePickerType, getFilePickerBuilder } from '@nextcloud/dialogs'
import OC from './index.js' import { t } from '@nextcloud/l10n'
import { DialogBuilder, FilePickerType, getFilePickerBuilder, spawnDialog } from '@nextcloud/dialogs' import { spawnDialog } from '@nextcloud/vue/functions/dialog'
import { translate as t } from '@nextcloud/l10n'
import { basename } from 'path' import { basename } from 'path'
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'

@ -3,19 +3,23 @@
- SPDX-License-Identifier: AGPL-3.0-or-later - SPDX-License-Identifier: AGPL-3.0-or-later
--> -->
<template> <template>
<PublicPageMenuEntry :id="id" <Fragment>
:icon="icon" <PublicPageMenuEntry :id="id"
href="#" :icon="icon"
:label="label" href="#"
@click="openDialog" /> :label="label"
@click="openDialog" />
<PublicPageMenuExternalDialog v-if="showDialog" :label="label" />
</Fragment>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { spawnDialog } from '@nextcloud/dialogs' import { ref } from 'vue'
import { Fragment } from 'vue-frag'
import PublicPageMenuEntry from './PublicPageMenuEntry.vue' import PublicPageMenuEntry from './PublicPageMenuEntry.vue'
import PublicPageMenuExternalDialog from './PublicPageMenuExternalDialog.vue' import PublicPageMenuExternalDialog from './PublicPageMenuExternalDialog.vue'
const props = defineProps<{ defineProps<{
id: string id: string
label: string label: string
icon: string icon: string
@ -26,11 +30,13 @@ const emit = defineEmits<{
(e: 'click'): void (e: 'click'): void
}>() }>()
const showDialog = ref(false)
/** /**
* Open the "create federated share" dialog * Open the "create federated share" dialog
*/ */
function openDialog() { function openDialog() {
spawnDialog(PublicPageMenuExternalDialog, { label: props.label }) showDialog.value = true
emit('click') emit('click')
} }
</script> </script>