refactor: library-exclusion-pattern-form modal (#18654)

Co-authored-by: Daniel Dietzler <36593685+danieldietzler@users.noreply.github.com>
This commit is contained in:
Arno 2025-05-29 16:50:11 +02:00 committed by GitHub
parent 44d49b9671
commit 2b1b20ab0b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 52 additions and 75 deletions

View File

@ -1,12 +1,13 @@
<script lang="ts"> <script lang="ts">
import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte'; import CircleIconButton from '$lib/components/elements/buttons/circle-icon-button.svelte';
import { modalManager } from '$lib/managers/modal-manager.svelte';
import LibraryExclusionPatternModal from '$lib/modals/LibraryExclusionPatternModal.svelte';
import { type LibraryResponseDto } from '@immich/sdk'; import { type LibraryResponseDto } from '@immich/sdk';
import { Button } from '@immich/ui'; import { Button } from '@immich/ui';
import { mdiPencilOutline } from '@mdi/js'; import { mdiPencilOutline } from '@mdi/js';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
import { handleError } from '../../utils/handle-error'; import { handleError } from '../../utils/handle-error';
import LibraryExclusionPatternForm from './library-exclusion-pattern-form.svelte';
interface Props { interface Props {
library: Partial<LibraryResponseDto>; library: Partial<LibraryResponseDto>;
@ -16,12 +17,6 @@
let { library = $bindable(), onCancel, onSubmit }: Props = $props(); let { library = $bindable(), onCancel, onSubmit }: Props = $props();
let addExclusionPattern = $state(false);
let editExclusionPattern: number | null = $state(null);
let exclusionPatternToAdd: string = $state('');
let editedExclusionPattern: string = $state('');
let exclusionPatterns: string[] = $state([]); let exclusionPatterns: string[] = $state([]);
onMount(() => { onMount(() => {
@ -32,11 +27,7 @@
} }
}); });
const handleAddExclusionPattern = () => { const handleAddExclusionPattern = (exclusionPatternToAdd: string) => {
if (!addExclusionPattern) {
return;
}
if (!library.exclusionPatterns) { if (!library.exclusionPatterns) {
library.exclusionPatterns = []; library.exclusionPatterns = [];
} }
@ -49,33 +40,24 @@
} }
} catch (error) { } catch (error) {
handleError(error, $t('errors.unable_to_add_exclusion_pattern')); handleError(error, $t('errors.unable_to_add_exclusion_pattern'));
} finally {
exclusionPatternToAdd = '';
addExclusionPattern = false;
} }
}; };
const handleEditExclusionPattern = () => { const handleEditExclusionPattern = (editedExclusionPattern: string, patternIndex: number) => {
if (editExclusionPattern === null) {
return;
}
if (!library.exclusionPatterns) { if (!library.exclusionPatterns) {
library.exclusionPatterns = []; library.exclusionPatterns = [];
} }
try { try {
library.exclusionPatterns[editExclusionPattern] = editedExclusionPattern; library.exclusionPatterns[patternIndex] = editedExclusionPattern;
exclusionPatterns = library.exclusionPatterns; exclusionPatterns = library.exclusionPatterns;
} catch (error) { } catch (error) {
handleError(error, $t('errors.unable_to_edit_exclusion_pattern')); handleError(error, $t('errors.unable_to_edit_exclusion_pattern'));
} finally {
editExclusionPattern = null;
} }
}; };
const handleDeleteExclusionPattern = () => { const handleDeleteExclusionPattern = (patternIndexToDelete?: number) => {
if (editExclusionPattern === null) { if (patternIndexToDelete === undefined) {
return; return;
} }
@ -84,13 +66,39 @@
library.exclusionPatterns = []; library.exclusionPatterns = [];
} }
const pathToDelete = library.exclusionPatterns[editExclusionPattern]; const patternToDelete = library.exclusionPatterns[patternIndexToDelete];
library.exclusionPatterns = library.exclusionPatterns.filter((path) => path != pathToDelete); library.exclusionPatterns = library.exclusionPatterns.filter((path) => path != patternToDelete);
exclusionPatterns = library.exclusionPatterns; exclusionPatterns = library.exclusionPatterns;
} catch (error) { } catch (error) {
handleError(error, $t('errors.unable_to_delete_exclusion_pattern')); handleError(error, $t('errors.unable_to_delete_exclusion_pattern'));
} finally { }
editExclusionPattern = null; };
const onEditExclusionPattern = async (patternIndexToEdit?: number) => {
const result = await modalManager.show(LibraryExclusionPatternModal, {
submitText: patternIndexToEdit === undefined ? $t('add') : $t('save'),
isEditing: patternIndexToEdit !== undefined,
exclusionPattern: patternIndexToEdit === undefined ? '' : exclusionPatterns[patternIndexToEdit],
exclusionPatterns,
});
if (!result) {
return;
}
switch (result.action) {
case 'submit': {
if (patternIndexToEdit === undefined) {
handleAddExclusionPattern(result.exclusionPattern);
} else {
handleEditExclusionPattern(result.exclusionPattern, patternIndexToEdit);
}
break;
}
case 'delete': {
handleDeleteExclusionPattern(patternIndexToEdit);
break;
}
} }
}; };
@ -100,28 +108,6 @@
}; };
</script> </script>
{#if addExclusionPattern}
<LibraryExclusionPatternForm
submitText={$t('add')}
bind:exclusionPattern={exclusionPatternToAdd}
{exclusionPatterns}
onSubmit={handleAddExclusionPattern}
onCancel={() => (addExclusionPattern = false)}
/>
{/if}
{#if editExclusionPattern != undefined}
<LibraryExclusionPatternForm
submitText={$t('save')}
isEditing={true}
bind:exclusionPattern={editedExclusionPattern}
{exclusionPatterns}
onSubmit={handleEditExclusionPattern}
onDelete={handleDeleteExclusionPattern}
onCancel={() => (editExclusionPattern = null)}
/>
{/if}
<form {onsubmit} autocomplete="off" class="m-4 flex flex-col gap-4"> <form {onsubmit} autocomplete="off" class="m-4 flex flex-col gap-4">
<table class="w-full text-start"> <table class="w-full text-start">
<tbody class="block w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray"> <tbody class="block w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray">
@ -136,10 +122,7 @@
icon={mdiPencilOutline} icon={mdiPencilOutline}
title={$t('edit_exclusion_pattern')} title={$t('edit_exclusion_pattern')}
size="16" size="16"
onclick={() => { onclick={() => onEditExclusionPattern(listIndex)}
editExclusionPattern = listIndex;
editedExclusionPattern = exclusionPattern;
}}
/> />
</td> </td>
</tr> </tr>
@ -153,13 +136,9 @@
{/if} {/if}
</td> </td>
<td class="w-1/4 text-ellipsis px-4 text-sm flex justify-center"> <td class="w-1/4 text-ellipsis px-4 text-sm flex justify-center">
<Button <Button size="small" shape="round" onclick={() => onEditExclusionPattern()}>
size="small" {$t('add_exclusion_pattern')}
shape="round" </Button>
onclick={() => {
addExclusionPattern = true;
}}>{$t('add_exclusion_pattern')}</Button
>
</td> </td>
</tr> </tr>
</tbody> </tbody>

View File

@ -9,9 +9,7 @@
exclusionPatterns?: string[]; exclusionPatterns?: string[];
isEditing?: boolean; isEditing?: boolean;
submitText?: string; submitText?: string;
onCancel: () => void; onClose: (data?: { action: 'delete' } | { action: 'submit'; exclusionPattern: string }) => void;
onSubmit: (exclusionPattern: string) => void;
onDelete?: () => void;
} }
let { let {
@ -19,9 +17,7 @@
exclusionPatterns = $bindable([]), exclusionPatterns = $bindable([]),
isEditing = false, isEditing = false,
submitText = $t('submit'), submitText = $t('submit'),
onCancel, onClose,
onSubmit,
onDelete,
}: Props = $props(); }: Props = $props();
onMount(() => { onMount(() => {
@ -36,12 +32,12 @@
const onsubmit = (event: Event) => { const onsubmit = (event: Event) => {
event.preventDefault(); event.preventDefault();
if (canSubmit) { if (canSubmit) {
onSubmit(exclusionPattern); onClose({ action: 'submit', exclusionPattern });
} }
}; };
</script> </script>
<Modal size="small" title={$t('add_exclusion_pattern')} icon={mdiFolderRemove} onClose={onCancel}> <Modal size="small" title={$t('add_exclusion_pattern')} icon={mdiFolderRemove} {onClose}>
<ModalBody> <ModalBody>
<form {onsubmit} autocomplete="off" id="add-exclusion-pattern-form"> <form {onsubmit} autocomplete="off" id="add-exclusion-pattern-form">
<p class="py-5 text-sm"> <p class="py-5 text-sm">
@ -68,13 +64,15 @@
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
<div class="flex gap-2 w-full"> <div class="flex gap-2 w-full">
<Button shape="round" color="secondary" fullWidth onclick={onCancel}>{$t('cancel')}</Button> <Button shape="round" color="secondary" fullWidth onclick={() => onClose()}>{$t('cancel')}</Button>
{#if isEditing} {#if isEditing}
<Button shape="round" color="danger" fullWidth onclick={onDelete}>{$t('delete')}</Button> <Button shape="round" color="danger" fullWidth onclick={() => onClose({ action: 'delete' })}
>{$t('delete')}</Button
>
{/if} {/if}
<Button shape="round" type="submit" disabled={!canSubmit} fullWidth form="add-exclusion-pattern-form" <Button shape="round" type="submit" disabled={!canSubmit} fullWidth form="add-exclusion-pattern-form">
>{submitText}</Button {submitText}
> </Button>
</div> </div>
</ModalFooter> </ModalFooter>
</Modal> </Modal>