Skip to content

Commit

Permalink
Merge pull request #1176 from nextcloud-libraries/fix/conflict-picker
Browse files Browse the repository at this point in the history
fix(ConflictPicker): Allow to set recursive upload note + fix types for conflict utils functions
  • Loading branch information
susnux authored Apr 29, 2024
2 parents 9ec92b0 + c235aca commit 2101b60
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 15 deletions.
5 changes: 4 additions & 1 deletion l10n/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ msgstr ""
msgid "Existing version"
msgstr ""

msgid "If you select both versions, the copied file will have a number added to its name."
msgid "If you select both versions, the incoming file will have a number added to its name."
msgstr ""

msgid "Last modified date unknown"
Expand Down Expand Up @@ -87,6 +87,9 @@ msgstr ""
msgid "When an incoming folder is selected, any conflicting files within it will also be overwritten."
msgstr ""

msgid "When an incoming folder is selected, the content is written into the existing folder and a recursive conflict resolution is performed."
msgstr ""

msgid "Which files do you want to keep?"
msgstr ""

Expand Down
8 changes: 5 additions & 3 deletions lib/components/ConflictPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
<!-- Description -->
<p id="conflict-picker-description" class="conflict-picker__description">
{{ t('Which files do you want to keep?') }}<br>
{{ t('If you select both versions, the copied file will have a number added to its name.') }}
<template v-if="!recursiveUpload">
<br>
{{ t('If you select both versions, the incoming file will have a number added to its name.') }}<br>
<template v-if="recursiveUpload">
{{ t('When an incoming folder is selected, the content is written into the existing folder and a recursive conflict resolution is performed.') }}
</template>
<template v-else>
{{ t('When an incoming folder is selected, any conflicting files within it will also be overwritten.') }}
</template>
</p>
Expand Down
44 changes: 33 additions & 11 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ export { Upload, Status as UploadStatus } from './upload'

let _uploader: Uploader | null = null

export type ConflictResolutionResult = {
selected: (File|FileSystemEntry|Node)[],
renamed: (File|FileSystemEntry|Node)[],
export type ConflictResolutionResult<T extends File|FileSystemEntry|Node> = {
selected: T[],
renamed: T[],
}
/**
* Get an Uploader instance
Expand Down Expand Up @@ -47,14 +47,28 @@ export function upload(destinationPath: string, file: File): Uploader {
return uploader
}

interface ConflictPickerOptions {
/**
* When this is set to true a hint is shown that conflicts in directories are handles recursivly
* You still need to call this function for each directory separatly.
*/
recursive?: boolean
}

/**
* Open the conflict resolver
* @param {string} dirname the directory name
* @param {(File|Node)[]} conflicts the incoming files
* @param {Node[]} content all the existing files in the directory
* @param {ConflictPickerOptions} options Optional settings for the conflict picker
* @return {Promise<ConflictResolutionResult>} the selected and renamed files
*/
export async function openConflictPicker(dirname: string | undefined, conflicts: (File|FileSystemEntry|Node)[], content: Node[]): Promise<ConflictResolutionResult> {
export async function openConflictPicker<T extends File|FileSystemEntry|Node>(
dirname: string | undefined,
conflicts: T[],
content: Node[],
options?: ConflictPickerOptions,
): Promise<ConflictResolutionResult<T>> {
const ConflictPicker = defineAsyncComponent(() => import('./components/ConflictPicker.vue')) as AsyncComponent
return new Promise((resolve, reject) => {
const picker = new Vue({
Expand All @@ -64,9 +78,10 @@ export async function openConflictPicker(dirname: string | undefined, conflicts:
dirname,
conflicts,
content,
recursiveUpload: options?.recursive === true,
},
on: {
submit(results: ConflictResolutionResult) {
submit(results: ConflictResolutionResult<T>) {
// Return the results
resolve(results)

Expand Down Expand Up @@ -94,21 +109,28 @@ export async function openConflictPicker(dirname: string | undefined, conflicts:

/**
* Check if there is a conflict between two sets of files
* @param {(File|Node)[]} files the incoming files
* @param {Array<File|FileSystemEntry|Node>} files the incoming files
* @param {Node[]} content all the existing files in the directory
* @return {boolean} true if there is a conflict
*/
export function hasConflict(files: (File|FileSystemEntry|Node)[], content: Node[]): boolean {
// If the browser does not support the file system api we do not want a ReferenceError, so fallback to File
const SupportedFileSystemEntry = window.FileSystemEntry ?? File
return getConflicts(files, content).length > 0
}

/**
* Get the conflicts between two sets of files
* @param {Array<File|FileSystemEntry|Node>} files the incoming files
* @param {Node[]} content all the existing files in the directory
* @return {boolean} true if there is a conflict
*/
export function getConflicts<T extends File|FileSystemEntry|Node>(files: T[], content: Node[]): T[] {
const contentNames = content.map((node: Node) => node.basename)
const conflicts = files.filter((node: File|FileSystemEntry|Node) => {
const name = (node instanceof File || node instanceof SupportedFileSystemEntry) ? node.name : node.basename
const name = (node instanceof File || node instanceof FileSystemEntry) ? node.name : node.basename
return contentNames.indexOf(name) !== -1
}) as Node[]
})

return conflicts.length > 0
return conflicts
}

/** UploadPicker vue component */
Expand Down

0 comments on commit 2101b60

Please sign in to comment.