Skip to content

Commit

Permalink
Improves notifications.
Browse files Browse the repository at this point in the history
  • Loading branch information
mntone committed Jul 1, 2024
1 parent 539e950 commit 132ee5b
Show file tree
Hide file tree
Showing 22 changed files with 187 additions and 105 deletions.
1 change: 1 addition & 0 deletions public/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"EggGraph.fail": "",

"Dialog.log": "Protokoll",
"Dialog.noLogs": "Keine Protokolle",

"Notification.notificationTest": "Testbenachrichtigung",
"Notification.succeedToTestNotification": "Die Testbenachrichtigung wurde erfolgreich gesendet.",
Expand Down
1 change: 1 addition & 0 deletions public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"EggGraph.fail": "",

"Dialog.log": "Log",
"Dialog.noLogs": "No Logs",

"Notification.notificationTest": "Testing Notification",
"Notification.succeedToTestNotification": "The testing notification was sent successfully.",
Expand Down
1 change: 1 addition & 0 deletions public/locales/es-419.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"EggGraph.fail": "",

"Dialog.log": "Registro",
"Dialog.noLogs": "Sin registros",

"Notification.notificationTest": "Notificación de prueba",
"Notification.succeedToTestNotification": "La notificación de prueba se envió correctamente.",
Expand Down
1 change: 1 addition & 0 deletions public/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"EggGraph.fail": "",

"Dialog.log": "Registro",
"Dialog.noLogs": "Sin registros",

"Notification.notificationTest": "Notificación de prueba",
"Notification.succeedToTestNotification": "La notificación de prueba se envió correctamente.",
Expand Down
1 change: 1 addition & 0 deletions public/locales/fr-CA.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"EggGraph.fail": "",

"Dialog.log": "Journal",
"Dialog.noLogs": "Aucun journal",

"Notification.notificationTest": "Notification de test",
"Notification.succeedToTestNotification": "La notification de test a été envoyée avec succès.",
Expand Down
1 change: 1 addition & 0 deletions public/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"EggGraph.fail": "",

"Dialog.log": "Journal",
"Dialog.noLogs": "Aucun journal",

"Notification.notificationTest": "Notification de test",
"Notification.succeedToTestNotification": "La notification de test a été envoyée avec succès.",
Expand Down
1 change: 1 addition & 0 deletions public/locales/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"EggGraph.fail": "",

"Dialog.log": "Registro",
"Dialog.noLogs": "Nessun registro",

"Notification.notificationTest": "Notifica di prova",
"Notification.succeedToTestNotification": "La notifica di prova è stata inviata con successo.",
Expand Down
1 change: 1 addition & 0 deletions public/locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"EggGraph.fail": "NG",

"Dialog.log": "ログ",
"Dialog.noLogs": "ログがありません",

"Notification.notificationTest": "通知テスト",
"Notification.succeedToTestNotification": "通知テストに成功しました",
Expand Down
1 change: 1 addition & 0 deletions public/locales/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"EggGraph.failure": "NG",

"Dialog.log": "로그",
"Dialog.noLogs": "로그 없음",

"Notification.notificationTest": "테스트 알림",
"Notification.succeedToTestNotification": "테스트 알림이 성공적으로 전송되었습니다.",
Expand Down
1 change: 1 addition & 0 deletions public/locales/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"EggGraph.fail": "",

"Dialog.log": "Logboek",
"Dialog.noLogs": "Geen logboeken",

"Notification.notificationTest": "Testmelding",
"Notification.succeedToTestNotification": "De testmelding is succesvol verzonden.",
Expand Down
1 change: 1 addition & 0 deletions public/locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"EggGraph.fail": "",

"Dialog.log": "Журнал",
"Dialog.noLogs": "Нет журналов",

"Notification.notificationTest": "Тестирование уведомления",
"Notification.succeedToTestNotification": "Тестовое уведомление было успешно отправлено.",
Expand Down
1 change: 1 addition & 0 deletions public/locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"EggGraph.fail": "NG",

"Dialog.log": "日志",
"Dialog.noLogs": "没有日志",

"Notification.notificationTest": "测试通知",
"Notification.succeedToTestNotification": "测试通知已成功发送。",
Expand Down
1 change: 1 addition & 0 deletions public/locales/zh-TW.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"EggGraph.fail": "NG",

"Dialog.log": "日誌",
"Dialog.noLogs": "沒有日誌",

"Notification.notificationTest": "測試通知",
"Notification.succeedToTestNotification": "測試通知已成功發送。",
Expand Down
3 changes: 2 additions & 1 deletion src/app/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { combineReducers, configureStore } from '@reduxjs/toolkit'
import { FLUSH, PAUSE, PERSIST, PURGE, REGISTER, REHYDRATE } from 'redux-persist'
import persistStore from 'redux-persist/es/persistStore'

import autoCleanupLogs from '@/notification/middlewares/autoCleanupLogs'
import log from '@/notification/slicers'
import overlay from '@/overlay/slicers'
import config from '@/settings/slicers'
Expand All @@ -25,7 +26,7 @@ const store = configureStore({
serializableCheck: {
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
},
}).concat(overlayMiddleware as any),
}).concat(overlayMiddleware as any, autoCleanupLogs),
})

export const persistor = persistStore(store)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from 'react'
import { memo, useEffect, useRef, useState } from 'react'
import { useIntl } from 'react-intl'

import type { WebSocketLog } from '@/telemetry/hooks/websocket'
Expand All @@ -11,10 +11,10 @@ import NotificationMessages from './messages'

const SUPPRESS_DISCONNECT_DURATION = 2 * 60 * 1000

const NotificationController = () => {
const NotificationController = function () {
const intl = useIntl()
const logs = useAppSelector(state => state.log.logs)
const [previousLogLength, setPreviousLogLength] = useState(0)
const [previousTimestamp, setPreviousTimestamp] = useState(Date.now())
const [previousDisconnectedTimestamp, setPreviousDisconnectedTimestamp] = useState(0)
const savedRef = useRef<NotificationHandle>(null)

Expand All @@ -24,7 +24,14 @@ const NotificationController = () => {
return
}

for (let i = previousLogLength; i < logs.length; ++i) {
const targetIndex = logs.findIndex(function (log) {
return log.timestamp > previousTimestamp
})
if (targetIndex === -1) {
return
}

for (let i = targetIndex; i >= 0; --i) {
const log = logs[i]

let message: NotificationMessage
Expand Down Expand Up @@ -63,10 +70,10 @@ const NotificationController = () => {
}
handler.publish(message)
}
setPreviousLogLength(logs.length)
setPreviousTimestamp(logs[0].timestamp)
}, [logs])

return <NotificationHost ref={savedRef} maxCount={5} />
return <NotificationHost ref={savedRef} maxCount={3} />
}

export default NotificationController
export default memo(NotificationController)
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { memo } from 'react'

import { XMarkIcon } from '@heroicons/react/16/solid'
import * as ToastPrimitive from '@radix-ui/react-toast'

interface NotificationProps {
timestamp: number
title: string
description?: string
duration?: number
readonly timestamp: number
readonly title: string
readonly description?: string
readonly duration?: number
onClose?(timestamp: number): void
}

Expand Down Expand Up @@ -47,4 +49,4 @@ const Notification = (props: NotificationProps) => {
)
}

export default Notification
export default memo(Notification)
55 changes: 32 additions & 23 deletions src/modules/notification/components/NotificationHost/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ export interface NotificationHandle {
}

export interface NotificationMessage {
timestamp: number
title: string
description?: string
duration?: number
readonly timestamp: number
readonly title: string
readonly description?: string
readonly duration?: number
}

export interface NotificationHostProps {
Expand All @@ -26,41 +26,50 @@ export const NotificationHost = forwardRef<NotificationHandle, NotificationHostP
const [isBottom, setIsBottom] = useState(true)
const [notifications, setNotifications] = useState<NotificationMessage[]>([])

useImperativeHandle(forwardedRef, () => ({
publish: (notification: NotificationMessage) => {
const length = notifications.length + 1
if (maxCount && length > maxCount) {
const newNotifications = notifications.slice(length - maxCount)
newNotifications.push(notification)
setNotifications(newNotifications)
} else {
const newNotifications = [...notifications, notification]
setNotifications(newNotifications)
}
},
}))
useImperativeHandle(forwardedRef, function () {
return {
publish(notification: NotificationMessage) {
const length = notifications.length + 1
if (maxCount && length > maxCount) {
const newNotifications = notifications.slice(length - maxCount)
newNotifications.push(notification)
setNotifications(newNotifications)
} else {
const newNotifications = [...notifications, notification]
setNotifications(newNotifications)
}
},
} satisfies NotificationHandle
})

useEffect(() => {
useEffect(function () {
if (isBottom && ref.current) {
ref.current.scrollTop = ref.current.scrollHeight
}
}, [notifications])

const handleScroll = (e: UIEvent) => {
const handleScroll = function (e: UIEvent) {
const target = e.currentTarget
const availableTop = target.scrollHeight - target.clientHeight
setIsBottom(target.scrollTop === availableTop)
}

const handleClose = useCallback((timestamp: number) => {
const handleClose = useCallback(function (timestamp: number) {
setNotifications(function (notifications) {
const index = notifications.findIndex(n => n.timestamp === timestamp)
notifications.splice(index, 1)
}, [])
if (index !== -1) {
const newNotifications = notifications.slice(0)
newNotifications.splice(index, 1)
return newNotifications
}
return notifications
})
}, [setNotifications])

return (
<ToastPrimitive.Provider swipeDirection='right'>
<>
{notifications.map(notification => {
{notifications.map(function (notification) {
return (
<Notification
key={notification.timestamp}
Expand Down
Loading

0 comments on commit 132ee5b

Please sign in to comment.