1
0
mirror of https://github.com/immich-app/immich.git synced 2024-12-25 10:43:13 +02:00

fix(web): don't limit merge face selector to 10 people (#5551)

* fix: don't limit merge face selector to 10 people

* fix: don't use class to hide people in detail-panel

* fix: map faces and person in asset response
This commit is contained in:
martin 2023-12-08 15:21:29 +01:00 committed by GitHub
parent d2fbbe790b
commit 7b3465621f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 48 deletions

View File

@ -1,6 +1,6 @@
import { AssetEntity, AssetFaceEntity, AssetType } from '@app/infra/entities'; import { AssetEntity, AssetFaceEntity, AssetType } from '@app/infra/entities';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
import { PersonWithFacesResponseDto } from '../../person/person.dto'; import { PersonWithFacesResponseDto, mapFacesWithoutPerson, mapPerson } from '../../person/person.dto';
import { TagResponseDto, mapTag } from '../../tag'; import { TagResponseDto, mapTag } from '../../tag';
import { UserResponseDto, mapUser } from '../../user/response-dto/user-response.dto'; import { UserResponseDto, mapUser } from '../../user/response-dto/user-response.dto';
import { ExifResponseDto, mapExif } from './exif-response.dto'; import { ExifResponseDto, mapExif } from './exif-response.dto';
@ -62,7 +62,7 @@ const peopleWithFaces = (faces: AssetFaceEntity[]): PersonWithFacesResponseDto[]
if (existingPersonEntry) { if (existingPersonEntry) {
existingPersonEntry.faces.push(face); existingPersonEntry.faces.push(face);
} else { } else {
result.push({ ...face.person!, faces: [face] }); result.push({ ...mapPerson(face.person!), faces: [mapFacesWithoutPerson(face)] });
} }
} }
}); });

View File

@ -144,7 +144,7 @@ export function mapPerson(person: PersonEntity): PersonResponseDto {
}; };
} }
export function mapFaces(face: AssetFaceEntity, authUser: AuthUserDto): AssetFaceResponseDto { export function mapFacesWithoutPerson(face: AssetFaceEntity): AssetFaceWithoutPersonResponseDto {
return { return {
id: face.id, id: face.id,
imageHeight: face.imageHeight, imageHeight: face.imageHeight,
@ -153,6 +153,12 @@ export function mapFaces(face: AssetFaceEntity, authUser: AuthUserDto): AssetFac
boundingBoxX2: face.boundingBoxX2, boundingBoxX2: face.boundingBoxX2,
boundingBoxY1: face.boundingBoxY1, boundingBoxY1: face.boundingBoxY1,
boundingBoxY2: face.boundingBoxY2, boundingBoxY2: face.boundingBoxY2,
};
}
export function mapFaces(face: AssetFaceEntity, authUser: AuthUserDto): AssetFaceResponseDto {
return {
...mapFacesWithoutPerson(face),
person: face.person?.ownerId === authUser.id ? mapPerson(face.person) : null, person: face.person?.ownerId === authUser.id ? mapPerson(face.person) : null,
}; };
} }

View File

@ -228,51 +228,52 @@
<div class="mt-2 flex flex-wrap gap-2"> <div class="mt-2 flex flex-wrap gap-2">
{#each people as person, index (person.id)} {#each people as person, index (person.id)}
<div {#if showingHiddenPeople || !person.isHidden}
class="w-[90px]" <div
role="button" class="w-[90px]"
tabindex={index} role="button"
on:focus={() => ($boundingBoxesArray = people[index].faces)} tabindex={index}
on:mouseover={() => ($boundingBoxesArray = people[index].faces)} on:focus={() => ($boundingBoxesArray = people[index].faces)}
on:mouseleave={() => ($boundingBoxesArray = [])} on:mouseover={() => ($boundingBoxesArray = people[index].faces)}
> on:mouseleave={() => ($boundingBoxesArray = [])}
<a
href="/people/{person.id}?previousRoute={albumId ? `${AppRoute.ALBUMS}/${albumId}` : AppRoute.PHOTOS}"
class=" {!showingHiddenPeople && person.isHidden ? 'hidden' : ''}"
on:click={() => dispatch('close-viewer')}
> >
<div class="relative"> <a
<ImageThumbnail href="/people/{person.id}?previousRoute={albumId ? `${AppRoute.ALBUMS}/${albumId}` : AppRoute.PHOTOS}"
curve on:click={() => dispatch('close-viewer')}
shadow >
url={api.getPeopleThumbnailUrl(person.id)} <div class="relative">
altText={person.name} <ImageThumbnail
title={person.name} curve
widthStyle="90px" shadow
heightStyle="90px" url={api.getPeopleThumbnailUrl(person.id)}
thumbhash={null} altText={person.name}
hidden={person.isHidden} title={person.name}
/> widthStyle="90px"
</div> heightStyle="90px"
<p class="mt-1 truncate font-medium" title={person.name}>{person.name}</p> thumbhash={null}
{#if person.birthDate} hidden={person.isHidden}
{@const personBirthDate = DateTime.fromISO(person.birthDate)} />
<p </div>
class="font-light" <p class="mt-1 truncate font-medium" title={person.name}>{person.name}</p>
title={personBirthDate.toLocaleString( {#if person.birthDate}
{ {@const personBirthDate = DateTime.fromISO(person.birthDate)}
month: 'long', <p
day: 'numeric', class="font-light"
year: 'numeric', title={personBirthDate.toLocaleString(
}, {
{ locale: $locale }, month: 'long',
)} day: 'numeric',
> year: 'numeric',
Age {Math.floor(DateTime.fromISO(asset.fileCreatedAt).diff(personBirthDate, 'years').years)} },
</p> { locale: $locale },
{/if} )}
</a> >
</div> Age {Math.floor(DateTime.fromISO(asset.fileCreatedAt).diff(personBirthDate, 'years').years)}
</p>
{/if}
</a>
</div>
{/if}
{/each} {/each}
</div> </div>
</section> </section>

View File

@ -30,7 +30,9 @@
people = peopleCopy.filter( people = peopleCopy.filter(
(person) => !unselectedPeople.some((unselectedPerson) => unselectedPerson.id === person.id), (person) => !unselectedPeople.some((unselectedPerson) => unselectedPerson.id === person.id),
); );
people = searchNameLocal(name, people, 10); if (name) {
people = searchNameLocal(name, people, 10);
}
} }
const searchPeople = async (force: boolean) => { const searchPeople = async (force: boolean) => {