diff --git a/cli/src/api/open-api/api.ts b/cli/src/api/open-api/api.ts index 2b2a31b71..8aa65b66f 100644 --- a/cli/src/api/open-api/api.ts +++ b/cli/src/api/open-api/api.ts @@ -2343,6 +2343,31 @@ export interface SearchResponseDto { */ 'assets': SearchAssetResponseDto; } +/** + * + * @export + * @interface ServerConfigDto + */ +export interface ServerConfigDto { + /** + * + * @type {string} + * @memberof ServerConfigDto + */ + 'loginPageMessage': string; + /** + * + * @type {string} + * @memberof ServerConfigDto + */ + 'mapTileUrl': string; + /** + * + * @type {string} + * @memberof ServerConfigDto + */ + 'oauthButtonText': string; +} /** * * @export @@ -2367,6 +2392,12 @@ export interface ServerFeaturesDto { * @memberof ServerFeaturesDto */ 'facialRecognition': boolean; + /** + * + * @type {boolean} + * @memberof ServerFeaturesDto + */ + 'map': boolean; /** * * @type {boolean} @@ -2810,6 +2841,12 @@ export interface SystemConfigDto { * @memberof SystemConfigDto */ 'machineLearning': SystemConfigMachineLearningDto; + /** + * + * @type {SystemConfigMapDto} + * @memberof SystemConfigDto + */ + 'map': SystemConfigMapDto; /** * * @type {SystemConfigOAuthDto} @@ -3050,6 +3087,25 @@ export interface SystemConfigMachineLearningDto { */ 'url': string; } +/** + * + * @export + * @interface SystemConfigMapDto + */ +export interface SystemConfigMapDto { + /** + * + * @type {boolean} + * @memberof SystemConfigMapDto + */ + 'enabled': boolean; + /** + * + * @type {string} + * @memberof SystemConfigMapDto + */ + 'tileUrl': string; +} /** * * @export @@ -10825,6 +10881,35 @@ export class SearchApi extends BaseAPI { */ export const ServerInfoApiAxiosParamCreator = function (configuration?: Configuration) { return { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getServerConfig: async (options: AxiosRequestConfig = {}): Promise => { + const localVarPath = `/server-info/config`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * * @param {*} [options] Override http request option. @@ -11027,6 +11112,15 @@ export const ServerInfoApiAxiosParamCreator = function (configuration?: Configur export const ServerInfoApiFp = function(configuration?: Configuration) { const localVarAxiosParamCreator = ServerInfoApiAxiosParamCreator(configuration) return { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getServerConfig(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getServerConfig(options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @param {*} [options] Override http request option. @@ -11091,6 +11185,14 @@ export const ServerInfoApiFp = function(configuration?: Configuration) { export const ServerInfoApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { const localVarFp = ServerInfoApiFp(configuration) return { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getServerConfig(options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.getServerConfig(options).then((request) => request(axios, basePath)); + }, /** * * @param {*} [options] Override http request option. @@ -11149,6 +11251,16 @@ export const ServerInfoApiFactory = function (configuration?: Configuration, bas * @extends {BaseAPI} */ export class ServerInfoApi extends BaseAPI { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ServerInfoApi + */ + public getServerConfig(options?: AxiosRequestConfig) { + return ServerInfoApiFp(this.configuration).getServerConfig(options).then((request) => request(this.axios, this.basePath)); + } + /** * * @param {*} [options] Override http request option. diff --git a/mobile/openapi/.openapi-generator/FILES b/mobile/openapi/.openapi-generator/FILES index 5cb7fa651..40490a32d 100644 --- a/mobile/openapi/.openapi-generator/FILES +++ b/mobile/openapi/.openapi-generator/FILES @@ -97,6 +97,7 @@ doc/SearchExploreResponseDto.md doc/SearchFacetCountResponseDto.md doc/SearchFacetResponseDto.md doc/SearchResponseDto.md +doc/ServerConfigDto.md doc/ServerFeaturesDto.md doc/ServerInfoApi.md doc/ServerInfoResponseDto.md @@ -116,6 +117,7 @@ doc/SystemConfigDto.md doc/SystemConfigFFmpegDto.md doc/SystemConfigJobDto.md doc/SystemConfigMachineLearningDto.md +doc/SystemConfigMapDto.md doc/SystemConfigOAuthDto.md doc/SystemConfigPasswordLoginDto.md doc/SystemConfigStorageTemplateDto.md @@ -249,6 +251,7 @@ lib/model/search_explore_response_dto.dart lib/model/search_facet_count_response_dto.dart lib/model/search_facet_response_dto.dart lib/model/search_response_dto.dart +lib/model/server_config_dto.dart lib/model/server_features_dto.dart lib/model/server_info_response_dto.dart lib/model/server_media_types_response_dto.dart @@ -265,6 +268,7 @@ lib/model/system_config_dto.dart lib/model/system_config_f_fmpeg_dto.dart lib/model/system_config_job_dto.dart 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_storage_template_dto.dart @@ -382,6 +386,7 @@ test/search_explore_response_dto_test.dart test/search_facet_count_response_dto_test.dart test/search_facet_response_dto_test.dart test/search_response_dto_test.dart +test/server_config_dto_test.dart test/server_features_dto_test.dart test/server_info_api_test.dart test/server_info_response_dto_test.dart @@ -401,6 +406,7 @@ test/system_config_dto_test.dart test/system_config_f_fmpeg_dto_test.dart test/system_config_job_dto_test.dart 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_storage_template_dto_test.dart diff --git a/mobile/openapi/README.md b/mobile/openapi/README.md index 52e680175..096cc9715 100644 --- a/mobile/openapi/README.md +++ b/mobile/openapi/README.md @@ -142,6 +142,7 @@ Class | Method | HTTP request | Description *PersonApi* | [**updatePerson**](doc//PersonApi.md#updateperson) | **PUT** /person/{id} | *SearchApi* | [**getExploreData**](doc//SearchApi.md#getexploredata) | **GET** /search/explore | *SearchApi* | [**search**](doc//SearchApi.md#search) | **GET** /search | +*ServerInfoApi* | [**getServerConfig**](doc//ServerInfoApi.md#getserverconfig) | **GET** /server-info/config | *ServerInfoApi* | [**getServerFeatures**](doc//ServerInfoApi.md#getserverfeatures) | **GET** /server-info/features | *ServerInfoApi* | [**getServerInfo**](doc//ServerInfoApi.md#getserverinfo) | **GET** /server-info | *ServerInfoApi* | [**getServerVersion**](doc//ServerInfoApi.md#getserverversion) | **GET** /server-info/version | @@ -266,6 +267,7 @@ Class | Method | HTTP request | Description - [SearchFacetCountResponseDto](doc//SearchFacetCountResponseDto.md) - [SearchFacetResponseDto](doc//SearchFacetResponseDto.md) - [SearchResponseDto](doc//SearchResponseDto.md) + - [ServerConfigDto](doc//ServerConfigDto.md) - [ServerFeaturesDto](doc//ServerFeaturesDto.md) - [ServerInfoResponseDto](doc//ServerInfoResponseDto.md) - [ServerMediaTypesResponseDto](doc//ServerMediaTypesResponseDto.md) @@ -282,6 +284,7 @@ Class | Method | HTTP request | Description - [SystemConfigFFmpegDto](doc//SystemConfigFFmpegDto.md) - [SystemConfigJobDto](doc//SystemConfigJobDto.md) - [SystemConfigMachineLearningDto](doc//SystemConfigMachineLearningDto.md) + - [SystemConfigMapDto](doc//SystemConfigMapDto.md) - [SystemConfigOAuthDto](doc//SystemConfigOAuthDto.md) - [SystemConfigPasswordLoginDto](doc//SystemConfigPasswordLoginDto.md) - [SystemConfigStorageTemplateDto](doc//SystemConfigStorageTemplateDto.md) diff --git a/mobile/openapi/doc/ServerConfigDto.md b/mobile/openapi/doc/ServerConfigDto.md new file mode 100644 index 000000000..f40c28a65 --- /dev/null +++ b/mobile/openapi/doc/ServerConfigDto.md @@ -0,0 +1,17 @@ +# openapi.model.ServerConfigDto + +## Load the model package +```dart +import 'package:openapi/api.dart'; +``` + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**loginPageMessage** | **String** | | +**mapTileUrl** | **String** | | +**oauthButtonText** | **String** | | + +[[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 168479b99..c5f7946f3 100644 --- a/mobile/openapi/doc/ServerFeaturesDto.md +++ b/mobile/openapi/doc/ServerFeaturesDto.md @@ -11,6 +11,7 @@ Name | Type | Description | Notes **clipEncode** | **bool** | | **configFile** | **bool** | | **facialRecognition** | **bool** | | +**map** | **bool** | | **oauth** | **bool** | | **oauthAutoLaunch** | **bool** | | **passwordLogin** | **bool** | | diff --git a/mobile/openapi/doc/ServerInfoApi.md b/mobile/openapi/doc/ServerInfoApi.md index 62758afbe..c196bf108 100644 --- a/mobile/openapi/doc/ServerInfoApi.md +++ b/mobile/openapi/doc/ServerInfoApi.md @@ -9,6 +9,7 @@ All URIs are relative to */api* Method | HTTP request | Description ------------- | ------------- | ------------- +[**getServerConfig**](ServerInfoApi.md#getserverconfig) | **GET** /server-info/config | [**getServerFeatures**](ServerInfoApi.md#getserverfeatures) | **GET** /server-info/features | [**getServerInfo**](ServerInfoApi.md#getserverinfo) | **GET** /server-info | [**getServerVersion**](ServerInfoApi.md#getserverversion) | **GET** /server-info/version | @@ -17,6 +18,43 @@ Method | HTTP request | Description [**pingServer**](ServerInfoApi.md#pingserver) | **GET** /server-info/ping | +# **getServerConfig** +> ServerConfigDto getServerConfig() + + + +### Example +```dart +import 'package:openapi/api.dart'; + +final api_instance = ServerInfoApi(); + +try { + final result = api_instance.getServerConfig(); + print(result); +} catch (e) { + print('Exception when calling ServerInfoApi->getServerConfig: $e\n'); +} +``` + +### Parameters +This endpoint does not need any parameter. + +### Return type + +[**ServerConfigDto**](ServerConfigDto.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **getServerFeatures** > ServerFeaturesDto getServerFeatures() diff --git a/mobile/openapi/doc/SystemConfigDto.md b/mobile/openapi/doc/SystemConfigDto.md index 6fc980852..40d528b40 100644 --- a/mobile/openapi/doc/SystemConfigDto.md +++ b/mobile/openapi/doc/SystemConfigDto.md @@ -11,6 +11,7 @@ Name | Type | Description | Notes **ffmpeg** | [**SystemConfigFFmpegDto**](SystemConfigFFmpegDto.md) | | **job** | [**SystemConfigJobDto**](SystemConfigJobDto.md) | | **machineLearning** | [**SystemConfigMachineLearningDto**](SystemConfigMachineLearningDto.md) | | +**map** | [**SystemConfigMapDto**](SystemConfigMapDto.md) | | **oauth** | [**SystemConfigOAuthDto**](SystemConfigOAuthDto.md) | | **passwordLogin** | [**SystemConfigPasswordLoginDto**](SystemConfigPasswordLoginDto.md) | | **storageTemplate** | [**SystemConfigStorageTemplateDto**](SystemConfigStorageTemplateDto.md) | | diff --git a/mobile/openapi/doc/SystemConfigMapDto.md b/mobile/openapi/doc/SystemConfigMapDto.md new file mode 100644 index 000000000..99fa91fd2 --- /dev/null +++ b/mobile/openapi/doc/SystemConfigMapDto.md @@ -0,0 +1,16 @@ +# openapi.model.SystemConfigMapDto + +## Load the model package +```dart +import 'package:openapi/api.dart'; +``` + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**enabled** | **bool** | | +**tileUrl** | **String** | | + +[[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 73a6d84e1..cec7ba904 100644 --- a/mobile/openapi/lib/api.dart +++ b/mobile/openapi/lib/api.dart @@ -128,6 +128,7 @@ part 'model/search_explore_response_dto.dart'; part 'model/search_facet_count_response_dto.dart'; part 'model/search_facet_response_dto.dart'; part 'model/search_response_dto.dart'; +part 'model/server_config_dto.dart'; part 'model/server_features_dto.dart'; part 'model/server_info_response_dto.dart'; part 'model/server_media_types_response_dto.dart'; @@ -144,6 +145,7 @@ part 'model/system_config_dto.dart'; part 'model/system_config_f_fmpeg_dto.dart'; part 'model/system_config_job_dto.dart'; 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_storage_template_dto.dart'; diff --git a/mobile/openapi/lib/api/server_info_api.dart b/mobile/openapi/lib/api/server_info_api.dart index 3b7899cc2..51bcbfa4b 100644 --- a/mobile/openapi/lib/api/server_info_api.dart +++ b/mobile/openapi/lib/api/server_info_api.dart @@ -16,6 +16,47 @@ class ServerInfoApi { final ApiClient apiClient; + /// Performs an HTTP 'GET /server-info/config' operation and returns the [Response]. + Future getServerConfigWithHttpInfo() async { + // ignore: prefer_const_declarations + final path = r'/server-info/config'; + + // ignore: prefer_final_locals + Object? postBody; + + final queryParams = []; + final headerParams = {}; + final formParams = {}; + + const contentTypes = []; + + + return apiClient.invokeAPI( + path, + 'GET', + queryParams, + postBody, + headerParams, + formParams, + contentTypes.isEmpty ? null : contentTypes.first, + ); + } + + Future getServerConfig() async { + final response = await getServerConfigWithHttpInfo(); + if (response.statusCode >= HttpStatus.badRequest) { + throw ApiException(response.statusCode, await _decodeBodyBytes(response)); + } + // When a remote server returns no body with a status of 204, we shall not decode it. + // At the time of writing this, `dart:convert` will throw an "Unexpected end of input" + // FormatException when trying to decode an empty string. + if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { + return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ServerConfigDto',) as ServerConfigDto; + + } + return null; + } + /// Performs an HTTP 'GET /server-info/features' operation and returns the [Response]. Future getServerFeaturesWithHttpInfo() async { // ignore: prefer_const_declarations diff --git a/mobile/openapi/lib/api_client.dart b/mobile/openapi/lib/api_client.dart index 38ffa7f1b..063e1cb27 100644 --- a/mobile/openapi/lib/api_client.dart +++ b/mobile/openapi/lib/api_client.dart @@ -349,6 +349,8 @@ class ApiClient { return SearchFacetResponseDto.fromJson(value); case 'SearchResponseDto': return SearchResponseDto.fromJson(value); + case 'ServerConfigDto': + return ServerConfigDto.fromJson(value); case 'ServerFeaturesDto': return ServerFeaturesDto.fromJson(value); case 'ServerInfoResponseDto': @@ -381,6 +383,8 @@ class ApiClient { return SystemConfigJobDto.fromJson(value); case 'SystemConfigMachineLearningDto': return SystemConfigMachineLearningDto.fromJson(value); + case 'SystemConfigMapDto': + return SystemConfigMapDto.fromJson(value); case 'SystemConfigOAuthDto': return SystemConfigOAuthDto.fromJson(value); case 'SystemConfigPasswordLoginDto': diff --git a/mobile/openapi/lib/model/server_config_dto.dart b/mobile/openapi/lib/model/server_config_dto.dart new file mode 100644 index 000000000..75fe4b2bf --- /dev/null +++ b/mobile/openapi/lib/model/server_config_dto.dart @@ -0,0 +1,114 @@ +// +// 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 ServerConfigDto { + /// Returns a new [ServerConfigDto] instance. + ServerConfigDto({ + required this.loginPageMessage, + required this.mapTileUrl, + required this.oauthButtonText, + }); + + String loginPageMessage; + + String mapTileUrl; + + String oauthButtonText; + + @override + bool operator ==(Object other) => identical(this, other) || other is ServerConfigDto && + other.loginPageMessage == loginPageMessage && + other.mapTileUrl == mapTileUrl && + other.oauthButtonText == oauthButtonText; + + @override + int get hashCode => + // ignore: unnecessary_parenthesis + (loginPageMessage.hashCode) + + (mapTileUrl.hashCode) + + (oauthButtonText.hashCode); + + @override + String toString() => 'ServerConfigDto[loginPageMessage=$loginPageMessage, mapTileUrl=$mapTileUrl, oauthButtonText=$oauthButtonText]'; + + Map toJson() { + final json = {}; + json[r'loginPageMessage'] = this.loginPageMessage; + json[r'mapTileUrl'] = this.mapTileUrl; + json[r'oauthButtonText'] = this.oauthButtonText; + return json; + } + + /// Returns a new [ServerConfigDto] instance and imports its values from + /// [value] if it's a [Map], null otherwise. + // ignore: prefer_constructors_over_static_methods + static ServerConfigDto? fromJson(dynamic value) { + if (value is Map) { + final json = value.cast(); + + return ServerConfigDto( + loginPageMessage: mapValueOfType(json, r'loginPageMessage')!, + mapTileUrl: mapValueOfType(json, r'mapTileUrl')!, + oauthButtonText: mapValueOfType(json, r'oauthButtonText')!, + ); + } + 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 = ServerConfigDto.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 = ServerConfigDto.fromJson(entry.value); + if (value != null) { + map[entry.key] = value; + } + } + } + return map; + } + + // maps a json object with a list of ServerConfigDto-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] = ServerConfigDto.listFromJson(entry.value, growable: growable,); + } + } + return map; + } + + /// The list of required keys that must be present in a JSON. + static const requiredKeys = { + 'loginPageMessage', + 'mapTileUrl', + 'oauthButtonText', + }; +} + diff --git a/mobile/openapi/lib/model/server_features_dto.dart b/mobile/openapi/lib/model/server_features_dto.dart index 60827add6..07a725232 100644 --- a/mobile/openapi/lib/model/server_features_dto.dart +++ b/mobile/openapi/lib/model/server_features_dto.dart @@ -16,6 +16,7 @@ class ServerFeaturesDto { required this.clipEncode, required this.configFile, required this.facialRecognition, + required this.map, required this.oauth, required this.oauthAutoLaunch, required this.passwordLogin, @@ -30,6 +31,8 @@ class ServerFeaturesDto { bool facialRecognition; + bool map; + bool oauth; bool oauthAutoLaunch; @@ -47,6 +50,7 @@ class ServerFeaturesDto { other.clipEncode == clipEncode && other.configFile == configFile && other.facialRecognition == facialRecognition && + other.map == map && other.oauth == oauth && other.oauthAutoLaunch == oauthAutoLaunch && other.passwordLogin == passwordLogin && @@ -60,6 +64,7 @@ class ServerFeaturesDto { (clipEncode.hashCode) + (configFile.hashCode) + (facialRecognition.hashCode) + + (map.hashCode) + (oauth.hashCode) + (oauthAutoLaunch.hashCode) + (passwordLogin.hashCode) + @@ -68,13 +73,14 @@ class ServerFeaturesDto { (tagImage.hashCode); @override - String toString() => 'ServerFeaturesDto[clipEncode=$clipEncode, configFile=$configFile, facialRecognition=$facialRecognition, 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, search=$search, sidecar=$sidecar, tagImage=$tagImage]'; Map toJson() { final json = {}; json[r'clipEncode'] = this.clipEncode; json[r'configFile'] = this.configFile; json[r'facialRecognition'] = this.facialRecognition; + json[r'map'] = this.map; json[r'oauth'] = this.oauth; json[r'oauthAutoLaunch'] = this.oauthAutoLaunch; json[r'passwordLogin'] = this.passwordLogin; @@ -95,6 +101,7 @@ class ServerFeaturesDto { clipEncode: mapValueOfType(json, r'clipEncode')!, configFile: mapValueOfType(json, r'configFile')!, facialRecognition: mapValueOfType(json, r'facialRecognition')!, + map: mapValueOfType(json, r'map')!, oauth: mapValueOfType(json, r'oauth')!, oauthAutoLaunch: mapValueOfType(json, r'oauthAutoLaunch')!, passwordLogin: mapValueOfType(json, r'passwordLogin')!, @@ -151,6 +158,7 @@ class ServerFeaturesDto { 'clipEncode', 'configFile', 'facialRecognition', + 'map', 'oauth', 'oauthAutoLaunch', 'passwordLogin', diff --git a/mobile/openapi/lib/model/system_config_dto.dart b/mobile/openapi/lib/model/system_config_dto.dart index da0500ebf..2fe46a039 100644 --- a/mobile/openapi/lib/model/system_config_dto.dart +++ b/mobile/openapi/lib/model/system_config_dto.dart @@ -16,6 +16,7 @@ class SystemConfigDto { required this.ffmpeg, required this.job, required this.machineLearning, + required this.map, required this.oauth, required this.passwordLogin, required this.storageTemplate, @@ -28,6 +29,8 @@ class SystemConfigDto { SystemConfigMachineLearningDto machineLearning; + SystemConfigMapDto map; + SystemConfigOAuthDto oauth; SystemConfigPasswordLoginDto passwordLogin; @@ -41,6 +44,7 @@ class SystemConfigDto { other.ffmpeg == ffmpeg && other.job == job && other.machineLearning == machineLearning && + other.map == map && other.oauth == oauth && other.passwordLogin == passwordLogin && other.storageTemplate == storageTemplate && @@ -52,19 +56,21 @@ class SystemConfigDto { (ffmpeg.hashCode) + (job.hashCode) + (machineLearning.hashCode) + + (map.hashCode) + (oauth.hashCode) + (passwordLogin.hashCode) + (storageTemplate.hashCode) + (thumbnail.hashCode); @override - String toString() => 'SystemConfigDto[ffmpeg=$ffmpeg, job=$job, machineLearning=$machineLearning, oauth=$oauth, passwordLogin=$passwordLogin, storageTemplate=$storageTemplate, thumbnail=$thumbnail]'; + String toString() => 'SystemConfigDto[ffmpeg=$ffmpeg, job=$job, machineLearning=$machineLearning, map=$map, oauth=$oauth, passwordLogin=$passwordLogin, storageTemplate=$storageTemplate, thumbnail=$thumbnail]'; Map toJson() { final json = {}; json[r'ffmpeg'] = this.ffmpeg; json[r'job'] = this.job; json[r'machineLearning'] = this.machineLearning; + json[r'map'] = this.map; json[r'oauth'] = this.oauth; json[r'passwordLogin'] = this.passwordLogin; json[r'storageTemplate'] = this.storageTemplate; @@ -83,6 +89,7 @@ class SystemConfigDto { ffmpeg: SystemConfigFFmpegDto.fromJson(json[r'ffmpeg'])!, job: SystemConfigJobDto.fromJson(json[r'job'])!, machineLearning: SystemConfigMachineLearningDto.fromJson(json[r'machineLearning'])!, + map: SystemConfigMapDto.fromJson(json[r'map'])!, oauth: SystemConfigOAuthDto.fromJson(json[r'oauth'])!, passwordLogin: SystemConfigPasswordLoginDto.fromJson(json[r'passwordLogin'])!, storageTemplate: SystemConfigStorageTemplateDto.fromJson(json[r'storageTemplate'])!, @@ -137,6 +144,7 @@ class SystemConfigDto { 'ffmpeg', 'job', 'machineLearning', + 'map', 'oauth', 'passwordLogin', 'storageTemplate', diff --git a/mobile/openapi/lib/model/system_config_map_dto.dart b/mobile/openapi/lib/model/system_config_map_dto.dart new file mode 100644 index 000000000..1d39f7152 --- /dev/null +++ b/mobile/openapi/lib/model/system_config_map_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 SystemConfigMapDto { + /// Returns a new [SystemConfigMapDto] instance. + SystemConfigMapDto({ + required this.enabled, + required this.tileUrl, + }); + + bool enabled; + + String tileUrl; + + @override + bool operator ==(Object other) => identical(this, other) || other is SystemConfigMapDto && + other.enabled == enabled && + other.tileUrl == tileUrl; + + @override + int get hashCode => + // ignore: unnecessary_parenthesis + (enabled.hashCode) + + (tileUrl.hashCode); + + @override + String toString() => 'SystemConfigMapDto[enabled=$enabled, tileUrl=$tileUrl]'; + + Map toJson() { + final json = {}; + json[r'enabled'] = this.enabled; + json[r'tileUrl'] = this.tileUrl; + return json; + } + + /// Returns a new [SystemConfigMapDto] instance and imports its values from + /// [value] if it's a [Map], null otherwise. + // ignore: prefer_constructors_over_static_methods + static SystemConfigMapDto? fromJson(dynamic value) { + if (value is Map) { + final json = value.cast(); + + return SystemConfigMapDto( + enabled: mapValueOfType(json, r'enabled')!, + tileUrl: mapValueOfType(json, r'tileUrl')!, + ); + } + 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 = SystemConfigMapDto.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 = SystemConfigMapDto.fromJson(entry.value); + if (value != null) { + map[entry.key] = value; + } + } + } + return map; + } + + // maps a json object with a list of SystemConfigMapDto-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] = SystemConfigMapDto.listFromJson(entry.value, growable: growable,); + } + } + return map; + } + + /// The list of required keys that must be present in a JSON. + static const requiredKeys = { + 'enabled', + 'tileUrl', + }; +} + diff --git a/mobile/openapi/test/server_config_dto_test.dart b/mobile/openapi/test/server_config_dto_test.dart new file mode 100644 index 000000000..03aa0ea43 --- /dev/null +++ b/mobile/openapi/test/server_config_dto_test.dart @@ -0,0 +1,37 @@ +// +// 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 ServerConfigDto +void main() { + // final instance = ServerConfigDto(); + + group('test ServerConfigDto', () { + // String loginPageMessage + test('to test the property `loginPageMessage`', () async { + // TODO + }); + + // String mapTileUrl + test('to test the property `mapTileUrl`', () async { + // TODO + }); + + // String oauthButtonText + test('to test the property `oauthButtonText`', () async { + // TODO + }); + + + }); + +} diff --git a/mobile/openapi/test/server_features_dto_test.dart b/mobile/openapi/test/server_features_dto_test.dart index 2cd1387ba..6838e1256 100644 --- a/mobile/openapi/test/server_features_dto_test.dart +++ b/mobile/openapi/test/server_features_dto_test.dart @@ -31,6 +31,11 @@ void main() { // TODO }); + // bool map + test('to test the property `map`', () async { + // TODO + }); + // bool oauth test('to test the property `oauth`', () async { // TODO diff --git a/mobile/openapi/test/server_info_api_test.dart b/mobile/openapi/test/server_info_api_test.dart index 8ca3e30ef..17e5e2c5e 100644 --- a/mobile/openapi/test/server_info_api_test.dart +++ b/mobile/openapi/test/server_info_api_test.dart @@ -17,6 +17,11 @@ void main() { // final instance = ServerInfoApi(); group('tests for ServerInfoApi', () { + //Future getServerConfig() async + test('test getServerConfig', () async { + // TODO + }); + //Future getServerFeatures() async test('test getServerFeatures', () async { // TODO diff --git a/mobile/openapi/test/system_config_dto_test.dart b/mobile/openapi/test/system_config_dto_test.dart index 4ea0b98bd..8951d16ca 100644 --- a/mobile/openapi/test/system_config_dto_test.dart +++ b/mobile/openapi/test/system_config_dto_test.dart @@ -31,6 +31,11 @@ void main() { // TODO }); + // SystemConfigMapDto map + test('to test the property `map`', () async { + // TODO + }); + // SystemConfigOAuthDto oauth test('to test the property `oauth`', () async { // TODO diff --git a/mobile/openapi/test/system_config_map_dto_test.dart b/mobile/openapi/test/system_config_map_dto_test.dart new file mode 100644 index 000000000..d0b753dc0 --- /dev/null +++ b/mobile/openapi/test/system_config_map_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 SystemConfigMapDto +void main() { + // final instance = SystemConfigMapDto(); + + group('test SystemConfigMapDto', () { + // bool enabled + test('to test the property `enabled`', () async { + // TODO + }); + + // String tileUrl + test('to test the property `tileUrl`', () async { + // TODO + }); + + + }); + +} diff --git a/server/immich-openapi-specs.json b/server/immich-openapi-specs.json index 2495001da..ef6bee00f 100644 --- a/server/immich-openapi-specs.json +++ b/server/immich-openapi-specs.json @@ -3342,6 +3342,27 @@ ] } }, + "/server-info/config": { + "get": { + "operationId": "getServerConfig", + "parameters": [], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServerConfigDto" + } + } + }, + "description": "" + } + }, + "tags": [ + "Server Info" + ] + } + }, "/server-info/features": { "get": { "operationId": "getServerFeatures", @@ -6618,6 +6639,25 @@ ], "type": "object" }, + "ServerConfigDto": { + "properties": { + "loginPageMessage": { + "type": "string" + }, + "mapTileUrl": { + "type": "string" + }, + "oauthButtonText": { + "type": "string" + } + }, + "required": [ + "oauthButtonText", + "loginPageMessage", + "mapTileUrl" + ], + "type": "object" + }, "ServerFeaturesDto": { "properties": { "clipEncode": { @@ -6629,6 +6669,9 @@ "facialRecognition": { "type": "boolean" }, + "map": { + "type": "boolean" + }, "oauth": { "type": "boolean" }, @@ -6649,15 +6692,16 @@ } }, "required": [ - "configFile", "clipEncode", + "configFile", "facialRecognition", - "sidecar", - "search", - "tagImage", + "map", "oauth", "oauthAutoLaunch", - "passwordLogin" + "passwordLogin", + "sidecar", + "search", + "tagImage" ], "type": "object" }, @@ -6989,6 +7033,9 @@ "machineLearning": { "$ref": "#/components/schemas/SystemConfigMachineLearningDto" }, + "map": { + "$ref": "#/components/schemas/SystemConfigMapDto" + }, "oauth": { "$ref": "#/components/schemas/SystemConfigOAuthDto" }, @@ -7005,6 +7052,7 @@ "required": [ "ffmpeg", "machineLearning", + "map", "oauth", "passwordLogin", "storageTemplate", @@ -7162,6 +7210,21 @@ ], "type": "object" }, + "SystemConfigMapDto": { + "properties": { + "enabled": { + "type": "boolean" + }, + "tileUrl": { + "type": "string" + } + }, + "required": [ + "enabled", + "tileUrl" + ], + "type": "object" + }, "SystemConfigOAuthDto": { "properties": { "autoLaunch": { diff --git a/server/src/domain/server-info/server-info.dto.ts b/server/src/domain/server-info/server-info.dto.ts index b9cdd181f..105fc1bd2 100644 --- a/server/src/domain/server-info/server-info.dto.ts +++ b/server/src/domain/server-info/server-info.dto.ts @@ -79,16 +79,21 @@ export class ServerMediaTypesResponseDto { sidecar!: string[]; } -export class ServerFeaturesDto implements FeatureFlags { - configFile!: boolean; - clipEncode!: boolean; - facialRecognition!: boolean; - sidecar!: boolean; - search!: boolean; - tagImage!: boolean; +export class ServerConfigDto { + oauthButtonText!: string; + loginPageMessage!: string; + mapTileUrl!: string; +} - // TODO: use these instead of `POST oauth/config` +export class ServerFeaturesDto implements FeatureFlags { + clipEncode!: boolean; + configFile!: boolean; + facialRecognition!: boolean; + map!: boolean; oauth!: boolean; oauthAutoLaunch!: boolean; passwordLogin!: boolean; + sidecar!: boolean; + search!: boolean; + tagImage!: 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 6c8d19464..4363e379b 100644 --- a/server/src/domain/server-info/server-info.service.spec.ts +++ b/server/src/domain/server-info/server-info.service.spec.ts @@ -143,22 +143,34 @@ describe(ServerInfoService.name, () => { it('should respond the server version', () => { expect(sut.getVersion()).toEqual(serverVersion); }); + }); - describe('getFeatures', () => { - it('should respond the server features', async () => { - await expect(sut.getFeatures()).resolves.toEqual({ - clipEncode: true, - facialRecognition: true, - oauth: false, - oauthAutoLaunch: false, - passwordLogin: true, - search: true, - sidecar: true, - tagImage: true, - configFile: false, - }); - expect(configMock.load).toHaveBeenCalled(); + describe('getFeatures', () => { + it('should respond the server features', async () => { + await expect(sut.getFeatures()).resolves.toEqual({ + clipEncode: true, + facialRecognition: true, + map: true, + oauth: false, + oauthAutoLaunch: false, + passwordLogin: true, + search: true, + sidecar: true, + tagImage: true, + configFile: false, }); + expect(configMock.load).toHaveBeenCalled(); + }); + }); + + describe('getConfig', () => { + it('should respond the server configuration', async () => { + await expect(sut.getConfig()).resolves.toEqual({ + loginPageMessage: '', + oauthButtonText: 'Login with OAuth', + mapTileUrl: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + }); + expect(configMock.load).toHaveBeenCalled(); }); }); diff --git a/server/src/domain/server-info/server-info.service.ts b/server/src/domain/server-info/server-info.service.ts index 655b21603..86dc4b8d0 100644 --- a/server/src/domain/server-info/server-info.service.ts +++ b/server/src/domain/server-info/server-info.service.ts @@ -5,6 +5,7 @@ import { IStorageRepository, StorageCore, StorageFolder } from '../storage'; import { ISystemConfigRepository, SystemConfigCore } from '../system-config'; import { IUserRepository, UserStatsQueryResponse } from '../user'; import { + ServerConfigDto, ServerFeaturesDto, ServerInfoResponseDto, ServerMediaTypesResponseDto, @@ -55,6 +56,19 @@ export class ServerInfoService { return this.configCore.getFeatures(); } + async getConfig(): Promise { + const config = await this.configCore.getConfig(); + + // TODO move to system config + const loginPageMessage = process.env.PUBLIC_LOGIN_PAGE_MESSAGE || ''; + + return { + loginPageMessage, + mapTileUrl: config.map.tileUrl, + oauthButtonText: config.oauth.buttonText, + }; + } + async getStats(): Promise { const userStats: UserStatsQueryResponse[] = await this.userRepository.getUserStats(); const serverStats = new ServerStatsResponseDto(); diff --git a/server/src/domain/system-config/dto/system-config-map.dto.ts b/server/src/domain/system-config/dto/system-config-map.dto.ts new file mode 100644 index 000000000..479b1486d --- /dev/null +++ b/server/src/domain/system-config/dto/system-config-map.dto.ts @@ -0,0 +1,9 @@ +import { IsBoolean, IsString } from 'class-validator'; + +export class SystemConfigMapDto { + @IsBoolean() + enabled!: boolean; + + @IsString() + tileUrl!: string; +} 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 c089da3df..9ec7de622 100644 --- a/server/src/domain/system-config/dto/system-config.dto.ts +++ b/server/src/domain/system-config/dto/system-config.dto.ts @@ -5,6 +5,7 @@ import { IsObject, ValidateNested } from 'class-validator'; import { SystemConfigFFmpegDto } from './system-config-ffmpeg.dto'; import { SystemConfigJobDto } from './system-config-job.dto'; import { SystemConfigMachineLearningDto } from './system-config-machine-learning.dto'; +import { SystemConfigMapDto } from './system-config-map.dto'; import { SystemConfigOAuthDto } from './system-config-oauth.dto'; import { SystemConfigPasswordLoginDto } from './system-config-password-login.dto'; import { SystemConfigStorageTemplateDto } from './system-config-storage-template.dto'; @@ -20,6 +21,11 @@ export class SystemConfigDto implements SystemConfig { @IsObject() machineLearning!: SystemConfigMachineLearningDto; + @Type(() => SystemConfigMapDto) + @ValidateNested() + @IsObject() + map!: SystemConfigMapDto; + @Type(() => SystemConfigOAuthDto) @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 cfe64b0a7..e33a168e8 100644 --- a/server/src/domain/system-config/system-config.core.ts +++ b/server/src/domain/system-config/system-config.core.ts @@ -55,7 +55,6 @@ export const defaults = Object.freeze({ [QueueName.THUMBNAIL_GENERATION]: { concurrency: 5 }, [QueueName.VIDEO_CONVERSION]: { concurrency: 1 }, }, - machineLearning: { enabled: process.env.IMMICH_MACHINE_LEARNING_ENABLED !== 'false', url: process.env.IMMICH_MACHINE_LEARNING_URL || 'http://immich-machine-learning:3003', @@ -75,6 +74,10 @@ export const defaults = Object.freeze({ maxDistance: 0.6, }, }, + map: { + enabled: true, + tileUrl: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + }, oauth: { enabled: false, issuerUrl: '', @@ -108,6 +111,7 @@ export enum FeatureFlag { CLIP_ENCODE = 'clipEncode', FACIAL_RECOGNITION = 'facialRecognition', TAG_IMAGE = 'tagImage', + MAP = 'map', SIDECAR = 'sidecar', SEARCH = 'search', OAUTH = 'oauth', @@ -169,6 +173,7 @@ export class SystemConfigCore { [FeatureFlag.CLIP_ENCODE]: mlEnabled && config.machineLearning.clip.enabled, [FeatureFlag.FACIAL_RECOGNITION]: mlEnabled && config.machineLearning.facialRecognition.enabled, [FeatureFlag.TAG_IMAGE]: mlEnabled && config.machineLearning.classification.enabled, + [FeatureFlag.MAP]: config.map.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 7e28d041c..24d5914b0 100644 --- a/server/src/domain/system-config/system-config.service.spec.ts +++ b/server/src/domain/system-config/system-config.service.spec.ts @@ -73,6 +73,10 @@ const updatedConfig = Object.freeze({ maxDistance: 0.6, }, }, + map: { + enabled: true, + tileUrl: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + }, oauth: { autoLaunch: true, autoRegister: true, diff --git a/server/src/immich/controllers/server-info.controller.ts b/server/src/immich/controllers/server-info.controller.ts index 3b69c3532..b286329ab 100644 --- a/server/src/immich/controllers/server-info.controller.ts +++ b/server/src/immich/controllers/server-info.controller.ts @@ -1,4 +1,5 @@ import { + ServerConfigDto, ServerFeaturesDto, ServerInfoResponseDto, ServerInfoService, @@ -42,6 +43,12 @@ export class ServerInfoController { return this.service.getFeatures(); } + @PublicRoute() + @Get('config') + getServerConfig(): Promise { + return this.service.getConfig(); + } + @AdminRoute() @Get('stats') getStats(): Promise { diff --git a/server/src/infra/entities/system-config.entity.ts b/server/src/infra/entities/system-config.entity.ts index 2da905d10..ebcdcac07 100644 --- a/server/src/infra/entities/system-config.entity.ts +++ b/server/src/infra/entities/system-config.entity.ts @@ -58,6 +58,9 @@ export enum SystemConfigKey { MACHINE_LEARNING_FACIAL_RECOGNITION_MIN_SCORE = 'machineLearning.facialRecognition.minScore', MACHINE_LEARNING_FACIAL_RECOGNITION_MAX_DISTANCE = 'machineLearning.facialRecognition.maxDistance', + MAP_ENABLED = 'map.enabled', + MAP_TILE_URL = 'map.tileUrl', + OAUTH_ENABLED = 'oauth.enabled', OAUTH_ISSUER_URL = 'oauth.issuerUrl', OAUTH_CLIENT_ID = 'oauth.clientId', @@ -164,6 +167,10 @@ export interface SystemConfig { maxDistance: number; }; }; + map: { + enabled: boolean; + tileUrl: string; + }; oauth: { enabled: boolean; issuerUrl: string; diff --git a/server/test/e2e/server-info.e2e-spec.ts b/server/test/e2e/server-info.e2e-spec.ts index d04415dc6..2d344996d 100644 --- a/server/test/e2e/server-info.e2e-spec.ts +++ b/server/test/e2e/server-info.e2e-spec.ts @@ -83,6 +83,7 @@ describe(`${ServerInfoController.name} (e2e)`, () => { clipEncode: true, configFile: false, facialRecognition: true, + map: true, oauth: false, oauthAutoLaunch: false, passwordLogin: true, @@ -93,6 +94,18 @@ describe(`${ServerInfoController.name} (e2e)`, () => { }); }); + describe('GET /server-info/config', () => { + it('should respond with the server configuration', async () => { + const { status, body } = await request(server).get('/server-info/config'); + expect(status).toBe(200); + expect(body).toEqual({ + loginPageMessage: '', + oauthButtonText: 'Login with OAuth', + mapTileUrl: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + }); + }); + }); + describe('GET /server-info/stats', () => { it('should require authentication', async () => { const { status, body } = await request(server).get('/server-info/stats'); diff --git a/web/src/api/open-api/api.ts b/web/src/api/open-api/api.ts index 2b2a31b71..8aa65b66f 100644 --- a/web/src/api/open-api/api.ts +++ b/web/src/api/open-api/api.ts @@ -2343,6 +2343,31 @@ export interface SearchResponseDto { */ 'assets': SearchAssetResponseDto; } +/** + * + * @export + * @interface ServerConfigDto + */ +export interface ServerConfigDto { + /** + * + * @type {string} + * @memberof ServerConfigDto + */ + 'loginPageMessage': string; + /** + * + * @type {string} + * @memberof ServerConfigDto + */ + 'mapTileUrl': string; + /** + * + * @type {string} + * @memberof ServerConfigDto + */ + 'oauthButtonText': string; +} /** * * @export @@ -2367,6 +2392,12 @@ export interface ServerFeaturesDto { * @memberof ServerFeaturesDto */ 'facialRecognition': boolean; + /** + * + * @type {boolean} + * @memberof ServerFeaturesDto + */ + 'map': boolean; /** * * @type {boolean} @@ -2810,6 +2841,12 @@ export interface SystemConfigDto { * @memberof SystemConfigDto */ 'machineLearning': SystemConfigMachineLearningDto; + /** + * + * @type {SystemConfigMapDto} + * @memberof SystemConfigDto + */ + 'map': SystemConfigMapDto; /** * * @type {SystemConfigOAuthDto} @@ -3050,6 +3087,25 @@ export interface SystemConfigMachineLearningDto { */ 'url': string; } +/** + * + * @export + * @interface SystemConfigMapDto + */ +export interface SystemConfigMapDto { + /** + * + * @type {boolean} + * @memberof SystemConfigMapDto + */ + 'enabled': boolean; + /** + * + * @type {string} + * @memberof SystemConfigMapDto + */ + 'tileUrl': string; +} /** * * @export @@ -10825,6 +10881,35 @@ export class SearchApi extends BaseAPI { */ export const ServerInfoApiAxiosParamCreator = function (configuration?: Configuration) { return { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getServerConfig: async (options: AxiosRequestConfig = {}): Promise => { + const localVarPath = `/server-info/config`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * * @param {*} [options] Override http request option. @@ -11027,6 +11112,15 @@ export const ServerInfoApiAxiosParamCreator = function (configuration?: Configur export const ServerInfoApiFp = function(configuration?: Configuration) { const localVarAxiosParamCreator = ServerInfoApiAxiosParamCreator(configuration) return { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getServerConfig(options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getServerConfig(options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @param {*} [options] Override http request option. @@ -11091,6 +11185,14 @@ export const ServerInfoApiFp = function(configuration?: Configuration) { export const ServerInfoApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { const localVarFp = ServerInfoApiFp(configuration) return { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getServerConfig(options?: AxiosRequestConfig): AxiosPromise { + return localVarFp.getServerConfig(options).then((request) => request(axios, basePath)); + }, /** * * @param {*} [options] Override http request option. @@ -11149,6 +11251,16 @@ export const ServerInfoApiFactory = function (configuration?: Configuration, bas * @extends {BaseAPI} */ export class ServerInfoApi extends BaseAPI { + /** + * + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ServerInfoApi + */ + public getServerConfig(options?: AxiosRequestConfig) { + return ServerInfoApiFp(this.configuration).getServerConfig(options).then((request) => request(this.axios, this.basePath)); + } + /** * * @param {*} [options] Override http request option. diff --git a/web/src/lib/components/admin-page/jobs/jobs-panel.svelte b/web/src/lib/components/admin-page/jobs/jobs-panel.svelte index 441210fc2..38230afd2 100644 --- a/web/src/lib/components/admin-page/jobs/jobs-panel.svelte +++ b/web/src/lib/components/admin-page/jobs/jobs-panel.svelte @@ -4,7 +4,7 @@ NotificationType, } from '$lib/components/shared-components/notification/notification'; import { AppRoute } from '$lib/constants'; - import { featureFlags } from '$lib/stores/feature-flags.store'; + import { featureFlags } from '$lib/stores/server-config.store'; import { handleError } from '$lib/utils/handle-error'; import { AllJobStatusResponseDto, api, JobCommand, JobCommandDto, JobName } from '@api'; import type { ComponentType } from 'svelte'; 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 new file mode 100644 index 000000000..dff3c65a3 --- /dev/null +++ b/web/src/lib/components/admin-page/settings/map-settings/map-settings.svelte @@ -0,0 +1,98 @@ + + +
+ {#await getConfigs() then} +
+
+
+ + +
+ + + + +
+
+
+ {/await} +
diff --git a/web/src/lib/components/asset-viewer/detail-panel.svelte b/web/src/lib/components/asset-viewer/detail-panel.svelte index 53bff125f..cea013424 100644 --- a/web/src/lib/components/asset-viewer/detail-panel.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel.svelte @@ -1,18 +1,19 @@ diff --git a/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte b/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte index 2a71f5e82..c34183bcb 100644 --- a/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte +++ b/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte @@ -16,7 +16,7 @@ import IconButton from '$lib/components/elements/buttons/icon-button.svelte'; import Cog from 'svelte-material-icons/Cog.svelte'; import UserAvatar from '../user-avatar.svelte'; - import { featureFlags } from '$lib/stores/feature-flags.store'; + import { featureFlags } from '$lib/stores/server-config.store'; export let user: UserResponseDto; export let showUploadButton = true; diff --git a/web/src/lib/components/shared-components/side-bar/side-bar.svelte b/web/src/lib/components/shared-components/side-bar/side-bar.svelte index 770bbfa23..c6ac3b13a 100644 --- a/web/src/lib/components/shared-components/side-bar/side-bar.svelte +++ b/web/src/lib/components/shared-components/side-bar/side-bar.svelte @@ -17,7 +17,7 @@ import SideBarButton from './side-bar-button.svelte'; import { locale } from '$lib/stores/preferences.store'; import SideBarSection from './side-bar-section.svelte'; - import { featureFlags } from '$lib/stores/feature-flags.store'; + import { featureFlags } from '$lib/stores/server-config.store'; const getStats = async (dto: AssetApiGetAssetStatsRequest) => { const { data: stats } = await api.assetApi.getAssetStats(dto); @@ -62,9 +62,11 @@ {/if} - - - + {#if $featureFlags.map} + + + + {/if} import { goto } from '$app/navigation'; - import { featureFlags } from '$lib/stores/feature-flags.store'; + import { featureFlags } from '$lib/stores/server-config.store'; import { oauth, UserResponseDto } from '@api'; import { onMount } from 'svelte'; import { fade } from 'svelte/transition'; diff --git a/web/src/lib/components/user-settings-page/user-settings-list.svelte b/web/src/lib/components/user-settings-page/user-settings-list.svelte index a30539c29..0aa9a6df8 100644 --- a/web/src/lib/components/user-settings-page/user-settings-list.svelte +++ b/web/src/lib/components/user-settings-page/user-settings-list.svelte @@ -1,7 +1,7 @@ - -
- {#if leaflet} - {@const { Map, TileLayer, AssetMarkerCluster, Control } = leaflet} - - +
+ {#if leaflet} + {@const { Map, TileLayer, AssetMarkerCluster, Control } = leaflet} + OpenStreetMap', + maxBounds: [ + [-90, -180], + [90, 180], + ], + minZoom: 2, }} - /> - onViewAssets(detail.assetIds, detail.activeAssetIndex)} - /> - - - - - {/if} -
- + > + OpenStreetMap', + }} + /> + onViewAssets(detail.assetIds, detail.activeAssetIndex)} + /> + + + + + {/if} +
+ - - {#if $showAssetViewer} - 1} - on:next={navigateNext} - on:previous={navigatePrevious} - on:close={() => assetViewingStore.showAssetViewer(false)} + + {#if $showAssetViewer} + 1} + on:next={navigateNext} + on:previous={navigatePrevious} + on:close={() => assetViewingStore.showAssetViewer(false)} + /> + {/if} + + + {#if showSettingsModal} + (showSettingsModal = false)} + on:save={async ({ detail }) => { + const shouldUpdate = !isEqual(omit(detail, 'allowDarkMode'), omit($mapSettings, 'allowDarkMode')); + showSettingsModal = false; + $mapSettings = detail; + + if (shouldUpdate) { + mapMarkers = await loadMapMarkers(); + } + }} /> {/if} - - -{#if showSettingsModal} - (showSettingsModal = false)} - on:save={async ({ detail }) => { - const shouldUpdate = !isEqual(omit(detail, 'allowDarkMode'), omit($mapSettings, 'allowDarkMode')); - showSettingsModal = false; - $mapSettings = detail; - - if (shouldUpdate) { - mapMarkers = await loadMapMarkers(); - } - }} - /> {/if} diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index 519cdd786..9ed7bf282 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -14,7 +14,7 @@ import AppleHeader from '$lib/components/shared-components/apple-header.svelte'; import FaviconHeader from '$lib/components/shared-components/favicon-header.svelte'; import { onMount } from 'svelte'; - import { loadFeatureFlags } from '$lib/stores/feature-flags.store'; + import { loadConfig } from '$lib/stores/server-config.store'; import { handleError } from '$lib/utils/handle-error'; import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store'; import { api } from '@api'; @@ -37,9 +37,9 @@ onMount(async () => { try { - await loadFeatureFlags(); + await loadConfig(); } catch (error) { - handleError(error, 'Unable to load feature flags'); + handleError(error, 'Unable to connect to server'); } }); diff --git a/web/src/routes/admin/system-settings/+page.svelte b/web/src/routes/admin/system-settings/+page.svelte index e7626148e..fe8a78d55 100644 --- a/web/src/routes/admin/system-settings/+page.svelte +++ b/web/src/routes/admin/system-settings/+page.svelte @@ -3,6 +3,7 @@ import FFmpegSettings from '$lib/components/admin-page/settings/ffmpeg/ffmpeg-settings.svelte'; import JobSettings from '$lib/components/admin-page/settings/job-settings/job-settings.svelte'; import MachineLearningSettings from '$lib/components/admin-page/settings/machine-learning-settings/machine-learning-settings.svelte'; + import MapSettings from '$lib/components/admin-page/settings/map-settings/map-settings.svelte'; import OAuthSettings from '$lib/components/admin-page/settings/oauth/oauth-settings.svelte'; import PasswordLoginSettings from '$lib/components/admin-page/settings/password-login/password-login-settings.svelte'; import SettingAccordion from '$lib/components/admin-page/settings/setting-accordion.svelte'; @@ -11,7 +12,7 @@ import Button from '$lib/components/elements/buttons/button.svelte'; import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte'; import { downloadManager } from '$lib/stores/download'; - import { featureFlags } from '$lib/stores/feature-flags.store'; + import { featureFlags } from '$lib/stores/server-config.store'; import { downloadBlob } from '$lib/utils/asset-utils'; import { SystemConfigDto, api, copyToClipboard } from '@api'; import Alert from 'svelte-material-icons/Alert.svelte'; @@ -57,20 +58,6 @@ Export as JSON - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + {/await} diff --git a/web/src/routes/auth/login/+page.svelte b/web/src/routes/auth/login/+page.svelte index c3e4e8a41..4b11481f6 100644 --- a/web/src/routes/auth/login/+page.svelte +++ b/web/src/routes/auth/login/+page.svelte @@ -3,18 +3,17 @@ import LoginForm from '$lib/components/forms/login-form.svelte'; import FullscreenContainer from '$lib/components/shared-components/fullscreen-container.svelte'; import { AppRoute } from '$lib/constants'; - import { loginPageMessage } from '$lib/constants'; - import { featureFlags } from '$lib/stores/feature-flags.store'; + import { featureFlags, serverConfig } from '$lib/stores/server-config.store'; import type { PageData } from './$types'; export let data: PageData; {#if $featureFlags.loaded} - +

- {@html loginPageMessage} + {@html $serverConfig.loginPageMessage}