From ad9549106c6fdfeabec5229b071b4983fa3b537b Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Wed, 20 May 2026 15:46:11 +0200 Subject: [PATCH] feat(ConflictPicker): allow to set overwrite flag Some operations like MOVE will not write into folder like the upload, but will just replace one folder with another. Basically handle files and folders the same way. In this case we need to indicate that the whole folder is to-be-replaced. Signed-off-by: Ferdinand Thiessen --- l10n/messages.pot | 3 ++ .../ConflictPicker/ConflictPicker.vue | 8 +++++ lib/conflict-picker.ts | 7 ++++ tests/components/ConflictPicker.spec.ts | 36 ++++++++++++++++++- 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/l10n/messages.pot b/l10n/messages.pot index 7d8e0597b..637ae6139 100644 --- a/l10n/messages.pot +++ b/l10n/messages.pot @@ -208,6 +208,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, any 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 "" diff --git a/lib/components/ConflictPicker/ConflictPicker.vue b/lib/components/ConflictPicker/ConflictPicker.vue index 6920c86b9..6f78df9df 100644 --- a/lib/components/ConflictPicker/ConflictPicker.vue +++ b/lib/components/ConflictPicker/ConflictPicker.vue @@ -43,6 +43,11 @@ const props = defineProps<{ * If set to true no hint about overwriting directory content will be shown */ recursiveUpload?: boolean + + /** + * If set tot true a hint is shown that any folder content will be overwritten + */ + isOverwriting?: boolean }>() const emit = defineEmits<{ @@ -185,6 +190,9 @@ function onSubmit() { + diff --git a/lib/conflict-picker.ts b/lib/conflict-picker.ts index af9326f3b..5929f70fe 100644 --- a/lib/conflict-picker.ts +++ b/lib/conflict-picker.ts @@ -41,6 +41,12 @@ export interface ConflictPickerOptions { * You still need to call this function for each directory separately. */ recursive?: boolean + + /** + * When this is set to true a hint is shown that any folder content will be overwritten. + * This is useful if the operation with conflicts is a move that will not perform any "write-into" logic. + */ + overwriting?: boolean } /** @@ -84,6 +90,7 @@ export async function openConflictPicker( dirname, existing, incoming, + isOverwriting: options?.overwriting === true, recursiveUpload: options?.recursive === true, }, { container: options?.container, diff --git a/tests/components/ConflictPicker.spec.ts b/tests/components/ConflictPicker.spec.ts index f1fdb2d49..bccf15b8d 100644 --- a/tests/components/ConflictPicker.spec.ts +++ b/tests/components/ConflictPicker.spec.ts @@ -6,7 +6,7 @@ import type { ConflictInput, ConflictResolutionResult } from '../../lib/conflict-picker.ts' import { File as NcFile } from '@nextcloud/files' -import { cleanup, fireEvent, getAllByRole, getByRole, render } from '@testing-library/vue' +import { cleanup, findByText, fireEvent, getAllByRole, getByRole, render } from '@testing-library/vue' import { readFile } from 'fs/promises' import { join } from 'path' import { afterEach, beforeAll, describe, expect, test } from 'vitest' @@ -75,6 +75,40 @@ describe('ConflictPicker resolving', () => { ] }) + test('Show override hint', async () => { + const component = render(ConflictPicker, { + props: { + container: getContainer(), + dirname: 'Pictures', + existing: [old1, old2], + incoming: [...images], + }, + }) + + const dialog = getByRole(document.body, 'dialog') + expect(dialog).toBeInstanceOf(HTMLElement) + + await expect(findByText(dialog, /folder is selected, any conflicting files within it/)).resolves.not.toThrow() + + await component.rerender({ + container: getContainer(), + dirname: 'Pictures', + existing: [old1, old2], + incoming: [...images], + isOverwriting: true, + }) + await expect(findByText(dialog, /folder is selected, any files within it/)).resolves.not.toThrow() + + await component.rerender({ + container: getContainer(), + dirname: 'Pictures', + existing: [old1, old2], + incoming: [...images], + recursiveUpload: true, + }) + await expect(findByText(dialog, /folder is selected, the content is written into the existing folder/)).resolves.not.toThrow() + }) + test('Pick all incoming files', async () => { const component = render(ConflictPicker, { props: {