feat: toasts (#23298)

This commit is contained in:
Jason Rasmussen
2025-10-28 15:09:11 -04:00
committed by GitHub
parent 106effca2e
commit 52596255c8
80 changed files with 341 additions and 1069 deletions
@@ -11,10 +11,6 @@
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
import {
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
@@ -68,7 +64,7 @@
updateAlbumInfo,
type AlbumUserAddDto,
} from '@immich/sdk';
import { Button, Icon, IconButton, modalManager } from '@immich/ui';
import { Button, Icon, IconButton, modalManager, toastManager } from '@immich/ui';
import {
mdiArrowLeft,
mdiCogOutline,
@@ -189,10 +185,7 @@
});
const count = results.filter(({ success }) => success).length;
notificationController.show({
type: NotificationType.Info,
message: $t('assets_added_count', { values: { count } }),
});
toastManager.success($t('assets_added_count', { values: { count } }));
await refreshAlbum();
@@ -304,10 +297,7 @@
albumThumbnailAssetId: assetId,
},
});
notificationController.show({
type: NotificationType.Info,
message: $t('album_cover_updated'),
});
toastManager.success($t('album_cover_updated'));
} catch (error) {
handleError(error, $t('errors.unable_to_update_album_cover'));
}
+4 -17
View File
@@ -9,10 +9,6 @@
import PeopleInfiniteScroll from '$lib/components/faces-page/people-infinite-scroll.svelte';
import SearchPeople from '$lib/components/faces-page/people-search.svelte';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import {
notificationController,
NotificationType,
} from '$lib/components/shared-components/notification/notification';
import { ActionQueryParameterValue, AppRoute, QueryParameter, SessionStorageKey } from '$lib/constants';
import PersonEditBirthDateModal from '$lib/modals/PersonEditBirthDateModal.svelte';
import PersonMergeSuggestionModal from '$lib/modals/PersonMergeSuggestionModal.svelte';
@@ -22,7 +18,7 @@
import { handleError } from '$lib/utils/handle-error';
import { clearQueryParam } from '$lib/utils/navigation';
import { getAllPeople, getPerson, searchPerson, updatePerson, type PersonResponseDto } from '@immich/sdk';
import { Button, Icon, modalManager } from '@immich/ui';
import { Button, Icon, modalManager, toastManager } from '@immich/ui';
import { mdiAccountOff, mdiEyeOutline } from '@mdi/js';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
@@ -161,10 +157,7 @@
break;
}
}
notificationController.show({
message: $t('change_name_successfully'),
type: NotificationType.Info,
});
toastManager.success($t('change_name_successfully'));
} catch (error) {
handleError(error, $t('errors.unable_to_save_name'));
}
@@ -185,10 +178,7 @@
return person;
});
notificationController.show({
message: $t('changed_visibility_successfully'),
type: NotificationType.Info,
});
toastManager.success($t('changed_visibility_successfully'));
} catch (error) {
handleError(error, $t('errors.unable_to_hide_person'));
}
@@ -208,10 +198,7 @@
return person;
});
notificationController.show({
message: updatedPerson.isFavorite ? $t('added_to_favorites') : $t('removed_from_favorites'),
type: NotificationType.Info,
});
toastManager.success(updatedPerson.isFavorite ? $t('added_to_favorites') : $t('removed_from_favorites'));
} catch (error) {
handleError(error, $t('errors.unable_to_add_remove_favorites', { values: { favorite: detail.isFavorite } }));
}
@@ -11,10 +11,6 @@
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import ControlAppBar from '$lib/components/shared-components/control-app-bar.svelte';
import {
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import AddToAlbum from '$lib/components/timeline/actions/AddToAlbumAction.svelte';
import ArchiveAction from '$lib/components/timeline/actions/ArchiveAction.svelte';
import ChangeDate from '$lib/components/timeline/actions/ChangeDateAction.svelte';
@@ -49,7 +45,7 @@
updatePerson,
type PersonResponseDto,
} from '@immich/sdk';
import { LoadingSpinner, modalManager } from '@immich/ui';
import { LoadingSpinner, modalManager, toastManager } from '@immich/ui';
import {
mdiAccountBoxOutline,
mdiAccountMultipleCheckOutline,
@@ -165,10 +161,7 @@
personUpdateDto: { isHidden: !person.isHidden },
});
notificationController.show({
message: $t('changed_visibility_successfully'),
type: NotificationType.Info,
});
toastManager.success($t('changed_visibility_successfully'));
await goto(previousRoute);
} catch (error) {
@@ -186,10 +179,7 @@
// Invalidate to reload the page data and have the favorite status updated
await invalidateAll();
notificationController.show({
message: updatedPerson.isFavorite ? $t('added_to_favorites') : $t('removed_from_favorites'),
type: NotificationType.Info,
});
toastManager.success(updatedPerson.isFavorite ? $t('added_to_favorites') : $t('removed_from_favorites'));
} catch (error) {
handleError(error, $t('errors.unable_to_add_remove_favorites', { values: { favorite: person.isFavorite } }));
}
@@ -208,7 +198,7 @@
}
try {
person = await updatePerson({ id: person.id, personUpdateDto: { featureFaceAssetId: asset.id } });
notificationController.show({ message: $t('feature_photo_updated'), type: NotificationType.Info });
toastManager.success($t('feature_photo_updated'));
} catch (error) {
handleError(error, $t('errors.unable_to_set_feature_photo'));
}
@@ -270,11 +260,7 @@
try {
person = await updatePerson({ id: person.id, personUpdateDto: { name: personName } });
notificationController.show({
message: $t('change_name_successfully'),
type: NotificationType.Info,
});
toastManager.success($t('change_name_successfully'));
} catch (error) {
handleError(error, $t('errors.unable_to_save_name'));
}
@@ -2,17 +2,13 @@
import { goto } from '$app/navigation';
import { page } from '$app/state';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import {
notificationController,
NotificationType,
} from '$lib/components/shared-components/notification/notification';
import SharedLinkCard from '$lib/components/sharedlinks-page/shared-link-card.svelte';
import { AppRoute } from '$lib/constants';
import GroupTab from '$lib/elements/GroupTab.svelte';
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
import { handleError } from '$lib/utils/handle-error';
import { getAllSharedLinks, removeSharedLink, SharedLinkType, type SharedLinkResponseDto } from '@immich/sdk';
import { modalManager } from '@immich/ui';
import { modalManager, toastManager } from '@immich/ui';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
@@ -47,7 +43,7 @@
try {
await removeSharedLink({ id });
notificationController.show({ message: $t('deleted_shared_link'), type: NotificationType.Info });
toastManager.success($t('deleted_shared_link'));
await refresh();
} catch (error) {
handleError(error, $t('errors.unable_to_delete_shared_link'));
@@ -3,10 +3,6 @@
import empty3Url from '$lib/assets/empty-3.svg';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import {
notificationController,
NotificationType,
} from '$lib/components/shared-components/notification/notification';
import DeleteAssets from '$lib/components/timeline/actions/DeleteAssetsAction.svelte';
import RestoreAssets from '$lib/components/timeline/actions/RestoreAction.svelte';
import SelectAllAssets from '$lib/components/timeline/actions/SelectAllAction.svelte';
@@ -19,7 +15,7 @@
import { handlePromiseError } from '$lib/utils';
import { handleError } from '$lib/utils/handle-error';
import { emptyTrash, restoreTrash } from '@immich/sdk';
import { Button, HStack, modalManager, Text } from '@immich/ui';
import { Button, HStack, modalManager, Text, toastManager } from '@immich/ui';
import { mdiDeleteForeverOutline, mdiHistory } from '@mdi/js';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
@@ -47,11 +43,7 @@
try {
const { count } = await emptyTrash();
notificationController.show({
message: $t('assets_permanently_deleted_count', { values: { count } }),
type: NotificationType.Info,
});
toastManager.success($t('assets_permanently_deleted_count', { values: { count } }));
} catch (error) {
handleError(error, $t('errors.unable_to_empty_trash'));
}
@@ -64,10 +56,7 @@
}
try {
const { count } = await restoreTrash();
notificationController.show({
message: $t('assets_restored_count', { values: { count } }),
type: NotificationType.Info,
});
toastManager.success($t('assets_restored_count', { values: { count } }));
// reset asset grid (TODO fix in asset store that it should reset when it is empty)
// note - this is still a problem, but updateOptions with the same value will not
@@ -3,10 +3,6 @@
import { page } from '$app/state';
import { shortcuts } from '$lib/actions/shortcut';
import UserPageLayout from '$lib/components/layouts/user-page-layout.svelte';
import {
notificationController,
NotificationType,
} from '$lib/components/shared-components/notification/notification';
import DuplicatesCompareControl from '$lib/components/utilities-page/duplicates/duplicates-compare-control.svelte';
import { AppRoute } from '$lib/constants';
import DuplicatesInformationModal from '$lib/modals/DuplicatesInformationModal.svelte';
@@ -19,7 +15,7 @@
import { handleError } from '$lib/utils/handle-error';
import type { AssetResponseDto } from '@immich/sdk';
import { deleteAssets, deleteDuplicates, updateAssets } from '@immich/sdk';
import { Button, HStack, IconButton, modalManager, Text } from '@immich/ui';
import { Button, HStack, IconButton, modalManager, Text, toastManager } from '@immich/ui';
import {
mdiCheckOutline,
mdiChevronLeft,
@@ -96,12 +92,10 @@
return;
}
notificationController.show({
message: $featureFlags.trash
? $t('assets_moved_to_trash_count', { values: { count: trashedCount } })
: $t('permanently_deleted_assets_count', { values: { count: trashedCount } }),
type: NotificationType.Info,
});
const message = $featureFlags.trash
? $t('assets_moved_to_trash_count', { values: { count: trashedCount } })
: $t('permanently_deleted_assets_count', { values: { count: trashedCount } });
toastManager.success(message);
};
const handleResolve = async (duplicateId: string, duplicateAssetIds: string[], trashIds: string[]) => {
@@ -173,10 +167,7 @@
duplicates = [];
notificationController.show({
message: $t('resolved_all_duplicates'),
type: NotificationType.Info,
});
toastManager.success($t('resolved_all_duplicates'));
page.url.searchParams.delete('index');
await goto(`${AppRoute.DUPLICATES}`);
},
+4 -2
View File
@@ -6,7 +6,6 @@
import ErrorLayout from '$lib/components/layouts/ErrorLayout.svelte';
import AppleHeader from '$lib/components/shared-components/apple-header.svelte';
import NavigationLoadingBar from '$lib/components/shared-components/navigation-loading-bar.svelte';
import NotificationList from '$lib/components/shared-components/notification/notification-list.svelte';
import UploadPanel from '$lib/components/shared-components/upload-panel.svelte';
import { eventManager } from '$lib/managers/event-manager.svelte';
import VersionAnnouncementModal from '$lib/modals/VersionAnnouncementModal.svelte';
@@ -38,6 +37,10 @@
hide_password: $t('hide_password'),
confirm: $t('confirm'),
cancel: $t('cancel'),
toast_success_title: $t('success'),
toast_info_title: $t('info'),
toast_warning_title: $t('warning'),
toast_danger_title: $t('error'),
});
});
@@ -155,4 +158,3 @@
<DownloadPanel />
<UploadPanel />
<NotificationList />
@@ -5,10 +5,6 @@
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import {
notificationController,
NotificationType,
} from '$lib/components/shared-components/notification/notification';
import LibraryImportPathModal from '$lib/modals/LibraryImportPathModal.svelte';
import LibraryRenameModal from '$lib/modals/LibraryRenameModal.svelte';
import LibraryUserPickerModal from '$lib/modals/LibraryUserPickerModal.svelte';
@@ -30,7 +26,7 @@
type LibraryStatsResponseDto,
type UserResponseDto,
} from '@immich/sdk';
import { Button, LoadingSpinner, modalManager, Text } from '@immich/ui';
import { Button, LoadingSpinner, modalManager, Text, toastManager } from '@immich/ui';
import { mdiDotsVertical, mdiPlusBoxOutline, mdiSync } from '@mdi/js';
import { onMount } from 'svelte';
import { t } from 'svelte-i18n';
@@ -92,10 +88,7 @@
let createdLibrary: LibraryResponseDto | undefined;
try {
createdLibrary = await createLibrary({ createLibraryDto: { ownerId } });
notificationController.show({
message: $t('admin.library_created', { values: { library: createdLibrary.name } }),
type: NotificationType.Info,
});
toastManager.success($t('admin.library_created', { values: { library: createdLibrary.name } }));
} catch (error) {
handleError(error, $t('errors.unable_to_create_library'));
} finally {
@@ -160,10 +153,7 @@
try {
await sendJobCommand({ id: JobName.Library, jobCommandDto: { command: JobCommand.Start } });
notificationController.show({
message: $t('admin.refreshing_all_libraries'),
type: NotificationType.Info,
});
toastManager.info($t('admin.refreshing_all_libraries'));
} catch (error) {
handleError(error, $t('errors.unable_to_scan_libraries'));
}
@@ -172,10 +162,7 @@
const handleScan = async (libraryId: string) => {
try {
await scanLibrary({ id: libraryId });
notificationController.show({
message: $t('admin.scanning_library'),
type: NotificationType.Info,
});
toastManager.info($t('admin.scanning_library'));
} catch (error) {
handleError(error, $t('errors.unable_to_scan_library'));
}
@@ -244,7 +231,7 @@
try {
await deleteLibrary({ id: library.id });
notificationController.show({ message: $t('admin.library_deleted'), type: NotificationType.Info });
toastManager.success($t('admin.library_deleted'));
} catch (error) {
handleError(error, $t('errors.unable_to_remove_library'));
} finally {
+2 -9
View File
@@ -1,10 +1,6 @@
<script lang="ts">
import { page } from '$app/stores';
import AdminPageLayout from '$lib/components/layouts/AdminPageLayout.svelte';
import {
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import { AppRoute } from '$lib/constants';
import UserCreateModal from '$lib/modals/UserCreateModal.svelte';
import UserDeleteConfirmModal from '$lib/modals/UserDeleteConfirmModal.svelte';
@@ -15,7 +11,7 @@
import { websocketEvents } from '$lib/stores/websocket';
import { getByteUnitString } from '$lib/utils/byte-units';
import { UserStatus, searchUsersAdmin, type UserAdminResponseDto } from '@immich/sdk';
import { Button, HStack, Icon, IconButton, Text, modalManager } from '@immich/ui';
import { Button, HStack, Icon, IconButton, Text, modalManager, toastManager } from '@immich/ui';
import { mdiDeleteRestore, mdiEyeOutline, mdiInfinity, mdiPlusBoxOutline, mdiTrashCanOutline } from '@mdi/js';
import { DateTime } from 'luxon';
import { onMount } from 'svelte';
@@ -38,10 +34,7 @@
const user = allUsers.find(({ id }) => id === userId);
if (user) {
allUsers = allUsers.filter((user) => user.id !== userId);
notificationController.show({
type: NotificationType.Info,
message: $t('admin.user_successfully_removed', { values: { email: user.email } }),
});
toastManager.success($t('admin.user_successfully_removed', { values: { email: user.email } }));
}
};
+2 -6
View File
@@ -1,10 +1,6 @@
<script lang="ts">
import AdminPageLayout from '$lib/components/layouts/AdminPageLayout.svelte';
import ServerStatisticsCard from '$lib/components/server-statistics/ServerStatisticsCard.svelte';
import {
notificationController,
NotificationType,
} from '$lib/components/shared-components/notification/notification';
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
import DeviceCard from '$lib/components/user-settings-page/device-card.svelte';
import FeatureSetting from '$lib/components/users/FeatureSetting.svelte';
@@ -34,6 +30,7 @@
modalManager,
Stack,
Text,
toastManager,
} from '@immich/ui';
import {
mdiAccountOutline,
@@ -148,8 +145,7 @@
try {
await updateUserAdmin({ id: user.id, userAdminUpdateDto: { pinCode: null } });
notificationController.show({ type: NotificationType.Info, message: $t('pin_code_reset_successfully') });
toastManager.success($t('pin_code_reset_successfully'));
} catch (error) {
handleError(error, $t('errors.unable_to_reset_pin_code'));
}