1
0
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:
Alex 2022-08-10 22:48:25 -05:00 committed by GitHub
parent bd5ed1b684
commit 5c78f707fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 46 additions and 26 deletions

View File

@ -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',

View File

@ -203,7 +203,7 @@ class AlbumViewerPage extends HookConsumerWidget {
assetList: albumInfo.assets,
);
},
childCount: albumInfo.assets.length,
childCount: albumInfo.assetCount,
),
),
);

View File

@ -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());

View File

@ -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> {

View File

@ -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

View File

@ -90,6 +90,12 @@ export interface AdminSignupResponseDto {
* @interface AlbumResponseDto
*/
export interface AlbumResponseDto {
/**
*
* @type {number}
* @memberof AlbumResponseDto
*/
'assetCount': number;
/**
*
* @type {string}

View File

@ -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>

View File

@ -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}

View File

@ -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) {