mirror of
https://github.com/immich-app/immich.git
synced 2025-01-04 02:46:47 +01:00
feat(web): add types to dispatcher (#5700)
* feat: add types to dispatcher * fix: create album name * pr feedback * pr feedback * pr feedback * fix: api key name * remove newSharedAlbum * pr feedback * fix: api key creation * on:close * fix: owner * fix: onclose * remove unused code --------- Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
parent
502495883d
commit
4c5397d7e6
41 changed files with 199 additions and 130 deletions
|
@ -6,19 +6,22 @@
|
|||
|
||||
export let user: UserResponseDto;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
success: void;
|
||||
fail: void;
|
||||
}>();
|
||||
|
||||
const deleteUser = async () => {
|
||||
try {
|
||||
const deletedUser = await api.userApi.deleteUser({ id: user.id });
|
||||
if (deletedUser.data.deletedAt != null) {
|
||||
dispatch('user-delete-success');
|
||||
dispatch('success');
|
||||
} else {
|
||||
dispatch('user-delete-fail');
|
||||
dispatch('fail');
|
||||
}
|
||||
} catch (error) {
|
||||
handleError(error, 'Unable to delete user');
|
||||
dispatch('user-delete-fail');
|
||||
dispatch('fail');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -5,14 +5,17 @@
|
|||
|
||||
export let user: UserResponseDto;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
success: void;
|
||||
fail: void;
|
||||
}>();
|
||||
|
||||
const restoreUser = async () => {
|
||||
const restoredUser = await api.userApi.restoreUser({ id: user.id });
|
||||
if (restoredUser.data.deletedAt == null) {
|
||||
dispatch('user-restore-success');
|
||||
dispatch('success');
|
||||
} else {
|
||||
dispatch('user-restore-fail');
|
||||
dispatch('fail');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
import SettingButtonsRow from '../setting-buttons-row.svelte';
|
||||
import SettingSwitch from '../setting-switch.svelte';
|
||||
import SettingSelect from '../setting-select.svelte';
|
||||
import type { ResetOptions } from '$lib/utils/dipatch';
|
||||
|
||||
export let loggingConfig: SystemConfigLoggingDto; // this is the config that is being edited
|
||||
export let disabled = false;
|
||||
|
@ -24,6 +25,14 @@
|
|||
]);
|
||||
}
|
||||
|
||||
const handleReset = (detail: ResetOptions) => {
|
||||
if (detail.default) {
|
||||
resetToDefault();
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
async function saveSetting() {
|
||||
try {
|
||||
const { data: current } = await api.systemConfigApi.getConfig();
|
||||
|
@ -96,9 +105,8 @@
|
|||
/>
|
||||
|
||||
<SettingButtonsRow
|
||||
on:reset={reset}
|
||||
on:reset={({ detail }) => handleReset(detail)}
|
||||
on:save={saveSetting}
|
||||
on:reset-to-default={resetToDefault}
|
||||
showResetToDefault={!isEqual(savedConfig, defaultConfig)}
|
||||
{disabled}
|
||||
/>
|
||||
|
|
|
@ -10,7 +10,10 @@
|
|||
export let album: AlbumResponseDto;
|
||||
|
||||
let selectedThumbnail: AssetResponseDto | undefined;
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
close: void;
|
||||
thumbnail: AssetResponseDto | undefined;
|
||||
}>();
|
||||
|
||||
$: isSelected = (id: string): boolean | undefined => {
|
||||
if (!selectedThumbnail && album.albumThumbnailAssetId == id) {
|
||||
|
@ -25,7 +28,7 @@
|
|||
transition:fly={{ y: 500, duration: 100, easing: quintOut }}
|
||||
class="absolute left-0 top-0 z-[9999] h-full w-full bg-immich-bg py-[160px] dark:bg-immich-dark-bg"
|
||||
>
|
||||
<ControlAppBar on:close-button-click={() => dispatch('close')}>
|
||||
<ControlAppBar on:close={() => dispatch('close')}>
|
||||
<svelte:fragment slot="leading">
|
||||
<p class="text-lg">Select album cover</p>
|
||||
</svelte:fragment>
|
||||
|
@ -35,7 +38,7 @@
|
|||
size="sm"
|
||||
rounded="lg"
|
||||
disabled={selectedThumbnail == undefined}
|
||||
on:click={() => dispatch('thumbnail-selected', { asset: selectedThumbnail })}
|
||||
on:click={() => dispatch('thumbnail', selectedThumbnail)}
|
||||
>
|
||||
Done
|
||||
</Button>
|
||||
|
|
|
@ -9,7 +9,10 @@
|
|||
export let isShowActivity: boolean | undefined;
|
||||
export let disabled: boolean;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
openActivityTab: void;
|
||||
favorite: void;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<div
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
import { AlbumResponseDto, ThumbnailFormat, api } from '@api';
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
const dispatcher = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
album: void;
|
||||
}>();
|
||||
|
||||
export let album: AlbumResponseDto;
|
||||
export let variant: 'simple' | 'full' = 'full';
|
||||
|
@ -24,7 +26,7 @@
|
|||
</script>
|
||||
|
||||
<button
|
||||
on:click={() => dispatcher('album')}
|
||||
on:click={() => dispatch('album')}
|
||||
class="flex w-full gap-4 px-6 py-2 text-left transition-colors hover:bg-gray-200 dark:hover:bg-gray-700"
|
||||
>
|
||||
<div class="h-12 w-12 shrink-0 rounded-xl bg-slate-300">
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
type MenuItemEvent = 'addToAlbum' | 'addToSharedAlbum' | 'asProfileImage' | 'runJob' | 'playSlideShow' | 'unstack';
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
goBack: void;
|
||||
back: void;
|
||||
stopMotionPhoto: void;
|
||||
playMotionPhoto: void;
|
||||
download: void;
|
||||
|
@ -78,7 +78,7 @@
|
|||
class="z-[1001] flex h-16 place-items-center justify-between bg-gradient-to-b from-black/40 px-3 transition-transform duration-200"
|
||||
>
|
||||
<div class="text-white">
|
||||
<CircleIconButton isOpacity={true} icon={mdiArrowLeft} on:click={() => dispatch('goBack')} />
|
||||
<CircleIconButton isOpacity={true} icon={mdiArrowLeft} on:click={() => dispatch('back')} />
|
||||
</div>
|
||||
<div class="flex w-[calc(100%-3rem)] justify-end gap-2 overflow-hidden text-white">
|
||||
{#if asset.isOffline}
|
||||
|
|
|
@ -424,19 +424,17 @@
|
|||
addToSharedAlbum = shared;
|
||||
};
|
||||
|
||||
const handleAddToNewAlbum = (event: CustomEvent) => {
|
||||
const handleAddToNewAlbum = (albumName: string) => {
|
||||
isShowAlbumPicker = false;
|
||||
|
||||
const { albumName }: { albumName: string } = event.detail;
|
||||
api.albumApi.createAlbum({ createAlbumDto: { albumName, assetIds: [asset.id] } }).then((response) => {
|
||||
const album = response.data;
|
||||
goto(`${AppRoute.ALBUMS}/${album.id}`);
|
||||
});
|
||||
};
|
||||
|
||||
const handleAddToAlbum = async (event: CustomEvent<{ album: AlbumResponseDto }>) => {
|
||||
const handleAddToAlbum = async (album: AlbumResponseDto) => {
|
||||
isShowAlbumPicker = false;
|
||||
const album = event.detail.album;
|
||||
|
||||
await addAssetsToAlbum(album.id, [asset.id]);
|
||||
await getAllAlbums();
|
||||
|
@ -575,7 +573,7 @@
|
|||
showDetailButton={shouldShowDetailButton}
|
||||
showSlideshow={!!assetStore}
|
||||
hasStackChildren={$stackAssetsStore.length > 0}
|
||||
on:goBack={closeViewer}
|
||||
on:back={closeViewer}
|
||||
on:showDetail={showDetailInfoHandler}
|
||||
on:download={() => downloadFile(asset)}
|
||||
on:delete={trashOrDelete}
|
||||
|
@ -759,9 +757,8 @@
|
|||
{#if isShowAlbumPicker}
|
||||
<AlbumSelectionModal
|
||||
shared={addToSharedAlbum}
|
||||
on:newAlbum={handleAddToNewAlbum}
|
||||
on:newSharedAlbum={handleAddToNewAlbum}
|
||||
on:album={handleAddToAlbum}
|
||||
on:newAlbum={({ detail }) => handleAddToNewAlbum(detail)}
|
||||
on:album={({ detail }) => handleAddToAlbum(detail)}
|
||||
on:close={() => (isShowAlbumPicker = false)}
|
||||
/>
|
||||
{/if}
|
||||
|
@ -784,11 +781,7 @@
|
|||
{/if}
|
||||
|
||||
{#if isShowProfileImageCrop}
|
||||
<ProfileImageCropper
|
||||
{asset}
|
||||
on:close={() => (isShowProfileImageCrop = false)}
|
||||
on:close-viewer={handleCloseViewer}
|
||||
/>
|
||||
<ProfileImageCropper {asset} on:close={() => (isShowProfileImageCrop = false)} />
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { locale } from '$lib/stores/preferences.store';
|
||||
import { featureFlags } from '$lib/stores/server-config.store';
|
||||
import { getAssetFilename } from '$lib/utils/asset-utils';
|
||||
|
@ -53,7 +52,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
$: isOwner = $page?.data?.user?.id === asset.ownerId;
|
||||
$: isOwner = $user.id === asset.ownerId;
|
||||
|
||||
$: {
|
||||
// Get latest description from server
|
||||
|
|
|
@ -28,7 +28,11 @@
|
|||
let searchFaces = false;
|
||||
let searchName = '';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
close: void;
|
||||
createPerson: string | null;
|
||||
reassign: PersonResponseDto;
|
||||
}>();
|
||||
const handleBackButton = () => {
|
||||
dispatch('close');
|
||||
};
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
export let circle = false;
|
||||
export let border = false;
|
||||
|
||||
let dispatch = createEventDispatcher();
|
||||
let dispatch = createEventDispatcher<{
|
||||
click: PersonResponseDto;
|
||||
}>();
|
||||
|
||||
const handleOnClicked = () => {
|
||||
dispatch('click', person);
|
||||
|
|
|
@ -24,7 +24,10 @@
|
|||
let screenHeight: number;
|
||||
let isShowConfirmation = false;
|
||||
|
||||
let dispatch = createEventDispatcher();
|
||||
let dispatch = createEventDispatcher<{
|
||||
back: void;
|
||||
merge: void;
|
||||
}>();
|
||||
|
||||
$: hasSelection = selectedPeople.length > 0;
|
||||
$: unselectedPeople = people.filter(
|
||||
|
@ -37,7 +40,7 @@
|
|||
});
|
||||
|
||||
const onClose = () => {
|
||||
dispatch('go-back');
|
||||
dispatch('back');
|
||||
};
|
||||
|
||||
const handleSwapPeople = () => {
|
||||
|
@ -89,7 +92,7 @@
|
|||
transition:fly={{ y: 500, duration: 100, easing: quintOut }}
|
||||
class="absolute left-0 top-0 z-[9999] h-full w-full bg-immich-bg dark:bg-immich-dark-bg"
|
||||
>
|
||||
<ControlAppBar on:close-button-click={onClose}>
|
||||
<ControlAppBar on:close={onClose}>
|
||||
<svelte:fragment slot="leading">
|
||||
{#if hasSelection}
|
||||
Selected {selectedPeople.length}
|
||||
|
|
|
@ -40,7 +40,10 @@
|
|||
let automaticRefreshTimeout: NodeJS.Timeout;
|
||||
|
||||
const { onPersonThumbnail } = websocketStore;
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
close: void;
|
||||
refresh: void;
|
||||
}>();
|
||||
|
||||
// Reset value
|
||||
$onPersonThumbnail = '';
|
||||
|
|
|
@ -7,7 +7,12 @@
|
|||
import LoadingSpinner from '$lib/components/shared-components/loading-spinner.svelte';
|
||||
import { mdiClose, mdiEye, mdiEyeOff, mdiRestart } from '@mdi/js';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
close: void;
|
||||
reset: void;
|
||||
change: void;
|
||||
done: void;
|
||||
}>();
|
||||
|
||||
export let showLoadingSpinner: boolean;
|
||||
export let toggleVisibility: boolean;
|
||||
|
@ -21,24 +26,20 @@
|
|||
class="sticky top-0 z-10 flex h-16 w-full items-center justify-between border-b bg-white p-1 dark:border-immich-dark-gray dark:bg-black dark:text-immich-dark-fg md:p-8"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<CircleIconButton icon={mdiClose} on:click={() => dispatch('closeClick')} />
|
||||
<CircleIconButton icon={mdiClose} on:click={() => dispatch('close')} />
|
||||
<p class="ml-4 hidden sm:block">Show & hide people</p>
|
||||
</div>
|
||||
<div class="flex items-center justify-end">
|
||||
<div class="flex items-center md:mr-8">
|
||||
<CircleIconButton
|
||||
title="Reset people visibility"
|
||||
icon={mdiRestart}
|
||||
on:click={() => dispatch('reset-visibility')}
|
||||
/>
|
||||
<CircleIconButton title="Reset people visibility" icon={mdiRestart} on:click={() => dispatch('reset')} />
|
||||
<CircleIconButton
|
||||
title="Toggle visibility"
|
||||
icon={toggleVisibility ? mdiEye : mdiEyeOff}
|
||||
on:click={() => dispatch('toggle-visibility')}
|
||||
on:click={() => dispatch('change')}
|
||||
/>
|
||||
</div>
|
||||
{#if !showLoadingSpinner}
|
||||
<IconButton on:click={() => dispatch('doneClick')}>Done</IconButton>
|
||||
<IconButton on:click={() => dispatch('done')}>Done</IconButton>
|
||||
{:else}
|
||||
<LoadingSpinner />
|
||||
{/if}
|
||||
|
|
|
@ -28,7 +28,10 @@
|
|||
? people.filter((person) => selectedPerson && person.id !== selectedPerson.id && personAssets.id !== person.id)
|
||||
: people;
|
||||
|
||||
let dispatch = createEventDispatcher();
|
||||
let dispatch = createEventDispatcher<{
|
||||
confirm: void;
|
||||
close: void;
|
||||
}>();
|
||||
|
||||
const selectedPeople: AssetFaceUpdateItem[] = [];
|
||||
|
||||
|
@ -117,7 +120,7 @@
|
|||
transition:fly={{ y: 500, duration: 100, easing: quintOut }}
|
||||
class="absolute left-0 top-0 z-[9999] h-full w-full bg-immich-bg dark:bg-immich-dark-bg"
|
||||
>
|
||||
<ControlAppBar on:close-button-click={onClose}>
|
||||
<ControlAppBar on:close={onClose}>
|
||||
<svelte:fragment slot="leading">
|
||||
<slot name="header" />
|
||||
<div />
|
||||
|
|
|
@ -5,18 +5,32 @@
|
|||
import FullScreenModal from '../shared-components/full-screen-modal.svelte';
|
||||
import Icon from '$lib/components/elements/icon.svelte';
|
||||
import { mdiKeyVariant } from '@mdi/js';
|
||||
import { NotificationType, notificationController } from '../shared-components/notification/notification';
|
||||
|
||||
export let apiKey: Partial<APIKeyResponseDto>;
|
||||
export let title = 'API Key';
|
||||
export let cancelText = 'Cancel';
|
||||
export let submitText = 'Save';
|
||||
export let apiKeyName = 'API Key';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
cancel: void;
|
||||
submit: Partial<APIKeyResponseDto>;
|
||||
}>();
|
||||
const handleCancel = () => dispatch('cancel');
|
||||
const handleSubmit = () => dispatch('submit', { ...apiKey, name: apiKey.name });
|
||||
const handleSubmit = () => {
|
||||
if (apiKeyName) {
|
||||
dispatch('submit', { ...apiKey, name: apiKeyName });
|
||||
} else {
|
||||
notificationController.show({
|
||||
message: "Your API Key name shouldn't be empty",
|
||||
type: NotificationType.Warning,
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<FullScreenModal on:clickOutside={() => handleCancel()}>
|
||||
<FullScreenModal on:clickOutside={handleCancel}>
|
||||
<div
|
||||
class="w-[500px] max-w-[95vw] rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg"
|
||||
>
|
||||
|
@ -29,14 +43,14 @@
|
|||
</h1>
|
||||
</div>
|
||||
|
||||
<form on:submit|preventDefault={() => handleSubmit()} autocomplete="off">
|
||||
<form on:submit|preventDefault={handleSubmit} autocomplete="off">
|
||||
<div class="m-4 flex flex-col gap-2">
|
||||
<label class="immich-form-label" for="name">Name</label>
|
||||
<input class="immich-form-input" id="name" name="name" type="text" bind:value={apiKey.name} />
|
||||
<input class="immich-form-input" id="name" name="name" type="text" bind:value={apiKeyName} />
|
||||
</div>
|
||||
|
||||
<div class="mt-8 flex w-full gap-4 px-4">
|
||||
<Button color="gray" fullwidth on:click={() => handleCancel()}>{cancelText}</Button>
|
||||
<Button color="gray" fullwidth on:click={handleCancel}>{cancelText}</Button>
|
||||
<Button type="submit" fullwidth>{submitText}</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -8,7 +8,9 @@
|
|||
|
||||
export let secret = '';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
done: void;
|
||||
}>();
|
||||
const handleDone = () => dispatch('done');
|
||||
let canCopyImagesToClipboard = true;
|
||||
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
}
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
success: void;
|
||||
}>();
|
||||
|
||||
async function changePassword() {
|
||||
if (changeChagePassword) {
|
||||
|
|
|
@ -24,7 +24,10 @@
|
|||
canCreateUser = true;
|
||||
}
|
||||
}
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
submit: void;
|
||||
cancel: void;
|
||||
}>();
|
||||
|
||||
async function registerUser(event: SubmitEvent) {
|
||||
if (canCreateUser && !isCreatingUser) {
|
||||
|
@ -52,7 +55,7 @@
|
|||
if (status === 201) {
|
||||
success = 'New user created';
|
||||
|
||||
dispatch('user-created');
|
||||
dispatch('submit');
|
||||
|
||||
isCreatingUser = false;
|
||||
return;
|
||||
|
|
|
@ -9,7 +9,11 @@
|
|||
export let canDelete = false;
|
||||
export let submitText = 'Submit';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
cancel: void;
|
||||
submit: { excludePattern: string };
|
||||
delete: void;
|
||||
}>();
|
||||
const handleCancel = () => dispatch('cancel');
|
||||
const handleSubmit = () => dispatch('submit', { excludePattern: exclusionPattern });
|
||||
</script>
|
||||
|
|
|
@ -11,7 +11,11 @@
|
|||
export let submitText = 'Save';
|
||||
export let canDelete = false;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
cancel: void;
|
||||
submit: { importPath: string };
|
||||
delete: void;
|
||||
}>();
|
||||
const handleCancel = () => dispatch('cancel');
|
||||
const handleSubmit = () => dispatch('submit', { importPath });
|
||||
</script>
|
||||
|
|
|
@ -26,7 +26,10 @@
|
|||
}
|
||||
});
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
cancel: void;
|
||||
submit: Partial<LibraryResponseDto>;
|
||||
}>();
|
||||
const handleCancel = () => {
|
||||
dispatch('cancel');
|
||||
};
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
|
||||
export let library: Partial<LibraryResponseDto>;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
cancel: void;
|
||||
submit: Partial<LibraryResponseDto>;
|
||||
}>();
|
||||
const handleCancel = () => {
|
||||
dispatch('cancel');
|
||||
};
|
||||
|
|
|
@ -26,13 +26,16 @@
|
|||
}
|
||||
});
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
cancel: void;
|
||||
submit: { library: Partial<LibraryResponseDto>; type: LibraryType };
|
||||
}>();
|
||||
const handleCancel = () => {
|
||||
dispatch('cancel');
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
dispatch('submit', { ...library, libraryType: LibraryType.External });
|
||||
dispatch('submit', { library, type: LibraryType.External });
|
||||
};
|
||||
|
||||
const handleAddExclusionPattern = async () => {
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
|
||||
<section id="memory-viewer" class="w-full bg-immich-dark-gray" bind:this={memoryWrapper}>
|
||||
{#if currentMemory}
|
||||
<ControlAppBar on:close-button-click={() => goto(AppRoute.PHOTOS)} forceDark>
|
||||
<ControlAppBar on:close={() => goto(AppRoute.PHOTOS)} forceDark>
|
||||
<svelte:fragment slot="leading">
|
||||
<p class="text-lg">
|
||||
{currentMemory.title}
|
||||
|
|
|
@ -23,10 +23,9 @@
|
|||
closeMenu();
|
||||
};
|
||||
|
||||
const handleAddToNewAlbum = (event: CustomEvent) => {
|
||||
const handleAddToNewAlbum = (albumName: string) => {
|
||||
showAlbumPicker = false;
|
||||
|
||||
const { albumName }: { albumName: string } = event.detail;
|
||||
const assetIds = Array.from(getAssets()).map((asset) => asset.id);
|
||||
api.albumApi.createAlbum({ createAlbumDto: { albumName, assetIds } }).then((response) => {
|
||||
const { id, albumName } = response.data;
|
||||
|
@ -42,9 +41,8 @@
|
|||
});
|
||||
};
|
||||
|
||||
const handleAddToAlbum = async (event: CustomEvent<{ album: AlbumResponseDto }>) => {
|
||||
const handleAddToAlbum = async (album: AlbumResponseDto) => {
|
||||
showAlbumPicker = false;
|
||||
const album = event.detail.album;
|
||||
const assetIds = Array.from(getAssets()).map((asset) => asset.id);
|
||||
await addAssetsToAlbum(album.id, assetIds);
|
||||
clearSelect();
|
||||
|
@ -56,9 +54,8 @@
|
|||
{#if showAlbumPicker}
|
||||
<AlbumSelectionModal
|
||||
{shared}
|
||||
on:newAlbum={handleAddToNewAlbum}
|
||||
on:newSharedAlbum={handleAddToNewAlbum}
|
||||
on:album={handleAddToAlbum}
|
||||
on:newAlbum={({ detail }) => handleAddToNewAlbum(detail)}
|
||||
on:album={({ detail }) => handleAddToAlbum(detail)}
|
||||
on:close={handleHideAlbumPicker}
|
||||
/>
|
||||
{/if}
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<ControlAppBar on:close-button-click={clearSelect} backIcon={mdiClose} tailwindClasses="bg-white shadow-md">
|
||||
<ControlAppBar on:close={clearSelect} backIcon={mdiClose} tailwindClasses="bg-white shadow-md">
|
||||
<p class="font-medium text-immich-primary dark:text-immich-dark-primary" slot="leading">
|
||||
Selected {assets.size.toLocaleString($locale)}
|
||||
</p>
|
||||
|
|
|
@ -79,7 +79,7 @@
|
|||
{/if}
|
||||
</AssetSelectControlBar>
|
||||
{:else}
|
||||
<ControlAppBar on:close-button-click={() => goto(AppRoute.PHOTOS)} backIcon={mdiArrowLeft} showBackButton={false}>
|
||||
<ControlAppBar on:close={() => goto(AppRoute.PHOTOS)} backIcon={mdiArrowLeft} showBackButton={false}>
|
||||
<svelte:fragment slot="leading">
|
||||
<a
|
||||
data-sveltekit-preload-data="hover"
|
||||
|
|
|
@ -13,15 +13,8 @@
|
|||
let search = '';
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
newAlbum: {
|
||||
albumName: string;
|
||||
};
|
||||
album: {
|
||||
album: AlbumResponseDto;
|
||||
};
|
||||
newSharedAlbum: {
|
||||
albumName: string;
|
||||
};
|
||||
newAlbum: string;
|
||||
album: AlbumResponseDto;
|
||||
close: void;
|
||||
}>();
|
||||
|
||||
|
@ -47,15 +40,11 @@
|
|||
}
|
||||
|
||||
const handleSelect = (album: AlbumResponseDto) => {
|
||||
dispatch('album', { album });
|
||||
dispatch('album', album);
|
||||
};
|
||||
|
||||
const handleNew = () => {
|
||||
if (shared) {
|
||||
dispatch('newAlbum', { albumName: search.length > 0 ? search : '' });
|
||||
} else {
|
||||
dispatch('newSharedAlbum', { albumName: search.length > 0 ? search : '' });
|
||||
}
|
||||
dispatch('newAlbum', search.length > 0 ? search : '');
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
|
||||
let appBarBorder = 'bg-immich-bg border border-transparent';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
close: void;
|
||||
}>();
|
||||
|
||||
const onScroll = () => {
|
||||
if (window.pageYOffset > 80) {
|
||||
|
@ -50,7 +52,7 @@
|
|||
<div class="flex place-items-center gap-6 justify-self-start dark:text-immich-dark-fg">
|
||||
{#if showBackButton}
|
||||
<CircleIconButton
|
||||
on:click={() => dispatch('close-button-click')}
|
||||
on:click={() => dispatch('close')}
|
||||
icon={backIcon}
|
||||
backgroundColor={'transparent'}
|
||||
hoverColor={'#e2e7e9'}
|
||||
|
|
|
@ -12,7 +12,11 @@
|
|||
export let link: SharedLinkResponseDto;
|
||||
|
||||
let expirationCountdown: luxon.DurationObjectUnits;
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher<{
|
||||
delete: void;
|
||||
copy: void;
|
||||
edit: void;
|
||||
}>();
|
||||
|
||||
const getThumbnail = async (): Promise<AssetResponseDto> => {
|
||||
let assetId = '';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script lang="ts">
|
||||
import { api, UpdateLibraryDto, LibraryResponseDto, LibraryType, LibraryStatsResponseDto } from '@api';
|
||||
import { api, LibraryResponseDto, LibraryType, LibraryStatsResponseDto } from '@api';
|
||||
import { onMount } from 'svelte';
|
||||
import Button from '../elements/buttons/button.svelte';
|
||||
import { notificationController, NotificationType } from '../shared-components/notification/notification';
|
||||
|
@ -112,16 +112,15 @@
|
|||
}
|
||||
};
|
||||
|
||||
const handleUpdate = async (event: CustomEvent<UpdateLibraryDto>) => {
|
||||
const handleUpdate = async (event: Partial<LibraryResponseDto>) => {
|
||||
if (updateLibraryIndex === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const dto = event.detail;
|
||||
const libraryId = libraries[updateLibraryIndex].id;
|
||||
|
||||
await api.libraryApi.updateLibrary({ id: libraryId, updateLibraryDto: dto });
|
||||
await api.libraryApi.updateLibrary({ id: libraryId, updateLibraryDto: { ...event } });
|
||||
} catch (error) {
|
||||
handleError(error, 'Unable to update library');
|
||||
} finally {
|
||||
|
@ -375,19 +374,27 @@
|
|||
</tr>
|
||||
{#if renameLibrary === index}
|
||||
<div transition:slide={{ duration: 250 }}>
|
||||
<LibraryRenameForm {library} on:submit={handleUpdate} on:cancel={() => (renameLibrary = null)} />
|
||||
<LibraryRenameForm
|
||||
{library}
|
||||
on:submit={({ detail }) => handleUpdate(detail)}
|
||||
on:cancel={() => (renameLibrary = null)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if editImportPaths === index}
|
||||
<div transition:slide={{ duration: 250 }}>
|
||||
<LibraryImportPathsForm {library} on:submit={handleUpdate} on:cancel={() => (editImportPaths = null)} />
|
||||
<LibraryImportPathsForm
|
||||
{library}
|
||||
on:submit={({ detail }) => handleUpdate(detail)}
|
||||
on:cancel={() => (editImportPaths = null)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if editScanSettings === index}
|
||||
<div transition:slide={{ duration: 250 }} class="mb-4 ml-4 mr-4">
|
||||
<LibraryScanSettingsForm
|
||||
{library}
|
||||
on:submit={handleUpdate}
|
||||
on:submit={({ detail }) => handleUpdate(detail)}
|
||||
on:cancel={() => (editScanSettings = null)}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -29,10 +29,9 @@
|
|||
keys = data;
|
||||
}
|
||||
|
||||
const handleCreate = async (event: CustomEvent<APIKeyResponseDto>) => {
|
||||
const handleCreate = async (detail: Partial<APIKeyResponseDto>) => {
|
||||
try {
|
||||
const dto = event.detail;
|
||||
const { data } = await api.keyApi.createApiKey({ aPIKeyCreateDto: dto });
|
||||
const { data } = await api.keyApi.createApiKey({ aPIKeyCreateDto: detail });
|
||||
secret = data.secret;
|
||||
} catch (error) {
|
||||
handleError(error, 'Unable to create a new API Key');
|
||||
|
@ -42,15 +41,13 @@
|
|||
}
|
||||
};
|
||||
|
||||
const handleUpdate = async (event: CustomEvent<APIKeyResponseDto>) => {
|
||||
if (!editKey) {
|
||||
const handleUpdate = async (detail: Partial<APIKeyResponseDto>) => {
|
||||
if (!editKey || !detail.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dto = event.detail;
|
||||
|
||||
try {
|
||||
await api.keyApi.updateApiKey({ id: editKey.id, aPIKeyUpdateDto: { name: dto.name } });
|
||||
await api.keyApi.updateApiKey({ id: editKey.id, aPIKeyUpdateDto: { name: detail.name } });
|
||||
notificationController.show({
|
||||
message: `Saved API Key`,
|
||||
type: NotificationType.Info,
|
||||
|
@ -88,7 +85,7 @@
|
|||
title="New API Key"
|
||||
submitText="Create"
|
||||
apiKey={newKey}
|
||||
on:submit={handleCreate}
|
||||
on:submit={({ detail }) => handleCreate(detail)}
|
||||
on:cancel={() => (newKey = null)}
|
||||
/>
|
||||
{/if}
|
||||
|
@ -98,7 +95,12 @@
|
|||
{/if}
|
||||
|
||||
{#if editKey}
|
||||
<APIKeyForm submitText="Save" apiKey={editKey} on:submit={handleUpdate} on:cancel={() => (editKey = null)} />
|
||||
<APIKeyForm
|
||||
submitText="Save"
|
||||
apiKey={editKey}
|
||||
on:submit={({ detail }) => handleUpdate(detail)}
|
||||
on:cancel={() => (editKey = null)}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if deleteKey}
|
||||
|
|
|
@ -457,7 +457,7 @@
|
|||
</AssetSelectControlBar>
|
||||
{:else}
|
||||
{#if viewMode === ViewMode.VIEW || viewMode === ViewMode.ALBUM_OPTIONS}
|
||||
<ControlAppBar showBackButton backIcon={mdiArrowLeft} on:close-button-click={() => goto(backUrl)}>
|
||||
<ControlAppBar showBackButton backIcon={mdiArrowLeft} on:close={() => goto(backUrl)}>
|
||||
<svelte:fragment slot="trailing">
|
||||
<CircleIconButton
|
||||
title="Add Photos"
|
||||
|
@ -513,7 +513,7 @@
|
|||
{/if}
|
||||
|
||||
{#if viewMode === ViewMode.SELECT_ASSETS}
|
||||
<ControlAppBar on:close-button-click={handleCloseSelectAssets}>
|
||||
<ControlAppBar on:close={handleCloseSelectAssets}>
|
||||
<svelte:fragment slot="leading">
|
||||
<p class="text-lg dark:text-immich-dark-fg">
|
||||
{#if $timelineSelected.size === 0}
|
||||
|
@ -539,7 +539,7 @@
|
|||
{/if}
|
||||
|
||||
{#if viewMode === ViewMode.SELECT_THUMBNAIL}
|
||||
<ControlAppBar on:close-button-click={() => (viewMode = ViewMode.VIEW)}>
|
||||
<ControlAppBar on:close={() => (viewMode = ViewMode.VIEW)}>
|
||||
<svelte:fragment slot="leading">Select Album Cover</svelte:fragment>
|
||||
</ControlAppBar>
|
||||
{/if}
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
<DownloadAction />
|
||||
</AssetSelectControlBar>
|
||||
{:else}
|
||||
<ControlAppBar showBackButton backIcon={mdiArrowLeft} on:close-button-click={() => goto(AppRoute.SHARING)}>
|
||||
<ControlAppBar showBackButton backIcon={mdiArrowLeft} on:close={() => goto(AppRoute.SHARING)}>
|
||||
<svelte:fragment slot="leading">
|
||||
<p class="whitespace-nowrap text-immich-fg dark:text-immich-dark-fg">
|
||||
{data.partner.name}'s photos
|
||||
|
|
|
@ -438,10 +438,10 @@
|
|||
</UserPageLayout>
|
||||
{#if selectHidden}
|
||||
<ShowHide
|
||||
on:doneClick={handleDoneClick}
|
||||
on:closeClick={handleCloseClick}
|
||||
on:reset-visibility={handleResetVisibility}
|
||||
on:toggle-visibility={handleToggleVisibility}
|
||||
on:done={handleDoneClick}
|
||||
on:close={handleCloseClick}
|
||||
on:reset={handleResetVisibility}
|
||||
on:change={handleToggleVisibility}
|
||||
bind:showLoadingSpinner
|
||||
bind:toggleVisibility
|
||||
>
|
||||
|
|
|
@ -374,7 +374,7 @@
|
|||
{/if}
|
||||
|
||||
{#if viewMode === ViewMode.MERGE_PEOPLE}
|
||||
<MergeFaceSelector person={data.person} on:go-back={handleGoBack} on:merge={handleMerge} />
|
||||
<MergeFaceSelector person={data.person} on:back={handleGoBack} on:merge={handleMerge} />
|
||||
{/if}
|
||||
|
||||
<header>
|
||||
|
@ -398,7 +398,7 @@
|
|||
</AssetSelectControlBar>
|
||||
{:else}
|
||||
{#if viewMode === ViewMode.VIEW_ASSETS || viewMode === ViewMode.SUGGEST_MERGE || viewMode === ViewMode.BIRTH_DATE}
|
||||
<ControlAppBar showBackButton backIcon={mdiArrowLeft} on:close-button-click={() => goto(previousRoute)}>
|
||||
<ControlAppBar showBackButton backIcon={mdiArrowLeft} on:close={() => goto(previousRoute)}>
|
||||
<svelte:fragment slot="trailing">
|
||||
<AssetSelectContextMenu icon={mdiDotsVertical} title="Menu">
|
||||
<MenuOption text="Change feature photo" on:click={() => (viewMode = ViewMode.SELECT_PERSON)} />
|
||||
|
@ -414,7 +414,7 @@
|
|||
{/if}
|
||||
|
||||
{#if viewMode === ViewMode.SELECT_PERSON}
|
||||
<ControlAppBar on:close-button-click={() => (viewMode = ViewMode.VIEW_ASSETS)}>
|
||||
<ControlAppBar on:close={() => (viewMode = ViewMode.VIEW_ASSETS)}>
|
||||
<svelte:fragment slot="leading">Select feature photo</svelte:fragment>
|
||||
</ControlAppBar>
|
||||
{/if}
|
||||
|
|
|
@ -130,7 +130,7 @@
|
|||
</AssetSelectControlBar>
|
||||
</div>
|
||||
{:else}
|
||||
<ControlAppBar on:close-button-click={() => goto(previousRoute)} backIcon={mdiArrowLeft}>
|
||||
<ControlAppBar on:close={() => goto(previousRoute)} backIcon={mdiArrowLeft}>
|
||||
<div class="w-full flex-1 pl-4">
|
||||
<SearchBar grayTheme={false} value={term} />
|
||||
</div>
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
};
|
||||
</script>
|
||||
|
||||
<ControlAppBar backIcon={mdiArrowLeft} on:close-button-click={() => goto(AppRoute.SHARING)}>
|
||||
<ControlAppBar backIcon={mdiArrowLeft} on:close={() => goto(AppRoute.SHARING)}>
|
||||
<svelte:fragment slot="leading">Shared links</svelte:fragment>
|
||||
</ControlAppBar>
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@
|
|||
<section class="w-full pb-28 lg:w-[850px]">
|
||||
{#if shouldShowCreateUserForm}
|
||||
<FullScreenModal on:clickOutside={() => (shouldShowCreateUserForm = false)}>
|
||||
<CreateUserForm on:user-created={onUserCreated} on:cancel={() => (shouldShowCreateUserForm = false)} />
|
||||
<CreateUserForm on:submit={onUserCreated} on:cancel={() => (shouldShowCreateUserForm = false)} />
|
||||
</FullScreenModal>
|
||||
{/if}
|
||||
|
||||
|
@ -120,7 +120,7 @@
|
|||
user={selectedUser}
|
||||
canResetPassword={selectedUser?.id !== $user.id}
|
||||
on:editSuccess={onEditUserSuccess}
|
||||
on:reset-password-success={onEditPasswordSuccess}
|
||||
on:resetPasswordSuccess={onEditPasswordSuccess}
|
||||
on:close={() => (shouldShowEditUserForm = false)}
|
||||
/>
|
||||
</FullScreenModal>
|
||||
|
@ -129,8 +129,8 @@
|
|||
{#if shouldShowDeleteConfirmDialog}
|
||||
<DeleteConfirmDialog
|
||||
user={selectedUser}
|
||||
on:user-delete-success={onUserDeleteSuccess}
|
||||
on:user-delete-fail={onUserDeleteFail}
|
||||
on:succes={onUserDeleteSuccess}
|
||||
on:fail={onUserDeleteFail}
|
||||
on:cancel={() => (shouldShowDeleteConfirmDialog = false)}
|
||||
/>
|
||||
{/if}
|
||||
|
@ -138,8 +138,8 @@
|
|||
{#if shouldShowRestoreDialog}
|
||||
<RestoreDialogue
|
||||
user={selectedUser}
|
||||
on:user-restore-success={onUserRestoreSuccess}
|
||||
on:user-restore-fail={onUserRestoreFail}
|
||||
on:success={onUserRestoreSuccess}
|
||||
on:fail={onUserRestoreFail}
|
||||
on:cancel={() => (shouldShowRestoreDialog = false)}
|
||||
/>
|
||||
{/if}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<LoginForm
|
||||
on:success={() => goto(AppRoute.PHOTOS, { invalidateAll: true })}
|
||||
on:first-login={() => goto(AppRoute.AUTH_CHANGE_PASSWORD)}
|
||||
on:firstLogin={() => goto(AppRoute.AUTH_CHANGE_PASSWORD)}
|
||||
/>
|
||||
</FullscreenContainer>
|
||||
{/if}
|
||||
|
|
Loading…
Reference in a new issue