From 3714375c867f7a298c916b13e442b9a71f9d452c Mon Sep 17 00:00:00 2001 From: IMB11 Date: Wed, 30 Jul 2025 12:48:08 +0100 Subject: [PATCH 01/14] feat: migrate frontend notifications to dependency injection based notificaton manager --- .vscode/settings.json | 4 +- apps/frontend/src/app.vue | 7 +- .../components/ui/CollectionCreateModal.vue | 3 +- .../src/components/ui/ModalCreation.vue | 10 +- .../src/components/ui/NotificationItem.vue | 27 +--- .../components/ui/OrganizationCreateModal.vue | 4 +- .../src/components/ui/ProjectMemberHeader.vue | 16 +- .../moderation/ModerationDelphiReportCard.vue | 23 +-- .../ui/moderation/ModerationReportCard.vue | 23 +-- .../checklist/ModerationChecklist.vue | 67 ++++---- .../ui/servers/BackupCreateModal.vue | 6 +- .../ui/servers/BackupRenameModal.vue | 8 +- .../ui/servers/BackupRestoreModal.vue | 6 +- .../ui/servers/BackupSettingsModal.vue | 11 +- .../ui/servers/FilesUploadDropdown.vue | 9 +- .../PlatformChangeModpackVersionModal.vue | 6 +- .../ui/servers/PlatformMrpackModal.vue | 15 +- .../ui/servers/PlatformVersionSelectModal.vue | 15 +- .../ui/servers/ServerSubdomainLabel.vue | 4 +- .../ui/servers/notice/AssignNoticeModal.vue | 25 +-- .../ui/thread/ConversationThread.vue | 29 ++-- .../src/components/ui/thread/ReportThread.vue | 10 +- apps/frontend/src/composables/auth.js | 7 +- apps/frontend/src/composables/notifs.js | 38 ----- .../src/composables/use-client-try.ts | 4 +- apps/frontend/src/composables/user.js | 10 +- ...fications.ts => platform-notifications.ts} | 7 +- apps/frontend/src/layouts/default.vue | 78 +++++---- apps/frontend/src/pages/[type]/[id].vue | 35 ++-- .../src/pages/[type]/[id]/gallery.vue | 41 ++--- .../src/pages/[type]/[id]/moderation.vue | 9 +- .../src/pages/[type]/[id]/settings/index.vue | 8 +- .../pages/[type]/[id]/settings/members.vue | 29 ++-- .../src/pages/[type]/[id]/settings/tags.vue | 7 +- .../pages/[type]/[id]/version/[version].vue | 75 ++++----- .../frontend/src/pages/admin/billing/[id].vue | 23 +-- .../src/pages/admin/servers/notices.vue | 33 ++-- apps/frontend/src/pages/admin/user_email.vue | 5 +- apps/frontend/src/pages/auth/authorize.vue | 13 +- .../src/pages/auth/reset-password.vue | 9 +- apps/frontend/src/pages/auth/sign-in.vue | 17 +- apps/frontend/src/pages/auth/sign-up.vue | 19 ++- apps/frontend/src/pages/collection/[id].vue | 10 +- apps/frontend/src/pages/dashboard/index.vue | 2 +- .../src/pages/dashboard/notifications.vue | 2 +- .../frontend/src/pages/dashboard/projects.vue | 21 +-- .../src/pages/dashboard/revenue/index.vue | 6 +- .../src/pages/dashboard/revenue/transfers.vue | 8 +- .../src/pages/dashboard/revenue/withdraw.vue | 19 ++- .../organization/[id]/settings/index.vue | 7 +- .../organization/[id]/settings/members.vue | 11 +- .../organization/[id]/settings/projects.vue | 26 +-- apps/frontend/src/pages/plus.vue | 11 +- apps/frontend/src/pages/report.vue | 37 ++--- apps/frontend/src/pages/servers/index.vue | 21 +-- .../src/pages/servers/manage/[id].vue | 41 ++--- .../src/pages/servers/manage/[id]/backups.vue | 19 ++- .../servers/manage/[id]/content/index.vue | 25 +-- .../src/pages/servers/manage/[id]/files.vue | 39 ++--- .../servers/manage/[id]/options/index.vue | 11 +- .../servers/manage/[id]/options/info.vue | 3 +- .../servers/manage/[id]/options/network.vue | 28 ++-- .../manage/[id]/options/preferences.vue | 3 +- .../manage/[id]/options/properties.vue | 8 +- .../servers/manage/[id]/options/startup.vue | 7 +- apps/frontend/src/pages/settings/account.vue | 31 ++-- .../src/pages/settings/applications.vue | 27 ++-- .../src/pages/settings/authorizations.vue | 14 +- .../src/pages/settings/billing/index.vue | 75 ++++----- apps/frontend/src/pages/settings/index.vue | 4 +- apps/frontend/src/pages/settings/pats.vue | 23 ++- apps/frontend/src/pages/settings/profile.vue | 10 +- apps/frontend/src/pages/settings/sessions.vue | 11 +- apps/frontend/src/plugins/shorthands.js | 1 - .../src/providers/web-notifications.ts | 44 +++++ packages/ui/index.ts | 1 + .../ui/src/components/base/Notifications.vue | 152 ------------------ packages/ui/src/components/index.ts | 1 + .../src/components/nav/NotificationPanel.vue | 98 +++++------ packages/ui/src/providers/index.ts | 81 ++++++++++ .../ui/src/providers/web-notifications.ts | 111 +++++++++++++ 81 files changed, 932 insertions(+), 912 deletions(-) delete mode 100644 apps/frontend/src/composables/notifs.js rename apps/frontend/src/helpers/{notifications.ts => platform-notifications.ts} (97%) create mode 100644 apps/frontend/src/providers/web-notifications.ts delete mode 100644 packages/ui/src/components/base/Notifications.vue rename apps/frontend/src/components/ui/Notifications.vue => packages/ui/src/components/nav/NotificationPanel.vue (74%) create mode 100644 packages/ui/src/providers/index.ts create mode 100644 packages/ui/src/providers/web-notifications.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 9caec96a4c..c900f4ec03 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,6 +4,8 @@ "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"], "editor.detectIndentation": true, "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit" + "source.fixAll.eslint": "explicit", + "source.organizeImports": "always", + "source.sortImports": "always" } } diff --git a/apps/frontend/src/app.vue b/apps/frontend/src/app.vue index ebd9fa5606..a1325645b2 100644 --- a/apps/frontend/src/app.vue +++ b/apps/frontend/src/app.vue @@ -1,11 +1,14 @@ diff --git a/apps/frontend/src/components/ui/CollectionCreateModal.vue b/apps/frontend/src/components/ui/CollectionCreateModal.vue index 02b0756077..ca34868f70 100644 --- a/apps/frontend/src/components/ui/CollectionCreateModal.vue +++ b/apps/frontend/src/components/ui/CollectionCreateModal.vue @@ -51,7 +51,9 @@ - diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts index 85b7f2da0b..4613884468 100644 --- a/packages/ui/src/components/index.ts +++ b/packages/ui/src/components/index.ts @@ -76,6 +76,7 @@ export { default as Breadcrumbs } from './nav/Breadcrumbs.vue' export { default as NavItem } from './nav/NavItem.vue' export { default as NavRow } from './nav/NavRow.vue' export { default as NavStack } from './nav/NavStack.vue' +export { default as NotificationPanel } from './nav/NotificationPanel.vue' export { default as PagewideBanner } from './nav/PagewideBanner.vue' // Project diff --git a/apps/frontend/src/components/ui/Notifications.vue b/packages/ui/src/components/nav/NotificationPanel.vue similarity index 74% rename from apps/frontend/src/components/ui/Notifications.vue rename to packages/ui/src/components/nav/NotificationPanel.vue index ebb43c2e0c..88db6128a1 100644 --- a/apps/frontend/src/components/ui/Notifications.vue +++ b/packages/ui/src/components/nav/NotificationPanel.vue @@ -1,10 +1,7 @@ - + diff --git a/packages/ui/src/providers/web-notifications.ts b/packages/ui/src/providers/web-notifications.ts index 7b82a3a6c5..be120f20be 100644 --- a/packages/ui/src/providers/web-notifications.ts +++ b/packages/ui/src/providers/web-notifications.ts @@ -10,17 +10,21 @@ export interface WebNotification { timer?: NodeJS.Timeout } +export type WebNotificationLocation = 'left' | 'right' + export abstract class AbstractWebNotificationManager { protected readonly AUTO_DISMISS_DELAY_MS = 30 * 1000 abstract getNotifications(): WebNotification[] + abstract getNotificationLocation(): WebNotificationLocation + abstract setNotificationLocation(location: WebNotificationLocation): void protected abstract addNotificationToStorage(notification: WebNotification): void protected abstract removeNotificationFromStorage(id: string | number): void protected abstract removeNotificationFromStorageByIndex(index: number): void protected abstract clearAllNotificationsFromStorage(): void - addNotification(notification: Partial): void { + addNotification = (notification: Partial): void => { const existingNotif = this.findExistingNotification(notification) if (existingNotif) { @@ -34,7 +38,7 @@ export abstract class AbstractWebNotificationManager { this.addNotificationToStorage(newNotification) } - removeNotification(id: string | number): void { + removeNotification = (id: string | number): void => { const notifications = this.getNotifications() const notification = notifications.find((n) => n.id === id) @@ -44,7 +48,7 @@ export abstract class AbstractWebNotificationManager { } } - removeNotificationByIndex(index: number): void { + removeNotificationByIndex = (index: number): void => { const notifications = this.getNotifications() if (index >= 0 && index < notifications.length) { @@ -54,7 +58,7 @@ export abstract class AbstractWebNotificationManager { } } - clearAllNotifications(): void { + clearAllNotifications = (): void => { const notifications = this.getNotifications() notifications.forEach((notification) => { this.clearNotificationTimer(notification) @@ -62,7 +66,7 @@ export abstract class AbstractWebNotificationManager { this.clearAllNotificationsFromStorage() } - setNotificationTimer(notification: WebNotification): void { + setNotificationTimer = (notification: WebNotification): void => { if (!notification) return this.clearNotificationTimer(notification) @@ -72,7 +76,7 @@ export abstract class AbstractWebNotificationManager { }, this.AUTO_DISMISS_DELAY_MS) } - stopNotificationTimer(notification: WebNotification): void { + stopNotificationTimer = (notification: WebNotification): void => { this.clearNotificationTimer(notification) } From 718a35737abb2628bcf97a014f6c99233e5be294 Mon Sep 17 00:00:00 2001 From: IMB11 Date: Thu, 31 Jul 2025 12:33:16 +0100 Subject: [PATCH 05/14] refactor: move org context to new DI setup --- .../composables/servers/modrinth-servers.ts | 10 +- apps/frontend/src/pages/organization/[id].vue | 183 +++++++----------- .../organization/[id]/settings/analytics.vue | 3 +- .../organization/[id]/settings/index.vue | 3 +- .../organization/[id]/settings/members.vue | 3 +- .../organization/[id]/settings/projects.vue | 3 +- .../src/providers/organization-context.ts | 108 +++++++++++ packages/utils/types.ts | 70 +++++++ 8 files changed, 259 insertions(+), 124 deletions(-) create mode 100644 apps/frontend/src/providers/organization-context.ts diff --git a/apps/frontend/src/composables/servers/modrinth-servers.ts b/apps/frontend/src/composables/servers/modrinth-servers.ts index d0e3cd921c..22d1126fbb 100644 --- a/apps/frontend/src/composables/servers/modrinth-servers.ts +++ b/apps/frontend/src/composables/servers/modrinth-servers.ts @@ -1,18 +1,20 @@ -import { ModrinthServerError } from "@modrinth/utils"; import type { JWTAuth, ModuleError, ModuleName } from "@modrinth/utils"; +import { ModrinthServerError } from "@modrinth/utils"; +import { injectNotificationManager } from "@modrinth/ui"; import { useServersFetch } from "./servers-fetch.ts"; import { - GeneralModule, - ContentModule, BackupsModule, + ContentModule, + FSModule, + GeneralModule, NetworkModule, StartupModule, WSModule, - FSModule, } from "./modules/index.ts"; export function handleError(err: any) { + const { addNotification } = injectNotificationManager(); if (err instanceof ModrinthServerError && err.v1Error) { addNotification({ title: err.v1Error?.context ?? `An error occurred`, diff --git a/apps/frontend/src/pages/organization/[id].vue b/apps/frontend/src/pages/organization/[id].vue index 9013001610..1e629c5da8 100644 --- a/apps/frontend/src/pages/organization/[id].vue +++ b/apps/frontend/src/pages/organization/[id].vue @@ -28,7 +28,7 @@ - {{ $formatNumber(acceptedMembers?.length || 0) }} + {{ formatNumber(acceptedMembers?.length || 0) }} member @@ -120,11 +120,11 @@ { id: 'manage-projects', action: () => - navigateTo('/organization/' + organization.slug + '/settings/projects'), - hoverOnly: true, - shown: auth.user && currentMember, + router.push('/organization/' + organization?.slug + '/settings/projects'), + hoverFilledOnly: true, + shown: !!(auth.user && currentMember), }, - { divider: true, shown: auth.user && currentMember }, + { divider: true, shown: !!(auth?.user && currentMember) }, { id: 'copy-id', action: () => copyId() }, { id: 'copy-permalink', action: () => copyPermalink() }, ]" @@ -157,20 +157,20 @@