mirror of
https://github.com/immich-app/immich.git
synced 2024-12-25 10:43:13 +02:00
Modify Album API endpoint to return a count attribute instead of a full assets array (#454)
* Change API to return assets count and change web behavior accordingly * Refactor assets.length * Explicitly declare type of assetCount so Dart SDK understand it * Finished refactoring on mobile
This commit is contained in:
parent
bd5ed1b684
commit
5c78f707fe
@ -61,13 +61,13 @@ class AlbumThumbnailCard extends StatelessWidget {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
album.assets.length == 1
|
||||
album.assetCount == 1
|
||||
? 'album_thumbnail_card_item'
|
||||
: 'album_thumbnail_card_items',
|
||||
style: const TextStyle(
|
||||
fontSize: 10,
|
||||
),
|
||||
).tr(args: ['${album.assets.length }']),
|
||||
).tr(args: ['${album.assetCount}']),
|
||||
if (album.shared)
|
||||
const Text(
|
||||
'album_thumbnail_card_shared',
|
||||
|
@ -203,7 +203,7 @@ class AlbumViewerPage extends HookConsumerWidget {
|
||||
assetList: albumInfo.assets,
|
||||
);
|
||||
},
|
||||
childCount: albumInfo.assets.length,
|
||||
childCount: albumInfo.assetCount,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -134,21 +134,14 @@ export class AlbumRepository implements IAlbumRepository {
|
||||
.leftJoinAndSelect('album.sharedUsers', 'sharedUser')
|
||||
.leftJoinAndSelect('sharedUser.userInfo', 'userInfo')
|
||||
.where('album.ownerId = :ownerId', { ownerId: userId });
|
||||
// .orWhere((qb) => {
|
||||
// const subQuery = qb
|
||||
// .subQuery()
|
||||
// .select('userAlbum.albumId')
|
||||
// .from(UserAlbumEntity, 'userAlbum')
|
||||
// .where('userAlbum.sharedUserId = :sharedUserId', { sharedUserId: userId })
|
||||
// .getQuery();
|
||||
// return `album.id IN ${subQuery}`;
|
||||
// });
|
||||
}
|
||||
|
||||
// Get information of assets in albums
|
||||
query = query
|
||||
.leftJoinAndSelect('album.assets', 'assets')
|
||||
.leftJoinAndSelect('assets.assetInfo', 'assetInfo')
|
||||
.orderBy('"assetInfo"."createdAt"::timestamptz', 'ASC');
|
||||
|
||||
const albums = await query.getMany();
|
||||
|
||||
albums.sort((a, b) => new Date(b.createdAt).valueOf() - new Date(a.createdAt).valueOf());
|
||||
|
@ -7,7 +7,7 @@ import { AddUsersDto } from './dto/add-users.dto';
|
||||
import { RemoveAssetsDto } from './dto/remove-assets.dto';
|
||||
import { UpdateAlbumDto } from './dto/update-album.dto';
|
||||
import { GetAlbumsDto } from './dto/get-albums.dto';
|
||||
import { AlbumResponseDto, mapAlbum } from './response-dto/album-response.dto';
|
||||
import { AlbumResponseDto, mapAlbum, mapAlbumExcludeAssetInfo } from './response-dto/album-response.dto';
|
||||
import { ALBUM_REPOSITORY, IAlbumRepository } from './album-repository';
|
||||
|
||||
@Injectable()
|
||||
@ -49,7 +49,8 @@ export class AlbumService {
|
||||
*/
|
||||
async getAllAlbums(authUser: AuthUserDto, getAlbumsDto: GetAlbumsDto): Promise<AlbumResponseDto[]> {
|
||||
const albums = await this._albumRepository.getList(authUser.id, getAlbumsDto);
|
||||
return albums.map((album) => mapAlbum(album));
|
||||
|
||||
return albums.map((album) => mapAlbumExcludeAssetInfo(album));
|
||||
}
|
||||
|
||||
async getAlbumInfo(authUser: AuthUserDto, albumId: string): Promise<AlbumResponseDto> {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { AlbumEntity } from '../../../../../../libs/database/src/entities/album.entity';
|
||||
import { UserResponseDto, mapUser } from '../../user/response-dto/user-response.dto';
|
||||
import { AssetResponseDto, mapAsset } from '../../asset/response-dto/asset-response.dto';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class AlbumResponseDto {
|
||||
id!: string;
|
||||
@ -11,6 +12,9 @@ export class AlbumResponseDto {
|
||||
shared!: boolean;
|
||||
sharedUsers!: UserResponseDto[];
|
||||
assets!: AssetResponseDto[];
|
||||
|
||||
@ApiProperty({ type: 'integer' })
|
||||
assetCount!: number;
|
||||
}
|
||||
|
||||
export function mapAlbum(entity: AlbumEntity): AlbumResponseDto {
|
||||
@ -24,5 +28,21 @@ export function mapAlbum(entity: AlbumEntity): AlbumResponseDto {
|
||||
sharedUsers,
|
||||
shared: sharedUsers.length > 0,
|
||||
assets: entity.assets?.map((assetAlbum) => mapAsset(assetAlbum.assetInfo)) || [],
|
||||
assetCount: entity.assets?.length || 0,
|
||||
};
|
||||
}
|
||||
|
||||
export function mapAlbumExcludeAssetInfo(entity: AlbumEntity): AlbumResponseDto {
|
||||
const sharedUsers = entity.sharedUsers?.map((userAlbum) => mapUser(userAlbum.userInfo)) || [];
|
||||
return {
|
||||
albumName: entity.albumName,
|
||||
albumThumbnailAssetId: entity.albumThumbnailAssetId,
|
||||
createdAt: entity.createdAt,
|
||||
id: entity.id,
|
||||
ownerId: entity.ownerId,
|
||||
sharedUsers,
|
||||
shared: sharedUsers.length > 0,
|
||||
assets: [],
|
||||
assetCount: entity.assets?.length || 0,
|
||||
};
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
@ -90,6 +90,12 @@ export interface AdminSignupResponseDto {
|
||||
* @interface AlbumResponseDto
|
||||
*/
|
||||
export interface AlbumResponseDto {
|
||||
/**
|
||||
*
|
||||
* @type {number}
|
||||
* @memberof AlbumResponseDto
|
||||
*/
|
||||
'assetCount': number;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
|
@ -32,7 +32,7 @@
|
||||
};
|
||||
|
||||
onMount(async () => {
|
||||
imageData = await loadHighQualityThumbnail(album.albumThumbnailAssetId) || 'no-thumbnail.png';
|
||||
imageData = (await loadHighQualityThumbnail(album.albumThumbnailAssetId)) || 'no-thumbnail.png';
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -67,7 +67,7 @@
|
||||
</p>
|
||||
|
||||
<span class="text-xs flex gap-2">
|
||||
<p>{album.assets.length} items</p>
|
||||
<p>{album.assetCount} items</p>
|
||||
|
||||
{#if album.shared}
|
||||
<p>·</p>
|
||||
|
@ -61,7 +61,7 @@
|
||||
|
||||
$: {
|
||||
if (album.assets?.length < 6) {
|
||||
thumbnailSize = Math.floor(viewWidth / album.assets.length - album.assets.length);
|
||||
thumbnailSize = Math.floor(viewWidth / album.assetCount - album.assetCount);
|
||||
} else {
|
||||
thumbnailSize = Math.floor(viewWidth / 6 - 6);
|
||||
}
|
||||
@ -69,7 +69,7 @@
|
||||
|
||||
const getDateRange = () => {
|
||||
const startDate = new Date(album.assets[0].createdAt);
|
||||
const endDate = new Date(album.assets[album.assets.length - 1].createdAt);
|
||||
const endDate = new Date(album.assets[album.assetCount - 1].createdAt);
|
||||
|
||||
const timeFormatOption: Intl.DateTimeFormatOptions = {
|
||||
month: 'short',
|
||||
@ -135,7 +135,7 @@
|
||||
};
|
||||
const navigateAssetForward = () => {
|
||||
try {
|
||||
if (currentViewAssetIndex < album.assets.length - 1) {
|
||||
if (currentViewAssetIndex < album.assetCount - 1) {
|
||||
currentViewAssetIndex++;
|
||||
selectedAsset = album.assets[currentViewAssetIndex];
|
||||
pushState(selectedAsset.id);
|
||||
@ -296,7 +296,7 @@
|
||||
{#if !isMultiSelectionMode}
|
||||
<ControlAppBar on:close-button-click={() => goto(backUrl)} backIcon={ArrowLeft}>
|
||||
<svelte:fragment slot="trailing">
|
||||
{#if album.assets.length > 0}
|
||||
{#if album.assetCount > 0}
|
||||
<CircleIconButton
|
||||
title="Add Photos"
|
||||
on:click={() => (isShowAssetSelection = true)}
|
||||
@ -322,7 +322,7 @@
|
||||
|
||||
{#if isCreatingSharedAlbum && album.sharedUsers.length == 0}
|
||||
<button
|
||||
disabled={album.assets.length == 0}
|
||||
disabled={album.assetCount == 0}
|
||||
on:click={() => (isShowShareUserSelection = true)}
|
||||
class="immich-text-button border bg-immich-primary text-gray-50 hover:bg-immich-primary/75 px-6 text-sm disabled:opacity-25 disabled:bg-gray-500 disabled:cursor-not-allowed"
|
||||
><span class="px-2">Share</span></button
|
||||
@ -351,7 +351,7 @@
|
||||
bind:this={titleInput}
|
||||
/>
|
||||
|
||||
{#if album.assets.length > 0}
|
||||
{#if album.assetCount > 0}
|
||||
<p class="my-4 text-sm text-gray-500 font-medium">{getDateRange()}</p>
|
||||
{/if}
|
||||
|
||||
@ -375,11 +375,11 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if album.assets.length > 0}
|
||||
{#if album.assetCount > 0}
|
||||
<div class="flex flex-wrap gap-1 w-full pb-20" bind:clientWidth={viewWidth}>
|
||||
{#each album.assets as asset}
|
||||
{#key asset.id}
|
||||
{#if album.assets.length < 7}
|
||||
{#if album.assetCount < 7}
|
||||
<ImmichThumbnail
|
||||
{asset}
|
||||
{thumbnailSize}
|
||||
|
@ -61,7 +61,7 @@
|
||||
|
||||
// Delete album that has no photos and is named 'Untitled'
|
||||
for (const album of albums) {
|
||||
if (album.albumName === 'Untitled' && album.assets.length === 0) {
|
||||
if (album.albumName === 'Untitled' && album.assetCount === 0) {
|
||||
const isDeleted = await autoDeleteAlbum(album);
|
||||
|
||||
if (isDeleted) {
|
||||
|
Loading…
Reference in New Issue
Block a user