mirror of
https://github.com/datahub-project/datahub.git
synced 2025-12-28 10:28:22 +00:00
feat(ui): include parent term groups, domains in glossary, domain dropdown (#9715)
This commit is contained in:
parent
2bb4b73f98
commit
dc16c73937
@ -10,11 +10,19 @@ import { BrowserWrapper } from '../../../shared/tags/AddTagsTermsModal';
|
||||
import TermLabel from '../../../shared/TermLabel';
|
||||
import { useEntityRegistry } from '../../../useEntityRegistry';
|
||||
import { useEntityData, useRefetch } from '../../shared/EntityContext';
|
||||
import ParentEntities from '../../../search/filters/ParentEntities';
|
||||
import { getParentEntities } from '../../../search/filters/utils';
|
||||
|
||||
const StyledSelect = styled(Select)`
|
||||
width: 480px;
|
||||
`;
|
||||
|
||||
const SearchResultContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
onClose: () => void;
|
||||
relationshipType: TermRelationshipType;
|
||||
@ -68,7 +76,10 @@ function AddRelatedTermsModal(props: Props) {
|
||||
|
||||
return (
|
||||
<Select.Option value={result.entity.urn} key={result.entity.urn} name={displayName}>
|
||||
<TermLabel name={displayName} />
|
||||
<SearchResultContainer>
|
||||
<ParentEntities parentEntities={getParentEntities(result.entity) || []} />
|
||||
<TermLabel name={displayName} />
|
||||
</SearchResultContainer>
|
||||
</Select.Option>
|
||||
);
|
||||
});
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Select } from 'antd';
|
||||
import styled from 'styled-components';
|
||||
import { EntityType, GlossaryNode, SearchResult } from '../../../../types.generated';
|
||||
import { useEntityRegistry } from '../../../useEntityRegistry';
|
||||
import { useEntityData } from '../EntityContext';
|
||||
@ -7,6 +8,14 @@ import ClickOutside from '../../../shared/ClickOutside';
|
||||
import GlossaryBrowser from '../../../glossary/GlossaryBrowser/GlossaryBrowser';
|
||||
import { BrowserWrapper } from '../../../shared/tags/AddTagsTermsModal';
|
||||
import useParentSelector from './useParentSelector';
|
||||
import ParentEntities from '../../../search/filters/ParentEntities';
|
||||
import { getParentGlossary } from '../../../glossary/utils';
|
||||
|
||||
const SearchResultContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
// filter out entity itself and its children
|
||||
export function filterResultsForMove(entity: GlossaryNode, entityUrn: string) {
|
||||
@ -46,10 +55,9 @@ function NodeParentSelect(props: Props) {
|
||||
setSelectedParentUrn,
|
||||
});
|
||||
|
||||
let nodeSearchResults: SearchResult[] = [];
|
||||
if (isMoving) {
|
||||
nodeSearchResults = searchResults.filter((r) => filterResultsForMove(r.entity as GlossaryNode, entityDataUrn));
|
||||
}
|
||||
const nodeSearchResults: SearchResult[] = searchResults.filter((r) =>
|
||||
filterResultsForMove(r.entity as GlossaryNode, entityDataUrn),
|
||||
);
|
||||
|
||||
const isShowingGlossaryBrowser = !searchQuery && isFocusedOnInput;
|
||||
const shouldHideSelf = isMoving && entityType === EntityType.GlossaryNode;
|
||||
@ -70,7 +78,10 @@ function NodeParentSelect(props: Props) {
|
||||
>
|
||||
{nodeSearchResults?.map((result) => (
|
||||
<Select.Option key={result?.entity?.urn} value={result.entity.urn}>
|
||||
{entityRegistry.getDisplayName(result.entity.type, result.entity)}
|
||||
<SearchResultContainer>
|
||||
<ParentEntities parentEntities={getParentGlossary(result.entity, entityRegistry)} />
|
||||
{entityRegistry.getDisplayName(result.entity.type, result.entity)}
|
||||
</SearchResultContainer>
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
@ -16,6 +16,8 @@ import DomainNavigator from '../../../../../../domain/nestedDomains/domainNaviga
|
||||
import ClickOutside from '../../../../../../shared/ClickOutside';
|
||||
import { ANTD_GRAY } from '../../../../constants';
|
||||
import { getModalDomContainer } from '../../../../../../../utils/focus';
|
||||
import ParentEntities from '../../../../../../search/filters/ParentEntities';
|
||||
import { getParentDomains } from '../../../../../../domain/utils';
|
||||
|
||||
type Props = {
|
||||
urns: string[];
|
||||
@ -44,6 +46,12 @@ const LoadingWrapper = styled.div`
|
||||
}
|
||||
`;
|
||||
|
||||
const SearchResultContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
export const SetDomainModal = ({ urns, onCloseModal, refetch, defaultValue, onOkOverride, titleOverride }: Props) => {
|
||||
const entityRegistry = useEntityRegistry();
|
||||
const [isFocusedOnInput, setIsFocusedOnInput] = useState(false);
|
||||
@ -88,7 +96,10 @@ export const SetDomainModal = ({ urns, onCloseModal, refetch, defaultValue, onOk
|
||||
const displayName = entityRegistry.getDisplayName(entity.type, entity);
|
||||
return (
|
||||
<Select.Option value={entity.urn} key={entity.urn}>
|
||||
<DomainLabel name={displayName} />
|
||||
<SearchResultContainer>
|
||||
<ParentEntities parentEntities={getParentDomains(entity, entityRegistry)} />
|
||||
<DomainLabel name={displayName} />
|
||||
</SearchResultContainer>
|
||||
</Select.Option>
|
||||
);
|
||||
};
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
// Create a new component called SearchResultItem.js
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Highlight from 'react-highlighter';
|
||||
import styled from 'styled-components/macro';
|
||||
import { Entity } from '../../types.generated';
|
||||
import { IconStyleType } from '../entity/Entity';
|
||||
import { ANTD_GRAY } from '../entity/shared/constants';
|
||||
import ParentEntities from '../search/filters/ParentEntities';
|
||||
import { getParentGlossary } from './utils';
|
||||
import EntityRegistry from '../entity/EntityRegistry';
|
||||
|
||||
type Props = {
|
||||
entity: Entity;
|
||||
entityRegistry: EntityRegistry;
|
||||
query: string;
|
||||
onResultClick: () => void;
|
||||
};
|
||||
|
||||
const SearchResult = styled(Link)`
|
||||
color: #262626;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
height: 100%;
|
||||
padding: 6px 8px;
|
||||
width: 100%;
|
||||
&:hover {
|
||||
background-color: ${ANTD_GRAY[3]};
|
||||
color: #262626;
|
||||
}
|
||||
`;
|
||||
|
||||
const IconWrapper = styled.span``;
|
||||
|
||||
const highlightMatchStyle = {
|
||||
fontWeight: 'bold',
|
||||
background: 'none',
|
||||
padding: 0,
|
||||
};
|
||||
|
||||
function GlossarySearchResultItem({ entity, entityRegistry, query, onResultClick }: Props) {
|
||||
return (
|
||||
<SearchResult to={entityRegistry.getEntityUrl(entity.type, entity.urn)} onClick={onResultClick}>
|
||||
<IconWrapper>{entityRegistry.getIcon(entity.type, 12, IconStyleType.TAB_VIEW)}</IconWrapper>
|
||||
<div>
|
||||
<ParentEntities parentEntities={getParentGlossary(entity, entityRegistry)} />
|
||||
<Highlight matchStyle={highlightMatchStyle} search={query}>
|
||||
{entityRegistry.getDisplayName(entity.type, entity)}
|
||||
</Highlight>
|
||||
</div>
|
||||
</SearchResult>
|
||||
);
|
||||
}
|
||||
|
||||
export default GlossarySearchResultItem;
|
||||
@ -1,13 +1,12 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styled from 'styled-components/macro';
|
||||
import { useGetSearchResultsForMultipleQuery } from '../../graphql/search.generated';
|
||||
import { EntityType } from '../../types.generated';
|
||||
import { IconStyleType } from '../entity/Entity';
|
||||
import { ANTD_GRAY } from '../entity/shared/constants';
|
||||
import { SearchBar } from '../search/SearchBar';
|
||||
import ClickOutside from '../shared/ClickOutside';
|
||||
import { useEntityRegistry } from '../useEntityRegistry';
|
||||
import GloassarySearchResultItem from './GloassarySearchResultItem';
|
||||
|
||||
const GlossarySearchWrapper = styled.div`
|
||||
position: relative;
|
||||
@ -28,20 +27,10 @@ const ResultsWrapper = styled.div`
|
||||
top: 45px;
|
||||
`;
|
||||
|
||||
const SearchResult = styled(Link)`
|
||||
color: #262626;
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
padding: 6px 8px;
|
||||
width: 100%;
|
||||
&:hover {
|
||||
background-color: ${ANTD_GRAY[3]};
|
||||
color: #262626;
|
||||
}
|
||||
`;
|
||||
|
||||
const IconWrapper = styled.span`
|
||||
margin-right: 8px;
|
||||
const TermNodeName = styled.span`
|
||||
margin-top: 12px;
|
||||
color: ${ANTD_GRAY[8]};
|
||||
font-weight: bold;
|
||||
`;
|
||||
|
||||
function GlossarySearch() {
|
||||
@ -63,6 +52,21 @@ function GlossarySearch() {
|
||||
|
||||
const searchResults = data?.searchAcrossEntities?.searchResults;
|
||||
|
||||
const renderSearchResults = () => (
|
||||
<ResultsWrapper>
|
||||
<TermNodeName>Glossary Terms</TermNodeName>
|
||||
{searchResults?.map((result) => (
|
||||
<GloassarySearchResultItem
|
||||
key={result.entity.urn}
|
||||
entity={result.entity}
|
||||
entityRegistry={entityRegistry}
|
||||
query={query}
|
||||
onResultClick={() => setIsSearchBarFocused(false)}
|
||||
/>
|
||||
))}
|
||||
</ResultsWrapper>
|
||||
);
|
||||
|
||||
return (
|
||||
<GlossarySearchWrapper>
|
||||
<ClickOutside onClickOutside={() => setIsSearchBarFocused(false)}>
|
||||
@ -84,23 +88,8 @@ function GlossarySearch() {
|
||||
entityRegistry={entityRegistry}
|
||||
onFocus={() => setIsSearchBarFocused(true)}
|
||||
/>
|
||||
{isSearchBarFocused && searchResults && !!searchResults.length && (
|
||||
<ResultsWrapper>
|
||||
{searchResults.map((result) => {
|
||||
return (
|
||||
<SearchResult
|
||||
to={`${entityRegistry.getEntityUrl(result.entity.type, result.entity.urn)}`}
|
||||
onClick={() => setIsSearchBarFocused(false)}
|
||||
>
|
||||
<IconWrapper>
|
||||
{entityRegistry.getIcon(result.entity.type, 12, IconStyleType.ACCENT)}
|
||||
</IconWrapper>
|
||||
{entityRegistry.getDisplayName(result.entity.type, result.entity)}
|
||||
</SearchResult>
|
||||
);
|
||||
})}
|
||||
</ResultsWrapper>
|
||||
)}
|
||||
{isSearchBarFocused && searchResults && !!searchResults.length && renderSearchResults()}
|
||||
|
||||
</ClickOutside>
|
||||
</GlossarySearchWrapper>
|
||||
);
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { EntityType } from '../../types.generated';
|
||||
import { Entity, EntityType } from '../../types.generated';
|
||||
import EntityRegistry from '../entity/EntityRegistry';
|
||||
import { GenericEntityProperties } from '../entity/shared/types';
|
||||
|
||||
export const ROOT_NODES = 'rootNodes';
|
||||
@ -25,3 +26,8 @@ export function updateGlossarySidebar(
|
||||
) {
|
||||
setUrnsToUpdate([...urnsToUpdate, ...parentNodesToUpdate]);
|
||||
}
|
||||
|
||||
export function getParentGlossary<T extends Entity>(node: T, entityRegistry: EntityRegistry) {
|
||||
const props = entityRegistry.getGenericEntityProperties(EntityType.GlossaryNode, node);
|
||||
return props?.parentNodes?.nodes ?? [];
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ const DomainContainerWrapper = styled.div`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
padding: 2px;
|
||||
`;
|
||||
|
||||
const DomainContentWrapper = styled.div`
|
||||
|
||||
@ -20,6 +20,8 @@ import { FORBIDDEN_URN_CHARS_REGEX, handleBatchError } from '../../entity/shared
|
||||
import { TagTermLabel } from './TagTermLabel';
|
||||
import { ENTER_KEY_CODE } from '../constants';
|
||||
import { getModalDomContainer } from '../../../utils/focus';
|
||||
import ParentEntities from '../../search/filters/ParentEntities';
|
||||
import { getParentEntities } from '../../search/filters/utils';
|
||||
|
||||
export enum OperationType {
|
||||
ADD,
|
||||
@ -69,6 +71,12 @@ export const BrowserWrapper = styled.div<{ isHidden: boolean; width?: string; ma
|
||||
`}
|
||||
`;
|
||||
|
||||
const SearchResultContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
const CREATE_TAG_VALUE = '____reserved____.createTagValue';
|
||||
|
||||
const isValidTagName = (tagName: string) => {
|
||||
@ -139,7 +147,10 @@ export default function EditTagTermsModal({
|
||||
const tagOrTermComponent = <TagTermLabel entity={entity} />;
|
||||
return (
|
||||
<Select.Option data-testid="tag-term-option" value={entity.urn} key={entity.urn} name={displayName}>
|
||||
{tagOrTermComponent}
|
||||
<SearchResultContainer>
|
||||
<ParentEntities parentEntities={getParentEntities(entity) || []} />
|
||||
{tagOrTermComponent}
|
||||
</SearchResultContainer>
|
||||
</Select.Option>
|
||||
);
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user