mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-04 03:39:37 -05:00 
			
		
		
		
	fix(web): new feature photo (#9443)
* fix: new feature photo * fix: use updatedAt
This commit is contained in:
		
							parent
							
								
									325aa1d392
								
							
						
					
					
						commit
						37b5d92110
					
				
							
								
								
									
										24
									
								
								mobile/openapi/lib/model/person_response_dto.dart
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										24
									
								
								mobile/openapi/lib/model/person_response_dto.dart
									
									
									
										generated
									
									
									
								
							@ -18,6 +18,7 @@ class PersonResponseDto {
 | 
				
			|||||||
    required this.isHidden,
 | 
					    required this.isHidden,
 | 
				
			||||||
    required this.name,
 | 
					    required this.name,
 | 
				
			||||||
    required this.thumbnailPath,
 | 
					    required this.thumbnailPath,
 | 
				
			||||||
 | 
					    this.updatedAt,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  DateTime? birthDate;
 | 
					  DateTime? birthDate;
 | 
				
			||||||
@ -30,13 +31,23 @@ class PersonResponseDto {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  String thumbnailPath;
 | 
					  String thumbnailPath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// This property was added in v1.107.0
 | 
				
			||||||
 | 
					  ///
 | 
				
			||||||
 | 
					  /// Please note: This property should have been non-nullable! Since the specification file
 | 
				
			||||||
 | 
					  /// does not include a default value (using the "default:" property), however, the generated
 | 
				
			||||||
 | 
					  /// source code must fall back to having a nullable type.
 | 
				
			||||||
 | 
					  /// Consider adding a "default:" property in the specification file to hide this note.
 | 
				
			||||||
 | 
					  ///
 | 
				
			||||||
 | 
					  DateTime? updatedAt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  bool operator ==(Object other) => identical(this, other) || other is PersonResponseDto &&
 | 
					  bool operator ==(Object other) => identical(this, other) || other is PersonResponseDto &&
 | 
				
			||||||
    other.birthDate == birthDate &&
 | 
					    other.birthDate == birthDate &&
 | 
				
			||||||
    other.id == id &&
 | 
					    other.id == id &&
 | 
				
			||||||
    other.isHidden == isHidden &&
 | 
					    other.isHidden == isHidden &&
 | 
				
			||||||
    other.name == name &&
 | 
					    other.name == name &&
 | 
				
			||||||
    other.thumbnailPath == thumbnailPath;
 | 
					    other.thumbnailPath == thumbnailPath &&
 | 
				
			||||||
 | 
					    other.updatedAt == updatedAt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  int get hashCode =>
 | 
					  int get hashCode =>
 | 
				
			||||||
@ -45,10 +56,11 @@ class PersonResponseDto {
 | 
				
			|||||||
    (id.hashCode) +
 | 
					    (id.hashCode) +
 | 
				
			||||||
    (isHidden.hashCode) +
 | 
					    (isHidden.hashCode) +
 | 
				
			||||||
    (name.hashCode) +
 | 
					    (name.hashCode) +
 | 
				
			||||||
    (thumbnailPath.hashCode);
 | 
					    (thumbnailPath.hashCode) +
 | 
				
			||||||
 | 
					    (updatedAt == null ? 0 : updatedAt!.hashCode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String toString() => 'PersonResponseDto[birthDate=$birthDate, id=$id, isHidden=$isHidden, name=$name, thumbnailPath=$thumbnailPath]';
 | 
					  String toString() => 'PersonResponseDto[birthDate=$birthDate, id=$id, isHidden=$isHidden, name=$name, thumbnailPath=$thumbnailPath, updatedAt=$updatedAt]';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Map<String, dynamic> toJson() {
 | 
					  Map<String, dynamic> toJson() {
 | 
				
			||||||
    final json = <String, dynamic>{};
 | 
					    final json = <String, dynamic>{};
 | 
				
			||||||
@ -61,6 +73,11 @@ class PersonResponseDto {
 | 
				
			|||||||
      json[r'isHidden'] = this.isHidden;
 | 
					      json[r'isHidden'] = this.isHidden;
 | 
				
			||||||
      json[r'name'] = this.name;
 | 
					      json[r'name'] = this.name;
 | 
				
			||||||
      json[r'thumbnailPath'] = this.thumbnailPath;
 | 
					      json[r'thumbnailPath'] = this.thumbnailPath;
 | 
				
			||||||
 | 
					    if (this.updatedAt != null) {
 | 
				
			||||||
 | 
					      json[r'updatedAt'] = this.updatedAt!.toUtc().toIso8601String();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					    //  json[r'updatedAt'] = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return json;
 | 
					    return json;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -77,6 +94,7 @@ class PersonResponseDto {
 | 
				
			|||||||
        isHidden: mapValueOfType<bool>(json, r'isHidden')!,
 | 
					        isHidden: mapValueOfType<bool>(json, r'isHidden')!,
 | 
				
			||||||
        name: mapValueOfType<String>(json, r'name')!,
 | 
					        name: mapValueOfType<String>(json, r'name')!,
 | 
				
			||||||
        thumbnailPath: mapValueOfType<String>(json, r'thumbnailPath')!,
 | 
					        thumbnailPath: mapValueOfType<String>(json, r'thumbnailPath')!,
 | 
				
			||||||
 | 
					        updatedAt: mapDateTime(json, r'updatedAt', r''),
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
 | 
				
			|||||||
@ -19,6 +19,7 @@ class PersonWithFacesResponseDto {
 | 
				
			|||||||
    required this.isHidden,
 | 
					    required this.isHidden,
 | 
				
			||||||
    required this.name,
 | 
					    required this.name,
 | 
				
			||||||
    required this.thumbnailPath,
 | 
					    required this.thumbnailPath,
 | 
				
			||||||
 | 
					    this.updatedAt,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  DateTime? birthDate;
 | 
					  DateTime? birthDate;
 | 
				
			||||||
@ -33,6 +34,15 @@ class PersonWithFacesResponseDto {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  String thumbnailPath;
 | 
					  String thumbnailPath;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// This property was added in v1.107.0
 | 
				
			||||||
 | 
					  ///
 | 
				
			||||||
 | 
					  /// Please note: This property should have been non-nullable! Since the specification file
 | 
				
			||||||
 | 
					  /// does not include a default value (using the "default:" property), however, the generated
 | 
				
			||||||
 | 
					  /// source code must fall back to having a nullable type.
 | 
				
			||||||
 | 
					  /// Consider adding a "default:" property in the specification file to hide this note.
 | 
				
			||||||
 | 
					  ///
 | 
				
			||||||
 | 
					  DateTime? updatedAt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  bool operator ==(Object other) => identical(this, other) || other is PersonWithFacesResponseDto &&
 | 
					  bool operator ==(Object other) => identical(this, other) || other is PersonWithFacesResponseDto &&
 | 
				
			||||||
    other.birthDate == birthDate &&
 | 
					    other.birthDate == birthDate &&
 | 
				
			||||||
@ -40,7 +50,8 @@ class PersonWithFacesResponseDto {
 | 
				
			|||||||
    other.id == id &&
 | 
					    other.id == id &&
 | 
				
			||||||
    other.isHidden == isHidden &&
 | 
					    other.isHidden == isHidden &&
 | 
				
			||||||
    other.name == name &&
 | 
					    other.name == name &&
 | 
				
			||||||
    other.thumbnailPath == thumbnailPath;
 | 
					    other.thumbnailPath == thumbnailPath &&
 | 
				
			||||||
 | 
					    other.updatedAt == updatedAt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  int get hashCode =>
 | 
					  int get hashCode =>
 | 
				
			||||||
@ -50,10 +61,11 @@ class PersonWithFacesResponseDto {
 | 
				
			|||||||
    (id.hashCode) +
 | 
					    (id.hashCode) +
 | 
				
			||||||
    (isHidden.hashCode) +
 | 
					    (isHidden.hashCode) +
 | 
				
			||||||
    (name.hashCode) +
 | 
					    (name.hashCode) +
 | 
				
			||||||
    (thumbnailPath.hashCode);
 | 
					    (thumbnailPath.hashCode) +
 | 
				
			||||||
 | 
					    (updatedAt == null ? 0 : updatedAt!.hashCode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String toString() => 'PersonWithFacesResponseDto[birthDate=$birthDate, faces=$faces, id=$id, isHidden=$isHidden, name=$name, thumbnailPath=$thumbnailPath]';
 | 
					  String toString() => 'PersonWithFacesResponseDto[birthDate=$birthDate, faces=$faces, id=$id, isHidden=$isHidden, name=$name, thumbnailPath=$thumbnailPath, updatedAt=$updatedAt]';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Map<String, dynamic> toJson() {
 | 
					  Map<String, dynamic> toJson() {
 | 
				
			||||||
    final json = <String, dynamic>{};
 | 
					    final json = <String, dynamic>{};
 | 
				
			||||||
@ -67,6 +79,11 @@ class PersonWithFacesResponseDto {
 | 
				
			|||||||
      json[r'isHidden'] = this.isHidden;
 | 
					      json[r'isHidden'] = this.isHidden;
 | 
				
			||||||
      json[r'name'] = this.name;
 | 
					      json[r'name'] = this.name;
 | 
				
			||||||
      json[r'thumbnailPath'] = this.thumbnailPath;
 | 
					      json[r'thumbnailPath'] = this.thumbnailPath;
 | 
				
			||||||
 | 
					    if (this.updatedAt != null) {
 | 
				
			||||||
 | 
					      json[r'updatedAt'] = this.updatedAt!.toUtc().toIso8601String();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					    //  json[r'updatedAt'] = null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return json;
 | 
					    return json;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -84,6 +101,7 @@ class PersonWithFacesResponseDto {
 | 
				
			|||||||
        isHidden: mapValueOfType<bool>(json, r'isHidden')!,
 | 
					        isHidden: mapValueOfType<bool>(json, r'isHidden')!,
 | 
				
			||||||
        name: mapValueOfType<String>(json, r'name')!,
 | 
					        name: mapValueOfType<String>(json, r'name')!,
 | 
				
			||||||
        thumbnailPath: mapValueOfType<String>(json, r'thumbnailPath')!,
 | 
					        thumbnailPath: mapValueOfType<String>(json, r'thumbnailPath')!,
 | 
				
			||||||
 | 
					        updatedAt: mapDateTime(json, r'updatedAt', r''),
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
 | 
				
			|||||||
@ -9345,6 +9345,11 @@
 | 
				
			|||||||
          },
 | 
					          },
 | 
				
			||||||
          "thumbnailPath": {
 | 
					          "thumbnailPath": {
 | 
				
			||||||
            "type": "string"
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "updatedAt": {
 | 
				
			||||||
 | 
					            "description": "This property was added in v1.107.0",
 | 
				
			||||||
 | 
					            "format": "date-time",
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "required": [
 | 
					        "required": [
 | 
				
			||||||
@ -9414,6 +9419,11 @@
 | 
				
			|||||||
          },
 | 
					          },
 | 
				
			||||||
          "thumbnailPath": {
 | 
					          "thumbnailPath": {
 | 
				
			||||||
            "type": "string"
 | 
					            "type": "string"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "updatedAt": {
 | 
				
			||||||
 | 
					            "description": "This property was added in v1.107.0",
 | 
				
			||||||
 | 
					            "format": "date-time",
 | 
				
			||||||
 | 
					            "type": "string"
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "required": [
 | 
					        "required": [
 | 
				
			||||||
 | 
				
			|||||||
@ -158,6 +158,8 @@ export type PersonWithFacesResponseDto = {
 | 
				
			|||||||
    isHidden: boolean;
 | 
					    isHidden: boolean;
 | 
				
			||||||
    name: string;
 | 
					    name: string;
 | 
				
			||||||
    thumbnailPath: string;
 | 
					    thumbnailPath: string;
 | 
				
			||||||
 | 
					    /** This property was added in v1.107.0 */
 | 
				
			||||||
 | 
					    updatedAt?: string;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export type SmartInfoResponseDto = {
 | 
					export type SmartInfoResponseDto = {
 | 
				
			||||||
    objects?: string[] | null;
 | 
					    objects?: string[] | null;
 | 
				
			||||||
@ -432,6 +434,8 @@ export type PersonResponseDto = {
 | 
				
			|||||||
    isHidden: boolean;
 | 
					    isHidden: boolean;
 | 
				
			||||||
    name: string;
 | 
					    name: string;
 | 
				
			||||||
    thumbnailPath: string;
 | 
					    thumbnailPath: string;
 | 
				
			||||||
 | 
					    /** This property was added in v1.107.0 */
 | 
				
			||||||
 | 
					    updatedAt?: string;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
export type AssetFaceResponseDto = {
 | 
					export type AssetFaceResponseDto = {
 | 
				
			||||||
    boundingBoxX1: number;
 | 
					    boundingBoxX1: number;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
import { ApiProperty } from '@nestjs/swagger';
 | 
					import { ApiProperty } from '@nestjs/swagger';
 | 
				
			||||||
import { Type } from 'class-transformer';
 | 
					import { Type } from 'class-transformer';
 | 
				
			||||||
import { IsArray, IsNotEmpty, IsString, MaxDate, ValidateNested } from 'class-validator';
 | 
					import { IsArray, IsNotEmpty, IsString, MaxDate, ValidateNested } from 'class-validator';
 | 
				
			||||||
 | 
					import { PropertyLifecycle } from 'src/decorators';
 | 
				
			||||||
import { AuthDto } from 'src/dtos/auth.dto';
 | 
					import { AuthDto } from 'src/dtos/auth.dto';
 | 
				
			||||||
import { AssetFaceEntity } from 'src/entities/asset-face.entity';
 | 
					import { AssetFaceEntity } from 'src/entities/asset-face.entity';
 | 
				
			||||||
import { PersonEntity } from 'src/entities/person.entity';
 | 
					import { PersonEntity } from 'src/entities/person.entity';
 | 
				
			||||||
@ -71,6 +72,8 @@ export class PersonResponseDto {
 | 
				
			|||||||
  birthDate!: Date | null;
 | 
					  birthDate!: Date | null;
 | 
				
			||||||
  thumbnailPath!: string;
 | 
					  thumbnailPath!: string;
 | 
				
			||||||
  isHidden!: boolean;
 | 
					  isHidden!: boolean;
 | 
				
			||||||
 | 
					  @PropertyLifecycle({ addedAt: 'v1.107.0' })
 | 
				
			||||||
 | 
					  updatedAt?: Date;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class PersonWithFacesResponseDto extends PersonResponseDto {
 | 
					export class PersonWithFacesResponseDto extends PersonResponseDto {
 | 
				
			||||||
@ -138,6 +141,7 @@ export function mapPerson(person: PersonEntity): PersonResponseDto {
 | 
				
			|||||||
    birthDate: person.birthDate,
 | 
					    birthDate: person.birthDate,
 | 
				
			||||||
    thumbnailPath: person.thumbnailPath,
 | 
					    thumbnailPath: person.thumbnailPath,
 | 
				
			||||||
    isHidden: person.isHidden,
 | 
					    isHidden: person.isHidden,
 | 
				
			||||||
 | 
					    updatedAt: person.updatedAt,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -42,6 +42,7 @@ const responseDto: PersonResponseDto = {
 | 
				
			|||||||
  birthDate: null,
 | 
					  birthDate: null,
 | 
				
			||||||
  thumbnailPath: '/path/to/thumbnail.jpg',
 | 
					  thumbnailPath: '/path/to/thumbnail.jpg',
 | 
				
			||||||
  isHidden: false,
 | 
					  isHidden: false,
 | 
				
			||||||
 | 
					  updatedAt: expect.any(Date),
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const statistics = { assets: 3 };
 | 
					const statistics = { assets: 3 };
 | 
				
			||||||
@ -126,6 +127,7 @@ describe(PersonService.name, () => {
 | 
				
			|||||||
            birthDate: null,
 | 
					            birthDate: null,
 | 
				
			||||||
            thumbnailPath: '/path/to/thumbnail.jpg',
 | 
					            thumbnailPath: '/path/to/thumbnail.jpg',
 | 
				
			||||||
            isHidden: true,
 | 
					            isHidden: true,
 | 
				
			||||||
 | 
					            updatedAt: expect.any(Date),
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
@ -255,6 +257,7 @@ describe(PersonService.name, () => {
 | 
				
			|||||||
        birthDate: new Date('1976-06-30'),
 | 
					        birthDate: new Date('1976-06-30'),
 | 
				
			||||||
        thumbnailPath: '/path/to/thumbnail.jpg',
 | 
					        thumbnailPath: '/path/to/thumbnail.jpg',
 | 
				
			||||||
        isHidden: false,
 | 
					        isHidden: false,
 | 
				
			||||||
 | 
					        updatedAt: expect.any(Date),
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
      expect(personMock.update).toHaveBeenCalledWith({ id: 'person-1', birthDate: new Date('1976-06-30') });
 | 
					      expect(personMock.update).toHaveBeenCalledWith({ id: 'person-1', birthDate: new Date('1976-06-30') });
 | 
				
			||||||
      expect(jobMock.queue).not.toHaveBeenCalled();
 | 
					      expect(jobMock.queue).not.toHaveBeenCalled();
 | 
				
			||||||
@ -407,6 +410,7 @@ describe(PersonService.name, () => {
 | 
				
			|||||||
        id: personStub.noName.id,
 | 
					        id: personStub.noName.id,
 | 
				
			||||||
        name: personStub.noName.name,
 | 
					        name: personStub.noName.name,
 | 
				
			||||||
        thumbnailPath: personStub.noName.thumbnailPath,
 | 
					        thumbnailPath: personStub.noName.thumbnailPath,
 | 
				
			||||||
 | 
					        updatedAt: expect.any(Date),
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      expect(jobMock.queue).not.toHaveBeenCalledWith();
 | 
					      expect(jobMock.queue).not.toHaveBeenCalledWith();
 | 
				
			||||||
 | 
				
			|||||||
@ -213,7 +213,7 @@
 | 
				
			|||||||
                <ImageThumbnail
 | 
					                <ImageThumbnail
 | 
				
			||||||
                  curve
 | 
					                  curve
 | 
				
			||||||
                  shadow
 | 
					                  shadow
 | 
				
			||||||
                  url={getPeopleThumbnailUrl(person.id)}
 | 
					                  url={getPeopleThumbnailUrl(person)}
 | 
				
			||||||
                  altText={person.name}
 | 
					                  altText={person.name}
 | 
				
			||||||
                  title={person.name}
 | 
					                  title={person.name}
 | 
				
			||||||
                  widthStyle="90px"
 | 
					                  widthStyle="90px"
 | 
				
			||||||
 | 
				
			|||||||
@ -108,7 +108,7 @@
 | 
				
			|||||||
                <ImageThumbnail
 | 
					                <ImageThumbnail
 | 
				
			||||||
                  curve
 | 
					                  curve
 | 
				
			||||||
                  shadow
 | 
					                  shadow
 | 
				
			||||||
                  url={getPeopleThumbnailUrl(person.id)}
 | 
					                  url={getPeopleThumbnailUrl(person)}
 | 
				
			||||||
                  altText={getPersonNameWithHiddenValue(person.name, person.isHidden)}
 | 
					                  altText={getPersonNameWithHiddenValue(person.name, person.isHidden)}
 | 
				
			||||||
                  title={getPersonNameWithHiddenValue(person.name, person.isHidden)}
 | 
					                  title={getPersonNameWithHiddenValue(person.name, person.isHidden)}
 | 
				
			||||||
                  widthStyle="90px"
 | 
					                  widthStyle="90px"
 | 
				
			||||||
 | 
				
			|||||||
@ -36,7 +36,7 @@
 | 
				
			|||||||
    class:dark:border-immich-dark-primary={border}
 | 
					    class:dark:border-immich-dark-primary={border}
 | 
				
			||||||
    class:border-immich-primary={border}
 | 
					    class:border-immich-primary={border}
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <ImageThumbnail {circle} url={getPeopleThumbnailUrl(person.id)} altText={person.name} widthStyle="100%" shadow />
 | 
					    <ImageThumbnail {circle} url={getPeopleThumbnailUrl(person)} altText={person.name} widthStyle="100%" shadow />
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <div
 | 
					  <div
 | 
				
			||||||
 | 
				
			|||||||
@ -38,7 +38,7 @@
 | 
				
			|||||||
        <ImageThumbnail
 | 
					        <ImageThumbnail
 | 
				
			||||||
          circle
 | 
					          circle
 | 
				
			||||||
          shadow
 | 
					          shadow
 | 
				
			||||||
          url={getPeopleThumbnailUrl(personMerge1.id)}
 | 
					          url={getPeopleThumbnailUrl(personMerge1)}
 | 
				
			||||||
          altText={personMerge1.name}
 | 
					          altText={personMerge1.name}
 | 
				
			||||||
          widthStyle="100%"
 | 
					          widthStyle="100%"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
@ -65,7 +65,7 @@
 | 
				
			|||||||
          border={potentialMergePeople.length > 0}
 | 
					          border={potentialMergePeople.length > 0}
 | 
				
			||||||
          circle
 | 
					          circle
 | 
				
			||||||
          shadow
 | 
					          shadow
 | 
				
			||||||
          url={getPeopleThumbnailUrl(personMerge2.id)}
 | 
					          url={getPeopleThumbnailUrl(personMerge2)}
 | 
				
			||||||
          altText={personMerge2.name}
 | 
					          altText={personMerge2.name}
 | 
				
			||||||
          widthStyle="100%"
 | 
					          widthStyle="100%"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
@ -84,7 +84,7 @@
 | 
				
			|||||||
                    border={true}
 | 
					                    border={true}
 | 
				
			||||||
                    circle
 | 
					                    circle
 | 
				
			||||||
                    shadow
 | 
					                    shadow
 | 
				
			||||||
                    url={getPeopleThumbnailUrl(person.id)}
 | 
					                    url={getPeopleThumbnailUrl(person)}
 | 
				
			||||||
                    altText={person.name}
 | 
					                    altText={person.name}
 | 
				
			||||||
                    widthStyle="100%"
 | 
					                    widthStyle="100%"
 | 
				
			||||||
                    on:click={() => changePersonToMerge(person)}
 | 
					                    on:click={() => changePersonToMerge(person)}
 | 
				
			||||||
 | 
				
			|||||||
@ -50,7 +50,7 @@
 | 
				
			|||||||
      <ImageThumbnail
 | 
					      <ImageThumbnail
 | 
				
			||||||
        shadow
 | 
					        shadow
 | 
				
			||||||
        {preload}
 | 
					        {preload}
 | 
				
			||||||
        url={getPeopleThumbnailUrl(person.id)}
 | 
					        url={getPeopleThumbnailUrl(person)}
 | 
				
			||||||
        altText={person.name}
 | 
					        altText={person.name}
 | 
				
			||||||
        title={person.name}
 | 
					        title={person.name}
 | 
				
			||||||
        widthStyle="100%"
 | 
					        widthStyle="100%"
 | 
				
			||||||
 | 
				
			|||||||
@ -234,7 +234,7 @@
 | 
				
			|||||||
                  <ImageThumbnail
 | 
					                  <ImageThumbnail
 | 
				
			||||||
                    curve
 | 
					                    curve
 | 
				
			||||||
                    shadow
 | 
					                    shadow
 | 
				
			||||||
                    url={getPeopleThumbnailUrl(selectedPersonToReassign[face.id].id)}
 | 
					                    url={getPeopleThumbnailUrl(selectedPersonToReassign[face.id])}
 | 
				
			||||||
                    altText={selectedPersonToReassign[face.id].name}
 | 
					                    altText={selectedPersonToReassign[face.id].name}
 | 
				
			||||||
                    title={getPersonNameWithHiddenValue(
 | 
					                    title={getPersonNameWithHiddenValue(
 | 
				
			||||||
                      selectedPersonToReassign[face.id].name,
 | 
					                      selectedPersonToReassign[face.id].name,
 | 
				
			||||||
@ -248,7 +248,7 @@
 | 
				
			|||||||
                  <ImageThumbnail
 | 
					                  <ImageThumbnail
 | 
				
			||||||
                    curve
 | 
					                    curve
 | 
				
			||||||
                    shadow
 | 
					                    shadow
 | 
				
			||||||
                    url={getPeopleThumbnailUrl(face.person.id)}
 | 
					                    url={getPeopleThumbnailUrl(face.person)}
 | 
				
			||||||
                    altText={face.person.name}
 | 
					                    altText={face.person.name}
 | 
				
			||||||
                    title={getPersonNameWithHiddenValue(face.person.name, face.person.isHidden)}
 | 
					                    title={getPersonNameWithHiddenValue(face.person.name, face.person.isHidden)}
 | 
				
			||||||
                    widthStyle={thumbnailWidth}
 | 
					                    widthStyle={thumbnailWidth}
 | 
				
			||||||
 | 
				
			|||||||
@ -71,13 +71,7 @@
 | 
				
			|||||||
              : 'border-transparent'}"
 | 
					              : 'border-transparent'}"
 | 
				
			||||||
            on:click={() => togglePersonSelection(person.id)}
 | 
					            on:click={() => togglePersonSelection(person.id)}
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <ImageThumbnail
 | 
					            <ImageThumbnail circle shadow url={getPeopleThumbnailUrl(person)} altText={person.name} widthStyle="100%" />
 | 
				
			||||||
              circle
 | 
					 | 
				
			||||||
              shadow
 | 
					 | 
				
			||||||
              url={getPeopleThumbnailUrl(person.id)}
 | 
					 | 
				
			||||||
              altText={person.name}
 | 
					 | 
				
			||||||
              widthStyle="100%"
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
            <p class="mt-2 line-clamp-2 text-sm font-medium dark:text-white">{person.name}</p>
 | 
					            <p class="mt-2 line-clamp-2 text-sm font-medium dark:text-white">{person.name}</p>
 | 
				
			||||||
          </button>
 | 
					          </button>
 | 
				
			||||||
        {/each}
 | 
					        {/each}
 | 
				
			||||||
 | 
				
			|||||||
@ -621,6 +621,7 @@
 | 
				
			|||||||
    "unable_to_save_settings": "Unable to save settings",
 | 
					    "unable_to_save_settings": "Unable to save settings",
 | 
				
			||||||
    "unable_to_scan_libraries": "Unable to scan libraries",
 | 
					    "unable_to_scan_libraries": "Unable to scan libraries",
 | 
				
			||||||
    "unable_to_scan_library": "Unable to scan library",
 | 
					    "unable_to_scan_library": "Unable to scan library",
 | 
				
			||||||
 | 
					    "unable_to_set_feature_photo": "Unable to set feature photo",
 | 
				
			||||||
    "unable_to_set_profile_picture": "Unable to set profile picture",
 | 
					    "unable_to_set_profile_picture": "Unable to set profile picture",
 | 
				
			||||||
    "unable_to_submit_job": "Unable to submit job",
 | 
					    "unable_to_submit_job": "Unable to submit job",
 | 
				
			||||||
    "unable_to_trash_asset": "Unable to trash asset",
 | 
					    "unable_to_trash_asset": "Unable to trash asset",
 | 
				
			||||||
 | 
				
			|||||||
@ -17,6 +17,7 @@ import {
 | 
				
			|||||||
  startOAuth,
 | 
					  startOAuth,
 | 
				
			||||||
  unlinkOAuthAccount,
 | 
					  unlinkOAuthAccount,
 | 
				
			||||||
  type AssetResponseDto,
 | 
					  type AssetResponseDto,
 | 
				
			||||||
 | 
					  type PersonResponseDto,
 | 
				
			||||||
  type SharedLinkResponseDto,
 | 
					  type SharedLinkResponseDto,
 | 
				
			||||||
} from '@immich/sdk';
 | 
					} from '@immich/sdk';
 | 
				
			||||||
import { mdiCogRefreshOutline, mdiDatabaseRefreshOutline, mdiImageRefreshOutline } from '@mdi/js';
 | 
					import { mdiCogRefreshOutline, mdiDatabaseRefreshOutline, mdiImageRefreshOutline } from '@mdi/js';
 | 
				
			||||||
@ -205,7 +206,8 @@ export const getAssetPlaybackUrl = (options: string | { id: string; checksum?: s
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export const getProfileImageUrl = (userId: string) => createUrl(getUserProfileImagePath(userId));
 | 
					export const getProfileImageUrl = (userId: string) => createUrl(getUserProfileImagePath(userId));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getPeopleThumbnailUrl = (personId: string) => createUrl(getPeopleThumbnailPath(personId));
 | 
					export const getPeopleThumbnailUrl = (person: PersonResponseDto, updatedAt?: string) =>
 | 
				
			||||||
 | 
					  createUrl(getPeopleThumbnailPath(person.id), { updatedAt: updatedAt ?? person.updatedAt });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getAssetJobName = derived(t, ($t) => {
 | 
					export const getAssetJobName = derived(t, ($t) => {
 | 
				
			||||||
  return (job: AssetJobName) => {
 | 
					  return (job: AssetJobName) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -61,7 +61,7 @@
 | 
				
			|||||||
              <ImageThumbnail
 | 
					              <ImageThumbnail
 | 
				
			||||||
                circle
 | 
					                circle
 | 
				
			||||||
                shadow
 | 
					                shadow
 | 
				
			||||||
                url={getPeopleThumbnailUrl(person.id)}
 | 
					                url={getPeopleThumbnailUrl(person)}
 | 
				
			||||||
                altText={person.name}
 | 
					                altText={person.name}
 | 
				
			||||||
                widthStyle="100%"
 | 
					                widthStyle="100%"
 | 
				
			||||||
              />
 | 
					              />
 | 
				
			||||||
 | 
				
			|||||||
@ -508,7 +508,7 @@
 | 
				
			|||||||
            preload={searchName !== '' || index < 20}
 | 
					            preload={searchName !== '' || index < 20}
 | 
				
			||||||
            bind:hidden={person.isHidden}
 | 
					            bind:hidden={person.isHidden}
 | 
				
			||||||
            shadow
 | 
					            shadow
 | 
				
			||||||
            url={getPeopleThumbnailUrl(person.id)}
 | 
					            url={getPeopleThumbnailUrl(person)}
 | 
				
			||||||
            altText={person.name}
 | 
					            altText={person.name}
 | 
				
			||||||
            widthStyle="100%"
 | 
					            widthStyle="100%"
 | 
				
			||||||
            bind:eyeColor={eyeColorMap[person.id]}
 | 
					            bind:eyeColor={eyeColorMap[person.id]}
 | 
				
			||||||
 | 
				
			|||||||
@ -91,7 +91,7 @@
 | 
				
			|||||||
  let refreshAssetGrid = false;
 | 
					  let refreshAssetGrid = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let personName = '';
 | 
					  let personName = '';
 | 
				
			||||||
  $: thumbnailData = getPeopleThumbnailUrl(data.person.id);
 | 
					  $: thumbnailData = getPeopleThumbnailUrl(data.person);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let name: string = data.person.name;
 | 
					  let name: string = data.person.name;
 | 
				
			||||||
  let suggestedPeople: PersonResponseDto[] = [];
 | 
					  let suggestedPeople: PersonResponseDto[] = [];
 | 
				
			||||||
@ -121,7 +121,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return websocketEvents.on('on_person_thumbnail', (personId: string) => {
 | 
					    return websocketEvents.on('on_person_thumbnail', (personId: string) => {
 | 
				
			||||||
      if (data.person.id === personId) {
 | 
					      if (data.person.id === personId) {
 | 
				
			||||||
        thumbnailData = getPeopleThumbnailUrl(data.person.id) + `?now=${Date.now()}`;
 | 
					        thumbnailData = getPeopleThumbnailUrl(data.person, Date.now().toString());
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
@ -206,10 +206,13 @@
 | 
				
			|||||||
    if (viewMode !== ViewMode.SELECT_PERSON) {
 | 
					    if (viewMode !== ViewMode.SELECT_PERSON) {
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
      await updatePerson({ id: data.person.id, personUpdateDto: { featureFaceAssetId: asset.id } });
 | 
					      await updatePerson({ id: data.person.id, personUpdateDto: { featureFaceAssetId: asset.id } });
 | 
				
			||||||
 | 
					 | 
				
			||||||
      notificationController.show({ message: $t('feature_photo_updated'), type: NotificationType.Info });
 | 
					      notificationController.show({ message: $t('feature_photo_updated'), type: NotificationType.Info });
 | 
				
			||||||
 | 
					    } catch (error) {
 | 
				
			||||||
 | 
					      handleError(error, $t('errors.unable_to_set_feature_photo'));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    assetInteractionStore.clearMultiselect();
 | 
					    assetInteractionStore.clearMultiselect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    viewMode = ViewMode.VIEW_ASSETS;
 | 
					    viewMode = ViewMode.VIEW_ASSETS;
 | 
				
			||||||
@ -525,7 +528,7 @@
 | 
				
			|||||||
                      <ImageThumbnail
 | 
					                      <ImageThumbnail
 | 
				
			||||||
                        circle
 | 
					                        circle
 | 
				
			||||||
                        shadow
 | 
					                        shadow
 | 
				
			||||||
                        url={getPeopleThumbnailUrl(person.id)}
 | 
					                        url={getPeopleThumbnailUrl(person)}
 | 
				
			||||||
                        altText={person.name}
 | 
					                        altText={person.name}
 | 
				
			||||||
                        widthStyle="2rem"
 | 
					                        widthStyle="2rem"
 | 
				
			||||||
                        heightStyle="2rem"
 | 
					                        heightStyle="2rem"
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user