From fc64be660347530c1b232af5f522c1ab073aa744 Mon Sep 17 00:00:00 2001 From: martin <74269598+martabal@users.noreply.github.com> Date: Sat, 23 Sep 2023 06:58:51 +0200 Subject: [PATCH] feat(web): suggest people when typing a name (#4126) * feat(web): suggest people when entering a name * fix: border size from 2 to 1 pixel * pr feedback * fix: web unit test * pr feedback --------- Co-authored-by: Alex --- .../faces-page/edit-name-input.svelte | 10 +- .../faces-page/merge-suggestion-modal.svelte | 15 +-- web/src/routes/(user)/people/+page.svelte | 13 +- .../(user)/people/[personId]/+page.svelte | 127 +++++++++++++----- 4 files changed, 117 insertions(+), 48 deletions(-) diff --git a/web/src/lib/components/faces-page/edit-name-input.svelte b/web/src/lib/components/faces-page/edit-name-input.svelte index de2be40d95..7b197b98f3 100644 --- a/web/src/lib/components/faces-page/edit-name-input.svelte +++ b/web/src/lib/components/faces-page/edit-name-input.svelte @@ -3,10 +3,10 @@ import { createEventDispatcher } from 'svelte'; import ImageThumbnail from '../assets/thumbnail/image-thumbnail.svelte'; import Button from '../elements/buttons/button.svelte'; - import { clickOutside } from '$lib/utils/click-outside'; export let person: PersonResponseDto; - let name = person.name; + export let name: string; + export let suggestedPeople = false; const dispatch = createEventDispatcher<{ change: string; @@ -15,9 +15,9 @@
dispatch('cancel')} + class="flex w-full place-items-center {suggestedPeople + ? 'rounded-t-lg border-b dark:border-immich-dark-gray' + : 'rounded-lg'} bg-gray-100 p-2 dark:bg-gray-700" > - personMerge2.name.toLowerCase() === person.name.toLowerCase() && - person.id !== personMerge2.id && - person.id !== personMerge1.id && - !person.isHidden, - ) - .slice(0, 3); + export let potentialMergePeople: PersonResponseDto[]; let choosePersonToMerge = false; @@ -48,7 +39,9 @@

Merge faces - {title}

- dispatch('close')} /> +
+ dispatch('close')} /> +
diff --git a/web/src/routes/(user)/people/+page.svelte b/web/src/routes/(user)/people/+page.svelte index b74578f488..c1371553a9 100644 --- a/web/src/routes/(user)/people/+page.svelte +++ b/web/src/routes/(user)/people/+page.svelte @@ -42,6 +42,7 @@ let personName = ''; let personMerge1: PersonResponseDto; let personMerge2: PersonResponseDto; + let potentialMergePeople: PersonResponseDto[] = []; let edittingPerson: PersonResponseDto | null = null; people.forEach((person: PersonResponseDto) => { @@ -248,6 +249,7 @@ }; const submitNameChange = async () => { + potentialMergePeople = []; showChangeNameModal = false; if (!edittingPerson || personName === edittingPerson.name) { return; @@ -264,6 +266,15 @@ if (existingPerson) { personMerge2 = existingPerson; showMergeModal = true; + potentialMergePeople = people + .filter( + (person: PersonResponseDto) => + personMerge2.name.toLowerCase() === person.name.toLowerCase() && + person.id !== personMerge2.id && + person.id !== personMerge1.id && + !person.isHidden, + ) + .slice(0, 3); return; } changeName(); @@ -332,7 +343,7 @@ (showMergeModal = false)} on:reject={() => changeName()} on:confirm={(event) => handleMergeSameFace(event.detail)} diff --git a/web/src/routes/(user)/people/[personId]/+page.svelte b/web/src/routes/(user)/people/[personId]/+page.svelte index f449b71784..ab6b5e6629 100644 --- a/web/src/routes/(user)/people/[personId]/+page.svelte +++ b/web/src/routes/(user)/people/[personId]/+page.svelte @@ -32,6 +32,7 @@ import DotsVertical from 'svelte-material-icons/DotsVertical.svelte'; import Plus from 'svelte-material-icons/Plus.svelte'; import type { PageData } from './$types'; + import { clickOutside } from '$lib/utils/click-outside'; export let data: PageData; @@ -58,12 +59,27 @@ let people = data.people.people; let personMerge1: PersonResponseDto; let personMerge2: PersonResponseDto; + let potentialMergePeople: PersonResponseDto[] = []; let personName = ''; + let name: string = data.person.name; + let suggestedPeople: PersonResponseDto[] = []; + $: isAllArchive = Array.from($selectedAssets).every((asset) => asset.isArchived); $: isAllFavorite = Array.from($selectedAssets).every((asset) => asset.isFavorite); + $: { + suggestedPeople = !name + ? [] + : people + .filter( + (person: PersonResponseDto) => + person.name.toLowerCase().startsWith(name.toLowerCase()) && person.id !== data.person.id, + ) + .slice(0, 5); + } + onMount(() => { const action = $page.url.searchParams.get('action'); if (action == 'merge') { @@ -147,6 +163,14 @@ } }; + const handleSuggestPeople = (person: PersonResponseDto) => { + isEditingName = false; + potentialMergePeople = []; + personMerge1 = data.person; + personMerge2 = person; + viewMode = ViewMode.SUGGEST_MERGE; + }; + const changeName = async () => { viewMode = ViewMode.VIEW_ASSETS; data.person.name = personName; @@ -183,6 +207,7 @@ }; const handleNameChange = async (name: string) => { + potentialMergePeople = []; personName = name; if (data.person.name === personName) { @@ -196,6 +221,15 @@ if (existingPerson) { personMerge2 = existingPerson; personMerge1 = data.person; + potentialMergePeople = people + .filter( + (person: PersonResponseDto) => + personMerge2.name.toLowerCase() === person.name.toLowerCase() && + person.id !== personMerge2.id && + person.id !== personMerge1.id && + !person.isHidden, + ) + .slice(0, 3); viewMode = ViewMode.SUGGEST_MERGE; return; } @@ -238,7 +272,7 @@ (viewMode = ViewMode.VIEW_ASSETS)} on:reject={() => changeName()} on:confirm={(event) => handleMergeSameFace(event.detail)} @@ -306,39 +340,70 @@ > {#if viewMode === ViewMode.VIEW_ASSETS || viewMode === ViewMode.SUGGEST_MERGE || viewMode === ViewMode.BIRTH_DATE} -
- {#if isEditingName} - handleNameChange(event.detail)} - on:cancel={() => handleCancelEditName()} - /> - {:else} - + {:else} + - + + {/if} +
+ {#if isEditingName} +
+ {#each suggestedPeople as person, index (person.id)} +
+ +
+ {/each} +
{/if} - +
{/if} {/key}