MINOR: fix the knowledge, Glossary/Term page redirect notification link (#21341)

* fix the knowledge page redirect notification link

* fix the feed redirection for glossary

* use entityRef data for displayName if present

(cherry picked from commit 8d4b7c78947678e151ff448a77f63bf2eb00a23d)
This commit is contained in:
Ashish Gupta 2025-08-23 22:01:46 +05:30 committed by OpenMetadata Release Bot
parent ca8610314d
commit 66dfc9d375
3 changed files with 132 additions and 8 deletions

View File

@ -21,7 +21,7 @@ import {
formatDateTime,
getRelativeTime,
} from '../../utils/date-time/DateTimeUtils';
import { getEntityLinkFromType } from '../../utils/EntityUtils';
import { getEntityLinkFromType, getEntityName } from '../../utils/EntityUtils';
import { entityDisplayName, prepareFeedLink } from '../../utils/FeedUtils';
import Fqn from '../../utils/Fqn';
import { getTaskDetailPath } from '../../utils/TasksUtils';
@ -84,6 +84,12 @@ const NotificationFeedCard: FC<NotificationFeedProp> = ({
);
}, [entityType, task, taskDetails]);
const entityName = useMemo(() => {
return task?.entityRef
? getEntityName(task?.entityRef)
: entityDisplayName(entityType, entityFQN);
}, [task, entityType, entityFQN]);
return (
<Link
className="no-underline"
@ -96,7 +102,10 @@ const NotificationFeedCard: FC<NotificationFeedProp> = ({
avatar={<ProfilePicture name={createdBy} width="32" />}
className="m-0"
description={
<Space direction="vertical" size={0}>
<Space
data-testid={`notification-item-${entityName}`}
direction="vertical"
size={0}>
<Typography.Paragraph
className="m-0"
style={{ color: '#37352F', marginBottom: 0 }}>
@ -107,8 +116,9 @@ const NotificationFeedCard: FC<NotificationFeedProp> = ({
<span>{entityType} </span>
<Link
className="truncate"
data-testid={`notification-link-${entityName}`}
to={prepareFeedLink(entityType, entityFQN)}>
{entityDisplayName(entityType, entityFQN)}
{entityName}
</Link>
</>
) : (

View File

@ -13,6 +13,7 @@
import { act, render, screen } from '@testing-library/react';
import React from 'react';
import { ThreadType } from '../../generated/api/feed/createThread';
import { Thread } from '../../generated/entity/feed/thread';
import NotificationFeedCard from './NotificationFeedCard.component';
jest.mock('../../utils/date-time/DateTimeUtils', () => ({
@ -40,21 +41,63 @@ jest.mock('react-router-dom', () => ({
}));
jest.mock('../../utils/EntityUtils', () => ({
getEntityLinkFromType: jest.fn().mockReturnValue('/mock-entity-link'),
getEntityName: jest
.fn()
.mockImplementation(({ displayName, name }) => displayName || name || ''),
}));
jest.mock('../../utils/Fqn', () => ({
split: jest.fn().mockReturnValue(['mockGlossary']),
}));
const mockThread = {
about: 'test',
id: '33873393-bd68-46e9-bccc-7701c1c41ad6',
message: 'f93d08e9-2d38-4d01-a294-f8b44fbb0f4a',
type: 'Conversation',
href: 'http://host.docker.internal:8585/v1/feed/b41ef8d2-e369-4fce-b106-8f000258e361',
threadTs: 1755772414483,
about: '<#E::page::Article_sQDEeTK6::description>',
entityRef: {
id: 'eda48fe4-515f-44ee-8afc-f7e4ef01277a',
type: 'page',
name: 'Article_sQDEeTK6',
fullyQualifiedName: 'Article_sQDEeTK6',
description: '',
displayName: 'SACHIN',
},
generatedBy: 'user',
cardStyle: 'default',
fieldOperation: 'updated',
createdBy: 'admin',
updatedAt: 1755772414483,
updatedBy: 'admin',
resolved: false,
task: {
id: 16,
type: 'RequestTestCaseFailureResolution',
assignees: [
{
id: '9311f065-e150-4948-96a4-e98906443b37',
type: 'user',
name: 'admin',
fullyQualifiedName: 'admin',
displayName: 'admin',
deleted: false,
},
],
status: 'Open',
testCaseResolutionStatusId: '29c0871d-bd96-431b-8823-e968316915af',
},
message:
'<#E::user::admin|[@admin](http://localhost:3000/users/admin)> Hii!',
postsCount: 0,
posts: [],
reactions: [],
};
const mockProps = {
createdBy: 'admin',
entityType: 'task',
entityFQN: 'test',
task: mockThread,
task: mockThread as Thread,
feedType: ThreadType.Task,
};
@ -66,4 +109,76 @@ describe('Test NotificationFeedCard Component', () => {
expect(await screen.findByText('ProfilePicture')).toBeInTheDocument();
});
it('renders assigned task message and link for ThreadType.Task', async () => {
await act(async () => {
render(<NotificationFeedCard {...mockProps} />);
});
expect(
screen.getByText(/assigned-you-a-new-task-lowercase/i)
).toBeInTheDocument();
expect(
screen.getByText(`#${mockThread.task.id} ${mockThread.task.type}`)
).toBeInTheDocument();
});
it('renders mentioned message and entity link for ThreadType.Conversation', async () => {
const conversationProps = {
...mockProps,
feedType: ThreadType.Conversation,
};
await act(async () => {
render(<NotificationFeedCard {...conversationProps} />);
});
expect(
screen.getByText(/mentioned-you-on-the-lowercase/i)
).toBeInTheDocument();
expect(screen.getByText(conversationProps.entityType)).toBeInTheDocument();
});
it('should renders entityRef data is available', async () => {
const conversationProps = {
...mockProps,
feedType: ThreadType.Conversation,
};
await act(async () => {
render(<NotificationFeedCard {...conversationProps} />);
});
expect(
screen.getByText(mockThread.entityRef.displayName)
).toBeInTheDocument();
});
it('should renders default entityName by entityDisplayName if entityRef not present', async () => {
const conversationProps = {
...mockProps,
task: {
...mockProps.task,
entityRef: undefined,
},
feedType: ThreadType.Conversation,
};
await act(async () => {
render(<NotificationFeedCard {...conversationProps} />);
});
expect(screen.getByText('database.schema.table')).toBeInTheDocument();
});
it('renders timestamp', async () => {
const timestampProps = {
...mockProps,
timestamp: 1692612000000, // Example: 2023-08-21T10:00:00Z in ms
};
await act(async () => {
render(<NotificationFeedCard {...timestampProps} />);
});
expect(screen.getByText('1692612000000')).toBeInTheDocument();
});
});

View File

@ -501,9 +501,8 @@ export const updateThreadData = async (
export const prepareFeedLink = (entityType: string, entityFQN: string) => {
const withoutFeedEntities = [
EntityType.WEBHOOK,
EntityType.GLOSSARY,
EntityType.GLOSSARY_TERM,
EntityType.TYPE,
EntityType.KNOWLEDGE_PAGE,
];
const entityLink = entityUtilClassBase.getEntityLink(entityType, entityFQN);