1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2024-12-29 15:11:58 +00:00

feat(web): sort albums in modal (#12331)

This commit is contained in:
Jason Rasmussen 2024-09-04 18:21:21 -04:00 committed by GitHub
parent 0a8bd7dc66
commit 720412645f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 81 additions and 70 deletions

View file

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { groupBy, orderBy } from 'lodash-es'; import { groupBy } from 'lodash-es';
import { addUsersToAlbum, deleteAlbum, type AlbumUserAddDto, type AlbumResponseDto, isHttpError } from '@immich/sdk'; import { addUsersToAlbum, deleteAlbum, type AlbumUserAddDto, type AlbumResponseDto, isHttpError } from '@immich/sdk';
import { mdiDeleteOutline, mdiShareVariantOutline, mdiFolderDownloadOutline, mdiRenameOutline } from '@mdi/js'; import { mdiDeleteOutline, mdiShareVariantOutline, mdiFolderDownloadOutline, mdiRenameOutline } from '@mdi/js';
import EditAlbumForm from '$lib/components/forms/edit-album-form.svelte'; import EditAlbumForm from '$lib/components/forms/edit-album-form.svelte';
@ -17,7 +17,13 @@
import { handleError } from '$lib/utils/handle-error'; import { handleError } from '$lib/utils/handle-error';
import { downloadAlbum } from '$lib/utils/asset-utils'; import { downloadAlbum } from '$lib/utils/asset-utils';
import { normalizeSearchString } from '$lib/utils/string-utils'; import { normalizeSearchString } from '$lib/utils/string-utils';
import { getSelectedAlbumGroupOption, type AlbumGroup, confirmAlbumDelete } from '$lib/utils/album-utils'; import {
getSelectedAlbumGroupOption,
type AlbumGroup,
confirmAlbumDelete,
sortAlbums,
stringToSortOrder,
} from '$lib/utils/album-utils';
import type { ContextMenuPosition } from '$lib/utils/context-menu'; import type { ContextMenuPosition } from '$lib/utils/context-menu';
import { user } from '$lib/stores/user.store'; import { user } from '$lib/stores/user.store';
import { import {
@ -45,10 +51,6 @@
[option: string]: (order: SortOrder, albums: AlbumResponseDto[]) => AlbumGroup[]; [option: string]: (order: SortOrder, albums: AlbumResponseDto[]) => AlbumGroup[];
} }
interface AlbumSortOption {
[option: string]: (order: SortOrder, albums: AlbumResponseDto[]) => AlbumResponseDto[];
}
const groupOptions: AlbumGroupOption = { const groupOptions: AlbumGroupOption = {
/** No grouping */ /** No grouping */
[AlbumGroupBy.None]: (order, albums): AlbumGroup[] => { [AlbumGroupBy.None]: (order, albums): AlbumGroup[] => {
@ -116,41 +118,6 @@
}, },
}; };
const sortOptions: AlbumSortOption = {
/** Sort by album title */
[AlbumSortBy.Title]: (order, albums) => {
const sortSign = order === SortOrder.Desc ? -1 : 1;
return albums.slice().sort((a, b) => a.albumName.localeCompare(b.albumName, $locale) * sortSign);
},
/** Sort by asset count */
[AlbumSortBy.ItemCount]: (order, albums) => {
return orderBy(albums, 'assetCount', [order]);
},
/** Sort by last modified */
[AlbumSortBy.DateModified]: (order, albums) => {
return orderBy(albums, [({ updatedAt }) => new Date(updatedAt)], [order]);
},
/** Sort by creation date */
[AlbumSortBy.DateCreated]: (order, albums) => {
return orderBy(albums, [({ createdAt }) => new Date(createdAt)], [order]);
},
/** Sort by the most recent photo date */
[AlbumSortBy.MostRecentPhoto]: (order, albums) => {
albums = orderBy(albums, [({ endDate }) => (endDate ? new Date(endDate) : '')], [order]);
return albums.sort(sortUnknownYearAlbums);
},
/** Sort by the oldest photo date */
[AlbumSortBy.OldestPhoto]: (order, albums) => {
albums = orderBy(albums, [({ startDate }) => (startDate ? new Date(startDate) : '')], [order]);
return albums.sort(sortUnknownYearAlbums);
},
};
let albums: AlbumResponseDto[] = []; let albums: AlbumResponseDto[] = [];
let filteredAlbums: AlbumResponseDto[] = []; let filteredAlbums: AlbumResponseDto[] = [];
let groupedAlbums: AlbumGroup[] = []; let groupedAlbums: AlbumGroup[] = [];
@ -208,16 +175,10 @@
// Step 4: Sort albums amongst each group. // Step 4: Sort albums amongst each group.
$: { $: {
const defaultSortOption = AlbumSortBy.DateModified;
const selectedSortOption = userSettings.sortBy ?? defaultSortOption;
const sortFunc = sortOptions[selectedSortOption] ?? sortOptions[defaultSortOption];
const sortOrder = stringToSortOrder(userSettings.sortOrder);
groupedAlbums = groupedAlbums.map((group) => ({ groupedAlbums = groupedAlbums.map((group) => ({
id: group.id, id: group.id,
name: group.name, name: group.name,
albums: sortFunc(sortOrder, group.albums), albums: sortAlbums(group.albums, { sortBy: userSettings.sortBy, orderBy: userSettings.sortOrder }),
})); }));
albumGroupIds = groupedAlbums.map(({ id }) => id); albumGroupIds = groupedAlbums.map(({ id }) => id);
@ -231,20 +192,6 @@
} }
}); });
const sortUnknownYearAlbums = (a: AlbumResponseDto, b: AlbumResponseDto) => {
if (!a.endDate) {
return 1;
}
if (!b.endDate) {
return -1;
}
return 0;
};
const stringToSortOrder = (order: string) => {
return order === 'desc' ? SortOrder.Desc : SortOrder.Asc;
};
const showAlbumContextMenu = (contextMenuDetail: ContextMenuPosition, album: AlbumResponseDto) => { const showAlbumContextMenu = (contextMenuDetail: ContextMenuPosition, album: AlbumResponseDto) => {
contextMenuTargetAlbum = album; contextMenuTargetAlbum = album;
contextMenuPosition = { contextMenuPosition = {

View file

@ -8,6 +8,8 @@
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte'; import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
import { initInput } from '$lib/actions/focus'; import { initInput } from '$lib/actions/focus';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
import { sortAlbums } from '$lib/utils/album-utils';
import { albumViewSettings } from '$lib/stores/preferences.store';
let albums: AlbumResponseDto[] = []; let albums: AlbumResponseDto[] = [];
let recentAlbums: AlbumResponseDto[] = []; let recentAlbums: AlbumResponseDto[] = [];
@ -29,14 +31,14 @@
loading = false; loading = false;
}); });
$: { $: filteredAlbums = sortAlbums(
filteredAlbums = search.length > 0 && albums.length > 0
search.length > 0 && albums.length > 0 ? albums.filter((album) => {
? albums.filter((album) => { return normalizeSearchString(album.albumName).includes(normalizeSearchString(search));
return normalizeSearchString(album.albumName).includes(normalizeSearchString(search)); })
}) : albums,
: albums; { sortBy: $albumViewSettings.sortBy, orderBy: $albumViewSettings.sortOrder },
} );
const handleSelect = (album: AlbumResponseDto) => { const handleSelect = (album: AlbumResponseDto) => {
dispatch('album', album); dispatch('album', album);

View file

@ -7,11 +7,13 @@ import {
AlbumSortBy, AlbumSortBy,
SortOrder, SortOrder,
albumViewSettings, albumViewSettings,
locale,
type AlbumViewSettings, type AlbumViewSettings,
} from '$lib/stores/preferences.store'; } from '$lib/stores/preferences.store';
import { handleError } from '$lib/utils/handle-error'; import { handleError } from '$lib/utils/handle-error';
import type { AlbumResponseDto } from '@immich/sdk'; import type { AlbumResponseDto } from '@immich/sdk';
import * as sdk from '@immich/sdk'; import * as sdk from '@immich/sdk';
import { orderBy } from 'lodash-es';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
import { get } from 'svelte/store'; import { get } from 'svelte/store';
@ -213,3 +215,63 @@ export const confirmAlbumDelete = async (album: AlbumResponseDto) => {
return dialogController.show({ prompt }); return dialogController.show({ prompt });
}; };
interface AlbumSortOption {
[option: string]: (order: SortOrder, albums: AlbumResponseDto[]) => AlbumResponseDto[];
}
const sortUnknownYearAlbums = (a: AlbumResponseDto, b: AlbumResponseDto) => {
if (!a.endDate) {
return 1;
}
if (!b.endDate) {
return -1;
}
return 0;
};
export const stringToSortOrder = (order: string) => {
return order === 'desc' ? SortOrder.Desc : SortOrder.Asc;
};
const sortOptions: AlbumSortOption = {
/** Sort by album title */
[AlbumSortBy.Title]: (order, albums) => {
const sortSign = order === SortOrder.Desc ? -1 : 1;
return albums.slice().sort((a, b) => a.albumName.localeCompare(b.albumName, get(locale)) * sortSign);
},
/** Sort by asset count */
[AlbumSortBy.ItemCount]: (order, albums) => {
return orderBy(albums, 'assetCount', [order]);
},
/** Sort by last modified */
[AlbumSortBy.DateModified]: (order, albums) => {
return orderBy(albums, [({ updatedAt }) => new Date(updatedAt)], [order]);
},
/** Sort by creation date */
[AlbumSortBy.DateCreated]: (order, albums) => {
return orderBy(albums, [({ createdAt }) => new Date(createdAt)], [order]);
},
/** Sort by the most recent photo date */
[AlbumSortBy.MostRecentPhoto]: (order, albums) => {
albums = orderBy(albums, [({ endDate }) => (endDate ? new Date(endDate) : '')], [order]);
return albums.sort(sortUnknownYearAlbums);
},
/** Sort by the oldest photo date */
[AlbumSortBy.OldestPhoto]: (order, albums) => {
albums = orderBy(albums, [({ startDate }) => (startDate ? new Date(startDate) : '')], [order]);
return albums.sort(sortUnknownYearAlbums);
},
};
export const sortAlbums = (albums: AlbumResponseDto[], { sortBy, orderBy }: { sortBy: string; orderBy: string }) => {
const sort = sortOptions[sortBy] ?? sortOptions[AlbumSortBy.DateModified];
const order = stringToSortOrder(orderBy);
return sort(order, albums);
};