fix: album sorting options (#5127)

* fix: album sort options

* fix: don't load assets

* pr feedback

* fix: albumStub

* fix(web): album shared without assets

* fix: tests

---------

Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
martin
2023-11-20 20:01:21 +01:00
committed by GitHub
parent 347e6191c5
commit 725f30c494
13 changed files with 180 additions and 109 deletions

View File

@@ -5,10 +5,10 @@
export let option: Sort;
const handleSort = () => {
if (albumViewSettings === option.sortTitle) {
if (albumViewSettings === option.title) {
option.sortDesc = !option.sortDesc;
} else {
albumViewSettings = option.sortTitle;
albumViewSettings = option.title;
}
};
</script>
@@ -18,12 +18,12 @@
class="rounded-lg p-2 hover:bg-immich-dark-primary hover:dark:bg-immich-dark-primary/50"
on:click={() => handleSort()}
>
{#if albumViewSettings === option.sortTitle}
{#if albumViewSettings === option.title}
{#if option.sortDesc}
&#8595;
{:else}
&#8593;
{/if}
{/if}{option.table}</button
{/if}{option.title}</button
></th
>

View File

@@ -7,6 +7,7 @@
import { createEventDispatcher } from 'svelte';
import { goto } from '$app/navigation';
import { mdiCircleEditOutline, mdiContentCopy, mdiDelete, mdiOpenInNew } from '@mdi/js';
import noThumbnailUrl from '$lib/assets/no-thumbnail.png';
export let link: SharedLinkResponseDto;
@@ -60,18 +61,28 @@
class="flex w-full gap-4 border-b border-gray-200 py-4 transition-all hover:border-immich-primary dark:border-gray-600 dark:text-immich-gray dark:hover:border-immich-dark-primary"
>
<div>
{#await getAssetInfo()}
<LoadingSpinner />
{:then asset}
{#if (link?.album?.assetCount && link?.album?.assetCount > 0) || link.assets.length > 0}
{#await getAssetInfo()}
<LoadingSpinner />
{:then asset}
<img
id={asset.id}
src={api.getAssetThumbnailUrl(asset.id, ThumbnailFormat.Webp)}
alt={asset.id}
class="h-[100px] w-[100px] rounded-lg object-cover"
loading="lazy"
draggable="false"
/>
{/await}
{:else}
<img
id={asset.id}
src={api.getAssetThumbnailUrl(asset.id, ThumbnailFormat.Webp)}
alt={asset.id}
src={noThumbnailUrl}
alt={'Album without assets'}
class="h-[100px] w-[100px] rounded-lg object-cover"
loading="lazy"
draggable="false"
/>
{/await}
{/if}
</div>
<div class="flex flex-col justify-between">

View File

@@ -1,9 +1,6 @@
<script lang="ts" context="module">
// table is the text printed in the table and sortTitle is the text printed in the dropDow menu
export interface Sort {
table: string;
sortTitle: string;
title: string;
sortDesc: boolean;
widthClass: string;
sortFn: (reverse: boolean, albums: AlbumResponseDto[]) => AlbumResponseDto[];
@@ -54,46 +51,75 @@
let sortByOptions: Record<string, Sort> = {
albumTitle: {
table: 'Album title',
sortTitle: 'Album title',
title: 'Album title',
sortDesc: $albumViewSettings.sortDesc, // Load Sort Direction
widthClass: 'w-8/12 text-left sm:w-4/12 md:w-4/12 md:w-4/12 2xl:w-6/12',
widthClass: 'text-left w-8/12 sm:w-4/12 md:w-4/12 md:w-4/12 xl:w-[30%] 2xl:w-[40%]',
sortFn: (reverse, albums) => {
return orderBy(albums, 'albumName', [reverse ? 'desc' : 'asc']);
},
},
numberOfAssets: {
table: 'Assets',
sortTitle: 'Number of assets',
title: 'Number of assets',
sortDesc: $albumViewSettings.sortDesc,
widthClass: 'w-4/12 text-center sm:w-2/12 2xl:w-1/12',
widthClass: 'text-center w-4/12 m:w-2/12 md:w-2/12 xl:w-[15%] 2xl:w-[12%]',
sortFn: (reverse, albums) => {
return orderBy(albums, 'assetCount', [reverse ? 'desc' : 'asc']);
},
},
lastModified: {
table: 'Updated date',
sortTitle: 'Last modified',
title: 'Last modified',
sortDesc: $albumViewSettings.sortDesc,
widthClass: 'text-center hidden sm:block w-3/12 lg:w-2/12',
widthClass: 'text-center hidden sm:block w-3/12 xl:w-[15%] 2xl:w-[12%]',
sortFn: (reverse, albums) => {
return orderBy(albums, [(album) => new Date(album.updatedAt)], [reverse ? 'desc' : 'asc']);
},
},
mostRecent: {
table: 'Created date',
sortTitle: 'Most recent photo',
created: {
title: 'Created date',
sortDesc: $albumViewSettings.sortDesc,
widthClass: 'text-center hidden sm:block w-3/12 lg:w-2/12',
widthClass: 'text-center hidden sm:block w-3/12 xl:w-[15%] 2xl:w-[12%]',
sortFn: (reverse, albums) => {
return orderBy(albums, [(album) => new Date(album.createdAt)], [reverse ? 'desc' : 'asc']);
},
},
mostRecent: {
title: 'Most recent photo',
sortDesc: $albumViewSettings.sortDesc,
widthClass: 'text-center hidden xl:block xl:w-[15%] 2xl:w-[12%]',
sortFn: (reverse, albums) => {
return orderBy(
albums,
[
(album) =>
album.lastModifiedAssetTimestamp ? new Date(album.lastModifiedAssetTimestamp) : new Date(album.updatedAt),
],
[(album) => (album.endDate ? new Date(album.endDate) : '')],
[reverse ? 'desc' : 'asc'],
);
).sort((a, b) => {
if (a.endDate === undefined) {
return 1;
}
if (b.endDate === undefined) {
return -1;
}
return 0;
});
},
},
mostOld: {
title: 'Oldest photo',
sortDesc: $albumViewSettings.sortDesc,
widthClass: 'text-center hidden xl:block xl:w-[15%] 2xl:w-[12%]',
sortFn: (reverse, albums) => {
return orderBy(
albums,
[(album) => (album.startDate ? new Date(album.startDate) : null)],
[reverse ? 'desc' : 'asc'],
).sort((a, b) => {
if (a.startDate === undefined) {
return 1;
}
if (b.startDate === undefined) {
return -1;
}
return 0;
});
},
},
};
@@ -144,16 +170,25 @@
};
$: {
const { sortBy } = $albumViewSettings;
for (const key in sortByOptions) {
if (sortByOptions[key].sortTitle === sortBy) {
if (sortByOptions[key].title === $albumViewSettings.sortBy) {
$albums = sortByOptions[key].sortFn(sortByOptions[key].sortDesc, $unsortedAlbums);
$albumViewSettings.sortDesc = sortByOptions[key].sortDesc; // "Save" sortDesc
$albumViewSettings.sortBy = sortByOptions[key].title;
break;
}
}
}
const test = (searched: string): Sort => {
for (const key in sortByOptions) {
if (sortByOptions[key].title === searched) {
return sortByOptions[key];
}
}
return sortByOptions[0];
};
const handleCreateAlbum = async () => {
const newAlbum = await createAlbum();
if (newAlbum) {
@@ -220,19 +255,20 @@
<Dropdown
options={Object.values(sortByOptions)}
selectedOption={test($albumViewSettings.sortBy)}
render={(option) => {
return {
title: option.sortTitle,
title: option.title,
icon: option.sortDesc ? mdiArrowDownThin : mdiArrowUpThin,
};
}}
on:select={(event) => {
for (const key in sortByOptions) {
if (sortByOptions[key].sortTitle === event.detail.sortTitle) {
if (sortByOptions[key].title === event.detail.title) {
sortByOptions[key].sortDesc = !sortByOptions[key].sortDesc;
$albumViewSettings.sortBy = sortByOptions[key].title;
}
}
$albumViewSettings.sortBy = event.detail.sortTitle;
}}
/>
@@ -271,7 +307,7 @@
{#each Object.keys(sortByOptions) as key (key)}
<TableHeader bind:albumViewSettings={$albumViewSettings.sortBy} bind:option={sortByOptions[key]} />
{/each}
<th class="hidden w-2/12 text-center text-sm font-medium lg:block 2xl:w-1/12">Action</th>
<th class="hidden text-center text-sm font-medium 2xl:block 2xl:w-[12%]">Action</th>
</tr>
</thead>
<tbody
@@ -284,18 +320,34 @@
on:keydown={(event) => event.key === 'Enter' && goto(`albums/${album.id}`)}
tabindex="0"
>
<td class="text-md w-8/12 text-ellipsis text-left sm:w-4/12 md:w-4/12 2xl:w-6/12">{album.albumName}</td>
<td class="text-md w-4/12 text-ellipsis text-center sm:w-2/12 md:w-2/12 2xl:w-1/12">
{album.assetCount}
{album.assetCount == 1 ? `item` : `items`}
</td>
<td class="text-md hidden w-3/12 text-ellipsis text-center sm:block lg:w-2/12"
>{dateLocaleString(album.updatedAt)}</td
<td class="text-md text-ellipsis text-left w-8/12 sm:w-4/12 md:w-4/12 xl:w-[30%] 2xl:w-[40%]"
>{album.albumName}</td
>
<td class="text-md hidden w-3/12 text-ellipsis text-center sm:block lg:w-2/12"
<td class="text-md text-ellipsis text-center sm:w-2/12 md:w-2/12 xl:w-[15%] 2xl:w-[12%]">
{album.assetCount}
{album.assetCount > 1 ? `items` : `item`}
</td>
<td class="text-md hidden text-ellipsis text-center sm:block w-3/12 xl:w-[15%] 2xl:w-[12%]"
>{dateLocaleString(album.updatedAt)}
</td>
<td class="text-md hidden text-ellipsis text-center sm:block w-3/12 xl:w-[15%] 2xl:w-[12%]"
>{dateLocaleString(album.createdAt)}</td
>
<td class="text-md hidden w-2/12 text-ellipsis text-center lg:block 2xl:w-1/12">
<td class="text-md text-ellipsis text-center hidden xl:block xl:w-[15%] 2xl:w-[12%]">
{#if album.endDate}
{dateLocaleString(album.endDate)}
{:else}
&#10060;
{/if}</td
>
<td class="text-md text-ellipsis text-center hidden xl:block xl:w-[15%] 2xl:w-[12%]"
>{#if album.startDate}
{dateLocaleString(album.startDate)}
{:else}
&#10060;
{/if}</td
>
<td class="text-md hidden text-ellipsis text-center 2xl:block xl:w-[15%] 2xl:w-[12%]">
<button
on:click|stopPropagation={() => handleEdit(album)}
class="rounded-full bg-immich-primary p-3 text-gray-100 transition-all duration-150 hover:bg-immich-primary/75 dark:bg-immich-dark-primary dark:text-gray-700"