mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	fix: hide faces (#3352)
* fix: hide faces * remove unused variable * fix: work even if one fails * better style for hidden people * add hide face in the menu dropdown * add buttons to toggle visibility for all faces * add server test * close modal with escape key * fix: explore page * improve show & hide faces modal * keep name on people card * simplify layout * sticky app bar in show-hide page * fix format --------- Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
		@@ -1,6 +1,6 @@
 | 
			
		||||
import { AssetFaceEntity, PersonEntity } from '@app/infra/entities';
 | 
			
		||||
import { Transform } from 'class-transformer';
 | 
			
		||||
import { IsBoolean, IsOptional, IsString } from 'class-validator';
 | 
			
		||||
import { Transform, Type } from 'class-transformer';
 | 
			
		||||
import { IsArray, IsBoolean, IsNotEmpty, IsOptional, IsString, ValidateNested } from 'class-validator';
 | 
			
		||||
import { toBoolean, ValidateUUID } from '../domain.util';
 | 
			
		||||
 | 
			
		||||
export class PersonUpdateDto {
 | 
			
		||||
@@ -26,6 +26,43 @@ export class PersonUpdateDto {
 | 
			
		||||
  isHidden?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class PeopleUpdateDto {
 | 
			
		||||
  @IsArray()
 | 
			
		||||
  @ValidateNested({ each: true })
 | 
			
		||||
  @Type(() => PeopleUpdateItem)
 | 
			
		||||
  people!: PeopleUpdateItem[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class PeopleUpdateItem {
 | 
			
		||||
  /**
 | 
			
		||||
   * Person id.
 | 
			
		||||
   */
 | 
			
		||||
  @IsString()
 | 
			
		||||
  @IsNotEmpty()
 | 
			
		||||
  id!: string;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Person name.
 | 
			
		||||
   */
 | 
			
		||||
  @IsOptional()
 | 
			
		||||
  @IsString()
 | 
			
		||||
  name?: string;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Asset is used to get the feature face thumbnail.
 | 
			
		||||
   */
 | 
			
		||||
  @IsOptional()
 | 
			
		||||
  @IsString()
 | 
			
		||||
  featureFaceAssetId?: string;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Person visibility
 | 
			
		||||
   */
 | 
			
		||||
  @IsOptional()
 | 
			
		||||
  @IsBoolean()
 | 
			
		||||
  isHidden?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class MergePersonDto {
 | 
			
		||||
  @ValidateUUID({ each: true })
 | 
			
		||||
  ids!: string[];
 | 
			
		||||
 
 | 
			
		||||
@@ -188,6 +188,16 @@ describe(PersonService.name, () => {
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('updateAll', () => {
 | 
			
		||||
    it('should throw an error when personId is invalid', async () => {
 | 
			
		||||
      personMock.getById.mockResolvedValue(null);
 | 
			
		||||
      await expect(
 | 
			
		||||
        sut.updatePeople(authStub.admin, { people: [{ id: 'person-1', name: 'Person 1' }] }),
 | 
			
		||||
      ).resolves.toEqual([{ error: BulkIdErrorReason.UNKNOWN, id: 'person-1', success: false }]);
 | 
			
		||||
      expect(personMock.update).not.toHaveBeenCalled();
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  describe('handlePersonCleanup', () => {
 | 
			
		||||
    it('should delete people without faces', async () => {
 | 
			
		||||
      personMock.getAllWithoutFaces.mockResolvedValue([personStub.noName]);
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import {
 | 
			
		||||
  mapPerson,
 | 
			
		||||
  MergePersonDto,
 | 
			
		||||
  PeopleResponseDto,
 | 
			
		||||
  PeopleUpdateDto,
 | 
			
		||||
  PersonResponseDto,
 | 
			
		||||
  PersonSearchDto,
 | 
			
		||||
  PersonUpdateDto,
 | 
			
		||||
@@ -96,6 +97,24 @@ export class PersonService {
 | 
			
		||||
    return mapPerson(person);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async updatePeople(authUser: AuthUserDto, dto: PeopleUpdateDto): Promise<BulkIdResponseDto[]> {
 | 
			
		||||
    const results: BulkIdResponseDto[] = [];
 | 
			
		||||
    for (const person of dto.people) {
 | 
			
		||||
      try {
 | 
			
		||||
        await this.update(authUser, person.id, {
 | 
			
		||||
          isHidden: person.isHidden,
 | 
			
		||||
          name: person.name,
 | 
			
		||||
          featureFaceAssetId: person.featureFaceAssetId,
 | 
			
		||||
        }),
 | 
			
		||||
          results.push({ id: person.id, success: true });
 | 
			
		||||
      } catch (error: Error | any) {
 | 
			
		||||
        this.logger.error(`Unable to update ${person.id} : ${error}`, error?.stack);
 | 
			
		||||
        results.push({ id: person.id, success: false, error: BulkIdErrorReason.UNKNOWN });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return results;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async handlePersonCleanup() {
 | 
			
		||||
    const people = await this.repository.getAllWithoutFaces();
 | 
			
		||||
    for (const person of people) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user