diff --git a/api/src/store/index.ts b/api/src/store/index.ts index a38893c94..d40aa65a5 100644 --- a/api/src/store/index.ts +++ b/api/src/store/index.ts @@ -8,7 +8,6 @@ import { dynamicRemoteAccessReducer } from '@app/store/modules/dynamic-remote-ac import { dynamix } from '@app/store/modules/dynamix.js'; import { emhttp } from '@app/store/modules/emhttp.js'; import { mothership } from '@app/store/modules/minigraph.js'; -import { notificationReducer } from '@app/store/modules/notifications.js'; import { paths } from '@app/store/modules/paths.js'; import { registration } from '@app/store/modules/registration.js'; import { remoteGraphQLReducer } from '@app/store/modules/remote-graphql.js'; @@ -23,7 +22,6 @@ export const store = configureStore({ emhttp: emhttp.reducer, registration: registration.reducer, remoteGraphQL: remoteGraphQLReducer, - notifications: notificationReducer, cache: cache.reducer, docker: docker.reducer, upnp: upnp.reducer, @@ -46,7 +44,6 @@ export const getters = { dynamix: () => store.getState().dynamix, emhttp: () => store.getState().emhttp, minigraph: () => store.getState().minigraph, - notifications: () => store.getState().notifications, paths: () => store.getState().paths, registration: () => store.getState().registration, remoteGraphQL: () => store.getState().remoteGraphQL, diff --git a/api/src/store/listeners/notification-path-listener.ts b/api/src/store/listeners/notification-path-listener.ts deleted file mode 100644 index 89436b0f4..000000000 --- a/api/src/store/listeners/notification-path-listener.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { logger } from '@app/core/log.js'; -import { startAppListening } from '@app/store/listeners/listener-middleware.js'; -import { clearAllNotifications } from '@app/store/modules/notifications.js'; - -export const enableNotificationPathListener = () => - startAppListening({ - predicate(_, currentState, previousState) { - if ( - currentState.dynamix.notify?.path !== '' && - previousState.dynamix.notify?.path !== currentState.dynamix.notify?.path - ) { - return true; - } - - return false; - }, - async effect(_, { dispatch }) { - logger.debug('Notification Path Changed or Loaded, Recreating Watcher'); - dispatch(clearAllNotifications()); - }, - }); diff --git a/api/src/store/modules/notifications.ts b/api/src/store/modules/notifications.ts deleted file mode 100644 index 4aeb794fe..000000000 --- a/api/src/store/modules/notifications.ts +++ /dev/null @@ -1,92 +0,0 @@ -import type { PayloadAction } from '@reduxjs/toolkit'; -import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'; - -import type { Notification } from '@app/graphql/generated/api/types.js'; -import { logger } from '@app/core/log.js'; -import { pubsub, PUBSUB_CHANNEL } from '@app/core/pubsub.js'; -import { type NotificationIni } from '@app/core/types/states/notification.js'; -import { parseConfig } from '@app/core/utils/misc/parse-config.js'; -import { NotificationSchema } from '@app/graphql/generated/api/operations.js'; -import { Importance, NotificationType } from '@app/graphql/generated/api/types.js'; -import { type AppDispatch, type RootState } from '@app/store/index.js'; - -interface NotificationState { - notifications: Record; -} - -const notificationInitialState: NotificationState = { - notifications: {}, -}; - -const fileImportanceToGqlImportance = (importance: NotificationIni['importance']): Importance => { - switch (importance) { - case 'alert': - return Importance.ALERT; - case 'warning': - return Importance.WARNING; - default: - return Importance.INFO; - } -}; - -const parseNotificationDateToIsoDate = (unixStringSeconds: string | undefined): string | null => { - if (unixStringSeconds && !isNaN(Number(unixStringSeconds))) { - return new Date(Number(unixStringSeconds) * 1_000).toISOString(); - } - return null; -}; - -export const loadNotification = createAsyncThunk< - { id: string; notification: Notification }, - { path: string }, - { state: RootState; dispatch: AppDispatch } ->('notifications/loadNotification', ({ path }) => { - const notificationFile = parseConfig({ - filePath: path, - type: 'ini', - }); - - const notification: Notification = { - id: path, - title: notificationFile.event, - subject: notificationFile.subject, - description: notificationFile.description ?? '', - importance: fileImportanceToGqlImportance(notificationFile.importance), - link: notificationFile.link, - timestamp: parseNotificationDateToIsoDate(notificationFile.timestamp), - type: NotificationType.UNREAD, - }; - const convertedNotification = NotificationSchema().parse(notification); - - if (convertedNotification) { - pubsub.publish(PUBSUB_CHANNEL.NOTIFICATION, { notificationAdded: convertedNotification }); - return { id: path, notification: convertedNotification }; - } - throw new Error('Failed to parse notification'); -}); - -export const notificationsStore = createSlice({ - name: 'notifications', - initialState: notificationInitialState, - reducers: { - clearNotification: (state, action: PayloadAction<{ path: string }>) => { - if (state.notifications[action.payload.path]) { - delete state.notifications[action.payload.path]; - } - }, - clearAllNotifications: (state) => { - state.notifications = {}; - }, - }, - extraReducers: (builder) => { - builder.addCase(loadNotification.fulfilled, (state, { payload }) => { - state.notifications[payload.id] = payload.notification; - }); - builder.addCase(loadNotification.rejected, (_, action) => { - logger.debug('Failed to load notification with error %o', action.error); - }); - }, -}); - -export const notificationReducer = notificationsStore.reducer; -export const { clearNotification, clearAllNotifications } = notificationsStore.actions; diff --git a/api/src/store/store-sync.ts b/api/src/store/store-sync.ts index 45dad597e..5463d11a8 100644 --- a/api/src/store/store-sync.ts +++ b/api/src/store/store-sync.ts @@ -41,10 +41,6 @@ export const startStoreSync = async () => { join(state.paths.states, 'graphql.log'), JSON.stringify(state.minigraph, null, 2) ); - writeFileSync( - join(state.paths.states, 'notifications.log'), - JSON.stringify(state.notifications, null, 2) - ); } lastState = state; diff --git a/api/src/unraid-api/graph/resolvers/notifications/notifications.service.ts b/api/src/unraid-api/graph/resolvers/notifications/notifications.service.ts index acc1cfc49..7064b845a 100644 --- a/api/src/unraid-api/graph/resolvers/notifications/notifications.service.ts +++ b/api/src/unraid-api/graph/resolvers/notifications/notifications.service.ts @@ -33,6 +33,10 @@ import { batchProcess, formatDatetime, isFulfilled, isRejected, unraidTimestamp export class NotificationsService { private logger = new Logger(NotificationsService.name); private static watcher: FSWatcher | null = null; + /** + * The path to the notification directory - will be updated if the user changes the notifier path + */ + private path: string | null = null; private static overview: NotificationOverview = { unread: { @@ -50,7 +54,8 @@ export class NotificationsService { }; constructor() { - NotificationsService.watcher = this.getNotificationsWatcher(); + this.path = getters.dynamix().notify!.path; + void this.getNotificationsWatcher(this.path); } /** @@ -63,6 +68,13 @@ export class NotificationsService { */ public paths(): Record<'basePath' | NotificationType, string> { const basePath = getters.dynamix().notify!.path; + + if (this.path !== basePath) { + // Recreate the watcher with force = true + void this.getNotificationsWatcher(basePath, true); + this.path = basePath; + } + const makePath = (type: NotificationType) => join(basePath, type.toLowerCase()); return { basePath, @@ -78,12 +90,11 @@ export class NotificationsService { * events to their event handlers. *------------------------------------------------------------------------**/ - private getNotificationsWatcher() { - const { basePath } = this.paths(); - - if (NotificationsService.watcher) { + private async getNotificationsWatcher(basePath: string, recreate = false): Promise { + if (NotificationsService.watcher && !recreate) { return NotificationsService.watcher; } + await NotificationsService.watcher?.close().catch((e) => this.logger.error(e)); NotificationsService.watcher = watch(basePath, { usePolling: CHOKIDAR_USEPOLLING }).on( 'add', diff --git a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/.login.php.last-download-time b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/.login.php.last-download-time index c41576b02..9e339bed1 100644 --- a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/.login.php.last-download-time +++ b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/.login.php.last-download-time @@ -1 +1 @@ -1739911366509 \ No newline at end of file +1740588065597 \ No newline at end of file diff --git a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/DefaultPageLayout.php.last-download-time b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/DefaultPageLayout.php.last-download-time index d77a47264..28745ffb3 100644 --- a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/DefaultPageLayout.php.last-download-time +++ b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/DefaultPageLayout.php.last-download-time @@ -1 +1 @@ -1739911365729 \ No newline at end of file +1740588063495 \ No newline at end of file diff --git a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/Notifications.page.last-download-time b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/Notifications.page.last-download-time index 72a5b106f..890c275e2 100644 --- a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/Notifications.page.last-download-time +++ b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/Notifications.page.last-download-time @@ -1 +1 @@ -1739911366308 \ No newline at end of file +1740588063858 \ No newline at end of file diff --git a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/auth-request.php.last-download-time b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/auth-request.php.last-download-time index 6d6404683..57b142023 100644 --- a/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/auth-request.php.last-download-time +++ b/api/src/unraid-api/unraid-file-modifier/modifications/__test__/__fixtures__/downloaded/auth-request.php.last-download-time @@ -1 +1 @@ -1739911366763 \ No newline at end of file +1740588065854 \ No newline at end of file