fix(ui): add warning for view all modal (#14702)

This commit is contained in:
Aseem Bansal 2025-09-08 19:27:41 +05:30 committed by GitHub
parent 9105241bfd
commit 3e1e9fcf34
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 123 additions and 10 deletions

View File

@ -78,6 +78,8 @@ export enum EventType {
IngestionTestConnectionEvent,
IngestionExecutionResultViewedEvent,
IngestionSourceConfigurationImpressionEvent,
IngestionViewAllClickEvent,
IngestionViewAllClickWarningEvent,
CreateIngestionSourceEvent,
UpdateIngestionSourceEvent,
DeleteIngestionSourceEvent,
@ -620,6 +622,16 @@ export interface IngestionTestConnectionEvent extends BaseEvent {
outcome?: string;
}
export interface IngestionViewAllClickEvent extends BaseEvent {
type: EventType.IngestionViewAllClickEvent;
executionUrn?: string;
}
export interface IngestionViewAllClickWarningEvent extends BaseEvent {
type: EventType.IngestionViewAllClickWarningEvent;
executionUrn?: string;
}
export interface IngestionExecutionResultViewedEvent extends BaseEvent {
type: EventType.IngestionExecutionResultViewedEvent;
executionUrn: string;
@ -1249,4 +1261,6 @@ export type Event =
| ProductTourButtonClickEvent
| IngestionTestConnectionEvent
| IngestionExecutionResultViewedEvent
| IngestionSourceConfigurationImpressionEvent;
| IngestionSourceConfigurationImpressionEvent
| IngestionViewAllClickEvent
| IngestionViewAllClickWarningEvent;

View File

@ -109,6 +109,8 @@ type Props = {
applyView?: boolean;
onLineageClick?: () => void;
isLineageTab?: boolean;
isViewAllMode?: boolean | false;
handleViewAllClickWarning?: () => void;
};
export const EmbeddedListSearch = ({
@ -139,6 +141,8 @@ export const EmbeddedListSearch = ({
applyView = false,
onLineageClick,
isLineageTab = false,
isViewAllMode = false,
handleViewAllClickWarning,
}: Props) => {
const { shouldRefetchEmbeddedListSearch, setShouldRefetchEmbeddedListSearch } = useEntityContext();
// Adjust query based on props
@ -348,6 +352,8 @@ export const EmbeddedListSearch = ({
setSelectedEntities={setSelectedEntities}
entityAction={entityAction}
applyView={applyView}
isViewAllMode={isViewAllMode}
handleViewAllClickWarning={handleViewAllClickWarning}
/>
</Container>
);

View File

@ -33,6 +33,8 @@ type Props = {
searchBarInputStyle?: any;
entityAction?: React.FC<EntityActionProps>;
applyView?: boolean;
isViewAllMode?: boolean | false;
handleViewAllClickWarning?: () => void;
};
export const EmbeddedListSearchModal = ({
@ -48,6 +50,8 @@ export const EmbeddedListSearchModal = ({
searchBarInputStyle,
entityAction,
applyView,
isViewAllMode,
handleViewAllClickWarning,
}: Props) => {
// Component state
const [query, setQuery] = useState<string>('');
@ -98,6 +102,8 @@ export const EmbeddedListSearchModal = ({
searchBarInputStyle={searchBarInputStyle}
entityAction={entityAction}
applyView={applyView}
isViewAllMode={isViewAllMode}
handleViewAllClickWarning={handleViewAllClickWarning}
/>
</SearchContainer>
</Modal>

View File

@ -1,6 +1,8 @@
import { LoadingOutlined } from '@ant-design/icons';
import { ExclamationCircleFilled, LoadingOutlined } from '@ant-design/icons';
import { Text, colors } from '@components';
import { Button, Pagination, Spin, Typography } from 'antd';
import React from 'react';
import { useHistory } from 'react-router';
import styled from 'styled-components';
import {
@ -13,10 +15,11 @@ import { EntityAndType } from '@app/entity/shared/types';
import { SearchFiltersSection } from '@app/search/SearchFiltersSection';
import { combineSiblingsInSearchResults } from '@app/search/utils/combineSiblingsInSearchResults';
import { UnionType } from '@app/search/utils/constants';
import { navigateToSearchUrl } from '@app/searchV2/utils/navigateToSearchUrl';
import { useIsShowSeparateSiblingsEnabled } from '@app/useAppConfig';
import { SearchCfg } from '@src/conf';
import { FacetFilterInput, FacetMetadata, SearchResults as SearchResultType } from '@types';
import { Dataset, FacetFilterInput, FacetMetadata, SearchResults as SearchResultType } from '@types';
const SearchBody = styled.div`
height: 100%;
@ -82,6 +85,17 @@ const ErrorMessage = styled.div`
flex: 1;
`;
const WarningMessage = styled.div`
gap: 8px;
padding: 8px;
display: flex;
margin: 8px 16px 0 16px
align-items: center;
color: ${colors.yellow[1000]};
background-color: ${colors.yellow[0]};
border-radius: 8px;
`;
const StyledLinkButton = styled(Button)`
margin: 0 -14px;
font-size: 16px;
@ -110,8 +124,14 @@ interface Props {
onClickLessHops?: () => void;
onLineageClick?: () => void;
isLineageTab?: boolean;
isViewAllMode?: boolean | false;
handleViewAllClickWarning?: () => void;
}
const getPlatformUrnFromSearchResponse = (searchResponse: SearchResultType | null | undefined) => {
return searchResponse?.facets?.find((facet) => facet.field === 'platform')?.aggregations?.[0]?.value;
};
export const EmbeddedListSearchResults = ({
page,
searchResponse,
@ -135,7 +155,10 @@ export const EmbeddedListSearchResults = ({
onClickLessHops,
onLineageClick,
isLineageTab = false,
isViewAllMode = false,
handleViewAllClickWarning,
}: Props) => {
const history = useHistory();
const showSeparateSiblings = useIsShowSeparateSiblingsEnabled();
const combinedSiblingSearchResults = combineSiblingsInSearchResults(
showSeparateSiblings,
@ -147,6 +170,28 @@ export const EmbeddedListSearchResults = ({
const totalResults = searchResponse?.total || 0;
const lastResultIndex = pageStart + pageSize > totalResults ? totalResults : pageStart + pageSize;
const platformUrn = getPlatformUrnFromSearchResponse(searchResponse);
let platform: string | null = null;
try {
platform = (combinedSiblingSearchResults?.[0]?.entity as Dataset).platform?.name;
} catch (error) {
console.error('Error getting platform from search response', error);
}
const handleSearchAllAssetsClick = () => {
handleViewAllClickWarning?.();
if (platformUrn) {
const platformFilter: FacetFilterInput = {
field: 'platform',
values: [platformUrn],
};
navigateToSearchUrl({
filters: [platformFilter],
history,
});
}
};
return (
<>
<SearchBody>
@ -180,6 +225,30 @@ export const EmbeddedListSearchResults = ({
</StyledLinkButton>
</ErrorMessage>
)}
{isViewAllMode && (
<WarningMessage>
<ExclamationCircleFilled style={{ color: colors.yellow[1000], fontSize: 16 }} />
<Text weight="bold" style={{ lineHeight: 'normal' }}>
Results may be incomplete.{' '}
{platform && (
<span
onClick={handleSearchAllAssetsClick}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleSearchAllAssetsClick();
}
}}
role="button"
tabIndex={0}
style={{ cursor: 'pointer', textDecoration: 'underline' }}
>
Search all ingested {platform} assets
</span>
)}
</Text>
</WarningMessage>
)}
{!loading && !isServerOverloadError && (
<EntitySearchResults
searchResults={combinedSiblingSearchResults || []}

View File

@ -100,7 +100,7 @@ export const SummaryTab = ({
)}
<IngestedAssetsSection>
{data?.executionRequest?.id && (
<IngestedAssets executionResult={result} id={data?.executionRequest?.id} />
<IngestedAssets executionResult={result} id={data?.executionRequest?.id} urn={urn} />
)}
</IngestedAssetsSection>
<SectionBase>

View File

@ -1,6 +1,8 @@
import React, { useMemo, useState } from 'react';
import styled from 'styled-components';
import analytics from '@app/analytics';
import { EventType } from '@app/analytics/event';
import { EmbeddedListSearchModal } from '@app/entity/shared/components/styled/search/EmbeddedListSearchModal';
import {
extractEntityTypeCountsFromFacets,
@ -107,6 +109,7 @@ const IngestionRowCount = styled(Text)`
type Props = {
id: string;
executionResult?: Maybe<Partial<ExecutionRequestResult>>;
urn: string;
};
const ENTITY_FACET_NAME = 'entity';
@ -153,12 +156,27 @@ const IngestionContents: React.FC<RenderIngestionContentsProps> = ({ items, getK
</IngestionBoxesContainer>
);
export default function IngestedAssets({ id, executionResult }: Props) {
export default function IngestedAssets({ id, executionResult, urn }: Props) {
const entityRegistry = useEntityRegistry();
// First thing to do is to search for all assets with the id as the run id!
const [showAssetSearch, setShowAssetSearch] = useState(false);
const handleViewAllClick = () => {
analytics.event({
type: EventType.IngestionViewAllClickEvent,
executionUrn: urn,
});
setShowAssetSearch(true);
};
const handleViewAllClickWarning = () => {
analytics.event({
type: EventType.IngestionViewAllClickWarningEvent,
executionUrn: urn,
});
};
// Try getting the counts via the ingestion report.
const totalEntitiesIngested = executionResult && getTotalEntitiesIngested(executionResult, entityRegistry);
const entitiesIngestedByTypeFromReport =
@ -245,11 +263,7 @@ export default function IngestedAssets({ id, executionResult }: Props) {
<Card
title={formatNumber(total)}
button={
<Button
style={{ width: '110px' }}
variant="text"
onClick={() => setShowAssetSearch(true)}
>
<Button style={{ width: '110px' }} variant="text" onClick={handleViewAllClick}>
View All
</Button>
}
@ -323,6 +337,8 @@ export default function IngestedAssets({ id, executionResult }: Props) {
unionType: UnionType.AND,
filters: [{ field: 'runId', values: [id] }],
}}
isViewAllMode
handleViewAllClickWarning={handleViewAllClickWarning}
onClose={() => setShowAssetSearch(false)}
/>
)}

View File

@ -58,6 +58,8 @@ public enum DataHubUsageEventType {
INGESTION_TEST_CONNECTION_EVENT("IngestionTestConnectionEvent"),
INGESTION_EXECUTION_RESULT_VIEWED_EVENT("IngestionExecutionResultViewedEvent"),
INGESTION_SOURCE_CONFIGURATION_IMPRESSION_EVENT("IngestionSourceConfigurationImpressionEvent"),
INGESTION_VIEW_ALL_CLICK_EVENT("IngestionViewAllClickEvent"),
INGESTION_VIEW_ALL_CLICK_WARNING_EVENT("IngestionViewAllClickWarningEvent"),
CREATE_INGESTION_SOURCE_EVENT("CreateIngestionSourceEvent"),
UPDATE_INGESTION_SOURCE_EVENT("UpdateIngestionSourceEvent"),
DELETE_INGESTION_SOURCE_EVENT("DeleteIngestionSourceEvent"),