feat: cluster groups (#30739)

Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
This commit is contained in:
Jason Rasmussen
2026-08-20 20:03:00 +02:00
committed by GitHub
co-authored by Daniel Dietzler
parent f88fb628ff
commit 11b1aa5ecf
100 changed files with 4299 additions and 1006 deletions
+1 -1
View File
@@ -130,7 +130,7 @@ describe('/asset', () => {
});
await utils.createFace({
assetId: user1Assets[0].id,
personId: person1.id,
personGroupId: person1.id,
});
};
beforeAll(setupTests, 30_000);
+21 -21
View File
@@ -82,32 +82,32 @@ describe('/people', () => {
const asset4 = await utils.createAsset(admin.accessToken);
await Promise.all([
utils.createFace({ assetId: asset1.id, personId: visiblePerson.id }),
utils.createFace({ assetId: asset1.id, personId: hiddenPerson.id }),
utils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
utils.createFace({ assetId: asset1.id, personId: multipleAssetsPerson.id }),
utils.createFace({ assetId: asset2.id, personId: multipleAssetsPerson.id }),
utils.createFace({ assetId: asset3.id, personId: multipleAssetsPerson.id }), // 4 assets
utils.createFace({ assetId: asset1.id, personGroupId: visiblePerson.id }),
utils.createFace({ assetId: asset1.id, personGroupId: hiddenPerson.id }),
utils.createFace({ assetId: asset1.id, personGroupId: multipleAssetsPerson.id }),
utils.createFace({ assetId: asset1.id, personGroupId: multipleAssetsPerson.id }),
utils.createFace({ assetId: asset2.id, personGroupId: multipleAssetsPerson.id }),
utils.createFace({ assetId: asset3.id, personGroupId: multipleAssetsPerson.id }), // 4 assets
// Named persons
utils.createFace({ assetId: asset1.id, personId: nameCharliePerson.id }), // 1 asset
utils.createFace({ assetId: asset1.id, personId: nameBobPerson.id }),
utils.createFace({ assetId: asset2.id, personId: nameBobPerson.id }), // 2 assets
utils.createFace({ assetId: asset1.id, personId: nameAlicePerson.id }), // 1 asset
utils.createFace({ assetId: asset1.id, personGroupId: nameCharliePerson.id }), // 1 asset
utils.createFace({ assetId: asset1.id, personGroupId: nameBobPerson.id }),
utils.createFace({ assetId: asset2.id, personGroupId: nameBobPerson.id }), // 2 assets
utils.createFace({ assetId: asset1.id, personGroupId: nameAlicePerson.id }), // 1 asset
// Null-named person 4 assets
utils.createFace({ assetId: asset1.id, personId: nameNullPerson4Assets.id }),
utils.createFace({ assetId: asset2.id, personId: nameNullPerson4Assets.id }),
utils.createFace({ assetId: asset3.id, personId: nameNullPerson4Assets.id }),
utils.createFace({ assetId: asset4.id, personId: nameNullPerson4Assets.id }), // 4 assets
utils.createFace({ assetId: asset1.id, personGroupId: nameNullPerson4Assets.id }),
utils.createFace({ assetId: asset2.id, personGroupId: nameNullPerson4Assets.id }),
utils.createFace({ assetId: asset3.id, personGroupId: nameNullPerson4Assets.id }),
utils.createFace({ assetId: asset4.id, personGroupId: nameNullPerson4Assets.id }), // 4 assets
// Null-named person 3 assets
utils.createFace({ assetId: asset1.id, personId: nameNullPerson3Assets.id }),
utils.createFace({ assetId: asset2.id, personId: nameNullPerson3Assets.id }),
utils.createFace({ assetId: asset3.id, personId: nameNullPerson3Assets.id }), // 3 assets
utils.createFace({ assetId: asset1.id, personGroupId: nameNullPerson3Assets.id }),
utils.createFace({ assetId: asset2.id, personGroupId: nameNullPerson3Assets.id }),
utils.createFace({ assetId: asset3.id, personGroupId: nameNullPerson3Assets.id }), // 3 assets
// Null-named person 1 asset
utils.createFace({ assetId: asset3.id, personId: nameNullPerson1Asset.id }),
utils.createFace({ assetId: asset3.id, personGroupId: nameNullPerson1Asset.id }),
// Favourite People
utils.createFace({ assetId: asset1.id, personId: nameFreddyPersonFavourite.id }),
utils.createFace({ assetId: asset2.id, personId: nameFreddyPersonFavourite.id }),
utils.createFace({ assetId: asset1.id, personId: nameBillPersonFavourite.id }),
utils.createFace({ assetId: asset1.id, personGroupId: nameFreddyPersonFavourite.id }),
utils.createFace({ assetId: asset2.id, personGroupId: nameFreddyPersonFavourite.id }),
utils.createFace({ assetId: asset1.id, personGroupId: nameBillPersonFavourite.id }),
]);
});
+7 -3
View File
@@ -184,6 +184,8 @@ export const utils = {
'library',
'shared_link',
'person',
'person_group',
'cluster_group',
'album',
'asset',
'asset_face',
@@ -434,12 +436,12 @@ export const utils = {
return person;
},
createFace: async ({ assetId, personId }: { assetId: string; personId: string }) => {
createFace: async ({ assetId, personGroupId }: { assetId: string; personGroupId: string }) => {
if (!client) {
return;
}
await client.query('INSERT INTO asset_face ("assetId", "personId") VALUES ($1, $2)', [assetId, personId]);
await client.query('INSERT INTO asset_face ("assetId", "personGroupId") VALUES ($1, $2)', [assetId, personGroupId]);
},
setPersonThumbnail: async (personId: string) => {
@@ -447,7 +449,9 @@ export const utils = {
return;
}
await client.query(`UPDATE "person" set "thumbnailPath" = '/my/awesome/thumbnail.jpg' where "id" = $1`, [personId]);
await client.query(`UPDATE "person" set "thumbnailPath" = '/my/awesome/thumbnail.jpg' where "personGroupId" = $1`, [
personId,
]);
},
createSharedLink: (accessToken: string, dto: SharedLinkCreateDto) =>