1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-03-01 15:11:21 +01:00

refactor: deprecate /server-info and replace with /server-info/storage (#9645)

This commit is contained in:
Zack Pollard 2024-05-22 10:25:55 +01:00 committed by GitHub
parent a341ab0050
commit a3e7e8cc31
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 265 additions and 99 deletions

View file

@ -32,7 +32,7 @@ class ServerDiskInfo {
return 'ServerDiskInfo(diskAvailable: $diskAvailable, diskSize: $diskSize, diskUse: $diskUse, diskUsagePercentage: $diskUsagePercentage)'; return 'ServerDiskInfo(diskAvailable: $diskAvailable, diskSize: $diskSize, diskUse: $diskUse, diskUsagePercentage: $diskUsagePercentage)';
} }
ServerDiskInfo.fromDto(ServerInfoResponseDto dto) ServerDiskInfo.fromDto(ServerStorageResponseDto dto)
: diskAvailable = dto.diskAvailable, : diskAvailable = dto.diskAvailable,
diskSize = dto.diskSize, diskSize = dto.diskSize,
diskUse = dto.diskUse, diskUse = dto.diskUse,

View file

@ -374,7 +374,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
if (state.backupProgress != BackUpProgressEnum.inBackground) { if (state.backupProgress != BackUpProgressEnum.inBackground) {
await _getBackupAlbumsInfo(); await _getBackupAlbumsInfo();
await updateServerInfo(); await updateDiskInfo();
await _updateBackupAssetCount(); await _updateBackupAssetCount();
} else { } else {
log.warning("cannot get backup info - background backup is in progress!"); log.warning("cannot get backup info - background backup is in progress!");
@ -542,7 +542,7 @@ class BackupNotifier extends StateNotifier<BackUpState> {
_updatePersistentAlbumsSelection(); _updatePersistentAlbumsSelection();
} }
updateServerInfo(); updateDiskInfo();
} }
void _onUploadProgress(int sent, int total) { void _onUploadProgress(int sent, int total) {
@ -579,13 +579,13 @@ class BackupNotifier extends StateNotifier<BackUpState> {
); );
} }
Future<void> updateServerInfo() async { Future<void> updateDiskInfo() async {
final serverInfo = await _serverInfoService.getServerInfo(); final diskInfo = await _serverInfoService.getDiskInfo();
// Update server info // Update server info
if (serverInfo != null) { if (diskInfo != null) {
state = state.copyWith( state = state.copyWith(
serverInfo: serverInfo, serverInfo: diskInfo,
); );
} }
} }

View file

@ -121,7 +121,7 @@ class ManualUploadNotifier extends StateNotifier<ManualUploadState> {
bool isDuplicated, bool isDuplicated,
) { ) {
state = state.copyWith(successfulUploads: state.successfulUploads + 1); state = state.copyWith(successfulUploads: state.successfulUploads + 1);
_backupProvider.updateServerInfo(); _backupProvider.updateDiskInfo();
} }
void _onAssetUploadError(ErrorUploadAsset errorAssetInfo) { void _onAssetUploadError(ErrorUploadAsset errorAssetInfo) {

View file

@ -18,14 +18,14 @@ class ServerInfoService {
ServerInfoService(this._apiService); ServerInfoService(this._apiService);
Future<ServerDiskInfo?> getServerInfo() async { Future<ServerDiskInfo?> getDiskInfo() async {
try { try {
final dto = await _apiService.serverInfoApi.getServerInfo(); final dto = await _apiService.serverInfoApi.getStorage();
if (dto != null) { if (dto != null) {
return ServerDiskInfo.fromDto(dto); return ServerDiskInfo.fromDto(dto);
} }
} catch (e) { } catch (e) {
debugPrint("Error [getServerInfo] ${e.toString()}"); debugPrint("Error [getDiskInfo] ${e.toString()}");
} }
return null; return null;
} }

View file

@ -31,7 +31,7 @@ class ImmichAppBarDialog extends HookConsumerWidget {
useEffect( useEffect(
() { () {
ref.read(backupProvider.notifier).updateServerInfo(); ref.read(backupProvider.notifier).updateDiskInfo();
ref.read(currentUserProvider.notifier).refresh(); ref.read(currentUserProvider.notifier).refresh();
return null; return null;
}, },

View file

@ -116,6 +116,7 @@ Class | Method | HTTP request | Description
*AuthenticationApi* | [**logout**](doc//AuthenticationApi.md#logout) | **POST** /auth/logout | *AuthenticationApi* | [**logout**](doc//AuthenticationApi.md#logout) | **POST** /auth/logout |
*AuthenticationApi* | [**signUpAdmin**](doc//AuthenticationApi.md#signupadmin) | **POST** /auth/admin-sign-up | *AuthenticationApi* | [**signUpAdmin**](doc//AuthenticationApi.md#signupadmin) | **POST** /auth/admin-sign-up |
*AuthenticationApi* | [**validateAccessToken**](doc//AuthenticationApi.md#validateaccesstoken) | **POST** /auth/validateToken | *AuthenticationApi* | [**validateAccessToken**](doc//AuthenticationApi.md#validateaccesstoken) | **POST** /auth/validateToken |
*DeprecatedApi* | [**getServerInfo**](doc//DeprecatedApi.md#getserverinfo) | **GET** /server-info |
*DownloadApi* | [**downloadArchive**](doc//DownloadApi.md#downloadarchive) | **POST** /download/archive | *DownloadApi* | [**downloadArchive**](doc//DownloadApi.md#downloadarchive) | **POST** /download/archive |
*DownloadApi* | [**downloadFile**](doc//DownloadApi.md#downloadfile) | **POST** /download/asset/{id} | *DownloadApi* | [**downloadFile**](doc//DownloadApi.md#downloadfile) | **POST** /download/asset/{id} |
*DownloadApi* | [**getDownloadInfo**](doc//DownloadApi.md#getdownloadinfo) | **POST** /download/info | *DownloadApi* | [**getDownloadInfo**](doc//DownloadApi.md#getdownloadinfo) | **POST** /download/info |
@ -174,6 +175,7 @@ Class | Method | HTTP request | Description
*ServerInfoApi* | [**getServerInfo**](doc//ServerInfoApi.md#getserverinfo) | **GET** /server-info | *ServerInfoApi* | [**getServerInfo**](doc//ServerInfoApi.md#getserverinfo) | **GET** /server-info |
*ServerInfoApi* | [**getServerStatistics**](doc//ServerInfoApi.md#getserverstatistics) | **GET** /server-info/statistics | *ServerInfoApi* | [**getServerStatistics**](doc//ServerInfoApi.md#getserverstatistics) | **GET** /server-info/statistics |
*ServerInfoApi* | [**getServerVersion**](doc//ServerInfoApi.md#getserverversion) | **GET** /server-info/version | *ServerInfoApi* | [**getServerVersion**](doc//ServerInfoApi.md#getserverversion) | **GET** /server-info/version |
*ServerInfoApi* | [**getStorage**](doc//ServerInfoApi.md#getstorage) | **GET** /server-info/storage |
*ServerInfoApi* | [**getSupportedMediaTypes**](doc//ServerInfoApi.md#getsupportedmediatypes) | **GET** /server-info/media-types | *ServerInfoApi* | [**getSupportedMediaTypes**](doc//ServerInfoApi.md#getsupportedmediatypes) | **GET** /server-info/media-types |
*ServerInfoApi* | [**getTheme**](doc//ServerInfoApi.md#gettheme) | **GET** /server-info/theme | *ServerInfoApi* | [**getTheme**](doc//ServerInfoApi.md#gettheme) | **GET** /server-info/theme |
*ServerInfoApi* | [**pingServer**](doc//ServerInfoApi.md#pingserver) | **GET** /server-info/ping | *ServerInfoApi* | [**pingServer**](doc//ServerInfoApi.md#pingserver) | **GET** /server-info/ping |
@ -348,10 +350,10 @@ Class | Method | HTTP request | Description
- [SearchSuggestionType](doc//SearchSuggestionType.md) - [SearchSuggestionType](doc//SearchSuggestionType.md)
- [ServerConfigDto](doc//ServerConfigDto.md) - [ServerConfigDto](doc//ServerConfigDto.md)
- [ServerFeaturesDto](doc//ServerFeaturesDto.md) - [ServerFeaturesDto](doc//ServerFeaturesDto.md)
- [ServerInfoResponseDto](doc//ServerInfoResponseDto.md)
- [ServerMediaTypesResponseDto](doc//ServerMediaTypesResponseDto.md) - [ServerMediaTypesResponseDto](doc//ServerMediaTypesResponseDto.md)
- [ServerPingResponse](doc//ServerPingResponse.md) - [ServerPingResponse](doc//ServerPingResponse.md)
- [ServerStatsResponseDto](doc//ServerStatsResponseDto.md) - [ServerStatsResponseDto](doc//ServerStatsResponseDto.md)
- [ServerStorageResponseDto](doc//ServerStorageResponseDto.md)
- [ServerThemeDto](doc//ServerThemeDto.md) - [ServerThemeDto](doc//ServerThemeDto.md)
- [ServerVersionResponseDto](doc//ServerVersionResponseDto.md) - [ServerVersionResponseDto](doc//ServerVersionResponseDto.md)
- [SessionResponseDto](doc//SessionResponseDto.md) - [SessionResponseDto](doc//SessionResponseDto.md)

View file

@ -35,6 +35,7 @@ part 'api/album_api.dart';
part 'api/asset_api.dart'; part 'api/asset_api.dart';
part 'api/audit_api.dart'; part 'api/audit_api.dart';
part 'api/authentication_api.dart'; part 'api/authentication_api.dart';
part 'api/deprecated_api.dart';
part 'api/download_api.dart'; part 'api/download_api.dart';
part 'api/duplicate_api.dart'; part 'api/duplicate_api.dart';
part 'api/face_api.dart'; part 'api/face_api.dart';
@ -180,10 +181,10 @@ part 'model/search_response_dto.dart';
part 'model/search_suggestion_type.dart'; part 'model/search_suggestion_type.dart';
part 'model/server_config_dto.dart'; part 'model/server_config_dto.dart';
part 'model/server_features_dto.dart'; part 'model/server_features_dto.dart';
part 'model/server_info_response_dto.dart';
part 'model/server_media_types_response_dto.dart'; part 'model/server_media_types_response_dto.dart';
part 'model/server_ping_response.dart'; part 'model/server_ping_response.dart';
part 'model/server_stats_response_dto.dart'; part 'model/server_stats_response_dto.dart';
part 'model/server_storage_response_dto.dart';
part 'model/server_theme_dto.dart'; part 'model/server_theme_dto.dart';
part 'model/server_version_response_dto.dart'; part 'model/server_version_response_dto.dart';
part 'model/session_response_dto.dart'; part 'model/session_response_dto.dart';

View file

@ -0,0 +1,62 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.18
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class DeprecatedApi {
DeprecatedApi([ApiClient? apiClient]) : apiClient = apiClient ?? defaultApiClient;
final ApiClient apiClient;
/// This property was deprecated in v1.106.0
///
/// Note: This method returns the HTTP [Response].
Future<Response> getServerInfoWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/server-info';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
/// This property was deprecated in v1.106.0
Future<ServerStorageResponseDto?> getServerInfo() async {
final response = await getServerInfoWithHttpInfo();
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), 'ServerStorageResponseDto',) as ServerStorageResponseDto;
}
return null;
}
}

View file

@ -98,7 +98,9 @@ class ServerInfoApi {
return null; return null;
} }
/// Performs an HTTP 'GET /server-info' operation and returns the [Response]. /// This property was deprecated in v1.106.0
///
/// Note: This method returns the HTTP [Response].
Future<Response> getServerInfoWithHttpInfo() async { Future<Response> getServerInfoWithHttpInfo() async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations
final path = r'/server-info'; final path = r'/server-info';
@ -124,7 +126,8 @@ class ServerInfoApi {
); );
} }
Future<ServerInfoResponseDto?> getServerInfo() async { /// This property was deprecated in v1.106.0
Future<ServerStorageResponseDto?> getServerInfo() async {
final response = await getServerInfoWithHttpInfo(); final response = await getServerInfoWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) { if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response)); throw ApiException(response.statusCode, await _decodeBodyBytes(response));
@ -133,7 +136,7 @@ class ServerInfoApi {
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input" // At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string. // FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) { if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ServerInfoResponseDto',) as ServerInfoResponseDto; return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'ServerStorageResponseDto',) as ServerStorageResponseDto;
} }
return null; return null;
@ -221,6 +224,47 @@ class ServerInfoApi {
return null; return null;
} }
/// Performs an HTTP 'GET /server-info/storage' operation and returns the [Response].
Future<Response> getStorageWithHttpInfo() async {
// ignore: prefer_const_declarations
final path = r'/server-info/storage';
// ignore: prefer_final_locals
Object? postBody;
final queryParams = <QueryParam>[];
final headerParams = <String, String>{};
final formParams = <String, String>{};
const contentTypes = <String>[];
return apiClient.invokeAPI(
path,
'GET',
queryParams,
postBody,
headerParams,
formParams,
contentTypes.isEmpty ? null : contentTypes.first,
);
}
Future<ServerStorageResponseDto?> getStorage() async {
final response = await getStorageWithHttpInfo();
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), 'ServerStorageResponseDto',) as ServerStorageResponseDto;
}
return null;
}
/// Performs an HTTP 'GET /server-info/media-types' operation and returns the [Response]. /// Performs an HTTP 'GET /server-info/media-types' operation and returns the [Response].
Future<Response> getSupportedMediaTypesWithHttpInfo() async { Future<Response> getSupportedMediaTypesWithHttpInfo() async {
// ignore: prefer_const_declarations // ignore: prefer_const_declarations

View file

@ -428,14 +428,14 @@ class ApiClient {
return ServerConfigDto.fromJson(value); return ServerConfigDto.fromJson(value);
case 'ServerFeaturesDto': case 'ServerFeaturesDto':
return ServerFeaturesDto.fromJson(value); return ServerFeaturesDto.fromJson(value);
case 'ServerInfoResponseDto':
return ServerInfoResponseDto.fromJson(value);
case 'ServerMediaTypesResponseDto': case 'ServerMediaTypesResponseDto':
return ServerMediaTypesResponseDto.fromJson(value); return ServerMediaTypesResponseDto.fromJson(value);
case 'ServerPingResponse': case 'ServerPingResponse':
return ServerPingResponse.fromJson(value); return ServerPingResponse.fromJson(value);
case 'ServerStatsResponseDto': case 'ServerStatsResponseDto':
return ServerStatsResponseDto.fromJson(value); return ServerStatsResponseDto.fromJson(value);
case 'ServerStorageResponseDto':
return ServerStorageResponseDto.fromJson(value);
case 'ServerThemeDto': case 'ServerThemeDto':
return ServerThemeDto.fromJson(value); return ServerThemeDto.fromJson(value);
case 'ServerVersionResponseDto': case 'ServerVersionResponseDto':

View file

@ -10,9 +10,9 @@
part of openapi.api; part of openapi.api;
class ServerInfoResponseDto { class ServerStorageResponseDto {
/// Returns a new [ServerInfoResponseDto] instance. /// Returns a new [ServerStorageResponseDto] instance.
ServerInfoResponseDto({ ServerStorageResponseDto({
required this.diskAvailable, required this.diskAvailable,
required this.diskAvailableRaw, required this.diskAvailableRaw,
required this.diskSize, required this.diskSize,
@ -37,7 +37,7 @@ class ServerInfoResponseDto {
int diskUseRaw; int diskUseRaw;
@override @override
bool operator ==(Object other) => identical(this, other) || other is ServerInfoResponseDto && bool operator ==(Object other) => identical(this, other) || other is ServerStorageResponseDto &&
other.diskAvailable == diskAvailable && other.diskAvailable == diskAvailable &&
other.diskAvailableRaw == diskAvailableRaw && other.diskAvailableRaw == diskAvailableRaw &&
other.diskSize == diskSize && other.diskSize == diskSize &&
@ -58,7 +58,7 @@ class ServerInfoResponseDto {
(diskUseRaw.hashCode); (diskUseRaw.hashCode);
@override @override
String toString() => 'ServerInfoResponseDto[diskAvailable=$diskAvailable, diskAvailableRaw=$diskAvailableRaw, diskSize=$diskSize, diskSizeRaw=$diskSizeRaw, diskUsagePercentage=$diskUsagePercentage, diskUse=$diskUse, diskUseRaw=$diskUseRaw]'; String toString() => 'ServerStorageResponseDto[diskAvailable=$diskAvailable, diskAvailableRaw=$diskAvailableRaw, diskSize=$diskSize, diskSizeRaw=$diskSizeRaw, diskUsagePercentage=$diskUsagePercentage, diskUse=$diskUse, diskUseRaw=$diskUseRaw]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final json = <String, dynamic>{}; final json = <String, dynamic>{};
@ -72,14 +72,14 @@ class ServerInfoResponseDto {
return json; return json;
} }
/// Returns a new [ServerInfoResponseDto] instance and imports its values from /// Returns a new [ServerStorageResponseDto] instance and imports its values from
/// [value] if it's a [Map], null otherwise. /// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods // ignore: prefer_constructors_over_static_methods
static ServerInfoResponseDto? fromJson(dynamic value) { static ServerStorageResponseDto? fromJson(dynamic value) {
if (value is Map) { if (value is Map) {
final json = value.cast<String, dynamic>(); final json = value.cast<String, dynamic>();
return ServerInfoResponseDto( return ServerStorageResponseDto(
diskAvailable: mapValueOfType<String>(json, r'diskAvailable')!, diskAvailable: mapValueOfType<String>(json, r'diskAvailable')!,
diskAvailableRaw: mapValueOfType<int>(json, r'diskAvailableRaw')!, diskAvailableRaw: mapValueOfType<int>(json, r'diskAvailableRaw')!,
diskSize: mapValueOfType<String>(json, r'diskSize')!, diskSize: mapValueOfType<String>(json, r'diskSize')!,
@ -92,11 +92,11 @@ class ServerInfoResponseDto {
return null; return null;
} }
static List<ServerInfoResponseDto> listFromJson(dynamic json, {bool growable = false,}) { static List<ServerStorageResponseDto> listFromJson(dynamic json, {bool growable = false,}) {
final result = <ServerInfoResponseDto>[]; final result = <ServerStorageResponseDto>[];
if (json is List && json.isNotEmpty) { if (json is List && json.isNotEmpty) {
for (final row in json) { for (final row in json) {
final value = ServerInfoResponseDto.fromJson(row); final value = ServerStorageResponseDto.fromJson(row);
if (value != null) { if (value != null) {
result.add(value); result.add(value);
} }
@ -105,12 +105,12 @@ class ServerInfoResponseDto {
return result.toList(growable: growable); return result.toList(growable: growable);
} }
static Map<String, ServerInfoResponseDto> mapFromJson(dynamic json) { static Map<String, ServerStorageResponseDto> mapFromJson(dynamic json) {
final map = <String, ServerInfoResponseDto>{}; final map = <String, ServerStorageResponseDto>{};
if (json is Map && json.isNotEmpty) { if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) { for (final entry in json.entries) {
final value = ServerInfoResponseDto.fromJson(entry.value); final value = ServerStorageResponseDto.fromJson(entry.value);
if (value != null) { if (value != null) {
map[entry.key] = value; map[entry.key] = value;
} }
@ -119,14 +119,14 @@ class ServerInfoResponseDto {
return map; return map;
} }
// maps a json object with a list of ServerInfoResponseDto-objects as value to a dart map // maps a json object with a list of ServerStorageResponseDto-objects as value to a dart map
static Map<String, List<ServerInfoResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) { static Map<String, List<ServerStorageResponseDto>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<ServerInfoResponseDto>>{}; final map = <String, List<ServerStorageResponseDto>>{};
if (json is Map && json.isNotEmpty) { if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments // ignore: parameter_assignments
json = json.cast<String, dynamic>(); json = json.cast<String, dynamic>();
for (final entry in json.entries) { for (final entry in json.entries) {
map[entry.key] = ServerInfoResponseDto.listFromJson(entry.value, growable: growable,); map[entry.key] = ServerStorageResponseDto.listFromJson(entry.value, growable: growable,);
} }
} }
return map; return map;

View file

@ -4337,6 +4337,8 @@
}, },
"/server-info": { "/server-info": {
"get": { "get": {
"deprecated": true,
"description": "This property was deprecated in v1.106.0",
"operationId": "getServerInfo", "operationId": "getServerInfo",
"parameters": [], "parameters": [],
"responses": { "responses": {
@ -4344,7 +4346,7 @@
"content": { "content": {
"application/json": { "application/json": {
"schema": { "schema": {
"$ref": "#/components/schemas/ServerInfoResponseDto" "$ref": "#/components/schemas/ServerStorageResponseDto"
} }
} }
}, },
@ -4363,8 +4365,12 @@
} }
], ],
"tags": [ "tags": [
"Server Info" "Server Info",
] "Deprecated"
],
"x-immich-lifecycle": {
"deprecatedAt": "v1.106.0"
}
} }
}, },
"/server-info/config": { "/server-info/config": {
@ -4483,6 +4489,38 @@
] ]
} }
}, },
"/server-info/storage": {
"get": {
"operationId": "getStorage",
"parameters": [],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ServerStorageResponseDto"
}
}
},
"description": ""
}
},
"security": [
{
"bearer": []
},
{
"cookie": []
},
{
"api_key": []
}
],
"tags": [
"Server Info"
]
}
},
"/server-info/theme": { "/server-info/theme": {
"get": { "get": {
"operationId": "getTheme", "operationId": "getTheme",
@ -9487,45 +9525,6 @@
], ],
"type": "object" "type": "object"
}, },
"ServerInfoResponseDto": {
"properties": {
"diskAvailable": {
"type": "string"
},
"diskAvailableRaw": {
"format": "int64",
"type": "integer"
},
"diskSize": {
"type": "string"
},
"diskSizeRaw": {
"format": "int64",
"type": "integer"
},
"diskUsagePercentage": {
"format": "float",
"type": "number"
},
"diskUse": {
"type": "string"
},
"diskUseRaw": {
"format": "int64",
"type": "integer"
}
},
"required": [
"diskAvailable",
"diskAvailableRaw",
"diskSize",
"diskSizeRaw",
"diskUsagePercentage",
"diskUse",
"diskUseRaw"
],
"type": "object"
},
"ServerMediaTypesResponseDto": { "ServerMediaTypesResponseDto": {
"properties": { "properties": {
"image": { "image": {
@ -9606,6 +9605,45 @@
], ],
"type": "object" "type": "object"
}, },
"ServerStorageResponseDto": {
"properties": {
"diskAvailable": {
"type": "string"
},
"diskAvailableRaw": {
"format": "int64",
"type": "integer"
},
"diskSize": {
"type": "string"
},
"diskSizeRaw": {
"format": "int64",
"type": "integer"
},
"diskUsagePercentage": {
"format": "float",
"type": "number"
},
"diskUse": {
"type": "string"
},
"diskUseRaw": {
"format": "int64",
"type": "integer"
}
},
"required": [
"diskAvailable",
"diskAvailableRaw",
"diskSize",
"diskSizeRaw",
"diskUsagePercentage",
"diskUse",
"diskUseRaw"
],
"type": "object"
},
"ServerThemeDto": { "ServerThemeDto": {
"properties": { "properties": {
"customCss": { "customCss": {

View file

@ -732,7 +732,7 @@ export type SmartSearchDto = {
withDeleted?: boolean; withDeleted?: boolean;
withExif?: boolean; withExif?: boolean;
}; };
export type ServerInfoResponseDto = { export type ServerStorageResponseDto = {
diskAvailable: string; diskAvailable: string;
diskAvailableRaw: number; diskAvailableRaw: number;
diskSize: string; diskSize: string;
@ -2245,10 +2245,13 @@ export function getSearchSuggestions({ country, make, model, state, $type }: {
...opts ...opts
})); }));
} }
/**
* This property was deprecated in v1.106.0
*/
export function getServerInfo(opts?: Oazapfts.RequestOpts) { export function getServerInfo(opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{ return oazapfts.ok(oazapfts.fetchJson<{
status: 200; status: 200;
data: ServerInfoResponseDto; data: ServerStorageResponseDto;
}>("/server-info", { }>("/server-info", {
...opts ...opts
})); }));
@ -2293,6 +2296,14 @@ export function getServerStatistics(opts?: Oazapfts.RequestOpts) {
...opts ...opts
})); }));
} }
export function getStorage(opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: ServerStorageResponseDto;
}>("/server-info/storage", {
...opts
}));
}
export function getTheme(opts?: Oazapfts.RequestOpts) { export function getTheme(opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{ return oazapfts.ok(oazapfts.fetchJson<{
status: 200; status: 200;

View file

@ -1,12 +1,13 @@
import { Controller, Get } from '@nestjs/common'; import { Controller, Get } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger'; import { ApiTags } from '@nestjs/swagger';
import { EndpointLifecycle } from 'src/decorators';
import { import {
ServerConfigDto, ServerConfigDto,
ServerFeaturesDto, ServerFeaturesDto,
ServerInfoResponseDto,
ServerMediaTypesResponseDto, ServerMediaTypesResponseDto,
ServerPingResponse, ServerPingResponse,
ServerStatsResponseDto, ServerStatsResponseDto,
ServerStorageResponseDto,
ServerThemeDto, ServerThemeDto,
ServerVersionResponseDto, ServerVersionResponseDto,
} from 'src/dtos/server-info.dto'; } from 'src/dtos/server-info.dto';
@ -23,9 +24,16 @@ export class ServerInfoController {
) {} ) {}
@Get() @Get()
@EndpointLifecycle({ deprecatedAt: 'v1.106.0' })
@Authenticated() @Authenticated()
getServerInfo(): Promise<ServerInfoResponseDto> { getServerInfo(): Promise<ServerStorageResponseDto> {
return this.service.getInfo(); return this.service.getStorage();
}
@Get('storage')
@Authenticated()
getStorage(): Promise<ServerStorageResponseDto> {
return this.service.getStorage();
} }
@Get('ping') @Get('ping')

View file

@ -7,7 +7,7 @@ export class ServerPingResponse {
res!: string; res!: string;
} }
export class ServerInfoResponseDto { export class ServerStorageResponseDto {
diskSize!: string; diskSize!: string;
diskUse!: string; diskUse!: string;
diskAvailable!: string; diskAvailable!: string;

View file

@ -29,11 +29,11 @@ describe(ServerInfoService.name, () => {
expect(sut).toBeDefined(); expect(sut).toBeDefined();
}); });
describe('getInfo', () => { describe('getStorage', () => {
it('should return the disk space as B', async () => { it('should return the disk space as B', async () => {
storageMock.checkDiskUsage.mockResolvedValue({ free: 200, available: 300, total: 500 }); storageMock.checkDiskUsage.mockResolvedValue({ free: 200, available: 300, total: 500 });
await expect(sut.getInfo()).resolves.toEqual({ await expect(sut.getStorage()).resolves.toEqual({
diskAvailable: '300 B', diskAvailable: '300 B',
diskAvailableRaw: 300, diskAvailableRaw: 300,
diskSize: '500 B', diskSize: '500 B',
@ -49,7 +49,7 @@ describe(ServerInfoService.name, () => {
it('should return the disk space as KiB', async () => { it('should return the disk space as KiB', async () => {
storageMock.checkDiskUsage.mockResolvedValue({ free: 200_000, available: 300_000, total: 500_000 }); storageMock.checkDiskUsage.mockResolvedValue({ free: 200_000, available: 300_000, total: 500_000 });
await expect(sut.getInfo()).resolves.toEqual({ await expect(sut.getStorage()).resolves.toEqual({
diskAvailable: '293.0 KiB', diskAvailable: '293.0 KiB',
diskAvailableRaw: 300_000, diskAvailableRaw: 300_000,
diskSize: '488.3 KiB', diskSize: '488.3 KiB',
@ -65,7 +65,7 @@ describe(ServerInfoService.name, () => {
it('should return the disk space as MiB', async () => { it('should return the disk space as MiB', async () => {
storageMock.checkDiskUsage.mockResolvedValue({ free: 200_000_000, available: 300_000_000, total: 500_000_000 }); storageMock.checkDiskUsage.mockResolvedValue({ free: 200_000_000, available: 300_000_000, total: 500_000_000 });
await expect(sut.getInfo()).resolves.toEqual({ await expect(sut.getStorage()).resolves.toEqual({
diskAvailable: '286.1 MiB', diskAvailable: '286.1 MiB',
diskAvailableRaw: 300_000_000, diskAvailableRaw: 300_000_000,
diskSize: '476.8 MiB', diskSize: '476.8 MiB',
@ -85,7 +85,7 @@ describe(ServerInfoService.name, () => {
total: 500_000_000_000, total: 500_000_000_000,
}); });
await expect(sut.getInfo()).resolves.toEqual({ await expect(sut.getStorage()).resolves.toEqual({
diskAvailable: '279.4 GiB', diskAvailable: '279.4 GiB',
diskAvailableRaw: 300_000_000_000, diskAvailableRaw: 300_000_000_000,
diskSize: '465.7 GiB', diskSize: '465.7 GiB',
@ -105,7 +105,7 @@ describe(ServerInfoService.name, () => {
total: 500_000_000_000_000, total: 500_000_000_000_000,
}); });
await expect(sut.getInfo()).resolves.toEqual({ await expect(sut.getStorage()).resolves.toEqual({
diskAvailable: '272.8 TiB', diskAvailable: '272.8 TiB',
diskAvailableRaw: 300_000_000_000_000, diskAvailableRaw: 300_000_000_000_000,
diskSize: '454.7 TiB', diskSize: '454.7 TiB',
@ -125,7 +125,7 @@ describe(ServerInfoService.name, () => {
total: 500_000_000_000_000_000, total: 500_000_000_000_000_000,
}); });
await expect(sut.getInfo()).resolves.toEqual({ await expect(sut.getStorage()).resolves.toEqual({
diskAvailable: '266.5 PiB', diskAvailable: '266.5 PiB',
diskAvailableRaw: 300_000_000_000_000_000, diskAvailableRaw: 300_000_000_000_000_000,
diskSize: '444.1 PiB', diskSize: '444.1 PiB',

View file

@ -4,10 +4,10 @@ import { SystemConfigCore } from 'src/cores/system-config.core';
import { import {
ServerConfigDto, ServerConfigDto,
ServerFeaturesDto, ServerFeaturesDto,
ServerInfoResponseDto,
ServerMediaTypesResponseDto, ServerMediaTypesResponseDto,
ServerPingResponse, ServerPingResponse,
ServerStatsResponseDto, ServerStatsResponseDto,
ServerStorageResponseDto,
UsageByUserDto, UsageByUserDto,
} from 'src/dtos/server-info.dto'; } from 'src/dtos/server-info.dto';
import { SystemMetadataKey } from 'src/entities/system-metadata.entity'; import { SystemMetadataKey } from 'src/entities/system-metadata.entity';
@ -42,13 +42,13 @@ export class ServerInfoService {
} }
} }
async getInfo(): Promise<ServerInfoResponseDto> { async getStorage(): Promise<ServerStorageResponseDto> {
const libraryBase = StorageCore.getBaseFolder(StorageFolder.LIBRARY); const libraryBase = StorageCore.getBaseFolder(StorageFolder.LIBRARY);
const diskInfo = await this.storageRepository.checkDiskUsage(libraryBase); const diskInfo = await this.storageRepository.checkDiskUsage(libraryBase);
const usagePercentage = (((diskInfo.total - diskInfo.free) / diskInfo.total) * 100).toFixed(2); const usagePercentage = (((diskInfo.total - diskInfo.free) / diskInfo.total) * 100).toFixed(2);
const serverInfo = new ServerInfoResponseDto(); const serverInfo = new ServerStorageResponseDto();
serverInfo.diskAvailable = asHumanReadable(diskInfo.available); serverInfo.diskAvailable = asHumanReadable(diskInfo.available);
serverInfo.diskSize = asHumanReadable(diskInfo.total); serverInfo.diskSize = asHumanReadable(diskInfo.total);
serverInfo.diskUse = asHumanReadable(diskInfo.total - diskInfo.free); serverInfo.diskUse = asHumanReadable(diskInfo.total - diskInfo.free);

View file

@ -1,4 +1,4 @@
import type { ServerInfoResponseDto } from '@immich/sdk'; import type { ServerStorageResponseDto } from '@immich/sdk';
import { writable } from 'svelte/store'; import { writable } from 'svelte/store';
export const serverInfo = writable<ServerInfoResponseDto>(); export const serverInfo = writable<ServerStorageResponseDto>();

View file

@ -1,7 +1,7 @@
import { browser } from '$app/environment'; import { browser } from '$app/environment';
import { serverInfo } from '$lib/stores/server-info.store'; import { serverInfo } from '$lib/stores/server-info.store';
import { user } from '$lib/stores/user.store'; import { user } from '$lib/stores/user.store';
import { getMyUserInfo, getServerInfo } from '@immich/sdk'; import { getMyUserInfo, getStorage } from '@immich/sdk';
import { redirect } from '@sveltejs/kit'; import { redirect } from '@sveltejs/kit';
import { get } from 'svelte/store'; import { get } from 'svelte/store';
import { AppRoute } from '../constants'; import { AppRoute } from '../constants';
@ -58,7 +58,7 @@ export const authenticate = async (options?: AuthOptions) => {
export const requestServerInfo = async () => { export const requestServerInfo = async () => {
if (get(user)) { if (get(user)) {
const data = await getServerInfo(); const data = await getStorage();
serverInfo.set(data); serverInfo.set(data);
} }
}; };