refactor: move handleError to main notification manager class

This commit is contained in:
IMB11 2025-08-02 12:40:40 +01:00
parent 444ace8e54
commit c0f9bc0f48
22 changed files with 57 additions and 63 deletions

View File

@ -1,12 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { add_project_from_path } from '@/helpers/profile.js' import { add_project_from_path } from '@/helpers/profile.js'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { DropdownIcon, FolderOpenIcon, PlusIcon } from '@modrinth/assets' import { DropdownIcon, FolderOpenIcon, PlusIcon } from '@modrinth/assets'
import { ButtonStyled, injectNotificationManager, OverflowMenu } from '@modrinth/ui' import { ButtonStyled, injectNotificationManager, OverflowMenu } from '@modrinth/ui'
import { open } from '@tauri-apps/plugin-dialog' import { open } from '@tauri-apps/plugin-dialog'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const props = defineProps({ const props = defineProps({
instance: { instance: {

View File

@ -4,7 +4,6 @@ import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import { get_user_many } from '@/helpers/cache' import { get_user_many } from '@/helpers/cache'
import { friend_listener } from '@/helpers/events' import { friend_listener } from '@/helpers/events'
import { add_friend, friend_statuses, friends, remove_friend } from '@/helpers/friends' import { add_friend, friend_statuses, friends, remove_friend } from '@/helpers/friends'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { import {
MailIcon, MailIcon,
MoreVerticalIcon, MoreVerticalIcon,
@ -24,7 +23,7 @@ import type { Dayjs } from 'dayjs'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { computed, onUnmounted, ref, watch } from 'vue' import { computed, onUnmounted, ref, watch } from 'vue'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const formatRelativeTime = useRelativeTime() const formatRelativeTime = useRelativeTime()
const props = defineProps<{ const props = defineProps<{

View File

@ -2,7 +2,6 @@
import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue' import ConfirmModalWrapper from '@/components/ui/modal/ConfirmModalWrapper.vue'
import { trackEvent } from '@/helpers/analytics' import { trackEvent } from '@/helpers/analytics'
import { duplicate, edit, edit_icon, list, remove } from '@/helpers/profile' import { duplicate, edit, edit_icon, list, remove } from '@/helpers/profile'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { CopyIcon, EditIcon, PlusIcon, SpinnerIcon, TrashIcon, UploadIcon } from '@modrinth/assets' import { CopyIcon, EditIcon, PlusIcon, SpinnerIcon, TrashIcon, UploadIcon } from '@modrinth/assets'
import { import {
Avatar, Avatar,
@ -18,7 +17,7 @@ import { computed, ref, type Ref, watch } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import type { GameInstance, InstanceSettingsTabProps } from '../../../helpers/types' import type { GameInstance, InstanceSettingsTabProps } from '../../../helpers/types'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const router = useRouter() const router = useRouter()

View File

@ -1,13 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { edit } from '@/helpers/profile' import { edit } from '@/helpers/profile'
import { get } from '@/helpers/settings.ts' import { get } from '@/helpers/settings.ts'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { Checkbox, injectNotificationManager } from '@modrinth/ui' import { Checkbox, injectNotificationManager } from '@modrinth/ui'
import { defineMessages, useVIntl } from '@vintl/vintl' import { defineMessages, useVIntl } from '@vintl/vintl'
import { computed, ref, watch } from 'vue' import { computed, ref, watch } from 'vue'
import type { AppSettings, Hooks, InstanceSettingsTabProps } from '../../../helpers/types' import type { AppSettings, Hooks, InstanceSettingsTabProps } from '../../../helpers/types'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const props = defineProps<InstanceSettingsTabProps>() const props = defineProps<InstanceSettingsTabProps>()

View File

@ -6,7 +6,6 @@ import { get_project, get_version_many } from '@/helpers/cache'
import { get_loader_versions } from '@/helpers/metadata' import { get_loader_versions } from '@/helpers/metadata'
import { edit, install, update_repair_modrinth } from '@/helpers/profile' import { edit, install, update_repair_modrinth } from '@/helpers/profile'
import { get_game_versions, get_loaders } from '@/helpers/tags' import { get_game_versions, get_loaders } from '@/helpers/tags'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { import {
DownloadIcon, DownloadIcon,
HammerIcon, HammerIcon,
@ -42,7 +41,7 @@ import type {
ManifestLoaderVersion, ManifestLoaderVersion,
} from '../../../helpers/types' } from '../../../helpers/types'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const repairConfirmModal = ref() const repairConfirmModal = ref()

View File

@ -3,14 +3,13 @@ import JavaSelector from '@/components/ui/JavaSelector.vue'
import useMemorySlider from '@/composables/useMemorySlider' import useMemorySlider from '@/composables/useMemorySlider'
import { edit, get_optimal_jre_key } from '@/helpers/profile' import { edit, get_optimal_jre_key } from '@/helpers/profile'
import { get } from '@/helpers/settings.ts' import { get } from '@/helpers/settings.ts'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { CheckCircleIcon, XCircleIcon } from '@modrinth/assets' import { CheckCircleIcon, XCircleIcon } from '@modrinth/assets'
import { Checkbox, injectNotificationManager, Slider } from '@modrinth/ui' import { Checkbox, injectNotificationManager, Slider } from '@modrinth/ui'
import { defineMessages, useVIntl } from '@vintl/vintl' import { defineMessages, useVIntl } from '@vintl/vintl'
import { computed, readonly, ref, watch } from 'vue' import { computed, readonly, ref, watch } from 'vue'
import type { AppSettings, InstanceSettingsTabProps, MemorySettings } from '../../../helpers/types' import type { AppSettings, InstanceSettingsTabProps, MemorySettings } from '../../../helpers/types'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const props = defineProps<InstanceSettingsTabProps>() const props = defineProps<InstanceSettingsTabProps>()

View File

@ -1,13 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { edit } from '@/helpers/profile' import { edit } from '@/helpers/profile'
import { get } from '@/helpers/settings.ts' import { get } from '@/helpers/settings.ts'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { Checkbox, injectNotificationManager, Toggle } from '@modrinth/ui' import { Checkbox, injectNotificationManager, Toggle } from '@modrinth/ui'
import { defineMessages, useVIntl } from '@vintl/vintl' import { defineMessages, useVIntl } from '@vintl/vintl'
import { computed, ref, type Ref, watch } from 'vue' import { computed, ref, type Ref, watch } from 'vue'
import type { AppSettings, InstanceSettingsTabProps } from '../../../helpers/types' import type { AppSettings, InstanceSettingsTabProps } from '../../../helpers/types'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const props = defineProps<InstanceSettingsTabProps>() const props = defineProps<InstanceSettingsTabProps>()

View File

@ -113,7 +113,6 @@ import {
type Skin, type Skin,
type SkinModel, type SkinModel,
} from '@/helpers/skins.ts' } from '@/helpers/skins.ts'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { import {
CheckIcon, CheckIcon,
ChevronRightIcon, ChevronRightIcon,
@ -133,7 +132,7 @@ import {
} from '@modrinth/ui' } from '@modrinth/ui'
import { computed, ref, useTemplateRef, watch } from 'vue' import { computed, ref, useTemplateRef, watch } from 'vue'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const modal = useTemplateRef('modal') const modal = useTemplateRef('modal')
const selectCapeModal = useTemplateRef('selectCapeModal') const selectCapeModal = useTemplateRef('selectCapeModal')

View File

@ -6,7 +6,6 @@ import { get_by_profile_path } from '@/helpers/process'
import { kill, run } from '@/helpers/profile' import { kill, run } from '@/helpers/profile'
import type { GameInstance } from '@/helpers/types' import type { GameInstance } from '@/helpers/types'
import { showProfileInFolder } from '@/helpers/utils' import { showProfileInFolder } from '@/helpers/utils'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { handleSevereError } from '@/store/error' import { handleSevereError } from '@/store/error'
import { import {
EyeIcon, EyeIcon,
@ -33,7 +32,7 @@ import dayjs from 'dayjs'
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue' import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const formatRelativeTime = useRelativeTime() const formatRelativeTime = useRelativeTime()

View File

@ -18,7 +18,6 @@ import {
start_join_server, start_join_server,
start_join_singleplayer_world, start_join_singleplayer_world,
} from '@/helpers/worlds.ts' } from '@/helpers/worlds.ts'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { handleSevereError } from '@/store/error' import { handleSevereError } from '@/store/error'
import { useTheming } from '@/store/theme.ts' import { useTheming } from '@/store/theme.ts'
import { GAME_MODES, HeadingLink, injectNotificationManager } from '@modrinth/ui' import { GAME_MODES, HeadingLink, injectNotificationManager } from '@modrinth/ui'
@ -26,7 +25,7 @@ import type { Dayjs } from 'dayjs'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { computed, onMounted, onUnmounted, ref, watch } from 'vue' import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const props = defineProps<{ const props = defineProps<{
recentInstances: GameInstance[] recentInstances: GameInstance[]

View File

@ -4,13 +4,12 @@ import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue'
import ServerModalBody from '@/components/ui/world/modal/ServerModalBody.vue' import ServerModalBody from '@/components/ui/world/modal/ServerModalBody.vue'
import type { GameInstance } from '@/helpers/types' import type { GameInstance } from '@/helpers/types'
import { add_server_to_profile, type ServerPackStatus, type ServerWorld } from '@/helpers/worlds.ts' import { add_server_to_profile, type ServerPackStatus, type ServerWorld } from '@/helpers/worlds.ts'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { PlayIcon, PlusIcon, XIcon } from '@modrinth/assets' import { PlayIcon, PlusIcon, XIcon } from '@modrinth/assets'
import { ButtonStyled, commonMessages, injectNotificationManager } from '@modrinth/ui' import { ButtonStyled, commonMessages, injectNotificationManager } from '@modrinth/ui'
import { defineMessages, useVIntl } from '@vintl/vintl' import { defineMessages, useVIntl } from '@vintl/vintl'
import { ref } from 'vue' import { ref } from 'vue'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const emit = defineEmits<{ const emit = defineEmits<{

View File

@ -10,13 +10,12 @@ import {
type ServerPackStatus, type ServerPackStatus,
type ServerWorld, type ServerWorld,
} from '@/helpers/worlds.ts' } from '@/helpers/worlds.ts'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { SaveIcon, XIcon } from '@modrinth/assets' import { SaveIcon, XIcon } from '@modrinth/assets'
import { ButtonStyled, commonMessages, injectNotificationManager } from '@modrinth/ui' import { ButtonStyled, commonMessages, injectNotificationManager } from '@modrinth/ui'
import { defineMessage, useVIntl } from '@vintl/vintl' import { defineMessage, useVIntl } from '@vintl/vintl'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const emit = defineEmits<{ const emit = defineEmits<{

View File

@ -4,13 +4,12 @@ import HideFromHomeOption from '@/components/ui/world/modal/HideFromHomeOption.v
import type { GameInstance } from '@/helpers/types' import type { GameInstance } from '@/helpers/types'
import type { DisplayStatus, SingleplayerWorld } from '@/helpers/worlds.ts' import type { DisplayStatus, SingleplayerWorld } from '@/helpers/worlds.ts'
import { rename_world, reset_world_icon, set_world_display_status } from '@/helpers/worlds.ts' import { rename_world, reset_world_icon, set_world_display_status } from '@/helpers/worlds.ts'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { ChevronRightIcon, SaveIcon, UndoIcon, XIcon } from '@modrinth/assets' import { ChevronRightIcon, SaveIcon, UndoIcon, XIcon } from '@modrinth/assets'
import { Avatar, ButtonStyled, commonMessages, injectNotificationManager } from '@modrinth/ui' import { Avatar, ButtonStyled, commonMessages, injectNotificationManager } from '@modrinth/ui'
import { defineMessages, useVIntl } from '@vintl/vintl' import { defineMessages, useVIntl } from '@vintl/vintl'
import { computed, ref } from 'vue' import { computed, ref } from 'vue'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const emit = defineEmits<{ const emit = defineEmits<{

View File

@ -1,4 +1,3 @@
import type { AppNotificationManager } from '@/providers/app-notifications'
import { injectNotificationManager } from '@modrinth/ui' import { injectNotificationManager } from '@modrinth/ui'
import { arrayBufferToBase64 } from '@modrinth/utils' import { arrayBufferToBase64 } from '@modrinth/utils'
import { invoke } from '@tauri-apps/api/core' import { invoke } from '@tauri-apps/api/core'
@ -40,7 +39,7 @@ export const DEFAULT_MODELS: Record<string, SkinModel> = {
export function filterSavedSkins(list: Skin[]) { export function filterSavedSkins(list: Skin[]) {
const customSkins = list.filter((s) => s.source !== 'default') const customSkins = list.filter((s) => s.source !== 'default')
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
fixUnknownSkins(customSkins).catch(handleError) fixUnknownSkins(customSkins).catch(handleError)
return customSkins return customSkins
} }

View File

@ -7,7 +7,6 @@ import SearchCard from '@/components/ui/SearchCard.vue'
import { get_search_results } from '@/helpers/cache.js' import { get_search_results } from '@/helpers/cache.js'
import { get as getInstance, get_projects as getInstanceProjects } from '@/helpers/profile.js' import { get as getInstance, get_projects as getInstanceProjects } from '@/helpers/profile.js'
import { get_categories, get_game_versions, get_loaders } from '@/helpers/tags' import { get_categories, get_game_versions, get_loaders } from '@/helpers/tags'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { useBreadcrumbs } from '@/store/breadcrumbs' import { useBreadcrumbs } from '@/store/breadcrumbs'
import { ClipboardCopyIcon, ExternalIcon, GlobeIcon, SearchIcon, XIcon } from '@modrinth/assets' import { ClipboardCopyIcon, ExternalIcon, GlobeIcon, SearchIcon, XIcon } from '@modrinth/assets'
import type { Category, GameVersion, Platform, ProjectType, SortType, Tags } from '@modrinth/ui' import type { Category, GameVersion, Platform, ProjectType, SortType, Tags } from '@modrinth/ui'
@ -29,7 +28,7 @@ import { computed, nextTick, ref, shallowRef, watch } from 'vue'
import type { LocationQuery } from 'vue-router' import type { LocationQuery } from 'vue-router'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const router = useRouter() const router = useRouter()

View File

@ -5,7 +5,6 @@ import { get_search_results } from '@/helpers/cache.js'
import { profile_listener } from '@/helpers/events' import { profile_listener } from '@/helpers/events'
import { list } from '@/helpers/profile.js' import { list } from '@/helpers/profile.js'
import type { GameInstance } from '@/helpers/types' import type { GameInstance } from '@/helpers/types'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { useBreadcrumbs } from '@/store/breadcrumbs' import { useBreadcrumbs } from '@/store/breadcrumbs'
import { injectNotificationManager } from '@modrinth/ui' import { injectNotificationManager } from '@modrinth/ui'
import type { SearchResult } from '@modrinth/utils' import type { SearchResult } from '@modrinth/utils'
@ -13,7 +12,7 @@ import dayjs from 'dayjs'
import { computed, onUnmounted, ref } from 'vue' import { computed, onUnmounted, ref } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const route = useRoute() const route = useRoute()
const breadcrumbs = useBreadcrumbs() const breadcrumbs = useBreadcrumbs()

View File

@ -20,7 +20,6 @@ import {
remove_custom_skin, remove_custom_skin,
set_default_cape, set_default_cape,
} from '@/helpers/skins.ts' } from '@/helpers/skins.ts'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { handleSevereError } from '@/store/error' import { handleSevereError } from '@/store/error'
import { import {
EditIcon, EditIcon,
@ -48,7 +47,7 @@ const editSkinModal = useTemplateRef('editSkinModal')
const selectCapeModal = useTemplateRef('selectCapeModal') const selectCapeModal = useTemplateRef('selectCapeModal')
const uploadSkinModal = useTemplateRef('uploadSkinModal') const uploadSkinModal = useTemplateRef('uploadSkinModal')
const notifications = injectNotificationManager() as AppNotificationManager const notifications = injectNotificationManager()
const { handleError } = notifications const { handleError } = notifications
const settings = ref(await getSettings()) const settings = ref(await getSettings())

View File

@ -273,7 +273,6 @@ import {
} from '@/helpers/profile.js' } from '@/helpers/profile.js'
import type { CacheBehaviour, ContentFile, GameInstance } from '@/helpers/types' import type { CacheBehaviour, ContentFile, GameInstance } from '@/helpers/types'
import { highlightModInProfile } from '@/helpers/utils.js' import { highlightModInProfile } from '@/helpers/utils.js'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { import {
CheckCircleIcon, CheckCircleIcon,
ClipboardCopyIcon, ClipboardCopyIcon,
@ -311,7 +310,7 @@ import dayjs from 'dayjs'
import type { ComputedRef } from 'vue' import type { ComputedRef } from 'vue'
import { computed, onUnmounted, ref, watch } from 'vue' import { computed, onUnmounted, ref, watch } from 'vue'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const props = defineProps<{ const props = defineProps<{
instance: GameInstance instance: GameInstance

View File

@ -151,7 +151,6 @@ import {
start_join_server, start_join_server,
start_join_singleplayer_world, start_join_singleplayer_world,
} from '@/helpers/worlds.ts' } from '@/helpers/worlds.ts'
import type { AppNotificationManager } from '@/providers/app-notifications'
import { PlusIcon, SearchIcon, SpinnerIcon, UpdatedIcon, XIcon } from '@modrinth/assets' import { PlusIcon, SearchIcon, SpinnerIcon, UpdatedIcon, XIcon } from '@modrinth/assets'
import { import {
Button, Button,
@ -168,7 +167,7 @@ import { defineMessages } from '@vintl/vintl'
import { computed, onUnmounted, ref, watch } from 'vue' import { computed, onUnmounted, ref, watch } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
const { handleError } = injectNotificationManager() as AppNotificationManager const { handleError } = injectNotificationManager()
const route = useRoute() const route = useRoute()
const addServerModal = ref<InstanceType<typeof AddServerModal>>() const addServerModal = ref<InstanceType<typeof AddServerModal>>()

View File

@ -1,33 +1,25 @@
import { import {
AbstractWebNotificationManager, AbstractWebNotificationManager,
type NotificationPanelLocation,
type WebNotification, type WebNotification,
type WebNotificationLocation,
} from '@modrinth/ui' } from '@modrinth/ui'
import { ref, type Ref } from 'vue' import { ref, type Ref } from 'vue'
export class AppNotificationManager extends AbstractWebNotificationManager { export class AppNotificationManager extends AbstractWebNotificationManager {
private readonly state: Ref<WebNotification[]> private readonly state: Ref<WebNotification[]>
private readonly locationState: Ref<WebNotificationLocation> private readonly locationState: Ref<NotificationPanelLocation>
public constructor() { public constructor() {
super() super()
this.state = ref<WebNotification[]>([]) this.state = ref<WebNotification[]>([])
this.locationState = ref<WebNotificationLocation>('right') this.locationState = ref<NotificationPanelLocation>('right')
} }
public handleError = (error: Error): void => { public getNotificationLocation(): NotificationPanelLocation {
this.addNotification({
title: 'An error occurred',
text: error.message ?? error,
type: 'error',
})
}
public getNotificationLocation(): WebNotificationLocation {
return this.locationState.value return this.locationState.value
} }
public setNotificationLocation(location: WebNotificationLocation): void { public setNotificationLocation(location: NotificationPanelLocation): void {
this.locationState.value = location this.locationState.value = location
} }

View File

@ -1,25 +1,28 @@
import { useState } from "#app"; import { useState } from "#app";
import { import {
type NotificationPanelLocation,
type WebNotification, type WebNotification,
type WebNotificationLocation,
AbstractWebNotificationManager, AbstractWebNotificationManager,
} from "@modrinth/ui"; } from "@modrinth/ui";
export class FrontendNotificationManager extends AbstractWebNotificationManager { export class FrontendNotificationManager extends AbstractWebNotificationManager {
private readonly state: Ref<WebNotification[]>; private readonly state: Ref<WebNotification[]>;
private readonly locationState: Ref<WebNotificationLocation>; private readonly locationState: Ref<NotificationPanelLocation>;
public constructor() { public constructor() {
super(); super();
this.state = useState<WebNotification[]>("notifications", () => []); this.state = useState<WebNotification[]>("notifications", () => []);
this.locationState = useState<WebNotificationLocation>("notifications.location", () => "right"); this.locationState = useState<NotificationPanelLocation>(
"notifications.location",
() => "right",
);
} }
public getNotificationLocation(): WebNotificationLocation { public getNotificationLocation(): NotificationPanelLocation {
return this.locationState.value; return this.locationState.value;
} }
public setNotificationLocation(location: WebNotificationLocation): void { public setNotificationLocation(location: NotificationPanelLocation): void {
this.locationState.value = location; this.locationState.value = location;
} }

View File

@ -10,35 +10,47 @@ export interface WebNotification {
timer?: NodeJS.Timeout timer?: NodeJS.Timeout
} }
export type WebNotificationLocation = 'left' | 'right' export type NotificationPanelLocation = 'left' | 'right'
export abstract class AbstractWebNotificationManager { export abstract class AbstractWebNotificationManager {
protected readonly AUTO_DISMISS_DELAY_MS = 30 * 1000 protected readonly AUTO_DISMISS_DELAY_MS = 30 * 1000
abstract getNotifications(): WebNotification[] abstract getNotifications(): WebNotification[]
abstract getNotificationLocation(): WebNotificationLocation abstract getNotificationLocation(): NotificationPanelLocation
abstract setNotificationLocation(location: WebNotificationLocation): void abstract setNotificationLocation(location: NotificationPanelLocation): void
protected abstract addNotificationToStorage(notification: WebNotification): void protected abstract addNotificationToStorage(notification: WebNotification): void
protected abstract removeNotificationFromStorage(id: string | number): void protected abstract removeNotificationFromStorage(id: string | number): void
protected abstract removeNotificationFromStorageByIndex(index: number): void protected abstract removeNotificationFromStorageByIndex(index: number): void
protected abstract clearAllNotificationsFromStorage(): void protected abstract clearAllNotificationsFromStorage(): void
addNotification = (notification: Partial<WebNotification>): void => { addNotification = (notification: Partial<WebNotification>): WebNotification => {
const existingNotif = this.findExistingNotification(notification) const existingNotif = this.findExistingNotification(notification)
if (existingNotif) { if (existingNotif) {
this.refreshNotificationTimer(existingNotif) this.refreshNotificationTimer(existingNotif)
existingNotif.count = (existingNotif.count || 0) + 1 existingNotif.count = (existingNotif.count || 0) + 1
return return existingNotif
} }
const newNotification = this.createNotification(notification) const newNotification = this.createNotification(notification)
this.setNotificationTimer(newNotification) this.setNotificationTimer(newNotification)
this.addNotificationToStorage(newNotification) this.addNotificationToStorage(newNotification)
return newNotification
} }
removeNotification = (id: string | number): void => { /**
* @deprecated You should use `addNotification` instead to provide a more human-readable error message to the user.
*/
handleError = (error: Error): void => {
this.addNotification({
title: 'An error occurred',
text: error.message ?? error,
type: 'error',
})
}
removeNotification = (id: string | number): WebNotification | undefined => {
const notifications = this.getNotifications() const notifications = this.getNotifications()
const notification = notifications.find((n) => n.id === id) const notification = notifications.find((n) => n.id === id)
@ -46,16 +58,22 @@ export abstract class AbstractWebNotificationManager {
this.clearNotificationTimer(notification) this.clearNotificationTimer(notification)
this.removeNotificationFromStorage(id) this.removeNotificationFromStorage(id)
} }
return notification
} }
removeNotificationByIndex = (index: number): void => { removeNotificationByIndex = (index: number): WebNotification | null => {
const notifications = this.getNotifications() const notifications = this.getNotifications()
if (index >= 0 && index < notifications.length) { if (index >= 0 && index < notifications.length) {
const notification = notifications[index] const notification = notifications[index]
this.clearNotificationTimer(notification) this.clearNotificationTimer(notification)
this.removeNotificationFromStorageByIndex(index) this.removeNotificationFromStorageByIndex(index)
return notification
} }
return null
} }
clearAllNotifications = (): void => { clearAllNotifications = (): void => {