Skip to content

feat(mobile): add three-state field serialization - #27231

Merged
jrasm91 merged 3 commits into
mainfrom
refactor/drop-dart-patches
Jun 3, 2026
Merged

feat(mobile): add three-state field serialization#27231
jrasm91 merged 3 commits into
mainfrom
refactor/drop-dart-patches

Conversation

@timonrieger

@timonrieger timonrieger commented Mar 24, 2026

Copy link
Copy Markdown
Collaborator

Upgrade the openapi-generator to the latest version: v7.22.0, which enables the Dart client to distinguish between:

  • absent
  • null
  • present

The PR looks big, that's mostly due to the client generation (2nd commit). The actual changes are small. Mobile call sites have been migrated by resolving errors reported by mise //mobile:analyze:dart

For additional context read the outline doc.

@timonrieger
timonrieger force-pushed the refactor/drop-dart-patches branch from f6dea8b to 2503e74 Compare March 24, 2026 22:44
@timonrieger timonrieger changed the title refactor: updade openapi-generator to v7.21.0 chore: updade openapi-generator to v7.21.0 Mar 25, 2026
@timonrieger
timonrieger marked this pull request as ready for review March 25, 2026 14:46
@timonrieger
timonrieger force-pushed the refactor/drop-dart-patches branch from 2503e74 to dbec691 Compare March 26, 2026 11:55
@timonrieger
timonrieger marked this pull request as draft March 26, 2026 12:07
@timonrieger

This comment was marked as outdated.

@timonrieger timonrieger changed the title chore: updade openapi-generator to v7.21.0 chore: update openapi-generator to v7.21.0 Apr 17, 2026
@timonrieger
timonrieger force-pushed the refactor/drop-dart-patches branch from dbec691 to 49b30ea Compare May 4, 2026 15:29
@timonrieger timonrieger changed the title chore: update openapi-generator to v7.21.0 chore: update openapi-generator to v7.22.0 May 4, 2026
@timonrieger
timonrieger marked this pull request as ready for review May 4, 2026 19:56
@timonrieger
timonrieger marked this pull request as draft May 5, 2026 09:06
@timonrieger timonrieger changed the title chore: update openapi-generator to v7.22.0 chore(mobile): add three-state field serialization May 18, 2026
@timonrieger
timonrieger force-pushed the refactor/drop-dart-patches branch from 3753a3e to 8faa495 Compare May 18, 2026 12:40
@timonrieger timonrieger changed the title chore(mobile): add three-state field serialization feat(mobile): add three-state field serialization May 18, 2026
@github-actions

github-actions Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

📱 Android release APK (universal)182de9871a9f0d8582ccf61632af53bb113c3e7e

Download: https://github.com/immich-app/immich/actions/runs/26042656731/artifacts/7062131338

QR code QR code

Installs as a separate app (applicationId app.alextran.immich.pr27231), so it coexists with the Play Store version and any other PR builds.

@timonrieger
timonrieger force-pushed the refactor/drop-dart-patches branch from 8faa495 to b25413c Compare May 18, 2026 12:55
@timonrieger
timonrieger marked this pull request as ready for review May 18, 2026 12:55
@timonrieger
timonrieger requested a review from jrasm91 May 18, 2026 13:19
@timonrieger
timonrieger force-pushed the refactor/drop-dart-patches branch from b25413c to 182de98 Compare May 18, 2026 15:18

@jrasm91 jrasm91 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code LGTM. Will need more testing though.

@github-actions

Copy link
Copy Markdown
Contributor

Deploying preview environment to https://pr-27231.preview.internal.immich.build/

@timonrieger

Copy link
Copy Markdown
Collaborator Author

Code LGTM. Will need more testing though.

tested this against current main server. yielded some unrelated "silent" bugs that were hidden due to our patching efforts in the dart client. apart from that the mobile app worked fine with the above changes. Imo good to merge now! (some patches can be dropped once upstream 7.23.0 is released, got it on my list) .

Below I list all "unrelated" bugs found so far:

@timonrieger
timonrieger force-pushed the refactor/drop-dart-patches branch from 182de98 to 0b39f43 Compare June 1, 2026 22:39
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jun 15, 2026
…ich-app#27231)

Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all
mobile DTO fields three-state Optional<T?>. Changes:
- Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0:
  upstream's three-state + array/complex-Optional fromJson handling + the fork's
  #584 date birth-fix.
- Regenerate the mobile OpenAPI dart client.
- Adapt 8 fork mobile files (space_card, shared_space_api.repository,
  drift_library.page, + test fixtures/specs) to read/write Optional fields.
dart analyze lib+test clean; flutter tests pass.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jun 15, 2026
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization,
but the openapi-generator v7.22.0 useOptional branch reintroduced it for
three-state fields when batch 183 adopted upstream immich-app#27231 — shifting
birthdays by a day for users west/east of UTC. Extend the
native_class.mustache patch to the x-is-optional date branch and
regenerate the affected DTOs. CI never caught it because runners are UTC;
the fork's person_update_dto_test only fails in non-UTC timezones.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jun 16, 2026
…ich-app#27231)

Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all
mobile DTO fields three-state Optional<T?>. Changes:
- Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0:
  upstream's three-state + array/complex-Optional fromJson handling + the fork's
  #584 date birth-fix.
- Regenerate the mobile OpenAPI dart client.
- Adapt 8 fork mobile files (space_card, shared_space_api.repository,
  drift_library.page, + test fixtures/specs) to read/write Optional fields.
dart analyze lib+test clean; flutter tests pass.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jun 16, 2026
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization,
but the openapi-generator v7.22.0 useOptional branch reintroduced it for
three-state fields when batch 183 adopted upstream immich-app#27231 — shifting
birthdays by a day for users west/east of UTC. Extend the
native_class.mustache patch to the x-is-optional date branch and
regenerate the affected DTOs. CI never caught it because runners are UTC;
the fork's person_update_dto_test only fails in non-UTC timezones.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jun 17, 2026
…ich-app#27231)

Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all
mobile DTO fields three-state Optional<T?>. Changes:
- Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0:
  upstream's three-state + array/complex-Optional fromJson handling + the fork's
  #584 date birth-fix.
- Regenerate the mobile OpenAPI dart client.
- Adapt 8 fork mobile files (space_card, shared_space_api.repository,
  drift_library.page, + test fixtures/specs) to read/write Optional fields.
dart analyze lib+test clean; flutter tests pass.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jun 17, 2026
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization,
but the openapi-generator v7.22.0 useOptional branch reintroduced it for
three-state fields when batch 183 adopted upstream immich-app#27231 — shifting
birthdays by a day for users west/east of UTC. Extend the
native_class.mustache patch to the x-is-optional date branch and
regenerate the affected DTOs. CI never caught it because runners are UTC;
the fork's person_update_dto_test only fails in non-UTC timezones.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jun 17, 2026
…ich-app#27231)

Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all
mobile DTO fields three-state Optional<T?>. Changes:
- Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0:
  upstream's three-state + array/complex-Optional fromJson handling + the fork's
  #584 date birth-fix.
- Regenerate the mobile OpenAPI dart client.
- Adapt 8 fork mobile files (space_card, shared_space_api.repository,
  drift_library.page, + test fixtures/specs) to read/write Optional fields.
dart analyze lib+test clean; flutter tests pass.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jun 17, 2026
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization,
but the openapi-generator v7.22.0 useOptional branch reintroduced it for
three-state fields when batch 183 adopted upstream immich-app#27231 — shifting
birthdays by a day for users west/east of UTC. Extend the
native_class.mustache patch to the x-is-optional date branch and
regenerate the affected DTOs. CI never caught it because runners are UTC;
the fork's person_update_dto_test only fails in non-UTC timezones.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jun 19, 2026
…ich-app#27231)

Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all
mobile DTO fields three-state Optional<T?>. Changes:
- Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0:
  upstream's three-state + array/complex-Optional fromJson handling + the fork's
  #584 date birth-fix.
- Regenerate the mobile OpenAPI dart client.
- Adapt 8 fork mobile files (space_card, shared_space_api.repository,
  drift_library.page, + test fixtures/specs) to read/write Optional fields.
dart analyze lib+test clean; flutter tests pass.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jun 19, 2026
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization,
but the openapi-generator v7.22.0 useOptional branch reintroduced it for
three-state fields when batch 183 adopted upstream immich-app#27231 — shifting
birthdays by a day for users west/east of UTC. Extend the
native_class.mustache patch to the x-is-optional date branch and
regenerate the affected DTOs. CI never caught it because runners are UTC;
the fork's person_update_dto_test only fails in non-UTC timezones.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jun 19, 2026
…ich-app#27231)

Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all
mobile DTO fields three-state Optional<T?>. Changes:
- Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0:
  upstream's three-state + array/complex-Optional fromJson handling + the fork's
  #584 date birth-fix.
- Regenerate the mobile OpenAPI dart client.
- Adapt 8 fork mobile files (space_card, shared_space_api.repository,
  drift_library.page, + test fixtures/specs) to read/write Optional fields.
dart analyze lib+test clean; flutter tests pass.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jun 19, 2026
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization,
but the openapi-generator v7.22.0 useOptional branch reintroduced it for
three-state fields when batch 183 adopted upstream immich-app#27231 — shifting
birthdays by a day for users west/east of UTC. Extend the
native_class.mustache patch to the x-is-optional date branch and
regenerate the affected DTOs. CI never caught it because runners are UTC;
the fork's person_update_dto_test only fails in non-UTC timezones.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jun 24, 2026
…ich-app#27231)

Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all
mobile DTO fields three-state Optional<T?>. Changes:
- Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0:
  upstream's three-state + array/complex-Optional fromJson handling + the fork's
  #584 date birth-fix.
- Regenerate the mobile OpenAPI dart client.
- Adapt 8 fork mobile files (space_card, shared_space_api.repository,
  drift_library.page, + test fixtures/specs) to read/write Optional fields.
dart analyze lib+test clean; flutter tests pass.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jun 24, 2026
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization,
but the openapi-generator v7.22.0 useOptional branch reintroduced it for
three-state fields when batch 183 adopted upstream immich-app#27231 — shifting
birthdays by a day for users west/east of UTC. Extend the
native_class.mustache patch to the x-is-optional date branch and
regenerate the affected DTOs. CI never caught it because runners are UTC;
the fork's person_update_dto_test only fails in non-UTC timezones.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jul 2, 2026
…ich-app#27231)

Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all
mobile DTO fields three-state Optional<T?>. Changes:
- Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0:
  upstream's three-state + array/complex-Optional fromJson handling + the fork's
  #584 date birth-fix.
- Regenerate the mobile OpenAPI dart client.
- Adapt 8 fork mobile files (space_card, shared_space_api.repository,
  drift_library.page, + test fixtures/specs) to read/write Optional fields.
dart analyze lib+test clean; flutter tests pass.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jul 2, 2026
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization,
but the openapi-generator v7.22.0 useOptional branch reintroduced it for
three-state fields when batch 183 adopted upstream immich-app#27231 — shifting
birthdays by a day for users west/east of UTC. Extend the
native_class.mustache patch to the x-is-optional date branch and
regenerate the affected DTOs. CI never caught it because runners are UTC;
the fork's person_update_dto_test only fails in non-UTC timezones.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jul 17, 2026
…ich-app#27231)

Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all
mobile DTO fields three-state Optional<T?>. Changes:
- Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0:
  upstream's three-state + array/complex-Optional fromJson handling + the fork's
  #584 date birth-fix.
- Regenerate the mobile OpenAPI dart client.
- Adapt 8 fork mobile files (space_card, shared_space_api.repository,
  drift_library.page, + test fixtures/specs) to read/write Optional fields.
dart analyze lib+test clean; flutter tests pass.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jul 17, 2026
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization,
but the openapi-generator v7.22.0 useOptional branch reintroduced it for
three-state fields when batch 183 adopted upstream immich-app#27231 — shifting
birthdays by a day for users west/east of UTC. Extend the
native_class.mustache patch to the x-is-optional date branch and
regenerate the affected DTOs. CI never caught it because runners are UTC;
the fork's person_update_dto_test only fails in non-UTC timezones.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jul 17, 2026
…-trim race, Dart nullable-items patch, branding/i18n, ownership-glob (#743) (#794)

* fix(tools): escape route-group parens in ownership-coverage micromatch globs (#743)

micromatch parses bare `(user)` as an empty regex capture group, so
ownership globs like `web/src/routes/(user)/spaces/**` silently matched
nothing in coverage.ts (both the ignore filter and the glob classifier).
Port the literal-parens escaping the S20 manifest guard already uses.

* fix(server): make rapid re-trims of the same video race-free (#743)

Overlapping trim jobs shared the frame path `{id}_edited.mp4.frame.jpg`
(one job's cleanup unlinked the frame the other was reading -> 'Input
file is missing') and ffmpeg overwrote `{id}_edited.mp4` in place while
the previous job could still be probing it.

- serialize trims per asset id (AsyncLock, in-process)
- unique per-invocation temp frame path (covers cross-process overlap)
- trim to a temp file and atomically rename into place

* fix(server): mask isFavorite in LibraryAssetSync for non-owned assets (#743)

LibraryAssetSync streamed the raw asset.isFavorite to every library
member. Apply the same per-row ownership mask SharedSpaceAssetSync /
AlbumAssetSync use (owner keeps the flag, everyone else sees false) on
both the backfill and upsert paths.

* fix(branding): brand the 4 remaining Immich i18n keys + close the missing-override gap (#743)

- asset_offline_description was the #672 bug shape again: overridden at
  the TOP LEVEL with the admin-block text, clobbering the user-facing
  string while admin.asset_offline_description kept leaking 'Immich'.
  Both nesting levels now carry their own branded text.
- add overrides for import_option_skip_duplicates, my_immich_title,
  my_immich_description (the my.immich.app redirect service keeps its
  domain name).
- verify-branding.sh and test-i18n-branding.sh only checked keys that
  HAVE overrides, so a leaking key with no override passed silently —
  both now scan every string value in the branded en.json.

* fix(mobile): re-author the Dart nullable-items-in-arrays template patch (#743)

The patch that types nullable-item arrays as List<T?> was orphaned:
generate-dart-sdk.sh stopped applying it after the upstream three-state
DTO template rework (immich-app#27231) rewrote the same template regions, so
TimeBucketAssetResponseDto declared its 8 nullable-item array fields
as non-nullable and a null city/thumbhash/duration item threw at decode
time instead of surfacing in the type system.

- re-author the hunks against the current (post-immich-app#27231) template,
  covering required, x-is-optional, and plain-optional declarations;
  the rebuild only kicks in when items.isNullable so no other model
  regenerates differently
- re-insert the patch application into generate-dart-sdk.sh (after
  native_class.mustache.patch, which its hunks are authored against)
- drop the stack hand-patch (time_bucket_asset_response_dto.dart.patch)
  — the template now produces the same declaration
- add a preflight guard: the script must keep applying the patch, and
  every nullable-item array in the spec must be List<T?> in the
  committed generated model (this is the guard that would have caught
  the orphaning)

The old patch's third hunk (implicit-optional number parsing) is
obsolete: the x-is-optional pipeline now handles absent/null numbers.

Verified: full mobile test suite (2520 tests) + dart analyze
--fatal-infos green on the regenerated SDK.

* chore(server): satisfy require-await in the trim-serialization test (#743)
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jul 18, 2026
…-trim race, Dart nullable-items patch, branding/i18n, ownership-glob (#743) (#794)

* fix(tools): escape route-group parens in ownership-coverage micromatch globs (#743)

micromatch parses bare `(user)` as an empty regex capture group, so
ownership globs like `web/src/routes/(user)/spaces/**` silently matched
nothing in coverage.ts (both the ignore filter and the glob classifier).
Port the literal-parens escaping the S20 manifest guard already uses.

* fix(server): make rapid re-trims of the same video race-free (#743)

Overlapping trim jobs shared the frame path `{id}_edited.mp4.frame.jpg`
(one job's cleanup unlinked the frame the other was reading -> 'Input
file is missing') and ffmpeg overwrote `{id}_edited.mp4` in place while
the previous job could still be probing it.

- serialize trims per asset id (AsyncLock, in-process)
- unique per-invocation temp frame path (covers cross-process overlap)
- trim to a temp file and atomically rename into place

* fix(server): mask isFavorite in LibraryAssetSync for non-owned assets (#743)

LibraryAssetSync streamed the raw asset.isFavorite to every library
member. Apply the same per-row ownership mask SharedSpaceAssetSync /
AlbumAssetSync use (owner keeps the flag, everyone else sees false) on
both the backfill and upsert paths.

* fix(branding): brand the 4 remaining Immich i18n keys + close the missing-override gap (#743)

- asset_offline_description was the #672 bug shape again: overridden at
  the TOP LEVEL with the admin-block text, clobbering the user-facing
  string while admin.asset_offline_description kept leaking 'Immich'.
  Both nesting levels now carry their own branded text.
- add overrides for import_option_skip_duplicates, my_immich_title,
  my_immich_description (the my.immich.app redirect service keeps its
  domain name).
- verify-branding.sh and test-i18n-branding.sh only checked keys that
  HAVE overrides, so a leaking key with no override passed silently —
  both now scan every string value in the branded en.json.

* fix(mobile): re-author the Dart nullable-items-in-arrays template patch (#743)

The patch that types nullable-item arrays as List<T?> was orphaned:
generate-dart-sdk.sh stopped applying it after the upstream three-state
DTO template rework (immich-app#27231) rewrote the same template regions, so
TimeBucketAssetResponseDto declared its 8 nullable-item array fields
as non-nullable and a null city/thumbhash/duration item threw at decode
time instead of surfacing in the type system.

- re-author the hunks against the current (post-immich-app#27231) template,
  covering required, x-is-optional, and plain-optional declarations;
  the rebuild only kicks in when items.isNullable so no other model
  regenerates differently
- re-insert the patch application into generate-dart-sdk.sh (after
  native_class.mustache.patch, which its hunks are authored against)
- drop the stack hand-patch (time_bucket_asset_response_dto.dart.patch)
  — the template now produces the same declaration
- add a preflight guard: the script must keep applying the patch, and
  every nullable-item array in the spec must be List<T?> in the
  committed generated model (this is the guard that would have caught
  the orphaning)

The old patch's third hunk (implicit-optional number parsing) is
obsolete: the x-is-optional pipeline now handles absent/null numbers.

Verified: full mobile test suite (2520 tests) + dart analyze
--fatal-infos green on the regenerated SDK.

* chore(server): satisfy require-await in the trim-serialization test (#743)
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jul 20, 2026
…ich-app#27231)

Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all
mobile DTO fields three-state Optional<T?>. Changes:
- Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0:
  upstream's three-state + array/complex-Optional fromJson handling + the fork's
  #584 date birth-fix.
- Regenerate the mobile OpenAPI dart client.
- Adapt 8 fork mobile files (space_card, shared_space_api.repository,
  drift_library.page, + test fixtures/specs) to read/write Optional fields.
dart analyze lib+test clean; flutter tests pass.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jul 20, 2026
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization,
but the openapi-generator v7.22.0 useOptional branch reintroduced it for
three-state fields when batch 183 adopted upstream immich-app#27231 — shifting
birthdays by a day for users west/east of UTC. Extend the
native_class.mustache patch to the x-is-optional date branch and
regenerate the affected DTOs. CI never caught it because runners are UTC;
the fork's person_update_dto_test only fails in non-UTC timezones.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jul 20, 2026
…-trim race, Dart nullable-items patch, branding/i18n, ownership-glob (#743) (#794)

* fix(tools): escape route-group parens in ownership-coverage micromatch globs (#743)

micromatch parses bare `(user)` as an empty regex capture group, so
ownership globs like `web/src/routes/(user)/spaces/**` silently matched
nothing in coverage.ts (both the ignore filter and the glob classifier).
Port the literal-parens escaping the S20 manifest guard already uses.

* fix(server): make rapid re-trims of the same video race-free (#743)

Overlapping trim jobs shared the frame path `{id}_edited.mp4.frame.jpg`
(one job's cleanup unlinked the frame the other was reading -> 'Input
file is missing') and ffmpeg overwrote `{id}_edited.mp4` in place while
the previous job could still be probing it.

- serialize trims per asset id (AsyncLock, in-process)
- unique per-invocation temp frame path (covers cross-process overlap)
- trim to a temp file and atomically rename into place

* fix(server): mask isFavorite in LibraryAssetSync for non-owned assets (#743)

LibraryAssetSync streamed the raw asset.isFavorite to every library
member. Apply the same per-row ownership mask SharedSpaceAssetSync /
AlbumAssetSync use (owner keeps the flag, everyone else sees false) on
both the backfill and upsert paths.

* fix(branding): brand the 4 remaining Immich i18n keys + close the missing-override gap (#743)

- asset_offline_description was the #672 bug shape again: overridden at
  the TOP LEVEL with the admin-block text, clobbering the user-facing
  string while admin.asset_offline_description kept leaking 'Immich'.
  Both nesting levels now carry their own branded text.
- add overrides for import_option_skip_duplicates, my_immich_title,
  my_immich_description (the my.immich.app redirect service keeps its
  domain name).
- verify-branding.sh and test-i18n-branding.sh only checked keys that
  HAVE overrides, so a leaking key with no override passed silently —
  both now scan every string value in the branded en.json.

* fix(mobile): re-author the Dart nullable-items-in-arrays template patch (#743)

The patch that types nullable-item arrays as List<T?> was orphaned:
generate-dart-sdk.sh stopped applying it after the upstream three-state
DTO template rework (immich-app#27231) rewrote the same template regions, so
TimeBucketAssetResponseDto declared its 8 nullable-item array fields
as non-nullable and a null city/thumbhash/duration item threw at decode
time instead of surfacing in the type system.

- re-author the hunks against the current (post-immich-app#27231) template,
  covering required, x-is-optional, and plain-optional declarations;
  the rebuild only kicks in when items.isNullable so no other model
  regenerates differently
- re-insert the patch application into generate-dart-sdk.sh (after
  native_class.mustache.patch, which its hunks are authored against)
- drop the stack hand-patch (time_bucket_asset_response_dto.dart.patch)
  — the template now produces the same declaration
- add a preflight guard: the script must keep applying the patch, and
  every nullable-item array in the spec must be List<T?> in the
  committed generated model (this is the guard that would have caught
  the orphaning)

The old patch's third hunk (implicit-optional number parsing) is
obsolete: the x-is-optional pipeline now handles absent/null numbers.

Verified: full mobile test suite (2520 tests) + dart analyze
--fatal-infos green on the regenerated SDK.

* chore(server): satisfy require-await in the trim-serialization test (#743)
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jul 21, 2026
…ich-app#27231)

Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all
mobile DTO fields three-state Optional<T?>. Changes:
- Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0:
  upstream's three-state + array/complex-Optional fromJson handling + the fork's
  #584 date birth-fix.
- Regenerate the mobile OpenAPI dart client.
- Adapt 8 fork mobile files (space_card, shared_space_api.repository,
  drift_library.page, + test fixtures/specs) to read/write Optional fields.
dart analyze lib+test clean; flutter tests pass.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jul 21, 2026
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization,
but the openapi-generator v7.22.0 useOptional branch reintroduced it for
three-state fields when batch 183 adopted upstream immich-app#27231 — shifting
birthdays by a day for users west/east of UTC. Extend the
native_class.mustache patch to the x-is-optional date branch and
regenerate the affected DTOs. CI never caught it because runners are UTC;
the fork's person_update_dto_test only fails in non-UTC timezones.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jul 21, 2026
…-trim race, Dart nullable-items patch, branding/i18n, ownership-glob (#743) (#794)

* fix(tools): escape route-group parens in ownership-coverage micromatch globs (#743)

micromatch parses bare `(user)` as an empty regex capture group, so
ownership globs like `web/src/routes/(user)/spaces/**` silently matched
nothing in coverage.ts (both the ignore filter and the glob classifier).
Port the literal-parens escaping the S20 manifest guard already uses.

* fix(server): make rapid re-trims of the same video race-free (#743)

Overlapping trim jobs shared the frame path `{id}_edited.mp4.frame.jpg`
(one job's cleanup unlinked the frame the other was reading -> 'Input
file is missing') and ffmpeg overwrote `{id}_edited.mp4` in place while
the previous job could still be probing it.

- serialize trims per asset id (AsyncLock, in-process)
- unique per-invocation temp frame path (covers cross-process overlap)
- trim to a temp file and atomically rename into place

* fix(server): mask isFavorite in LibraryAssetSync for non-owned assets (#743)

LibraryAssetSync streamed the raw asset.isFavorite to every library
member. Apply the same per-row ownership mask SharedSpaceAssetSync /
AlbumAssetSync use (owner keeps the flag, everyone else sees false) on
both the backfill and upsert paths.

* fix(branding): brand the 4 remaining Immich i18n keys + close the missing-override gap (#743)

- asset_offline_description was the #672 bug shape again: overridden at
  the TOP LEVEL with the admin-block text, clobbering the user-facing
  string while admin.asset_offline_description kept leaking 'Immich'.
  Both nesting levels now carry their own branded text.
- add overrides for import_option_skip_duplicates, my_immich_title,
  my_immich_description (the my.immich.app redirect service keeps its
  domain name).
- verify-branding.sh and test-i18n-branding.sh only checked keys that
  HAVE overrides, so a leaking key with no override passed silently —
  both now scan every string value in the branded en.json.

* fix(mobile): re-author the Dart nullable-items-in-arrays template patch (#743)

The patch that types nullable-item arrays as List<T?> was orphaned:
generate-dart-sdk.sh stopped applying it after the upstream three-state
DTO template rework (immich-app#27231) rewrote the same template regions, so
TimeBucketAssetResponseDto declared its 8 nullable-item array fields
as non-nullable and a null city/thumbhash/duration item threw at decode
time instead of surfacing in the type system.

- re-author the hunks against the current (post-immich-app#27231) template,
  covering required, x-is-optional, and plain-optional declarations;
  the rebuild only kicks in when items.isNullable so no other model
  regenerates differently
- re-insert the patch application into generate-dart-sdk.sh (after
  native_class.mustache.patch, which its hunks are authored against)
- drop the stack hand-patch (time_bucket_asset_response_dto.dart.patch)
  — the template now produces the same declaration
- add a preflight guard: the script must keep applying the patch, and
  every nullable-item array in the spec must be List<T?> in the
  committed generated model (this is the guard that would have caught
  the orphaning)

The old patch's third hunk (implicit-optional number parsing) is
obsolete: the x-is-optional pipeline now handles absent/null numbers.

Verified: full mobile test suite (2520 tests) + dart analyze
--fatal-infos green on the regenerated SDK.

* chore(server): satisfy require-await in the trim-serialization test (#743)
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jul 22, 2026
…ich-app#27231)

Upstream immich-app#27231 enabled useOptional=true (OpenAPI-generator v7.22.0), making all
mobile DTO fields three-state Optional<T?>. Changes:
- Regenerate the fork Dart codegen patch (native_class.mustache.patch) for v7.22.0:
  upstream's three-state + array/complex-Optional fromJson handling + the fork's
  #584 date birth-fix.
- Regenerate the mobile OpenAPI dart client.
- Adapt 8 fork mobile files (space_card, shared_space_api.repository,
  drift_library.page, + test fixtures/specs) to read/write Optional fields.
dart analyze lib+test clean; flutter tests pass.
Deeds67 added a commit to open-noodle/gallery that referenced this pull request Jul 22, 2026
Fork #584 removed .toUtc() from _dateFormatter (civil date) serialization,
but the openapi-generator v7.22.0 useOptional branch reintroduced it for
three-state fields when batch 183 adopted upstream immich-app#27231 — shifting
birthdays by a day for users west/east of UTC. Extend the
native_class.mustache patch to the x-is-optional date branch and
regenerate the affected DTOs. CI never caught it because runners are UTC;
the fork's person_update_dto_test only fails in non-UTC timezones.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants