fix(web): Handle duplicate library settings gracefully (#6950)

* don't add duplicate import paths

* improve library import paths form

* same for exclusion patterns

* remove newline
This commit is contained in:
Jonathan Jogenfors 2024-02-09 01:09:09 +01:00 committed by GitHub
parent 90a7f16817
commit b67fddf4b8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 78 additions and 24 deletions

View File

@ -4,11 +4,22 @@
import FullScreenModal from '../shared-components/full-screen-modal.svelte'; import FullScreenModal from '../shared-components/full-screen-modal.svelte';
import Icon from '$lib/components/elements/icon.svelte'; import Icon from '$lib/components/elements/icon.svelte';
import { mdiFolderRemove } from '@mdi/js'; import { mdiFolderRemove } from '@mdi/js';
import { onMount } from 'svelte';
export let exclusionPattern: string; export let exclusionPattern: string;
export let canDelete = false; export let exclusionPatterns: string[] = [];
export let isEditing = false;
export let submitText = 'Submit'; export let submitText = 'Submit';
onMount(() => {
if (isEditing) {
exclusionPatterns = exclusionPatterns.filter((pattern) => pattern !== exclusionPattern);
}
});
$: isDuplicate = exclusionPattern !== null && exclusionPatterns.includes(exclusionPattern);
$: canSubmit = exclusionPattern !== '' && exclusionPattern !== null && !exclusionPatterns.includes(exclusionPattern);
const dispatch = createEventDispatcher<{ const dispatch = createEventDispatcher<{
cancel: void; cancel: void;
submit: { excludePattern: string }; submit: { excludePattern: string };
@ -49,11 +60,16 @@
</div> </div>
<div class="mt-8 flex w-full gap-4 px-4"> <div class="mt-8 flex w-full gap-4 px-4">
<Button color="gray" fullwidth on:click={() => handleCancel()}>Cancel</Button> <Button color="gray" fullwidth on:click={() => handleCancel()}>Cancel</Button>
{#if canDelete} {#if isEditing}
<Button color="red" fullwidth on:click={() => dispatch('delete')}>Delete</Button> <Button color="red" fullwidth on:click={() => dispatch('delete')}>Delete</Button>
{/if} {/if}
<Button type="submit" fullwidth>{submitText}</Button> <Button type="submit" disabled={!canSubmit} fullwidth>{submitText}</Button>
</div>
<div class="mt-8 flex w-full gap-4 px-4">
{#if isDuplicate}
<p class="text-red-500 text-sm">This exclusion pattern already exists.</p>
{/if}
</div> </div>
</form> </form>
</div> </div>

View File

@ -4,16 +4,27 @@
import Button from '../elements/buttons/button.svelte'; import Button from '../elements/buttons/button.svelte';
import FullScreenModal from '../shared-components/full-screen-modal.svelte'; import FullScreenModal from '../shared-components/full-screen-modal.svelte';
import { mdiFolderSync } from '@mdi/js'; import { mdiFolderSync } from '@mdi/js';
import { onMount } from 'svelte';
export let importPath: string; export let importPath: string | null;
export let importPaths: string[] = [];
export let title = 'Import path'; export let title = 'Import path';
export let cancelText = 'Cancel'; export let cancelText = 'Cancel';
export let submitText = 'Save'; export let submitText = 'Save';
export let canDelete = false; export let isEditing = false;
onMount(() => {
if (isEditing) {
importPaths = importPaths.filter((path) => path !== importPath);
}
});
$: isDuplicate = importPath !== null && importPaths.includes(importPath);
$: canSubmit = importPath !== '' && importPath !== null && !importPaths.includes(importPath);
const dispatch = createEventDispatcher<{ const dispatch = createEventDispatcher<{
cancel: void; cancel: void;
submit: { importPath: string }; submit: { importPath: string | null };
delete: void; delete: void;
}>(); }>();
const handleCancel = () => dispatch('cancel'); const handleCancel = () => dispatch('cancel');
@ -47,11 +58,17 @@
<div class="mt-8 flex w-full gap-4 px-4"> <div class="mt-8 flex w-full gap-4 px-4">
<Button color="gray" fullwidth on:click={() => handleCancel()}>{cancelText}</Button> <Button color="gray" fullwidth on:click={() => handleCancel()}>{cancelText}</Button>
{#if canDelete} {#if isEditing}
<Button color="red" fullwidth on:click={() => dispatch('delete')}>Delete</Button> <Button color="red" fullwidth on:click={() => dispatch('delete')}>Delete</Button>
{/if} {/if}
<Button type="submit" fullwidth>{submitText}</Button> <Button type="submit" disabled={!canSubmit} fullwidth>{submitText}</Button>
</div>
<div class="mt-8 flex w-full gap-4 px-4">
{#if isDuplicate}
<p class="text-red-500 text-sm">This import path already exists.</p>
{/if}
</div> </div>
</form> </form>
</div> </div>

View File

@ -13,7 +13,7 @@
let addImportPath = false; let addImportPath = false;
let editImportPath: number | null = null; let editImportPath: number | null = null;
let importPathToAdd: string; let importPathToAdd: string | null = null;
let editedImportPath: string; let editedImportPath: string;
let importPaths: string[] = []; let importPaths: string[] = [];
@ -39,7 +39,7 @@
}; };
const handleAddImportPath = async () => { const handleAddImportPath = async () => {
if (!addImportPath) { if (!addImportPath || !importPathToAdd) {
return; return;
} }
@ -48,12 +48,16 @@
} }
try { try {
library.importPaths.push(importPathToAdd); // Check so that import path isn't duplicated
importPaths = library.importPaths; if (!library.importPaths.includes(importPathToAdd)) {
library.importPaths.push(importPathToAdd);
importPaths = library.importPaths;
}
} catch (error) { } catch (error) {
handleError(error, 'Unable to remove import path'); handleError(error, 'Unable to add import path');
} finally { } finally {
addImportPath = false; addImportPath = false;
importPathToAdd = null;
} }
}; };
@ -67,8 +71,13 @@
} }
try { try {
library.importPaths[editImportPath] = editedImportPath; // Check so that import path isn't duplicated
importPaths = library.importPaths;
if (!library.importPaths.includes(editedImportPath)) {
// Update import path
library.importPaths[editImportPath] = editedImportPath;
importPaths = library.importPaths;
}
} catch (error) { } catch (error) {
editImportPath = null; editImportPath = null;
handleError(error, 'Unable to edit import path'); handleError(error, 'Unable to edit import path');
@ -103,9 +112,11 @@
title="Add Import Path" title="Add Import Path"
submitText="Add" submitText="Add"
bind:importPath={importPathToAdd} bind:importPath={importPathToAdd}
{importPaths}
on:submit={handleAddImportPath} on:submit={handleAddImportPath}
on:cancel={() => { on:cancel={() => {
addImportPath = false; addImportPath = false;
importPathToAdd = null;
}} }}
/> />
{/if} {/if}
@ -114,8 +125,9 @@
<LibraryImportPathForm <LibraryImportPathForm
title="Edit Import Path" title="Edit Import Path"
submitText="Save" submitText="Save"
canDelete={true} isEditing={true}
bind:importPath={editedImportPath} bind:importPath={editedImportPath}
{importPaths}
on:submit={handleEditImportPath} on:submit={handleEditImportPath}
on:delete={handleDeleteImportPath} on:delete={handleDeleteImportPath}
on:cancel={() => { on:cancel={() => {
@ -157,7 +169,11 @@
: 'bg-immich-bg dark:bg-immich-dark-gray/50' : 'bg-immich-bg dark:bg-immich-dark-gray/50'
}`} }`}
> >
<td class="w-4/5 text-ellipsis px-4 text-sm" /> <td class="w-4/5 text-ellipsis px-4 text-sm">
{#if importPaths.length === 0}
No paths added
{/if}</td
>
<td class="w-1/5 text-ellipsis px-4 text-sm" <td class="w-1/5 text-ellipsis px-4 text-sm"
><Button ><Button
type="button" type="button"

View File

@ -48,13 +48,16 @@
} }
try { try {
library.exclusionPatterns.push(exclusionPatternToAdd); // Check so that exclusion pattern isn't duplicated
exclusionPatternToAdd = ''; if (!library.exclusionPatterns.includes(exclusionPatternToAdd)) {
library.exclusionPatterns.push(exclusionPatternToAdd);
exclusionPatterns = library.exclusionPatterns; exclusionPatterns = library.exclusionPatterns;
addExclusionPattern = false; }
} catch (error) { } catch (error) {
handleError(error, 'Unable to add exclude pattern'); handleError(error, 'Unable to add exclusion pattern');
} finally {
exclusionPatternToAdd = '';
addExclusionPattern = false;
} }
}; };
@ -102,6 +105,7 @@
<LibraryExclusionPatternForm <LibraryExclusionPatternForm
submitText="Add" submitText="Add"
bind:exclusionPattern={exclusionPatternToAdd} bind:exclusionPattern={exclusionPatternToAdd}
{exclusionPatterns}
on:submit={handleAddExclusionPattern} on:submit={handleAddExclusionPattern}
on:cancel={() => { on:cancel={() => {
addExclusionPattern = false; addExclusionPattern = false;
@ -112,8 +116,9 @@
{#if editExclusionPattern != undefined} {#if editExclusionPattern != undefined}
<LibraryExclusionPatternForm <LibraryExclusionPatternForm
submitText="Save" submitText="Save"
canDelete={true} isEditing={true}
bind:exclusionPattern={editedExclusionPattern} bind:exclusionPattern={editedExclusionPattern}
{exclusionPatterns}
on:submit={handleEditExclusionPattern} on:submit={handleEditExclusionPattern}
on:delete={handleDeleteExclusionPattern} on:delete={handleDeleteExclusionPattern}
on:cancel={() => { on:cancel={() => {