diff --git a/web/src/lib/components/faces-page/merge-suggestion-modal.svelte b/web/src/lib/components/faces-page/merge-suggestion-modal.svelte deleted file mode 100644 index 3aedfd3450d..00000000000 --- a/web/src/lib/components/faces-page/merge-suggestion-modal.svelte +++ /dev/null @@ -1,126 +0,0 @@ - - - - - {#if !choosePersonToMerge} - - - - - ([personMerge1, personMerge2] = [personMerge2, personMerge1])} - /> - - - { - if (potentialMergePeople.length > 0) { - choosePersonToMerge = !choosePersonToMerge; - } - }} - > - 0} - circle - shadow - url={getPeopleThumbnailUrl(personMerge2)} - altText={personMerge2.name} - widthStyle="100%" - /> - - {:else} - - - (choosePersonToMerge = false)}> - - - - {#each potentialMergePeople as person (person.id)} - - changePersonToMerge(person)}> - - - - {/each} - - - - {/if} - - - - {$t('are_these_the_same_person')} - - - {$t('they_will_be_merged_together')} - - - {#snippet stickyBottom()} - {$t('no')} - onConfirm([personMerge1, personMerge2])}> - {$t('yes')} - - {/snippet} - diff --git a/web/src/lib/constants.ts b/web/src/lib/constants.ts index bec3b0ceaab..e4603217e07 100644 --- a/web/src/lib/constants.ts +++ b/web/src/lib/constants.ts @@ -383,7 +383,6 @@ export enum PersonPageViewMode { VIEW_ASSETS = 'view-assets', SELECT_PERSON = 'select-person', MERGE_PEOPLE = 'merge-people', - SUGGEST_MERGE = 'suggest-merge', UNASSIGN_ASSETS = 'unassign-faces', } diff --git a/web/src/lib/modals/PersonMergeSuggestionModal.svelte b/web/src/lib/modals/PersonMergeSuggestionModal.svelte new file mode 100644 index 00000000000..e762b30c037 --- /dev/null +++ b/web/src/lib/modals/PersonMergeSuggestionModal.svelte @@ -0,0 +1,147 @@ + + + + + + {#if !choosePersonToMerge} + + + + + ([personToMerge, personToBeMergedInto] = [personToBeMergedInto, personToMerge])} + /> + + + { + if (potentialMergePeople.length > 0) { + choosePersonToMerge = !choosePersonToMerge; + } + }} + > + 0} + circle + shadow + url={getPeopleThumbnailUrl(personToBeMergedInto)} + altText={personToBeMergedInto.name} + widthStyle="100%" + /> + + {:else} + + + (choosePersonToMerge = false)}> + + + + {#each potentialMergePeople as person (person.id)} + + changePersonToMerge(person)}> + + + + {/each} + + + + {/if} + + + + {$t('are_these_the_same_person')} + + + {$t('they_will_be_merged_together')} + + + + + + onClose()}>{$t('no')} + + {$t('yes')} + + + + diff --git a/web/src/routes/(user)/people/+page.svelte b/web/src/routes/(user)/people/+page.svelte index f53d3646113..7ee95a5f7d0 100644 --- a/web/src/routes/(user)/people/+page.svelte +++ b/web/src/routes/(user)/people/+page.svelte @@ -3,9 +3,9 @@ import { page } from '$app/stores'; import { focusTrap } from '$lib/actions/focus-trap'; import { scrollMemory } from '$lib/actions/scroll-memory'; + import { shortcut } from '$lib/actions/shortcut'; import Icon from '$lib/components/elements/icon.svelte'; import ManagePeopleVisibility from '$lib/components/faces-page/manage-people-visibility.svelte'; - import MergeSuggestionModal from '$lib/components/faces-page/merge-suggestion-modal.svelte'; import PeopleCard from '$lib/components/faces-page/people-card.svelte'; import PeopleInfiniteScroll from '$lib/components/faces-page/people-infinite-scroll.svelte'; import SearchPeople from '$lib/components/faces-page/people-search.svelte'; @@ -17,19 +17,13 @@ import { ActionQueryParameterValue, AppRoute, QueryParameter, SessionStorageKey } from '$lib/constants'; import { modalManager } from '$lib/managers/modal-manager.svelte'; import PersonEditBirthDateModal from '$lib/modals/PersonEditBirthDateModal.svelte'; + import PersonMergeSuggestionModal from '$lib/modals/PersonMergeSuggestionModal.svelte'; import { locale } from '$lib/stores/preferences.store'; import { websocketEvents } from '$lib/stores/websocket'; import { handlePromiseError } from '$lib/utils'; import { handleError } from '$lib/utils/handle-error'; import { clearQueryParam } from '$lib/utils/navigation'; - import { - getAllPeople, - getPerson, - mergePerson, - searchPerson, - updatePerson, - type PersonResponseDto, - } from '@immich/sdk'; + import { getAllPeople, getPerson, searchPerson, updatePerson, type PersonResponseDto } from '@immich/sdk'; import { Button } from '@immich/ui'; import { mdiAccountOff, mdiEyeOutline } from '@mdi/js'; import { onMount } from 'svelte'; @@ -46,7 +40,6 @@ let selectHidden = $state(false); let searchName = $state(''); - let showMergeModal = $state(false); let newName = $state(''); let currentPage = $state(1); let nextPage = $state(data.people.hasNextPage ? 2 : null); @@ -131,42 +124,41 @@ } }; - const handleMergeSamePerson = async (response: [PersonResponseDto, PersonResponseDto]) => { - const [personToMerge, personToBeMergedIn] = response; - showMergeModal = false; - - if (!editingPerson) { + const handleMerge = async () => { + if (!editingPerson || !personMerge1 || !personMerge2) { return; } - try { - await mergePerson({ - id: personToBeMergedIn.id, - mergePersonDto: { ids: [personToMerge.id] }, - }); - const mergedPerson = await getPerson({ id: personToBeMergedIn.id }); + const response = await modalManager.show(PersonMergeSuggestionModal, { + personToMerge: personMerge1, + personToBeMergedInto: personMerge2, + potentialMergePeople, + }); - people = people.filter((person: PersonResponseDto) => person.id !== personToMerge.id); - people = people.map((person: PersonResponseDto) => (person.id === personToBeMergedIn.id ? mergedPerson : person)); - notificationController.show({ - message: $t('merge_people_successfully'), - type: NotificationType.Info, - }); - } catch (error) { - handleError(error, $t('errors.unable_to_save_name')); + if (!response) { + await updateName(personMerge1.id, newName); + return; } - if (personToBeMergedIn.name !== newName && editingPerson.id === personToBeMergedIn.id) { + + const [personToMerge, personToBeMergedInto] = response; + + const mergedPerson = await getPerson({ id: personToBeMergedInto.id }); + + people = people.filter((person: PersonResponseDto) => person.id !== personToMerge.id); + people = people.map((person: PersonResponseDto) => (person.id === personToBeMergedInto.id ? mergedPerson : person)); + + if (personToBeMergedInto.name !== newName && editingPerson.id === personToBeMergedInto.id) { /* * - * If the user merges one of the suggested people into the person he's editing it, it's merging the suggested person AND renames + * If the user merges one of the suggested people into the person he's editing, it's merging the suggested person AND renames * the person he's editing * */ try { - await updatePerson({ id: personToBeMergedIn.id, personUpdateDto: { name: newName } }); + await updatePerson({ id: personToBeMergedInto.id, personUpdateDto: { name: newName } }); for (const person of people) { - if (person.id === personToBeMergedIn.id) { + if (person.id === personToBeMergedInto.id) { person.name = newName; break; } @@ -263,7 +255,7 @@ const onNameChangeSubmit = async (name: string, targetPerson: PersonResponseDto) => { try { - if (name == targetPerson.name || showMergeModal) { + if (name == targetPerson.name) { return; } @@ -285,7 +277,7 @@ !person.isHidden, ) .slice(0, 3); - showMergeModal = true; + await handleMerge(); return; } await updateName(targetPerson.id, name); @@ -315,32 +307,10 @@ (person) => person.name.toLowerCase() === name.toLowerCase() && person.id !== personId && person.name, ); }; - - const handleMergeCancel = async () => { - if (!personMerge1) { - return; - } - - await updateName(personMerge1.id, newName); - showMergeModal = false; - }; -{#if showMergeModal && personMerge1 && personMerge2} - { - showMergeModal = false; - }} - onReject={() => handleMergeCancel()} - onConfirm={handleMergeSamePerson} - /> -{/if} - handleToggleFavorite(person)} /> - onNameChangeSubmit(newName, person)}> - onNameChangeInputFocus(person)} - onfocusout={() => onNameChangeSubmit(newName, person)} - oninput={(event) => onNameChangeInputUpdate(event)} - /> - + e.currentTarget.blur() }} + onfocusin={() => onNameChangeInputFocus(person)} + onfocusout={() => onNameChangeSubmit(newName, person)} + oninput={(event) => onNameChangeInputUpdate(event)} + /> {/snippet} diff --git a/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte index 70500ca755c..1c63cf8d05b 100644 --- a/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte +++ b/web/src/routes/(user)/people/[personId]/[[photos=photos]]/[[assetId=id]]/+page.svelte @@ -7,7 +7,6 @@ import ImageThumbnail from '$lib/components/assets/thumbnail/image-thumbnail.svelte'; import EditNameInput from '$lib/components/faces-page/edit-name-input.svelte'; import MergeFaceSelector from '$lib/components/faces-page/merge-face-selector.svelte'; - import MergeSuggestionModal from '$lib/components/faces-page/merge-suggestion-modal.svelte'; import UnMergeFaceSelector from '$lib/components/faces-page/unmerge-face-selector.svelte'; import AddToAlbum from '$lib/components/photos-page/actions/add-to-album.svelte'; import ArchiveAction from '$lib/components/photos-page/actions/archive-action.svelte'; @@ -32,6 +31,7 @@ import { AppRoute, PersonPageViewMode, QueryParameter, SessionStorageKey } from '$lib/constants'; import { modalManager } from '$lib/managers/modal-manager.svelte'; import PersonEditBirthDateModal from '$lib/modals/PersonEditBirthDateModal.svelte'; + import PersonMergeSuggestionModal from '$lib/modals/PersonMergeSuggestionModal.svelte'; import { AssetInteraction } from '$lib/stores/asset-interaction.svelte'; import { assetViewingStore } from '$lib/stores/asset-viewing.store'; import { AssetStore } from '$lib/stores/assets-store.svelte'; @@ -44,7 +44,6 @@ import { AssetVisibility, getPersonStatistics, - mergePerson, searchPerson, updatePerson, type AssetResponseDto, @@ -122,7 +121,7 @@ }); const handleEscape = async () => { - if ($showAssetViewer || viewMode === PersonPageViewMode.SUGGEST_MERGE) { + if ($showAssetViewer) { return; } if (assetInteraction.selectionActive) { @@ -220,31 +219,32 @@ viewMode = PersonPageViewMode.VIEW_ASSETS; }; - const handleMergeSamePerson = async (response: [PersonResponseDto, PersonResponseDto]) => { - const [personToMerge, personToBeMergedIn] = response; - viewMode = PersonPageViewMode.VIEW_ASSETS; - isEditingName = false; - try { - await mergePerson({ - id: personToBeMergedIn.id, - mergePersonDto: { ids: [personToMerge.id] }, - }); - notificationController.show({ - message: $t('merge_people_successfully'), - type: NotificationType.Info, - }); - people = people.filter((person: PersonResponseDto) => person.id !== personToMerge.id); - if (personToBeMergedIn.name != personName && person.id === personToBeMergedIn.id) { - await updateAssetCount(); - return; - } - await goto(`${AppRoute.PEOPLE}/${personToBeMergedIn.id}`, { replaceState: true }); - } catch (error) { - handleError(error, $t('errors.unable_to_save_name')); + const handleMergeSuggestion = async () => { + if (!personMerge1 || !personMerge2) { + return; } + + const result = await modalManager.show(PersonMergeSuggestionModal, { + personToMerge: personMerge1, + personToBeMergedInto: personMerge2, + potentialMergePeople, + }); + + if (!result) { + return; + } + + const [personToMerge, personToBeMergedInto] = result; + + people = people.filter((person: PersonResponseDto) => person.id !== personToMerge.id); + if (personToBeMergedInto.name != personName && person.id === personToBeMergedInto.id) { + await updateAssetCount(); + return; + } + await goto(`${AppRoute.PEOPLE}/${personToBeMergedInto.id}`, { replaceState: true }); }; - const handleSuggestPeople = (person2: PersonResponseDto) => { + const handleSuggestPeople = async (person2: PersonResponseDto) => { isEditingName = false; if (person.id !== person2.id) { potentialMergePeople = []; @@ -252,7 +252,8 @@ personMerge1 = person; personMerge2 = person2; isSuggestionSelectedByUser = true; - viewMode = PersonPageViewMode.SUGGEST_MERGE; + + await handleMergeSuggestion(); } }; @@ -280,9 +281,6 @@ }; const handleCancelEditName = () => { - if (viewMode === PersonPageViewMode.SUGGEST_MERGE) { - return; - } isSearchingPeople = false; isEditingName = false; }; @@ -317,7 +315,7 @@ !person.isHidden, ) .slice(0, 3); - viewMode = PersonPageViewMode.SUGGEST_MERGE; + await handleMergeSuggestion(); return; } await changeName(); @@ -382,7 +380,7 @@ onSelect={handleSelectFeaturePhoto} onEscape={handleEscape} > - {#if viewMode === PersonPageViewMode.VIEW_ASSETS || viewMode === PersonPageViewMode.SUGGEST_MERGE} + {#if viewMode === PersonPageViewMode.VIEW_ASSETS} {/if} -{#if viewMode === PersonPageViewMode.SUGGEST_MERGE && personMerge1 && personMerge2} - (viewMode = PersonPageViewMode.VIEW_ASSETS)} - onReject={changeName} - onConfirm={handleMergeSamePerson} - /> -{/if} - {#if viewMode === PersonPageViewMode.MERGE_PEOPLE} {/if} @@ -553,7 +540,7 @@ {:else} - {#if viewMode === PersonPageViewMode.VIEW_ASSETS || viewMode === PersonPageViewMode.SUGGEST_MERGE} + {#if viewMode === PersonPageViewMode.VIEW_ASSETS} goto(previousRoute)}> {#snippet trailing()}
{$t('they_will_be_merged_together')}