mirror of
https://github.com/immich-app/immich.git
synced 2025-01-04 02:46:47 +01:00
pr feedback
This commit is contained in:
parent
7ced61e67d
commit
0f6e665d99
13 changed files with 58 additions and 16 deletions
|
@ -214,7 +214,7 @@ describe('/asset', () => {
|
|||
id: user1Assets[0].id,
|
||||
isFavorite: false,
|
||||
people: {
|
||||
faces: [
|
||||
visiblePeople: [
|
||||
{
|
||||
birthDate: null,
|
||||
id: expect.any(String),
|
||||
|
@ -484,7 +484,7 @@ describe('/asset', () => {
|
|||
id: user1Assets[0].id,
|
||||
isFavorite: true,
|
||||
people: {
|
||||
faces: [
|
||||
visiblePeople: [
|
||||
{
|
||||
birthDate: null,
|
||||
id: expect.any(String),
|
||||
|
|
|
@ -72,7 +72,7 @@ class AssetService {
|
|||
final AssetResponseDto? dto =
|
||||
await _apiService.assetApi.getAssetInfo(remoteId);
|
||||
|
||||
return dto?.people?.faces;
|
||||
return dto?.people?.visiblePeople;
|
||||
} catch (error, stack) {
|
||||
log.severe(
|
||||
'Error while getting remote asset info: ${error.toString()}',
|
||||
|
|
BIN
mobile/openapi/doc/PeopleWithFacesResponseDto.md
generated
BIN
mobile/openapi/doc/PeopleWithFacesResponseDto.md
generated
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -9014,19 +9014,19 @@
|
|||
},
|
||||
"PeopleWithFacesResponseDto": {
|
||||
"properties": {
|
||||
"faces": {
|
||||
"numberOfFaces": {
|
||||
"type": "integer"
|
||||
},
|
||||
"visiblePeople": {
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/PersonWithFacesResponseDto"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"numberOfFaces": {
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"faces",
|
||||
"numberOfFaces"
|
||||
"numberOfFaces",
|
||||
"visiblePeople"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
|
|
|
@ -101,8 +101,8 @@ export type PersonWithFacesResponseDto = {
|
|||
thumbnailPath: string;
|
||||
};
|
||||
export type PeopleWithFacesResponseDto = {
|
||||
faces: PersonWithFacesResponseDto[];
|
||||
numberOfFaces: number;
|
||||
visiblePeople: PersonWithFacesResponseDto[];
|
||||
};
|
||||
export type SmartInfoResponseDto = {
|
||||
objects?: string[] | null;
|
||||
|
|
|
@ -78,7 +78,7 @@ const peopleWithFaces = (faces: AssetFaceEntity[]): PeopleWithFacesResponseDto =
|
|||
}
|
||||
}
|
||||
|
||||
return { faces: result, numberOfFaces: faces.length };
|
||||
return { visiblePeople: result, numberOfFaces: faces.length };
|
||||
};
|
||||
|
||||
export function mapAsset(entity: AssetEntity, options: AssetMapOptions = {}): AssetResponseDto {
|
||||
|
|
|
@ -78,7 +78,7 @@ export class PersonWithFacesResponseDto extends PersonResponseDto {
|
|||
}
|
||||
|
||||
export class PeopleWithFacesResponseDto {
|
||||
faces!: PersonWithFacesResponseDto[];
|
||||
visiblePeople!: PersonWithFacesResponseDto[];
|
||||
@ApiProperty({ type: 'integer' })
|
||||
numberOfFaces!: number;
|
||||
}
|
||||
|
|
|
@ -449,6 +449,18 @@ describe(PersonService.name, () => {
|
|||
await expect(sut.unassignFace(authStub.admin, faceStub.face1.id)).resolves.toStrictEqual(
|
||||
mapFaces(faceStub.unassignedFace, authStub.admin),
|
||||
);
|
||||
|
||||
expect(mediaMock.generateThumbnail).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not unassign a face if user has no create access', async () => {
|
||||
personMock.getFaceById.mockResolvedValueOnce(faceStub.face1);
|
||||
accessMock.person.checkOwnerAccess.mockResolvedValue(new Set([personStub.noName.id]));
|
||||
personMock.reassignFace.mockResolvedValue(1);
|
||||
personMock.getRandomFace.mockResolvedValue(null);
|
||||
personMock.getFaceById.mockResolvedValueOnce(faceStub.unassignedFace);
|
||||
|
||||
await expect(sut.unassignFace(authStub.admin, faceStub.face1.id)).rejects.toBeInstanceOf(BadRequestException);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -465,6 +477,18 @@ describe(PersonService.name, () => {
|
|||
sut.unassignFaces(authStub.admin, { data: [{ assetId: faceStub.face1.id, personId: 'person-1' }] }),
|
||||
).resolves.toStrictEqual([{ id: 'assetFaceId1', success: true }]);
|
||||
});
|
||||
|
||||
it('should not unassign a face if the user has no create access', async () => {
|
||||
personMock.getFacesByIds.mockResolvedValueOnce([faceStub.face1]);
|
||||
accessMock.person.checkOwnerAccess.mockResolvedValue(new Set([personStub.noName.id]));
|
||||
personMock.reassignFace.mockResolvedValue(1);
|
||||
personMock.getRandomFace.mockResolvedValue(null);
|
||||
personMock.getFaceById.mockResolvedValueOnce(faceStub.unassignedFace);
|
||||
|
||||
await expect(
|
||||
sut.unassignFaces(authStub.admin, { data: [{ assetId: faceStub.face1.id, personId: 'person-1' }] }),
|
||||
).rejects.toBeInstanceOf(BadRequestException);
|
||||
});
|
||||
});
|
||||
|
||||
describe('handlePersonCleanup', () => {
|
||||
|
|
|
@ -218,7 +218,7 @@
|
|||
<div class="flex h-10 w-full items-center justify-between">
|
||||
<h2>PEOPLE</h2>
|
||||
<div class="flex gap-2 items-center">
|
||||
{#if people.faces.some((person) => person.isHidden)}
|
||||
{#if people.visiblePeople.some((person) => person.isHidden)}
|
||||
<CircleIconButton
|
||||
title="Show hidden people"
|
||||
icon={showingHiddenPeople ? mdiEyeOff : mdiEye}
|
||||
|
@ -239,7 +239,7 @@
|
|||
</div>
|
||||
|
||||
<div class="mt-2 flex flex-wrap gap-2">
|
||||
{#each people.faces as person (person.id)}
|
||||
{#each people.visiblePeople as person (person.id)}
|
||||
{#if showingHiddenPeople || !person.isHidden}
|
||||
<a
|
||||
class="w-[90px]"
|
||||
|
|
|
@ -64,6 +64,10 @@
|
|||
let loaderLoadingDoneTimeout: ReturnType<typeof setTimeout>;
|
||||
let automaticRefreshTimeout: ReturnType<typeof setTimeout>;
|
||||
|
||||
$: mapFacesToBeCreated = Object.entries(selectedPersonToAdd)
|
||||
.filter(([_, value]) => value.person === null)
|
||||
.map(([key, _]) => key);
|
||||
|
||||
const thumbnailWidth = '90px';
|
||||
|
||||
const generatePeopleWithoutFaces = async () => {
|
||||
|
@ -94,9 +98,23 @@
|
|||
isShowLoadingPeople = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* we wait for the server to create the feature photo for:
|
||||
* - people which has been reassigned to a new person
|
||||
* - faces removed assigned to a new person
|
||||
*
|
||||
* if after 15 seconds the server has not generated the feature photos,
|
||||
* we go back to the detail-panel
|
||||
*/
|
||||
const onPersonThumbnail = (personId: string) => {
|
||||
assetFaceGenerated.push(personId);
|
||||
if (isEqual(assetFaceGenerated, peopleToCreate) && loaderLoadingDoneTimeout && automaticRefreshTimeout) {
|
||||
|
||||
if (
|
||||
isEqual(assetFaceGenerated, peopleToCreate) &&
|
||||
isEqual(assetFaceGenerated, mapFacesToBeCreated) &&
|
||||
loaderLoadingDoneTimeout &&
|
||||
automaticRefreshTimeout
|
||||
) {
|
||||
clearTimeout(loaderLoadingDoneTimeout);
|
||||
clearTimeout(automaticRefreshTimeout);
|
||||
onRefresh();
|
||||
|
|
|
@ -45,7 +45,7 @@ export function getAltText(asset: AssetResponseDto) {
|
|||
altText += ` in ${asset.exifInfo.city}, ${asset.exifInfo.country}`;
|
||||
}
|
||||
|
||||
const names = asset.people?.faces.filter((p) => p.name).map((p) => p.name) ?? [];
|
||||
const names = asset.people?.visiblePeople.filter((p) => p.name).map((p) => p.name) ?? [];
|
||||
if (names.length == 1) {
|
||||
altText += ` with ${names[0]}`;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue