diff --git a/cli/src/api/open-api/api.ts b/cli/src/api/open-api/api.ts index e39b6e4f12..f9c983833f 100644 --- a/cli/src/api/open-api/api.ts +++ b/cli/src/api/open-api/api.ts @@ -1055,6 +1055,22 @@ export interface CheckExistingAssetsResponseDto { */ 'existingIds': Array; } +/** + * + * @export + * @enum {string} + */ + +export const CitiesFile = { + Cities15000: 'cities15000', + Cities5000: 'cities5000', + Cities1000: 'cities1000', + Cities500: 'cities500' +} as const; + +export type CitiesFile = typeof CitiesFile[keyof typeof CitiesFile]; + + /** * * @export @@ -2650,6 +2666,12 @@ export interface ServerFeaturesDto { * @memberof ServerFeaturesDto */ 'passwordLogin': boolean; + /** + * + * @type {boolean} + * @memberof ServerFeaturesDto + */ + 'reverseGeocoding': boolean; /** * * @type {boolean} @@ -3093,6 +3115,12 @@ export interface SystemConfigDto { * @memberof SystemConfigDto */ 'passwordLogin': SystemConfigPasswordLoginDto; + /** + * + * @type {SystemConfigReverseGeocodingDto} + * @memberof SystemConfigDto + */ + 'reverseGeocoding': SystemConfigReverseGeocodingDto; /** * * @type {SystemConfigStorageTemplateDto} @@ -3438,6 +3466,27 @@ export interface SystemConfigPasswordLoginDto { */ 'enabled': boolean; } +/** + * + * @export + * @interface SystemConfigReverseGeocodingDto + */ +export interface SystemConfigReverseGeocodingDto { + /** + * + * @type {CitiesFile} + * @memberof SystemConfigReverseGeocodingDto + */ + 'citiesFileOverride': CitiesFile; + /** + * + * @type {boolean} + * @memberof SystemConfigReverseGeocodingDto + */ + 'enabled': boolean; +} + + /** * * @export diff --git a/docs/docs/install/environment-variables.md b/docs/docs/install/environment-variables.md index ed84fd439f..403ff2c363 100644 --- a/docs/docs/install/environment-variables.md +++ b/docs/docs/install/environment-variables.md @@ -49,11 +49,9 @@ These environment variables are used by the `docker-compose.yml` file and do **N ## Geocoding -| Variable | Description | Default | Services | -| :--------------------------------- | :---------------------------------- | :--------------------------: | :------------ | -| `DISABLE_REVERSE_GEOCODING` | Disable Reverse Geocoding Precision | `false` | microservices | -| `REVERSE_GEOCODING_PRECISION` | Reverse Geocoding Precision | `3` | microservices | -| `REVERSE_GEOCODING_DUMP_DIRECTORY` | Reverse Geocoding Dump Directory | `./.reverse-geocoding-dump/` | microservices | +| Variable | Description | Default | Services | +| :--------------------------------- | :------------------------------- | :--------------------------: | :------------ | +| `REVERSE_GEOCODING_DUMP_DIRECTORY` | Reverse Geocoding Dump Directory | `./.reverse-geocoding-dump/` | microservices | ## Ports diff --git a/mobile/openapi/.openapi-generator/FILES b/mobile/openapi/.openapi-generator/FILES index f10fa425c5..60dc2f1521 100644 --- a/mobile/openapi/.openapi-generator/FILES +++ b/mobile/openapi/.openapi-generator/FILES @@ -43,6 +43,7 @@ doc/CheckDuplicateAssetDto.md doc/CheckDuplicateAssetResponseDto.md doc/CheckExistingAssetsDto.md doc/CheckExistingAssetsResponseDto.md +doc/CitiesFile.md doc/ClassificationConfig.md doc/Colorspace.md doc/CreateAlbumDto.md @@ -126,6 +127,7 @@ doc/SystemConfigMachineLearningDto.md doc/SystemConfigMapDto.md doc/SystemConfigOAuthDto.md doc/SystemConfigPasswordLoginDto.md +doc/SystemConfigReverseGeocodingDto.md doc/SystemConfigStorageTemplateDto.md doc/SystemConfigTemplateStorageOptionDto.md doc/SystemConfigThumbnailDto.md @@ -207,6 +209,7 @@ lib/model/check_duplicate_asset_dto.dart lib/model/check_duplicate_asset_response_dto.dart lib/model/check_existing_assets_dto.dart lib/model/check_existing_assets_response_dto.dart +lib/model/cities_file.dart lib/model/classification_config.dart lib/model/clip_config.dart lib/model/clip_mode.dart @@ -284,6 +287,7 @@ lib/model/system_config_machine_learning_dto.dart lib/model/system_config_map_dto.dart lib/model/system_config_o_auth_dto.dart lib/model/system_config_password_login_dto.dart +lib/model/system_config_reverse_geocoding_dto.dart lib/model/system_config_storage_template_dto.dart lib/model/system_config_template_storage_option_dto.dart lib/model/system_config_thumbnail_dto.dart @@ -343,6 +347,7 @@ test/check_duplicate_asset_dto_test.dart test/check_duplicate_asset_response_dto_test.dart test/check_existing_assets_dto_test.dart test/check_existing_assets_response_dto_test.dart +test/cities_file_test.dart test/classification_config_test.dart test/clip_config_test.dart test/clip_mode_test.dart @@ -429,6 +434,7 @@ test/system_config_machine_learning_dto_test.dart test/system_config_map_dto_test.dart test/system_config_o_auth_dto_test.dart test/system_config_password_login_dto_test.dart +test/system_config_reverse_geocoding_dto_test.dart test/system_config_storage_template_dto_test.dart test/system_config_template_storage_option_dto_test.dart test/system_config_thumbnail_dto_test.dart diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index 889f20658d..f1e4193fd2 100644 --- a/mobile/openapi/README.md +++ b/mobile/openapi/README.md @@ -227,6 +227,7 @@ Class | Method | HTTP request | Description - [CheckDuplicateAssetResponseDto](doc//CheckDuplicateAssetResponseDto.md) - [CheckExistingAssetsDto](doc//CheckExistingAssetsDto.md) - [CheckExistingAssetsResponseDto](doc//CheckExistingAssetsResponseDto.md) + - [CitiesFile](doc//CitiesFile.md) - [ClassificationConfig](doc//ClassificationConfig.md) - [Colorspace](doc//Colorspace.md) - [CreateAlbumDto](doc//CreateAlbumDto.md) @@ -301,6 +302,7 @@ Class | Method | HTTP request | Description - [SystemConfigMapDto](doc//SystemConfigMapDto.md) - [SystemConfigOAuthDto](doc//SystemConfigOAuthDto.md) - [SystemConfigPasswordLoginDto](doc//SystemConfigPasswordLoginDto.md) + - [SystemConfigReverseGeocodingDto](doc//SystemConfigReverseGeocodingDto.md) - [SystemConfigStorageTemplateDto](doc//SystemConfigStorageTemplateDto.md) - [SystemConfigTemplateStorageOptionDto](doc//SystemConfigTemplateStorageOptionDto.md) - [SystemConfigThumbnailDto](doc//SystemConfigThumbnailDto.md) diff --git a/mobile/openapi/doc/CitiesFile.md b/mobile/openapi/doc/CitiesFile.md new file mode 100644 index 0000000000..9acca959c7 --- /dev/null +++ b/mobile/openapi/doc/CitiesFile.md @@ -0,0 +1,14 @@ +# openapi.model.CitiesFile + +## Load the model package +```dart +import 'package:openapi/api.dart'; +``` + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/mobile/openapi/doc/ServerFeaturesDto.md b/mobile/openapi/doc/ServerFeaturesDto.md index c5f7946f30..8c772e3b91 100644 --- a/mobile/openapi/doc/ServerFeaturesDto.md +++ b/mobile/openapi/doc/ServerFeaturesDto.md @@ -15,6 +15,7 @@ Name | Type | Description | Notes **oauth** | **bool** | | **oauthAutoLaunch** | **bool** | | **passwordLogin** | **bool** | | +**reverseGeocoding** | **bool** | | **search** | **bool** | | **sidecar** | **bool** | | **tagImage** | **bool** | | diff --git a/mobile/openapi/doc/SystemConfigDto.md b/mobile/openapi/doc/SystemConfigDto.md index 40d528b401..f91a540635 100644 --- a/mobile/openapi/doc/SystemConfigDto.md +++ b/mobile/openapi/doc/SystemConfigDto.md @@ -14,6 +14,7 @@ Name | Type | Description | Notes **map** | [**SystemConfigMapDto**](SystemConfigMapDto.md) | | **oauth** | [**SystemConfigOAuthDto**](SystemConfigOAuthDto.md) | | **passwordLogin** | [**SystemConfigPasswordLoginDto**](SystemConfigPasswordLoginDto.md) | | +**reverseGeocoding** | [**SystemConfigReverseGeocodingDto**](SystemConfigReverseGeocodingDto.md) | | **storageTemplate** | [**SystemConfigStorageTemplateDto**](SystemConfigStorageTemplateDto.md) | | **thumbnail** | [**SystemConfigThumbnailDto**](SystemConfigThumbnailDto.md) | | diff --git a/mobile/openapi/doc/SystemConfigReverseGeocodingDto.md b/mobile/openapi/doc/SystemConfigReverseGeocodingDto.md new file mode 100644 index 0000000000..36eab47477 --- /dev/null +++ b/mobile/openapi/doc/SystemConfigReverseGeocodingDto.md @@ -0,0 +1,16 @@ +# openapi.model.SystemConfigReverseGeocodingDto + +## Load the model package +```dart +import 'package:openapi/api.dart'; +``` + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**citiesFileOverride** | [**CitiesFile**](CitiesFile.md) | | +**enabled** | **bool** | | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/mobile/openapi/lib/api.dart b/mobile/openapi/lib/api.dart index 1ff40f5ed6..e332902a3e 100644 --- a/mobile/openapi/lib/api.dart +++ b/mobile/openapi/lib/api.dart @@ -80,6 +80,7 @@ part 'model/check_duplicate_asset_dto.dart'; part 'model/check_duplicate_asset_response_dto.dart'; part 'model/check_existing_assets_dto.dart'; part 'model/check_existing_assets_response_dto.dart'; +part 'model/cities_file.dart'; part 'model/classification_config.dart'; part 'model/colorspace.dart'; part 'model/create_album_dto.dart'; @@ -154,6 +155,7 @@ part 'model/system_config_machine_learning_dto.dart'; part 'model/system_config_map_dto.dart'; part 'model/system_config_o_auth_dto.dart'; part 'model/system_config_password_login_dto.dart'; +part 'model/system_config_reverse_geocoding_dto.dart'; part 'model/system_config_storage_template_dto.dart'; part 'model/system_config_template_storage_option_dto.dart'; part 'model/system_config_thumbnail_dto.dart'; diff --git a/mobile/openapi/lib/api_client.dart b/mobile/openapi/lib/api_client.dart index e20a8d6984..c9678d94fe 100644 --- a/mobile/openapi/lib/api_client.dart +++ b/mobile/openapi/lib/api_client.dart @@ -251,6 +251,8 @@ class ApiClient { return CheckExistingAssetsDto.fromJson(value); case 'CheckExistingAssetsResponseDto': return CheckExistingAssetsResponseDto.fromJson(value); + case 'CitiesFile': + return CitiesFileTypeTransformer().decode(value); case 'ClassificationConfig': return ClassificationConfig.fromJson(value); case 'Colorspace': @@ -399,6 +401,8 @@ class ApiClient { return SystemConfigOAuthDto.fromJson(value); case 'SystemConfigPasswordLoginDto': return SystemConfigPasswordLoginDto.fromJson(value); + case 'SystemConfigReverseGeocodingDto': + return SystemConfigReverseGeocodingDto.fromJson(value); case 'SystemConfigStorageTemplateDto': return SystemConfigStorageTemplateDto.fromJson(value); case 'SystemConfigTemplateStorageOptionDto': diff --git a/mobile/openapi/lib/api_helper.dart b/mobile/openapi/lib/api_helper.dart index 3b6099f79d..986305f02e 100644 --- a/mobile/openapi/lib/api_helper.dart +++ b/mobile/openapi/lib/api_helper.dart @@ -70,6 +70,9 @@ String parameterToString(dynamic value) { if (value is CQMode) { return CQModeTypeTransformer().encode(value).toString(); } + if (value is CitiesFile) { + return CitiesFileTypeTransformer().encode(value).toString(); + } if (value is Colorspace) { return ColorspaceTypeTransformer().encode(value).toString(); } diff --git a/mobile/openapi/lib/model/cities_file.dart b/mobile/openapi/lib/model/cities_file.dart new file mode 100644 index 0000000000..96f5d8e573 --- /dev/null +++ b/mobile/openapi/lib/model/cities_file.dart @@ -0,0 +1,91 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// 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 CitiesFile { + /// Instantiate a new enum with the provided [value]. + const CitiesFile._(this.value); + + /// The underlying value of this enum member. + final String value; + + @override + String toString() => value; + + String toJson() => value; + + static const cities15000 = CitiesFile._(r'cities15000'); + static const cities5000 = CitiesFile._(r'cities5000'); + static const cities1000 = CitiesFile._(r'cities1000'); + static const cities500 = CitiesFile._(r'cities500'); + + /// List of all possible values in this [enum][CitiesFile]. + static const values = [ + cities15000, + cities5000, + cities1000, + cities500, + ]; + + static CitiesFile? fromJson(dynamic value) => CitiesFileTypeTransformer().decode(value); + + static List? listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + if (json is List && json.isNotEmpty) { + for (final row in json) { + final value = CitiesFile.fromJson(row); + if (value != null) { + result.add(value); + } + } + } + return result.toList(growable: growable); + } +} + +/// Transformation class that can [encode] an instance of [CitiesFile] to String, +/// and [decode] dynamic data back to [CitiesFile]. +class CitiesFileTypeTransformer { + factory CitiesFileTypeTransformer() => _instance ??= const CitiesFileTypeTransformer._(); + + const CitiesFileTypeTransformer._(); + + String encode(CitiesFile data) => data.value; + + /// Decodes a [dynamic value][data] to a CitiesFile. + /// + /// 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. + CitiesFile? decode(dynamic data, {bool allowNull = true}) { + if (data != null) { + switch (data) { + case r'cities15000': return CitiesFile.cities15000; + case r'cities5000': return CitiesFile.cities5000; + case r'cities1000': return CitiesFile.cities1000; + case r'cities500': return CitiesFile.cities500; + default: + if (!allowNull) { + throw ArgumentError('Unknown enum value to decode: $data'); + } + } + } + return null; + } + + /// Singleton [CitiesFileTypeTransformer] instance. + static CitiesFileTypeTransformer? _instance; +} + diff --git a/mobile/openapi/lib/model/server_features_dto.dart b/mobile/openapi/lib/model/server_features_dto.dart index 07a725232f..5175b99d78 100644 --- a/mobile/openapi/lib/model/server_features_dto.dart +++ b/mobile/openapi/lib/model/server_features_dto.dart @@ -20,6 +20,7 @@ class ServerFeaturesDto { required this.oauth, required this.oauthAutoLaunch, required this.passwordLogin, + required this.reverseGeocoding, required this.search, required this.sidecar, required this.tagImage, @@ -39,6 +40,8 @@ class ServerFeaturesDto { bool passwordLogin; + bool reverseGeocoding; + bool search; bool sidecar; @@ -54,6 +57,7 @@ class ServerFeaturesDto { other.oauth == oauth && other.oauthAutoLaunch == oauthAutoLaunch && other.passwordLogin == passwordLogin && + other.reverseGeocoding == reverseGeocoding && other.search == search && other.sidecar == sidecar && other.tagImage == tagImage; @@ -68,12 +72,13 @@ class ServerFeaturesDto { (oauth.hashCode) + (oauthAutoLaunch.hashCode) + (passwordLogin.hashCode) + + (reverseGeocoding.hashCode) + (search.hashCode) + (sidecar.hashCode) + (tagImage.hashCode); @override - String toString() => 'ServerFeaturesDto[clipEncode=$clipEncode, configFile=$configFile, facialRecognition=$facialRecognition, map=$map, oauth=$oauth, oauthAutoLaunch=$oauthAutoLaunch, passwordLogin=$passwordLogin, search=$search, sidecar=$sidecar, tagImage=$tagImage]'; + String toString() => 'ServerFeaturesDto[clipEncode=$clipEncode, configFile=$configFile, facialRecognition=$facialRecognition, map=$map, oauth=$oauth, oauthAutoLaunch=$oauthAutoLaunch, passwordLogin=$passwordLogin, reverseGeocoding=$reverseGeocoding, search=$search, sidecar=$sidecar, tagImage=$tagImage]'; Map toJson() { final json = {}; @@ -84,6 +89,7 @@ class ServerFeaturesDto { json[r'oauth'] = this.oauth; json[r'oauthAutoLaunch'] = this.oauthAutoLaunch; json[r'passwordLogin'] = this.passwordLogin; + json[r'reverseGeocoding'] = this.reverseGeocoding; json[r'search'] = this.search; json[r'sidecar'] = this.sidecar; json[r'tagImage'] = this.tagImage; @@ -105,6 +111,7 @@ class ServerFeaturesDto { oauth: mapValueOfType(json, r'oauth')!, oauthAutoLaunch: mapValueOfType(json, r'oauthAutoLaunch')!, passwordLogin: mapValueOfType(json, r'passwordLogin')!, + reverseGeocoding: mapValueOfType(json, r'reverseGeocoding')!, search: mapValueOfType(json, r'search')!, sidecar: mapValueOfType(json, r'sidecar')!, tagImage: mapValueOfType(json, r'tagImage')!, @@ -162,6 +169,7 @@ class ServerFeaturesDto { 'oauth', 'oauthAutoLaunch', 'passwordLogin', + 'reverseGeocoding', 'search', 'sidecar', 'tagImage', diff --git a/mobile/openapi/lib/model/system_config_dto.dart b/mobile/openapi/lib/model/system_config_dto.dart index 2fe46a039a..1468279708 100644 --- a/mobile/openapi/lib/model/system_config_dto.dart +++ b/mobile/openapi/lib/model/system_config_dto.dart @@ -19,6 +19,7 @@ class SystemConfigDto { required this.map, required this.oauth, required this.passwordLogin, + required this.reverseGeocoding, required this.storageTemplate, required this.thumbnail, }); @@ -35,6 +36,8 @@ class SystemConfigDto { SystemConfigPasswordLoginDto passwordLogin; + SystemConfigReverseGeocodingDto reverseGeocoding; + SystemConfigStorageTemplateDto storageTemplate; SystemConfigThumbnailDto thumbnail; @@ -47,6 +50,7 @@ class SystemConfigDto { other.map == map && other.oauth == oauth && other.passwordLogin == passwordLogin && + other.reverseGeocoding == reverseGeocoding && other.storageTemplate == storageTemplate && other.thumbnail == thumbnail; @@ -59,11 +63,12 @@ class SystemConfigDto { (map.hashCode) + (oauth.hashCode) + (passwordLogin.hashCode) + + (reverseGeocoding.hashCode) + (storageTemplate.hashCode) + (thumbnail.hashCode); @override - String toString() => 'SystemConfigDto[ffmpeg=$ffmpeg, job=$job, machineLearning=$machineLearning, map=$map, oauth=$oauth, passwordLogin=$passwordLogin, storageTemplate=$storageTemplate, thumbnail=$thumbnail]'; + String toString() => 'SystemConfigDto[ffmpeg=$ffmpeg, job=$job, machineLearning=$machineLearning, map=$map, oauth=$oauth, passwordLogin=$passwordLogin, reverseGeocoding=$reverseGeocoding, storageTemplate=$storageTemplate, thumbnail=$thumbnail]'; Map toJson() { final json = {}; @@ -73,6 +78,7 @@ class SystemConfigDto { json[r'map'] = this.map; json[r'oauth'] = this.oauth; json[r'passwordLogin'] = this.passwordLogin; + json[r'reverseGeocoding'] = this.reverseGeocoding; json[r'storageTemplate'] = this.storageTemplate; json[r'thumbnail'] = this.thumbnail; return json; @@ -92,6 +98,7 @@ class SystemConfigDto { map: SystemConfigMapDto.fromJson(json[r'map'])!, oauth: SystemConfigOAuthDto.fromJson(json[r'oauth'])!, passwordLogin: SystemConfigPasswordLoginDto.fromJson(json[r'passwordLogin'])!, + reverseGeocoding: SystemConfigReverseGeocodingDto.fromJson(json[r'reverseGeocoding'])!, storageTemplate: SystemConfigStorageTemplateDto.fromJson(json[r'storageTemplate'])!, thumbnail: SystemConfigThumbnailDto.fromJson(json[r'thumbnail'])!, ); @@ -147,6 +154,7 @@ class SystemConfigDto { 'map', 'oauth', 'passwordLogin', + 'reverseGeocoding', 'storageTemplate', 'thumbnail', }; diff --git a/mobile/openapi/lib/model/system_config_reverse_geocoding_dto.dart b/mobile/openapi/lib/model/system_config_reverse_geocoding_dto.dart new file mode 100644 index 0000000000..727e5534fd --- /dev/null +++ b/mobile/openapi/lib/model/system_config_reverse_geocoding_dto.dart @@ -0,0 +1,106 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// 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 SystemConfigReverseGeocodingDto { + /// Returns a new [SystemConfigReverseGeocodingDto] instance. + SystemConfigReverseGeocodingDto({ + required this.citiesFileOverride, + required this.enabled, + }); + + CitiesFile citiesFileOverride; + + bool enabled; + + @override + bool operator ==(Object other) => identical(this, other) || other is SystemConfigReverseGeocodingDto && + other.citiesFileOverride == citiesFileOverride && + other.enabled == enabled; + + @override + int get hashCode => + // ignore: unnecessary_parenthesis + (citiesFileOverride.hashCode) + + (enabled.hashCode); + + @override + String toString() => 'SystemConfigReverseGeocodingDto[citiesFileOverride=$citiesFileOverride, enabled=$enabled]'; + + Map toJson() { + final json = {}; + json[r'citiesFileOverride'] = this.citiesFileOverride; + json[r'enabled'] = this.enabled; + return json; + } + + /// Returns a new [SystemConfigReverseGeocodingDto] instance and imports its values from + /// [value] if it's a [Map], null otherwise. + // ignore: prefer_constructors_over_static_methods + static SystemConfigReverseGeocodingDto? fromJson(dynamic value) { + if (value is Map) { + final json = value.cast(); + + return SystemConfigReverseGeocodingDto( + citiesFileOverride: CitiesFile.fromJson(json[r'citiesFileOverride'])!, + enabled: mapValueOfType(json, r'enabled')!, + ); + } + return null; + } + + static List listFromJson(dynamic json, {bool growable = false,}) { + final result = []; + if (json is List && json.isNotEmpty) { + for (final row in json) { + final value = SystemConfigReverseGeocodingDto.fromJson(row); + if (value != null) { + result.add(value); + } + } + } + return result.toList(growable: growable); + } + + static Map mapFromJson(dynamic json) { + final map = {}; + if (json is Map && json.isNotEmpty) { + json = json.cast(); // ignore: parameter_assignments + for (final entry in json.entries) { + final value = SystemConfigReverseGeocodingDto.fromJson(entry.value); + if (value != null) { + map[entry.key] = value; + } + } + } + return map; + } + + // maps a json object with a list of SystemConfigReverseGeocodingDto-objects as value to a dart map + static Map> mapListFromJson(dynamic json, {bool growable = false,}) { + final map = >{}; + if (json is Map && json.isNotEmpty) { + // ignore: parameter_assignments + json = json.cast(); + for (final entry in json.entries) { + map[entry.key] = SystemConfigReverseGeocodingDto.listFromJson(entry.value, growable: growable,); + } + } + return map; + } + + /// The list of required keys that must be present in a JSON. + static const requiredKeys = { + 'citiesFileOverride', + 'enabled', + }; +} + diff --git a/mobile/openapi/test/cities_file_test.dart b/mobile/openapi/test/cities_file_test.dart new file mode 100644 index 0000000000..cfe63b7548 --- /dev/null +++ b/mobile/openapi/test/cities_file_test.dart @@ -0,0 +1,21 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// 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 + +import 'package:openapi/api.dart'; +import 'package:test/test.dart'; + +// tests for CitiesFile +void main() { + + group('test CitiesFile', () { + + }); + +} diff --git a/mobile/openapi/test/server_features_dto_test.dart b/mobile/openapi/test/server_features_dto_test.dart index 6838e12563..864a489c90 100644 --- a/mobile/openapi/test/server_features_dto_test.dart +++ b/mobile/openapi/test/server_features_dto_test.dart @@ -51,6 +51,11 @@ void main() { // TODO }); + // bool reverseGeocoding + test('to test the property `reverseGeocoding`', () async { + // TODO + }); + // bool search test('to test the property `search`', () async { // TODO diff --git a/mobile/openapi/test/system_config_dto_test.dart b/mobile/openapi/test/system_config_dto_test.dart index 8951d16ca8..1ada973063 100644 --- a/mobile/openapi/test/system_config_dto_test.dart +++ b/mobile/openapi/test/system_config_dto_test.dart @@ -46,6 +46,11 @@ void main() { // TODO }); + // SystemConfigReverseGeocodingDto reverseGeocoding + test('to test the property `reverseGeocoding`', () async { + // TODO + }); + // SystemConfigStorageTemplateDto storageTemplate test('to test the property `storageTemplate`', () async { // TODO diff --git a/mobile/openapi/test/system_config_reverse_geocoding_dto_test.dart b/mobile/openapi/test/system_config_reverse_geocoding_dto_test.dart new file mode 100644 index 0000000000..12f7655ead --- /dev/null +++ b/mobile/openapi/test/system_config_reverse_geocoding_dto_test.dart @@ -0,0 +1,32 @@ +// +// AUTO-GENERATED FILE, DO NOT MODIFY! +// +// @dart=2.12 + +// 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 + +import 'package:openapi/api.dart'; +import 'package:test/test.dart'; + +// tests for SystemConfigReverseGeocodingDto +void main() { + // final instance = SystemConfigReverseGeocodingDto(); + + group('test SystemConfigReverseGeocodingDto', () { + // CitiesFile citiesFileOverride + test('to test the property `citiesFileOverride`', () async { + // TODO + }); + + // bool enabled + test('to test the property `enabled`', () async { + // TODO + }); + + + }); + +} diff --git a/server/immich-openapi-specs.json b/server/immich-openapi-specs.json index f5f58868ad..21a905f6bd 100644 --- a/server/immich-openapi-specs.json +++ b/server/immich-openapi-specs.json @@ -5914,6 +5914,15 @@ ], "type": "object" }, + "CitiesFile": { + "enum": [ + "cities15000", + "cities5000", + "cities1000", + "cities500" + ], + "type": "string" + }, "ClassificationConfig": { "properties": { "enabled": { @@ -7229,6 +7238,9 @@ "passwordLogin": { "type": "boolean" }, + "reverseGeocoding": { + "type": "boolean" + }, "search": { "type": "boolean" }, @@ -7244,6 +7256,7 @@ "configFile", "facialRecognition", "map", + "reverseGeocoding", "oauth", "oauthAutoLaunch", "passwordLogin", @@ -7590,6 +7603,9 @@ "passwordLogin": { "$ref": "#/components/schemas/SystemConfigPasswordLoginDto" }, + "reverseGeocoding": { + "$ref": "#/components/schemas/SystemConfigReverseGeocodingDto" + }, "storageTemplate": { "$ref": "#/components/schemas/SystemConfigStorageTemplateDto" }, @@ -7603,6 +7619,7 @@ "map", "oauth", "passwordLogin", + "reverseGeocoding", "storageTemplate", "job", "thumbnail" @@ -7843,6 +7860,21 @@ ], "type": "object" }, + "SystemConfigReverseGeocodingDto": { + "properties": { + "citiesFileOverride": { + "$ref": "#/components/schemas/CitiesFile" + }, + "enabled": { + "type": "boolean" + } + }, + "required": [ + "citiesFileOverride", + "enabled" + ], + "type": "object" + }, "SystemConfigStorageTemplateDto": { "properties": { "template": { diff --git a/server/src/domain/metadata/geocoding.repository.ts b/server/src/domain/metadata/geocoding.repository.ts index 07e8ee4990..4e0dce87a7 100644 --- a/server/src/domain/metadata/geocoding.repository.ts +++ b/server/src/domain/metadata/geocoding.repository.ts @@ -1,3 +1,5 @@ +import { InitOptions } from 'local-reverse-geocoder'; + export const IGeocodingRepository = 'IGeocodingRepository'; export interface GeoPoint { @@ -12,7 +14,7 @@ export interface ReverseGeocodeResult { } export interface IGeocodingRepository { - init(): Promise; + init(options: Partial): Promise; reverseGeocode(point: GeoPoint): Promise; deleteCache(): Promise; } diff --git a/server/src/domain/server-info/server-info.dto.ts b/server/src/domain/server-info/server-info.dto.ts index 105fc1bd2d..119aaf86ed 100644 --- a/server/src/domain/server-info/server-info.dto.ts +++ b/server/src/domain/server-info/server-info.dto.ts @@ -90,6 +90,7 @@ export class ServerFeaturesDto implements FeatureFlags { configFile!: boolean; facialRecognition!: boolean; map!: boolean; + reverseGeocoding!: boolean; oauth!: boolean; oauthAutoLaunch!: boolean; passwordLogin!: boolean; diff --git a/server/src/domain/server-info/server-info.service.spec.ts b/server/src/domain/server-info/server-info.service.spec.ts index 4363e379b6..7a1e8ebcee 100644 --- a/server/src/domain/server-info/server-info.service.spec.ts +++ b/server/src/domain/server-info/server-info.service.spec.ts @@ -151,6 +151,7 @@ describe(ServerInfoService.name, () => { clipEncode: true, facialRecognition: true, map: true, + reverseGeocoding: true, oauth: false, oauthAutoLaunch: false, passwordLogin: true, diff --git a/server/src/domain/system-config/dto/system-config-reverse-geocoding.dto.ts b/server/src/domain/system-config/dto/system-config-reverse-geocoding.dto.ts new file mode 100644 index 0000000000..be20a02c79 --- /dev/null +++ b/server/src/domain/system-config/dto/system-config-reverse-geocoding.dto.ts @@ -0,0 +1,12 @@ +import { CitiesFile } from '@app/infra/entities'; +import { ApiProperty } from '@nestjs/swagger'; +import { IsBoolean, IsEnum } from 'class-validator'; + +export class SystemConfigReverseGeocodingDto { + @IsBoolean() + enabled!: boolean; + + @IsEnum(CitiesFile) + @ApiProperty({ enum: CitiesFile, enumName: 'CitiesFile' }) + citiesFileOverride!: CitiesFile; +} diff --git a/server/src/domain/system-config/dto/system-config.dto.ts b/server/src/domain/system-config/dto/system-config.dto.ts index 9ec7de6225..b4099c2b22 100644 --- a/server/src/domain/system-config/dto/system-config.dto.ts +++ b/server/src/domain/system-config/dto/system-config.dto.ts @@ -8,6 +8,7 @@ import { SystemConfigMachineLearningDto } from './system-config-machine-learning import { SystemConfigMapDto } from './system-config-map.dto'; import { SystemConfigOAuthDto } from './system-config-oauth.dto'; import { SystemConfigPasswordLoginDto } from './system-config-password-login.dto'; +import { SystemConfigReverseGeocodingDto } from './system-config-reverse-geocoding.dto'; import { SystemConfigStorageTemplateDto } from './system-config-storage-template.dto'; export class SystemConfigDto implements SystemConfig { @@ -36,6 +37,11 @@ export class SystemConfigDto implements SystemConfig { @IsObject() passwordLogin!: SystemConfigPasswordLoginDto; + @Type(() => SystemConfigReverseGeocodingDto) + @ValidateNested() + @IsObject() + reverseGeocoding!: SystemConfigReverseGeocodingDto; + @Type(() => SystemConfigStorageTemplateDto) @ValidateNested() @IsObject() diff --git a/server/src/domain/system-config/system-config.core.ts b/server/src/domain/system-config/system-config.core.ts index 57a2f71f96..0dc35cc103 100644 --- a/server/src/domain/system-config/system-config.core.ts +++ b/server/src/domain/system-config/system-config.core.ts @@ -1,6 +1,7 @@ import { AudioCodec, CQMode, + CitiesFile, Colorspace, SystemConfig, SystemConfigEntity, @@ -81,6 +82,10 @@ export const defaults = Object.freeze({ enabled: true, tileUrl: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', }, + reverseGeocoding: { + enabled: true, + citiesFileOverride: CitiesFile.CITIES_500, + }, oauth: { enabled: false, issuerUrl: '', @@ -115,6 +120,7 @@ export enum FeatureFlag { FACIAL_RECOGNITION = 'facialRecognition', TAG_IMAGE = 'tagImage', MAP = 'map', + REVERSE_GEOCODING = 'reverseGeocoding', SIDECAR = 'sidecar', SEARCH = 'search', OAUTH = 'oauth', @@ -177,6 +183,7 @@ export class SystemConfigCore { [FeatureFlag.FACIAL_RECOGNITION]: mlEnabled && config.machineLearning.facialRecognition.enabled, [FeatureFlag.TAG_IMAGE]: mlEnabled && config.machineLearning.classification.enabled, [FeatureFlag.MAP]: config.map.enabled, + [FeatureFlag.REVERSE_GEOCODING]: config.reverseGeocoding.enabled, [FeatureFlag.SIDECAR]: true, [FeatureFlag.SEARCH]: process.env.TYPESENSE_ENABLED !== 'false', diff --git a/server/src/domain/system-config/system-config.service.spec.ts b/server/src/domain/system-config/system-config.service.spec.ts index 67484e06d4..fc50839ba7 100644 --- a/server/src/domain/system-config/system-config.service.spec.ts +++ b/server/src/domain/system-config/system-config.service.spec.ts @@ -1,6 +1,7 @@ import { AudioCodec, CQMode, + CitiesFile, Colorspace, SystemConfig, SystemConfigEntity, @@ -80,6 +81,10 @@ const updatedConfig = Object.freeze({ enabled: true, tileUrl: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', }, + reverseGeocoding: { + enabled: true, + citiesFileOverride: CitiesFile.CITIES_500, + }, oauth: { autoLaunch: true, autoRegister: true, diff --git a/server/src/infra/entities/system-config.entity.ts b/server/src/infra/entities/system-config.entity.ts index 825e22dbee..e8d9f5f1a3 100644 --- a/server/src/infra/entities/system-config.entity.ts +++ b/server/src/infra/entities/system-config.entity.ts @@ -64,6 +64,9 @@ export enum SystemConfigKey { MAP_ENABLED = 'map.enabled', MAP_TILE_URL = 'map.tileUrl', + REVERSE_GEOCODING_ENABLED = 'reverseGeocoding.enabled', + REVERSE_GEOCODING_CITIES_FILE_OVERRIDE = 'reverseGeocoding.citiesFileOverride', + OAUTH_ENABLED = 'oauth.enabled', OAUTH_ISSUER_URL = 'oauth.issuerUrl', OAUTH_CLIENT_ID = 'oauth.clientId', @@ -130,6 +133,13 @@ export enum Colorspace { P3 = 'p3', } +export enum CitiesFile { + CITIES_15000 = 'cities15000', + CITIES_5000 = 'cities5000', + CITIES_1000 = 'cities1000', + CITIES_500 = 'cities500', +} + export interface SystemConfig { ffmpeg: { crf: number; @@ -175,6 +185,10 @@ export interface SystemConfig { enabled: boolean; tileUrl: string; }; + reverseGeocoding: { + enabled: boolean; + citiesFileOverride: CitiesFile; + }; oauth: { enabled: boolean; issuerUrl: string; diff --git a/server/src/infra/infra.config.ts b/server/src/infra/infra.config.ts index 81bb61bf1e..a3bcd10072 100644 --- a/server/src/infra/infra.config.ts +++ b/server/src/infra/infra.config.ts @@ -2,7 +2,6 @@ import { QueueName } from '@app/domain'; import { RegisterQueueOptions } from '@nestjs/bullmq'; import { QueueOptions } from 'bullmq'; import { RedisOptions } from 'ioredis'; -import { InitOptions } from 'local-reverse-geocoder'; import { ConfigurationOptions } from 'typesense/lib/Typesense/Configuration'; function parseRedisConfig(): RedisOptions { @@ -72,20 +71,5 @@ function parseTypeSenseConfig(): ConfigurationOptions { export const typesenseConfig: ConfigurationOptions = parseTypeSenseConfig(); -function parseLocalGeocodingConfig(): InitOptions { - const precision = Number(process.env.REVERSE_GEOCODING_PRECISION); - - return { - citiesFileOverride: precision ? ['cities15000', 'cities5000', 'cities1000', 'cities500'][precision] : undefined, - load: { - admin1: true, - admin2: true, - admin3And4: false, - alternateNames: false, - }, - countries: [], - dumpDirectory: process.env.REVERSE_GEOCODING_DUMP_DIRECTORY || process.cwd() + '/.reverse-geocoding-dump/', - }; -} - -export const localGeocodingConfig: InitOptions = parseLocalGeocodingConfig(); +export const REVERSE_GEOCODING_DUMP_DIRECTORY = + process.env.REVERSE_GEOCODING_DUMP_DIRECTORY || process.cwd() + '/.reverse-geocoding-dump/'; diff --git a/server/src/infra/repositories/geocoding.repository.ts b/server/src/infra/repositories/geocoding.repository.ts index 7b7b763756..eae72a904f 100644 --- a/server/src/infra/repositories/geocoding.repository.ts +++ b/server/src/infra/repositories/geocoding.repository.ts @@ -1,9 +1,9 @@ import { GeoPoint, IGeocodingRepository, ReverseGeocodeResult } from '@app/domain'; -import { localGeocodingConfig } from '@app/infra'; +import { REVERSE_GEOCODING_DUMP_DIRECTORY } from '@app/infra'; import { Injectable, Logger } from '@nestjs/common'; import { readdir, rm } from 'fs/promises'; import { getName } from 'i18n-iso-countries'; -import geocoder, { AddressObject } from 'local-reverse-geocoder'; +import geocoder, { AddressObject, InitOptions } from 'local-reverse-geocoder'; import path from 'path'; import { promisify } from 'util'; @@ -18,19 +18,33 @@ export type GeoData = AddressObject & { admin2Code?: AdminCode | string; }; -const init = (): Promise => new Promise((resolve) => geocoder.init(localGeocodingConfig, resolve)); const lookup = promisify(geocoder.lookUp).bind(geocoder); @Injectable() export class GeocodingRepository implements IGeocodingRepository { private logger = new Logger(GeocodingRepository.name); - async init(): Promise { - await init(); + async init(options: Partial): Promise { + return new Promise((resolve) => { + geocoder.init( + { + load: { + admin1: true, + admin2: true, + admin3And4: false, + alternateNames: false, + }, + countries: [], + dumpDirectory: REVERSE_GEOCODING_DUMP_DIRECTORY, + ...options, + }, + resolve, + ); + }); } async deleteCache() { - const dumpDirectory = localGeocodingConfig.dumpDirectory; + const dumpDirectory = REVERSE_GEOCODING_DUMP_DIRECTORY; if (dumpDirectory) { // delete contents const items = await readdir(dumpDirectory, { withFileTypes: true }); diff --git a/server/src/microservices/processors/metadata-extraction.processor.ts b/server/src/microservices/processors/metadata-extraction.processor.ts index 9da6903f6b..10d1d27f27 100644 --- a/server/src/microservices/processors/metadata-extraction.processor.ts +++ b/server/src/microservices/processors/metadata-extraction.processor.ts @@ -1,4 +1,5 @@ import { + FeatureFlag, IAlbumRepository, IAssetRepository, IBaseJob, @@ -7,17 +8,18 @@ import { IGeocodingRepository, IJobRepository, IStorageRepository, + ISystemConfigRepository, JobName, JOBS_ASSET_PAGINATION_SIZE, QueueName, StorageCore, StorageFolder, + SystemConfigCore, usePagination, WithoutProperty, } from '@app/domain'; import { AssetEntity, AssetType, ExifEntity } from '@app/infra/entities'; import { Inject, Logger } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; import { DefaultReadTaskOptions, ExifDateTime, exiftool, ReadTaskOptions, Tags } from 'exiftool-vendored'; import { firstDateTime } from 'exiftool-vendored/dist/FirstDateTime'; import * as geotz from 'geo-tz'; @@ -51,8 +53,9 @@ const validate = (value: T): T | null => (typeof value === 'string' ? null : export class MetadataExtractionProcessor { private logger = new Logger(MetadataExtractionProcessor.name); - private reverseGeocodingEnabled: boolean; private storageCore: StorageCore; + private configCore: SystemConfigCore; + private oldCities?: string; constructor( @Inject(IAssetRepository) private assetRepository: IAssetRepository, @@ -61,31 +64,35 @@ export class MetadataExtractionProcessor { @Inject(IGeocodingRepository) private geocodingRepository: IGeocodingRepository, @Inject(ICryptoRepository) private cryptoRepository: ICryptoRepository, @Inject(IStorageRepository) private storageRepository: IStorageRepository, - - configService: ConfigService, + @Inject(ISystemConfigRepository) configRepository: ISystemConfigRepository, ) { - this.reverseGeocodingEnabled = !configService.get('DISABLE_REVERSE_GEOCODING'); this.storageCore = new StorageCore(storageRepository); + this.configCore = new SystemConfigCore(configRepository); + this.configCore.config$.subscribe(() => this.init()); } async init(deleteCache = false) { - this.logger.log(`Reverse geocoding is ${this.reverseGeocodingEnabled ? 'enabled' : 'disabled'}`); - if (!this.reverseGeocodingEnabled) { + const { reverseGeocoding } = await this.configCore.getConfig(); + const { citiesFileOverride } = reverseGeocoding; + + if (!reverseGeocoding.enabled) { return; } try { if (deleteCache) { await this.geocodingRepository.deleteCache(); + } else if (this.oldCities && this.oldCities === citiesFileOverride) { + return; } - this.logger.log('Initializing Reverse Geocoding'); await this.jobRepository.pause(QueueName.METADATA_EXTRACTION); - await this.geocodingRepository.init(); + await this.geocodingRepository.init({ citiesFileOverride }); await this.jobRepository.resume(QueueName.METADATA_EXTRACTION); - this.logger.log('Reverse Geocoding Initialized'); - } catch (error: any) { + this.logger.log(`Initialized local reverse geocoder with ${citiesFileOverride}`); + this.oldCities = citiesFileOverride; + } catch (error: Error | any) { this.logger.error(`Unable to initialize reverse geocoding: ${error}`, error?.stack); } } @@ -161,7 +168,7 @@ export class MetadataExtractionProcessor { private async applyReverseGeocoding(asset: AssetEntity, exifData: ExifEntity) { const { latitude, longitude } = exifData; - if (!this.reverseGeocodingEnabled || !longitude || !latitude) { + if (!(await this.configCore.hasFeature(FeatureFlag.REVERSE_GEOCODING)) || !longitude || !latitude) { return; } diff --git a/server/test/e2e/server-info.e2e-spec.ts b/server/test/e2e/server-info.e2e-spec.ts index e1f6b7ee50..c686b78be2 100644 --- a/server/test/e2e/server-info.e2e-spec.ts +++ b/server/test/e2e/server-info.e2e-spec.ts @@ -85,6 +85,7 @@ describe(`${ServerInfoController.name} (e2e)`, () => { configFile: false, facialRecognition: true, map: true, + reverseGeocoding: true, oauth: false, oauthAutoLaunch: false, passwordLogin: true, diff --git a/web/src/api/open-api/api.ts b/web/src/api/open-api/api.ts index e39b6e4f12..f9c983833f 100644 --- a/web/src/api/open-api/api.ts +++ b/web/src/api/open-api/api.ts @@ -1055,6 +1055,22 @@ export interface CheckExistingAssetsResponseDto { */ 'existingIds': Array; } +/** + * + * @export + * @enum {string} + */ + +export const CitiesFile = { + Cities15000: 'cities15000', + Cities5000: 'cities5000', + Cities1000: 'cities1000', + Cities500: 'cities500' +} as const; + +export type CitiesFile = typeof CitiesFile[keyof typeof CitiesFile]; + + /** * * @export @@ -2650,6 +2666,12 @@ export interface ServerFeaturesDto { * @memberof ServerFeaturesDto */ 'passwordLogin': boolean; + /** + * + * @type {boolean} + * @memberof ServerFeaturesDto + */ + 'reverseGeocoding': boolean; /** * * @type {boolean} @@ -3093,6 +3115,12 @@ export interface SystemConfigDto { * @memberof SystemConfigDto */ 'passwordLogin': SystemConfigPasswordLoginDto; + /** + * + * @type {SystemConfigReverseGeocodingDto} + * @memberof SystemConfigDto + */ + 'reverseGeocoding': SystemConfigReverseGeocodingDto; /** * * @type {SystemConfigStorageTemplateDto} @@ -3438,6 +3466,27 @@ export interface SystemConfigPasswordLoginDto { */ 'enabled': boolean; } +/** + * + * @export + * @interface SystemConfigReverseGeocodingDto + */ +export interface SystemConfigReverseGeocodingDto { + /** + * + * @type {CitiesFile} + * @memberof SystemConfigReverseGeocodingDto + */ + 'citiesFileOverride': CitiesFile; + /** + * + * @type {boolean} + * @memberof SystemConfigReverseGeocodingDto + */ + 'enabled': boolean; +} + + /** * * @export diff --git a/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte b/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte index dff3c65a36..df9059fced 100644 --- a/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte +++ b/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte @@ -4,23 +4,25 @@ NotificationType, } from '$lib/components/shared-components/notification/notification'; import { handleError } from '$lib/utils/handle-error'; - import { api, SystemConfigMapDto } from '@api'; - import { isEqual } from 'lodash-es'; + import { api, CitiesFile, SystemConfigDto } from '@api'; + import { cloneDeep, isEqual } from 'lodash-es'; import { fade } from 'svelte/transition'; + import SettingAccordion from '../setting-accordion.svelte'; import SettingButtonsRow from '../setting-buttons-row.svelte'; - import SettingSwitch from '../setting-switch.svelte'; import SettingInputField, { SettingInputFieldType } from '../setting-input-field.svelte'; + import SettingSwitch from '../setting-switch.svelte'; + import SettingSelect from '../setting-select.svelte'; - export let mapConfig: SystemConfigMapDto; // this is the config that is being edited + export let config: SystemConfigDto; // this is the config that is being edited export let disabled = false; - let savedConfig: SystemConfigMapDto; - let defaultConfig: SystemConfigMapDto; + let savedConfig: SystemConfigDto; + let defaultConfig: SystemConfigDto; - async function getConfigs() { + async function refreshConfig() { [savedConfig, defaultConfig] = await Promise.all([ - api.systemConfigApi.getConfig().then((res) => res.data.map), - api.systemConfigApi.getDefaults().then((res) => res.data.map), + api.systemConfigApi.getConfig().then((res) => res.data), + api.systemConfigApi.getDefaults().then((res) => res.data), ]); } @@ -28,11 +30,21 @@ try { const { data: current } = await api.systemConfigApi.getConfig(); const { data: updated } = await api.systemConfigApi.updateConfig({ - systemConfigDto: { ...current, map: mapConfig }, + systemConfigDto: { + ...current, + map: { + enabled: config.map.enabled, + tileUrl: config.map.tileUrl, + }, + reverseGeocoding: { + enabled: config.reverseGeocoding.enabled, + citiesFileOverride: config.reverseGeocoding.citiesFileOverride, + }, + }, }); - mapConfig = { ...updated.map }; - savedConfig = { ...updated.map }; + config = cloneDeep(updated); + savedConfig = cloneDeep(updated); notificationController.show({ message: 'Settings saved', type: NotificationType.Info }); } catch (error) { @@ -43,8 +55,8 @@ async function reset() { const { data: resetConfig } = await api.systemConfigApi.getConfig(); - mapConfig = { ...resetConfig.map }; - savedConfig = { ...resetConfig.map }; + config = cloneDeep(resetConfig); + savedConfig = cloneDeep(resetConfig); notificationController.show({ message: 'Reset settings to the recent saved settings', @@ -55,8 +67,8 @@ async function resetToDefault() { const { data: configs } = await api.systemConfigApi.getDefaults(); - mapConfig = { ...configs.map }; - defaultConfig = { ...configs.map }; + config = cloneDeep(configs); + defaultConfig = cloneDeep(configs); notificationController.show({ message: 'Reset map settings to default', @@ -65,30 +77,81 @@ } -
- {#await getConfigs() then} +
+ {#await refreshConfig() then}
-
- +
+ +
+ -
+
- + +
+ + + +

+ Manage Reverse Geocoding settings +

+
+
+ + +
+ + +
diff --git a/web/src/lib/components/admin-page/settings/setting-accordion.svelte b/web/src/lib/components/admin-page/settings/setting-accordion.svelte index 9acdfb392e..1d9290e617 100755 --- a/web/src/lib/components/admin-page/settings/setting-accordion.svelte +++ b/web/src/lib/components/admin-page/settings/setting-accordion.svelte @@ -14,7 +14,9 @@ {title} -

{subtitle}

+ +

{subtitle}

+