Skip to content

Commit 2de0800

Browse files
authored
feat(ui): Announcements in domains and data products (open-metadata#24089)
* commit progress * commit progress * add playwright * minor styles adjustments
1 parent 3bdf994 commit 2de0800

File tree

9 files changed

+283
-17
lines changed

9 files changed

+283
-17
lines changed

openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Domains.spec.ts

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,14 @@ import {
6464
verifyDataProductAssetsAfterDelete,
6565
verifyDomain,
6666
} from '../../utils/domain';
67-
import { followEntity, unFollowEntity } from '../../utils/entity';
67+
import {
68+
createAnnouncement,
69+
deleteAnnouncement,
70+
editAnnouncement,
71+
followEntity,
72+
replyAnnouncement,
73+
unFollowEntity,
74+
} from '../../utils/entity';
6875
import {
6976
settingClick,
7077
SettingOptionsType,
@@ -930,6 +937,80 @@ test.describe('Domains', () => {
930937
await afterAction();
931938
}
932939
});
940+
941+
test('Domain announcement create, edit & delete', async ({ page }) => {
942+
test.slow(true);
943+
944+
const { afterAction, apiContext } = await getApiContext(page);
945+
const domain = new Domain();
946+
947+
try {
948+
await domain.create(apiContext);
949+
await page.reload();
950+
await sidebarClick(page, SidebarItem.DOMAIN);
951+
await selectDomain(page, domain.data);
952+
953+
await createAnnouncement(
954+
page,
955+
{
956+
title: 'Domain Announcement Test',
957+
description: 'Domain Announcement Description',
958+
},
959+
false
960+
);
961+
962+
await editAnnouncement(page, {
963+
title: 'Edited Domain Announcement',
964+
description: 'Updated Domain Announcement Description',
965+
});
966+
967+
await replyAnnouncement(page);
968+
await deleteAnnouncement(page);
969+
} finally {
970+
await domain.delete(apiContext);
971+
await afterAction();
972+
}
973+
});
974+
975+
test('Data Product announcement create, edit & delete', async ({ page }) => {
976+
test.slow(true);
977+
978+
const { afterAction, apiContext } = await getApiContext(page);
979+
const domain = new Domain();
980+
const dataProduct = new DataProduct([domain]);
981+
982+
try {
983+
await domain.create(apiContext);
984+
await page.reload();
985+
await sidebarClick(page, SidebarItem.DOMAIN);
986+
await selectDomain(page, domain.data);
987+
await createDataProduct(page, dataProduct.data);
988+
989+
await sidebarClick(page, SidebarItem.DATA_PRODUCT);
990+
await selectDataProduct(page, dataProduct.data);
991+
992+
await createAnnouncement(
993+
page,
994+
{
995+
title: 'Data Product Announcement Test',
996+
description: 'Data Product Announcement Description',
997+
},
998+
false
999+
);
1000+
1001+
await editAnnouncement(page, {
1002+
title: 'Edited Data Product Announcement',
1003+
description: 'Updated Data Product Announcement Description',
1004+
});
1005+
1006+
await replyAnnouncement(page);
1007+
await deleteAnnouncement(page);
1008+
} finally {
1009+
await dataProduct.delete(apiContext);
1010+
await domain.delete(apiContext);
1011+
await afterAction();
1012+
}
1013+
});
9331014
});
9341015

9351016
test.describe('Domains Rbac', () => {

openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,7 +1096,8 @@ const announcementForm = async (
10961096
startDate: string;
10971097
endDate: string;
10981098
description: string;
1099-
}
1099+
},
1100+
hideAlert = true
11001101
) => {
11011102
await page.fill('#title', data.title);
11021103

@@ -1117,12 +1118,15 @@ const announcementForm = async (
11171118
await page.click('#announcement-submit');
11181119
await announcementSubmit;
11191120
await page.click('[data-testid="announcement-close"]');
1120-
await page.click('[data-testid="alert-icon-close"]');
1121+
if (hideAlert) {
1122+
await page.click('[data-testid="alert-icon-close"]');
1123+
}
11211124
};
11221125

11231126
export const createAnnouncement = async (
11241127
page: Page,
1125-
data: { title: string; description: string }
1128+
data: { title: string; description: string },
1129+
hideAlert?: boolean
11261130
) => {
11271131
await page.getByTestId('manage-button').click();
11281132
await page.getByTestId('announcement-button').click();
@@ -1142,7 +1146,7 @@ export const createAnnouncement = async (
11421146
'Make an announcement'
11431147
);
11441148

1145-
await announcementForm(page, { ...data, startDate, endDate });
1149+
await announcementForm(page, { ...data, startDate, endDate }, hideAlert);
11461150
await page.reload();
11471151
await page.waitForLoadState('networkidle');
11481152
await page.waitForSelector('[data-testid="loader"]', {
@@ -1315,7 +1319,8 @@ export const editAnnouncement = async (
13151319

13161320
export const createInactiveAnnouncement = async (
13171321
page: Page,
1318-
data: { title: string; description: string }
1322+
data: { title: string; description: string },
1323+
hideAlert?: boolean
13191324
) => {
13201325
await page.getByTestId('manage-button').click();
13211326
await page.getByTestId('announcement-button').click();
@@ -1334,7 +1339,7 @@ export const createInactiveAnnouncement = async (
13341339
'Make an announcement'
13351340
);
13361341

1337-
await announcementForm(page, { ...data, startDate, endDate });
1342+
await announcementForm(page, { ...data, startDate, endDate }, hideAlert);
13381343
await page.getByTestId('inActive-announcements').isVisible();
13391344
await page.reload();
13401345
};

openmetadata-ui/src/main/resources/ui/src/components/DataProducts/DataProductsDetailsPage/DataProductsDetailsPage.component.tsx

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ import ButtonGroup from 'antd/lib/button/button-group';
1717
import { ItemType } from 'antd/lib/menu/hooks/useItems';
1818
import { AxiosError } from 'axios';
1919
import classNames from 'classnames';
20-
import { cloneDeep, toString } from 'lodash';
20+
import { cloneDeep, isEmpty, toString } from 'lodash';
2121
import { useSnackbar } from 'notistack';
2222
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2323
import { useTranslation } from 'react-i18next';
2424
import { useNavigate } from 'react-router-dom';
25+
import { ReactComponent as IconAnnouncementsBlack } from '../../../assets/svg/announcements-black.svg';
2526
import { ReactComponent as EditIcon } from '../../../assets/svg/edit-new.svg';
2627
import { ReactComponent as DeleteIcon } from '../../../assets/svg/ic-delete.svg';
2728
import { ReactComponent as VersionIcon } from '../../../assets/svg/ic-version.svg';
@@ -42,13 +43,15 @@ import {
4243
ChangeDescription,
4344
DataProduct,
4445
} from '../../../generated/entity/domains/dataProduct';
46+
import { Thread } from '../../../generated/entity/feed/thread';
4547
import { Operation } from '../../../generated/entity/policies/policy';
4648
import { PageType } from '../../../generated/system/ui/page';
4749
import { Style } from '../../../generated/type/tagLabel';
4850
import { useCustomPages } from '../../../hooks/useCustomPages';
4951
import { useFqn } from '../../../hooks/useFqn';
5052
import { FeedCounts } from '../../../interface/feed.interface';
5153
import { QueryFilterInterface } from '../../../pages/ExplorePage/ExplorePage.interface';
54+
import { getActiveAnnouncement } from '../../../rest/feedsAPI';
5255
import { searchQuery } from '../../../rest/searchAPI';
5356
import {
5457
getEntityDeleteMessage,
@@ -63,7 +66,7 @@ import dataProductClassBase from '../../../utils/DataProduct/DataProductClassBas
6366
import { getDomainContainerStyles } from '../../../utils/DomainPageStyles';
6467
import { getQueryFilterToIncludeDomain } from '../../../utils/DomainUtils';
6568
import entityUtilClassBase from '../../../utils/EntityUtilClassBase';
66-
import { getEntityName } from '../../../utils/EntityUtils';
69+
import { getEntityFeedLink, getEntityName } from '../../../utils/EntityUtils';
6770
import { getEntityVersionByField } from '../../../utils/EntityVersionUtils';
6871
import { showNotistackError } from '../../../utils/NotistackUtils';
6972
import {
@@ -81,6 +84,8 @@ import type { BreadcrumbItem } from '../../common/atoms/navigation/useBreadcrumb
8184
import { useBreadcrumbs } from '../../common/atoms/navigation/useBreadcrumbs';
8285
import { CoverImage } from '../../common/CoverImage/CoverImage.component';
8386
import { EntityAvatar } from '../../common/EntityAvatar/EntityAvatar';
87+
import AnnouncementCard from '../../common/EntityPageInfos/AnnouncementCard/AnnouncementCard';
88+
import AnnouncementDrawer from '../../common/EntityPageInfos/AnnouncementDrawer/AnnouncementDrawer';
8489
import { AlignRightIconButton } from '../../common/IconButtons/EditIconButton';
8590
import Loader from '../../common/Loader/Loader';
8691
import { ManageButtonItemLabel } from '../../common/ManageButtonContentItem/ManageButtonContentItem.component';
@@ -136,6 +141,9 @@ const DataProductsDetailsPage = ({
136141
const [feedCount, setFeedCount] = useState<FeedCounts>(
137142
FEED_COUNT_INITIAL_DATA
138143
);
144+
const [isAnnouncementDrawerOpen, setIsAnnouncementDrawerOpen] =
145+
useState<boolean>(false);
146+
const [activeAnnouncement, setActiveAnnouncement] = useState<Thread>();
139147

140148
const handleFeedCount = useCallback((data: FeedCounts) => {
141149
setFeedCount(data);
@@ -157,6 +165,36 @@ const DataProductsDetailsPage = ({
157165
setIsAssetDrawerOpen(false);
158166
}, []);
159167

168+
const fetchActiveAnnouncement = async () => {
169+
try {
170+
const announcements = await getActiveAnnouncement(
171+
getEntityFeedLink(
172+
EntityType.DATA_PRODUCT,
173+
dataProduct.fullyQualifiedName ?? ''
174+
)
175+
);
176+
if (!isEmpty(announcements.data)) {
177+
setActiveAnnouncement(announcements.data[0]);
178+
} else {
179+
setActiveAnnouncement(undefined);
180+
}
181+
} catch (error) {
182+
showNotistackError(enqueueSnackbar, error as AxiosError, undefined, {
183+
vertical: 'top',
184+
horizontal: 'center',
185+
});
186+
}
187+
};
188+
189+
const handleOpenAnnouncementDrawer = () => {
190+
setIsAnnouncementDrawerOpen(true);
191+
};
192+
193+
const handleCloseAnnouncementDrawer = () => {
194+
setIsAnnouncementDrawerOpen(false);
195+
fetchActiveAnnouncement();
196+
};
197+
160198
const breadcrumbItems = useMemo<BreadcrumbItem[]>(() => {
161199
const items: BreadcrumbItem[] = [];
162200

@@ -278,6 +316,26 @@ const DataProductsDetailsPage = ({
278316
}, [dataProduct, enqueueSnackbar]);
279317

280318
const manageButtonContent: ItemType[] = [
319+
...(editAllPermission
320+
? ([
321+
{
322+
label: (
323+
<ManageButtonItemLabel
324+
description={t('message.announcement-action-description')}
325+
icon={IconAnnouncementsBlack}
326+
id="announcement-button"
327+
name={t('label.announcement-plural')}
328+
/>
329+
),
330+
key: 'announcement-button',
331+
onClick: (e) => {
332+
e.domEvent.stopPropagation();
333+
handleOpenAnnouncementDrawer();
334+
setShowActions(false);
335+
},
336+
},
337+
] as ItemType[])
338+
: []),
281339
...(editDisplayNamePermission
282340
? ([
283341
{
@@ -488,6 +546,7 @@ const DataProductsDetailsPage = ({
488546
fetchDataProductPermission();
489547
fetchDataProductAssets();
490548
getEntityFeedCount();
549+
fetchActiveAnnouncement();
491550
}, [dataProductFqn]);
492551

493552
const toggleTabExpanded = () => {
@@ -569,12 +628,13 @@ const DataProductsDetailsPage = ({
569628
titleColor={dataProduct.style?.color}
570629
/>
571630
</Box>
572-
<Box sx={{ width: '320px' }}>
631+
<Box>
573632
<Box
574633
sx={{
575634
display: 'flex',
576635
gap: 3,
577636
justifyContent: 'flex-end',
637+
alignItems: 'center',
578638
pb: '4px',
579639
}}>
580640
{!isVersionsView && dataProductPermission.Create && (
@@ -646,6 +706,13 @@ const DataProductsDetailsPage = ({
646706
</Dropdown>
647707
)}
648708
</ButtonGroup>
709+
710+
{activeAnnouncement && (
711+
<AnnouncementCard
712+
announcement={activeAnnouncement}
713+
onClick={handleOpenAnnouncementDrawer}
714+
/>
715+
)}
649716
</Box>
650717
</Box>
651718
</Box>
@@ -737,6 +804,15 @@ const DataProductsDetailsPage = ({
737804
onCancel={() => setIsStyleEditing(false)}
738805
onSubmit={onStyleSave}
739806
/>
807+
808+
<AnnouncementDrawer
809+
showToastInSnackbar
810+
createPermission={editAllPermission}
811+
entityFQN={dataProduct.fullyQualifiedName ?? ''}
812+
entityType={EntityType.DATA_PRODUCT}
813+
open={isAnnouncementDrawerOpen}
814+
onClose={handleCloseAnnouncementDrawer}
815+
/>
740816
</>
741817
);
742818

openmetadata-ui/src/main/resources/ui/src/components/DataProducts/DataProductsDetailsPage/data-products-details-page.less

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,8 @@
1616
.ant-tabs-tabpane {
1717
min-height: 70vh;
1818
}
19+
20+
.announcement-card {
21+
margin-top: 4px;
22+
}
1923
}

0 commit comments

Comments
 (0)