mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-13 17:58:36 +00:00
* supported the task filter on landing page widget * added playwright for the test
This commit is contained in:
parent
3d9e9dd9ab
commit
57ed033703
@ -590,6 +590,100 @@ test.describe('Activity feed', () => {
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test('Check Task Filter in Landing Page Widget', async ({ browser }) => {
|
||||
const { page: page1, afterAction: afterActionUser1 } =
|
||||
await performUserLogin(browser, user1);
|
||||
const { page: page2, afterAction: afterActionUser2 } =
|
||||
await performUserLogin(browser, user2);
|
||||
|
||||
await base.step('Create and Assign Task to User 2', async () => {
|
||||
await redirectToHomePage(page1);
|
||||
await entity.visitEntityPage(page1);
|
||||
|
||||
// Create task for the user 2
|
||||
await page1.getByTestId('request-description').click();
|
||||
await createDescriptionTask(page1, {
|
||||
term: entity.entity.displayName,
|
||||
assignee: user2.responseData.name,
|
||||
});
|
||||
|
||||
await afterActionUser1();
|
||||
});
|
||||
|
||||
await base.step('Create and Validate Task as per Filters', async () => {
|
||||
await redirectToHomePage(page2);
|
||||
await entity.visitEntityPage(page2);
|
||||
|
||||
// Create task for the user 1
|
||||
await page2.getByTestId('request-entity-tags').click();
|
||||
await createTagTask(page2, {
|
||||
term: entity.entity.displayName,
|
||||
tag: 'PII.None',
|
||||
assignee: user1.responseData.name,
|
||||
});
|
||||
|
||||
await redirectToHomePage(page2);
|
||||
const taskResponse = page2.waitForResponse(
|
||||
'/api/v1/feed?type=Task&filterType=OWNER&taskStatus=Open&userId=*'
|
||||
);
|
||||
|
||||
await page2
|
||||
.getByTestId('activity-feed-widget')
|
||||
.getByText('Tasks')
|
||||
.click();
|
||||
|
||||
await taskResponse;
|
||||
|
||||
await expect(
|
||||
page2.locator(
|
||||
'[data-testid="activity-feed-widget"] [data-testid="no-data-placeholder"]'
|
||||
)
|
||||
).not.toBeVisible();
|
||||
|
||||
// Check the Task based on ALL task filter
|
||||
await expect(page2.getByTestId('message-container')).toHaveCount(2);
|
||||
|
||||
// Check the Task based on Assigned task filter
|
||||
await page2.getByTestId('filter-button').click();
|
||||
await page2.waitForSelector('.ant-popover ', { state: 'visible' });
|
||||
|
||||
const taskAssignedResponse = page2.waitForResponse(
|
||||
'/api/v1/feed?type=Task&filterType=ASSIGNED_TO&taskStatus=Open&userId=*'
|
||||
);
|
||||
await page2.getByText('Assigned').click();
|
||||
await page2.getByTestId('selectable-list-update-btn').click();
|
||||
|
||||
await taskAssignedResponse;
|
||||
|
||||
await expect(page2.getByTestId('message-container')).toHaveCount(1);
|
||||
|
||||
await expect(page2.getByTestId('owner-link')).toContainText(
|
||||
user2.responseData.displayName
|
||||
);
|
||||
|
||||
// Check the Task based on Created by me task filter
|
||||
|
||||
await page2.getByTestId('filter-button').click();
|
||||
await page2.waitForSelector('.ant-popover ', { state: 'visible' });
|
||||
|
||||
const taskCreatedByResponse = page2.waitForResponse(
|
||||
'/api/v1/feed?type=Task&filterType=ASSIGNED_BY&taskStatus=Open&userId=*'
|
||||
);
|
||||
await page2.getByText('Created By').click();
|
||||
await page2.getByTestId('selectable-list-update-btn').click();
|
||||
|
||||
await taskCreatedByResponse;
|
||||
|
||||
await expect(page2.getByTestId('message-container')).toHaveCount(1);
|
||||
|
||||
await expect(page2.getByTestId('owner-link')).toContainText(
|
||||
user1.responseData.displayName
|
||||
);
|
||||
|
||||
await afterActionUser2();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
base.describe('Activity feed with Data Consumer User', () => {
|
||||
|
@ -20,6 +20,7 @@ import { Link, useHistory } from 'react-router-dom';
|
||||
import { PAGE_SIZE_MEDIUM, ROUTES } from '../../../../constants/constants';
|
||||
import { FEED_COUNT_INITIAL_DATA } from '../../../../constants/entity.constants';
|
||||
import { mockFeedData } from '../../../../constants/mockTourData.constants';
|
||||
import { TAB_SUPPORTED_FILTER } from '../../../../constants/Widgets.constant';
|
||||
import { useTourProvider } from '../../../../context/TourProvider/TourProvider';
|
||||
import { EntityTabs, EntityType } from '../../../../enums/entity.enum';
|
||||
import { FeedFilter } from '../../../../enums/mydata.enum';
|
||||
@ -76,7 +77,7 @@ const FeedsWidget = ({
|
||||
getFeedData(FeedFilter.MENTIONS);
|
||||
} else if (activeTab === ActivityFeedTabs.TASKS) {
|
||||
getFeedData(
|
||||
FeedFilter.OWNER,
|
||||
defaultFilter,
|
||||
undefined,
|
||||
ThreadType.Task,
|
||||
undefined,
|
||||
@ -106,7 +107,12 @@ const FeedsWidget = ({
|
||||
[count.openTaskCount, activeTab]
|
||||
);
|
||||
|
||||
const onTabChange = (key: string) => setActiveTab(key as ActivityFeedTabs);
|
||||
const onTabChange = (key: string) => {
|
||||
if (key === ActivityFeedTabs.TASKS) {
|
||||
setDefaultFilter(FeedFilter.OWNER);
|
||||
}
|
||||
setActiveTab(key as ActivityFeedTabs);
|
||||
};
|
||||
|
||||
const redirectToUserPage = useCallback(() => {
|
||||
history.push(
|
||||
@ -259,13 +265,10 @@ const FeedsWidget = ({
|
||||
]}
|
||||
tabBarExtraContent={
|
||||
<Space>
|
||||
{activeTab === ActivityFeedTabs.ALL && (
|
||||
{TAB_SUPPORTED_FILTER.includes(activeTab) && (
|
||||
<FeedsFilterPopover
|
||||
defaultFilter={
|
||||
currentUser?.isAdmin
|
||||
? FeedFilter.ALL
|
||||
: FeedFilter.OWNER_OR_FOLLOWS
|
||||
}
|
||||
defaultFilter={defaultFilter}
|
||||
feedTab={activeTab}
|
||||
onUpdate={onFilterUpdate}
|
||||
/>
|
||||
)}
|
||||
|
@ -82,7 +82,16 @@ jest.mock(
|
||||
|
||||
jest.mock(
|
||||
'../../../common/FeedsFilterPopover/FeedsFilterPopover.component',
|
||||
() => jest.fn().mockImplementation(({ children }) => <p>{children}</p>)
|
||||
() =>
|
||||
jest.fn().mockImplementation(({ onUpdate }) => (
|
||||
<div>
|
||||
<button onClick={() => onUpdate('ALL')}>all_button</button>
|
||||
<button onClick={() => onUpdate('ASSIGNED_TO')}>assigned_button</button>
|
||||
<button onClick={() => onUpdate('ASSIGNED_BY')}>
|
||||
created_by_button
|
||||
</button>
|
||||
</div>
|
||||
))
|
||||
);
|
||||
|
||||
jest.mock('../../../../rest/feedsAPI', () => ({
|
||||
@ -193,4 +202,56 @@ describe('FeedsWidget', () => {
|
||||
|
||||
expect(mockHandleRemoveWidget).toHaveBeenCalledWith(widgetProps.widgetKey);
|
||||
});
|
||||
|
||||
it('should call api with correct parameters based on the tab selected', () => {
|
||||
render(<FeedsWidget {...widgetProps} />);
|
||||
const tabs = screen.getAllByRole('tab');
|
||||
const conversationTab = tabs[0];
|
||||
fireEvent.click(conversationTab);
|
||||
|
||||
// initial API call for the Feed
|
||||
expect(conversationTab.getAttribute('aria-selected')).toBe('true');
|
||||
expect(mockUseActivityFeedProviderValue.getFeedData).toHaveBeenCalledWith(
|
||||
'OWNER_OR_FOLLOWS',
|
||||
undefined,
|
||||
'Conversation',
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
25
|
||||
);
|
||||
|
||||
// Reset mock between checks
|
||||
mockUseActivityFeedProviderValue.getFeedData.mockReset();
|
||||
|
||||
// Testing for "Task Tab", to call API with OWNER filter parameters
|
||||
const taskTab = tabs[2];
|
||||
fireEvent.click(taskTab);
|
||||
|
||||
expect(taskTab.getAttribute('aria-selected')).toBe('true');
|
||||
expect(mockUseActivityFeedProviderValue.getFeedData).toHaveBeenCalledWith(
|
||||
'OWNER',
|
||||
undefined,
|
||||
'Task',
|
||||
undefined,
|
||||
undefined,
|
||||
'Open'
|
||||
);
|
||||
|
||||
// Reset mock for the next check
|
||||
mockUseActivityFeedProviderValue.getFeedData.mockReset();
|
||||
|
||||
// Applying the filter for the assigned button
|
||||
const assignedFilterButton = screen.getByText('assigned_button');
|
||||
fireEvent.click(assignedFilterButton);
|
||||
|
||||
expect(mockUseActivityFeedProviderValue.getFeedData).toHaveBeenCalledWith(
|
||||
'ASSIGNED_TO',
|
||||
undefined,
|
||||
'Task',
|
||||
undefined,
|
||||
undefined,
|
||||
'Open'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -25,10 +25,12 @@ import { ReactComponent as FilterIcon } from '../../../assets/svg/ic-feeds-filte
|
||||
import { FeedFilter } from '../../../enums/mydata.enum';
|
||||
|
||||
import { useApplicationStore } from '../../../hooks/useApplicationStore';
|
||||
import { getFeedFilterWidgets } from '../../../utils/LandingPageWidget/WidgetsUtils';
|
||||
import './feeds-filter-popover.less';
|
||||
import { FeedsFilterPopoverProps } from './FeedsFilterPopover.interface';
|
||||
|
||||
const FeedsFilterPopover = ({
|
||||
feedTab,
|
||||
defaultFilter,
|
||||
onUpdate,
|
||||
}: FeedsFilterPopoverProps) => {
|
||||
@ -39,26 +41,8 @@ const FeedsFilterPopover = ({
|
||||
useState<FeedFilter>(defaultFilter);
|
||||
|
||||
const items = useMemo(
|
||||
() => [
|
||||
{
|
||||
title: t('label.all'),
|
||||
key: currentUser?.isAdmin
|
||||
? FeedFilter.ALL
|
||||
: FeedFilter.OWNER_OR_FOLLOWS,
|
||||
description: t('message.feed-filter-all'),
|
||||
},
|
||||
{
|
||||
title: t('label.my-data'),
|
||||
key: FeedFilter.OWNER,
|
||||
description: t('message.feed-filter-owner'),
|
||||
},
|
||||
{
|
||||
title: t('label.following'),
|
||||
key: FeedFilter.FOLLOWS,
|
||||
description: t('message.feed-filter-following'),
|
||||
},
|
||||
],
|
||||
[currentUser]
|
||||
() => getFeedFilterWidgets(feedTab, currentUser?.isAdmin),
|
||||
[currentUser?.isAdmin, feedTab]
|
||||
);
|
||||
|
||||
const onFilterUpdate = useCallback(() => {
|
||||
|
@ -11,8 +11,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { FeedFilter } from '../../../enums/mydata.enum';
|
||||
import { ActivityFeedTabs } from '../../ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface';
|
||||
|
||||
export interface FeedsFilterPopoverProps {
|
||||
feedTab: ActivityFeedTabs;
|
||||
defaultFilter: FeedFilter;
|
||||
onUpdate: (value: FeedFilter) => void;
|
||||
}
|
||||
|
@ -13,10 +13,12 @@
|
||||
import { act, fireEvent, render, screen } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { FeedFilter } from '../../../enums/mydata.enum';
|
||||
import { ActivityFeedTabs } from '../../ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface';
|
||||
import FeedsFilterPopover from './FeedsFilterPopover.component';
|
||||
|
||||
const onUpdateMock = jest.fn();
|
||||
const mockProps = {
|
||||
feedTab: ActivityFeedTabs.ALL,
|
||||
defaultFilter: FeedFilter.ALL,
|
||||
onUpdate: onUpdateMock,
|
||||
};
|
||||
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2025 Collate.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ActivityFeedTabs } from '../components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface';
|
||||
import { FeedFilter } from '../enums/mydata.enum';
|
||||
import i18n from '../utils/i18next/LocalUtil';
|
||||
|
||||
export const TAB_SUPPORTED_FILTER = [
|
||||
ActivityFeedTabs.ALL,
|
||||
ActivityFeedTabs.TASKS,
|
||||
];
|
||||
|
||||
export const TASK_FEED_FILTER_LIST = [
|
||||
{
|
||||
title: i18n.t('label.all'),
|
||||
key: FeedFilter.OWNER,
|
||||
description: i18n.t('message.feed-filter-all'),
|
||||
},
|
||||
{
|
||||
title: i18n.t('label.assigned'),
|
||||
key: FeedFilter.ASSIGNED_TO,
|
||||
description: i18n.t('message.feed-filter-owner'),
|
||||
},
|
||||
{
|
||||
title: i18n.t('label.created-by'),
|
||||
key: FeedFilter.ASSIGNED_BY,
|
||||
description: i18n.t('message.feed-filter-following'),
|
||||
},
|
||||
];
|
||||
|
||||
export const ACTIVITY_FEED_FILTER_LIST = [
|
||||
{
|
||||
title: i18n.t('label.my-data'),
|
||||
key: FeedFilter.OWNER,
|
||||
description: i18n.t('message.feed-filter-owner'),
|
||||
},
|
||||
{
|
||||
title: i18n.t('label.following'),
|
||||
key: FeedFilter.FOLLOWS,
|
||||
description: i18n.t('message.feed-filter-following'),
|
||||
},
|
||||
];
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2025 Collate.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ActivityFeedTabs } from '../../components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface';
|
||||
import {
|
||||
ACTIVITY_FEED_FILTER_LIST,
|
||||
TASK_FEED_FILTER_LIST,
|
||||
} from '../../constants/Widgets.constant';
|
||||
import { FeedFilter } from '../../enums/mydata.enum';
|
||||
import i18n from '../i18next/LocalUtil';
|
||||
import { getFeedFilterWidgets } from './WidgetsUtils';
|
||||
|
||||
describe('Widgets Utils', () => {
|
||||
describe('getFeedFilterWidgets', () => {
|
||||
it('should return list for Feed Filters', () => {
|
||||
const response = getFeedFilterWidgets(ActivityFeedTabs.ALL);
|
||||
|
||||
expect(response).toEqual([
|
||||
{
|
||||
title: i18n.t('label.all'),
|
||||
key: FeedFilter.OWNER_OR_FOLLOWS,
|
||||
description: i18n.t('message.feed-filter-all'),
|
||||
},
|
||||
...ACTIVITY_FEED_FILTER_LIST,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return list for Feed Filters for Admin', () => {
|
||||
const response = getFeedFilterWidgets(ActivityFeedTabs.ALL, true);
|
||||
|
||||
expect(response).toEqual([
|
||||
{
|
||||
title: i18n.t('label.all'),
|
||||
key: FeedFilter.ALL,
|
||||
description: i18n.t('message.feed-filter-all'),
|
||||
},
|
||||
...ACTIVITY_FEED_FILTER_LIST,
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return list for Task Filters', () => {
|
||||
const response = getFeedFilterWidgets(ActivityFeedTabs.TASKS);
|
||||
|
||||
expect(response).toEqual(TASK_FEED_FILTER_LIST);
|
||||
});
|
||||
});
|
||||
});
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2025 Collate.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ActivityFeedTabs } from '../../components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.interface';
|
||||
import {
|
||||
ACTIVITY_FEED_FILTER_LIST,
|
||||
TASK_FEED_FILTER_LIST,
|
||||
} from '../../constants/Widgets.constant';
|
||||
import { FeedFilter } from '../../enums/mydata.enum';
|
||||
import i18n from '../i18next/LocalUtil';
|
||||
|
||||
export const getFeedFilterWidgets = (
|
||||
tab: ActivityFeedTabs,
|
||||
isAdmin?: boolean
|
||||
) => {
|
||||
return tab === ActivityFeedTabs.TASKS
|
||||
? TASK_FEED_FILTER_LIST
|
||||
: [
|
||||
{
|
||||
title: i18n.t('label.all'),
|
||||
key: isAdmin ? FeedFilter.ALL : FeedFilter.OWNER_OR_FOLLOWS,
|
||||
description: i18n.t('message.feed-filter-all'),
|
||||
},
|
||||
...ACTIVITY_FEED_FILTER_LIST,
|
||||
];
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user