diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AppContainer/app-container.less b/openmetadata-ui/src/main/resources/ui/src/components/AppContainer/app-container.less index bb622901504..8f30b04c273 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/AppContainer/app-container.less +++ b/openmetadata-ui/src/main/resources/ui/src/components/AppContainer/app-container.less @@ -19,13 +19,13 @@ line-height: inherit; } .navbar-container { - border: 1px solid @border-color; - padding: 12px 16px; + border-bottom: 1px solid @border-color; + padding: 13px 16px; display: flex; align-items: center; justify-content: space-between; .appbar-search { - height: 38px; + min-width: 380px; } .navbar-items { display: flex; @@ -42,4 +42,9 @@ background-color: @white; } } + .ant-layout-content { + height: calc(100vh - 64px); + overflow-y: auto; + overflow-x: hidden; + } } diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/KPIChartV1.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/KPIChartV1.tsx index ce719b737d5..305d446c7fc 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/KPIChartV1.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataInsightDetail/KPIChartV1.tsx @@ -147,7 +147,7 @@ const KPIChartV1: FC = ({ kpiList, selectedDays }) => { return ( { }, []); return ( -
+
); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/LeftSidebar/LeftSidebar.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/LeftSidebar/LeftSidebar.component.tsx index 2ac1f44b8a4..36376affdf6 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/LeftSidebar/LeftSidebar.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/LeftSidebar/LeftSidebar.component.tsx @@ -93,6 +93,7 @@ const LeftSidebar = () => { @@ -102,7 +103,7 @@ const LeftSidebar = () => { }> - + {
- + { + const { t } = useTranslation(); + const currentUserDetails = AppState.getCurrentUserDetails(); + const [isLoading, setIsLoading] = useState(true); + const [data, setData] = useState([]); + + const fetchMyDataAssets = async () => { + if (!currentUserDetails || !currentUserDetails.id) { + return; + } + setIsLoading(true); + try { + const userData = await getUserById(currentUserDetails?.id, 'owns'); + + if (userData) { + const includeData = Object.values(AssetsType); + const owns: EntityReference[] = userData.owns ?? []; + + const includedOwnsData = owns.filter((data) => + includeData.includes(data.type as AssetsType) + ); + + setData(includedOwnsData.slice(0, 8)); + } + } catch (err) { + setData([]); + } finally { + setIsLoading(false); + } + }; + + useEffect(() => { + fetchMyDataAssets(); + }, [currentUserDetails]); + + return ( + + + {t('label.my-data')} + + {data.length ? ( + + + {t('label.view-all')}{' '} + + {`(${data.length})`} + + + + ) : null} + + }> + + <> +
+ {data.length + ? data.map((item, index) => { + return ( +
+
+ +
+ } + type="text"> + + {getEntityName(item)} + + + +
+
+ ); + }) + : t('message.no-recently-viewed-date')} + + +
+
+ ); +}; + +export const MyDataWidget = observer(MyDataWidgetInternal); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/ResizablePanels/ResizablePanels.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/ResizablePanels/ResizablePanels.tsx index f394c24f5d4..d51d00255c7 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/ResizablePanels/ResizablePanels.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/ResizablePanels/ResizablePanels.tsx @@ -10,11 +10,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React from 'react'; -import { ReflexContainer, ReflexElement, ReflexSplitter } from 'react-reflex'; - import classNames from 'classnames'; import DocumentTitle from 'components/DocumentTitle/DocumentTitle'; +import React from 'react'; +import { ReflexContainer, ReflexElement, ReflexSplitter } from 'react-reflex'; import PanelContainer from './PanelContainer/PanelContainer'; import { ResizablePanelsProps } from './ResizablePanels.interface'; import './ResizablePanels.less'; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/nav-bar/NavBar.tsx b/openmetadata-ui/src/main/resources/ui/src/components/nav-bar/NavBar.tsx index 128ea27b438..43eda91e0e5 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/nav-bar/NavBar.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/nav-bar/NavBar.tsx @@ -321,26 +321,22 @@ const NavBar = ({ return ( <> -
-
- - - -
-
+
+ + + +
))}
-
- - - {t('label.help')} - - - + + + {t('label.help')} + + + + + + {upperCase((language || SupportedLocales.English).split('-')[0])} + + + + + -
- - {isImgUrlValid ? ( -
- user -
- ) : ( - - )} - - } - isDropDownIconVisible={false} - type="link" - /> -
+ +
+ + {isImgUrlValid ? ( +
+ user +
+ ) : ( + + )} + + } + isDropDownIconVisible={false} + type="link" + />
{ - const { t } = useTranslation(); - const location = useLocation(); - const { isAuthDisabled } = useAuth(location.pathname); - const [error, setError] = useState(''); - - const initialState = useMemo( - () => ({ - entityCounts: { - tableCount: 0, - topicCount: 0, - dashboardCount: 0, - pipelineCount: 0, - mlmodelCount: 0, - servicesCount: 0, - userCount: 0, - teamCount: 0, - }, - entityCountLoading: false, - }), - [] - ); - - const [state, dispatch] = useReducer< - Reducer> - >(reducerWithoutAction, initialState); - - const handleStateChange = useCallback((newState: Partial) => { - dispatch(newState); - }, []); - - const [ownedData, setOwnedData] = useState>(); - const [followedData, setFollowedData] = useState>(); - const [ownedDataCount, setOwnedDataCount] = useState(0); - const [followedDataCount, setFollowedDataCount] = useState(0); - const [pendingTaskCount, setPendingTaskCount] = useState(0); - - const [entityThread, setEntityThread] = useState([]); - const [isFeedLoading, setIsFeedLoading] = useState(false); - const [isLoadingOwnedData, setIsLoadingOwnedData] = useState(false); - - const [activityFeeds, setActivityFeeds] = useState([]); - - const [paging, setPaging] = useState({} as Paging); - const { socket } = useWebSocketConnector(); - - const currentUser = useMemo( - () => AppState.getCurrentUserDetails(), - [AppState.userDetails, AppState.nonSecureUserDetails] - ); - - const fetchEntityCount = async () => { - handleStateChange({ - entityCountLoading: true, - }); - try { - const res = await getAllEntityCount(); - handleStateChange({ - entityCounts: { - ...res, - }, - }); - } catch (err) { - showErrorToast(err as AxiosError); - handleStateChange({ - entityCounts: { - tableCount: 0, - topicCount: 0, - dashboardCount: 0, - pipelineCount: 0, - mlmodelCount: 0, - storageContainerCount: 0, - servicesCount: 0, - userCount: 0, - teamCount: 0, - glossaryTermCount: 0, - }, - }); - } finally { - handleStateChange({ - entityCountLoading: false, - }); - } - }; - - const fetchData = () => { - setError(''); - fetchEntityCount(); - }; - - const fetchMyData = async () => { - if (!currentUser || !currentUser.id) { - return; - } - setIsLoadingOwnedData(true); - try { - const userData = await getUserById(currentUser?.id, 'follows, owns'); - - if (userData) { - const includeData = Object.values(AssetsType); - const owns: EntityReference[] = userData.owns ?? []; - const follows: EntityReference[] = userData.follows ?? []; - - const includedFollowsData = follows.filter((data) => - includeData.includes(data.type as AssetsType) - ); - const includedOwnsData = owns.filter((data) => - includeData.includes(data.type as AssetsType) - ); - - setFollowedDataCount(includedFollowsData.length); - setOwnedDataCount(includedOwnsData.length); - - setFollowedData(includedFollowsData.slice(0, 8)); - setOwnedData(includedOwnsData.slice(0, 8)); - } - } catch (err) { - setOwnedData([]); - setFollowedData([]); - } finally { - setIsLoadingOwnedData(false); - } - }; - - const getFeedData = ( - filterType?: FeedFilter, - after?: string, - type?: ThreadType - ) => { - setIsFeedLoading(true); - const feedFilterType = filterType ?? FeedFilter.ALL; - const userId = - feedFilterType === FeedFilter.ALL ? undefined : currentUser?.id; - - getFeedsWithFilter(userId, feedFilterType, after, type) - .then((res) => { - const { data, paging: pagingObj } = res; - setPaging(pagingObj); - setEntityThread((prevData) => [...prevData, ...data]); - }) - .catch((err: AxiosError) => { - showErrorToast( - err, - t('server.entity-fetch-error', { - entity: t('label.activity-feed'), - }) - ); - }) - .finally(() => { - setIsFeedLoading(false); - }); - }; - - const handleFeedFetchFromFeedList = useCallback( - (filterType?: FeedFilter, after?: string, type?: ThreadType) => { - !after && setEntityThread([]); - getFeedData(filterType, after, type); - }, - [getFeedData, setEntityThread] - ); - - const postFeedHandler = (value: string, id: string) => { - const data = { - message: value, - from: currentUser?.name, - }; - postFeedById(id, data as Post) - .then((res) => { - if (res) { - const { id, posts } = res; - setEntityThread((pre) => { - return pre.map((thread) => { - if (thread.id === id) { - return { ...res, posts: posts?.slice(-3) }; - } else { - return thread; - } - }); - }); - } - }) - .catch((err: AxiosError) => { - showErrorToast(err, t('server.feed-post-error')); - }); - }; - - const deletePostHandler = ( - threadId: string, - postId: string, - isThread: boolean - ) => { - deletePost(threadId, postId, isThread, setEntityThread); - }; - - const updateThreadHandler = ( - threadId: string, - postId: string, - isThread: boolean, - data: Operation[] - ) => { - updateThreadData(threadId, postId, isThread, data, setEntityThread); - }; - - // Fetch tasks list to show count for Pending tasks - const fetchMyTaskData = useCallback(() => { - if (!currentUser || !currentUser.id) { - return; - } - - getFeedsWithFilter( - currentUser.id, - FeedFilter.ASSIGNED_TO, - undefined, - ThreadType.Task - ).then((res) => { - res.data && setPendingTaskCount(res.paging.total); - }); - }, [currentUser]); - - useEffect(() => { - fetchData(); - fetchMyTaskData(); - }, []); - - useEffect(() => { - getFeedData(FeedFilter.OWNER); - }, []); - - useEffect(() => { - if ( - ((isAuthDisabled && AppState.users.length) || - !isEmpty(AppState.userDetails)) && - (isNil(ownedData) || isNil(followedData)) - ) { - fetchMyData(); - } - }, [AppState.userDetails, AppState.users, isAuthDisabled]); - - useEffect(() => { - if (socket) { - socket.on(SOCKET_EVENTS.ACTIVITY_FEED, (newActivity) => { - if (newActivity) { - setActivityFeeds((prevActivities) => [ - JSON.parse(newActivity), - ...prevActivities, - ]); - } - }); - socket.on(SOCKET_EVENTS.TASK_CHANNEL, (newActivity) => { - if (newActivity) { - setPendingTaskCount((prevCount) => - prevCount ? prevCount + 1 : prevCount - ); - } - }); - } - - return () => { - socket && socket.off(SOCKET_EVENTS.ACTIVITY_FEED); - socket && socket.off(SOCKET_EVENTS.TASK_CHANNEL); - }; - }, [socket]); - - const onRefreshFeeds = () => { - getFeedData(); - setEntityThread([]); - setActivityFeeds([]); - }; - - return ( - <> - {!isEmpty(state.entityCounts) ? ( - - - - ) : ( - - )} - - ); -}; - -export default observer(MyDataPage); diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/MyDataPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/MyDataPage.test.tsx deleted file mode 100644 index 09e5392c13e..00000000000 --- a/openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/MyDataPage.test.tsx +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2022 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 { findByText, queryByText, render } from '@testing-library/react'; -import React from 'react'; -import { getAllEntityCount } from 'rest/miscAPI'; -import MyDataPageComponent from './MyDataPage.component'; - -const mockAuth = { - isAuthDisabled: true, -}; - -jest.mock('react', () => { - const originalReact = jest.requireActual('react'); - - return { - ...originalReact, - useReducer: jest.fn((_reducer, initialState) => { - return [initialState, jest.fn()]; - }), - }; -}); - -jest.mock('components/MyData/MyData.component', () => { - return jest - .fn() - .mockReturnValue(

Mydata component

); -}); - -jest.mock('rest/miscAPI', () => ({ - fetchSandboxConfig: jest.fn().mockImplementation(() => - Promise.resolve({ - data: { - sandboxModeEnabled: false, - }, - }) - ), - getAllEntityCount: jest.fn().mockImplementation(() => - Promise.resolve({ - data: { - tableCount: 40, - topicCount: 13, - dashboardCount: 10, - pipelineCount: 3, - mlmodelCount: 2, - servicesCount: 193, - userCount: 100, - teamCount: 7, - }, - }) - ), -})); - -jest.mock('rest/feedsAPI', () => ({ - getFeedsWithFilter: jest.fn().mockImplementation(() => - Promise.resolve({ - data: { - data: [], - }, - }) - ), -})); - -jest.mock('../../utils/CommonUtils', () => ({ - isSandboxOMD: jest.fn().mockReturnValue(true), -})); - -jest.mock('../../hooks/authHooks', () => ({ - useAuth: jest.fn(() => mockAuth), -})); - -jest.mock('react-router-dom', () => ({ - useLocation: jest.fn().mockReturnValue({ - pathname: 'pathname', - }), -})); - -jest.mock('../../utils/APIUtils', () => ({ - formatDataResponse: jest.fn(), -})); - -jest.mock('components/MyData/MyData.component', () => { - return jest.fn().mockImplementation(() =>

MyData.component

); -}); - -jest.mock('components/GithubStarButton/GithubStarButton', () => { - return jest.fn().mockImplementation(() =>

GithubStarButton.component

); -}); - -describe('Test MyData page component', () => { - it('Component should render', async () => { - const { container } = render(); - const myData = await findByText(container, /MyData.component/i); - - const githubStarButton = await queryByText( - container, - /GithubStarButton.component/i - ); - - const slackChat = await queryByText(container, /SlackChat.component/i); - - expect(myData).toBeInTheDocument(); - expect(githubStarButton).not.toBeInTheDocument(); - expect(slackChat).not.toBeInTheDocument(); - }); - - it('Component should render in sandbox mode', async () => { - const { container } = render(); - const myData = await findByText(container, /MyData.component/i); - - expect(myData).toBeInTheDocument(); - }); - - describe('render Sad Paths', () => { - it('show error message on failing of config/sandbox api', async () => { - const { container } = render(); - const myData = await findByText(container, /MyData.component/i); - - const githubStarButton = await queryByText( - container, - /GithubStarButton.component/i - ); - - expect(myData).toBeInTheDocument(); - expect(githubStarButton).not.toBeInTheDocument(); - }); - - it('show error message on no data from config/sandbox api', async () => { - const { container } = render(); - const myData = await findByText(container, /MyData.component/i); - - const githubStarButton = await queryByText( - container, - /GithubStarButton.component/i - ); - - expect(myData).toBeInTheDocument(); - expect(githubStarButton).not.toBeInTheDocument(); - }); - - it('should render component if table count api fails', async () => { - (getAllEntityCount as jest.Mock).mockImplementationOnce(() => - Promise.reject({ - response: { data: { message: 'Error!' } }, - }) - ); - - const { container } = render(); - const myData = await findByText(container, /MyData.component/i); - - expect(myData).toBeInTheDocument(); - }); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/MyDataPageV1.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/MyDataPageV1.component.tsx index 3fe16f14479..9c6740d1252 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/MyDataPageV1.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/MyDataPageV1.component.tsx @@ -16,6 +16,7 @@ import { AxiosError } from 'axios'; import ActivityFeedProvider from 'components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider'; import PageLayoutV1 from 'components/containers/PageLayoutV1'; import KPIWidget from 'components/KPIWidget/KPIWidget.component'; +import { MyDataWidget } from 'components/MyData/MyDataWidget/MyDataWidget.component'; import RightSidebar from 'components/MyData/RightSidebar/RightSidebar.component'; import TotalDataAssetsWidget from 'components/TotalDataAssetsWidget/TotalDataAssetsWidget.component'; import FeedsWidget from 'components/Widgets/FeedsWidget/FeedsWidget.component'; @@ -30,7 +31,7 @@ import AppState from '../../AppState'; import { AssetsType } from '../../enums/entity.enum'; import { EntityReference } from '../../generated/type/entityReference'; import { useAuth } from '../../hooks/authHooks'; -import './myData.less'; +import './my-data.less'; const MyDataPageV1 = () => { const { t } = useTranslation(); @@ -132,7 +133,10 @@ const MyDataPageV1 = () => { - + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/myData.less b/openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/my-data.less similarity index 92% rename from openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/myData.less rename to openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/my-data.less index ea07ae4966b..24bab77720b 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/myData.less +++ b/openmetadata-ui/src/main/resources/ui/src/pages/MyDataPage/my-data.less @@ -35,3 +35,9 @@ .view-all-btn { color: @group-title-color !important; } + +.card-widget { + box-shadow: none; + border-radius: 10px; + height: 100%; +} diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/page-not-found/index.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/page-not-found/index.tsx index bf3bbd71ffa..4afc12fe004 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/page-not-found/index.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/page-not-found/index.tsx @@ -27,7 +27,7 @@ const PageNotFound = () => { className="page-not-found-container tw-relative" data-testid="no-page-found">
- {t('label.not-found')} + {t('label.not-found-lowercase')}
@@ -53,7 +53,7 @@ const PageNotFound = () => {
- {t('label.not-found')} + {t('label.not-found-lowercase')}
diff --git a/openmetadata-ui/src/main/resources/ui/src/styles/layout/page-layout.less b/openmetadata-ui/src/main/resources/ui/src/styles/layout/page-layout.less index 446b42e31b8..33ab91a0290 100644 --- a/openmetadata-ui/src/main/resources/ui/src/styles/layout/page-layout.less +++ b/openmetadata-ui/src/main/resources/ui/src/styles/layout/page-layout.less @@ -15,7 +15,7 @@ .page-layout-v1-vertical-scroll { // 64 header + ( 16 + 16 )spacing Y - height: calc(100vh - 96px); + height: calc(100vh - 64px); overflow-y: auto; overflow-x: hidden; }