mirror of
				https://github.com/immich-app/immich.git
				synced 2025-10-31 10:49:11 -04: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:
		
							parent
							
								
									d2fbbe790b
								
							
						
					
					
						commit
						7b3465621f
					
				| @ -1,6 +1,6 @@ | ||||
| import { AssetEntity, AssetFaceEntity, AssetType } from '@app/infra/entities'; | ||||
| 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 { UserResponseDto, mapUser } from '../../user/response-dto/user-response.dto'; | ||||
| import { ExifResponseDto, mapExif } from './exif-response.dto'; | ||||
| @ -62,7 +62,7 @@ const peopleWithFaces = (faces: AssetFaceEntity[]): PersonWithFacesResponseDto[] | ||||
|         if (existingPersonEntry) { | ||||
|           existingPersonEntry.faces.push(face); | ||||
|         } else { | ||||
|           result.push({ ...face.person!, faces: [face] }); | ||||
|           result.push({ ...mapPerson(face.person!), faces: [mapFacesWithoutPerson(face)] }); | ||||
|         } | ||||
|       } | ||||
|     }); | ||||
|  | ||||
| @ -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 { | ||||
|     id: face.id, | ||||
|     imageHeight: face.imageHeight, | ||||
| @ -153,6 +153,12 @@ export function mapFaces(face: AssetFaceEntity, authUser: AuthUserDto): AssetFac | ||||
|     boundingBoxX2: face.boundingBoxX2, | ||||
|     boundingBoxY1: face.boundingBoxY1, | ||||
|     boundingBoxY2: face.boundingBoxY2, | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| export function mapFaces(face: AssetFaceEntity, authUser: AuthUserDto): AssetFaceResponseDto { | ||||
|   return { | ||||
|     ...mapFacesWithoutPerson(face), | ||||
|     person: face.person?.ownerId === authUser.id ? mapPerson(face.person) : null, | ||||
|   }; | ||||
| } | ||||
|  | ||||
| @ -228,51 +228,52 @@ | ||||
| 
 | ||||
|       <div class="mt-2 flex flex-wrap gap-2"> | ||||
|         {#each people as person, index (person.id)} | ||||
|           <div | ||||
|             class="w-[90px]" | ||||
|             role="button" | ||||
|             tabindex={index} | ||||
|             on:focus={() => ($boundingBoxesArray = people[index].faces)} | ||||
|             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')} | ||||
|           {#if showingHiddenPeople || !person.isHidden} | ||||
|             <div | ||||
|               class="w-[90px]" | ||||
|               role="button" | ||||
|               tabindex={index} | ||||
|               on:focus={() => ($boundingBoxesArray = people[index].faces)} | ||||
|               on:mouseover={() => ($boundingBoxesArray = people[index].faces)} | ||||
|               on:mouseleave={() => ($boundingBoxesArray = [])} | ||||
|             > | ||||
|               <div class="relative"> | ||||
|                 <ImageThumbnail | ||||
|                   curve | ||||
|                   shadow | ||||
|                   url={api.getPeopleThumbnailUrl(person.id)} | ||||
|                   altText={person.name} | ||||
|                   title={person.name} | ||||
|                   widthStyle="90px" | ||||
|                   heightStyle="90px" | ||||
|                   thumbhash={null} | ||||
|                   hidden={person.isHidden} | ||||
|                 /> | ||||
|               </div> | ||||
|               <p class="mt-1 truncate font-medium" title={person.name}>{person.name}</p> | ||||
|               {#if person.birthDate} | ||||
|                 {@const personBirthDate = DateTime.fromISO(person.birthDate)} | ||||
|                 <p | ||||
|                   class="font-light" | ||||
|                   title={personBirthDate.toLocaleString( | ||||
|                     { | ||||
|                       month: 'long', | ||||
|                       day: 'numeric', | ||||
|                       year: 'numeric', | ||||
|                     }, | ||||
|                     { locale: $locale }, | ||||
|                   )} | ||||
|                 > | ||||
|                   Age {Math.floor(DateTime.fromISO(asset.fileCreatedAt).diff(personBirthDate, 'years').years)} | ||||
|                 </p> | ||||
|               {/if} | ||||
|             </a> | ||||
|           </div> | ||||
|               <a | ||||
|                 href="/people/{person.id}?previousRoute={albumId ? `${AppRoute.ALBUMS}/${albumId}` : AppRoute.PHOTOS}" | ||||
|                 on:click={() => dispatch('close-viewer')} | ||||
|               > | ||||
|                 <div class="relative"> | ||||
|                   <ImageThumbnail | ||||
|                     curve | ||||
|                     shadow | ||||
|                     url={api.getPeopleThumbnailUrl(person.id)} | ||||
|                     altText={person.name} | ||||
|                     title={person.name} | ||||
|                     widthStyle="90px" | ||||
|                     heightStyle="90px" | ||||
|                     thumbhash={null} | ||||
|                     hidden={person.isHidden} | ||||
|                   /> | ||||
|                 </div> | ||||
|                 <p class="mt-1 truncate font-medium" title={person.name}>{person.name}</p> | ||||
|                 {#if person.birthDate} | ||||
|                   {@const personBirthDate = DateTime.fromISO(person.birthDate)} | ||||
|                   <p | ||||
|                     class="font-light" | ||||
|                     title={personBirthDate.toLocaleString( | ||||
|                       { | ||||
|                         month: 'long', | ||||
|                         day: 'numeric', | ||||
|                         year: 'numeric', | ||||
|                       }, | ||||
|                       { locale: $locale }, | ||||
|                     )} | ||||
|                   > | ||||
|                     Age {Math.floor(DateTime.fromISO(asset.fileCreatedAt).diff(personBirthDate, 'years').years)} | ||||
|                   </p> | ||||
|                 {/if} | ||||
|               </a> | ||||
|             </div> | ||||
|           {/if} | ||||
|         {/each} | ||||
|       </div> | ||||
|     </section> | ||||
|  | ||||
| @ -30,7 +30,9 @@ | ||||
|     people = peopleCopy.filter( | ||||
|       (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) => { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user