Skip to content

Commit 04da216

Browse files
committed
feat: add confirmation dialog for file extension changes
- Introduced a dialog to confirm if users want to proceed with changing the file extension. - Added handling for dialog visibility to prevent recursion. (Since it looks like use must press escape to stop rename???) Signed-off-by: nfebe <[email protected]>
1 parent 8fd7210 commit 04da216

File tree

1 file changed

+63
-3
lines changed

1 file changed

+63
-3
lines changed

apps/files/src/store/renaming.ts

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,61 @@ import type { RenamingStore } from '../types'
88
import axios, { isAxiosError } from '@nextcloud/axios'
99
import { emit, subscribe } from '@nextcloud/event-bus'
1010
import { NodeStatus } from '@nextcloud/files'
11+
import { DialogBuilder } from '@nextcloud/dialogs'
1112
import { t } from '@nextcloud/l10n'
12-
import { basename, dirname } from 'path'
13+
import { basename, dirname, extname } from 'path'
1314
import { defineStore } from 'pinia'
1415
import logger from '../logger'
1516
import Vue from 'vue'
17+
import IconCancel from '@mdi/svg/svg/cancel.svg?raw'
18+
import IconCheck from '@mdi/svg/svg/check.svg?raw'
1619

17-
export const useRenamingStore = function(...args) {
20+
let isDialogVisible = false
21+
22+
const showWarningDialog = (oldExtension: string, newExtension: string): Promise<boolean> => {
23+
if (isDialogVisible) {
24+
return Promise.resolve(false)
25+
}
26+
27+
isDialogVisible = true
28+
29+
return new Promise((resolve) => {
30+
const dialog = new DialogBuilder()
31+
.setName(t('files', 'Extension Change Warning'))
32+
.setText(t(
33+
'files',
34+
'You are attempting to change the file extension from "{old}" to "{new}". This may affect how the file is handled. Do you want to proceed?',
35+
{ old: oldExtension || t('files', 'none'), new: newExtension || t('files', 'none') }
36+
))
37+
.setButtons([
38+
{
39+
label: t('files', 'Cancel'),
40+
icon: IconCancel,
41+
type: 'secondary',
42+
callback: () => {
43+
isDialogVisible = false
44+
resolve(false)
45+
},
46+
},
47+
{
48+
label: t('files', 'Proceed'),
49+
icon: IconCheck,
50+
type: 'primary',
51+
callback: () => {
52+
isDialogVisible = false
53+
resolve(true)
54+
},
55+
},
56+
])
57+
.build()
58+
59+
dialog.show().then(() => {
60+
dialog.hide()
61+
})
62+
})
63+
}
64+
65+
export const useRenamingStore = function (...args) {
1866
const store = defineStore('renaming', {
1967
state: () => ({
2068
renamingNode: undefined,
@@ -36,6 +84,18 @@ export const useRenamingStore = function(...args) {
3684
const newName = this.newName.trim?.() || ''
3785
const oldName = this.renamingNode.basename
3886
const oldEncodedSource = this.renamingNode.encodedSource
87+
88+
// Check for extension change
89+
const oldExtension = extname(oldName)
90+
const newExtension = extname(newName)
91+
if (oldExtension !== newExtension) {
92+
const proceed = await showWarningDialog(oldExtension, newExtension)
93+
if (!proceed) {
94+
// User canceled, abort the operation
95+
return false
96+
}
97+
}
98+
3999
if (oldName === newName) {
40100
return false
41101
}
@@ -98,7 +158,7 @@ export const useRenamingStore = function(...args) {
98158

99159
// Make sure we only register the listeners once
100160
if (!renamingStore._initialized) {
101-
subscribe('files:node:rename', function(node: Node) {
161+
subscribe('files:node:rename', function (node: Node) {
102162
renamingStore.renamingNode = node
103163
renamingStore.newName = node.basename
104164
})

0 commit comments

Comments
 (0)