From df27460f1cba7944177f92f44c369994fc0b3a63 Mon Sep 17 00:00:00 2001 From: Jason Rasmussen Date: Fri, 19 Jan 2024 12:09:18 -0500 Subject: [PATCH 1/9] fix: open api pump (#6502) --- docs/docs/developer/open-api.md | 8 ++------ misc/release/pump-version.sh | 2 +- mobile/openapi/README.md | Bin 24290 -> 24290 bytes open-api/immich-openapi-specs.json | 2 +- open-api/typescript-sdk/client/api.ts | 2 +- open-api/typescript-sdk/client/base.ts | 2 +- open-api/typescript-sdk/client/common.ts | 2 +- .../typescript-sdk/client/configuration.ts | 2 +- open-api/typescript-sdk/client/index.ts | 2 +- 9 files changed, 9 insertions(+), 13 deletions(-) diff --git a/docs/docs/developer/open-api.md b/docs/docs/developer/open-api.md index ca9473a649..2c29c7365b 100644 --- a/docs/docs/developer/open-api.md +++ b/docs/docs/developer/open-api.md @@ -7,11 +7,7 @@ Immich uses the [OpenAPI](https://swagger.io/specification/) standard to generat OpenAPI is used to generate the client (Typescript, Dart) SDK. `openapi-generator-cli` can be installed [here](https://openapi-generator.tech/docs/installation/). The generated SDK is based on the `immich-openapi-specs.json` file, which is autogenerated by the server **when running in development mode**. The `immich-openapi-specs.json` file can be modified with `@nestjs/swagger` decorators used or referenced by controller endpoints. See the [NestJS OpenAPI docs](https://docs.nestjs.com/openapi/types-and-parameters) for more info. When you add a new endpoint or modify an existing one, you must run the server in development mode and run the command below to update the client SDK. ```bash -npm run api:generate # Run from the `server/` directory +make open-api ``` -You can find the generated client SDK in the `web/src/api` for Typescript SDK and `mobile/openapi` for Dart SDK. - -:::tip -This can also be run via `make open-api` from the project root directory (not in the `server` folder) -::: +You can find the generated client SDK in the `open-api/typescript-sdk/client` for Typescript SDK and `mobile/openapi` for Dart SDK. diff --git a/misc/release/pump-version.sh b/misc/release/pump-version.sh index a237909713..3342372fc6 100755 --- a/misc/release/pump-version.sh +++ b/misc/release/pump-version.sh @@ -62,7 +62,7 @@ fi if [ "$CURRENT_SERVER" != "$NEXT_SERVER" ]; then echo "Pumping Server: $CURRENT_SERVER => $NEXT_SERVER" npm --prefix server version $SERVER_PUMP - npm --prefix server run api:generate + make open-api poetry --directory machine-learning version $SERVER_PUMP fi diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index 10e5ecd45c2a826d7702810cd2b09f300d4789ae..755f4afee1dcb7beff6041994c4d7fae0753cf51 100644 GIT binary patch delta 14 WcmaE~m+{eF#tCy64L8npjROESat4q9 delta 14 WcmaE~m+{eF#tCy64K~hojROESZ3d43 diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index e6be8b8e36..16f665d26f 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -6221,7 +6221,7 @@ "info": { "title": "Immich", "description": "Immich API", - "version": "1.93.0", + "version": "1.93.1", "contact": {} }, "tags": [], diff --git a/open-api/typescript-sdk/client/api.ts b/open-api/typescript-sdk/client/api.ts index 6f68d29e66..a899fda5ac 100644 --- a/open-api/typescript-sdk/client/api.ts +++ b/open-api/typescript-sdk/client/api.ts @@ -4,7 +4,7 @@ * Immich * Immich API * - * The version of the OpenAPI document: 1.93.0 + * The version of the OpenAPI document: 1.93.1 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/open-api/typescript-sdk/client/base.ts b/open-api/typescript-sdk/client/base.ts index 9743cb9594..d09d838319 100644 --- a/open-api/typescript-sdk/client/base.ts +++ b/open-api/typescript-sdk/client/base.ts @@ -4,7 +4,7 @@ * Immich * Immich API * - * The version of the OpenAPI document: 1.93.0 + * The version of the OpenAPI document: 1.93.1 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/open-api/typescript-sdk/client/common.ts b/open-api/typescript-sdk/client/common.ts index db34640578..ba40b6202a 100644 --- a/open-api/typescript-sdk/client/common.ts +++ b/open-api/typescript-sdk/client/common.ts @@ -4,7 +4,7 @@ * Immich * Immich API * - * The version of the OpenAPI document: 1.93.0 + * The version of the OpenAPI document: 1.93.1 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/open-api/typescript-sdk/client/configuration.ts b/open-api/typescript-sdk/client/configuration.ts index 9061ba1ed4..7e37412c4c 100644 --- a/open-api/typescript-sdk/client/configuration.ts +++ b/open-api/typescript-sdk/client/configuration.ts @@ -4,7 +4,7 @@ * Immich * Immich API * - * The version of the OpenAPI document: 1.93.0 + * The version of the OpenAPI document: 1.93.1 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). diff --git a/open-api/typescript-sdk/client/index.ts b/open-api/typescript-sdk/client/index.ts index c6ccd43fcd..3fd4a3b635 100644 --- a/open-api/typescript-sdk/client/index.ts +++ b/open-api/typescript-sdk/client/index.ts @@ -4,7 +4,7 @@ * Immich * Immich API * - * The version of the OpenAPI document: 1.93.0 + * The version of the OpenAPI document: 1.93.1 * * * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). From 07b874eddab9432af829ab8ecc2810d7796fdf9d Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 19 Jan 2024 11:34:20 -0600 Subject: [PATCH 2/9] fix(web): revert smart merge (#6504) * revert smart merge * fix test * fix test * Remove Slider file --- .../src/domain/person/person.service.spec.ts | 33 +-------- server/src/domain/person/person.service.ts | 16 +---- server/test/fixtures/person.stub.ts | 14 ---- .../admin-page/settings/setting-switch.svelte | 66 ++++++++++++++++- web/src/lib/components/elements/slider.svelte | 72 ------------------- .../faces-page/merge-face-selector.svelte | 7 +- web/src/routes/(user)/people/+page.svelte | 4 -- .../(user)/people/[personId]/+page.svelte | 9 +-- 8 files changed, 74 insertions(+), 147 deletions(-) delete mode 100644 web/src/lib/components/elements/slider.svelte diff --git a/server/src/domain/person/person.service.spec.ts b/server/src/domain/person/person.service.spec.ts index 0d289e783d..1b163b9432 100644 --- a/server/src/domain/person/person.service.spec.ts +++ b/server/src/domain/person/person.service.spec.ts @@ -999,7 +999,7 @@ describe(PersonService.name, () => { expect(accessMock.person.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['person-1'])); }); - it('should merge two people without smart merge', async () => { + it('should merge two people', async () => { personMock.getById.mockResolvedValueOnce(personStub.primaryPerson); personMock.getById.mockResolvedValueOnce(personStub.mergePerson); accessMock.person.checkOwnerAccess.mockResolvedValueOnce(new Set(['person-1'])); @@ -1014,33 +1014,6 @@ describe(PersonService.name, () => { oldPersonId: personStub.mergePerson.id, }); - expect(personMock.update).not.toHaveBeenCalled(); - - expect(accessMock.person.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['person-1'])); - }); - - it('should merge two people with smart merge', async () => { - personMock.getById.mockResolvedValueOnce(personStub.randomPerson); - personMock.getById.mockResolvedValueOnce(personStub.primaryPerson); - personMock.update.mockResolvedValue({ ...personStub.randomPerson, name: personStub.primaryPerson.name }); - accessMock.person.checkOwnerAccess.mockResolvedValueOnce(new Set(['person-3'])); - accessMock.person.checkOwnerAccess.mockResolvedValueOnce(new Set(['person-1'])); - - await expect(sut.mergePerson(authStub.admin, 'person-3', { ids: ['person-1'] })).resolves.toEqual([ - { id: 'person-1', success: true }, - ]); - - expect(personMock.reassignFaces).toHaveBeenCalledWith({ - newPersonId: personStub.randomPerson.id, - oldPersonId: personStub.primaryPerson.id, - }); - - expect(personMock.update).toHaveBeenCalledWith({ - id: personStub.randomPerson.id, - name: personStub.primaryPerson.name, - }); - - expect(personMock.delete).toHaveBeenCalledWith([personStub.primaryPerson]); expect(accessMock.person.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['person-1'])); }); @@ -1072,8 +1045,8 @@ describe(PersonService.name, () => { }); it('should handle an error reassigning faces', async () => { - personMock.getById.mockResolvedValueOnce(personStub.primaryPerson); - personMock.getById.mockResolvedValueOnce(personStub.mergePerson); + personMock.getById.mockResolvedValue(personStub.primaryPerson); + personMock.getById.mockResolvedValue(personStub.mergePerson); personMock.reassignFaces.mockRejectedValue(new Error('update failed')); accessMock.person.checkOwnerAccess.mockResolvedValueOnce(new Set(['person-1'])); accessMock.person.checkOwnerAccess.mockResolvedValueOnce(new Set(['person-2'])); diff --git a/server/src/domain/person/person.service.ts b/server/src/domain/person/person.service.ts index 561630e549..57ab27a5d8 100644 --- a/server/src/domain/person/person.service.ts +++ b/server/src/domain/person/person.service.ts @@ -533,7 +533,7 @@ export class PersonService { async mergePerson(auth: AuthDto, id: string, dto: MergePersonDto): Promise { const mergeIds = dto.ids; await this.access.requirePermission(auth, Permission.PERSON_WRITE, id); - let primaryPerson = await this.findOrFail(id); + const primaryPerson = await this.findOrFail(id); const primaryName = primaryPerson.name || primaryPerson.id; const results: BulkIdResponseDto[] = []; @@ -554,19 +554,6 @@ export class PersonService { continue; } - const update: Partial = {}; - if (!primaryPerson.name && mergePerson.name) { - update.name = mergePerson.name; - } - - if (!primaryPerson.birthDate && mergePerson.birthDate) { - update.birthDate = mergePerson.birthDate; - } - - if (Object.keys(update).length > 0) { - primaryPerson = await this.repository.update({ id: primaryPerson.id, ...update }); - } - const mergeName = mergePerson.name || mergePerson.id; const mergeData: UpdateFacesData = { oldPersonId: mergeId, newPersonId: id }; this.logger.log(`Merging ${mergeName} into ${primaryName}`); @@ -581,6 +568,7 @@ export class PersonService { results.push({ id: mergeId, success: false, error: BulkIdErrorReason.UNKNOWN }); } } + return results; } diff --git a/server/test/fixtures/person.stub.ts b/server/test/fixtures/person.stub.ts index ad83d68001..76e2d14f72 100644 --- a/server/test/fixtures/person.stub.ts +++ b/server/test/fixtures/person.stub.ts @@ -128,18 +128,4 @@ export const personStub = { faceAsset: null, isHidden: false, }), - randomPerson: Object.freeze({ - id: 'person-3', - createdAt: new Date('2021-01-01'), - updatedAt: new Date('2021-01-01'), - ownerId: userStub.admin.id, - owner: userStub.admin, - name: '', - birthDate: null, - thumbnailPath: '/path/to/thumbnail', - faces: [], - faceAssetId: null, - faceAsset: null, - isHidden: false, - }), }; diff --git a/web/src/lib/components/admin-page/settings/setting-switch.svelte b/web/src/lib/components/admin-page/settings/setting-switch.svelte index d26144913f..6797423a55 100644 --- a/web/src/lib/components/admin-page/settings/setting-switch.svelte +++ b/web/src/lib/components/admin-page/settings/setting-switch.svelte @@ -2,7 +2,6 @@ import { quintOut } from 'svelte/easing'; import { fly } from 'svelte/transition'; import { createEventDispatcher } from 'svelte'; - import Slider from '$lib/components/elements/slider.svelte'; export let title: string; export let subtitle = ''; @@ -11,6 +10,7 @@ export let isEdited = false; const dispatch = createEventDispatcher<{ toggle: boolean }>(); + const onToggle = (event: Event) => dispatch('toggle', (event.target as HTMLInputElement).checked);
@@ -31,5 +31,67 @@

{subtitle}

- dispatch('toggle', checked)} /> + + + + diff --git a/web/src/lib/components/elements/slider.svelte b/web/src/lib/components/elements/slider.svelte deleted file mode 100644 index 77fe3da940..0000000000 --- a/web/src/lib/components/elements/slider.svelte +++ /dev/null @@ -1,72 +0,0 @@ - - - - - diff --git a/web/src/lib/components/faces-page/merge-face-selector.svelte b/web/src/lib/components/faces-page/merge-face-selector.svelte index 5dd48b04c6..56c1b86e7c 100644 --- a/web/src/lib/components/faces-page/merge-face-selector.svelte +++ b/web/src/lib/components/faces-page/merge-face-selector.svelte @@ -26,7 +26,7 @@ let dispatch = createEventDispatcher<{ back: void; - merge: PersonResponseDto; + merge: void; }>(); $: hasSelection = selectedPeople.length > 0; @@ -68,17 +68,16 @@ const handleMerge = async () => { try { - let { data: results } = await api.personApi.mergePerson({ + const { data: results } = await api.personApi.mergePerson({ id: person.id, mergePersonDto: { ids: selectedPeople.map(({ id }) => id) }, }); - const { data: mergedPerson } = await api.personApi.getPerson({ id: person.id }); const count = results.filter(({ success }) => success).length; notificationController.show({ message: `Merged ${count} ${count === 1 ? 'person' : 'people'}`, type: NotificationType.Info, }); - dispatch('merge', mergedPerson); + dispatch('merge'); } catch (error) { handleError(error, 'Cannot merge people'); } finally { diff --git a/web/src/routes/(user)/people/+page.svelte b/web/src/routes/(user)/people/+page.svelte index 323b160a82..eec418c6ad 100644 --- a/web/src/routes/(user)/people/+page.svelte +++ b/web/src/routes/(user)/people/+page.svelte @@ -165,12 +165,8 @@ id: personMerge2.id, mergePersonDto: { ids: [personToMerge.id] }, }); - - const { data: mergedPerson } = await api.personApi.getPerson({ id: personToMerge.id }); - countVisiblePeople--; people = people.filter((person: PersonResponseDto) => person.id !== personToMerge.id); - people = people.map((person: PersonResponseDto) => (person.id === personMerge2.id ? mergedPerson : person)); notificationController.show({ message: 'Merge people succesfully', diff --git a/web/src/routes/(user)/people/[personId]/+page.svelte b/web/src/routes/(user)/people/[personId]/+page.svelte index 6d7bd77865..c97d3845cb 100644 --- a/web/src/routes/(user)/people/[personId]/+page.svelte +++ b/web/src/routes/(user)/people/[personId]/+page.svelte @@ -185,13 +185,8 @@ } }; - const handleMerge = async (person: PersonResponseDto) => { - const { data: statistics } = await api.personApi.getPersonStatistics({ id: person.id }); - numberOfAssets = statistics.assets; + const handleMerge = () => { handleGoBack(); - - data.person = person; - refreshAssetGrid = !refreshAssetGrid; }; @@ -379,7 +374,7 @@ {/if} {#if viewMode === ViewMode.MERGE_PEOPLE} - handleMerge(detail)} /> + {/if}
From d15c443d9bfed2502d57847a38221c7595455413 Mon Sep 17 00:00:00 2001 From: martin <74269598+martabal@users.noreply.github.com> Date: Fri, 19 Jan 2024 18:38:44 +0100 Subject: [PATCH 3/9] fix(web): user list when sharing an album (#6500) fix: user list when sharing an album Co-authored-by: Alex Tran --- .../lib/components/album-page/user-selection-modal.svelte | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/web/src/lib/components/album-page/user-selection-modal.svelte b/web/src/lib/components/album-page/user-selection-modal.svelte index b7c896fdf3..c5c3c083ff 100644 --- a/web/src/lib/components/album-page/user-selection-modal.svelte +++ b/web/src/lib/components/album-page/user-selection-modal.svelte @@ -92,10 +92,11 @@ class="flex w-full place-items-center gap-4 px-5 py-4 transition-all hover:bg-gray-200 dark:hover:bg-gray-700" > {#if selectedUsers.includes(user)} - +

+ {:else} {/if} From f80f867976be460859064bc84e929bdc685002a4 Mon Sep 17 00:00:00 2001 From: shenlong <139912620+shenlong-tanwen@users.noreply.github.com> Date: Fri, 19 Jan 2024 17:40:10 +0000 Subject: [PATCH 4/9] fix(mobile): stack button not in bottom app bar (#6497) Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> --- mobile/lib/modules/home/ui/control_bottom_app_bar.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mobile/lib/modules/home/ui/control_bottom_app_bar.dart b/mobile/lib/modules/home/ui/control_bottom_app_bar.dart index 119a94d9e7..12c06eaefd 100644 --- a/mobile/lib/modules/home/ui/control_bottom_app_bar.dart +++ b/mobile/lib/modules/home/ui/control_bottom_app_bar.dart @@ -197,7 +197,7 @@ class ControlBottomAppBar extends ConsumerWidget { label: "control_bottom_app_bar_edit_location".tr(), onPressed: enabled ? onEditLocation : null, ), - if (!hasLocal && + if (!selectionAssetState.hasLocal && selectionAssetState.selectedCount > 1 && onStack != null) ControlBoxButton( @@ -211,7 +211,7 @@ class ControlBottomAppBar extends ConsumerWidget { label: 'album_viewer_appbar_share_remove'.tr(), onPressed: enabled ? onRemoveFromAlbum : null, ), - if (hasLocal) + if (selectionAssetState.hasLocal) ControlBoxButton( iconData: Icons.backup_outlined, label: "Upload", From 17eaeb695eb720d4dbfc28e768995cabef5ffbae Mon Sep 17 00:00:00 2001 From: martin <74269598+martabal@users.noreply.github.com> Date: Fri, 19 Jan 2024 18:52:26 +0100 Subject: [PATCH 5/9] feat: smart merge (#6508) * pr feedback * fix: tests * update assets statistics * pr feedback * pr feedback * fix: linter * pr feedback * fix: don't limit the smart merge * pr feedback * fix: server code * remove slider * fix: tests --------- Co-authored-by: Jason Rasmussen --- .../src/domain/person/person.service.spec.ts | 30 +++++++++++++++++-- server/src/domain/person/person.service.ts | 16 ++++++++-- server/test/fixtures/person.stub.ts | 14 +++++++++ .../faces-page/merge-face-selector.svelte | 7 +++-- web/src/routes/(user)/people/+page.svelte | 4 +++ .../(user)/people/[personId]/+page.svelte | 9 ++++-- 6 files changed, 70 insertions(+), 10 deletions(-) diff --git a/server/src/domain/person/person.service.spec.ts b/server/src/domain/person/person.service.spec.ts index 1b163b9432..c28af12613 100644 --- a/server/src/domain/person/person.service.spec.ts +++ b/server/src/domain/person/person.service.spec.ts @@ -999,7 +999,7 @@ describe(PersonService.name, () => { expect(accessMock.person.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['person-1'])); }); - it('should merge two people', async () => { + it('should merge two people without smart merge', async () => { personMock.getById.mockResolvedValueOnce(personStub.primaryPerson); personMock.getById.mockResolvedValueOnce(personStub.mergePerson); accessMock.person.checkOwnerAccess.mockResolvedValueOnce(new Set(['person-1'])); @@ -1017,6 +1017,30 @@ describe(PersonService.name, () => { expect(accessMock.person.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['person-1'])); }); + it('should merge two people with smart merge', async () => { + personMock.getById.mockResolvedValueOnce(personStub.randomPerson); + personMock.getById.mockResolvedValueOnce(personStub.primaryPerson); + personMock.update.mockResolvedValue({ ...personStub.randomPerson, name: personStub.primaryPerson.name }); + accessMock.person.checkOwnerAccess.mockResolvedValueOnce(new Set(['person-3'])); + accessMock.person.checkOwnerAccess.mockResolvedValueOnce(new Set(['person-1'])); + + await expect(sut.mergePerson(authStub.admin, 'person-3', { ids: ['person-1'] })).resolves.toEqual([ + { id: 'person-1', success: true }, + ]); + + expect(personMock.reassignFaces).toHaveBeenCalledWith({ + newPersonId: personStub.randomPerson.id, + oldPersonId: personStub.primaryPerson.id, + }); + + expect(personMock.update).toHaveBeenCalledWith({ + id: personStub.randomPerson.id, + name: personStub.primaryPerson.name, + }); + + expect(accessMock.person.checkOwnerAccess).toHaveBeenCalledWith(authStub.admin.user.id, new Set(['person-1'])); + }); + it('should throw an error when the primary person is not found', async () => { personMock.getById.mockResolvedValue(null); accessMock.person.checkOwnerAccess.mockResolvedValue(new Set(['person-1'])); @@ -1045,8 +1069,8 @@ describe(PersonService.name, () => { }); it('should handle an error reassigning faces', async () => { - personMock.getById.mockResolvedValue(personStub.primaryPerson); - personMock.getById.mockResolvedValue(personStub.mergePerson); + personMock.getById.mockResolvedValueOnce(personStub.primaryPerson); + personMock.getById.mockResolvedValueOnce(personStub.mergePerson); personMock.reassignFaces.mockRejectedValue(new Error('update failed')); accessMock.person.checkOwnerAccess.mockResolvedValueOnce(new Set(['person-1'])); accessMock.person.checkOwnerAccess.mockResolvedValueOnce(new Set(['person-2'])); diff --git a/server/src/domain/person/person.service.ts b/server/src/domain/person/person.service.ts index 57ab27a5d8..561630e549 100644 --- a/server/src/domain/person/person.service.ts +++ b/server/src/domain/person/person.service.ts @@ -533,7 +533,7 @@ export class PersonService { async mergePerson(auth: AuthDto, id: string, dto: MergePersonDto): Promise { const mergeIds = dto.ids; await this.access.requirePermission(auth, Permission.PERSON_WRITE, id); - const primaryPerson = await this.findOrFail(id); + let primaryPerson = await this.findOrFail(id); const primaryName = primaryPerson.name || primaryPerson.id; const results: BulkIdResponseDto[] = []; @@ -554,6 +554,19 @@ export class PersonService { continue; } + const update: Partial = {}; + if (!primaryPerson.name && mergePerson.name) { + update.name = mergePerson.name; + } + + if (!primaryPerson.birthDate && mergePerson.birthDate) { + update.birthDate = mergePerson.birthDate; + } + + if (Object.keys(update).length > 0) { + primaryPerson = await this.repository.update({ id: primaryPerson.id, ...update }); + } + const mergeName = mergePerson.name || mergePerson.id; const mergeData: UpdateFacesData = { oldPersonId: mergeId, newPersonId: id }; this.logger.log(`Merging ${mergeName} into ${primaryName}`); @@ -568,7 +581,6 @@ export class PersonService { results.push({ id: mergeId, success: false, error: BulkIdErrorReason.UNKNOWN }); } } - return results; } diff --git a/server/test/fixtures/person.stub.ts b/server/test/fixtures/person.stub.ts index 76e2d14f72..ad83d68001 100644 --- a/server/test/fixtures/person.stub.ts +++ b/server/test/fixtures/person.stub.ts @@ -128,4 +128,18 @@ export const personStub = { faceAsset: null, isHidden: false, }), + randomPerson: Object.freeze({ + id: 'person-3', + createdAt: new Date('2021-01-01'), + updatedAt: new Date('2021-01-01'), + ownerId: userStub.admin.id, + owner: userStub.admin, + name: '', + birthDate: null, + thumbnailPath: '/path/to/thumbnail', + faces: [], + faceAssetId: null, + faceAsset: null, + isHidden: false, + }), }; diff --git a/web/src/lib/components/faces-page/merge-face-selector.svelte b/web/src/lib/components/faces-page/merge-face-selector.svelte index 56c1b86e7c..5dd48b04c6 100644 --- a/web/src/lib/components/faces-page/merge-face-selector.svelte +++ b/web/src/lib/components/faces-page/merge-face-selector.svelte @@ -26,7 +26,7 @@ let dispatch = createEventDispatcher<{ back: void; - merge: void; + merge: PersonResponseDto; }>(); $: hasSelection = selectedPeople.length > 0; @@ -68,16 +68,17 @@ const handleMerge = async () => { try { - const { data: results } = await api.personApi.mergePerson({ + let { data: results } = await api.personApi.mergePerson({ id: person.id, mergePersonDto: { ids: selectedPeople.map(({ id }) => id) }, }); + const { data: mergedPerson } = await api.personApi.getPerson({ id: person.id }); const count = results.filter(({ success }) => success).length; notificationController.show({ message: `Merged ${count} ${count === 1 ? 'person' : 'people'}`, type: NotificationType.Info, }); - dispatch('merge'); + dispatch('merge', mergedPerson); } catch (error) { handleError(error, 'Cannot merge people'); } finally { diff --git a/web/src/routes/(user)/people/+page.svelte b/web/src/routes/(user)/people/+page.svelte index eec418c6ad..323b160a82 100644 --- a/web/src/routes/(user)/people/+page.svelte +++ b/web/src/routes/(user)/people/+page.svelte @@ -165,8 +165,12 @@ id: personMerge2.id, mergePersonDto: { ids: [personToMerge.id] }, }); + + const { data: mergedPerson } = await api.personApi.getPerson({ id: personToMerge.id }); + countVisiblePeople--; people = people.filter((person: PersonResponseDto) => person.id !== personToMerge.id); + people = people.map((person: PersonResponseDto) => (person.id === personMerge2.id ? mergedPerson : person)); notificationController.show({ message: 'Merge people succesfully', diff --git a/web/src/routes/(user)/people/[personId]/+page.svelte b/web/src/routes/(user)/people/[personId]/+page.svelte index c97d3845cb..6d7bd77865 100644 --- a/web/src/routes/(user)/people/[personId]/+page.svelte +++ b/web/src/routes/(user)/people/[personId]/+page.svelte @@ -185,8 +185,13 @@ } }; - const handleMerge = () => { + const handleMerge = async (person: PersonResponseDto) => { + const { data: statistics } = await api.personApi.getPersonStatistics({ id: person.id }); + numberOfAssets = statistics.assets; handleGoBack(); + + data.person = person; + refreshAssetGrid = !refreshAssetGrid; }; @@ -374,7 +379,7 @@ {/if} {#if viewMode === ViewMode.MERGE_PEOPLE} - + handleMerge(detail)} /> {/if}
From 88ac3c2016f2db30e8f559d4b926b40fbf5b8106 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 19 Jan 2024 12:27:29 -0600 Subject: [PATCH 6/9] fix(web): better invite shared user to album layout (#6511) * fix(web): better invite to album design * rounded corner * use icon * padding --- .../album-page/user-selection-modal.svelte | 54 +++++++++++-------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/web/src/lib/components/album-page/user-selection-modal.svelte b/web/src/lib/components/album-page/user-selection-modal.svelte index c5c3c083ff..909afd8958 100644 --- a/web/src/lib/components/album-page/user-selection-modal.svelte +++ b/web/src/lib/components/album-page/user-selection-modal.svelte @@ -7,7 +7,7 @@ import ImmichLogo from '../shared-components/immich-logo.svelte'; import Button from '../elements/buttons/button.svelte'; import { AppRoute } from '$lib/constants'; - import { mdiLink, mdiShareCircle } from '@mdi/js'; + import { mdiCheck, mdiLink, mdiShareCircle } from '@mdi/js'; import Icon from '$lib/components/elements/icon.svelte'; export let album: AlbumResponseDto; @@ -60,28 +60,25 @@ -
- {#if selectedUsers.length > 0} -
-

To

+ {#if selectedUsers.length > 0} +
+

To

- {#each selectedUsers as user} - {#key user.id} - - {/key} - {/each} -
- -
-
- {/if} + {#each selectedUsers as user} + {#key user.id} + + {/key} + {/each} +
+ {/if} +
{#if users.length > 0}

SUGGESTIONS

@@ -95,7 +92,7 @@
-

+
{:else} @@ -119,7 +116,20 @@ {/if}
+ {#if users.length > 0} +
+ +
+ {/if} +
+
{#if innerHeight}
{#each reactions as reaction, index (reaction.id)} {#if reaction.type === 'comment'} -
+
@@ -215,7 +215,7 @@ {#if (index != reactions.length - 1 && !shouldGroup(reactions[index].createdAt, reactions[index + 1].createdAt)) || index === reactions.length - 1}
{timeSince(luxon.DateTime.fromISO(reaction.createdAt))} @@ -223,7 +223,7 @@ {/if} {:else if reaction.type === 'like'}
-
+
@@ -260,7 +260,7 @@
{#if (index != reactions.length - 1 && isTenMinutesApart(reactions[index].createdAt, reactions[index + 1].createdAt)) || index === reactions.length - 1}
{timeSince(luxon.DateTime.fromISO(reaction.createdAt))} @@ -274,7 +274,7 @@
-
+
diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte index fc298f471d..9de100c2a6 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte @@ -741,7 +741,7 @@
0 && !$showAssetViewer && (album.isActivityEnabled || $numberOfComments > 0); - afterNavigate(({ from }) => { + $: { + if (textarea) { + textarea.value = album.description; + autoGrowHeight(); + } + } + $: afterNavigate(({ from }) => { assetViewingStore.showAssetViewer(false); let url: string | undefined = from?.url?.pathname; @@ -142,6 +149,13 @@ } }); + const autoGrowHeight = () => { + // little hack so that the height of the text area is correctly initialized + textarea.scrollHeight; + textarea.style.height = '5px'; + textarea.style.height = `${textarea.scrollHeight}px`; + }; + const handleToggleEnableActivity = async () => { try { const { data } = await api.albumApi.updateAlbumInfo({ @@ -636,7 +650,12 @@ disabled={!isOwned} title="Edit description" > - {album.description || 'Add description'} +