From 7e5592fec5aada38ae8ef4532d86848a08fea1e5 Mon Sep 17 00:00:00 2001 From: Min Idzelis Date: Sat, 24 Jan 2026 00:18:02 -0500 Subject: [PATCH] feat: make progressive system config optional (#25486) --- ...m_config_generated_fullsize_image_dto.dart | 5 ++-- .../system_config_generated_image_dto.dart | 5 ++-- open-api/immich-openapi-specs.json | 4 +-- open-api/typescript-sdk/src/fetch-client.ts | 4 +-- .../system-config.controller.spec.ts | 28 +++++++++++++++++++ server/src/dtos/system-config.dto.ts | 8 +++--- server/src/types.ts | 4 +-- 7 files changed, 42 insertions(+), 16 deletions(-) diff --git a/mobile/openapi/lib/model/system_config_generated_fullsize_image_dto.dart b/mobile/openapi/lib/model/system_config_generated_fullsize_image_dto.dart index f36105f590..e7111771bd 100644 --- a/mobile/openapi/lib/model/system_config_generated_fullsize_image_dto.dart +++ b/mobile/openapi/lib/model/system_config_generated_fullsize_image_dto.dart @@ -15,7 +15,7 @@ class SystemConfigGeneratedFullsizeImageDto { SystemConfigGeneratedFullsizeImageDto({ required this.enabled, required this.format, - required this.progressive, + this.progressive = false, required this.quality, }); @@ -67,7 +67,7 @@ class SystemConfigGeneratedFullsizeImageDto { return SystemConfigGeneratedFullsizeImageDto( enabled: mapValueOfType(json, r'enabled')!, format: ImageFormat.fromJson(json[r'format'])!, - progressive: mapValueOfType(json, r'progressive')!, + progressive: mapValueOfType(json, r'progressive') ?? false, quality: mapValueOfType(json, r'quality')!, ); } @@ -118,7 +118,6 @@ class SystemConfigGeneratedFullsizeImageDto { static const requiredKeys = { 'enabled', 'format', - 'progressive', 'quality', }; } diff --git a/mobile/openapi/lib/model/system_config_generated_image_dto.dart b/mobile/openapi/lib/model/system_config_generated_image_dto.dart index 7dd5b2be7e..a46fc13d27 100644 --- a/mobile/openapi/lib/model/system_config_generated_image_dto.dart +++ b/mobile/openapi/lib/model/system_config_generated_image_dto.dart @@ -14,7 +14,7 @@ class SystemConfigGeneratedImageDto { /// Returns a new [SystemConfigGeneratedImageDto] instance. SystemConfigGeneratedImageDto({ required this.format, - required this.progressive, + this.progressive = false, required this.quality, required this.size, }); @@ -67,7 +67,7 @@ class SystemConfigGeneratedImageDto { return SystemConfigGeneratedImageDto( format: ImageFormat.fromJson(json[r'format'])!, - progressive: mapValueOfType(json, r'progressive')!, + progressive: mapValueOfType(json, r'progressive') ?? false, quality: mapValueOfType(json, r'quality')!, size: mapValueOfType(json, r'size')!, ); @@ -118,7 +118,6 @@ class SystemConfigGeneratedImageDto { /// The list of required keys that must be present in a JSON. static const requiredKeys = { 'format', - 'progressive', 'quality', 'size', }; diff --git a/open-api/immich-openapi-specs.json b/open-api/immich-openapi-specs.json index 1129dd4862..5f133b4f85 100644 --- a/open-api/immich-openapi-specs.json +++ b/open-api/immich-openapi-specs.json @@ -22625,6 +22625,7 @@ ] }, "progressive": { + "default": false, "type": "boolean" }, "quality": { @@ -22636,7 +22637,6 @@ "required": [ "enabled", "format", - "progressive", "quality" ], "type": "object" @@ -22651,6 +22651,7 @@ ] }, "progressive": { + "default": false, "type": "boolean" }, "quality": { @@ -22665,7 +22666,6 @@ }, "required": [ "format", - "progressive", "quality", "size" ], diff --git a/open-api/typescript-sdk/src/fetch-client.ts b/open-api/typescript-sdk/src/fetch-client.ts index a6bbf5cdde..52f6621d97 100644 --- a/open-api/typescript-sdk/src/fetch-client.ts +++ b/open-api/typescript-sdk/src/fetch-client.ts @@ -1538,12 +1538,12 @@ export type SystemConfigFFmpegDto = { export type SystemConfigGeneratedFullsizeImageDto = { enabled: boolean; format: ImageFormat; - progressive: boolean; + progressive?: boolean; quality: number; }; export type SystemConfigGeneratedImageDto = { format: ImageFormat; - progressive: boolean; + progressive?: boolean; quality: number; size: number; }; diff --git a/server/src/controllers/system-config.controller.spec.ts b/server/src/controllers/system-config.controller.spec.ts index 48b8c1bcf0..bbd1241dc5 100644 --- a/server/src/controllers/system-config.controller.spec.ts +++ b/server/src/controllers/system-config.controller.spec.ts @@ -70,5 +70,33 @@ describe(SystemConfigController.name, () => { expect(body).toEqual(errorDto.badRequest(['nightlyTasks.databaseCleanup must be a boolean value'])); }); }); + + describe('image', () => { + it('should accept config without optional progressive property', async () => { + const config = _.cloneDeep(defaults); + delete config.image.thumbnail.progressive; + delete config.image.preview.progressive; + delete config.image.fullsize.progressive; + const { status } = await request(ctx.getHttpServer()).put('/system-config').send(config); + expect(status).toBe(200); + }); + + it('should accept config with progressive set to true', async () => { + const config = _.cloneDeep(defaults); + config.image.thumbnail.progressive = true; + config.image.preview.progressive = true; + config.image.fullsize.progressive = true; + const { status } = await request(ctx.getHttpServer()).put('/system-config').send(config); + expect(status).toBe(200); + }); + + it('should reject invalid progressive value', async () => { + const config = _.cloneDeep(defaults); + (config.image.thumbnail.progressive as any) = 'invalid'; + const { status, body } = await request(ctx.getHttpServer()).put('/system-config').send(config); + expect(status).toBe(400); + expect(body).toEqual(errorDto.badRequest(['image.thumbnail.progressive must be a boolean value'])); + }); + }); }); }); diff --git a/server/src/dtos/system-config.dto.ts b/server/src/dtos/system-config.dto.ts index 4301d7193f..b0d5a0646d 100644 --- a/server/src/dtos/system-config.dto.ts +++ b/server/src/dtos/system-config.dto.ts @@ -586,8 +586,8 @@ class SystemConfigGeneratedImageDto { @ApiProperty({ type: 'integer' }) size!: number; - @ValidateBoolean() - progressive!: boolean; + @ValidateBoolean({ optional: true, default: false }) + progressive?: boolean; } class SystemConfigGeneratedFullsizeImageDto { @@ -604,8 +604,8 @@ class SystemConfigGeneratedFullsizeImageDto { @ApiProperty({ type: 'integer' }) quality!: number; - @ValidateBoolean() - progressive!: boolean; + @ValidateBoolean({ optional: true, default: false }) + progressive?: boolean; } export class SystemConfigImageDto { diff --git a/server/src/types.ts b/server/src/types.ts index 9f8c8011e5..f851ebd994 100644 --- a/server/src/types.ts +++ b/server/src/types.ts @@ -36,14 +36,14 @@ export type FullsizeImageOptions = { format: ImageFormat; quality: number; enabled: boolean; - progressive: boolean; + progressive?: boolean; }; export type ImageOptions = { format: ImageFormat; quality: number; size: number; - progressive: boolean; + progressive?: boolean; }; export type RawImageInfo = {