mirror of
https://github.com/nextcloud/server.git
synced 2026-06-09 00:32:29 -04:00
fix(files): Adjust getUniqueName for custom suffix and reuse for copy-move-action
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
parent
d2446762b5
commit
20331e4349
6 changed files with 43 additions and 41 deletions
|
|
@ -39,6 +39,7 @@ import FolderMoveSvg from '@mdi/svg/svg/folder-move.svg?raw'
|
|||
|
||||
import { MoveCopyAction, canCopy, canMove, getQueue } from './moveOrCopyActionUtils'
|
||||
import logger from '../logger'
|
||||
import { getUniqueName } from '../utils/fileUtils'
|
||||
|
||||
/**
|
||||
* Return the action that is possible for the given nodes
|
||||
|
|
@ -67,30 +68,6 @@ const getActionForNodes = (nodes: Node[]): MoveCopyAction => {
|
|||
* @return {Promise<void>} A promise that resolves when the copy/move is done
|
||||
*/
|
||||
export const handleCopyMoveNodeTo = async (node: Node, destination: Folder, method: MoveCopyAction.COPY | MoveCopyAction.MOVE, overwrite = false) => {
|
||||
/**
|
||||
* Create an unique name for a node
|
||||
* @param node Node that is copied
|
||||
* @param otherNodes Other nodes in the target directory to check for unique name
|
||||
* @return Either the node basename, if unique, or the name with a `(copy N)` suffix that is unique
|
||||
*/
|
||||
const makeUniqueName = (node: Node, otherNodes: Node[]|FileStat[]) => {
|
||||
const basename = node.basename.slice(0, node.basename.lastIndexOf('.'))
|
||||
let index = 0
|
||||
|
||||
const currentName = () => {
|
||||
switch (index) {
|
||||
case 0: return node.basename
|
||||
case 1: return `${basename} (copy)${node.extension ?? ''}`
|
||||
default: return `${basename} ${t('files', '(copy %n)', undefined, index)}${node.extension ?? ''}` // TRANSLATORS: Meaning it is the n'th copy of a file
|
||||
}
|
||||
}
|
||||
|
||||
while (otherNodes.some((other: Node|FileStat) => currentName() === other.basename)) {
|
||||
index += 1
|
||||
}
|
||||
return currentName()
|
||||
}
|
||||
|
||||
if (!destination) {
|
||||
return
|
||||
}
|
||||
|
|
@ -122,6 +99,13 @@ export const handleCopyMoveNodeTo = async (node: Node, destination: Folder, meth
|
|||
|
||||
const queue = getQueue()
|
||||
return await queue.add(async () => {
|
||||
const copySuffix = (index: number) => {
|
||||
if (index === 1) {
|
||||
return t('files', '(copy)') // TRANSLATORS: Mark a file as a copy of another file
|
||||
}
|
||||
return t('files', '(copy %n)', undefined, index) // TRANSLATORS: Meaning it is the n'th copy of a file
|
||||
}
|
||||
|
||||
try {
|
||||
const client = davGetClient()
|
||||
const currentPath = join(davRootPath, node.path)
|
||||
|
|
@ -132,7 +116,7 @@ export const handleCopyMoveNodeTo = async (node: Node, destination: Folder, meth
|
|||
// If we do not allow overwriting then find an unique name
|
||||
if (!overwrite) {
|
||||
const otherNodes = await client.getDirectoryContents(destinationPath) as FileStat[]
|
||||
target = makeUniqueName(node, otherNodes)
|
||||
target = getUniqueName(node.basename, otherNodes.map((n) => n.basename), copySuffix)
|
||||
}
|
||||
await client.copyFile(currentPath, join(destinationPath, target))
|
||||
// If the node is copied into current directory the view needs to be updated
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
*
|
||||
*/
|
||||
import type { Entry } from '@nextcloud/files'
|
||||
import type { TemplateFile } from './types'
|
||||
|
||||
import { Folder, Node, Permission, addNewFileMenuEntry, removeNewFileMenuEntry } from '@nextcloud/files'
|
||||
import { generateOcsUrl } from '@nextcloud/router'
|
||||
|
|
@ -35,7 +36,7 @@ import Vue from 'vue'
|
|||
import PlusSvg from '@mdi/svg/svg/plus.svg?raw'
|
||||
|
||||
import TemplatePickerView from './views/TemplatePicker.vue'
|
||||
import { getUniqueName } from './newMenu/newFolder'
|
||||
import { getUniqueName } from './utils/fileUtils.ts'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
|
||||
// Set up logger
|
||||
|
|
@ -58,7 +59,7 @@ TemplatePickerRoot.id = 'template-picker'
|
|||
document.body.appendChild(TemplatePickerRoot)
|
||||
|
||||
// Retrieve and init templates
|
||||
let templates = loadState('files', 'templates', [])
|
||||
let templates = loadState<TemplateFile[]>('files', 'templates', [])
|
||||
let templatesPath = loadState('files', 'templates_path', false)
|
||||
logger.debug('Templates providers', { templates })
|
||||
logger.debug('Templates folder', { templatesPath })
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
import MenuIcon from '@mdi/svg/svg/sun-compass.svg?raw'
|
||||
import { FileAction, addNewFileMenuEntry, registerDavProperty, registerFileAction } from '@nextcloud/files'
|
||||
import { addNewFileMenuEntry, registerDavProperty, registerFileAction } from '@nextcloud/files'
|
||||
|
||||
import { action as deleteAction } from './actions/deleteAction'
|
||||
import { action as downloadAction } from './actions/downloadAction'
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
import type { Entry, Node } from '@nextcloud/files'
|
||||
|
||||
import { basename, extname } from 'path'
|
||||
import { basename } from 'path'
|
||||
import { emit } from '@nextcloud/event-bus'
|
||||
import { getCurrentUser } from '@nextcloud/auth'
|
||||
import { Permission, Folder } from '@nextcloud/files'
|
||||
|
|
@ -31,6 +31,7 @@ import axios from '@nextcloud/axios'
|
|||
|
||||
import FolderPlusSvg from '@mdi/svg/svg/folder-plus.svg?raw'
|
||||
|
||||
import { getUniqueName } from '../utils/fileUtils.ts'
|
||||
import logger from '../logger'
|
||||
|
||||
type createFolderResponse = {
|
||||
|
|
@ -55,17 +56,6 @@ const createNewFolder = async (root: Folder, name: string): Promise<createFolder
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: move to @nextcloud/files
|
||||
export const getUniqueName = (name: string, names: string[]): string => {
|
||||
let newName = name
|
||||
let i = 1
|
||||
while (names.includes(newName)) {
|
||||
const ext = extname(name)
|
||||
newName = `${basename(name, ext)} (${i++})${ext}`
|
||||
}
|
||||
return newName
|
||||
}
|
||||
|
||||
export const entry = {
|
||||
id: 'newFolder',
|
||||
displayName: t('files', 'New folder'),
|
||||
|
|
|
|||
|
|
@ -111,3 +111,12 @@ export interface UploaderStore {
|
|||
export interface DragAndDropStore {
|
||||
dragging: FileId[]
|
||||
}
|
||||
|
||||
export interface TemplateFile {
|
||||
app: string
|
||||
label: string
|
||||
extension: string
|
||||
iconClass?: string
|
||||
mimetypes: string[]
|
||||
ratio?: number
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,25 @@
|
|||
*/
|
||||
import { FileType, type Node } from '@nextcloud/files'
|
||||
import { translate as t, translatePlural as n } from '@nextcloud/l10n'
|
||||
import { basename, extname } from 'path'
|
||||
|
||||
// TODO: move to @nextcloud/files
|
||||
/**
|
||||
* Create an unique file name
|
||||
* @param name The initial name to use
|
||||
* @param otherNames Other names that are already used
|
||||
* @param suffix A function that takes an index an returns a suffix to add, defaults to '(index)'
|
||||
* @return Either the initial name, if unique, or the name with the suffix so that the name is unique
|
||||
*/
|
||||
export const getUniqueName = (name: string, otherNames: string[], suffix = (n: number) => `(${n})`): string => {
|
||||
let newName = name
|
||||
let i = 1
|
||||
while (otherNames.includes(newName)) {
|
||||
const ext = extname(name)
|
||||
newName = `${basename(name, ext)} ${suffix(i++)}${ext}`
|
||||
}
|
||||
return newName
|
||||
}
|
||||
|
||||
export const encodeFilePath = function(path) {
|
||||
const pathSections = (path.startsWith('/') ? path : `/${path}`).split('/')
|
||||
|
|
|
|||
Loading…
Reference in a new issue