From ace12501b45bf7a611dcc9f0ebb4fe9be53d9497 Mon Sep 17 00:00:00 2001 From: Chirag Madlani Date: Fri, 24 Jun 2022 22:09:59 +0530 Subject: [PATCH] feat(ui): support web socket based feeds page (#5612) * feat(ui): support web socket based feeds page * update placement for refresh activity * styles update * textual updates --- .../src/main/resources/ui/package.json | 1 + .../ActivityFeedList/FeedListSeparator.tsx | 1 + .../components/MyData/MyData.component.tsx | 16 ++++++ .../src/components/MyData/MyData.interface.ts | 2 + .../resources/ui/src/constants/constants.ts | 5 ++ .../pages/MyDataPage/MyDataPage.component.tsx | 35 +++++++++++- .../main/resources/ui/src/styles/tailwind.css | 7 +++ .../src/main/resources/ui/tailwind.config.js | 4 ++ .../src/main/resources/ui/yarn.lock | 56 +++++++++++++++++++ 9 files changed, 126 insertions(+), 1 deletion(-) diff --git a/openmetadata-ui/src/main/resources/ui/package.json b/openmetadata-ui/src/main/resources/ui/package.json index f6750132dfc..2b78e767e41 100644 --- a/openmetadata-ui/src/main/resources/ui/package.json +++ b/openmetadata-ui/src/main/resources/ui/package.json @@ -90,6 +90,7 @@ "resolve": "1.15.0", "resolve-url-loader": "3.1.1", "slick-carousel": "^1.8.1", + "socket.io-client": "^4.5.1", "stream-http": "^3.2.0", "styled-components": "^5.2.3", "tailwindcss": "^2.1.4", diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/FeedListSeparator.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/FeedListSeparator.tsx index 5b6f1118e71..ea789737ad5 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/FeedListSeparator.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/ActivityFeedList/FeedListSeparator.tsx @@ -26,6 +26,7 @@ const FeedListSeparator: FC = ({ data-testid="separator" style={{ borderBottomWidth: '0.5px' }} /> + {relativeDay ? ( = ({ + activityFeeds, + onRefreshFeeds, error, countDashboards, countPipelines, @@ -214,6 +216,8 @@ const MyData: React.FC = ({ isMounted.current = true; }, []); + const newFeedsLength = activityFeeds && activityFeeds.length; + return ( {error ? ( @@ -223,6 +227,18 @@ const MyData: React.FC = ({ {feedData?.length > 0 || feedFilter !== FeedFilter.ALL ? ( {getFilterDropDown()} + + {newFeedsLength ? ( +
+ +
+ ) : null} + void; error: string; countServices: number; countTables: number; diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts index 1a22f08d238..b0ccc03dc1a 100644 --- a/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts +++ b/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts @@ -226,6 +226,11 @@ export const ROUTES = { CUSTOM_PROPERTIES: `/custom-properties`, CUSTOM_ENTITY_DETAIL: `/custom-properties/${PLACEHOLDER_ENTITY_TYPE_FQN}`, ADD_CUSTOM_PROPERTY: `/custom-properties/${PLACEHOLDER_ENTITY_TYPE_FQN}/add-field`, + ACTIVITY_PUSH_FEED: '/api/v1/push/feed', +}; + +export const SOCKET_EVENTS = { + ACTIVITY_FEED: 'activityFeed', }; export const IN_PAGE_SEARCH_ROUTES: Record> = { diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/MyDataPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/MyDataPage.component.tsx index c193c8a3cb0..298d5b4c3ce 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/MyDataPage.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/MyDataPage.component.tsx @@ -18,6 +18,7 @@ import { observer } from 'mobx-react'; import { FormatedTableData } from 'Models'; import React, { Fragment, useEffect, useMemo, useState } from 'react'; import { useLocation } from 'react-router-dom'; +import io from 'socket.io-client'; import AppState from '../../AppState'; import { getAllDashboards } from '../../axiosAPIs/dashboardAPI'; import { getFeedsWithFilter, postFeedById } from '../../axiosAPIs/feedsAPI'; @@ -32,6 +33,7 @@ import PageContainerV1 from '../../components/containers/PageContainerV1'; import GithubStarButton from '../../components/GithubStarButton/GithubStarButton'; import Loader from '../../components/Loader/Loader'; import MyData from '../../components/MyData/MyData.component'; +import { ROUTES, SOCKET_EVENTS } from '../../constants/constants'; import { onErrorText, onUpdatedConversastionError, @@ -75,6 +77,8 @@ const MyDataPage = () => { const [isFeedLoading, setIsFeedLoading] = useState(false); const [isSandbox, setIsSandbox] = useState(false); + const [activityFeeds, setActivityFeeds] = useState([]); + const [paging, setPaging] = useState({} as Paging); const feedFilterHandler = (filter: FeedFilter) => { @@ -310,7 +314,6 @@ const MyDataPage = () => { .then((res: AxiosResponse) => { const { data, paging: pagingObj } = res.data; setPaging(pagingObj); - setEntityThread((prevData) => [...prevData, ...data]); }) .catch((err: AxiosError) => { @@ -426,6 +429,34 @@ const MyDataPage = () => { } }, [AppState.userDetails, AppState.users, isAuthDisabled]); + useEffect(() => { + const socket = io(ROUTES.HOME, { + path: ROUTES.ACTIVITY_PUSH_FEED, + reconnectionAttempts: 3, + }); + + // socket.connect(); + + socket.on(SOCKET_EVENTS.ACTIVITY_FEED, (newActivity) => { + if (newActivity) { + setActivityFeeds((prevActivities) => [ + JSON.parse(newActivity), + ...prevActivities, + ]); + } + }); + + return () => { + socket.close(); + socket.off(SOCKET_EVENTS.ACTIVITY_FEED); + }; + }, []); + + const onRefreshFeeds = () => { + setEntityThread((prevData) => [...activityFeeds, ...prevData]); + setActivityFeeds([]); + }; + return ( {!isUndefined(countServices) && @@ -438,6 +469,7 @@ const MyDataPage = () => { !isUndefined(countUsers) ? ( { paging={paging} postFeedHandler={postFeedHandler} updateThreadHandler={updateThreadHandler} + onRefreshFeeds={onRefreshFeeds} /> {isSandbox ? : null} diff --git a/openmetadata-ui/src/main/resources/ui/src/styles/tailwind.css b/openmetadata-ui/src/main/resources/ui/src/styles/tailwind.css index eae0d1103ff..4c3fbd638ba 100644 --- a/openmetadata-ui/src/main/resources/ui/src/styles/tailwind.css +++ b/openmetadata-ui/src/main/resources/ui/src/styles/tailwind.css @@ -493,4 +493,11 @@ .ProseMirror .placeholder { @apply tw-text-grey-muted; } + + /* New Feed Button style */ + .tw-refreshButton { + @apply tw-w-full tw-rounded tw-text-info tw-w-full tw-py-1 tw-rounded tw-bg-feed-background tw-border tw-border-feed hover:tw-bg-feed-hover; + box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.1); + transition: background-color 100ms linear; + } } diff --git a/openmetadata-ui/src/main/resources/ui/tailwind.config.js b/openmetadata-ui/src/main/resources/ui/tailwind.config.js index 2833846b8a2..7c6c4ec6271 100644 --- a/openmetadata-ui/src/main/resources/ui/tailwind.config.js +++ b/openmetadata-ui/src/main/resources/ui/tailwind.config.js @@ -34,6 +34,7 @@ const info = '#1890FF'; const infoBG = '#1890FF40'; const warning = '#FFC34E'; const warningBG = '#FFC34E40'; +const feedBorder = '#D1E9FF'; // status colors @@ -88,6 +89,7 @@ module.exports = { hover: textBody, focus: primary, search: '#D5D6D9', + feed: feedBorder, }, boxShadow: { modal: '1px 1px 5px rgba(0, 0, 0, 0.2)', @@ -146,6 +148,8 @@ module.exports = { 'border-lite': liteGrayBorder, 'border-lite-60': liteGrayBorder60, 'border-gray': grayBorder, + 'feed-background': '#F8FBFF', + 'feed-hover': '#EBF2F9', }, fontFamily: { sans: ['Inter', ...defaultTheme.fontFamily.sans], diff --git a/openmetadata-ui/src/main/resources/ui/yarn.lock b/openmetadata-ui/src/main/resources/ui/yarn.lock index 954a5234588..23f230b4d53 100644 --- a/openmetadata-ui/src/main/resources/ui/yarn.lock +++ b/openmetadata-ui/src/main/resources/ui/yarn.lock @@ -1755,6 +1755,11 @@ dependencies: "@sinonjs/commons" "^1.7.0" +"@socket.io/component-emitter@~3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" + integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== + "@svgr/babel-plugin-add-jsx-attribute@^5.4.0": version "5.4.0" resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz#81ef61947bb268eb9d50523446f9c638fb355906" @@ -4908,6 +4913,13 @@ debug@^4.0.0, debug@^4.3.2: dependencies: ms "2.1.2" +debug@~4.3.1, debug@~4.3.2: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -5366,6 +5378,22 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" +engine.io-client@~6.2.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.2.2.tgz#c6c5243167f5943dcd9c4abee1bfc634aa2cbdd0" + integrity sha512-8ZQmx0LQGRTYkHuogVZuGSpDqYZtCM/nv8zQ68VZ+JkOpazJ7ICdsSpaO6iXwvaU30oFg5QJOJWj8zWqhbKjkQ== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + engine.io-parser "~5.0.3" + ws "~8.2.3" + xmlhttprequest-ssl "~2.0.0" + +engine.io-parser@~5.0.3: + version "5.0.4" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.4.tgz#0b13f704fa9271b3ec4f33112410d8f3f41d0fc0" + integrity sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg== + enhanced-resolve@^4.0.0: version "4.5.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" @@ -13104,6 +13132,24 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" +socket.io-client@^4.5.1: + version "4.5.1" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.5.1.tgz#cab8da71976a300d3090414e28c2203a47884d84" + integrity sha512-e6nLVgiRYatS+AHXnOnGi4ocOpubvOUCGhyWw8v+/FxW8saHkinG6Dfhi9TU0Kt/8mwJIAASxvw6eujQmjdZVA== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.2" + engine.io-client "~6.2.1" + socket.io-parser "~4.2.0" + +socket.io-parser@~4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.0.tgz#3f01e5bc525d94aa52a97ed5cbc12e229bbc4d6b" + integrity sha512-tLfmEwcEwnlQTxFB7jibL/q2+q8dlVQzj4JdRLJ/W/G1+Fu9VSxCx1Lo+n1HvXxKnM//dUuD0xgiA7tQf57Vng== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + sockjs-client@^1.5.0: version "1.5.1" resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.1.tgz#256908f6d5adfb94dabbdbd02c66362cca0f9ea6" @@ -14987,6 +15033,11 @@ ws@^7.3.1, ws@^7.4.6: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74" integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg== +ws@~8.2.3: + version "8.2.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" + integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== + xhr2@0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.3.tgz#cbfc4759a69b4a888e78cf4f20b051038757bd11" @@ -15007,6 +15058,11 @@ xmlchars@^2.1.1, xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +xmlhttprequest-ssl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67" + integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== + xtend@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"