chore(web): improve type checking (#2644)
* fix(web): use id instead of assetId * chore(web): improve type checking * fix test jobs * improve type checking and resolve errors
This commit is contained in:
parent
47673dd773
commit
9807f76aff
33 changed files with 149 additions and 129 deletions
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
|
@ -96,7 +96,11 @@ jobs:
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
- name: Run svelte checks
|
- name: Run svelte checks
|
||||||
run: npm run check
|
run: npm run check:svelte
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
|
- name: Run tsc
|
||||||
|
run: npm run check:typescript
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
|
|
||||||
- name: Run unit tests & coverage
|
- name: Run unit tests & coverage
|
||||||
|
|
|
@ -6,9 +6,10 @@
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"package": "svelte-kit package",
|
"package": "svelte-kit package",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"check": "svelte-check --no-tsconfig --fail-on-warnings --ignore \"src/api/open-api\"",
|
"check:svelte": "svelte-check --no-tsconfig --fail-on-warnings --ignore \"src/api/open-api\"",
|
||||||
"check:watch": "npm run check -- --watch",
|
"check:typescript": "tsc --noEmit",
|
||||||
"check:code": "npm run format && npm run lint && npm run check",
|
"check:watch": "npm run check:svelte -- --watch",
|
||||||
|
"check:code": "npm run format && npm run lint && npm run check:svelte && npm run check:typescript",
|
||||||
"check:all": "npm run check:code && npm run test:cov",
|
"check:all": "npm run check:code && npm run test:cov",
|
||||||
"lint": "eslint . --max-warnings 0",
|
"lint": "eslint . --max-warnings 0",
|
||||||
"lint:fix": "npm run lint -- --fix",
|
"lint:fix": "npm run lint -- --fix",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { AxiosError, AxiosPromise } from 'axios';
|
import type { AxiosError, AxiosPromise } from 'axios';
|
||||||
import { api } from './api';
|
import { api } from './api';
|
||||||
import { UserResponseDto } from './open-api';
|
import type { UserResponseDto } from './open-api';
|
||||||
|
|
||||||
export type ApiError = AxiosError<{ message: string }>;
|
export type ApiError = AxiosError<{ message: string }>;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type { Handle, HandleServerError } from '@sveltejs/kit';
|
|
||||||
import { AxiosError, AxiosResponse } from 'axios';
|
|
||||||
import { env } from '$env/dynamic/public';
|
import { env } from '$env/dynamic/public';
|
||||||
|
import type { Handle, HandleServerError } from '@sveltejs/kit';
|
||||||
|
import type { AxiosError, AxiosResponse } from 'axios';
|
||||||
import { ImmichApi } from './api/api';
|
import { ImmichApi } from './api/api';
|
||||||
|
|
||||||
export const handle = (async ({ event, resolve }) => {
|
export const handle = (async ({ event, resolve }) => {
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
notificationController,
|
notificationController,
|
||||||
NotificationType
|
NotificationType
|
||||||
} from '$lib/components/shared-components/notification/notification';
|
} from '$lib/components/shared-components/notification/notification';
|
||||||
|
import { AppRoute } from '$lib/constants';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { AllJobStatusResponseDto, api, JobCommand, JobCommandDto, JobName } from '@api';
|
import { AllJobStatusResponseDto, api, JobCommand, JobCommandDto, JobName } from '@api';
|
||||||
import type { ComponentType } from 'svelte';
|
import type { ComponentType } from 'svelte';
|
||||||
import Icon from 'svelte-material-icons/DotsVertical.svelte';
|
import type Icon from 'svelte-material-icons/DotsVertical.svelte';
|
||||||
import FaceRecognition from 'svelte-material-icons/FaceRecognition.svelte';
|
import FaceRecognition from 'svelte-material-icons/FaceRecognition.svelte';
|
||||||
import FileJpgBox from 'svelte-material-icons/FileJpgBox.svelte';
|
import FileJpgBox from 'svelte-material-icons/FileJpgBox.svelte';
|
||||||
import FileXmlBox from 'svelte-material-icons/FileXmlBox.svelte';
|
import FileXmlBox from 'svelte-material-icons/FileXmlBox.svelte';
|
||||||
|
@ -19,7 +20,6 @@
|
||||||
import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
|
import ConfirmDialogue from '../../shared-components/confirm-dialogue.svelte';
|
||||||
import JobTile from './job-tile.svelte';
|
import JobTile from './job-tile.svelte';
|
||||||
import StorageMigrationDescription from './storage-migration-description.svelte';
|
import StorageMigrationDescription from './storage-migration-description.svelte';
|
||||||
import { AppRoute } from '$lib/constants';
|
|
||||||
|
|
||||||
export let jobs: AllJobStatusResponseDto;
|
export let jobs: AllJobStatusResponseDto;
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ServerStatsResponseDto } from '@api';
|
|
||||||
import CameraIris from 'svelte-material-icons/CameraIris.svelte';
|
|
||||||
import PlayCircle from 'svelte-material-icons/PlayCircle.svelte';
|
|
||||||
import Memory from 'svelte-material-icons/Memory.svelte';
|
|
||||||
import StatsCard from './stats-card.svelte';
|
|
||||||
import { asByteUnitString, getBytesWithUnit } from '../../../utils/byte-units';
|
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
|
import type { ServerStatsResponseDto } from '@api';
|
||||||
|
import CameraIris from 'svelte-material-icons/CameraIris.svelte';
|
||||||
|
import Memory from 'svelte-material-icons/Memory.svelte';
|
||||||
|
import PlayCircle from 'svelte-material-icons/PlayCircle.svelte';
|
||||||
|
import { asByteUnitString, getBytesWithUnit } from '../../../utils/byte-units';
|
||||||
|
import StatsCard from './stats-card.svelte';
|
||||||
|
|
||||||
export let stats: ServerStatsResponseDto = {
|
export let stats: ServerStatsResponseDto = {
|
||||||
photos: 0,
|
photos: 0,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { SystemConfigTemplateStorageOptionDto } from '@api';
|
import type { SystemConfigTemplateStorageOptionDto } from '@api';
|
||||||
import * as luxon from 'luxon';
|
import * as luxon from 'luxon';
|
||||||
|
|
||||||
export let options: SystemConfigTemplateStorageOptionDto;
|
export let options: SystemConfigTemplateStorageOptionDto;
|
||||||
|
|
|
@ -37,7 +37,7 @@ describe('AlbumCard component', () => {
|
||||||
])(
|
])(
|
||||||
'shows album data without thumbnail with count $count - shared: $shared',
|
'shows album data without thumbnail with count $count - shared: $shared',
|
||||||
async ({ album, count, shared }) => {
|
async ({ album, count, shared }) => {
|
||||||
sut = render(AlbumCard, { album });
|
sut = render(AlbumCard, { album, user: album.owner });
|
||||||
|
|
||||||
const albumImgElement = sut.getByTestId('album-image');
|
const albumImgElement = sut.getByTestId('album-image');
|
||||||
const albumNameElement = sut.getByTestId('album-name');
|
const albumNameElement = sut.getByTestId('album-name');
|
||||||
|
@ -58,10 +58,10 @@ describe('AlbumCard component', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
it('shows album data and and loads the thumbnail image when available', async () => {
|
it('shows album data and and loads the thumbnail image when available', async () => {
|
||||||
const thumbnailBlob = new Blob();
|
const thumbnailFile = new File([new Blob()], 'fileThumbnail');
|
||||||
const thumbnailUrl = 'blob:thumbnailUrlOne';
|
const thumbnailUrl = 'blob:thumbnailUrlOne';
|
||||||
apiMock.assetApi.getAssetThumbnail.mockResolvedValue({
|
apiMock.assetApi.getAssetThumbnail.mockResolvedValue({
|
||||||
data: thumbnailBlob,
|
data: thumbnailFile,
|
||||||
config: {},
|
config: {},
|
||||||
headers: {},
|
headers: {},
|
||||||
status: 200,
|
status: 200,
|
||||||
|
@ -74,7 +74,7 @@ describe('AlbumCard component', () => {
|
||||||
shared: false,
|
shared: false,
|
||||||
albumName: 'some album name'
|
albumName: 'some album name'
|
||||||
});
|
});
|
||||||
sut = render(AlbumCard, { album });
|
sut = render(AlbumCard, { album, user: album.owner });
|
||||||
|
|
||||||
const albumImgElement = sut.getByTestId('album-image');
|
const albumImgElement = sut.getByTestId('album-image');
|
||||||
const albumNameElement = sut.getByTestId('album-name');
|
const albumNameElement = sut.getByTestId('album-name');
|
||||||
|
@ -92,7 +92,7 @@ describe('AlbumCard component', () => {
|
||||||
},
|
},
|
||||||
{ responseType: 'blob' }
|
{ responseType: 'blob' }
|
||||||
);
|
);
|
||||||
expect(createObjectURLMock).toHaveBeenCalledWith(thumbnailBlob);
|
expect(createObjectURLMock).toHaveBeenCalledWith(thumbnailFile);
|
||||||
|
|
||||||
expect(albumNameElement).toHaveTextContent('some album name');
|
expect(albumNameElement).toHaveTextContent('some album name');
|
||||||
expect(albumDetailsElement).toHaveTextContent('0 items');
|
expect(albumDetailsElement).toHaveTextContent('0 items');
|
||||||
|
@ -102,7 +102,7 @@ describe('AlbumCard component', () => {
|
||||||
const album = Object.freeze(albumFactory.build({ albumThumbnailAssetId: null }));
|
const album = Object.freeze(albumFactory.build({ albumThumbnailAssetId: null }));
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
sut = render(AlbumCard, { album });
|
sut = render(AlbumCard, { album, user: album.owner });
|
||||||
|
|
||||||
const albumImgElement = sut.getByTestId('album-image');
|
const albumImgElement = sut.getByTestId('album-image');
|
||||||
await waitFor(() => expect(albumImgElement).toHaveAttribute('src'));
|
await waitFor(() => expect(albumImgElement).toHaveAttribute('src'));
|
||||||
|
|
|
@ -1,23 +1,11 @@
|
||||||
<script lang="ts" context="module">
|
|
||||||
type OnShowContextMenu = {
|
|
||||||
showalbumcontextmenu: OnShowContextMenuDetail;
|
|
||||||
};
|
|
||||||
|
|
||||||
type OnClick = {
|
|
||||||
click: OnClickDetail;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type OnShowContextMenuDetail = { x: number; y: number };
|
|
||||||
export type OnClickDetail = AlbumResponseDto;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import noThumbnailUrl from '$lib/assets/no-thumbnail.png';
|
||||||
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
import { AlbumResponseDto, api, ThumbnailFormat, UserResponseDto } from '@api';
|
import { AlbumResponseDto, api, ThumbnailFormat, UserResponseDto } from '@api';
|
||||||
import { createEventDispatcher, onMount } from 'svelte';
|
import { createEventDispatcher, onMount } from 'svelte';
|
||||||
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
|
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
|
||||||
import noThumbnailUrl from '$lib/assets/no-thumbnail.png';
|
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
|
||||||
import IconButton from '../elements/buttons/icon-button.svelte';
|
import IconButton from '../elements/buttons/icon-button.svelte';
|
||||||
|
import type { OnClick, OnShowContextMenu } from './album-card';
|
||||||
|
|
||||||
export let album: AlbumResponseDto;
|
export let album: AlbumResponseDto;
|
||||||
export let isSharingView = false;
|
export let isSharingView = false;
|
||||||
|
|
12
web/src/lib/components/album-page/album-card.ts
Normal file
12
web/src/lib/components/album-page/album-card.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import type { AlbumResponseDto } from '@api';
|
||||||
|
|
||||||
|
export type OnShowContextMenu = {
|
||||||
|
showalbumcontextmenu: OnShowContextMenuDetail;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type OnClick = {
|
||||||
|
click: OnClickDetail;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type OnShowContextMenuDetail = { x: number; y: number };
|
||||||
|
export type OnClickDetail = AlbumResponseDto;
|
|
@ -1,18 +1,18 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher, onMount } from 'svelte';
|
|
||||||
import { quintOut } from 'svelte/easing';
|
|
||||||
import { fly } from 'svelte/transition';
|
|
||||||
import { AssetResponseDto } from '@api';
|
|
||||||
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
|
||||||
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
|
||||||
import AssetGrid from '../photos-page/asset-grid.svelte';
|
|
||||||
import {
|
import {
|
||||||
assetInteractionStore,
|
assetInteractionStore,
|
||||||
assetsInAlbumStoreState,
|
assetsInAlbumStoreState,
|
||||||
selectedAssets
|
selectedAssets
|
||||||
} from '$lib/stores/asset-interaction.store';
|
} from '$lib/stores/asset-interaction.store';
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
|
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
||||||
|
import type { AssetResponseDto } from '@api';
|
||||||
|
import { createEventDispatcher, onMount } from 'svelte';
|
||||||
|
import { quintOut } from 'svelte/easing';
|
||||||
|
import { fly } from 'svelte/transition';
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
|
import AssetGrid from '../photos-page/asset-grid.svelte';
|
||||||
|
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { AlbumResponseDto, AssetResponseDto } from '@api';
|
import type { AlbumResponseDto, AssetResponseDto } from '@api';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import { quintOut } from 'svelte/easing';
|
import { quintOut } from 'svelte/easing';
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
import Thumbnail from '../assets/thumbnail/thumbnail.svelte';
|
import Thumbnail from '../assets/thumbnail/thumbnail.svelte';
|
||||||
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
|
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
||||||
|
|
||||||
export let album: AlbumResponseDto;
|
export let album: AlbumResponseDto;
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,21 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { page } from '$app/stores';
|
||||||
|
|
||||||
import { clickOutside } from '$lib/utils/click-outside';
|
import { clickOutside } from '$lib/utils/click-outside';
|
||||||
|
import type { AssetResponseDto } from '@api';
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
|
import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
|
||||||
import CloudDownloadOutline from 'svelte-material-icons/CloudDownloadOutline.svelte';
|
import CloudDownloadOutline from 'svelte-material-icons/CloudDownloadOutline.svelte';
|
||||||
import InformationOutline from 'svelte-material-icons/InformationOutline.svelte';
|
import ContentCopy from 'svelte-material-icons/ContentCopy.svelte';
|
||||||
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
|
|
||||||
import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
|
import DeleteOutline from 'svelte-material-icons/DeleteOutline.svelte';
|
||||||
|
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
|
||||||
|
import Heart from 'svelte-material-icons/Heart.svelte';
|
||||||
|
import HeartOutline from 'svelte-material-icons/HeartOutline.svelte';
|
||||||
|
import InformationOutline from 'svelte-material-icons/InformationOutline.svelte';
|
||||||
|
import MotionPauseOutline from 'svelte-material-icons/MotionPauseOutline.svelte';
|
||||||
|
import MotionPlayOutline from 'svelte-material-icons/MotionPlayOutline.svelte';
|
||||||
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
|
||||||
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
|
import ContextMenu from '../shared-components/context-menu/context-menu.svelte';
|
||||||
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
|
import MenuOption from '../shared-components/context-menu/menu-option.svelte';
|
||||||
import Heart from 'svelte-material-icons/Heart.svelte';
|
|
||||||
import HeartOutline from 'svelte-material-icons/HeartOutline.svelte';
|
|
||||||
import ContentCopy from 'svelte-material-icons/ContentCopy.svelte';
|
|
||||||
import MotionPlayOutline from 'svelte-material-icons/MotionPlayOutline.svelte';
|
|
||||||
import MotionPauseOutline from 'svelte-material-icons/MotionPauseOutline.svelte';
|
|
||||||
|
|
||||||
import { page } from '$app/stores';
|
|
||||||
import { AssetResponseDto } from '../../../api';
|
|
||||||
|
|
||||||
export let asset: AssetResponseDto;
|
export let asset: AssetResponseDto;
|
||||||
export let showCopyButton: boolean;
|
export let showCopyButton: boolean;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { APIKeyResponseDto } from '@api';
|
import type { APIKeyResponseDto } from '@api';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import KeyVariant from 'svelte-material-icons/KeyVariant.svelte';
|
import KeyVariant from 'svelte-material-icons/KeyVariant.svelte';
|
||||||
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
|
||||||
import Button from '../elements/buttons/button.svelte';
|
import Button from '../elements/buttons/button.svelte';
|
||||||
|
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
||||||
|
|
||||||
export let apiKey: Partial<APIKeyResponseDto>;
|
export let apiKey: Partial<APIKeyResponseDto>;
|
||||||
export let title = 'API Key';
|
export let title = 'API Key';
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
<script lang="ts" context="module">
|
|
||||||
export interface MapSettings {
|
|
||||||
allowDarkMode: boolean;
|
|
||||||
onlyFavorites: boolean;
|
|
||||||
relativeDate: string;
|
|
||||||
dateAfter: string;
|
|
||||||
dateBefore: string;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
|
||||||
|
import type { MapSettings } from '$lib/stores/preferences.store';
|
||||||
import { Duration } from 'luxon';
|
import { Duration } from 'luxon';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import { fly } from 'svelte/transition';
|
import { fly } from 'svelte/transition';
|
||||||
|
|
|
@ -1,10 +1,4 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { assetStore } from '$lib/stores/assets.store';
|
|
||||||
import CheckCircle from 'svelte-material-icons/CheckCircle.svelte';
|
|
||||||
import CircleOutline from 'svelte-material-icons/CircleOutline.svelte';
|
|
||||||
import { fly } from 'svelte/transition';
|
|
||||||
import { AssetResponseDto } from '@api';
|
|
||||||
import lodash from 'lodash-es';
|
|
||||||
import {
|
import {
|
||||||
assetInteractionStore,
|
assetInteractionStore,
|
||||||
assetsInAlbumStoreState,
|
assetsInAlbumStoreState,
|
||||||
|
@ -12,9 +6,15 @@
|
||||||
selectedAssets,
|
selectedAssets,
|
||||||
selectedGroup
|
selectedGroup
|
||||||
} from '$lib/stores/asset-interaction.store';
|
} from '$lib/stores/asset-interaction.store';
|
||||||
|
import { assetStore } from '$lib/stores/assets.store';
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
import Thumbnail from '../assets/thumbnail/thumbnail.svelte';
|
import type { AssetResponseDto } from '@api';
|
||||||
|
import lodash from 'lodash-es';
|
||||||
|
import CheckCircle from 'svelte-material-icons/CheckCircle.svelte';
|
||||||
|
import CircleOutline from 'svelte-material-icons/CircleOutline.svelte';
|
||||||
import { flip } from 'svelte/animate';
|
import { flip } from 'svelte/animate';
|
||||||
|
import { fly } from 'svelte/transition';
|
||||||
|
import Thumbnail from '../assets/thumbnail/thumbnail.svelte';
|
||||||
|
|
||||||
export let assets: AssetResponseDto[];
|
export let assets: AssetResponseDto[];
|
||||||
export let bucketDate: string;
|
export let bucketDate: string;
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onDestroy, onMount } from 'svelte';
|
|
||||||
|
|
||||||
import { UserResponseDto } from '@api';
|
|
||||||
import IntersectionObserver from '../asset-viewer/intersection-observer.svelte';
|
|
||||||
import { assetGridState, assetStore, loadingBucketState } from '$lib/stores/assets.store';
|
|
||||||
import { api, AssetCountByTimeBucketResponseDto, AssetResponseDto, TimeGroupEnum } from '@api';
|
|
||||||
import AssetDateGroup from './asset-date-group.svelte';
|
|
||||||
import Portal from '../shared-components/portal/portal.svelte';
|
|
||||||
import AssetViewer from '../asset-viewer/asset-viewer.svelte';
|
|
||||||
import {
|
import {
|
||||||
assetInteractionStore,
|
assetInteractionStore,
|
||||||
isViewingAssetStoreState,
|
isViewingAssetStoreState,
|
||||||
viewingAssetStoreState
|
viewingAssetStoreState
|
||||||
} from '$lib/stores/asset-interaction.store';
|
} from '$lib/stores/asset-interaction.store';
|
||||||
|
import { assetGridState, assetStore, loadingBucketState } from '$lib/stores/assets.store';
|
||||||
|
import type { UserResponseDto } from '@api';
|
||||||
|
import { AssetCountByTimeBucketResponseDto, AssetResponseDto, TimeGroupEnum, api } from '@api';
|
||||||
|
import { onDestroy, onMount } from 'svelte';
|
||||||
|
import AssetViewer from '../asset-viewer/asset-viewer.svelte';
|
||||||
|
import IntersectionObserver from '../asset-viewer/intersection-observer.svelte';
|
||||||
|
import Portal from '../shared-components/portal/portal.svelte';
|
||||||
import Scrollbar, {
|
import Scrollbar, {
|
||||||
OnScrollbarClickDetail,
|
OnScrollbarClickDetail,
|
||||||
OnScrollbarDragDetail
|
OnScrollbarDragDetail
|
||||||
} from '../shared-components/scrollbar/scrollbar.svelte';
|
} from '../shared-components/scrollbar/scrollbar.svelte';
|
||||||
|
import AssetDateGroup from './asset-date-group.svelte';
|
||||||
|
|
||||||
export let user: UserResponseDto | undefined = undefined;
|
export let user: UserResponseDto | undefined = undefined;
|
||||||
export let isAlbumSelectionMode = false;
|
export let isAlbumSelectionMode = false;
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
import { AssetResponseDto } from '@api';
|
import type { AssetResponseDto } from '@api';
|
||||||
import Close from 'svelte-material-icons/Close.svelte';
|
import Close from 'svelte-material-icons/Close.svelte';
|
||||||
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher, onMount } from 'svelte';
|
|
||||||
import BaseModal from '../base-modal.svelte';
|
|
||||||
import Link from 'svelte-material-icons/Link.svelte';
|
|
||||||
import {
|
|
||||||
AlbumResponseDto,
|
|
||||||
api,
|
|
||||||
AssetResponseDto,
|
|
||||||
SharedLinkResponseDto,
|
|
||||||
SharedLinkType
|
|
||||||
} from '@api';
|
|
||||||
import { notificationController, NotificationType } from '../notification/notification';
|
|
||||||
import { ImmichDropDownOption } from '../dropdown-button.svelte';
|
|
||||||
import SettingSwitch from '$lib/components/admin-page/settings/setting-switch.svelte';
|
|
||||||
import DropdownButton from '../dropdown-button.svelte';
|
|
||||||
import SettingInputField, {
|
import SettingInputField, {
|
||||||
SettingInputFieldType
|
SettingInputFieldType
|
||||||
} from '$lib/components/admin-page/settings/setting-input-field.svelte';
|
} from '$lib/components/admin-page/settings/setting-input-field.svelte';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import SettingSwitch from '$lib/components/admin-page/settings/setting-switch.svelte';
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
import Button from '$lib/components/elements/buttons/button.svelte';
|
||||||
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
|
import {
|
||||||
|
AlbumResponseDto,
|
||||||
|
AssetResponseDto,
|
||||||
|
SharedLinkResponseDto,
|
||||||
|
SharedLinkType,
|
||||||
|
api
|
||||||
|
} from '@api';
|
||||||
|
import { createEventDispatcher, onMount } from 'svelte';
|
||||||
|
import Link from 'svelte-material-icons/Link.svelte';
|
||||||
|
import BaseModal from '../base-modal.svelte';
|
||||||
|
import type { ImmichDropDownOption } from '../dropdown-button.svelte';
|
||||||
|
import DropdownButton from '../dropdown-button.svelte';
|
||||||
|
import { NotificationType, notificationController } from '../notification/notification';
|
||||||
|
|
||||||
export let shareType: SharedLinkType;
|
export let shareType: SharedLinkType;
|
||||||
export let sharedAssets: AssetResponseDto[] = [];
|
export let sharedAssets: AssetResponseDto[] = [];
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { MapMarkerResponseDto } from '@api';
|
import type { MapMarkerResponseDto } from '@api';
|
||||||
import { DivIcon, LeafletEvent, LeafletMouseEvent, MarkerCluster, Point } from 'leaflet';
|
import { DivIcon, LeafletEvent, LeafletMouseEvent, MarkerCluster, Point } from 'leaflet';
|
||||||
import 'leaflet.markercluster';
|
import 'leaflet.markercluster';
|
||||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
|
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { UserResponseDto } from '@api';
|
import Button from '$lib/components/elements/buttons/button.svelte';
|
||||||
|
import { AppRoute } from '$lib/constants';
|
||||||
|
import type { UserResponseDto } from '@api';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import { fade } from 'svelte/transition';
|
|
||||||
import Cog from 'svelte-material-icons/Cog.svelte';
|
import Cog from 'svelte-material-icons/Cog.svelte';
|
||||||
import Logout from 'svelte-material-icons/Logout.svelte';
|
import Logout from 'svelte-material-icons/Logout.svelte';
|
||||||
import Button from '$lib/components/elements/buttons/button.svelte';
|
import { fade } from 'svelte/transition';
|
||||||
import UserAvatar from '../user-avatar.svelte';
|
import UserAvatar from '../user-avatar.svelte';
|
||||||
import { AppRoute } from '$lib/constants';
|
|
||||||
|
|
||||||
export let user: UserResponseDto;
|
export let user: UserResponseDto;
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { fade } from 'svelte/transition';
|
import type { UploadAsset } from '$lib/models/upload-asset';
|
||||||
import { asByteUnitString } from '$lib/utils/byte-units';
|
|
||||||
import { UploadAsset } from '$lib/models/upload-asset';
|
|
||||||
import ImmichLogo from './immich-logo.svelte';
|
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
|
import { asByteUnitString } from '$lib/utils/byte-units';
|
||||||
|
import { fade } from 'svelte/transition';
|
||||||
|
import ImmichLogo from './immich-logo.svelte';
|
||||||
|
|
||||||
export let uploadAsset: UploadAsset;
|
export let uploadAsset: UploadAsset;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { locale } from '$lib/stores/preferences.store';
|
import { locale } from '$lib/stores/preferences.store';
|
||||||
import { AuthDeviceResponseDto } from '@api';
|
import type { AuthDeviceResponseDto } from '@api';
|
||||||
import { DateTime, ToRelativeCalendarOptions } from 'luxon';
|
import { DateTime, ToRelativeCalendarOptions } from 'luxon';
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import Android from 'svelte-material-icons/Android.svelte';
|
import Android from 'svelte-material-icons/Android.svelte';
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { AssetResponseDto } from '@api';
|
import type { AssetResponseDto } from '@api';
|
||||||
|
|
||||||
export class AssetBucket {
|
export class AssetBucket {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { AssetResponseDto } from '@api';
|
import type { AssetResponseDto } from '@api';
|
||||||
import { writable } from 'svelte/store';
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
export const archivedAsset = writable<AssetResponseDto[]>([]);
|
export const archivedAsset = writable<AssetResponseDto[]>([]);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { browser } from '$app/environment';
|
import { browser } from '$app/environment';
|
||||||
import { MapSettings } from '$lib/components/map-page/map-settings-modal.svelte';
|
|
||||||
import { persisted } from 'svelte-local-storage-store';
|
import { persisted } from 'svelte-local-storage-store';
|
||||||
|
|
||||||
const initialTheme =
|
const initialTheme =
|
||||||
|
@ -21,6 +20,14 @@ export const locale = persisted<string | undefined>('locale', undefined, {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export interface MapSettings {
|
||||||
|
allowDarkMode: boolean;
|
||||||
|
onlyFavorites: boolean;
|
||||||
|
relativeDate: string;
|
||||||
|
dateAfter: string;
|
||||||
|
dateBefore: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const mapSettings = persisted<MapSettings>('map-settings', {
|
export const mapSettings = persisted<MapSettings>('map-settings', {
|
||||||
allowDarkMode: true,
|
allowDarkMode: true,
|
||||||
onlyFavorites: false,
|
onlyFavorites: false,
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
|
import { uploadAssetsStore } from '$lib/stores/upload';
|
||||||
|
import { addAssetsToAlbum, getFileMimeType, getFilenameExtension } from '$lib/utils/asset-utils';
|
||||||
|
import type { AssetFileUploadResponseDto } from '@api';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { combineLatestAll, filter, firstValueFrom, from, mergeMap, of } from 'rxjs';
|
||||||
|
import type { UploadAsset } from '../models/upload-asset';
|
||||||
import {
|
import {
|
||||||
notificationController,
|
notificationController,
|
||||||
NotificationType
|
NotificationType
|
||||||
} from './../components/shared-components/notification/notification';
|
} from './../components/shared-components/notification/notification';
|
||||||
import { uploadAssetsStore } from '$lib/stores/upload';
|
|
||||||
import type { UploadAsset } from '../models/upload-asset';
|
|
||||||
import { AssetFileUploadResponseDto } from '@api';
|
|
||||||
import { addAssetsToAlbum, getFileMimeType, getFilenameExtension } from '$lib/utils/asset-utils';
|
|
||||||
import { mergeMap, filter, firstValueFrom, from, of, combineLatestAll } from 'rxjs';
|
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
export const openFileUploadDialog = async (
|
export const openFileUploadDialog = async (
|
||||||
albumId: string | undefined = undefined,
|
albumId: string | undefined = undefined,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ApiError } from '../../api';
|
import type { ApiError } from '@api';
|
||||||
import {
|
import {
|
||||||
notificationController,
|
notificationController,
|
||||||
NotificationType
|
NotificationType
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
|
import type { OnShowContextMenuDetail } from '$lib/components/album-page/album-card';
|
||||||
import {
|
import {
|
||||||
notificationController,
|
notificationController,
|
||||||
NotificationType
|
NotificationType
|
||||||
} from '$lib/components/shared-components/notification/notification';
|
} from '$lib/components/shared-components/notification/notification';
|
||||||
import { AlbumResponseDto, api } from '@api';
|
import { AlbumResponseDto, api } from '@api';
|
||||||
import { OnShowContextMenuDetail } from '$lib/components/album-page/album-card.svelte';
|
import { derived, get, writable } from 'svelte/store';
|
||||||
import { writable, derived, get } from 'svelte/store';
|
|
||||||
|
|
||||||
type AlbumsProps = { albums: AlbumResponseDto[] };
|
type AlbumsProps = { albums: AlbumResponseDto[] };
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
|
||||||
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
|
import GalleryViewer from '$lib/components/shared-components/gallery-viewer/gallery-viewer.svelte';
|
||||||
import SearchBar from '$lib/components/shared-components/search-bar/search-bar.svelte';
|
import SearchBar from '$lib/components/shared-components/search-bar/search-bar.svelte';
|
||||||
import { AssetResponseDto } from '@api';
|
import type { AssetResponseDto } from '@api';
|
||||||
import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
|
import ArrowLeft from 'svelte-material-icons/ArrowLeft.svelte';
|
||||||
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
|
import DotsVertical from 'svelte-material-icons/DotsVertical.svelte';
|
||||||
import ImageOffOutline from 'svelte-material-icons/ImageOffOutline.svelte';
|
import ImageOffOutline from 'svelte-material-icons/ImageOffOutline.svelte';
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { AlbumResponseDto } from '@api';
|
import type { AlbumResponseDto } from '@api';
|
||||||
import { Sync } from 'factory.ts';
|
|
||||||
import { faker } from '@faker-js/faker';
|
import { faker } from '@faker-js/faker';
|
||||||
|
import { Sync } from 'factory.ts';
|
||||||
|
import { userFactory } from './user-factory';
|
||||||
|
|
||||||
export const albumFactory = Sync.makeFactory<AlbumResponseDto>({
|
export const albumFactory = Sync.makeFactory<AlbumResponseDto>({
|
||||||
albumName: Sync.each(() => faker.commerce.product()),
|
albumName: Sync.each(() => faker.commerce.product()),
|
||||||
|
@ -8,8 +9,10 @@ export const albumFactory = Sync.makeFactory<AlbumResponseDto>({
|
||||||
assetCount: Sync.each((i) => i % 5),
|
assetCount: Sync.each((i) => i % 5),
|
||||||
assets: [],
|
assets: [],
|
||||||
createdAt: Sync.each(() => faker.date.past().toISOString()),
|
createdAt: Sync.each(() => faker.date.past().toISOString()),
|
||||||
|
updatedAt: Sync.each(() => faker.date.past().toISOString()),
|
||||||
id: Sync.each(() => faker.datatype.uuid()),
|
id: Sync.each(() => faker.datatype.uuid()),
|
||||||
ownerId: Sync.each(() => faker.datatype.uuid()),
|
ownerId: Sync.each(() => faker.datatype.uuid()),
|
||||||
|
owner: userFactory.build(),
|
||||||
shared: false,
|
shared: false,
|
||||||
sharedUsers: []
|
sharedUsers: []
|
||||||
});
|
});
|
||||||
|
|
18
web/src/test-data/factories/user-factory.ts
Normal file
18
web/src/test-data/factories/user-factory.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import type { UserResponseDto } from '@api';
|
||||||
|
import { faker } from '@faker-js/faker';
|
||||||
|
import { Sync } from 'factory.ts';
|
||||||
|
|
||||||
|
export const userFactory = Sync.makeFactory<UserResponseDto>({
|
||||||
|
id: Sync.each(() => faker.datatype.uuid()),
|
||||||
|
email: Sync.each(() => faker.internet.email()),
|
||||||
|
firstName: Sync.each(() => faker.name.firstName()),
|
||||||
|
lastName: Sync.each(() => faker.name.lastName()),
|
||||||
|
storageLabel: Sync.each(() => faker.random.alphaNumeric()),
|
||||||
|
profileImagePath: '',
|
||||||
|
shouldChangePassword: Sync.each(() => faker.datatype.boolean()),
|
||||||
|
isAdmin: true,
|
||||||
|
createdAt: Sync.each(() => faker.date.past().toISOString()),
|
||||||
|
deletedAt: null,
|
||||||
|
updatedAt: Sync.each(() => faker.date.past().toISOString()),
|
||||||
|
oauthId: ''
|
||||||
|
});
|
|
@ -16,7 +16,6 @@
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"target": "es2020",
|
"target": "es2020",
|
||||||
"importsNotUsedAsValues": "preserve",
|
|
||||||
"preserveValueImports": false,
|
"preserveValueImports": false,
|
||||||
"paths": {
|
"paths": {
|
||||||
"$lib": [
|
"$lib": [
|
||||||
|
|
Loading…
Reference in a new issue