mirror of
https://github.com/KevinMidboe/immich.git
synced 2026-01-19 07:36:21 +00:00
feat (server, web): Implement Archive (#2225)
* feat (server, web): add archive * chore: generate api * feat (web): add empty placeholder for archive page * chore: remove title on favorites page Duplicates sidebar selection. Two pages (Archive and Favorites) are consistent now * refactor (web): create EmptyPlaceholder component for empty pages * fixed menu close button not close: * fix (web): remove not necessary store call * test (web): simplify asset tests code * test (web): simplify asset tests code * chore (server): remove isArchived while uploading * chore (server): remove isArchived from typesense schema * chore: generate api * fix (web): delete asset from archive page * chore: change archive asset count endpoint old endpoint: /asset/archived-count-by-user-id new endpoint: /asset/stat/archive * chore: generate api --------- Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
71
mobile/openapi/lib/api/asset_api.dart
generated
71
mobile/openapi/lib/api/asset_api.dart
generated
@@ -494,11 +494,13 @@ class AssetApi {
|
||||
///
|
||||
/// * [bool] isFavorite:
|
||||
///
|
||||
/// * [bool] isArchived:
|
||||
///
|
||||
/// * [num] skip:
|
||||
///
|
||||
/// * [String] ifNoneMatch:
|
||||
/// ETag of data already cached on the client
|
||||
Future<Response> getAllAssetsWithHttpInfo({ bool? isFavorite, num? skip, String? ifNoneMatch, }) async {
|
||||
Future<Response> getAllAssetsWithHttpInfo({ bool? isFavorite, bool? isArchived, num? skip, String? ifNoneMatch, }) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/asset';
|
||||
|
||||
@@ -512,6 +514,9 @@ class AssetApi {
|
||||
if (isFavorite != null) {
|
||||
queryParams.addAll(_queryParams('', 'isFavorite', isFavorite));
|
||||
}
|
||||
if (isArchived != null) {
|
||||
queryParams.addAll(_queryParams('', 'isArchived', isArchived));
|
||||
}
|
||||
if (skip != null) {
|
||||
queryParams.addAll(_queryParams('', 'skip', skip));
|
||||
}
|
||||
@@ -540,12 +545,14 @@ class AssetApi {
|
||||
///
|
||||
/// * [bool] isFavorite:
|
||||
///
|
||||
/// * [bool] isArchived:
|
||||
///
|
||||
/// * [num] skip:
|
||||
///
|
||||
/// * [String] ifNoneMatch:
|
||||
/// ETag of data already cached on the client
|
||||
Future<List<AssetResponseDto>?> getAllAssets({ bool? isFavorite, num? skip, String? ifNoneMatch, }) async {
|
||||
final response = await getAllAssetsWithHttpInfo( isFavorite: isFavorite, skip: skip, ifNoneMatch: ifNoneMatch, );
|
||||
Future<List<AssetResponseDto>?> getAllAssets({ bool? isFavorite, bool? isArchived, num? skip, String? ifNoneMatch, }) async {
|
||||
final response = await getAllAssetsWithHttpInfo( isFavorite: isFavorite, isArchived: isArchived, skip: skip, ifNoneMatch: ifNoneMatch, );
|
||||
if (response.statusCode >= HttpStatus.badRequest) {
|
||||
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||
}
|
||||
@@ -562,6 +569,50 @@ class AssetApi {
|
||||
return null;
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
/// Note: This method returns the HTTP [Response].
|
||||
Future<Response> getArchivedAssetCountByUserIdWithHttpInfo() async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/asset/stat/archive';
|
||||
|
||||
// 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<AssetCountByUserIdResponseDto?> getArchivedAssetCountByUserId() async {
|
||||
final response = await getArchivedAssetCountByUserIdWithHttpInfo();
|
||||
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), 'AssetCountByUserIdResponseDto',) as AssetCountByUserIdResponseDto;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Get a single asset's information
|
||||
///
|
||||
/// Note: This method returns the HTTP [Response].
|
||||
@@ -1312,10 +1363,12 @@ class AssetApi {
|
||||
///
|
||||
/// * [MultipartFile] livePhotoData:
|
||||
///
|
||||
/// * [bool] isArchived:
|
||||
///
|
||||
/// * [bool] isVisible:
|
||||
///
|
||||
/// * [String] duration:
|
||||
Future<Response> uploadFileWithHttpInfo(AssetTypeEnum assetType, MultipartFile assetData, String deviceAssetId, String deviceId, String fileCreatedAt, String fileModifiedAt, bool isFavorite, String fileExtension, { String? key, MultipartFile? livePhotoData, bool? isVisible, String? duration, }) async {
|
||||
Future<Response> uploadFileWithHttpInfo(AssetTypeEnum assetType, MultipartFile assetData, String deviceAssetId, String deviceId, String fileCreatedAt, String fileModifiedAt, bool isFavorite, String fileExtension, { String? key, MultipartFile? livePhotoData, bool? isArchived, bool? isVisible, String? duration, }) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/asset/upload';
|
||||
|
||||
@@ -1368,6 +1421,10 @@ class AssetApi {
|
||||
hasFields = true;
|
||||
mp.fields[r'isFavorite'] = parameterToString(isFavorite);
|
||||
}
|
||||
if (isArchived != null) {
|
||||
hasFields = true;
|
||||
mp.fields[r'isArchived'] = parameterToString(isArchived);
|
||||
}
|
||||
if (isVisible != null) {
|
||||
hasFields = true;
|
||||
mp.fields[r'isVisible'] = parameterToString(isVisible);
|
||||
@@ -1419,11 +1476,13 @@ class AssetApi {
|
||||
///
|
||||
/// * [MultipartFile] livePhotoData:
|
||||
///
|
||||
/// * [bool] isArchived:
|
||||
///
|
||||
/// * [bool] isVisible:
|
||||
///
|
||||
/// * [String] duration:
|
||||
Future<AssetFileUploadResponseDto?> uploadFile(AssetTypeEnum assetType, MultipartFile assetData, String deviceAssetId, String deviceId, String fileCreatedAt, String fileModifiedAt, bool isFavorite, String fileExtension, { String? key, MultipartFile? livePhotoData, bool? isVisible, String? duration, }) async {
|
||||
final response = await uploadFileWithHttpInfo(assetType, assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, fileExtension, key: key, livePhotoData: livePhotoData, isVisible: isVisible, duration: duration, );
|
||||
Future<AssetFileUploadResponseDto?> uploadFile(AssetTypeEnum assetType, MultipartFile assetData, String deviceAssetId, String deviceId, String fileCreatedAt, String fileModifiedAt, bool isFavorite, String fileExtension, { String? key, MultipartFile? livePhotoData, bool? isArchived, bool? isVisible, String? duration, }) async {
|
||||
final response = await uploadFileWithHttpInfo(assetType, assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, fileExtension, key: key, livePhotoData: livePhotoData, isArchived: isArchived, isVisible: isVisible, duration: duration, );
|
||||
if (response.statusCode >= HttpStatus.badRequest) {
|
||||
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||
}
|
||||
|
||||
13
mobile/openapi/lib/api/search_api.dart
generated
13
mobile/openapi/lib/api/search_api.dart
generated
@@ -123,6 +123,8 @@ class SearchApi {
|
||||
///
|
||||
/// * [bool] isFavorite:
|
||||
///
|
||||
/// * [bool] isArchived:
|
||||
///
|
||||
/// * [String] exifInfoPeriodCity:
|
||||
///
|
||||
/// * [String] exifInfoPeriodState:
|
||||
@@ -140,7 +142,7 @@ class SearchApi {
|
||||
/// * [bool] recent:
|
||||
///
|
||||
/// * [bool] motion:
|
||||
Future<Response> searchWithHttpInfo({ String? q, String? query, bool? clip, String? type, bool? isFavorite, String? exifInfoPeriodCity, String? exifInfoPeriodState, String? exifInfoPeriodCountry, String? exifInfoPeriodMake, String? exifInfoPeriodModel, List<String>? smartInfoPeriodObjects, List<String>? smartInfoPeriodTags, bool? recent, bool? motion, }) async {
|
||||
Future<Response> searchWithHttpInfo({ String? q, String? query, bool? clip, String? type, bool? isFavorite, bool? isArchived, String? exifInfoPeriodCity, String? exifInfoPeriodState, String? exifInfoPeriodCountry, String? exifInfoPeriodMake, String? exifInfoPeriodModel, List<String>? smartInfoPeriodObjects, List<String>? smartInfoPeriodTags, bool? recent, bool? motion, }) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final path = r'/search';
|
||||
|
||||
@@ -166,6 +168,9 @@ class SearchApi {
|
||||
if (isFavorite != null) {
|
||||
queryParams.addAll(_queryParams('', 'isFavorite', isFavorite));
|
||||
}
|
||||
if (isArchived != null) {
|
||||
queryParams.addAll(_queryParams('', 'isArchived', isArchived));
|
||||
}
|
||||
if (exifInfoPeriodCity != null) {
|
||||
queryParams.addAll(_queryParams('', 'exifInfo.city', exifInfoPeriodCity));
|
||||
}
|
||||
@@ -222,6 +227,8 @@ class SearchApi {
|
||||
///
|
||||
/// * [bool] isFavorite:
|
||||
///
|
||||
/// * [bool] isArchived:
|
||||
///
|
||||
/// * [String] exifInfoPeriodCity:
|
||||
///
|
||||
/// * [String] exifInfoPeriodState:
|
||||
@@ -239,8 +246,8 @@ class SearchApi {
|
||||
/// * [bool] recent:
|
||||
///
|
||||
/// * [bool] motion:
|
||||
Future<SearchResponseDto?> search({ String? q, String? query, bool? clip, String? type, bool? isFavorite, String? exifInfoPeriodCity, String? exifInfoPeriodState, String? exifInfoPeriodCountry, String? exifInfoPeriodMake, String? exifInfoPeriodModel, List<String>? smartInfoPeriodObjects, List<String>? smartInfoPeriodTags, bool? recent, bool? motion, }) async {
|
||||
final response = await searchWithHttpInfo( q: q, query: query, clip: clip, type: type, isFavorite: isFavorite, exifInfoPeriodCity: exifInfoPeriodCity, exifInfoPeriodState: exifInfoPeriodState, exifInfoPeriodCountry: exifInfoPeriodCountry, exifInfoPeriodMake: exifInfoPeriodMake, exifInfoPeriodModel: exifInfoPeriodModel, smartInfoPeriodObjects: smartInfoPeriodObjects, smartInfoPeriodTags: smartInfoPeriodTags, recent: recent, motion: motion, );
|
||||
Future<SearchResponseDto?> search({ String? q, String? query, bool? clip, String? type, bool? isFavorite, bool? isArchived, String? exifInfoPeriodCity, String? exifInfoPeriodState, String? exifInfoPeriodCountry, String? exifInfoPeriodMake, String? exifInfoPeriodModel, List<String>? smartInfoPeriodObjects, List<String>? smartInfoPeriodTags, bool? recent, bool? motion, }) async {
|
||||
final response = await searchWithHttpInfo( q: q, query: query, clip: clip, type: type, isFavorite: isFavorite, isArchived: isArchived, exifInfoPeriodCity: exifInfoPeriodCity, exifInfoPeriodState: exifInfoPeriodState, exifInfoPeriodCountry: exifInfoPeriodCountry, exifInfoPeriodMake: exifInfoPeriodMake, exifInfoPeriodModel: exifInfoPeriodModel, smartInfoPeriodObjects: smartInfoPeriodObjects, smartInfoPeriodTags: smartInfoPeriodTags, recent: recent, motion: motion, );
|
||||
if (response.statusCode >= HttpStatus.badRequest) {
|
||||
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||
}
|
||||
|
||||
10
mobile/openapi/lib/model/asset_response_dto.dart
generated
10
mobile/openapi/lib/model/asset_response_dto.dart
generated
@@ -25,6 +25,7 @@ class AssetResponseDto {
|
||||
required this.fileModifiedAt,
|
||||
required this.updatedAt,
|
||||
required this.isFavorite,
|
||||
required this.isArchived,
|
||||
required this.mimeType,
|
||||
required this.duration,
|
||||
required this.webpPath,
|
||||
@@ -59,6 +60,8 @@ class AssetResponseDto {
|
||||
|
||||
bool isFavorite;
|
||||
|
||||
bool isArchived;
|
||||
|
||||
String? mimeType;
|
||||
|
||||
String duration;
|
||||
@@ -101,6 +104,7 @@ class AssetResponseDto {
|
||||
other.fileModifiedAt == fileModifiedAt &&
|
||||
other.updatedAt == updatedAt &&
|
||||
other.isFavorite == isFavorite &&
|
||||
other.isArchived == isArchived &&
|
||||
other.mimeType == mimeType &&
|
||||
other.duration == duration &&
|
||||
other.webpPath == webpPath &&
|
||||
@@ -125,6 +129,7 @@ class AssetResponseDto {
|
||||
(fileModifiedAt.hashCode) +
|
||||
(updatedAt.hashCode) +
|
||||
(isFavorite.hashCode) +
|
||||
(isArchived.hashCode) +
|
||||
(mimeType == null ? 0 : mimeType!.hashCode) +
|
||||
(duration.hashCode) +
|
||||
(webpPath == null ? 0 : webpPath!.hashCode) +
|
||||
@@ -135,7 +140,7 @@ class AssetResponseDto {
|
||||
(tags.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'AssetResponseDto[type=$type, id=$id, deviceAssetId=$deviceAssetId, ownerId=$ownerId, deviceId=$deviceId, originalPath=$originalPath, originalFileName=$originalFileName, resizePath=$resizePath, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, updatedAt=$updatedAt, isFavorite=$isFavorite, mimeType=$mimeType, duration=$duration, webpPath=$webpPath, encodedVideoPath=$encodedVideoPath, exifInfo=$exifInfo, smartInfo=$smartInfo, livePhotoVideoId=$livePhotoVideoId, tags=$tags]';
|
||||
String toString() => 'AssetResponseDto[type=$type, id=$id, deviceAssetId=$deviceAssetId, ownerId=$ownerId, deviceId=$deviceId, originalPath=$originalPath, originalFileName=$originalFileName, resizePath=$resizePath, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, updatedAt=$updatedAt, isFavorite=$isFavorite, isArchived=$isArchived, mimeType=$mimeType, duration=$duration, webpPath=$webpPath, encodedVideoPath=$encodedVideoPath, exifInfo=$exifInfo, smartInfo=$smartInfo, livePhotoVideoId=$livePhotoVideoId, tags=$tags]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
@@ -155,6 +160,7 @@ class AssetResponseDto {
|
||||
json[r'fileModifiedAt'] = this.fileModifiedAt;
|
||||
json[r'updatedAt'] = this.updatedAt;
|
||||
json[r'isFavorite'] = this.isFavorite;
|
||||
json[r'isArchived'] = this.isArchived;
|
||||
if (this.mimeType != null) {
|
||||
json[r'mimeType'] = this.mimeType;
|
||||
} else {
|
||||
@@ -221,6 +227,7 @@ class AssetResponseDto {
|
||||
fileModifiedAt: mapValueOfType<String>(json, r'fileModifiedAt')!,
|
||||
updatedAt: mapValueOfType<String>(json, r'updatedAt')!,
|
||||
isFavorite: mapValueOfType<bool>(json, r'isFavorite')!,
|
||||
isArchived: mapValueOfType<bool>(json, r'isArchived')!,
|
||||
mimeType: mapValueOfType<String>(json, r'mimeType'),
|
||||
duration: mapValueOfType<String>(json, r'duration')!,
|
||||
webpPath: mapValueOfType<String>(json, r'webpPath'),
|
||||
@@ -290,6 +297,7 @@ class AssetResponseDto {
|
||||
'fileModifiedAt',
|
||||
'updatedAt',
|
||||
'isFavorite',
|
||||
'isArchived',
|
||||
'mimeType',
|
||||
'duration',
|
||||
'webpPath',
|
||||
|
||||
23
mobile/openapi/lib/model/update_asset_dto.dart
generated
23
mobile/openapi/lib/model/update_asset_dto.dart
generated
@@ -15,6 +15,7 @@ class UpdateAssetDto {
|
||||
UpdateAssetDto({
|
||||
this.tagIds = const [],
|
||||
this.isFavorite,
|
||||
this.isArchived,
|
||||
});
|
||||
|
||||
List<String> tagIds;
|
||||
@@ -27,19 +28,29 @@ class UpdateAssetDto {
|
||||
///
|
||||
bool? isFavorite;
|
||||
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
bool? isArchived;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is UpdateAssetDto &&
|
||||
other.tagIds == tagIds &&
|
||||
other.isFavorite == isFavorite;
|
||||
other.isFavorite == isFavorite &&
|
||||
other.isArchived == isArchived;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
// ignore: unnecessary_parenthesis
|
||||
(tagIds.hashCode) +
|
||||
(isFavorite == null ? 0 : isFavorite!.hashCode);
|
||||
(isFavorite == null ? 0 : isFavorite!.hashCode) +
|
||||
(isArchived == null ? 0 : isArchived!.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'UpdateAssetDto[tagIds=$tagIds, isFavorite=$isFavorite]';
|
||||
String toString() => 'UpdateAssetDto[tagIds=$tagIds, isFavorite=$isFavorite, isArchived=$isArchived]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
@@ -49,6 +60,11 @@ class UpdateAssetDto {
|
||||
} else {
|
||||
// json[r'isFavorite'] = null;
|
||||
}
|
||||
if (this.isArchived != null) {
|
||||
json[r'isArchived'] = this.isArchived;
|
||||
} else {
|
||||
// json[r'isArchived'] = null;
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
@@ -75,6 +91,7 @@ class UpdateAssetDto {
|
||||
? (json[r'tagIds'] as List).cast<String>()
|
||||
: const [],
|
||||
isFavorite: mapValueOfType<bool>(json, r'isFavorite'),
|
||||
isArchived: mapValueOfType<bool>(json, r'isArchived'),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user