chore: migrate away from event dispatcher (#12820)

This commit is contained in:
Daniel Dietzler 2024-09-20 23:02:58 +02:00 committed by GitHub
parent 529d49471f
commit 124eb8251b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
72 changed files with 360 additions and 656 deletions

View file

@ -2,7 +2,7 @@
import Icon from '$lib/components/elements/icon.svelte';
import { getAllAlbums, type AlbumResponseDto } from '@immich/sdk';
import { mdiPlus } from '@mdi/js';
import { createEventDispatcher, onMount } from 'svelte';
import { onMount } from 'svelte';
import AlbumListItem from '../asset-viewer/album-list-item.svelte';
import { normalizeSearchString } from '$lib/utils/string-utils';
import FullScreenModal from '$lib/components/shared-components/full-screen-modal.svelte';
@ -11,17 +11,15 @@
import { sortAlbums } from '$lib/utils/album-utils';
import { albumViewSettings } from '$lib/stores/preferences.store';
export let onNewAlbum: (search: string) => void;
export let onAlbumClick: (album: AlbumResponseDto) => void;
let albums: AlbumResponseDto[] = [];
let recentAlbums: AlbumResponseDto[] = [];
let filteredAlbums: AlbumResponseDto[] = [];
let loading = true;
let search = '';
const dispatch = createEventDispatcher<{
newAlbum: string;
album: AlbumResponseDto;
}>();
export let shared: boolean;
export let onClose: () => void;
@ -40,14 +38,6 @@
{ sortBy: $albumViewSettings.sortBy, orderBy: $albumViewSettings.sortOrder },
);
const handleSelect = (album: AlbumResponseDto) => {
dispatch('album', album);
};
const handleNew = () => {
dispatch('newAlbum', search.length > 0 ? search : '');
};
const getTitle = () => {
if (shared) {
return $t('add_to_shared_album');
@ -81,7 +71,7 @@
<div class="immich-scrollbar overflow-y-auto">
<button
type="button"
on:click={handleNew}
on:click={() => onNewAlbum(search)}
class="flex w-full items-center gap-4 px-6 py-2 transition-colors hover:bg-gray-200 dark:hover:bg-gray-700 rounded-xl"
>
<div class="flex h-12 w-12 items-center justify-center">
@ -96,7 +86,7 @@
{#if !shared && search.length === 0}
<p class="px-5 py-3 text-xs">{$t('recent').toUpperCase()}</p>
{#each recentAlbums as album (album.id)}
<AlbumListItem {album} on:album={() => handleSelect(album)} />
<AlbumListItem {album} onAlbumClick={() => onAlbumClick(album)} />
{/each}
{/if}
@ -106,7 +96,7 @@
</p>
{/if}
{#each filteredAlbums as album (album.id)}
<AlbumListItem {album} searchQuery={search} on:album={() => handleSelect(album)} />
<AlbumListItem {album} searchQuery={search} onAlbumClick={() => onAlbumClick(album)} />
{/each}
{:else if albums.length > 0}
<p class="px-5 py-1 text-sm">{$t('no_albums_with_name_yet')}</p>

View file

@ -1,5 +1,4 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import { DateTime } from 'luxon';
import ConfirmDialog from './dialog/confirm-dialog.svelte';
import Combobox from './combobox.svelte';
@ -8,6 +7,8 @@
export let initialDate: DateTime = DateTime.now();
export let initialTimeZone: string = '';
export let onCancel: () => void;
export let onConfirm: (date: string) => void;
type ZoneOption = {
/**
@ -118,17 +119,10 @@
return zoneA.value.localeCompare(zoneB.value, undefined, { sensitivity: 'base' });
}
const dispatch = createEventDispatcher<{
cancel: void;
confirm: string;
}>();
const handleCancel = () => dispatch('cancel');
const handleConfirm = () => {
const value = date.toISO();
if (value) {
dispatch('confirm', value);
onConfirm(value);
}
};
</script>
@ -139,7 +133,7 @@
prompt="Please select a new date:"
disabled={!date.isValid}
onConfirm={handleConfirm}
onCancel={handleCancel}
{onCancel}
>
<div class="flex flex-col text-left gap-2" slot="prompt">
<div class="flex flex-col">

View file

@ -1,5 +1,4 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
import ConfirmDialog from './dialog/confirm-dialog.svelte';
import { timeDebounceOnSearch } from '$lib/constants';
import { handleError } from '$lib/utils/handle-error';
@ -14,13 +13,15 @@
import { t } from 'svelte-i18n';
import CoordinatesInput from '$lib/components/shared-components/coordinates-input.svelte';
export let asset: AssetResponseDto | undefined = undefined;
interface Point {
lng: number;
lat: number;
}
export let asset: AssetResponseDto | undefined = undefined;
export let onCancel: () => void;
export let onConfirm: (point: Point) => void;
let places: PlacesResponseDto[] = [];
let suggestedPlaces: PlacesResponseDto[] = [];
let searchWord: string;
@ -30,11 +31,6 @@
let hideSuggestion = false;
let addClipMapMarker: (long: number, lat: number) => void;
const dispatch = createEventDispatcher<{
cancel: void;
confirm: Point;
}>();
$: lat = asset?.exifInfo?.latitude ?? undefined;
$: lng = asset?.exifInfo?.longitude ?? undefined;
$: zoom = lat !== undefined && lng !== undefined ? 12.5 : 1;
@ -50,17 +46,11 @@
let point: Point | null = null;
const handleCancel = () => dispatch('cancel');
const handleSelect = (selected: Point) => {
point = selected;
};
const handleConfirm = () => {
if (point) {
dispatch('confirm', point);
onConfirm(point);
} else {
dispatch('cancel');
onCancel();
}
};
@ -108,13 +98,7 @@
};
</script>
<ConfirmDialog
confirmColor="primary"
title={$t('change_location')}
width="wide"
onConfirm={handleConfirm}
onCancel={handleCancel}
>
<ConfirmDialog confirmColor="primary" title={$t('change_location')} width="wide" onConfirm={handleConfirm} {onCancel}>
<div slot="prompt" class="flex flex-col w-full h-full gap-2">
<div
class="relative w-64 sm:w-96"
@ -126,10 +110,8 @@
placeholder={$t('search_places')}
bind:name={searchWord}
{showLoadingSpinner}
on:reset={() => {
suggestedPlaces = [];
}}
on:search={handleSearchPlaces}
onReset={() => (suggestedPlaces = [])}
onSearch={handleSearchPlaces}
roundedBottom={suggestedPlaces.length === 0 || hideSuggestion}
/>
</button>
@ -180,7 +162,7 @@
center={lat && lng ? { lat, lng } : undefined}
simplified={true}
clickable={true}
on:clickedPoint={({ detail: point }) => handleSelect(point)}
onClickPoint={(selected) => (point = selected)}
/>
{/await}
</div>

View file

@ -21,7 +21,7 @@
import { fly } from 'svelte/transition';
import Icon from '$lib/components/elements/icon.svelte';
import { mdiMagnify, mdiUnfoldMoreHorizontal, mdiClose } from '@mdi/js';
import { createEventDispatcher, tick } from 'svelte';
import { tick } from 'svelte';
import type { FormEventHandler } from 'svelte/elements';
import { shortcuts } from '$lib/actions/shortcut';
import { focusOutside } from '$lib/actions/focus-outside';
@ -35,6 +35,7 @@
export let options: ComboBoxOption[] = [];
export let selectedOption: ComboBoxOption | undefined = undefined;
export let placeholder = '';
export let onSelect: (option: ComboBoxOption | undefined) => void = () => {};
/**
* Unique identifier for the combobox.
@ -61,10 +62,6 @@
searchQuery = selectedOption ? selectedOption.label : '';
}
const dispatch = createEventDispatcher<{
select: ComboBoxOption | undefined;
}>();
const activate = () => {
isActive = true;
searchQuery = '';
@ -105,10 +102,10 @@
optionRefs[0]?.scrollIntoView({ block: 'nearest' });
};
let onSelect = (option: ComboBoxOption) => {
let handleSelect = (option: ComboBoxOption) => {
selectedOption = option;
searchQuery = option.label;
dispatch('select', option);
onSelect(option);
closeDropdown();
};
@ -117,7 +114,7 @@
selectedIndex = undefined;
selectedOption = undefined;
searchQuery = '';
dispatch('select', selectedOption);
onSelect(selectedOption);
};
</script>
@ -188,7 +185,7 @@
shortcut: { key: 'Enter' },
onShortcut: () => {
if (selectedIndex !== undefined && filteredOptions.length > 0) {
onSelect(filteredOptions[selectedIndex]);
handleSelect(filteredOptions[selectedIndex]);
}
closeDropdown();
},
@ -245,7 +242,7 @@
bind:this={optionRefs[index]}
class="text-left w-full px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-700 transition-all cursor-pointer aria-selected:bg-gray-100 aria-selected:dark:bg-gray-700"
id={`${listboxId}-${index}`}
on:click={() => onSelect(option)}
on:click={() => handleSelect(option)}
role="option"
>
{option.label}

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { browser } from '$app/environment';
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
import { onDestroy, onMount } from 'svelte';
import CircleIconButton from '../elements/buttons/circle-icon-button.svelte';
import { fly } from 'svelte/transition';
import { mdiClose } from '@mdi/js';
@ -12,13 +12,10 @@
export let backIcon = mdiClose;
export let tailwindClasses = '';
export let forceDark = false;
export let onClose: () => void = () => {};
let appBarBorder = 'bg-immich-bg border border-transparent';
const dispatch = createEventDispatcher<{
close: void;
}>();
const onScroll = () => {
if (window.pageYOffset > 80) {
appBarBorder = 'border border-gray-200 bg-gray-50 dark:border-gray-600';
@ -33,7 +30,7 @@
const handleClose = () => {
$isSelectingAllAssets = false;
dispatch('close');
onClose();
};
onMount(() => {

View file

@ -7,7 +7,6 @@
import { handleError } from '$lib/utils/handle-error';
import { SharedLinkType, createSharedLink, updateSharedLink, type SharedLinkResponseDto } from '@immich/sdk';
import { mdiContentCopy, mdiLink } from '@mdi/js';
import { createEventDispatcher } from 'svelte';
import { NotificationType, notificationController } from '../notification/notification';
import SettingInputField, { SettingInputFieldType } from '../settings/setting-input-field.svelte';
import SettingSwitch from '../settings/setting-switch.svelte';
@ -21,6 +20,7 @@
export let albumId: string | undefined = undefined;
export let assetIds: string[] = [];
export let editingLink: SharedLinkResponseDto | undefined = undefined;
export let onCreated: () => void = () => {};
let sharedLink: string | null = null;
let description = '';
@ -32,10 +32,6 @@
let shouldChangeExpirationTime = false;
let enablePassword = false;
const dispatch = createEventDispatcher<{
created: void;
}>();
const expirationOptions: [number, Intl.RelativeTimeFormatUnit][] = [
[30, 'minutes'],
[1, 'hour'],
@ -97,7 +93,7 @@
},
});
sharedLink = makeSharedLinkUrl($serverConfig.externalDomain, data.key);
dispatch('created');
onCreated();
} catch (error) {
handleError(error, $t('errors.failed_to_create_shared_link'));
}

View file

@ -163,9 +163,9 @@
<AssetViewer
asset={$viewingAsset}
onAction={handleAction}
on:previous={handlePrevious}
on:next={handleNext}
on:close={() => {
onPrevious={handlePrevious}
onNext={handleNext}
onClose={() => {
assetViewingStore.showAssetViewer(false);
handlePromiseError(navigate({ targetRoute: 'current', assetId: null }));
}}

View file

@ -13,7 +13,6 @@
import type { Feature, GeoJsonProperties, Geometry, Point } from 'geojson';
import type { GeoJSONSource, LngLatLike, StyleSpecification } from 'maplibre-gl';
import maplibregl from 'maplibre-gl';
import { createEventDispatcher } from 'svelte';
import { t } from 'svelte-i18n';
import {
AttributionControl,
@ -52,6 +51,8 @@
}
export let onOpenInMapView: (() => Promise<void> | void) | undefined = undefined;
export let onSelect: (assetIds: string[]) => void = () => {};
export let onClickPoint: ({ lat, lng }: { lat: number; lng: number }) => void = () => {};
let map: maplibregl.Map;
let marker: maplibregl.Marker | null = null;
@ -62,16 +63,11 @@
key: getKey(),
}) as Promise<StyleSpecification>)();
const dispatch = createEventDispatcher<{
selected: string[];
clickedPoint: { lat: number; lng: number };
}>();
function handleAssetClick(assetId: string, map: Map | null) {
if (!map) {
return;
}
dispatch('selected', [assetId]);
onSelect([assetId]);
}
async function handleClusterClick(clusterId: number, map: Map | null) {
@ -82,13 +78,13 @@
const mapSource = map?.getSource('geojson') as GeoJSONSource;
const leaves = await mapSource.getClusterLeaves(clusterId, 10_000, 0);
const ids = leaves.map((leaf) => leaf.properties?.id);
dispatch('selected', ids);
onSelect(ids);
}
function handleMapClick(event: maplibregl.MapMouseEvent) {
if (clickable) {
const { lng, lat } = event.lngLat;
dispatch('clickedPoint', { lng, lat });
onClickPoint({ lng, lat });
if (marker) {
marker.remove();

View file

@ -9,19 +9,16 @@
import { handleError } from '$lib/utils/handle-error';
import { deleteProfileImage, updateMyPreferences, type UserAvatarColor } from '@immich/sdk';
import { mdiCog, mdiLogout, mdiPencil, mdiWrench } from '@mdi/js';
import { createEventDispatcher } from 'svelte';
import { t } from 'svelte-i18n';
import { fade } from 'svelte/transition';
import { NotificationType, notificationController } from '../notification/notification';
import UserAvatar from '../user-avatar.svelte';
import AvatarSelector from './avatar-selector.svelte';
let isShowSelectAvatar = false;
export let onLogout: () => void;
export let onClose: () => void = () => {};
const dispatch = createEventDispatcher<{
logout: void;
close: void;
}>();
let isShowSelectAvatar = false;
const handleSaveProfile = async (color: UserAvatarColor) => {
try {
@ -75,14 +72,7 @@
</div>
<div class="flex flex-col gap-1">
<Button
href={AppRoute.USER_SETTINGS}
on:click={() => dispatch('close')}
color="dark-gray"
size="sm"
shadow={false}
border
>
<Button href={AppRoute.USER_SETTINGS} on:click={onClose} color="dark-gray" size="sm" shadow={false} border>
<div class="flex place-content-center place-items-center text-center gap-2 px-2">
<Icon path={mdiCog} size="18" ariaHidden />
{$t('account_settings')}
@ -91,7 +81,7 @@
{#if $user.isAdmin}
<Button
href={AppRoute.ADMIN_USER_MANAGEMENT}
on:click={() => dispatch('close')}
on:click={onClose}
color="dark-gray"
size="sm"
shadow={false}
@ -111,7 +101,7 @@
<button
type="button"
class="flex w-full place-content-center place-items-center gap-2 py-3 font-medium text-gray-500 hover:bg-immich-primary/10 dark:text-gray-300"
on:click={() => dispatch('logout')}
on:click={onLogout}
>
<Icon path={mdiLogout} size={24} />
{$t('sign_out')}</button

View file

@ -10,7 +10,6 @@
import { handleLogout } from '$lib/utils/auth';
import { logout } from '@immich/sdk';
import { mdiMagnify, mdiTrayArrowUp } from '@mdi/js';
import { createEventDispatcher } from 'svelte';
import { t } from 'svelte-i18n';
import { fade } from 'svelte/transition';
import { AppRoute } from '../../../constants';
@ -21,13 +20,11 @@
import AccountInfoPanel from './account-info-panel.svelte';
export let showUploadButton = true;
export let onUploadClick: () => void;
let shouldShowAccountInfo = false;
let shouldShowAccountInfoPanel = false;
let innerWidth: number;
const dispatch = createEventDispatcher<{
uploadClicked: void;
}>();
const onLogout = async () => {
const { redirectUri } = await logout();
@ -67,14 +64,14 @@
<ThemeButton padding="2" />
{#if !$page.url.pathname.includes('/admin') && showUploadButton}
<LinkButton on:click={() => dispatch('uploadClicked')} class="hidden lg:block">
<LinkButton on:click={onUploadClick} class="hidden lg:block">
<div class="flex gap-2">
<Icon path={mdiTrayArrowUp} size="1.5em" />
<span>{$t('upload')}</span>
</div>
</LinkButton>
<CircleIconButton
on:click={() => dispatch('uploadClicked')}
on:click={onUploadClick}
title={$t('upload')}
icon={mdiTrayArrowUp}
class="lg:hidden"
@ -114,7 +111,7 @@
{/if}
{#if shouldShowAccountInfoPanel}
<AccountInfoPanel on:logout={onLogout} />
<AccountInfoPanel {onLogout} />
{/if}
</div>
</section>

View file

@ -8,7 +8,7 @@
<script lang="ts">
import { handlePromiseError } from '$lib/utils';
import { createEventDispatcher, onMount } from 'svelte';
import { onMount } from 'svelte';
import { tweened } from 'svelte/motion';
/**
@ -26,6 +26,10 @@
export let duration = 5;
export let onDone: () => void;
export let onPlaying: () => void = () => {};
export let onPaused: () => void = () => {};
const onChange = async () => {
progress = setDuration(duration);
await play();
@ -39,16 +43,10 @@
$: {
if ($progress === 1) {
dispatch('done');
onDone();
}
}
const dispatch = createEventDispatcher<{
done: void;
playing: void;
paused: void;
}>();
onMount(async () => {
if (autoplay) {
await play();
@ -57,13 +55,13 @@
export const play = async () => {
status = ProgressBarStatus.Playing;
dispatch('playing');
onPlaying();
await progress.set(1);
};
export const pause = async () => {
status = ProgressBarStatus.Paused;
dispatch('paused');
onPaused();
await progress.set($progress);
};

View file

@ -43,7 +43,7 @@
icon: option.icon,
};
}}
on:select={({ detail }) => onToggle(detail)}
onSelect={onToggle}
/>
</div>
</div>

View file

@ -1,7 +1,6 @@
<script lang="ts">
import { quintOut } from 'svelte/easing';
import { fly } from 'svelte/transition';
import { createEventDispatcher } from 'svelte';
import { t } from 'svelte-i18n';
import Icon from '$lib/components/elements/icon.svelte';
import { mdiChevronDown } from '@mdi/js';
@ -14,15 +13,14 @@
export let isEdited = false;
export let number = false;
export let disabled = false;
const dispatch = createEventDispatcher<{ select: string | number }>();
export let onSelect: (setting: string | number) => void = () => {};
const handleChange = (e: Event) => {
value = (e.target as HTMLInputElement).value;
if (number) {
value = Number.parseInt(value);
}
dispatch('select', value);
onSelect(value);
};
</script>

View file

@ -1,7 +1,6 @@
<script lang="ts">
import { quintOut } from 'svelte/easing';
import { fly } from 'svelte/transition';
import { createEventDispatcher } from 'svelte';
import Slider from '$lib/components/elements/slider.svelte';
import { generateId } from '$lib/utils/generate-id';
import { t } from 'svelte-i18n';
@ -11,14 +10,12 @@
export let checked = false;
export let disabled = false;
export let isEdited = false;
export let onToggle: (isChecked: boolean) => void = () => {};
let id: string = generateId();
$: sliderId = `${id}-slider`;
$: subtitleId = subtitle ? `${id}-subtitle` : undefined;
const dispatch = createEventDispatcher<{ toggle: boolean }>();
const onToggle = (isChecked: boolean) => dispatch('toggle', isChecked);
</script>
<div class="flex place-items-center justify-between">