chore(server,cli,web): housekeeping and stricter code style (#6751)

* add unicorn to eslint

* fix lint errors for cli

* fix merge

* fix album name extraction

* Update cli/src/commands/upload.command.ts

Co-authored-by: Ben McCann <322311+benmccann@users.noreply.github.com>

* es2k23

* use lowercase os

* return undefined album name

* fix bug in asset response dto

* auto fix issues

* fix server code style

* es2022 and formatting

* fix compilation error

* fix test

* fix config load

* fix last lint errors

* set string type

* bump ts

* start work on web

* web formatting

* Fix UUIDParamDto as UUIDParamDto

* fix library service lint

* fix web errors

* fix errors

* formatting

* wip

* lints fixed

* web can now start

* alphabetical package json

* rename error

* chore: clean up

---------

Co-authored-by: Ben McCann <322311+benmccann@users.noreply.github.com>
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
This commit is contained in:
Jonathan Jogenfors
2024-02-02 04:18:00 +01:00
committed by GitHub
parent e4d0560d49
commit f44fa45aa0
218 changed files with 2471 additions and 1244 deletions
+5 -8
View File
@@ -227,11 +227,8 @@
};
const handleChangeListMode = () => {
if ($albumViewSettings.view === AlbumViewMode.Cover) {
$albumViewSettings.view = AlbumViewMode.List;
} else {
$albumViewSettings.view = AlbumViewMode.Cover;
}
$albumViewSettings.view =
$albumViewSettings.view === AlbumViewMode.Cover ? AlbumViewMode.List : AlbumViewMode.Cover;
};
</script>
@@ -285,14 +282,14 @@
</div>
</LinkButton>
</div>
{#if $albums.length !== 0}
{#if $albums.length > 0}
<!-- Album Card -->
{#if $albumViewSettings.view === AlbumViewMode.Cover}
<div class="grid grid-cols-[repeat(auto-fill,minmax(14rem,1fr))]">
{#each $albums as album, idx (album.id)}
{#each $albums as album, index (album.id)}
<a data-sveltekit-preload-data="hover" href="{AppRoute.ALBUMS}/{album.id}" animate:flip={{ duration: 200 }}>
<AlbumCard
preload={idx < 20}
preload={index < 20}
{album}
on:showalbumcontextmenu={(e) => showAlbumContextMenu(e.detail, album)}
/>
@@ -111,14 +111,10 @@
const { selectedAssets: timelineSelected } = timelineInteractionStore;
$: isOwned = $user.id == album.ownerId;
$: isAllUserOwned = Array.from($selectedAssets).every((asset) => asset.ownerId === $user.id);
$: isAllFavorite = Array.from($selectedAssets).every((asset) => asset.isFavorite);
$: isAllUserOwned = [...$selectedAssets].every((asset) => asset.ownerId === $user.id);
$: isAllFavorite = [...$selectedAssets].every((asset) => asset.isFavorite);
$: {
if (isShowActivity) {
assetGridWidth = globalWidth - (globalWidth < 768 ? 360 : 460);
} else {
assetGridWidth = globalWidth;
}
assetGridWidth = isShowActivity ? globalWidth - (globalWidth < 768 ? 360 : 460) : globalWidth;
}
$: showActivityStatus =
album.sharedUsers.length > 0 && !$showAssetViewer && (album.isActivityEnabled || $numberOfComments > 0);
@@ -157,7 +153,7 @@
message: `Activity is ${album.isActivityEnabled ? 'enabled' : 'disabled'}`,
});
} catch (error) {
handleError(error, `Can't ${!album.isActivityEnabled ? 'enable' : 'disable'} activity`);
handleError(error, `Can't ${album.isActivityEnabled ? 'disable' : 'enable'} activity`);
}
};
@@ -224,10 +220,11 @@
}
const ctrl = event.ctrlKey;
switch (event.key) {
case 'Enter':
case 'Enter': {
if (ctrl && event.target === textArea) {
textArea.blur();
}
}
}
};
@@ -302,7 +299,7 @@
};
const handleAddAssets = async () => {
const assetIds = Array.from($timelineSelected).map((asset) => asset.id);
const assetIds = [...$timelineSelected].map((asset) => asset.id);
try {
const { data: results } = await api.albumApi.addAssetsToAlbum({
@@ -352,7 +349,7 @@
const { data } = await api.albumApi.addUsersToAlbum({
id: album.id,
addUsersDto: {
sharedUserIds: Array.from(users).map(({ id }) => id),
sharedUserIds: [...users].map(({ id }) => id),
},
});
@@ -373,8 +370,8 @@
try {
await refreshAlbum();
viewMode = album.sharedUsers.length > 1 ? ViewMode.SELECT_USERS : ViewMode.VIEW;
} catch (e) {
handleError(e, 'Error deleting share users');
} catch (error) {
handleError(error, 'Error deleting share users');
}
};
@@ -20,7 +20,9 @@ describe('Albums BLoC', () => {
afterEach(() => {
const notifications = get(notificationController.notificationList);
notifications.forEach((notification) => notificationController.removeNotificationById(notification.id));
for (const notification of notifications) {
notificationController.removeNotificationById(notification.id);
}
});
it('inits with provided albums', () => {
+3 -3
View File
@@ -3,10 +3,10 @@ import { notificationController, NotificationType } from '$lib/components/shared
import { type AlbumResponseDto, api } from '@api';
import { derived, get, writable } from 'svelte/store';
type AlbumsProps = { albums: AlbumResponseDto[] };
type AlbumsProperties = { albums: AlbumResponseDto[] };
export const useAlbums = (props: AlbumsProps) => {
const albums = writable([...props.albums]);
export const useAlbums = (properties: AlbumsProperties) => {
const albums = writable([...properties.albums]);
const contextMenuPosition = writable<OnShowContextMenuDetail>({ x: 0, y: 0 });
const contextMenuTargetAlbum = writable<AlbumResponseDto | undefined>();
const isShowContextMenu = derived(contextMenuTargetAlbum, ($selectedAlbum) => !!$selectedAlbum);
+1 -1
View File
@@ -24,7 +24,7 @@
const assetInteractionStore = createAssetInteractionStore();
const { isMultiSelectState, selectedAssets } = assetInteractionStore;
$: isAllFavorite = Array.from($selectedAssets).every((asset) => asset.isFavorite);
$: isAllFavorite = [...$selectedAssets].every((asset) => asset.isFavorite);
</script>
{#if $isMultiSelectState}
+1 -1
View File
@@ -26,7 +26,7 @@
const assetInteractionStore = createAssetInteractionStore();
const { isMultiSelectState, selectedAssets } = assetInteractionStore;
$: isAllArchive = Array.from($selectedAssets).every((asset) => asset.isArchived);
$: isAllArchive = [...$selectedAssets].every((asset) => asset.isArchived);
</script>
<!-- Multiselection mode app bar -->
@@ -19,7 +19,7 @@
const assetStore = new AssetStore({ userId: data.partner.id, isArchived: false, withStacked: true });
const assetInteractionStore = createAssetInteractionStore();
const { isMultiSelectState, selectedAssets } = assetInteractionStore;
const { isMultiSelectState, selectedAssets, clearMultiselect } = assetInteractionStore;
onDestroy(() => {
assetInteractionStore.clearMultiselect();
@@ -28,7 +28,7 @@
<main class="grid h-screen bg-immich-bg pt-18 dark:bg-immich-dark-bg">
{#if $isMultiSelectState}
<AssetSelectControlBar assets={$selectedAssets} clearSelect={assetInteractionStore.clearMultiselect}>
<AssetSelectControlBar assets={$selectedAssets} clearSelect={clearMultiselect}>
<CreateSharedLink />
<AssetSelectContextMenu icon={mdiPlus} title="Add">
<AddToAlbum />
+9 -10
View File
@@ -90,9 +90,10 @@
return;
}
switch (event.key) {
case 'Escape':
case 'Escape': {
handleCloseClick();
return;
}
}
};
@@ -288,10 +289,8 @@
}
return;
}
if (!force) {
if (people.length < maximumLengthSearchPeople && searchName.startsWith(searchWord)) {
return;
}
if (!force && people.length < maximumLengthSearchPeople && searchName.startsWith(searchWord)) {
return;
}
const timeout = setTimeout(() => (isSearchingPeople = true), timeBeforeShowLoadingSpinner);
@@ -417,7 +416,7 @@
</FullScreenModal>
{/if}
<UserPageLayout title="People" description={countTotalPeople !== 0 ? `(${countTotalPeople.toString()})` : undefined}>
<UserPageLayout title="People" description={countTotalPeople === 0 ? undefined : `(${countTotalPeople.toString()})`}>
<svelte:fragment slot="buttons">
{#if countTotalPeople > 0}
<div class="flex gap-2 items-center justify-center">
@@ -445,11 +444,11 @@
{#if countVisiblePeople > 0}
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 xl:grid-cols-7 2xl:grid-cols-9 gap-1">
{#each people as person, idx (person.id)}
{#each people as person, index (person.id)}
{#if !person.isHidden && (searchName ? searchedPeopleLocal.some((searchedPerson) => searchedPerson.id === person.id) : true)}
<PeopleCard
{person}
preload={idx < 20}
preload={index < 20}
on:change-name={() => handleChangeName(person)}
on:set-birth-date={() => handleSetBirthDate(person)}
on:merge-people={() => handleMergePeople(person)}
@@ -519,7 +518,7 @@
screenHeight={innerHeight}
>
<div class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 xl:grid-cols-7 2xl:grid-cols-9 gap-1">
{#each people as person, idx (person.id)}
{#each people as person, index (person.id)}
<button
class="relative"
on:click={() => (person.isHidden = !person.isHidden)}
@@ -527,7 +526,7 @@
on:mouseleave={() => (eyeColorMap[person.id] = 'white')}
>
<ImageThumbnail
preload={searchName !== '' || idx < 20}
preload={searchName !== '' || index < 20}
bind:hidden={person.isHidden}
shadow
url={api.getPeopleThumbnailUrl(person.id)}
@@ -108,14 +108,14 @@
isSearchingPeople = false;
};
$: isAllArchive = Array.from($selectedAssets).every((asset) => asset.isArchived);
$: isAllFavorite = Array.from($selectedAssets).every((asset) => asset.isFavorite);
$: isAllArchive = [...$selectedAssets].every((asset) => asset.isArchived);
$: isAllFavorite = [...$selectedAssets].every((asset) => asset.isFavorite);
$: $onPersonThumbnail === data.person.id &&
(thumbnailData = api.getPeopleThumbnailUrl(data.person.id) + `?now=${Date.now()}`);
$: {
if (people) {
suggestedPeople = !name ? [] : searchNameLocal(name, people, 5, data.person.id);
suggestedPeople = name ? searchNameLocal(name, people, 5, data.person.id) : [];
}
}
@@ -158,7 +158,7 @@
});
const handleUnmerge = () => {
$assetStore.removeAssets(Array.from($selectedAssets).map((a) => a.id));
$assetStore.removeAssets([...$selectedAssets].map((a) => a.id));
assetInteractionStore.clearMultiselect();
viewMode = ViewMode.VIEW_ASSETS;
};
@@ -352,7 +352,7 @@
{#if viewMode === ViewMode.UNASSIGN_ASSETS}
<UnMergeFaceSelector
assetIds={Array.from($selectedAssets).map((a) => a.id)}
assetIds={[...$selectedAssets].map((a) => a.id)}
personAssets={data.person}
on:close={() => (viewMode = ViewMode.VIEW_ASSETS)}
on:confirm={handleUnmerge}
+1 -1
View File
@@ -31,7 +31,7 @@
const assetInteractionStore = createAssetInteractionStore();
const { isMultiSelectState, selectedAssets } = assetInteractionStore;
$: isAllFavorite = Array.from($selectedAssets).every((asset) => asset.isFavorite);
$: isAllFavorite = [...$selectedAssets].every((asset) => asset.isFavorite);
const handleEscape = () => {
if ($showAssetViewer) {
+7 -6
View File
@@ -56,7 +56,7 @@
}
if (!$showAssetViewer) {
switch (event.key) {
case 'Escape':
case 'Escape': {
if (isMultiSelectionMode) {
selectedAssets = new Set();
return;
@@ -66,6 +66,7 @@
}
$preventRaceConditionSearchBar = false;
return;
}
}
}
};
@@ -96,8 +97,8 @@
let selectedAssets: Set<AssetResponseDto> = new Set();
$: isMultiSelectionMode = selectedAssets.size > 0;
$: isAllArchived = Array.from(selectedAssets).every((asset) => asset.isArchived);
$: isAllFavorite = Array.from(selectedAssets).every((asset) => asset.isFavorite);
$: isAllArchived = [...selectedAssets].every((asset) => asset.isArchived);
$: isAllFavorite = [...selectedAssets].every((asset) => asset.isFavorite);
$: searchResultAssets = data.results?.assets.items;
const onAssetDelete = (assetId: string) => {
@@ -140,14 +141,14 @@
<section class="relative mb-12 bg-immich-bg pt-32 dark:bg-immich-dark-bg">
<section class="immich-scrollbar relative overflow-y-auto">
{#if albums && albums.length}
{#if albums && albums.length > 0}
<section>
<div class="ml-6 text-4xl font-medium text-black/70 dark:text-white/80">ALBUMS</div>
<div class="grid grid-cols-[repeat(auto-fill,minmax(14rem,1fr))]">
{#each albums as album, idx (album.id)}
{#each albums as album, index (album.id)}
<a data-sveltekit-preload-data="hover" href={`albums/${album.id}`} animate:flip={{ duration: 200 }}>
<AlbumCard
preload={idx < 20}
preload={index < 20}
{album}
isSharingView={false}
showItemCount={false}
@@ -11,8 +11,8 @@
import { user } from '$lib/stores/user.store';
export let data: PageData;
let { sharedLink, passwordRequired, sharedLinkKey: key } = data;
let { title, description } = data.meta;
let { sharedLink, passwordRequired, sharedLinkKey: key, meta } = data;
let { title, description } = meta;
let isOwned = $user ? $user.id === sharedLink?.userId : false;
let password = '';
+4 -4
View File
@@ -1,8 +1,8 @@
import { getAuthUser } from '$lib/utils/auth';
import { api, ThumbnailFormat } from '@api';
import { error } from '@sveltejs/kit';
import type { AxiosError } from 'axios';
import type { PageLoad } from './$types';
import { error as throwError } from '@sveltejs/kit';
export const load = (async ({ params }) => {
const { key } = params;
@@ -24,10 +24,10 @@ export const load = (async ({ params }) => {
: '/feature-panel.png',
},
};
} catch (e) {
} catch (error) {
// handle unauthorized error
// TODO this doesn't allow for 404 shared links anymore
if ((e as AxiosError).response?.status === 401) {
if ((error as AxiosError).response?.status === 401) {
return {
passwordRequired: true,
sharedLinkKey: key,
@@ -37,7 +37,7 @@ export const load = (async ({ params }) => {
};
}
error(404, {
throwError(404, {
message: 'Invalid shared link',
});
}
+4 -4
View File
@@ -28,13 +28,13 @@
});
goto(`${AppRoute.ALBUMS}/${newAlbum.id}`);
} catch (e) {
} catch (error) {
notificationController.show({
message: 'Error creating album, check console for more details',
type: NotificationType.Error,
});
console.log('Error [createAlbum] ', e);
console.log('Error [createAlbum]', error);
}
};
</script>
@@ -94,9 +94,9 @@
<div>
<!-- Share Album List -->
<div class="grid grid-cols-[repeat(auto-fill,minmax(14rem,1fr))]">
{#each data.sharedAlbums as album, idx (album.id)}
{#each data.sharedAlbums as album, index (album.id)}
<a data-sveltekit-preload-data="hover" href={`albums/${album.id}`} animate:flip={{ duration: 200 }}>
<AlbumCard preload={idx < 20} {album} isSharingView showContextMenu={false} />
<AlbumCard preload={index < 20} {album} isSharingView showContextMenu={false} />
</a>
{/each}
</div>
+4 -4
View File
@@ -43,8 +43,8 @@
message: `Empty trash initiated. Refresh the page to see the changes`,
type: NotificationType.Info,
});
} catch (e) {
handleError(e, 'Error emptying trash');
} catch (error) {
handleError(error, 'Error emptying trash');
}
};
@@ -56,8 +56,8 @@
message: `Restore trash initiated. Refresh the page to see the changes`,
type: NotificationType.Info,
});
} catch (e) {
handleError(e, 'Error restoring trash');
} catch (error) {
handleError(error, 'Error restoring trash');
}
};
</script>
@@ -22,7 +22,7 @@
onMount(async () => {
await load();
timer = setInterval(load, 5_000);
timer = setInterval(load, 5000);
});
onDestroy(() => {
+8 -8
View File
@@ -44,7 +44,7 @@
downloadManager.add(downloadKey, blob.size);
downloadManager.update(downloadKey, blob.size);
downloadBlob(blob, downloadKey);
setTimeout(() => downloadManager.clear(downloadKey), 5_000);
setTimeout(() => downloadManager.clear(downloadKey), 5000);
}
if (orphans.length > 0) {
@@ -53,7 +53,7 @@
downloadManager.add(downloadKey, blob.size);
downloadManager.update(downloadKey, blob.size);
downloadBlob(blob, downloadKey);
setTimeout(() => downloadManager.clear(downloadKey), 5_000);
setTimeout(() => downloadManager.clear(downloadKey), 5000);
}
};
@@ -130,9 +130,9 @@
try {
const chunkSize = 10;
const filenames = [...extras.filter(({ checksum }) => !checksum).map(({ filename }) => filename)];
for (let i = 0; i < filenames.length; i += chunkSize) {
count += await loadAndMatch(filenames.slice(i, i + chunkSize));
const filenames = extras.filter(({ checksum }) => !checksum).map(({ filename }) => filename);
for (let index = 0; index < filenames.length; index += chunkSize) {
count += await loadAndMatch(filenames.slice(index, index + chunkSize));
}
} catch (error) {
handleError(error, 'Unable to check items');
@@ -218,7 +218,7 @@
<tr class="flex w-full place-items-center p-2 md:p-5">
<th class="w-full text-sm place-items-center font-medium flex justify-between" colspan="2">
<div class="px-3">
<p>MATCHES {matches.length ? `(${matches.length})` : ''}</p>
<p>MATCHES {matches.length > 0 ? `(${matches.length})` : ''}</p>
<p class="text-gray-600 dark:text-gray-300 mt-1">These files are matched by their checksums</p>
</div>
</th>
@@ -252,7 +252,7 @@
<tr class="flex w-full place-items-center p-1 md:p-5">
<th class="w-full text-sm font-medium justify-between place-items-center flex" colspan="2">
<div class="px-3">
<p>OFFLINE PATHS {orphans.length ? `(${orphans.length})` : ''}</p>
<p>OFFLINE PATHS {orphans.length > 0 ? `(${orphans.length})` : ''}</p>
<p class="text-gray-600 dark:text-gray-300 mt-1">
These files are the results of manually deletion of the default upload library
</p>
@@ -290,7 +290,7 @@
<tr class="flex w-full place-items-center p-2 md:p-5">
<th class="w-full text-sm font-medium place-items-center flex justify-between" colspan="2">
<div class="px-3">
<p>UNTRACKS FILES {extras.length ? `(${extras.length})` : ''}</p>
<p>UNTRACKS FILES {extras.length > 0 ? `(${extras.length})` : ''}</p>
<p class="text-gray-600 dark:text-gray-300 mt-1">
These files are not tracked by the application. They can be the results of failed moves,
interrupted uploads, or left behind due to a bug
@@ -38,7 +38,7 @@
downloadManager.add(downloadKey, blob.size);
downloadManager.update(downloadKey, blob.size);
downloadBlob(blob, downloadKey);
setTimeout(() => downloadManager.clear(downloadKey), 5_000);
setTimeout(() => downloadManager.clear(downloadKey), 5000);
};
const settings = [
@@ -31,7 +31,7 @@
});
const isDeleted = (user: UserResponseDto): boolean => {
return user.deletedAt != null;
return user.deletedAt != undefined;
};
const deleteDateFormat: Intl.DateTimeFormatOptions = {
@@ -41,7 +41,7 @@
};
const getDeleteDate = (user: UserResponseDto): string => {
let deletedAt = new Date(user.deletedAt ? user.deletedAt : Date.now());
let deletedAt = new Date(user.deletedAt ?? Date.now());
deletedAt.setDate(deletedAt.getDate() + 7);
return deletedAt.toLocaleString($locale, deleteDateFormat);
};
@@ -188,13 +188,13 @@
</thead>
<tbody class="block max-h-[320px] w-full overflow-y-auto rounded-md border dark:border-immich-dark-gray">
{#if allUsers}
{#each allUsers as immichUser, i}
{#each allUsers as immichUser, index}
<tr
class="flex h-[80px] overflow-hidden w-full place-items-center text-center dark:text-immich-dark-fg {isDeleted(
immichUser,
)
? 'bg-red-300 dark:bg-red-900'
: i % 2 == 0
: index % 2 == 0
? 'bg-immich-gray dark:bg-immich-dark-gray/75'
: 'bg-immich-bg dark:bg-immich-dark-gray/50'}"
>
+2 -2
View File
@@ -22,8 +22,8 @@
$: {
const stepState = $page.url.searchParams.get('step');
const tempIndex = onboardingSteps.findIndex((step) => step.name === stepState);
index = tempIndex >= 0 ? tempIndex : 0;
const temporaryIndex = onboardingSteps.findIndex((step) => step.name === stepState);
index = temporaryIndex >= 0 ? temporaryIndex : 0;
}
const handleDoneClicked = async () => {