From f098e30e8045467852791238d8189dc034751d17 Mon Sep 17 00:00:00 2001 From: Harshit Shah Date: Wed, 30 Jul 2025 12:39:08 +0530 Subject: [PATCH] Fix landing page feedbacks (#22648) * Fix landing page feedbacks * fix failing tests --- .../CustomizeMyData/CustomizeMyData.tsx | 6 -- .../FeedWidget/FeedWidget.component.tsx | 1 + .../MyDataWidget/MyDataWidget.component.tsx | 1 + .../PersonaDetailsCard.test.tsx | 5 +- .../PersonaDetailsCard/PersonaDetailsCard.tsx | 5 +- .../MyData/RightSidebar/FollowingWidget.tsx | 1 + .../Common/WidgetHeader/WidgetHeader.tsx | 15 ++++- .../CuratedAssetsWidget.test.tsx | 1 + .../CuratedAssetsWidget.tsx | 2 + .../DataAssetsWidget.component.tsx | 1 + .../Widgets/DomainsWidget/DomainsWidget.tsx | 48 ++++++++++------ .../Widgets/DomainsWidget/domains-widget.less | 56 ++++++++++--------- .../Widgets/KPIWidget/KPIWidget.component.tsx | 1 + .../Widgets/KPIWidget/KPIWidget.test.tsx | 4 ++ .../Widgets/MyTaskWidget/MyTaskWidget.tsx | 3 + .../TotalDataAssetsWidget.component.tsx | 1 + .../PersonaDetailsPage/PersonaDetailsPage.tsx | 18 ++++++ 17 files changed, 116 insertions(+), 53 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/CustomizableComponents/CustomizeMyData/CustomizeMyData.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/CustomizableComponents/CustomizeMyData/CustomizeMyData.tsx index e29e1d33ad1..b5084a39ba6 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/CustomizableComponents/CustomizeMyData/CustomizeMyData.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/CustomizableComponents/CustomizeMyData/CustomizeMyData.tsx @@ -132,11 +132,6 @@ function CustomizeMyData({ [layout] ); - const emptyWidgetPlaceholder = useMemo( - () => layout.find((widget) => widget.i.endsWith('.EmptyWidgetPlaceholder')), - [layout] - ); - const disableSave = useMemo(() => { const filteredLayout = layout.filter((widget) => widget.i.startsWith('KnowledgePanel') @@ -242,7 +237,6 @@ function CustomizeMyData({ customizeMyDataPageClassBase.landingPageWidgetMargin, customizeMyDataPageClassBase.landingPageWidgetMargin, ]} - maxRows={emptyWidgetPlaceholder?.y} preventCollision={false} rowHeight={customizeMyDataPageClassBase.landingPageRowHeight} onLayoutChange={handleLayoutUpdate}> diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/FeedWidget/FeedWidget.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/FeedWidget/FeedWidget.component.tsx index d7feb3e12ef..32f2d6f403f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/FeedWidget/FeedWidget.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/FeedWidget/FeedWidget.component.tsx @@ -152,6 +152,7 @@ const MyFeedWidgetInternal = ({ handleRemoveWidget={handleRemoveWidget} icon={} isEditView={isEditView} + redirectUrlOnTitleClick={ROUTES.EXPLORE} selectedSortBy={selectedFilter} sortOptions={FEED_WIDGET_FILTER_OPTIONS} title={t('label.activity-feed')} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/MyDataWidget/MyDataWidget.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/MyDataWidget/MyDataWidget.component.tsx index d7824583519..f3f9b867fca 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/MyDataWidget/MyDataWidget.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/MyDataWidget/MyDataWidget.component.tsx @@ -281,6 +281,7 @@ const MyDataWidgetInternal = ({ handleRemoveWidget={handleRemoveWidget} icon={} isEditView={isEditView} + redirectUrlOnTitleClick={ROUTES.EXPLORE} selectedSortBy={selectedFilter} sortOptions={MY_DATA_WIDGET_FILTER_OPTIONS} title={t('label.my-data')} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Persona/PersonaDetailsCard/PersonaDetailsCard.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Persona/PersonaDetailsCard/PersonaDetailsCard.test.tsx index 7dedb89c24c..affbeba81b7 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Persona/PersonaDetailsCard/PersonaDetailsCard.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Persona/PersonaDetailsCard/PersonaDetailsCard.test.tsx @@ -82,7 +82,10 @@ describe('PersonaDetailsCard Component', () => { const personaCardTitle = await screen.findByText('John Doe'); fireEvent.click(personaCardTitle); - expect(mockNavigate).toHaveBeenCalledWith('/settings/persona/john-doe'); + expect(mockNavigate).toHaveBeenCalledWith({ + hash: '#customize-ui', + pathname: '/settings/persona/john-doe', + }); }); it('should not navigate when persona.fullyQualifiedName is missing', async () => { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Persona/PersonaDetailsCard/PersonaDetailsCard.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Persona/PersonaDetailsCard/PersonaDetailsCard.tsx index 2e084816e76..d46f990e16b 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Persona/PersonaDetailsCard/PersonaDetailsCard.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Persona/PersonaDetailsCard/PersonaDetailsCard.tsx @@ -29,7 +29,10 @@ export const PersonaDetailsCard = ({ persona }: PersonaDetailsCardProps) => { const handleCardClick = useCallback(() => { if (persona.fullyQualifiedName) { - navigate(getPersonaDetailsPath(persona.fullyQualifiedName)); + navigate({ + pathname: getPersonaDetailsPath(persona.fullyQualifiedName), + hash: '#customize-ui', + }); } }, [persona]); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/RightSidebar/FollowingWidget.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/RightSidebar/FollowingWidget.tsx index d9b02a28542..9849ab122cd 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/RightSidebar/FollowingWidget.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/RightSidebar/FollowingWidget.tsx @@ -266,6 +266,7 @@ function FollowingWidget({ handleRemoveWidget={handleRemoveWidget} icon={} isEditView={isEditView} + redirectUrlOnTitleClick={ROUTES.EXPLORE} selectedSortBy={selectedEntityFilter} sortOptions={FOLLOWING_WIDGET_FILTER_OPTIONS} title={t('label.following-assets')} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/Common/WidgetHeader/WidgetHeader.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/Common/WidgetHeader/WidgetHeader.tsx index efcbb2c6601..3214fe1a128 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/Common/WidgetHeader/WidgetHeader.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/Common/WidgetHeader/WidgetHeader.tsx @@ -16,6 +16,7 @@ import { Button, Col, Row, Typography } from 'antd'; import { MenuInfo } from 'rc-menu/lib/interface'; import { ReactNode } from 'react'; import { Layout } from 'react-grid-layout'; +import { useNavigate } from 'react-router-dom'; import { ReactComponent as EditIcon } from '../../../../../assets/svg/edit-new.svg'; import { WidgetConfig } from '../../../../../pages/CustomizablePage/CustomizablePage.interface'; import WidgetMoreOptions from '../WidgetMoreOptions/WidgetMoreOptions'; @@ -33,6 +34,7 @@ export interface WidgetHeaderProps { isEditView?: boolean; onEditClick?: () => void; onSortChange?: (key: string) => void; + redirectUrlOnTitleClick?: string; selectedSortBy?: string; sortOptions?: Array<{ key: string; @@ -53,12 +55,14 @@ const WidgetHeader = ({ isEditView = false, onEditClick, onSortChange, + redirectUrlOnTitleClick, selectedSortBy, sortOptions, title, widgetKey, widgetWidth = 2, }: WidgetHeaderProps) => { + const navigate = useNavigate(); const handleSortByClick = (e: MenuInfo) => { onSortChange?.(e.key); }; @@ -83,6 +87,12 @@ const WidgetHeader = ({ } }; + const handleTitleClick = () => { + if (redirectUrlOnTitleClick) { + navigate(redirectUrlOnTitleClick); + } + }; + return ( {icon &&
{icon}
} + }} + onClick={handleTitleClick}> {title} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/CuratedAssetsWidget/CuratedAssetsWidget.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/CuratedAssetsWidget/CuratedAssetsWidget.test.tsx index 5fc4fd89d4b..f249e36e7a6 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/CuratedAssetsWidget/CuratedAssetsWidget.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/CuratedAssetsWidget/CuratedAssetsWidget.test.tsx @@ -26,6 +26,7 @@ jest.mock('../../../../rest/searchAPI', () => ({ })); jest.mock('react-router-dom', () => ({ + useNavigate: jest.fn(), Link: jest.fn().mockImplementation(({ children, to }) => ( {children} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/CuratedAssetsWidget/CuratedAssetsWidget.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/CuratedAssetsWidget/CuratedAssetsWidget.tsx index da4d7d1113e..ce269dd631f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/CuratedAssetsWidget/CuratedAssetsWidget.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/CuratedAssetsWidget/CuratedAssetsWidget.tsx @@ -22,6 +22,7 @@ import { Link } from 'react-router-dom'; import { ReactComponent as CuratedAssetsEmptyIcon } from '../../../../assets/svg/curated-assets-no-data-placeholder.svg'; import { ReactComponent as CuratedAssetsNoDataIcon } from '../../../../assets/svg/curated-assets-not-found-placeholder.svg'; import { ReactComponent as StarOutlinedIcon } from '../../../../assets/svg/star-outlined.svg'; +import { ROUTES } from '../../../../constants/constants'; import { getSortField, getSortOrder, @@ -374,6 +375,7 @@ const CuratedAssetsWidget = ({ ) } isEditView={isEditView} + redirectUrlOnTitleClick={ROUTES.EXPLORE} selectedSortBy={selectedSortBy} sortOptions={CURATED_ASSETS_SORT_BY_OPTIONS} title={ diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/DataAssetsWidget/DataAssetsWidget.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/DataAssetsWidget/DataAssetsWidget.component.tsx index 5a0b97f93c3..203c03e409a 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/DataAssetsWidget/DataAssetsWidget.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/DataAssetsWidget/DataAssetsWidget.component.tsx @@ -159,6 +159,7 @@ const DataAssetsWidget = ({ handleRemoveWidget={handleRemoveWidget} icon={} isEditView={isEditView} + redirectUrlOnTitleClick={ROUTES.EXPLORE} selectedSortBy={selectedSortBy} sortOptions={DATA_ASSETS_SORT_BY_OPTIONS} title={t('label.data-asset-plural')} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/DomainsWidget/DomainsWidget.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/DomainsWidget/DomainsWidget.tsx index 8a75e29ad38..27c7c5756e5 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/DomainsWidget/DomainsWidget.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/DomainsWidget/DomainsWidget.tsx @@ -10,10 +10,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Typography } from 'antd'; +import { Button, Typography } from 'antd'; +import classNames from 'classnames'; import { isEmpty } from 'lodash'; import { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { useNavigate } from 'react-router-dom'; import { ReactComponent as DomainNoDataPlaceholder } from '../../../../assets/svg/domain-no-data-placeholder.svg'; import { ReactComponent as DomainIcon } from '../../../../assets/svg/ic-domains-widget.svg'; import { @@ -35,6 +37,7 @@ import { } from '../../../../pages/CustomizablePage/CustomizablePage.interface'; import { searchData } from '../../../../rest/miscAPI'; import { getDomainIcon } from '../../../../utils/DomainUtils'; +import { getDomainDetailsPath } from '../../../../utils/RouterUtils'; import ErrorPlaceHolder from '../../../common/ErrorWithPlaceholder/ErrorPlaceHolder'; import WidgetEmptyState from '../Common/WidgetEmptyState/WidgetEmptyState'; import WidgetFooter from '../Common/WidgetFooter/WidgetFooter'; @@ -55,6 +58,7 @@ const DomainsWidget = ({ }: WidgetCommonProps) => { const { t } = useTranslation(); const [domains, setDomains] = useState([]); + const navigate = useNavigate(); const [selectedSortBy, setSelectedSortBy] = useState( DOMAIN_SORT_BY_KEYS.LATEST ); @@ -89,6 +93,13 @@ const DomainsWidget = ({ } }, [selectedSortBy, getSortField, getSortOrder, applySortToData]); + const handleDomainClick = useCallback( + (domain: Domain) => { + navigate(getDomainDetailsPath(domain.fullyQualifiedName ?? '')); + }, + [navigate] + ); + const domainsWidget = useMemo(() => { const widget = currentLayout?.find( (widget: WidgetConfig) => widget.i === widgetKey @@ -127,11 +138,15 @@ const DomainsWidget = ({
{domains.map((domain) => ( -
+ ))}
@@ -218,6 +229,7 @@ const DomainsWidget = ({ /> } isEditView={isEditView} + redirectUrlOnTitleClick={ROUTES.DOMAIN} selectedSortBy={selectedSortBy} sortOptions={DOMAIN_SORT_BY_OPTIONS} title={t('label.domain-plural')} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/DomainsWidget/domains-widget.less b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/DomainsWidget/domains-widget.less index 43592595fa2..51f5f561778 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/DomainsWidget/domains-widget.less +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/DomainsWidget/domains-widget.less @@ -72,24 +72,21 @@ box-shadow: @button-box-shadow-default; position: relative; overflow: hidden; - height: @size-2xl; + height: 32px; border: 1px solid #dbe0e7; border-radius: @size-xs; } .domain-card-bar { - width: 6px; height: 100%; - border-radius: 6px 0 0 6px; - flex-shrink: 0; - background: @primary-color; + border-left: 6px solid @primary-color; } .domain-card-content { display: flex; align-items: center; width: 100%; - padding: 0 @size-md; + padding: 0 @size-xs; min-width: 0; } @@ -97,33 +94,33 @@ display: flex; align-items: center; gap: @size-xs; - font-size: @size-md; + font-size: @font-size-base; font-weight: @font-medium; - color: @text-color; + color: @grey-700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .domain-card-name { - max-width: 100%; + color: @grey-700 !important; + display: inline-block; + margin-bottom: 0 !important; + max-width: 150px !important; overflow: hidden; text-overflow: ellipsis; - white-space: nowrap; - display: inline-block; vertical-align: middle; - color: @grey-700 !important; + white-space: nowrap; } .domain-card-count { - background: @grey-31; - color: @grey-32; - font-size: @font-size-base; + background: @grey-15; + color: @grey-700; + font-size: @size-sm; font-weight: @font-semibold; border-radius: @size-md; - padding: 2px @size-sm; + padding: 2px @size-xs; margin-left: @size-xs; - min-width: 40px; text-align: center; display: inline-block; } @@ -134,11 +131,10 @@ background: @white; border: 1px solid #dbe0e7; border-radius: @size-sm; - width: 340px; - height: 80px; box-shadow: @button-box-shadow-default; + height: 70px !important; padding: 0 @size-sm; - gap: @size-mlg; + gap: @size-sm; } .domain-card-full-icon { @@ -151,6 +147,11 @@ font-size: 32px; color: @white; padding: @size-xs; + background: @primary-color; + + svg { + color: @white; + } } .domain-card-full-content { @@ -166,18 +167,23 @@ align-items: center; gap: @size-xs; margin-bottom: 2px; + color: @grey-700; + + .ant-typography { + color: @grey-700; + max-width: 240px; + } } .domain-card-full-count { - background: @grey-30; - color: @blue-35; + background: @grey-15; + color: @grey-700; font-size: @size-sm; - font-weight: @font-regular; - border-radius: @size-xs; + font-weight: @font-semibold; + border-radius: @size-md; padding: 2px @size-xs; text-align: center; display: inline-block; - margin-left: 6px; } .domain-card-icon { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/KPIWidget/KPIWidget.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/KPIWidget/KPIWidget.component.tsx index 100a404745d..1d47e6efefb 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/KPIWidget/KPIWidget.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/KPIWidget/KPIWidget.component.tsx @@ -337,6 +337,7 @@ const KPIWidget = ({ handleRemoveWidget={handleRemoveWidget} icon={} isEditView={isEditView} + redirectUrlOnTitleClick={ROUTES.KPI_LIST} title={widgetData?.w === 2 ? t('label.kpi-title') : t('label.kpi')} widgetKey={widgetKey} widgetWidth={widgetData?.w} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/KPIWidget/KPIWidget.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/KPIWidget/KPIWidget.test.tsx index 9681e12071f..6f0af2f7cb5 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/KPIWidget/KPIWidget.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/KPIWidget/KPIWidget.test.tsx @@ -90,6 +90,10 @@ jest.mock('./KPILegend/KPILegend', () => jest.fn().mockReturnValue(

KPILegend.Component

) ); +jest.mock('react-router-dom', () => ({ + useNavigate: jest.fn(), +})); + const mockHandleRemoveWidget = jest.fn(); const mockHandleLayoutUpdate = jest.fn(); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/MyTaskWidget/MyTaskWidget.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/MyTaskWidget/MyTaskWidget.tsx index 2c2da76879a..e4394a7cdaf 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/MyTaskWidget/MyTaskWidget.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/MyTaskWidget/MyTaskWidget.tsx @@ -97,6 +97,9 @@ const MyTaskWidget = ({ handleRemoveWidget={handleRemoveWidget} icon={} isEditView={isEditView} + redirectUrlOnTitleClick={ + currentUser?.name && `users/${currentUser?.name}/task` + } selectedSortBy={selectedFilter} sortOptions={MY_TASK_WIDGET_FILTER_OPTIONS} title={t('label.my-task-plural')} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/TotalDataAssetsWidget/TotalDataAssetsWidget.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/TotalDataAssetsWidget/TotalDataAssetsWidget.component.tsx index ee3adfdae85..dd1412f6fa1 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/TotalDataAssetsWidget/TotalDataAssetsWidget.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MyData/Widgets/TotalDataAssetsWidget/TotalDataAssetsWidget.component.tsx @@ -322,6 +322,7 @@ const TotalDataAssetsWidget = ({ handleRemoveWidget={handleRemoveWidget} icon={} isEditView={isEditView} + redirectUrlOnTitleClick={ROUTES.DATA_INSIGHT} selectedSortBy={selectedSortBy} sortOptions={DATA_ASSETS_SORT_BY_OPTIONS} title={t('label.data-insight-total-entity-summary')} diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/Persona/PersonaDetailsPage/PersonaDetailsPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/Persona/PersonaDetailsPage/PersonaDetailsPage.tsx index 3baa5765c17..3807cee47f4 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/Persona/PersonaDetailsPage/PersonaDetailsPage.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/Persona/PersonaDetailsPage/PersonaDetailsPage.tsx @@ -108,6 +108,24 @@ export const PersonaDetailsPage = () => { } }, [fqn]); + // Add #customize-ui to URL if # doesn't exist + useEffect(() => { + if (location.hash) { + return; + } + + if (!location.hash.includes('customize-ui')) { + navigate( + { + pathname: location.pathname, + search: location.search, + hash: '#customize-ui', + }, + { replace: true } + ); + } + }, []); + const fetchCurrentUser = useCallback(async () => { try { if (currentUser) {