mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-06-27 04:22:05 +00:00
supported rendering all suggestion on user avatar click
This commit is contained in:
parent
c77f6d5db6
commit
efb99c2889
@ -30,6 +30,7 @@ export interface SuggestionsContextType {
|
|||||||
allSuggestionsUsers: EntityReference[];
|
allSuggestionsUsers: EntityReference[];
|
||||||
onUpdateActiveUser: (user?: EntityReference) => void;
|
onUpdateActiveUser: (user?: EntityReference) => void;
|
||||||
fetchSuggestions: () => void;
|
fetchSuggestions: () => void;
|
||||||
|
fetchSuggestionsByUserId: (userId: string, limit?: number) => void;
|
||||||
acceptRejectSuggestion: (
|
acceptRejectSuggestion: (
|
||||||
suggestion: Suggestion,
|
suggestion: Suggestion,
|
||||||
action: SuggestionAction
|
action: SuggestionAction
|
||||||
|
@ -45,6 +45,7 @@ jest.mock('../../../hooks/useFqn', () => ({
|
|||||||
|
|
||||||
jest.mock('../../../rest/suggestionsAPI', () => ({
|
jest.mock('../../../rest/suggestionsAPI', () => ({
|
||||||
getSuggestionsList: jest.fn().mockImplementation(() => Promise.resolve()),
|
getSuggestionsList: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
|
getSuggestionsByUserId: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
approveRejectAllSuggestions: jest.fn(),
|
approveRejectAllSuggestions: jest.fn(),
|
||||||
updateSuggestionStatus: jest.fn(),
|
updateSuggestionStatus: jest.fn(),
|
||||||
}));
|
}));
|
||||||
@ -144,6 +145,26 @@ describe('SuggestionsProvider', () => {
|
|||||||
SuggestionAction.Reject
|
SuggestionAction.Reject
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('calls fetchSuggestionsByUserId when button is clicked', async () => {
|
||||||
|
const { getSuggestionsByUserId } = await import(
|
||||||
|
'../../../rest/suggestionsAPI'
|
||||||
|
);
|
||||||
|
|
||||||
|
render(
|
||||||
|
<SuggestionsProvider>
|
||||||
|
<TestComponent />
|
||||||
|
</SuggestionsProvider>
|
||||||
|
);
|
||||||
|
|
||||||
|
const fetchByUserIdBtn = screen.getByText('Fetch By User ID');
|
||||||
|
fireEvent.click(fetchByUserIdBtn);
|
||||||
|
|
||||||
|
expect(getSuggestionsByUserId).toHaveBeenCalledWith('test-user-id', {
|
||||||
|
entityFQN: 'mockFQN',
|
||||||
|
limit: 10,
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function TestComponent() {
|
function TestComponent() {
|
||||||
@ -151,6 +172,7 @@ function TestComponent() {
|
|||||||
acceptRejectAllSuggestions,
|
acceptRejectAllSuggestions,
|
||||||
onUpdateActiveUser,
|
onUpdateActiveUser,
|
||||||
acceptRejectSuggestion,
|
acceptRejectSuggestion,
|
||||||
|
fetchSuggestionsByUserId,
|
||||||
} = useSuggestionsContext();
|
} = useSuggestionsContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -181,6 +203,9 @@ function TestComponent() {
|
|||||||
}>
|
}>
|
||||||
Reject One
|
Reject One
|
||||||
</button>
|
</button>
|
||||||
|
<button onClick={() => fetchSuggestionsByUserId('test-user-id')}>
|
||||||
|
Fetch By User ID
|
||||||
|
</button>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ import { useFqn } from '../../../hooks/useFqn';
|
|||||||
import { usePub } from '../../../hooks/usePubSub';
|
import { usePub } from '../../../hooks/usePubSub';
|
||||||
import {
|
import {
|
||||||
approveRejectAllSuggestions,
|
approveRejectAllSuggestions,
|
||||||
|
getSuggestionsByUserId,
|
||||||
getSuggestionsList,
|
getSuggestionsList,
|
||||||
updateSuggestionStatus,
|
updateSuggestionStatus,
|
||||||
} from '../../../rest/suggestionsAPI';
|
} from '../../../rest/suggestionsAPI';
|
||||||
@ -97,6 +98,43 @@ const SuggestionsProvider = ({ children }: { children?: ReactNode }) => {
|
|||||||
[entityFqn, suggestionLimit]
|
[entityFqn, suggestionLimit]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const fetchSuggestionsByUserId = useCallback(
|
||||||
|
async (userId: string, limit?: number) => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const { data } = await getSuggestionsByUserId(userId, {
|
||||||
|
entityFQN: entityFqn,
|
||||||
|
limit: limit ?? suggestionLimit,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Merge new suggestions with existing ones, removing duplicates by ID
|
||||||
|
setSuggestions((prevSuggestions) => {
|
||||||
|
const existingIds = new Set(prevSuggestions.map((s) => s.id));
|
||||||
|
const newSuggestions = data.filter((s) => !existingIds.has(s.id));
|
||||||
|
const mergedSuggestions = [...prevSuggestions, ...newSuggestions];
|
||||||
|
|
||||||
|
// Update grouped suggestions with merged data
|
||||||
|
const { allUsersList, groupedSuggestions } =
|
||||||
|
getSuggestionByType(mergedSuggestions);
|
||||||
|
setAllSuggestionsUsers(uniqWith(allUsersList, isEqual));
|
||||||
|
setSuggestionsByUser(groupedSuggestions);
|
||||||
|
|
||||||
|
return mergedSuggestions;
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
showErrorToast(
|
||||||
|
err as AxiosError,
|
||||||
|
t('server.entity-fetch-error', {
|
||||||
|
entity: t('label.suggestion-lowercase-plural'),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[entityFqn, suggestionLimit]
|
||||||
|
);
|
||||||
|
|
||||||
const acceptRejectSuggestion = useCallback(
|
const acceptRejectSuggestion = useCallback(
|
||||||
async (suggestion: Suggestion, status: SuggestionAction) => {
|
async (suggestion: Suggestion, status: SuggestionAction) => {
|
||||||
try {
|
try {
|
||||||
@ -188,6 +226,7 @@ const SuggestionsProvider = ({ children }: { children?: ReactNode }) => {
|
|||||||
allSuggestionsUsers,
|
allSuggestionsUsers,
|
||||||
onUpdateActiveUser,
|
onUpdateActiveUser,
|
||||||
fetchSuggestions,
|
fetchSuggestions,
|
||||||
|
fetchSuggestionsByUserId,
|
||||||
acceptRejectSuggestion,
|
acceptRejectSuggestion,
|
||||||
acceptRejectAllSuggestions,
|
acceptRejectAllSuggestions,
|
||||||
};
|
};
|
||||||
@ -203,6 +242,7 @@ const SuggestionsProvider = ({ children }: { children?: ReactNode }) => {
|
|||||||
allSuggestionsUsers,
|
allSuggestionsUsers,
|
||||||
onUpdateActiveUser,
|
onUpdateActiveUser,
|
||||||
fetchSuggestions,
|
fetchSuggestions,
|
||||||
|
fetchSuggestionsByUserId,
|
||||||
acceptRejectSuggestion,
|
acceptRejectSuggestion,
|
||||||
acceptRejectAllSuggestions,
|
acceptRejectAllSuggestions,
|
||||||
]);
|
]);
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { EntityReference } from '../../../generated/entity/type';
|
import { EntityReference } from '../../../generated/entity/type';
|
||||||
|
import { useSuggestionsContext } from '../../Suggestions/SuggestionsProvider/SuggestionsProvider';
|
||||||
import AvatarCarouselItem from './AvatarCarouselItem';
|
import AvatarCarouselItem from './AvatarCarouselItem';
|
||||||
|
|
||||||
const suggestions = [
|
const suggestions = [
|
||||||
@ -46,6 +47,7 @@ jest.mock('../../Suggestions/SuggestionsProvider/SuggestionsProvider', () => ({
|
|||||||
acceptRejectSuggestion: jest.fn(),
|
acceptRejectSuggestion: jest.fn(),
|
||||||
selectedUserSuggestions: [],
|
selectedUserSuggestions: [],
|
||||||
onUpdateActiveUser: jest.fn(),
|
onUpdateActiveUser: jest.fn(),
|
||||||
|
fetchSuggestionsByUserId: jest.fn(),
|
||||||
})),
|
})),
|
||||||
__esModule: true,
|
__esModule: true,
|
||||||
default: 'SuggestionsProvider',
|
default: 'SuggestionsProvider',
|
||||||
@ -101,6 +103,37 @@ describe('AvatarCarouselItem', () => {
|
|||||||
expect(onAvatarClick).toHaveBeenCalledWith(index);
|
expect(onAvatarClick).toHaveBeenCalledWith(index);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('calls fetchSuggestionsByUserId when avatar is clicked', () => {
|
||||||
|
const mockFetchSuggestionsByUserId = jest.fn();
|
||||||
|
(useSuggestionsContext as jest.Mock).mockImplementation(() => ({
|
||||||
|
suggestions: suggestions,
|
||||||
|
suggestionsByUser: suggByUser,
|
||||||
|
allSuggestionsUsers: [
|
||||||
|
{ id: '1', name: 'Avatar 1', type: 'user' },
|
||||||
|
{ id: '2', name: 'Avatar 2', type: 'user' },
|
||||||
|
],
|
||||||
|
acceptRejectSuggestion: jest.fn(),
|
||||||
|
selectedUserSuggestions: [],
|
||||||
|
onUpdateActiveUser: jest.fn(),
|
||||||
|
fetchSuggestionsByUserId: mockFetchSuggestionsByUserId,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const { getByTestId } = render(
|
||||||
|
<AvatarCarouselItem
|
||||||
|
avatar={avatar}
|
||||||
|
avatarBtnRefs={avatarBtnRefs}
|
||||||
|
index={index}
|
||||||
|
isActive={isActive}
|
||||||
|
onAvatarClick={onAvatarClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const button = getByTestId(`avatar-carousel-item-${avatar.id}`);
|
||||||
|
button.click();
|
||||||
|
|
||||||
|
expect(mockFetchSuggestionsByUserId).toHaveBeenCalledWith(avatar.id);
|
||||||
|
});
|
||||||
|
|
||||||
it('sets isActive class when isActive is true', () => {
|
it('sets isActive class when isActive is true', () => {
|
||||||
const { getByTestId } = render(
|
const { getByTestId } = render(
|
||||||
<AvatarCarouselItem
|
<AvatarCarouselItem
|
||||||
|
@ -33,7 +33,8 @@ const AvatarCarouselItem = ({
|
|||||||
onAvatarClick,
|
onAvatarClick,
|
||||||
isActive,
|
isActive,
|
||||||
}: AvatarCarouselItemProps) => {
|
}: AvatarCarouselItemProps) => {
|
||||||
const { suggestionsByUser } = useSuggestionsContext();
|
const { suggestionsByUser, fetchSuggestionsByUserId } =
|
||||||
|
useSuggestionsContext();
|
||||||
const buttonRef = useRef(null);
|
const buttonRef = useRef(null);
|
||||||
avatarBtnRefs.current[index] = buttonRef;
|
avatarBtnRefs.current[index] = buttonRef;
|
||||||
const getUserSuggestionsCount = useCallback(
|
const getUserSuggestionsCount = useCallback(
|
||||||
@ -42,6 +43,16 @@ const AvatarCarouselItem = ({
|
|||||||
[suggestionsByUser]
|
[suggestionsByUser]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleAvatarClick = useCallback(() => {
|
||||||
|
// Call the original onAvatarClick function
|
||||||
|
onAvatarClick(index);
|
||||||
|
|
||||||
|
// Fetch suggestions for this specific user
|
||||||
|
if (avatar.id) {
|
||||||
|
fetchSuggestionsByUserId(avatar.id);
|
||||||
|
}
|
||||||
|
}, [onAvatarClick, index, avatar.id, fetchSuggestionsByUserId]);
|
||||||
|
|
||||||
const button = (
|
const button = (
|
||||||
<Button
|
<Button
|
||||||
className={classNames('p-0 m-r-xss avatar-item', {
|
className={classNames('p-0 m-r-xss avatar-item', {
|
||||||
@ -50,7 +61,7 @@ const AvatarCarouselItem = ({
|
|||||||
data-testid={`avatar-carousel-item-${avatar.id}`}
|
data-testid={`avatar-carousel-item-${avatar.id}`}
|
||||||
ref={buttonRef}
|
ref={buttonRef}
|
||||||
shape="circle"
|
shape="circle"
|
||||||
onClick={() => onAvatarClick(index)}>
|
onClick={handleAvatarClick}>
|
||||||
<ProfilePicture name={avatar.name ?? ''} width="28" />
|
<ProfilePicture name={avatar.name ?? ''} width="28" />
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
@ -25,6 +25,7 @@ const BASE_URL = '/suggestions';
|
|||||||
export type ListSuggestionsParams = ListParams & {
|
export type ListSuggestionsParams = ListParams & {
|
||||||
entityFQN?: string;
|
entityFQN?: string;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
|
userId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getSuggestionsList = async (params?: ListSuggestionsParams) => {
|
export const getSuggestionsList = async (params?: ListSuggestionsParams) => {
|
||||||
@ -35,6 +36,20 @@ export const getSuggestionsList = async (params?: ListSuggestionsParams) => {
|
|||||||
return response.data;
|
return response.data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getSuggestionsByUserId = async (
|
||||||
|
userId: string,
|
||||||
|
params?: Omit<ListSuggestionsParams, 'userId'>
|
||||||
|
) => {
|
||||||
|
const response = await APIClient.get<PagingResponse<Suggestion[]>>(BASE_URL, {
|
||||||
|
params: {
|
||||||
|
...params,
|
||||||
|
userId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
export const updateSuggestionStatus = (
|
export const updateSuggestionStatus = (
|
||||||
data: Suggestion,
|
data: Suggestion,
|
||||||
action: SuggestionAction
|
action: SuggestionAction
|
||||||
|
Loading…
x
Reference in New Issue
Block a user