Skip to content

Commit d65d464

Browse files
authored
Fix toast notification to show link to model transfer job (opendatahub-io#6709)
* Fix toast notification to show link to model transfer job Signed-off-by: ppadti <ppadti@redhat.com> * Fix lint Signed-off-by: ppadti <ppadti@redhat.com> --------- Signed-off-by: ppadti <ppadti@redhat.com>
1 parent e4ce8ff commit d65d464

File tree

2 files changed

+80
-46
lines changed

2 files changed

+80
-46
lines changed

frontend/src/utilities/useFederatedNotificationListener.ts renamed to frontend/src/utilities/useFederatedNotificationListener.tsx

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { useEffect } from 'react';
1+
import React, { useEffect } from 'react';
2+
import { useNavigate } from 'react-router-dom';
23
import { AlertVariant } from '@patternfly/react-core';
34
import { useAppDispatch } from '#~/redux/hooks';
45
import { addNotification } from '#~/redux/actions/actions';
@@ -23,28 +24,60 @@ const NOTIFICATION_BRIDGE_EVENT = 'odh-notification-bridge';
2324

2425
export const useFederatedNotificationListener = (): void => {
2526
const dispatch = useAppDispatch();
27+
const navigate = useNavigate();
2628

2729
useEffect(() => {
2830
const handleNotificationEvent = (event: Event) => {
2931
try {
3032
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
31-
const customEvent = event as CustomEvent;
32-
if (!customEvent.detail) {
33-
return;
34-
}
33+
const { detail } = event as CustomEvent;
34+
if (!detail) return;
3535

36-
const { status, title, message, timestamp } = customEvent.detail;
36+
const {
37+
status,
38+
title,
39+
message,
40+
timestamp,
41+
linkUrl,
42+
linkLabel,
43+
}: {
44+
status?: AlertVariant;
45+
title: string;
46+
message?: string;
47+
timestamp?: string;
48+
linkUrl?: string;
49+
linkLabel?: string;
50+
} = detail;
3751

3852
const timestampDate = timestamp ? new Date(timestamp) : new Date();
3953

40-
dispatch(
41-
addNotification({
42-
status: status || AlertVariant.info,
43-
title,
44-
message,
45-
timestamp: timestampDate,
46-
}),
47-
);
54+
const notificationMessage =
55+
linkUrl && linkLabel && message ? (
56+
<p>
57+
{message}
58+
<a
59+
href={linkUrl}
60+
onClick={(e: React.MouseEvent) => {
61+
e.preventDefault();
62+
navigate(linkUrl);
63+
}}
64+
>
65+
{linkLabel}
66+
</a>
67+
.
68+
</p>
69+
) : (
70+
message
71+
);
72+
73+
const notificationPayload = {
74+
status: status || AlertVariant.info,
75+
title,
76+
message: notificationMessage,
77+
timestamp: timestampDate,
78+
};
79+
80+
dispatch(addNotification(notificationPayload));
4881
} catch (error) {
4982
console.error('[NotificationBridge] Failed to handle notification event:', error);
5083
}
@@ -55,5 +88,5 @@ export const useFederatedNotificationListener = (): void => {
5588
return () => {
5689
window.removeEventListener(NOTIFICATION_BRIDGE_EVENT, handleNotificationEvent);
5790
};
58-
}, [dispatch]);
91+
}, [dispatch, navigate]);
5992
};

packages/model-registry/upstream/frontend/src/odh/hooks/useNotificationListener.ts

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,39 +17,40 @@ const NOTIFICATION_BRIDGE_EVENT = 'odh-notification-bridge';
1717

1818
export const useNotificationListener = (): void => {
1919
const { notifications } = useContext(NotificationContext);
20-
const lastNotificationIdRef = useRef<number | undefined>();
20+
const lastBridgedIndexRef = useRef(0);
2121

2222
useEffect(() => {
23-
if (notifications.length > 0) {
24-
const lastNotification = notifications[notifications.length - 1];
25-
26-
// Only dispatch event for new notifications we haven't seen before
27-
if (
28-
lastNotification.id !== undefined &&
29-
lastNotification.id !== lastNotificationIdRef.current &&
30-
!lastNotification.hidden
31-
) {
32-
lastNotificationIdRef.current = lastNotification.id;
33-
34-
try {
35-
const messageStr =
36-
typeof lastNotification.message === 'string' ? lastNotification.message : undefined;
37-
38-
// Dispatch a custom event that the midstream can listen to
39-
const event = new CustomEvent(NOTIFICATION_BRIDGE_EVENT, {
40-
detail: {
41-
status: lastNotification.status,
42-
title: lastNotification.title,
43-
message: messageStr,
44-
timestamp: lastNotification.timestamp?.toISOString() || new Date().toISOString(),
45-
},
46-
});
47-
48-
window.dispatchEvent(event);
49-
} catch (error) {
50-
console.error('[NotificationBridge] Failed to dispatch notification:', error);
51-
}
23+
const newNotifications = notifications.slice(lastBridgedIndexRef.current);
24+
lastBridgedIndexRef.current = notifications.length;
25+
26+
newNotifications.forEach((notification) => {
27+
if (notification.hidden || typeof notification.title !== 'string') {
28+
return;
29+
}
30+
31+
try {
32+
const messageStr =
33+
typeof notification.messageText === 'string'
34+
? notification.messageText
35+
: typeof notification.message === 'string'
36+
? notification.message
37+
: undefined;
38+
39+
const detail: Record<string, unknown> = {
40+
status: notification.status,
41+
title: notification.title,
42+
message: messageStr,
43+
timestamp: notification.timestamp?.toISOString() || new Date().toISOString(),
44+
...(notification.linkUrl && notification.linkLabel && {
45+
linkUrl: notification.linkUrl,
46+
linkLabel: notification.linkLabel,
47+
}),
48+
};
49+
50+
window.dispatchEvent(new CustomEvent(NOTIFICATION_BRIDGE_EVENT, { detail }));
51+
} catch (error) {
52+
console.error('[NotificationBridge] Failed to dispatch notification:', error);
5253
}
53-
}
54+
});
5455
}, [notifications]);
5556
};

0 commit comments

Comments
 (0)