diff --git a/public/config/config.json b/public/config/config.json index 5d5a44d..1a06d79 100644 --- a/public/config/config.json +++ b/public/config/config.json @@ -7,6 +7,7 @@ "TERMINAL_SOCKET_URL": "http://4.208.220.117:8080" }, "params": { - "FRONTEND_NAMESPACE": "demo-system" + "FRONTEND_NAMESPACE": "demo-system", + "DELAY_SAVE_NOTIFICATION": 10000 } } \ No newline at end of file diff --git a/src/components/Notifications/Notifications.tsx b/src/components/Notifications/Notifications.tsx index caae2b0..94b4a9c 100644 --- a/src/components/Notifications/Notifications.tsx +++ b/src/components/Notifications/Notifications.tsx @@ -1,26 +1,27 @@ -import { BellFilled, DeleteFilled } from "@ant-design/icons"; +import { BellFilled } from "@ant-design/icons"; import { Badge, Button, Drawer, List, Space, theme, Typography } from "antd"; -import { useEffect, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { useAppDispatch } from "../../redux/hooks"; import { useSelector } from "react-redux"; import { RootState } from "../../redux/store"; -import { appendNotification, NotificationType, removeNotification, selectNotifications, setNotificationRead, setNotifications } from "../../features/notifications/notificationsSlice"; +import { appendNotification, NotificationType, selectNotifications, setNotifications } from "../../features/notifications/notificationsSlice"; import styles from './styles.module.scss'; import { useNavigate } from "react-router-dom"; -import { useDeleteNotificationMutation, useGetNotificationsQuery } from "../../features/notifications/notificationApiSlice"; +import { useGetNotificationsQuery } from "../../features/notifications/notificationApiSlice"; import Skeleton from "../Skeleton/Skeleton"; -import { getBaseUrl } from "../../utils/config"; +import { getBaseUrl, getParam } from "../../utils/config"; import { formatISODate } from "../../utils/dateTime"; const Notification = () => { const [showNotificationPanel, setShowNotificationPanel] = useState(false); const navigate = useNavigate(); const { data, isSuccess, isLoading } = useGetNotificationsQuery(); - const [deleteNotification, {isSuccess: isDeleteSuccess, isLoading: isDeleteLoading}] = useDeleteNotificationMutation(); + + const timer = useRef(); + const eventsToAppend = useRef([]); const dispatch = useAppDispatch(); const notifications = useSelector((state: RootState) => selectNotifications(state)); - const [notificationToDelete, setNotificationToDelete] = useState(); const { useToken } = theme; const { token } = useToken(); @@ -36,7 +37,6 @@ const Notification = () => { description: el.message, date: el.metadata.creationTimestamp, url: getNotificationURL(el), - toRead: true, name: el.involvedObject.name, namespace: el.involvedObject.namespace, apiVersion: el.involvedObject.apiVersion, @@ -73,25 +73,12 @@ const Notification = () => { // dispatch(setNotifications({ data: mockData })); }, [data, dispatch, isSuccess]) - const onDelete = async (id: string) => { - await deleteNotification(id); - setNotificationToDelete(id); - } - const onClickNotification = (el: NotificationType) => { - // set as read - dispatch(setNotificationRead(el.uid)); if (el.url?.length > 0) { navigate(el.url) } } - useEffect(() => { - if (isDeleteSuccess && notificationToDelete) { - dispatch(removeNotification(notificationToDelete)); // deleteData is the element ID deleted - } - }, [dispatch, isDeleteSuccess, notificationToDelete]); - const getNotificationURL = (el) => { const url = ""; // se è presente compositionId allora è un composition (ex deployment) @@ -115,14 +102,12 @@ const Notification = () => { eventSource.addEventListener("krateo", (event) => { const data = JSON.parse(event.data); - const notification: NotificationType = { uid: data.metadata.uid, date: data.metadata.creationTimestamp, title: formatISODate(data.metadata.creationTimestamp, true), type: data.type, description: data.message, - toRead: true, url: getNotificationURL(data), name: data.involvedObject.name, namespace: data.involvedObject.namespace, @@ -130,7 +115,16 @@ const Notification = () => { apiVersion: data.involvedObject.apiVersion, } - dispatch(appendNotification(notification)); + // create a list to append after + eventsToAppend.current = [notification, ...eventsToAppend.current]; + + if (!timer.current) { + timer.current = setTimeout(() => { + dispatch(appendNotification(eventsToAppend.current)); + eventsToAppend.current = []; + timer.current = undefined; + }, getParam("DELAY_SAVE_NOTIFICATION")) + } }); // terminating the connection on component unmount @@ -139,7 +133,7 @@ const Notification = () => { return (
- el.toRead).length}> + - + ) }} diff --git a/src/components/Notifications/styles.module.scss b/src/components/Notifications/styles.module.scss index ca54575..f28a879 100644 --- a/src/components/Notifications/styles.module.scss +++ b/src/components/Notifications/styles.module.scss @@ -26,7 +26,7 @@ .notificationList { :global li.ant-list-item { align-items: baseline; - padding: 5px 10px 0 30px; + padding: 15px 10px 0 30px; border-radius: 10px; &:hover { @@ -40,6 +40,8 @@ position: relative; padding: 0; text-wrap: wrap; + display: block; + width: 100%; .icon { margin-right: 10px; diff --git a/src/features/notifications/notificationsSlice.ts b/src/features/notifications/notificationsSlice.ts index 59a4f43..cdb6b54 100644 --- a/src/features/notifications/notificationsSlice.ts +++ b/src/features/notifications/notificationsSlice.ts @@ -8,7 +8,6 @@ export type NotificationType = { description: string, date: string, url: string, - toRead: boolean, kind: string, name: string, namespace: string, @@ -30,11 +29,8 @@ export const notificationsSlice = createSlice({ setNotifications: (state, action: PayloadAction<{data: NotificationType[]}>) => { state.data = action.payload.data; }, - setNotificationRead: (state, action: PayloadAction) => { - state.data = state.data.map(el => (el.uid === action.payload ? {...el, toRead: false} : el)) - }, - appendNotification: (state, action: PayloadAction) => { - state.data = [action.payload, ...(state.data.length > 99 ? state.data.slice(0, 98) : state.data) ] + appendNotification: (state, action: PayloadAction) => { + state.data = [...action.payload, ...(state.data.length > 99 ? state.data.slice(0, 100 - action.payload.length) : state.data) ] }, removeNotification: (state, action: PayloadAction) => { state.data = state.data.filter(el => (el.uid !== action.payload)) @@ -42,7 +38,7 @@ export const notificationsSlice = createSlice({ } }); -export const { setNotifications, setNotificationRead, appendNotification, removeNotification } = notificationsSlice.actions; +export const { setNotifications, appendNotification, removeNotification } = notificationsSlice.actions; export default notificationsSlice.reducer; diff --git a/src/utils/config.ts b/src/utils/config.ts index 47ccda5..8457dc9 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -34,8 +34,8 @@ export const getBaseUrl = (type: "AUTH" | "BFF" | "EVENTS_PUSH" | "TERMINAL_SOCK return baseUrl; } -export const getParam = (name: "FRONTEND_NAMESPACE") => { - let param = ""; +export const getParam = (name: "FRONTEND_NAMESPACE" | "DELAY_SAVE_NOTIFICATION") => { + let param; const useConfig = import.meta.env.VITE_USE_CONFIG; if (useConfig === "true") { @@ -47,6 +47,10 @@ export const getParam = (name: "FRONTEND_NAMESPACE") => { param = configJson.params.FRONTEND_NAMESPACE; break; + case "DELAY_SAVE_NOTIFICATION": + param = configJson.params.DELAY_SAVE_NOTIFICATION; + break; + default: break; }