Skip to content

Commit

Permalink
feat: deployment terminal (#94)
Browse files Browse the repository at this point in the history
* feat: 20 wip terminal - composition card url by qs endpoint

* feat: 20 eslint fixes

* feat: 20 update events list

* feat: 20 events endpoint fix

* feat: 20 update notification style

* feat: 20 chartflow check initial data

* feat: 20 endpoints namespace as parameter

* feat: 20 events limit and queue append

* feat: 20 delete and read functionalities removed

* feat: 20 store notification data on intervals
  • Loading branch information
codev99 authored Aug 2, 2024
1 parent 0e7531a commit a27fff1
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 50 deletions.
3 changes: 2 additions & 1 deletion public/config/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
67 changes: 28 additions & 39 deletions src/components/Notifications/Notifications.tsx
Original file line number Diff line number Diff line change
@@ -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<boolean>(false);
const navigate = useNavigate();
const { data, isSuccess, isLoading } = useGetNotificationsQuery();
const [deleteNotification, {isSuccess: isDeleteSuccess, isLoading: isDeleteLoading}] = useDeleteNotificationMutation();

const timer = useRef<NodeJS.Timeout>();
const eventsToAppend = useRef<NotificationType[]>([]);

const dispatch = useAppDispatch();
const notifications = useSelector((state: RootState) => selectNotifications(state));
const [notificationToDelete, setNotificationToDelete] = useState<string>();

const { useToken } = theme;
const { token } = useToken();
Expand All @@ -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,
Expand Down Expand Up @@ -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)
Expand All @@ -115,22 +102,29 @@ 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,
kind: data.involvedObject.kind,
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
Expand All @@ -139,7 +133,7 @@ const Notification = () => {

return (
<div className={styles.notifications}>
<Badge className={styles.badge} count={notifications.filter(el => el.toRead).length}>
<Badge className={styles.badge} count={notifications.length}>
<Button
className={styles.toolButton}
type="link"
Expand Down Expand Up @@ -168,21 +162,16 @@ const Notification = () => {
return (
<List.Item
key={item.uid}
actions={[
<Button loading={item.uid === notificationToDelete && isDeleteLoading} type="text" shape='circle' icon={<DeleteFilled />} onClick={() => onDelete(item.uid)} />
]}
>
<Space style={{width: '100%'}} wrap>
<Button className={styles.notificationElement} type="link" onClick={() => onClickNotification(item)}>
<Space direction='vertical'>
<Badge color={item.type === "Normal" ? token.colorInfo : token.colorWarning} text={
<Typography.Text className={styles.title}>{item.toRead ? <strong>{item.title}</strong> : item.title}</Typography.Text>
} />
<Typography.Text className={styles.description}>{item.description}</Typography.Text>
<Typography.Paragraph className={styles.details}>{`${item.apiVersion}.${item.kind}/${item.name}@${item.namespace}`}</Typography.Paragraph>
</Space>
</Button>
</Space>
<Button className={styles.notificationElement} type="link" onClick={() => onClickNotification(item)}>
<Space direction='vertical'>
<Badge color={item.type === "Normal" ? token.colorInfo : token.colorWarning} text={
<Typography.Text className={styles.title} strong>{item.title}</Typography.Text>
} />
<Typography.Text className={styles.description}>{item.description}</Typography.Text>
<Typography.Paragraph className={styles.details}>{`${item.apiVersion}.${item.kind}/${item.name}@${item.namespace}`}</Typography.Paragraph>
</Space>
</Button>
</List.Item>
)
}}
Expand Down
4 changes: 3 additions & 1 deletion src/components/Notifications/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -40,6 +40,8 @@
position: relative;
padding: 0;
text-wrap: wrap;
display: block;
width: 100%;

.icon {
margin-right: 10px;
Expand Down
10 changes: 3 additions & 7 deletions src/features/notifications/notificationsSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export type NotificationType = {
description: string,
date: string,
url: string,
toRead: boolean,
kind: string,
name: string,
namespace: string,
Expand All @@ -30,19 +29,16 @@ export const notificationsSlice = createSlice({
setNotifications: (state, action: PayloadAction<{data: NotificationType[]}>) => {
state.data = action.payload.data;
},
setNotificationRead: (state, action: PayloadAction<string>) => {
state.data = state.data.map(el => (el.uid === action.payload ? {...el, toRead: false} : el))
},
appendNotification: (state, action: PayloadAction<NotificationType>) => {
state.data = [action.payload, ...(state.data.length > 99 ? state.data.slice(0, 98) : state.data) ]
appendNotification: (state, action: PayloadAction<NotificationType[]>) => {
state.data = [...action.payload, ...(state.data.length > 99 ? state.data.slice(0, 100 - action.payload.length) : state.data) ]
},
removeNotification: (state, action: PayloadAction<string>) => {
state.data = state.data.filter(el => (el.uid !== action.payload))
}
}
});

export const { setNotifications, setNotificationRead, appendNotification, removeNotification } = notificationsSlice.actions;
export const { setNotifications, appendNotification, removeNotification } = notificationsSlice.actions;

export default notificationsSlice.reducer;

Expand Down
8 changes: 6 additions & 2 deletions src/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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") {
Expand All @@ -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;
}
Expand Down

0 comments on commit a27fff1

Please sign in to comment.