Compare commits

..

4 Commits

Author SHA1 Message Date
izzy
efe0606863 fix: ensure name spec is defined correctly 2026-01-12 14:05:37 +00:00
izzy
d1fb292055 fix: annotate oneOf in open api schema 2026-01-12 13:50:36 +00:00
izzy
b49ee6d90d feat: create job with data dto 2026-01-12 12:32:55 +00:00
Jason Rasmussen
d4ad523eb3 refactor(web): user app settings (#25177) 2026-01-10 07:58:50 -05:00
31 changed files with 2066 additions and 120 deletions

View File

@@ -210,6 +210,7 @@ Class | Method | HTTP request | Description
*QueuesApi* | [**getQueue**](doc//QueuesApi.md#getqueue) | **GET** /queues/{name} | Retrieve a queue
*QueuesApi* | [**getQueueJobs**](doc//QueuesApi.md#getqueuejobs) | **GET** /queues/{name}/jobs | Retrieve queue jobs
*QueuesApi* | [**getQueues**](doc//QueuesApi.md#getqueues) | **GET** /queues | List all queues
*QueuesApi* | [**queueJob**](doc//QueuesApi.md#queuejob) | **POST** /queues/job | Create a manual job
*QueuesApi* | [**updateQueue**](doc//QueuesApi.md#updatequeue) | **PUT** /queues/{name} | Update a queue
*SearchApi* | [**getAssetsByCity**](doc//SearchApi.md#getassetsbycity) | **GET** /search/cities | Retrieve assets by city
*SearchApi* | [**getExploreData**](doc//SearchApi.md#getexploredata) | **GET** /search/explore | Retrieve explore data
@@ -388,6 +389,7 @@ Class | Method | HTTP request | Description
- [AudioCodec](doc//AudioCodec.md)
- [AuthStatusResponseDto](doc//AuthStatusResponseDto.md)
- [AvatarUpdate](doc//AvatarUpdate.md)
- [BaseJobData](doc//BaseJobData.md)
- [BulkIdErrorReason](doc//BulkIdErrorReason.md)
- [BulkIdResponseDto](doc//BulkIdResponseDto.md)
- [BulkIdsDto](doc//BulkIdsDto.md)
@@ -404,6 +406,7 @@ Class | Method | HTTP request | Description
- [CreateLibraryDto](doc//CreateLibraryDto.md)
- [CreateProfileImageResponseDto](doc//CreateProfileImageResponseDto.md)
- [CropParameters](doc//CropParameters.md)
- [DatabaseBackup](doc//DatabaseBackup.md)
- [DatabaseBackupConfig](doc//DatabaseBackupConfig.md)
- [DownloadArchiveInfo](doc//DownloadArchiveInfo.md)
- [DownloadInfoDto](doc//DownloadInfoDto.md)
@@ -421,8 +424,14 @@ Class | Method | HTTP request | Description
- [FoldersUpdate](doc//FoldersUpdate.md)
- [ImageFormat](doc//ImageFormat.md)
- [JobCreateDto](doc//JobCreateDto.md)
- [JobDatabaseBackup](doc//JobDatabaseBackup.md)
- [JobMemoryCleanup](doc//JobMemoryCleanup.md)
- [JobMemoryGenerate](doc//JobMemoryGenerate.md)
- [JobName](doc//JobName.md)
- [JobPersonCleanup](doc//JobPersonCleanup.md)
- [JobSettingsDto](doc//JobSettingsDto.md)
- [JobTagCleanup](doc//JobTagCleanup.md)
- [JobUserDeleteCheck](doc//JobUserDeleteCheck.md)
- [LibraryResponseDto](doc//LibraryResponseDto.md)
- [LibraryStatsResponseDto](doc//LibraryStatsResponseDto.md)
- [LicenseKeyDto](doc//LicenseKeyDto.md)
@@ -440,7 +449,9 @@ Class | Method | HTTP request | Description
- [MapReverseGeocodeResponseDto](doc//MapReverseGeocodeResponseDto.md)
- [MemoriesResponse](doc//MemoriesResponse.md)
- [MemoriesUpdate](doc//MemoriesUpdate.md)
- [MemoryCleanup](doc//MemoryCleanup.md)
- [MemoryCreateDto](doc//MemoryCreateDto.md)
- [MemoryGenerate](doc//MemoryGenerate.md)
- [MemoryResponseDto](doc//MemoryResponseDto.md)
- [MemorySearchOrder](doc//MemorySearchOrder.md)
- [MemoryStatisticsResponseDto](doc//MemoryStatisticsResponseDto.md)
@@ -475,6 +486,7 @@ Class | Method | HTTP request | Description
- [PeopleUpdateDto](doc//PeopleUpdateDto.md)
- [PeopleUpdateItem](doc//PeopleUpdateItem.md)
- [Permission](doc//Permission.md)
- [PersonCleanup](doc//PersonCleanup.md)
- [PersonCreateDto](doc//PersonCreateDto.md)
- [PersonResponseDto](doc//PersonResponseDto.md)
- [PersonStatisticsResponseDto](doc//PersonStatisticsResponseDto.md)
@@ -495,6 +507,8 @@ Class | Method | HTTP request | Description
- [QueueCommand](doc//QueueCommand.md)
- [QueueCommandDto](doc//QueueCommandDto.md)
- [QueueDeleteDto](doc//QueueDeleteDto.md)
- [QueueJobCreateDto](doc//QueueJobCreateDto.md)
- [QueueJobCreateDtoJob](doc//QueueJobCreateDtoJob.md)
- [QueueJobResponseDto](doc//QueueJobResponseDto.md)
- [QueueJobStatus](doc//QueueJobStatus.md)
- [QueueName](doc//QueueName.md)
@@ -617,6 +631,7 @@ Class | Method | HTTP request | Description
- [SystemConfigUserDto](doc//SystemConfigUserDto.md)
- [TagBulkAssetsDto](doc//TagBulkAssetsDto.md)
- [TagBulkAssetsResponseDto](doc//TagBulkAssetsResponseDto.md)
- [TagCleanup](doc//TagCleanup.md)
- [TagCreateDto](doc//TagCreateDto.md)
- [TagResponseDto](doc//TagResponseDto.md)
- [TagUpdateDto](doc//TagUpdateDto.md)
@@ -642,6 +657,7 @@ Class | Method | HTTP request | Description
- [UserAdminResponseDto](doc//UserAdminResponseDto.md)
- [UserAdminUpdateDto](doc//UserAdminUpdateDto.md)
- [UserAvatarColor](doc//UserAvatarColor.md)
- [UserDeleteCheck](doc//UserDeleteCheck.md)
- [UserLicense](doc//UserLicense.md)
- [UserMetadataKey](doc//UserMetadataKey.md)
- [UserPreferencesResponseDto](doc//UserPreferencesResponseDto.md)

View File

@@ -134,6 +134,7 @@ part 'model/asset_visibility.dart';
part 'model/audio_codec.dart';
part 'model/auth_status_response_dto.dart';
part 'model/avatar_update.dart';
part 'model/base_job_data.dart';
part 'model/bulk_id_error_reason.dart';
part 'model/bulk_id_response_dto.dart';
part 'model/bulk_ids_dto.dart';
@@ -150,6 +151,7 @@ part 'model/create_album_dto.dart';
part 'model/create_library_dto.dart';
part 'model/create_profile_image_response_dto.dart';
part 'model/crop_parameters.dart';
part 'model/database_backup.dart';
part 'model/database_backup_config.dart';
part 'model/download_archive_info.dart';
part 'model/download_info_dto.dart';
@@ -167,8 +169,14 @@ part 'model/folders_response.dart';
part 'model/folders_update.dart';
part 'model/image_format.dart';
part 'model/job_create_dto.dart';
part 'model/job_database_backup.dart';
part 'model/job_memory_cleanup.dart';
part 'model/job_memory_generate.dart';
part 'model/job_name.dart';
part 'model/job_person_cleanup.dart';
part 'model/job_settings_dto.dart';
part 'model/job_tag_cleanup.dart';
part 'model/job_user_delete_check.dart';
part 'model/library_response_dto.dart';
part 'model/library_stats_response_dto.dart';
part 'model/license_key_dto.dart';
@@ -186,7 +194,9 @@ part 'model/map_marker_response_dto.dart';
part 'model/map_reverse_geocode_response_dto.dart';
part 'model/memories_response.dart';
part 'model/memories_update.dart';
part 'model/memory_cleanup.dart';
part 'model/memory_create_dto.dart';
part 'model/memory_generate.dart';
part 'model/memory_response_dto.dart';
part 'model/memory_search_order.dart';
part 'model/memory_statistics_response_dto.dart';
@@ -221,6 +231,7 @@ part 'model/people_update.dart';
part 'model/people_update_dto.dart';
part 'model/people_update_item.dart';
part 'model/permission.dart';
part 'model/person_cleanup.dart';
part 'model/person_create_dto.dart';
part 'model/person_response_dto.dart';
part 'model/person_statistics_response_dto.dart';
@@ -241,6 +252,8 @@ part 'model/purchase_update.dart';
part 'model/queue_command.dart';
part 'model/queue_command_dto.dart';
part 'model/queue_delete_dto.dart';
part 'model/queue_job_create_dto.dart';
part 'model/queue_job_create_dto_job.dart';
part 'model/queue_job_response_dto.dart';
part 'model/queue_job_status.dart';
part 'model/queue_name.dart';
@@ -363,6 +376,7 @@ part 'model/system_config_trash_dto.dart';
part 'model/system_config_user_dto.dart';
part 'model/tag_bulk_assets_dto.dart';
part 'model/tag_bulk_assets_response_dto.dart';
part 'model/tag_cleanup.dart';
part 'model/tag_create_dto.dart';
part 'model/tag_response_dto.dart';
part 'model/tag_update_dto.dart';
@@ -388,6 +402,7 @@ part 'model/user_admin_delete_dto.dart';
part 'model/user_admin_response_dto.dart';
part 'model/user_admin_update_dto.dart';
part 'model/user_avatar_color.dart';
part 'model/user_delete_check.dart';
part 'model/user_license.dart';
part 'model/user_metadata_key.dart';
part 'model/user_preferences_response_dto.dart';

View File

@@ -245,6 +245,54 @@ class QueuesApi {
return null;
}
/// Create a manual job
///
/// Run a specific job. Most jobs are queued automatically, but this endpoint allows for manual creation of a handful of jobs, including various cleanup tasks, as well as creating a new database backup.
///
/// Note: This method returns the HTTP [Response].
///
/// Parameters:
///
/// * [QueueJobCreateDto] queueJobCreateDto (required):
Future<Response> queueJobWithHttpInfo(QueueJobCreateDto queueJobCreateDto,) async {
// ignore: prefer_const_declarations
final apiPath = r'/queues/job';
// ignore: prefer_final_locals
Object? postBody = queueJobCreateDto;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>['application/json'];
return apiClient.invokeAPI(
apiPath,
'POST',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// Create a manual job
///
/// Run a specific job. Most jobs are queued automatically, but this endpoint allows for manual creation of a handful of jobs, including various cleanup tasks, as well as creating a new database backup.
///
/// Parameters:
///
/// * [QueueJobCreateDto] queueJobCreateDto (required):
Future<void> queueJob(QueueJobCreateDto queueJobCreateDto,) async {
final response = await queueJobWithHttpInfo(queueJobCreateDto,);
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
}
/// Update a queue
///
/// Change the paused status of a specific queue.

View File

@@ -316,6 +316,8 @@ class ApiClient {
return AuthStatusResponseDto.fromJson(value);
case 'AvatarUpdate':
return AvatarUpdate.fromJson(value);
case 'BaseJobData':
return BaseJobData.fromJson(value);
case 'BulkIdErrorReason':
return BulkIdErrorReasonTypeTransformer().decode(value);
case 'BulkIdResponseDto':
@@ -348,6 +350,8 @@ class ApiClient {
return CreateProfileImageResponseDto.fromJson(value);
case 'CropParameters':
return CropParameters.fromJson(value);
case 'DatabaseBackup':
return DatabaseBackupTypeTransformer().decode(value);
case 'DatabaseBackupConfig':
return DatabaseBackupConfig.fromJson(value);
case 'DownloadArchiveInfo':
@@ -382,10 +386,22 @@ class ApiClient {
return ImageFormatTypeTransformer().decode(value);
case 'JobCreateDto':
return JobCreateDto.fromJson(value);
case 'JobDatabaseBackup':
return JobDatabaseBackup.fromJson(value);
case 'JobMemoryCleanup':
return JobMemoryCleanup.fromJson(value);
case 'JobMemoryGenerate':
return JobMemoryGenerate.fromJson(value);
case 'JobName':
return JobNameTypeTransformer().decode(value);
case 'JobPersonCleanup':
return JobPersonCleanup.fromJson(value);
case 'JobSettingsDto':
return JobSettingsDto.fromJson(value);
case 'JobTagCleanup':
return JobTagCleanup.fromJson(value);
case 'JobUserDeleteCheck':
return JobUserDeleteCheck.fromJson(value);
case 'LibraryResponseDto':
return LibraryResponseDto.fromJson(value);
case 'LibraryStatsResponseDto':
@@ -420,8 +436,12 @@ class ApiClient {
return MemoriesResponse.fromJson(value);
case 'MemoriesUpdate':
return MemoriesUpdate.fromJson(value);
case 'MemoryCleanup':
return MemoryCleanupTypeTransformer().decode(value);
case 'MemoryCreateDto':
return MemoryCreateDto.fromJson(value);
case 'MemoryGenerate':
return MemoryGenerateTypeTransformer().decode(value);
case 'MemoryResponseDto':
return MemoryResponseDto.fromJson(value);
case 'MemorySearchOrder':
@@ -490,6 +510,8 @@ class ApiClient {
return PeopleUpdateItem.fromJson(value);
case 'Permission':
return PermissionTypeTransformer().decode(value);
case 'PersonCleanup':
return PersonCleanupTypeTransformer().decode(value);
case 'PersonCreateDto':
return PersonCreateDto.fromJson(value);
case 'PersonResponseDto':
@@ -530,6 +552,10 @@ class ApiClient {
return QueueCommandDto.fromJson(value);
case 'QueueDeleteDto':
return QueueDeleteDto.fromJson(value);
case 'QueueJobCreateDto':
return QueueJobCreateDto.fromJson(value);
case 'QueueJobCreateDtoJob':
return QueueJobCreateDtoJob.fromJson(value);
case 'QueueJobResponseDto':
return QueueJobResponseDto.fromJson(value);
case 'QueueJobStatus':
@@ -774,6 +800,8 @@ class ApiClient {
return TagBulkAssetsDto.fromJson(value);
case 'TagBulkAssetsResponseDto':
return TagBulkAssetsResponseDto.fromJson(value);
case 'TagCleanup':
return TagCleanupTypeTransformer().decode(value);
case 'TagCreateDto':
return TagCreateDto.fromJson(value);
case 'TagResponseDto':
@@ -824,6 +852,8 @@ class ApiClient {
return UserAdminUpdateDto.fromJson(value);
case 'UserAvatarColor':
return UserAvatarColorTypeTransformer().decode(value);
case 'UserDeleteCheck':
return UserDeleteCheckTypeTransformer().decode(value);
case 'UserLicense':
return UserLicense.fromJson(value);
case 'UserMetadataKey':

View File

@@ -91,6 +91,9 @@ String parameterToString(dynamic value) {
if (value is Colorspace) {
return ColorspaceTypeTransformer().encode(value).toString();
}
if (value is DatabaseBackup) {
return DatabaseBackupTypeTransformer().encode(value).toString();
}
if (value is ImageFormat) {
return ImageFormatTypeTransformer().encode(value).toString();
}
@@ -106,6 +109,12 @@ String parameterToString(dynamic value) {
if (value is ManualJobName) {
return ManualJobNameTypeTransformer().encode(value).toString();
}
if (value is MemoryCleanup) {
return MemoryCleanupTypeTransformer().encode(value).toString();
}
if (value is MemoryGenerate) {
return MemoryGenerateTypeTransformer().encode(value).toString();
}
if (value is MemorySearchOrder) {
return MemorySearchOrderTypeTransformer().encode(value).toString();
}
@@ -130,6 +139,9 @@ String parameterToString(dynamic value) {
if (value is Permission) {
return PermissionTypeTransformer().encode(value).toString();
}
if (value is PersonCleanup) {
return PersonCleanupTypeTransformer().encode(value).toString();
}
if (value is PluginContextType) {
return PluginContextTypeTypeTransformer().encode(value).toString();
}
@@ -166,6 +178,9 @@ String parameterToString(dynamic value) {
if (value is SyncRequestType) {
return SyncRequestTypeTypeTransformer().encode(value).toString();
}
if (value is TagCleanup) {
return TagCleanupTypeTransformer().encode(value).toString();
}
if (value is ToneMapping) {
return ToneMappingTypeTransformer().encode(value).toString();
}
@@ -178,6 +193,9 @@ String parameterToString(dynamic value) {
if (value is UserAvatarColor) {
return UserAvatarColorTypeTransformer().encode(value).toString();
}
if (value is UserDeleteCheck) {
return UserDeleteCheckTypeTransformer().encode(value).toString();
}
if (value is UserMetadataKey) {
return UserMetadataKeyTypeTransformer().encode(value).toString();
}

View File

@@ -0,0 +1,108 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class BaseJobData {
/// Returns a new [BaseJobData] instance.
BaseJobData({
this.force,
});
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
bool? force;
@override
bool operator ==(Object other) => identical(this, other) || other is BaseJobData &&
other.force == force;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(force == null ? 0 : force!.hashCode);
@override
String toString() => 'BaseJobData[force=$force]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
if (this.force != null) {
json[r'force'] = this.force;
} else {
// json[r'force'] = null;
}
return json;
}
/// Returns a new [BaseJobData] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static BaseJobData? fromJson(dynamic value) {
upgradeDto(value, "BaseJobData");
if (value is Map) {
final json = value.cast<String, dynamic>();
return BaseJobData(
force: mapValueOfType<bool>(json, r'force'),
);
}
return null;
}
static List<BaseJobData> listFromJson(dynamic json, {bool growable = false,}) {
final result = <BaseJobData>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = BaseJobData.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, BaseJobData> mapFromJson(dynamic json) {
final map = <String, BaseJobData>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = BaseJobData.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of BaseJobData-objects as value to a dart map
static Map<String, List<BaseJobData>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<BaseJobData>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = BaseJobData.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
};
}

View File

@@ -0,0 +1,82 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class DatabaseBackup {
/// Instantiate a new enum with the provided [value].
const DatabaseBackup._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const databaseBackup = DatabaseBackup._(r'DatabaseBackup');
/// List of all possible values in this [enum][DatabaseBackup].
static const values = <DatabaseBackup>[
databaseBackup,
];
static DatabaseBackup? fromJson(dynamic value) => DatabaseBackupTypeTransformer().decode(value);
static List<DatabaseBackup> listFromJson(dynamic json, {bool growable = false,}) {
final result = <DatabaseBackup>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = DatabaseBackup.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [DatabaseBackup] to String,
/// and [decode] dynamic data back to [DatabaseBackup].
class DatabaseBackupTypeTransformer {
factory DatabaseBackupTypeTransformer() => _instance ??= const DatabaseBackupTypeTransformer._();
const DatabaseBackupTypeTransformer._();
String encode(DatabaseBackup data) => data.value;
/// Decodes a [dynamic value][data] to a DatabaseBackup.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
DatabaseBackup? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'DatabaseBackup': return DatabaseBackup.databaseBackup;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [DatabaseBackupTypeTransformer] instance.
static DatabaseBackupTypeTransformer? _instance;
}

View File

@@ -0,0 +1,107 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class JobDatabaseBackup {
/// Returns a new [JobDatabaseBackup] instance.
JobDatabaseBackup({
required this.data,
required this.name,
});
BaseJobData data;
DatabaseBackup name;
@override
bool operator ==(Object other) => identical(this, other) || other is JobDatabaseBackup &&
other.data == data &&
other.name == name;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(data.hashCode) +
(name.hashCode);
@override
String toString() => 'JobDatabaseBackup[data=$data, name=$name]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'data'] = this.data;
json[r'name'] = this.name;
return json;
}
/// Returns a new [JobDatabaseBackup] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static JobDatabaseBackup? fromJson(dynamic value) {
upgradeDto(value, "JobDatabaseBackup");
if (value is Map) {
final json = value.cast<String, dynamic>();
return JobDatabaseBackup(
data: BaseJobData.fromJson(json[r'data'])!,
name: DatabaseBackup.fromJson(json[r'name'])!,
);
}
return null;
}
static List<JobDatabaseBackup> listFromJson(dynamic json, {bool growable = false,}) {
final result = <JobDatabaseBackup>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = JobDatabaseBackup.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, JobDatabaseBackup> mapFromJson(dynamic json) {
final map = <String, JobDatabaseBackup>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = JobDatabaseBackup.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of JobDatabaseBackup-objects as value to a dart map
static Map<String, List<JobDatabaseBackup>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<JobDatabaseBackup>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = JobDatabaseBackup.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'data',
'name',
};
}

View File

@@ -0,0 +1,107 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class JobMemoryCleanup {
/// Returns a new [JobMemoryCleanup] instance.
JobMemoryCleanup({
required this.data,
required this.name,
});
BaseJobData data;
MemoryCleanup name;
@override
bool operator ==(Object other) => identical(this, other) || other is JobMemoryCleanup &&
other.data == data &&
other.name == name;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(data.hashCode) +
(name.hashCode);
@override
String toString() => 'JobMemoryCleanup[data=$data, name=$name]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'data'] = this.data;
json[r'name'] = this.name;
return json;
}
/// Returns a new [JobMemoryCleanup] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static JobMemoryCleanup? fromJson(dynamic value) {
upgradeDto(value, "JobMemoryCleanup");
if (value is Map) {
final json = value.cast<String, dynamic>();
return JobMemoryCleanup(
data: BaseJobData.fromJson(json[r'data'])!,
name: MemoryCleanup.fromJson(json[r'name'])!,
);
}
return null;
}
static List<JobMemoryCleanup> listFromJson(dynamic json, {bool growable = false,}) {
final result = <JobMemoryCleanup>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = JobMemoryCleanup.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, JobMemoryCleanup> mapFromJson(dynamic json) {
final map = <String, JobMemoryCleanup>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = JobMemoryCleanup.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of JobMemoryCleanup-objects as value to a dart map
static Map<String, List<JobMemoryCleanup>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<JobMemoryCleanup>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = JobMemoryCleanup.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'data',
'name',
};
}

View File

@@ -0,0 +1,107 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class JobMemoryGenerate {
/// Returns a new [JobMemoryGenerate] instance.
JobMemoryGenerate({
required this.data,
required this.name,
});
BaseJobData data;
MemoryGenerate name;
@override
bool operator ==(Object other) => identical(this, other) || other is JobMemoryGenerate &&
other.data == data &&
other.name == name;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(data.hashCode) +
(name.hashCode);
@override
String toString() => 'JobMemoryGenerate[data=$data, name=$name]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'data'] = this.data;
json[r'name'] = this.name;
return json;
}
/// Returns a new [JobMemoryGenerate] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static JobMemoryGenerate? fromJson(dynamic value) {
upgradeDto(value, "JobMemoryGenerate");
if (value is Map) {
final json = value.cast<String, dynamic>();
return JobMemoryGenerate(
data: BaseJobData.fromJson(json[r'data'])!,
name: MemoryGenerate.fromJson(json[r'name'])!,
);
}
return null;
}
static List<JobMemoryGenerate> listFromJson(dynamic json, {bool growable = false,}) {
final result = <JobMemoryGenerate>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = JobMemoryGenerate.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, JobMemoryGenerate> mapFromJson(dynamic json) {
final map = <String, JobMemoryGenerate>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = JobMemoryGenerate.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of JobMemoryGenerate-objects as value to a dart map
static Map<String, List<JobMemoryGenerate>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<JobMemoryGenerate>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = JobMemoryGenerate.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'data',
'name',
};
}

View File

@@ -0,0 +1,107 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class JobPersonCleanup {
/// Returns a new [JobPersonCleanup] instance.
JobPersonCleanup({
required this.data,
required this.name,
});
BaseJobData data;
PersonCleanup name;
@override
bool operator ==(Object other) => identical(this, other) || other is JobPersonCleanup &&
other.data == data &&
other.name == name;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(data.hashCode) +
(name.hashCode);
@override
String toString() => 'JobPersonCleanup[data=$data, name=$name]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'data'] = this.data;
json[r'name'] = this.name;
return json;
}
/// Returns a new [JobPersonCleanup] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static JobPersonCleanup? fromJson(dynamic value) {
upgradeDto(value, "JobPersonCleanup");
if (value is Map) {
final json = value.cast<String, dynamic>();
return JobPersonCleanup(
data: BaseJobData.fromJson(json[r'data'])!,
name: PersonCleanup.fromJson(json[r'name'])!,
);
}
return null;
}
static List<JobPersonCleanup> listFromJson(dynamic json, {bool growable = false,}) {
final result = <JobPersonCleanup>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = JobPersonCleanup.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, JobPersonCleanup> mapFromJson(dynamic json) {
final map = <String, JobPersonCleanup>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = JobPersonCleanup.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of JobPersonCleanup-objects as value to a dart map
static Map<String, List<JobPersonCleanup>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<JobPersonCleanup>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = JobPersonCleanup.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'data',
'name',
};
}

View File

@@ -0,0 +1,107 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class JobTagCleanup {
/// Returns a new [JobTagCleanup] instance.
JobTagCleanup({
required this.data,
required this.name,
});
BaseJobData data;
TagCleanup name;
@override
bool operator ==(Object other) => identical(this, other) || other is JobTagCleanup &&
other.data == data &&
other.name == name;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(data.hashCode) +
(name.hashCode);
@override
String toString() => 'JobTagCleanup[data=$data, name=$name]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'data'] = this.data;
json[r'name'] = this.name;
return json;
}
/// Returns a new [JobTagCleanup] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static JobTagCleanup? fromJson(dynamic value) {
upgradeDto(value, "JobTagCleanup");
if (value is Map) {
final json = value.cast<String, dynamic>();
return JobTagCleanup(
data: BaseJobData.fromJson(json[r'data'])!,
name: TagCleanup.fromJson(json[r'name'])!,
);
}
return null;
}
static List<JobTagCleanup> listFromJson(dynamic json, {bool growable = false,}) {
final result = <JobTagCleanup>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = JobTagCleanup.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, JobTagCleanup> mapFromJson(dynamic json) {
final map = <String, JobTagCleanup>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = JobTagCleanup.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of JobTagCleanup-objects as value to a dart map
static Map<String, List<JobTagCleanup>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<JobTagCleanup>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = JobTagCleanup.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'data',
'name',
};
}

View File

@@ -0,0 +1,107 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class JobUserDeleteCheck {
/// Returns a new [JobUserDeleteCheck] instance.
JobUserDeleteCheck({
required this.data,
required this.name,
});
BaseJobData data;
UserDeleteCheck name;
@override
bool operator ==(Object other) => identical(this, other) || other is JobUserDeleteCheck &&
other.data == data &&
other.name == name;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(data.hashCode) +
(name.hashCode);
@override
String toString() => 'JobUserDeleteCheck[data=$data, name=$name]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'data'] = this.data;
json[r'name'] = this.name;
return json;
}
/// Returns a new [JobUserDeleteCheck] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static JobUserDeleteCheck? fromJson(dynamic value) {
upgradeDto(value, "JobUserDeleteCheck");
if (value is Map) {
final json = value.cast<String, dynamic>();
return JobUserDeleteCheck(
data: BaseJobData.fromJson(json[r'data'])!,
name: UserDeleteCheck.fromJson(json[r'name'])!,
);
}
return null;
}
static List<JobUserDeleteCheck> listFromJson(dynamic json, {bool growable = false,}) {
final result = <JobUserDeleteCheck>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = JobUserDeleteCheck.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, JobUserDeleteCheck> mapFromJson(dynamic json) {
final map = <String, JobUserDeleteCheck>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = JobUserDeleteCheck.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of JobUserDeleteCheck-objects as value to a dart map
static Map<String, List<JobUserDeleteCheck>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<JobUserDeleteCheck>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = JobUserDeleteCheck.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'data',
'name',
};
}

View File

@@ -0,0 +1,82 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class MemoryCleanup {
/// Instantiate a new enum with the provided [value].
const MemoryCleanup._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const memoryCleanup = MemoryCleanup._(r'MemoryCleanup');
/// List of all possible values in this [enum][MemoryCleanup].
static const values = <MemoryCleanup>[
memoryCleanup,
];
static MemoryCleanup? fromJson(dynamic value) => MemoryCleanupTypeTransformer().decode(value);
static List<MemoryCleanup> listFromJson(dynamic json, {bool growable = false,}) {
final result = <MemoryCleanup>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = MemoryCleanup.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [MemoryCleanup] to String,
/// and [decode] dynamic data back to [MemoryCleanup].
class MemoryCleanupTypeTransformer {
factory MemoryCleanupTypeTransformer() => _instance ??= const MemoryCleanupTypeTransformer._();
const MemoryCleanupTypeTransformer._();
String encode(MemoryCleanup data) => data.value;
/// Decodes a [dynamic value][data] to a MemoryCleanup.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
MemoryCleanup? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'MemoryCleanup': return MemoryCleanup.memoryCleanup;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [MemoryCleanupTypeTransformer] instance.
static MemoryCleanupTypeTransformer? _instance;
}

View File

@@ -0,0 +1,82 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class MemoryGenerate {
/// Instantiate a new enum with the provided [value].
const MemoryGenerate._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const memoryGenerate = MemoryGenerate._(r'MemoryGenerate');
/// List of all possible values in this [enum][MemoryGenerate].
static const values = <MemoryGenerate>[
memoryGenerate,
];
static MemoryGenerate? fromJson(dynamic value) => MemoryGenerateTypeTransformer().decode(value);
static List<MemoryGenerate> listFromJson(dynamic json, {bool growable = false,}) {
final result = <MemoryGenerate>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = MemoryGenerate.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [MemoryGenerate] to String,
/// and [decode] dynamic data back to [MemoryGenerate].
class MemoryGenerateTypeTransformer {
factory MemoryGenerateTypeTransformer() => _instance ??= const MemoryGenerateTypeTransformer._();
const MemoryGenerateTypeTransformer._();
String encode(MemoryGenerate data) => data.value;
/// Decodes a [dynamic value][data] to a MemoryGenerate.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
MemoryGenerate? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'MemoryGenerate': return MemoryGenerate.memoryGenerate;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [MemoryGenerateTypeTransformer] instance.
static MemoryGenerateTypeTransformer? _instance;
}

View File

@@ -0,0 +1,82 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class PersonCleanup {
/// Instantiate a new enum with the provided [value].
const PersonCleanup._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const personCleanup = PersonCleanup._(r'PersonCleanup');
/// List of all possible values in this [enum][PersonCleanup].
static const values = <PersonCleanup>[
personCleanup,
];
static PersonCleanup? fromJson(dynamic value) => PersonCleanupTypeTransformer().decode(value);
static List<PersonCleanup> listFromJson(dynamic json, {bool growable = false,}) {
final result = <PersonCleanup>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = PersonCleanup.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [PersonCleanup] to String,
/// and [decode] dynamic data back to [PersonCleanup].
class PersonCleanupTypeTransformer {
factory PersonCleanupTypeTransformer() => _instance ??= const PersonCleanupTypeTransformer._();
const PersonCleanupTypeTransformer._();
String encode(PersonCleanup data) => data.value;
/// Decodes a [dynamic value][data] to a PersonCleanup.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
PersonCleanup? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'PersonCleanup': return PersonCleanup.personCleanup;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [PersonCleanupTypeTransformer] instance.
static PersonCleanupTypeTransformer? _instance;
}

View File

@@ -0,0 +1,99 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class QueueJobCreateDto {
/// Returns a new [QueueJobCreateDto] instance.
QueueJobCreateDto({
required this.job,
});
QueueJobCreateDtoJob job;
@override
bool operator ==(Object other) => identical(this, other) || other is QueueJobCreateDto &&
other.job == job;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(job.hashCode);
@override
String toString() => 'QueueJobCreateDto[job=$job]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'job'] = this.job;
return json;
}
/// Returns a new [QueueJobCreateDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static QueueJobCreateDto? fromJson(dynamic value) {
upgradeDto(value, "QueueJobCreateDto");
if (value is Map) {
final json = value.cast<String, dynamic>();
return QueueJobCreateDto(
job: QueueJobCreateDtoJob.fromJson(json[r'job'])!,
);
}
return null;
}
static List<QueueJobCreateDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <QueueJobCreateDto>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = QueueJobCreateDto.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, QueueJobCreateDto> mapFromJson(dynamic json) {
final map = <String, QueueJobCreateDto>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = QueueJobCreateDto.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of QueueJobCreateDto-objects as value to a dart map
static Map<String, List<QueueJobCreateDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<QueueJobCreateDto>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = QueueJobCreateDto.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'job',
};
}

View File

@@ -0,0 +1,107 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class QueueJobCreateDtoJob {
/// Returns a new [QueueJobCreateDtoJob] instance.
QueueJobCreateDtoJob({
required this.data,
required this.name,
});
BaseJobData data;
DatabaseBackup name;
@override
bool operator ==(Object other) => identical(this, other) || other is QueueJobCreateDtoJob &&
other.data == data &&
other.name == name;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(data.hashCode) +
(name.hashCode);
@override
String toString() => 'QueueJobCreateDtoJob[data=$data, name=$name]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'data'] = this.data;
json[r'name'] = this.name;
return json;
}
/// Returns a new [QueueJobCreateDtoJob] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static QueueJobCreateDtoJob? fromJson(dynamic value) {
upgradeDto(value, "QueueJobCreateDtoJob");
if (value is Map) {
final json = value.cast<String, dynamic>();
return QueueJobCreateDtoJob(
data: BaseJobData.fromJson(json[r'data'])!,
name: DatabaseBackup.fromJson(json[r'name'])!,
);
}
return null;
}
static List<QueueJobCreateDtoJob> listFromJson(dynamic json, {bool growable = false,}) {
final result = <QueueJobCreateDtoJob>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = QueueJobCreateDtoJob.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, QueueJobCreateDtoJob> mapFromJson(dynamic json) {
final map = <String, QueueJobCreateDtoJob>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = QueueJobCreateDtoJob.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of QueueJobCreateDtoJob-objects as value to a dart map
static Map<String, List<QueueJobCreateDtoJob>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<QueueJobCreateDtoJob>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = QueueJobCreateDtoJob.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'data',
'name',
};
}

View File

@@ -0,0 +1,82 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class TagCleanup {
/// Instantiate a new enum with the provided [value].
const TagCleanup._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const tagCleanup = TagCleanup._(r'TagCleanup');
/// List of all possible values in this [enum][TagCleanup].
static const values = <TagCleanup>[
tagCleanup,
];
static TagCleanup? fromJson(dynamic value) => TagCleanupTypeTransformer().decode(value);
static List<TagCleanup> listFromJson(dynamic json, {bool growable = false,}) {
final result = <TagCleanup>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = TagCleanup.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [TagCleanup] to String,
/// and [decode] dynamic data back to [TagCleanup].
class TagCleanupTypeTransformer {
factory TagCleanupTypeTransformer() => _instance ??= const TagCleanupTypeTransformer._();
const TagCleanupTypeTransformer._();
String encode(TagCleanup data) => data.value;
/// Decodes a [dynamic value][data] to a TagCleanup.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
TagCleanup? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'TagCleanup': return TagCleanup.tagCleanup;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [TagCleanupTypeTransformer] instance.
static TagCleanupTypeTransformer? _instance;
}

View File

@@ -0,0 +1,82 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class UserDeleteCheck {
/// Instantiate a new enum with the provided [value].
const UserDeleteCheck._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const userDeleteCheck = UserDeleteCheck._(r'UserDeleteCheck');
/// List of all possible values in this [enum][UserDeleteCheck].
static const values = <UserDeleteCheck>[
userDeleteCheck,
];
static UserDeleteCheck? fromJson(dynamic value) => UserDeleteCheckTypeTransformer().decode(value);
static List<UserDeleteCheck> listFromJson(dynamic json, {bool growable = false,}) {
final result = <UserDeleteCheck>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = UserDeleteCheck.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [UserDeleteCheck] to String,
/// and [decode] dynamic data back to [UserDeleteCheck].
class UserDeleteCheckTypeTransformer {
factory UserDeleteCheckTypeTransformer() => _instance ??= const UserDeleteCheckTypeTransformer._();
const UserDeleteCheckTypeTransformer._();
String encode(UserDeleteCheck data) => data.value;
/// Decodes a [dynamic value][data] to a UserDeleteCheck.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
UserDeleteCheck? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'UserDeleteCheck': return UserDeleteCheck.userDeleteCheck;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [UserDeleteCheckTypeTransformer] instance.
static UserDeleteCheckTypeTransformer? _instance;
}

View File

@@ -8476,6 +8476,56 @@
"x-immich-state": "Alpha"
}
},
"/queues/job": {
"post": {
"description": "Run a specific job. Most jobs are queued automatically, but this endpoint allows for manual creation of a handful of jobs, including various cleanup tasks, as well as creating a new database backup.",
"operationId": "queueJob",
"parameters": [],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/QueueJobCreateDto"
}
}
},
"required": true
},
"responses": {
"204": {
"description": ""
}
},
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
],
"summary": "Create a manual job",
"tags": [
"Queues"
],
"x-immich-admin-only": true,
"x-immich-history": [
{
"version": "v2.5.0",
"state": "Added"
},
{
"version": "v2.5.0",
"state": "Alpha"
}
],
"x-immich-permission": "job.create",
"x-immich-state": "Alpha"
}
},
"/queues/{name}": {
"get": {
"description": "Retrieves a specific queue by its name.",
@@ -16525,6 +16575,14 @@
},
"type": "object"
},
"BaseJobData": {
"properties": {
"force": {
"type": "boolean"
}
},
"type": "object"
},
"BulkIdErrorReason": {
"enum": [
"duplicate",
@@ -16814,6 +16872,12 @@
],
"type": "object"
},
"DatabaseBackup": {
"enum": [
"DatabaseBackup"
],
"type": "string"
},
"DatabaseBackupConfig": {
"properties": {
"cronExpression": {
@@ -17205,6 +17269,63 @@
],
"type": "object"
},
"JobDatabaseBackup": {
"properties": {
"data": {
"$ref": "#/components/schemas/BaseJobData"
},
"name": {
"allOf": [
{
"$ref": "#/components/schemas/DatabaseBackup"
}
]
}
},
"required": [
"data",
"name"
],
"type": "object"
},
"JobMemoryCleanup": {
"properties": {
"data": {
"$ref": "#/components/schemas/BaseJobData"
},
"name": {
"allOf": [
{
"$ref": "#/components/schemas/MemoryCleanup"
}
]
}
},
"required": [
"data",
"name"
],
"type": "object"
},
"JobMemoryGenerate": {
"properties": {
"data": {
"$ref": "#/components/schemas/BaseJobData"
},
"name": {
"allOf": [
{
"$ref": "#/components/schemas/MemoryGenerate"
}
]
}
},
"required": [
"data",
"name"
],
"type": "object"
},
"JobName": {
"enum": [
"AssetDelete",
@@ -17266,6 +17387,25 @@
],
"type": "string"
},
"JobPersonCleanup": {
"properties": {
"data": {
"$ref": "#/components/schemas/BaseJobData"
},
"name": {
"allOf": [
{
"$ref": "#/components/schemas/PersonCleanup"
}
]
}
},
"required": [
"data",
"name"
],
"type": "object"
},
"JobSettingsDto": {
"properties": {
"concurrency": {
@@ -17278,6 +17418,44 @@
],
"type": "object"
},
"JobTagCleanup": {
"properties": {
"data": {
"$ref": "#/components/schemas/BaseJobData"
},
"name": {
"allOf": [
{
"$ref": "#/components/schemas/TagCleanup"
}
]
}
},
"required": [
"data",
"name"
],
"type": "object"
},
"JobUserDeleteCheck": {
"properties": {
"data": {
"$ref": "#/components/schemas/BaseJobData"
},
"name": {
"allOf": [
{
"$ref": "#/components/schemas/UserDeleteCheck"
}
]
}
},
"required": [
"data",
"name"
],
"type": "object"
},
"LibraryResponseDto": {
"properties": {
"assetCount": {
@@ -17622,6 +17800,12 @@
},
"type": "object"
},
"MemoryCleanup": {
"enum": [
"MemoryCleanup"
],
"type": "string"
},
"MemoryCreateDto": {
"properties": {
"assetIds": {
@@ -17660,6 +17844,12 @@
],
"type": "object"
},
"MemoryGenerate": {
"enum": [
"MemoryGenerate"
],
"type": "string"
},
"MemoryResponseDto": {
"properties": {
"assets": {
@@ -18605,6 +18795,12 @@
],
"type": "string"
},
"PersonCleanup": {
"enum": [
"PersonCleanup"
],
"type": "string"
},
"PersonCreateDto": {
"properties": {
"birthDate": {
@@ -19135,6 +19331,36 @@
},
"type": "object"
},
"QueueJobCreateDto": {
"properties": {
"job": {
"oneOf": [
{
"$ref": "#/components/schemas/JobTagCleanup"
},
{
"$ref": "#/components/schemas/JobPersonCleanup"
},
{
"$ref": "#/components/schemas/JobUserDeleteCheck"
},
{
"$ref": "#/components/schemas/JobMemoryCleanup"
},
{
"$ref": "#/components/schemas/JobMemoryGenerate"
},
{
"$ref": "#/components/schemas/JobDatabaseBackup"
}
]
}
},
"required": [
"job"
],
"type": "object"
},
"QueueJobResponseDto": {
"properties": {
"data": {
@@ -22828,6 +23054,12 @@
],
"type": "object"
},
"TagCleanup": {
"enum": [
"TagCleanup"
],
"type": "string"
},
"TagCreateDto": {
"properties": {
"color": {
@@ -23549,6 +23781,12 @@
],
"type": "string"
},
"UserDeleteCheck": {
"enum": [
"UserDeleteCheck"
],
"type": "string"
},
"UserLicense": {
"properties": {
"activatedAt": {

View File

@@ -1038,6 +1038,36 @@ export type QueueResponseDto = {
name: QueueName;
statistics: QueueStatisticsDto;
};
export type BaseJobData = {
force?: boolean;
};
export type JobTagCleanup = {
data: BaseJobData;
name: TagCleanup;
};
export type JobPersonCleanup = {
data: BaseJobData;
name: PersonCleanup;
};
export type JobUserDeleteCheck = {
data: BaseJobData;
name: UserDeleteCheck;
};
export type JobMemoryCleanup = {
data: BaseJobData;
name: MemoryCleanup;
};
export type JobMemoryGenerate = {
data: BaseJobData;
name: MemoryGenerate;
};
export type JobDatabaseBackup = {
data: BaseJobData;
name: DatabaseBackup;
};
export type QueueJobCreateDto = {
job: JobTagCleanup | JobPersonCleanup | JobUserDeleteCheck | JobMemoryCleanup | JobMemoryGenerate | JobDatabaseBackup;
};
export type QueueUpdateDto = {
isPaused?: boolean;
};
@@ -3834,6 +3864,18 @@ export function getQueues(opts?: Oazapfts.RequestOpts) {
...opts
}));
}
/**
* Create a manual job
*/
export function queueJob({ queueJobCreateDto }: {
queueJobCreateDto: QueueJobCreateDto;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchText("/queues/job", oazapfts.json({
...opts,
method: "POST",
body: queueJobCreateDto
})));
}
/**
* Retrieve a queue
*/
@@ -5594,6 +5636,24 @@ export enum PluginTriggerType {
AssetCreate = "AssetCreate",
PersonRecognized = "PersonRecognized"
}
export enum TagCleanup {
TagCleanup = "TagCleanup"
}
export enum PersonCleanup {
PersonCleanup = "PersonCleanup"
}
export enum UserDeleteCheck {
UserDeleteCheck = "UserDeleteCheck"
}
export enum MemoryCleanup {
MemoryCleanup = "MemoryCleanup"
}
export enum MemoryGenerate {
MemoryGenerate = "MemoryGenerate"
}
export enum DatabaseBackup {
DatabaseBackup = "DatabaseBackup"
}
export enum QueueJobStatus {
Active = "active",
Failed = "failed",

View File

@@ -1,9 +1,10 @@
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Put, Query } from '@nestjs/common';
import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Put, Query } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { Endpoint, HistoryBuilder } from 'src/decorators';
import { AuthDto } from 'src/dtos/auth.dto';
import {
QueueDeleteDto,
QueueJobCreateDto,
QueueJobResponseDto,
QueueJobSearchDto,
QueueNameParamDto,
@@ -19,6 +20,19 @@ import { QueueService } from 'src/services/queue.service';
export class QueueController {
constructor(private service: QueueService) {}
@Post('job')
@Authenticated({ permission: Permission.JobCreate, admin: true })
@HttpCode(HttpStatus.NO_CONTENT)
@Endpoint({
summary: 'Create a manual job',
description:
'Run a specific job. Most jobs are queued automatically, but this endpoint allows for manual creation of a handful of jobs, including various cleanup tasks, as well as creating a new database backup.',
history: new HistoryBuilder().added('v2.5.0').alpha('v2.5.0'),
})
queueJob(@Body() dto: QueueJobCreateDto): Promise<void> {
return this.service.createJob(dto);
}
@Get()
@Authenticated({ permission: Permission.QueueRead, admin: true })
@Endpoint({

View File

@@ -1,7 +1,85 @@
import { ApiProperty } from '@nestjs/swagger';
import { ApiExtraModels, ApiProperty, getSchemaPath } from '@nestjs/swagger';
import { ClassConstructor, Transform, Type } from 'class-transformer';
import { Equals, IsBoolean, IsDefined, IsOptional, ValidateNested } from 'class-validator';
import { HistoryBuilder, Property } from 'src/decorators';
import { JobName, QueueCommand, QueueJobStatus, QueueName } from 'src/enum';
import { ValidateBoolean, ValidateEnum } from 'src/validation';
import { transformToOneOf, ValidateBoolean, ValidateEnum } from 'src/validation';
class BaseJobData {
@IsOptional()
@IsBoolean()
force?: boolean;
}
class BaseJob {
@ValidateNested()
@Type(() => BaseJobData)
data!: BaseJobData;
}
class JobTagCleanup extends BaseJob {
@ApiProperty({ enumName: JobName.TagCleanup, enum: [JobName.TagCleanup] })
@Equals(JobName.TagCleanup)
name!: JobName.TagCleanup;
}
class JobPersonCleanup extends BaseJob {
@ApiProperty({ enumName: JobName.PersonCleanup, enum: [JobName.PersonCleanup] })
@Equals(JobName.PersonCleanup)
name!: JobName.PersonCleanup;
}
class JobUserDeleteCheck extends BaseJob {
@ApiProperty({ enumName: JobName.UserDeleteCheck, enum: [JobName.UserDeleteCheck] })
@Equals(JobName.UserDeleteCheck)
name!: JobName.UserDeleteCheck;
}
class JobMemoryCleanup extends BaseJob {
@ApiProperty({ enumName: JobName.MemoryCleanup, enum: [JobName.MemoryCleanup] })
@Equals(JobName.MemoryCleanup)
name!: JobName.MemoryCleanup;
}
class JobMemoryGenerate extends BaseJob {
@ApiProperty({ enumName: JobName.MemoryGenerate, enum: [JobName.MemoryGenerate] })
@Equals(JobName.MemoryGenerate)
name!: JobName.MemoryGenerate;
}
class JobDatabaseBackup extends BaseJob {
@ApiProperty({ enumName: JobName.DatabaseBackup, enum: [JobName.DatabaseBackup] })
@Equals(JobName.DatabaseBackup)
name!: JobName.DatabaseBackup;
}
const JOB_MAP: Record<string, ClassConstructor<object>> = {
[JobName.TagCleanup]: JobTagCleanup,
[JobName.PersonCleanup]: JobPersonCleanup,
[JobName.UserDeleteCheck]: JobUserDeleteCheck,
[JobName.MemoryCleanup]: JobMemoryCleanup,
[JobName.MemoryGenerate]: JobMemoryGenerate,
[JobName.DatabaseBackup]: JobDatabaseBackup,
};
@ApiExtraModels(...Object.values(JOB_MAP))
export class QueueJobCreateDto {
@ApiProperty({
oneOf: Object.values(JOB_MAP).map((job) => ({ $ref: getSchemaPath(job) })),
})
@ValidateNested()
@Transform(transformToOneOf(JOB_MAP))
@IsDefined({
message: `job.name must be one of ${Object.keys(JOB_MAP)}`,
})
job!:
| JobTagCleanup
| JobPersonCleanup
| JobUserDeleteCheck
| JobMemoryCleanup
| JobMemoryGenerate
| JobDatabaseBackup;
}
export class QueueNameParamDto {
@ValidateEnum({ enum: QueueName, name: 'QueueName' })

View File

@@ -12,6 +12,7 @@ import {
import {
QueueCommandDto,
QueueDeleteDto,
QueueJobCreateDto,
QueueJobResponseDto,
QueueJobSearchDto,
QueueResponseDto,
@@ -100,6 +101,10 @@ export class QueueService extends BaseService {
this.services = services;
}
createJob(dto: QueueJobCreateDto): Promise<void> {
return this.jobRepository.queue(dto.job);
}
async runCommandLegacy(name: QueueName, dto: QueueCommandDto): Promise<QueueResponseLegacyDto> {
this.logger.debug(`Handling command: queue=${name},command=${dto.command},force=${dto.force}`);

View File

@@ -7,7 +7,7 @@ import {
applyDecorators,
} from '@nestjs/common';
import { ApiProperty, ApiPropertyOptions } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
import { ClassConstructor, Transform, TransformFnParams, plainToInstance } from 'class-transformer';
import {
IsArray,
IsBoolean,
@@ -417,3 +417,8 @@ export function IsIPRange(options: IsIPRangeOptions, validationOptions?: Validat
validationOptions,
);
}
export const transformToOneOf =
<T extends Record<string, ClassConstructor<object>>>(map: T) =>
({ value }: TransformFnParams) =>
value && typeof value === 'object' && map[value.name] ? plainToInstance(map[value.name], value) : null;

View File

@@ -8,7 +8,6 @@
import AddToStackAction from '$lib/components/asset-viewer/actions/add-to-stack-action.svelte';
import ArchiveAction from '$lib/components/asset-viewer/actions/archive-action.svelte';
import DeleteAction from '$lib/components/asset-viewer/actions/delete-action.svelte';
import EditAction from '$lib/components/asset-viewer/actions/edit-action.svelte';
import KeepThisDeleteOthersAction from '$lib/components/asset-viewer/actions/keep-this-delete-others.svelte';
import RatingAction from '$lib/components/asset-viewer/actions/rating-action.svelte';
import RemoveAssetFromStack from '$lib/components/asset-viewer/actions/remove-asset-from-stack.svelte';
@@ -21,7 +20,7 @@
import UnstackAction from '$lib/components/asset-viewer/actions/unstack-action.svelte';
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import { AppRoute, ProjectionType } from '$lib/constants';
import { AppRoute } from '$lib/constants';
import { featureFlagsManager } from '$lib/managers/feature-flags-manager.svelte';
import { getGlobalActions } from '$lib/services/app.service';
import { getAssetActions, handleReplaceAsset } from '$lib/services/asset.service';
@@ -73,7 +72,7 @@
onUndoDelete?: OnUndoDelete;
onRunJob: (name: AssetJobName) => void;
onPlaySlideshow: () => void;
onEdit: () => void;
// onEdit: () => void;
onClose?: () => void;
playOriginalVideo: boolean;
setPlayOriginalVideo: (value: boolean) => void;
@@ -93,7 +92,7 @@
onRunJob,
onPlaySlideshow,
onClose,
onEdit,
// onEdit,
playOriginalVideo = false,
setPlayOriginalVideo,
}: Props = $props();
@@ -116,15 +115,18 @@
const { Share, Download, SharedLinkDownload, Offline, Favorite, Unfavorite, PlayMotionPhoto, StopMotionPhoto, Info } =
$derived(getAssetActions($t, asset));
const editorDisabled = $derived(
isOwner ||
asset.type !== AssetTypeEnum.Image ||
asset.livePhotoVideoId ||
(asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR &&
asset.originalPath.toLowerCase().endsWith('.insp')) ||
asset.originalPath.toLowerCase().endsWith('.gif') ||
asset.originalPath.toLowerCase().endsWith('.svg'),
);
// TODO: Enable when edits are ready for release
// let showEditorButton = $derived(
// isOwner &&
// asset.type === AssetTypeEnum.Image &&
// !(
// asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR ||
// (asset.originalPath && asset.originalPath.toLowerCase().endsWith('.insp'))
// ) &&
// !(asset.originalPath && asset.originalPath.toLowerCase().endsWith('.gif')) &&
// !(asset.originalPath && asset.originalPath.toLowerCase().endsWith('.svg')) &&
// !asset.livePhotoVideoId,
// );
</script>
<CommandPaletteDefaultProvider
@@ -177,9 +179,9 @@
<RatingAction {asset} {onAction} />
{/if}
{#if !editorDisabled}
<!-- {#if showEditorButton}
<EditAction onAction={onEdit} />
{/if}
{/if} -->
{#if isOwner}
<DeleteAction {asset} {onAction} {preAction} {onUndoDelete} />

View File

@@ -255,12 +255,12 @@
});
};
const showEditor = () => {
if (assetViewerManager.isShowActivityPanel) {
assetViewerManager.isShowActivityPanel = false;
}
isShowEditor = !isShowEditor;
};
// const showEditor = () => {
// if (assetViewerManager.isShowActivityPanel) {
// assetViewerManager.isShowActivityPanel = false;
// }
// isShowEditor = !isShowEditor;
// };
const handleRunJob = async (name: AssetJobName) => {
try {
@@ -431,7 +431,6 @@
onCopyImage={copyImage}
preAction={handlePreAction}
onAction={handleAction}
onEdit={showEditor}
{onUndoDelete}
onRunJob={handleRunJob}
onPlaySlideshow={() => ($slideshowState = SlideshowState.PlaySlideshow)}

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import Combobox, { type ComboBoxOption } from '$lib/components/shared-components/combobox.svelte';
import { Label, Text } from '@immich/ui';
import type { Snippet } from 'svelte';
import { t } from 'svelte-i18n';
import { quintOut } from 'svelte/easing';
@@ -28,25 +29,21 @@
}: Props = $props();
</script>
<div class="grid grid-cols-2">
<div>
<div class="flex h-6.5 place-items-center gap-1">
<label class="font-medium text-primary text-sm" for={title}>
{title}
</label>
{#if isEdited}
<div
transition:fly={{ x: 10, duration: 200, easing: quintOut }}
class="rounded-full bg-orange-100 px-2 text-[10px] text-orange-900"
>
{$t('unsaved_change')}
</div>
{/if}
</div>
<p class="text-sm dark:text-immich-dark-fg">{subtitle}</p>
<div>
<div class="flex h-6.5 place-items-center gap-1">
<Label>{title}</Label>
{#if isEdited}
<div
transition:fly={{ x: 10, duration: 200, easing: quintOut }}
class="rounded-full bg-orange-100 px-2 text-[10px] text-orange-900"
>
{$t('unsaved_change')}
</div>
{/if}
</div>
<div class="flex items-center">
<Text size="small" color="muted">{subtitle}</Text>
<div class="flex items-center mt-2 max-w-[300px]">
<Combobox label={title} hideLabel={true} {selectedOption} {options} placeholder={comboboxPlaceholder} {onSelect} />
{@render children?.()}
</div>

View File

@@ -4,6 +4,7 @@
import { defaultLang, langs } from '$lib/constants';
import { lang } from '$lib/stores/preferences.store';
import { getClosestAvailableLocale, langCodes } from '$lib/utils/i18n';
import { Label, Text } from '@immich/ui';
import { locale as i18nLocale, t } from 'svelte-i18n';
interface Props {
@@ -34,16 +35,14 @@
let closestLanguage = $derived(getClosestAvailableLocale([$lang], langCodes));
</script>
<div class={showSettingDescription ? 'grid grid-cols-2' : ''}>
<div class="max-w-[300px]">
{#if showSettingDescription}
<div>
<div class="flex h-6.5 place-items-center gap-1">
<label class="font-medium text-primary text-sm" for={$t('language')}>
{$t('language')}
</label>
<Label>{$t('language')}</Label>
</div>
<p class="text-sm dark:text-immich-dark-fg">{$t('language_setting_description')}</p>
<Text size="small" color="muted">{$t('language_setting_description')}</Text>
</div>
{/if}

View File

@@ -1,7 +1,6 @@
<script lang="ts">
import type { ComboBoxOption } from '$lib/components/shared-components/combobox.svelte';
import SettingCombobox from '$lib/components/shared-components/settings/setting-combobox.svelte';
import SettingSwitch from '$lib/components/shared-components/settings/setting-switch.svelte';
import SettingsLanguageSelector from '$lib/components/shared-components/settings/settings-language-selector.svelte';
import { fallbackLocale, locales } from '$lib/constants';
import { themeManager } from '$lib/managers/theme-manager.svelte';
@@ -15,6 +14,7 @@
showDeleteModal,
} from '$lib/stores/preferences.store';
import { createDateFormatter, findLocale } from '$lib/utils';
import { Field, Switch, Text } from '@immich/ui';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
import { fade } from 'svelte/transition';
@@ -59,81 +59,55 @@
<section class="my-4">
<div in:fade={{ duration: 500 }}>
<div class="ms-4 mt-4 flex flex-col gap-4">
<div class="ms-4">
<SettingSwitch
title={$t('theme_selection')}
subtitle={$t('theme_selection_description')}
checked={themeManager.theme.system}
onToggle={(isChecked) => themeManager.setSystem(isChecked)}
/>
</div>
<div class="ms-8 mt-4 flex flex-col gap-4">
<Field label={$t('theme_selection')} description={$t('theme_selection_description')}>
<Switch checked={themeManager.theme.system} onCheckedChange={(checked) => themeManager.setSystem(checked)} />
</Field>
<div class="ms-4">
<SettingsLanguageSelector showSettingDescription />
</div>
<SettingsLanguageSelector showSettingDescription />
<Field label={$t('default_locale')} description={$t('default_locale_description')}>
<Switch checked={$locale == 'default'} onCheckedChange={handleToggleLocaleBrowser} />
<Text size="small" class="mt-2">{selectedDate}</Text>
</Field>
<div class="ms-4">
<SettingSwitch
title={$t('default_locale')}
subtitle={$t('default_locale_description')}
checked={$locale == 'default'}
onToggle={handleToggleLocaleBrowser}
>
<p class="mt-2 dark:text-gray-400">{selectedDate}</p>
</SettingSwitch>
</div>
{#if $locale !== 'default'}
<div class="ms-4">
<SettingCombobox
comboboxPlaceholder={$t('searching_locales')}
{selectedOption}
options={getAllLanguages()}
title={$t('custom_locale')}
subtitle={$t('custom_locale_description')}
onSelect={(combobox) => handleLocaleChange(combobox?.value)}
/>
</div>
<SettingCombobox
comboboxPlaceholder={$t('searching_locales')}
{selectedOption}
options={getAllLanguages()}
title={$t('custom_locale')}
subtitle={$t('custom_locale_description')}
onSelect={(combobox) => handleLocaleChange(combobox?.value)}
/>
{/if}
<div class="ms-4">
<SettingSwitch
title={$t('display_original_photos')}
subtitle={$t('display_original_photos_setting_description')}
bind:checked={$alwaysLoadOriginalFile}
/>
</div>
<div class="ms-4">
<SettingSwitch
title={$t('video_hover_setting')}
subtitle={$t('video_hover_setting_description')}
bind:checked={$playVideoThumbnailOnHover}
/>
</div>
<div class="ms-4">
<SettingSwitch
title={$t('setting_video_viewer_auto_play_title')}
subtitle={$t('setting_video_viewer_auto_play_subtitle')}
bind:checked={$autoPlayVideo}
/>
</div>
<div class="ms-4">
<SettingSwitch title={$t('loop_videos')} subtitle={$t('loop_videos_description')} bind:checked={$loopVideo} />
</div>
<div class="ms-4">
<SettingSwitch
title={$t('play_original_video')}
subtitle={$t('play_original_video_setting_description')}
bind:checked={$alwaysLoadOriginalVideo}
/>
</div>
<div class="ms-4">
<SettingSwitch
title={$t('permanent_deletion_warning')}
subtitle={$t('permanent_deletion_warning_setting_description')}
bind:checked={$showDeleteModal}
/>
</div>
<Field label={$t('display_original_photos')} description={$t('display_original_photos_setting_description')}>
<Switch bind:checked={$alwaysLoadOriginalFile} />
</Field>
<Field label={$t('video_hover_setting')} description={$t('video_hover_setting_description')}>
<Switch bind:checked={$playVideoThumbnailOnHover} />
</Field>
<Field
label={$t('setting_video_viewer_auto_play_title')}
description={$t('setting_video_viewer_auto_play_subtitle')}
>
<Switch bind:checked={$autoPlayVideo} />
</Field>
<Field label={$t('loop_videos')} description={$t('loop_videos_description')}>
<Switch bind:checked={$loopVideo} />
</Field>
<Field label={$t('play_original_video')} description={$t('play_original_video_setting_description')}>
<Switch bind:checked={$alwaysLoadOriginalVideo} />
</Field>
<Field label={$t('permanent_deletion_warning')} description={$t('permanent_deletion_warning_setting_description')}
><Switch bind:checked={$showDeleteModal} />
</Field>
</div>
</div>
</section>