feat(advanced-search): adding select value modal (#6026)

* adding select value modal

* responding to comments
This commit is contained in:
Gabe Lyons 2022-09-26 12:17:32 -07:00 committed by GitHub
parent 3c3ab64954
commit 60928757e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 643 additions and 61 deletions

View File

@ -149,7 +149,7 @@ export class ContainerEntity implements Entity<Container> {
};
displayName = (data: Container) => {
return data?.properties?.name || data?.urn;
return data?.properties?.name || data?.properties?.qualifiedName || data?.urn;
};
getOverridePropertiesFromEntity = (data: Container) => {

View File

@ -48,7 +48,6 @@ export default function GlossaryTermsDropdown({ urns, disabled = false, refetch
resourceUrn: urn,
}))}
operationType={operationType}
entityType={EntityType.Dataset} // TODO REMOVE
/>
)}
</>

View File

@ -47,7 +47,6 @@ export default function TagsDropdown({ urns, disabled = false, refetch }: Props)
resources={urns.map((urn) => ({
resourceUrn: urn,
}))}
entityType={EntityType.DataFlow}
operationType={operationType}
/>
)}

View File

@ -0,0 +1,189 @@
import { Button, Form, Modal, Select, Tag, Tooltip } from 'antd';
import React, { ReactNode, useRef, useState } from 'react';
import styled from 'styled-components/macro';
import { useGetSearchResultsLazyQuery } from '../../../../../../../graphql/search.generated';
import { Container, Entity, EntityType } from '../../../../../../../types.generated';
import { useEnterKeyListener } from '../../../../../../shared/useEnterKeyListener';
import { useEntityRegistry } from '../../../../../../useEntityRegistry';
type Props = {
onCloseModal: () => void;
defaultValues?: { urn: string; entity?: Entity | null }[];
onOkOverride?: (result: string[]) => void;
titleOverride?: string;
};
type SelectedContainer = {
entity?: Entity | null;
urn: string;
};
const StyleTag = styled(Tag)`
padding: 0px 7px;
margin-right: 3px;
display: flex;
justify-content: start;
align-items: center;
`;
const PreviewImage = styled.img`
max-height: 18px;
width: auto;
object-fit: contain;
background-color: transparent;
margin-right: 4px;
`;
export const ContainerSelectModal = ({ onCloseModal, defaultValues, onOkOverride, titleOverride }: Props) => {
const [containerSearch, { data: platforSearchData }] = useGetSearchResultsLazyQuery();
const entityRegistry = useEntityRegistry();
const containerSearchResults =
platforSearchData?.search?.searchResults?.map((searchResult) => searchResult.entity) || [];
const [selectedContainers, setSelectedContainers] = useState<SelectedContainer[]>(defaultValues || []);
const inputEl = useRef(null);
const onModalClose = () => {
onCloseModal();
};
const handleSearch = (text: string) => {
containerSearch({
variables: {
input: {
type: EntityType.Container,
query: text,
start: 0,
count: 5,
},
},
});
};
// Renders a search result in the select dropdown.
const renderSearchResult = (entity: Container) => {
const displayName = entityRegistry.getDisplayName(EntityType.Container, entity);
const truncatedDisplayName = displayName.length > 25 ? `${displayName.slice(0, 25)}...` : displayName;
return (
<Tooltip title={displayName}>
<PreviewImage src={entity.platform?.properties?.logoUrl || undefined} alt={entity.properties?.name} />
<span>{truncatedDisplayName}</span>
</Tooltip>
);
};
const containerSearchOptions = containerSearchResults?.map((result) => {
return (
<Select.Option value={result.urn} key={result.urn}>
{renderSearchResult(result as Container)}
</Select.Option>
);
});
const onSelectContainer = (newValue: { value: string; label: ReactNode }) => {
const newUrn = newValue.value;
if (inputEl && inputEl.current) {
(inputEl.current as any).blur();
}
const filteredContainer = containerSearchResults?.find((entity) => entity.urn === newUrn);
if (filteredContainer) {
const container = filteredContainer as Container;
setSelectedContainers([
...(selectedContainers || []),
{
entity: container,
urn: newUrn,
},
]);
}
};
const onDeselectContainer = (val) => {
setSelectedContainers(selectedContainers?.filter((container) => container.urn !== val.value));
};
const onOk = async () => {
if (!selectedContainers) {
return;
}
if (onOkOverride) {
onOkOverride(selectedContainers?.map((container) => container.urn));
}
};
// Handle the Enter press
useEnterKeyListener({
querySelectorToExecuteClick: '#setContainerButton',
});
const tagRender = (props) => {
// eslint-disable-next-line react/prop-types
const { label, closable, onClose } = props;
const onPreventMouseDown = (event) => {
event.preventDefault();
event.stopPropagation();
};
return (
<StyleTag onMouseDown={onPreventMouseDown} closable={closable} onClose={onClose}>
{label}
</StyleTag>
);
};
return (
<Modal
title={titleOverride || 'Select Container'}
visible
onCancel={onModalClose}
footer={
<>
<Button onClick={onModalClose} type="text">
Cancel
</Button>
<Button id="setContainerButton" disabled={selectedContainers?.length === 0} onClick={onOk}>
Add
</Button>
</>
}
>
<Form component={false}>
<Form.Item>
<Select
autoFocus
filterOption={false}
showSearch
mode="multiple"
defaultActiveFirstOption={false}
placeholder="Search for Containers..."
onSelect={(containerUrn: any) => onSelectContainer(containerUrn)}
onDeselect={onDeselectContainer}
onSearch={(value: string) => {
// eslint-disable-next-line react/prop-types
handleSearch(value.trim());
}}
ref={inputEl}
labelInValue
value={selectedContainers?.map((container) => ({
value: container.urn,
label: container.entity ? (
renderSearchResult(container.entity as Container)
) : (
<span>{container.urn}</span>
),
}))}
tagRender={tagRender}
>
{containerSearchOptions}
</Select>
</Form.Item>
</Form>
</Modal>
);
};

View File

@ -14,6 +14,9 @@ type Props = {
urns: string[];
onCloseModal: () => void;
refetch?: () => Promise<any>;
defaultValue?: { urn: string; entity?: Entity | null };
onOkOverride?: (result: string) => void;
titleOverride?: string;
};
type SelectedDomain = {
@ -30,10 +33,18 @@ const StyleTag = styled(Tag)`
align-items: center;
`;
export const SetDomainModal = ({ urns, onCloseModal, refetch }: Props) => {
export const SetDomainModal = ({ urns, onCloseModal, refetch, defaultValue, onOkOverride, titleOverride }: Props) => {
const entityRegistry = useEntityRegistry();
const [inputValue, setInputValue] = useState('');
const [selectedDomain, setSelectedDomain] = useState<SelectedDomain | undefined>(undefined);
const [selectedDomain, setSelectedDomain] = useState<SelectedDomain | undefined>(
defaultValue
? {
displayName: entityRegistry.getDisplayName(EntityType.Domain, defaultValue?.entity),
type: EntityType.Domain,
urn: defaultValue?.urn,
}
: undefined,
);
const [domainSearch, { data: domainSearchData }] = useGetSearchResultsLazyQuery();
const domainSearchResults =
domainSearchData?.search?.searchResults?.map((searchResult) => searchResult.entity) || [];
@ -100,6 +111,12 @@ export const SetDomainModal = ({ urns, onCloseModal, refetch }: Props) => {
if (!selectedDomain) {
return;
}
if (onOkOverride) {
onOkOverride(selectedDomain?.urn);
return;
}
batchSetDomainMutation({
variables: {
input: {
@ -149,7 +166,7 @@ export const SetDomainModal = ({ urns, onCloseModal, refetch }: Props) => {
return (
<Modal
title="Set Domain"
title={titleOverride || 'Set Domain'}
visible
onCancel={onModalClose}
footer={

View File

@ -41,12 +41,18 @@ type Props = {
onCloseModal: () => void;
refetch?: () => Promise<any>;
entityType?: EntityType; // Only used for tracking events
onOkOverride?: (result: SelectedOwner[]) => void;
title?: string;
defaultValues?: { urn: string; entity?: Entity | null }[];
};
// value: {ownerUrn: string, ownerEntityType: EntityType}
type SelectedOwner = {
label: string;
value;
label: string | React.ReactNode;
value: {
ownerUrn: string;
ownerEntityType: EntityType;
};
};
export const EditOwnersModal = ({
@ -57,13 +63,50 @@ export const EditOwnersModal = ({
onCloseModal,
refetch,
entityType,
onOkOverride,
title,
defaultValues,
}: Props) => {
const entityRegistry = useEntityRegistry();
// Renders a search result in the select dropdown.
const renderSearchResult = (entity: Entity) => {
const avatarUrl =
(entity.type === EntityType.CorpUser && (entity as CorpUser).editableProperties?.pictureLink) || undefined;
const displayName = entityRegistry.getDisplayName(entity.type, entity);
return (
<Select.Option value={entity.urn} key={entity.urn}>
<OwnerLabel name={displayName} avatarUrl={avatarUrl} type={entity.type} />
</Select.Option>
);
};
const renderDropdownResult = (entity: Entity) => {
const avatarUrl =
entity.type === EntityType.CorpUser
? (entity as CorpUser).editableProperties?.pictureLink || undefined
: undefined;
const displayName = entityRegistry.getDisplayName(entity.type, entity);
return <OwnerLabel name={displayName} avatarUrl={avatarUrl} type={entity.type} />;
};
const defaultValuesToSelectedOwners = (vals: { urn: string; entity?: Entity | null }[]): SelectedOwner[] => {
return vals.map((defaultValue) => ({
label: defaultValue.entity ? renderDropdownResult(defaultValue.entity) : defaultValue.urn,
value: {
ownerUrn: defaultValue.urn,
ownerEntityType: defaultValue.entity?.type || EntityType.CorpUser,
},
}));
};
const [inputValue, setInputValue] = useState('');
const [batchAddOwnersMutation] = useBatchAddOwnersMutation();
const [batchRemoveOwnersMutation] = useBatchRemoveOwnersMutation();
const ownershipTypes = OWNERSHIP_DISPLAY_TYPES;
const [selectedOwners, setSelectedOwners] = useState<SelectedOwner[]>([]);
const [selectedOwners, setSelectedOwners] = useState<SelectedOwner[]>(
defaultValuesToSelectedOwners(defaultValues || []),
);
const [selectedOwnerType, setSelectedOwnerType] = useState<OwnershipType>(defaultOwnerType || OwnershipType.None);
// User and group dropdown search results!
@ -101,20 +144,6 @@ export const EditOwnersModal = ({
handleSearch(EntityType.CorpGroup, text, groupSearch);
};
// Renders a search result in the select dropdown.
const renderSearchResult = (entity: Entity) => {
const avatarUrl =
entity.type === EntityType.CorpUser
? (entity as CorpUser).editableProperties?.pictureLink || undefined
: undefined;
const displayName = entityRegistry.getDisplayName(entity.type, entity);
return (
<Select.Option value={entity.urn} key={entity.urn}>
<OwnerLabel name={displayName} avatarUrl={avatarUrl} type={entity.type} />
</Select.Option>
);
};
const ownerResult = !inputValue || inputValue.length === 0 ? recommendedData : combinedSearchResults;
const ownerSearchOptions = ownerResult?.map((result) => {
@ -149,7 +178,7 @@ export const EditOwnersModal = ({
label: selectedValue.value,
value: {
ownerUrn: selectedValue.value,
ownerEntityType,
ownerEntityType: ownerEntityType as unknown as EntityType,
},
},
];
@ -160,7 +189,9 @@ export const EditOwnersModal = ({
// When a owner search result is deselected, remove the Owner
const onDeselectOwner = (selectedValue: { key: string; label: React.ReactNode; value: string }) => {
setInputValue('');
const newValues = selectedOwners.filter((owner) => owner.label !== selectedValue.value);
const newValues = selectedOwners.filter(
(owner) => owner.label !== selectedValue.value && owner.value.ownerUrn !== selectedValue.value,
);
setSelectedOwners(newValues);
};
@ -251,6 +282,12 @@ export const EditOwnersModal = ({
if (selectedOwners.length === 0) {
return;
}
if (onOkOverride) {
onOkOverride(selectedOwners);
return;
}
const inputs = selectedOwners.map((selectedActor) => {
const input = {
ownerUrn: selectedActor.value.ownerUrn,
@ -273,7 +310,7 @@ export const EditOwnersModal = ({
return (
<Modal
title={`${operationType === OperationType.ADD ? 'Add' : 'Remove'} Owners`}
title={title || `${operationType === OperationType.ADD ? 'Add' : 'Remove'} Owners`}
visible
onCancel={onModalClose}
keyboard
@ -312,7 +349,12 @@ export const EditOwnersModal = ({
}}
tagRender={tagRender}
onBlur={handleBlur}
value={selectedOwners}
value={selectedOwners as any}
defaultValue={selectedOwners.map((owner) => ({
key: owner.value.ownerUrn,
value: owner.value.ownerUrn,
label: owner.label,
}))}
>
{ownerSearchOptions}
</SelectInput>

View File

@ -8,7 +8,7 @@ import { useEnterKeyListener } from '../../../../../../shared/useEnterKeyListene
type Props = {
onCloseModal: () => void;
defaultValues?: { urn: string; entity?: Entity | null }[];
onOkOverride?: (result: string[]) => void;
onOk?: (result: string[]) => void;
titleOverride?: string;
};
@ -33,7 +33,7 @@ const PreviewImage = styled.img`
margin-right: 4px;
`;
export const SelectPlatformModal = ({ onCloseModal, defaultValues, onOkOverride, titleOverride }: Props) => {
export const SelectPlatformModal = ({ onCloseModal, defaultValues, onOk, titleOverride }: Props) => {
const [platformSearch, { data: platforSearchData }] = useGetSearchResultsLazyQuery();
const platformSearchResults =
platforSearchData?.search?.searchResults?.map((searchResult) => searchResult.entity) || [];
@ -102,16 +102,16 @@ export const SelectPlatformModal = ({ onCloseModal, defaultValues, onOkOverride,
};
const onDeselectPlatform = (val) => {
setSelectedPlatforms(selectedPlatforms?.filter((platform) => platform.urn !== val));
setSelectedPlatforms(selectedPlatforms?.filter((platform) => platform.urn !== val.value));
};
const onOk = async () => {
const handleOk = async () => {
if (!selectedPlatforms) {
return;
}
if (onOkOverride) {
onOkOverride(selectedPlatforms?.map((platform) => platform.urn));
if (onOk) {
onOk(selectedPlatforms?.map((platform) => platform.urn));
}
};
@ -144,7 +144,7 @@ export const SelectPlatformModal = ({ onCloseModal, defaultValues, onOkOverride,
<Button onClick={onModalClose} type="text">
Cancel
</Button>
<Button id="setPlatformButton" disabled={selectedPlatforms?.length === 0} onClick={onOk}>
<Button id="setPlatformButton" disabled={selectedPlatforms?.length === 0} onClick={handleOk}>
Add
</Button>
</>

View File

@ -0,0 +1,211 @@
import React from 'react';
import { FacetMetadata, EntityType } from '../../types.generated';
import { ContainerSelectModal } from '../entity/shared/containers/profile/sidebar/Container/ContainerSelectModal';
import { SetDomainModal } from '../entity/shared/containers/profile/sidebar/Domain/SetDomainModal';
import { EditOwnersModal } from '../entity/shared/containers/profile/sidebar/Ownership/EditOwnersModal';
import { SelectPlatformModal } from '../entity/shared/containers/profile/sidebar/Platform/SelectPlatformModal';
import EditTagTermsModal from '../shared/tags/AddTagsTermsModal';
import { ChooseEntityTypeModal } from './ChooseEntityTypeModal';
import { EditTextModal } from './EditTextModal';
type Props = {
facet?: FacetMetadata | null;
filterField: string;
onSelect: (values: string[]) => void;
onCloseModal: () => void;
initialValues?: string[];
};
export const AdvancedFilterSelectValueModal = ({
filterField,
onSelect,
onCloseModal,
initialValues,
facet,
}: Props) => {
if (filterField === 'owners') {
return (
<EditOwnersModal
title="Select Owners"
urns={[]}
defaultValues={initialValues?.map((urn) => ({
urn,
entity: facet?.aggregations.find((aggregation) => aggregation.value === urn)?.entity,
}))}
onCloseModal={onCloseModal}
hideOwnerType
onOkOverride={(owners) => {
onSelect(owners.map((owner) => owner.value.ownerUrn));
onCloseModal();
}}
/>
);
}
if (filterField === 'domains') {
return (
<SetDomainModal
titleOverride="Select Domain"
urns={[]}
defaultValue={
initialValues?.map((urn) => ({
urn,
entity: facet?.aggregations.find((aggregation) => aggregation.value === urn)?.entity,
}))?.[0]
}
onCloseModal={onCloseModal}
onOkOverride={(domainUrn) => {
onSelect([domainUrn]);
onCloseModal();
}}
/>
);
}
if (filterField === 'container') {
return (
<ContainerSelectModal
titleOverride="Select Container"
defaultValues={initialValues?.map((urn) => ({
urn,
entity: facet?.aggregations.find((aggregation) => aggregation.value === urn)?.entity,
}))}
onCloseModal={onCloseModal}
onOkOverride={(containerUrns) => {
onSelect(containerUrns);
onCloseModal();
}}
/>
);
}
if (filterField === 'platform') {
return (
<SelectPlatformModal
defaultValues={initialValues?.map((urn) => ({
urn,
entity: facet?.aggregations.find((aggregation) => aggregation.value === urn)?.entity,
}))}
titleOverride="Select Platform"
onCloseModal={onCloseModal}
onOk={(platformUrns) => {
onSelect(platformUrns);
onCloseModal();
}}
/>
);
}
if (filterField === 'fieldPaths') {
return (
<EditTextModal
title="Filter by Column"
defaultValue={initialValues?.[0]}
onCloseModal={onCloseModal}
onOk={(newValue) => {
onSelect([newValue]);
onCloseModal();
}}
/>
);
}
if (filterField === 'description' || filterField === 'fieldDescriptions') {
return (
<EditTextModal
title="Filter by Description"
defaultValue={initialValues?.[0]}
onCloseModal={onCloseModal}
onOk={(newValue) => {
onSelect([newValue]);
onCloseModal();
}}
/>
);
}
if (filterField === 'origin') {
return (
<EditTextModal
title="Filter by Environment"
defaultValue={initialValues?.[0]}
onCloseModal={onCloseModal}
onOk={(newValue) => {
onSelect([newValue]);
onCloseModal();
}}
/>
);
}
if (filterField === 'typeNames') {
return (
<EditTextModal
title="Filter by Subtype"
defaultValue={initialValues?.[0]}
onCloseModal={onCloseModal}
onOk={(newValue) => {
onSelect([newValue]);
onCloseModal();
}}
/>
);
}
if (filterField === 'entity') {
return (
<ChooseEntityTypeModal
title="Filter by Entity Type"
defaultValue={initialValues?.[0]}
onCloseModal={onCloseModal}
onOk={(newValue) => {
onSelect([newValue]);
onCloseModal();
}}
/>
);
}
if (filterField === 'tags' || filterField === 'fieldTags') {
return (
<EditTagTermsModal
resources={[]}
type={EntityType.Tag}
visible
onCloseModal={onCloseModal}
onOkOverride={(urns) => {
onSelect(urns);
onCloseModal();
}}
defaultValues={initialValues?.map((urn) => ({
urn,
entity: facet?.aggregations.find((aggregation) => aggregation.value === urn)?.entity,
}))}
/>
);
}
if (filterField === 'removed') {
onSelect(['true']);
onCloseModal();
}
if (filterField === 'glossaryTerms' || filterField === 'fieldGlossaryTerms') {
return (
<EditTagTermsModal
resources={[]}
type={EntityType.GlossaryTerm}
visible
onCloseModal={onCloseModal}
onOkOverride={(urns) => {
onSelect(urns);
onCloseModal();
}}
defaultValues={initialValues?.map((urn) => ({
urn,
entity: facet?.aggregations.find((aggregation) => aggregation.value === urn)?.entity,
}))}
/>
);
}
return null;
};

View File

@ -0,0 +1,48 @@
import { Button, Modal, Select } from 'antd';
import React, { useState } from 'react';
import { useEntityRegistry } from '../useEntityRegistry';
type Props = {
onCloseModal: () => void;
onOk?: (result: string) => void;
title?: string;
defaultValue?: string;
};
const { Option } = Select;
export const ChooseEntityTypeModal = ({ defaultValue, onCloseModal, onOk, title }: Props) => {
const entityRegistry = useEntityRegistry();
const entityTypes = entityRegistry.getSearchEntityTypes();
const [stagedValue, setStagedValue] = useState(defaultValue || entityTypes[0]);
return (
<Modal
title={title}
visible
onCancel={onCloseModal}
keyboard
footer={
<>
<Button onClick={onCloseModal} type="text">
Cancel
</Button>
<Button disabled={stagedValue.length === 0} onClick={() => onOk?.(stagedValue)}>
Done
</Button>
</>
}
>
<Select
onChange={(newValue) => setStagedValue(newValue)}
value={stagedValue}
dropdownMatchSelectWidth={false}
>
{entityTypes.map((type) => (
<Option value={type}>{entityRegistry.getCollectionName(type)}</Option>
))}
</Select>
</Modal>
);
};

View File

@ -0,0 +1,33 @@
import { Button, Input, Modal } from 'antd';
import React, { useState } from 'react';
type Props = {
onCloseModal: () => void;
onOk?: (result: string) => void;
title?: string;
defaultValue?: string;
};
export const EditTextModal = ({ defaultValue, onCloseModal, onOk, title }: Props) => {
const [stagedValue, setStagedValue] = useState(defaultValue || '');
return (
<Modal
title={title}
visible
onCancel={onCloseModal}
keyboard
footer={
<>
<Button onClick={onCloseModal} type="text">
Cancel
</Button>
<Button disabled={stagedValue.trim().length === 0} onClick={() => onOk?.(stagedValue)}>
Done
</Button>
</>
}
>
<Input onChange={(e) => setStagedValue(e.target.value)} value={stagedValue} />
</Modal>
);
};

View File

@ -12,13 +12,12 @@ import {
useBatchRemoveTermsMutation,
} from '../../../graphql/mutations.generated';
import { useEnterKeyListener } from '../useEnterKeyListener';
import TermLabel from '../TermLabel';
import TagLabel from '../TagLabel';
import GlossaryBrowser from '../../glossary/GlossaryBrowser/GlossaryBrowser';
import ClickOutside from '../ClickOutside';
import { useEntityRegistry } from '../../useEntityRegistry';
import { useGetRecommendations } from '../recommendation';
import { FORBIDDEN_URN_CHARS_REGEX } from '../../entity/shared/utils';
import { TagTermLabel } from './TagTermLabel';
export enum OperationType {
ADD,
@ -29,10 +28,10 @@ type EditTagsModalProps = {
visible: boolean;
onCloseModal: () => void;
resources: ResourceRefInput[];
// eslint-disable-next-line
entityType: EntityType;
type?: EntityType;
operationType?: OperationType;
defaultValues?: { urn: string; entity?: Entity | null }[];
onOkOverride?: (result: string[]) => void;
};
const TagSelect = styled(Select)`
@ -74,20 +73,37 @@ const isValidTagName = (tagName: string) => {
return tagName && tagName.length > 0 && !FORBIDDEN_URN_CHARS_REGEX.test(tagName);
};
const defaultValuesToSelectedValue = (defaultValues?: { urn: string; entity?: Entity | null }[]): any[] => {
return (
defaultValues?.map((defaultValue) => ({
urn: defaultValue.urn,
component: <TagTermLabel entity={defaultValue.entity} />,
})) || []
);
};
export default function EditTagTermsModal({
visible,
onCloseModal,
resources,
type = EntityType.Tag,
operationType = OperationType.ADD,
defaultValues = [],
onOkOverride,
}: EditTagsModalProps) {
const entityRegistry = useEntityRegistry();
const [inputValue, setInputValue] = useState('');
const [showCreateModal, setShowCreateModal] = useState(false);
const [disableAction, setDisableAction] = useState(false);
const [urns, setUrns] = useState<string[]>([]);
const [selectedTerms, setSelectedTerms] = useState<any[]>([]);
const [selectedTags, setSelectedTags] = useState<any[]>([]);
const [urns, setUrns] = useState<string[]>(defaultValues.map((defaultValue) => defaultValue.urn));
const [selectedTerms, setSelectedTerms] = useState<any[]>(
type === EntityType.GlossaryTerm ? defaultValuesToSelectedValue(defaultValues) : [],
);
const [selectedTags, setSelectedTags] = useState<any[]>(
type === EntityType.Tag ? defaultValuesToSelectedValue(defaultValues) : [],
);
const [isFocusedOnInput, setIsFocusedOnInput] = useState(false);
const [batchAddTagsMutation] = useBatchAddTagsMutation();
@ -118,16 +134,7 @@ export default function EditTagTermsModal({
const renderSearchResult = (entity: Entity) => {
const displayName =
entity.type === EntityType.Tag ? (entity as Tag).name : entityRegistry.getDisplayName(entity.type, entity);
const tagOrTermComponent =
entity.type === EntityType.Tag ? (
<TagLabel
name={displayName}
colorHash={(entity as Tag).urn}
color={(entity as Tag).properties?.colorHex}
/>
) : (
<TermLabel name={displayName} />
);
const tagOrTermComponent = <TagTermLabel entity={entity} />;
return (
<Select.Option value={entity.urn} key={entity.urn} name={displayName}>
{tagOrTermComponent}
@ -209,18 +216,15 @@ export default function EditTagTermsModal({
const selectedSearchOption = tagSearchOptions?.find((option) => option.props.value === urn);
const selectedTagOption = tagResult?.find((tag) => tag.urn === urn);
setUrns(newUrns);
setSelectedTerms([...selectedTerms, { urn, component: <TermLabel name={selectedSearchOption?.props.name} /> }]);
setSelectedTerms([
...selectedTerms,
{ urn, component: <TagTermLabel termName={selectedSearchOption?.props.name} /> },
]);
setSelectedTags([
...selectedTags,
{
urn,
component: (
<TagLabel
name={selectedSearchOption?.props.name}
colorHash={(selectedTagOption as Tag).urn}
color={(selectedTagOption as Tag).properties?.colorHex}
/>
),
component: <TagTermLabel entity={selectedTagOption} />,
},
]);
if (inputEl && inputEl.current) {
@ -368,6 +372,11 @@ export default function EditTagTermsModal({
// Function to handle the modal action's
const onOk = () => {
if (onOkOverride) {
onOkOverride(urns);
return;
}
if (!resources) {
onCloseModal();
return;
@ -385,7 +394,7 @@ export default function EditTagTermsModal({
setIsFocusedOnInput(false);
const newUrns = [...(urns || []), urn];
setUrns(newUrns);
setSelectedTerms([...selectedTerms, { urn, component: <TermLabel name={displayName} /> }]);
setSelectedTerms([...selectedTerms, { urn, component: <TagTermLabel termName={displayName} /> }]);
}
function clearInput() {

View File

@ -371,7 +371,6 @@ export default function TagTermGroup({
subResourceType: entitySubresource ? SubResourceType.DatasetField : null,
},
]}
entityType={entityType}
/>
)}
</>

View File

@ -0,0 +1,36 @@
import React from 'react';
import { Entity, EntityType, Tag } from '../../../types.generated';
import { useEntityRegistry } from '../../useEntityRegistry';
import TagLabel from '../TagLabel';
import TermLabel from '../TermLabel';
type Props = {
// default behavior is to accept an entity and render label based on that
entity?: Entity | null;
// if no entity is available, for terms just a name may be provided
termName?: string;
};
export const TagTermLabel = ({ entity, termName }: Props) => {
const entityRegistry = useEntityRegistry();
if (entity?.type === EntityType.Tag) {
return (
<TagLabel
name={entityRegistry.getDisplayName(entity.type, entity)}
colorHash={(entity as Tag).urn}
color={(entity as Tag).properties?.colorHex}
/>
);
}
if (entity?.type === EntityType.GlossaryTerm) {
return <TermLabel name={entityRegistry.getDisplayName(entity.type, entity)} />;
}
if (termName) {
return <TermLabel name={termName} />;
}
return null;
};