mirror of
https://github.com/immich-app/immich
synced 2025-11-14 17:36:12 +00:00
refactor(server)!: add/remove album assets (#3109)
* refactor: add/remove album assets * chore: open api * feat: remove owned assets from album * refactor: move to bulk id req/res dto * chore: open api * chore: merge main * dev: mobile work * fix: adding asset from web not sync with mobile * remove print statement --------- Co-authored-by: Alex Tran <Alex.Tran@conductix.com>
This commit is contained in:
parent
ba71c83948
commit
b9cda59172
51 changed files with 890 additions and 1282 deletions
120
web/src/api/open-api/api.ts
generated
120
web/src/api/open-api/api.ts
generated
|
|
@ -99,44 +99,6 @@ export interface APIKeyUpdateDto {
|
|||
*/
|
||||
'name': string;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface AddAssetsDto
|
||||
*/
|
||||
export interface AddAssetsDto {
|
||||
/**
|
||||
*
|
||||
* @type {Array<string>}
|
||||
* @memberof AddAssetsDto
|
||||
*/
|
||||
'assetIds': Array<string>;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface AddAssetsResponseDto
|
||||
*/
|
||||
export interface AddAssetsResponseDto {
|
||||
/**
|
||||
*
|
||||
* @type {AlbumResponseDto}
|
||||
* @memberof AddAssetsResponseDto
|
||||
*/
|
||||
'album'?: AlbumResponseDto;
|
||||
/**
|
||||
*
|
||||
* @type {Array<string>}
|
||||
* @memberof AddAssetsResponseDto
|
||||
*/
|
||||
'alreadyInAlbum': Array<string>;
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof AddAssetsResponseDto
|
||||
*/
|
||||
'successfullyAdded': number;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
|
|
@ -821,6 +783,19 @@ export const BulkIdResponseDtoErrorEnum = {
|
|||
|
||||
export type BulkIdResponseDtoErrorEnum = typeof BulkIdResponseDtoErrorEnum[keyof typeof BulkIdResponseDtoErrorEnum];
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface BulkIdsDto
|
||||
*/
|
||||
export interface BulkIdsDto {
|
||||
/**
|
||||
*
|
||||
* @type {Array<string>}
|
||||
* @memberof BulkIdsDto
|
||||
*/
|
||||
'ids': Array<string>;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
|
|
@ -1927,19 +1902,6 @@ export interface QueueStatusDto {
|
|||
*/
|
||||
'isPaused': boolean;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface RemoveAssetsDto
|
||||
*/
|
||||
export interface RemoveAssetsDto {
|
||||
/**
|
||||
*
|
||||
* @type {Array<string>}
|
||||
* @memberof RemoveAssetsDto
|
||||
*/
|
||||
'assetIds': Array<string>;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
|
|
@ -3679,16 +3641,16 @@ export const AlbumApiAxiosParamCreator = function (configuration?: Configuration
|
|||
/**
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {AddAssetsDto} addAssetsDto
|
||||
* @param {BulkIdsDto} bulkIdsDto
|
||||
* @param {string} [key]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
addAssetsToAlbum: async (id: string, addAssetsDto: AddAssetsDto, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
addAssetsToAlbum: async (id: string, bulkIdsDto: BulkIdsDto, key?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'id' is not null or undefined
|
||||
assertParamExists('addAssetsToAlbum', 'id', id)
|
||||
// verify required parameter 'addAssetsDto' is not null or undefined
|
||||
assertParamExists('addAssetsToAlbum', 'addAssetsDto', addAssetsDto)
|
||||
// verify required parameter 'bulkIdsDto' is not null or undefined
|
||||
assertParamExists('addAssetsToAlbum', 'bulkIdsDto', bulkIdsDto)
|
||||
const localVarPath = `/album/{id}/assets`
|
||||
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
|
|
@ -3722,7 +3684,7 @@ export const AlbumApiAxiosParamCreator = function (configuration?: Configuration
|
|||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(addAssetsDto, localVarRequestOptions, configuration)
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(bulkIdsDto, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
|
|
@ -3999,15 +3961,15 @@ export const AlbumApiAxiosParamCreator = function (configuration?: Configuration
|
|||
/**
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {RemoveAssetsDto} removeAssetsDto
|
||||
* @param {BulkIdsDto} bulkIdsDto
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
removeAssetFromAlbum: async (id: string, removeAssetsDto: RemoveAssetsDto, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
removeAssetFromAlbum: async (id: string, bulkIdsDto: BulkIdsDto, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'id' is not null or undefined
|
||||
assertParamExists('removeAssetFromAlbum', 'id', id)
|
||||
// verify required parameter 'removeAssetsDto' is not null or undefined
|
||||
assertParamExists('removeAssetFromAlbum', 'removeAssetsDto', removeAssetsDto)
|
||||
// verify required parameter 'bulkIdsDto' is not null or undefined
|
||||
assertParamExists('removeAssetFromAlbum', 'bulkIdsDto', bulkIdsDto)
|
||||
const localVarPath = `/album/{id}/assets`
|
||||
.replace(`{${"id"}}`, encodeURIComponent(String(id)));
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
|
|
@ -4037,7 +3999,7 @@ export const AlbumApiAxiosParamCreator = function (configuration?: Configuration
|
|||
setSearchParams(localVarUrlObj, localVarQueryParameter);
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(removeAssetsDto, localVarRequestOptions, configuration)
|
||||
localVarRequestOptions.data = serializeDataIfNeeded(bulkIdsDto, localVarRequestOptions, configuration)
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
|
|
@ -4151,13 +4113,13 @@ export const AlbumApiFp = function(configuration?: Configuration) {
|
|||
/**
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {AddAssetsDto} addAssetsDto
|
||||
* @param {BulkIdsDto} bulkIdsDto
|
||||
* @param {string} [key]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async addAssetsToAlbum(id: string, addAssetsDto: AddAssetsDto, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AddAssetsResponseDto>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.addAssetsToAlbum(id, addAssetsDto, key, options);
|
||||
async addAssetsToAlbum(id: string, bulkIdsDto: BulkIdsDto, key?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<BulkIdResponseDto>>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.addAssetsToAlbum(id, bulkIdsDto, key, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
|
|
@ -4225,12 +4187,12 @@ export const AlbumApiFp = function(configuration?: Configuration) {
|
|||
/**
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {RemoveAssetsDto} removeAssetsDto
|
||||
* @param {BulkIdsDto} bulkIdsDto
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async removeAssetFromAlbum(id: string, removeAssetsDto: RemoveAssetsDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AlbumResponseDto>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.removeAssetFromAlbum(id, removeAssetsDto, options);
|
||||
async removeAssetFromAlbum(id: string, bulkIdsDto: BulkIdsDto, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<Array<BulkIdResponseDto>>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.removeAssetFromAlbum(id, bulkIdsDto, options);
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||
},
|
||||
/**
|
||||
|
|
@ -4268,13 +4230,13 @@ export const AlbumApiFactory = function (configuration?: Configuration, basePath
|
|||
/**
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {AddAssetsDto} addAssetsDto
|
||||
* @param {BulkIdsDto} bulkIdsDto
|
||||
* @param {string} [key]
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
addAssetsToAlbum(id: string, addAssetsDto: AddAssetsDto, key?: string, options?: any): AxiosPromise<AddAssetsResponseDto> {
|
||||
return localVarFp.addAssetsToAlbum(id, addAssetsDto, key, options).then((request) => request(axios, basePath));
|
||||
addAssetsToAlbum(id: string, bulkIdsDto: BulkIdsDto, key?: string, options?: any): AxiosPromise<Array<BulkIdResponseDto>> {
|
||||
return localVarFp.addAssetsToAlbum(id, bulkIdsDto, key, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
|
|
@ -4335,12 +4297,12 @@ export const AlbumApiFactory = function (configuration?: Configuration, basePath
|
|||
/**
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {RemoveAssetsDto} removeAssetsDto
|
||||
* @param {BulkIdsDto} bulkIdsDto
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
removeAssetFromAlbum(id: string, removeAssetsDto: RemoveAssetsDto, options?: any): AxiosPromise<AlbumResponseDto> {
|
||||
return localVarFp.removeAssetFromAlbum(id, removeAssetsDto, options).then((request) => request(axios, basePath));
|
||||
removeAssetFromAlbum(id: string, bulkIdsDto: BulkIdsDto, options?: any): AxiosPromise<Array<BulkIdResponseDto>> {
|
||||
return localVarFp.removeAssetFromAlbum(id, bulkIdsDto, options).then((request) => request(axios, basePath));
|
||||
},
|
||||
/**
|
||||
*
|
||||
|
|
@ -4380,10 +4342,10 @@ export interface AlbumApiAddAssetsToAlbumRequest {
|
|||
|
||||
/**
|
||||
*
|
||||
* @type {AddAssetsDto}
|
||||
* @type {BulkIdsDto}
|
||||
* @memberof AlbumApiAddAssetsToAlbum
|
||||
*/
|
||||
readonly addAssetsDto: AddAssetsDto
|
||||
readonly bulkIdsDto: BulkIdsDto
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -4499,10 +4461,10 @@ export interface AlbumApiRemoveAssetFromAlbumRequest {
|
|||
|
||||
/**
|
||||
*
|
||||
* @type {RemoveAssetsDto}
|
||||
* @type {BulkIdsDto}
|
||||
* @memberof AlbumApiRemoveAssetFromAlbum
|
||||
*/
|
||||
readonly removeAssetsDto: RemoveAssetsDto
|
||||
readonly bulkIdsDto: BulkIdsDto
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -4562,7 +4524,7 @@ export class AlbumApi extends BaseAPI {
|
|||
* @memberof AlbumApi
|
||||
*/
|
||||
public addAssetsToAlbum(requestParameters: AlbumApiAddAssetsToAlbumRequest, options?: AxiosRequestConfig) {
|
||||
return AlbumApiFp(this.configuration).addAssetsToAlbum(requestParameters.id, requestParameters.addAssetsDto, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
|
||||
return AlbumApiFp(this.configuration).addAssetsToAlbum(requestParameters.id, requestParameters.bulkIdsDto, requestParameters.key, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -4638,7 +4600,7 @@ export class AlbumApi extends BaseAPI {
|
|||
* @memberof AlbumApi
|
||||
*/
|
||||
public removeAssetFromAlbum(requestParameters: AlbumApiRemoveAssetFromAlbumRequest, options?: AxiosRequestConfig) {
|
||||
return AlbumApiFp(this.configuration).removeAssetFromAlbum(requestParameters.id, requestParameters.removeAssetsDto, options).then((request) => request(this.axios, this.basePath));
|
||||
return AlbumApiFp(this.configuration).removeAssetFromAlbum(requestParameters.id, requestParameters.bulkIdsDto, options).then((request) => request(this.axios, this.basePath));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@
|
|||
|
||||
let multiSelectAsset: Set<AssetResponseDto> = new Set();
|
||||
$: isMultiSelectionMode = multiSelectAsset.size > 0;
|
||||
$: isMultiSelectionUserOwned = Array.from(multiSelectAsset).every((asset) => asset.ownerId === currentUser?.id);
|
||||
|
||||
afterNavigate(({ from }) => {
|
||||
backUrl = from?.url.pathname ?? '/albums';
|
||||
|
|
@ -182,24 +183,24 @@
|
|||
const createAlbumHandler = async (event: CustomEvent) => {
|
||||
const { assets }: { assets: AssetResponseDto[] } = event.detail;
|
||||
try {
|
||||
const { data } = await api.albumApi.addAssetsToAlbum({
|
||||
const { data: results } = await api.albumApi.addAssetsToAlbum({
|
||||
id: album.id,
|
||||
addAssetsDto: {
|
||||
assetIds: assets.map((a) => a.id),
|
||||
},
|
||||
bulkIdsDto: { ids: assets.map((a) => a.id) },
|
||||
key: sharedLink?.key,
|
||||
});
|
||||
|
||||
if (data.album) {
|
||||
album = data.album;
|
||||
}
|
||||
const count = results.filter(({ success }) => success).length;
|
||||
notificationController.show({
|
||||
type: NotificationType.Info,
|
||||
message: `Added ${count} asset${count === 1 ? '' : 's'}`,
|
||||
});
|
||||
|
||||
const { data } = await api.albumApi.getAlbumInfo({ id: album.id });
|
||||
album = data;
|
||||
|
||||
isShowAssetSelection = false;
|
||||
} catch (e) {
|
||||
console.error('Error [createAlbumHandler] ', e);
|
||||
notificationController.show({
|
||||
type: NotificationType.Error,
|
||||
message: 'Error creating album, check console for more details',
|
||||
});
|
||||
handleError(e, 'Error creating album');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -307,7 +308,7 @@
|
|||
{#if sharedLink?.allowDownload || !isPublicShared}
|
||||
<DownloadAction filename="{album.albumName}.zip" sharedLinkKey={sharedLink?.key} />
|
||||
{/if}
|
||||
{#if isOwned}
|
||||
{#if isOwned || isMultiSelectionUserOwned}
|
||||
<RemoveFromAlbum bind:album />
|
||||
{/if}
|
||||
</AssetSelectControlBar>
|
||||
|
|
|
|||
|
|
@ -189,11 +189,8 @@
|
|||
isShowAlbumPicker = false;
|
||||
const album = event.detail.album;
|
||||
|
||||
addAssetsToAlbum(album.id, [asset.id]).then((dto) => {
|
||||
if (dto.successfullyAdded === 1 && dto.album) {
|
||||
appearsInAlbums = [...appearsInAlbums, dto.album];
|
||||
}
|
||||
});
|
||||
await addAssetsToAlbum(album.id, [asset.id]);
|
||||
await getAllAlbums();
|
||||
};
|
||||
|
||||
const disableKeyDownEvent = () => {
|
||||
|
|
|
|||
|
|
@ -44,10 +44,9 @@
|
|||
const handleAddToAlbum = async (event: CustomEvent<{ album: AlbumResponseDto }>) => {
|
||||
showAlbumPicker = false;
|
||||
const album = event.detail.album;
|
||||
|
||||
const assetIds = Array.from(getAssets()).map((asset) => asset.id);
|
||||
|
||||
addAssetsToAlbum(album.id, assetIds).then(clearSelect);
|
||||
await addAssetsToAlbum(album.id, assetIds);
|
||||
clearSelect();
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -17,14 +17,20 @@
|
|||
|
||||
const removeFromAlbum = async () => {
|
||||
try {
|
||||
const { data } = await api.albumApi.removeAssetFromAlbum({
|
||||
const { data: results } = await api.albumApi.removeAssetFromAlbum({
|
||||
id: album.id,
|
||||
removeAssetsDto: {
|
||||
assetIds: Array.from(getAssets()).map((a) => a.id),
|
||||
},
|
||||
bulkIdsDto: { ids: Array.from(getAssets()).map((a) => a.id) },
|
||||
});
|
||||
|
||||
const { data } = await api.albumApi.getAlbumInfo({ id: album.id });
|
||||
album = data;
|
||||
|
||||
const count = results.filter(({ success }) => success).length;
|
||||
notificationController.show({
|
||||
type: NotificationType.Info,
|
||||
message: `Removed ${count} asset${count === 1 ? '' : 's'}`,
|
||||
});
|
||||
|
||||
clearSelect();
|
||||
} catch (e) {
|
||||
console.error('Error [album-viewer] [removeAssetFromAlbum]', e);
|
||||
|
|
|
|||
|
|
@ -1,23 +1,24 @@
|
|||
import { notificationController, NotificationType } from '$lib/components/shared-components/notification/notification';
|
||||
import { downloadManager } from '$lib/stores/download';
|
||||
import { AddAssetsResponseDto, api, AssetApiGetDownloadInfoRequest, AssetResponseDto, DownloadResponseDto } from '@api';
|
||||
import { api, AssetApiGetDownloadInfoRequest, BulkIdResponseDto, AssetResponseDto, DownloadResponseDto } from '@api';
|
||||
import { handleError } from './handle-error';
|
||||
|
||||
export const addAssetsToAlbum = async (
|
||||
albumId: string,
|
||||
assetIds: Array<string>,
|
||||
key: string | undefined = undefined,
|
||||
): Promise<AddAssetsResponseDto> =>
|
||||
api.albumApi.addAssetsToAlbum({ id: albumId, addAssetsDto: { assetIds }, key }).then(({ data: dto }) => {
|
||||
if (dto.successfullyAdded > 0) {
|
||||
): Promise<BulkIdResponseDto[]> =>
|
||||
api.albumApi.addAssetsToAlbum({ id: albumId, bulkIdsDto: { ids: assetIds }, key }).then(({ data: results }) => {
|
||||
const count = results.filter(({ success }) => success).length;
|
||||
if (count > 0) {
|
||||
// This might be 0 if the user tries to add an asset that is already in the album
|
||||
notificationController.show({
|
||||
message: `Added ${dto.successfullyAdded} to ${dto.album?.albumName}`,
|
||||
type: NotificationType.Info,
|
||||
message: `Added ${count} asset${count === 1 ? '' : 's'}`,
|
||||
});
|
||||
}
|
||||
|
||||
return dto;
|
||||
return results;
|
||||
});
|
||||
|
||||
const downloadBlob = (data: Blob, filename: string) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue