mirror of
https://github.com/datahub-project/datahub.git
synced 2025-11-02 19:58:59 +00:00
fix(ui): add warning for view all modal (#14702)
This commit is contained in:
parent
9105241bfd
commit
3e1e9fcf34
@ -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;
|
||||
|
||||
@ -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>
|
||||
);
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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 || []}
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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)}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -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"),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user