From ce46dc1111cf7c7182aadcc9da4191b19e14b473 Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Fri, 10 Jun 2022 15:14:21 +0530 Subject: [PATCH 01/28] Added suggestion to tags select input --- .../src/app/shared/tags/AddTagsTermsModal.tsx | 43 +++++++++- .../src/app/shared/tags/TagBrowser.tsx | 80 +++++++++++++++++++ 2 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 datahub-web-react/src/app/shared/tags/TagBrowser.tsx diff --git a/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx b/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx index 00479f3a0514e..4a02e236992f3 100644 --- a/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx +++ b/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx @@ -5,7 +5,6 @@ import styled from 'styled-components'; import { useGetSearchResultsLazyQuery } from '../../../graphql/search.generated'; import { EntityType, SubResourceType, SearchResult, Tag } from '../../../types.generated'; import CreateTagModal from './CreateTagModal'; -import { useEntityRegistry } from '../../useEntityRegistry'; import { useAddTagsMutation, useAddTermsMutation } from '../../../graphql/mutations.generated'; import analytics, { EventType, EntityActionType } from '../../analytics'; import { useEnterKeyListener } from '../useEnterKeyListener'; @@ -13,6 +12,8 @@ import TermLabel from '../TermLabel'; import TagLabel from '../TagLabel'; import GlossaryBrowser from '../../glossary/GlossaryBrowser/GlossaryBrowser'; import ClickOutside from '../ClickOutside'; +import { useEntityRegistry } from '../../useEntityRegistry'; +import TagBrowser from './TagBrowser'; type AddTagsModalProps = { visible: boolean; @@ -61,6 +62,7 @@ export default function AddTagsTermsModal({ const [disableAdd, setDisableAdd] = useState(false); const [urns, setUrns] = useState([]); const [selectedTerms, setSelectedTerms] = useState([]); + const [selectedTags, setSelectedTags] = useState([]); const [isFocusedOnInput, setIsFocusedOnInput] = useState(false); const [addTagsMutation] = useAddTagsMutation(); @@ -125,13 +127,15 @@ export default function AddTagsTermsModal({ const tagRender = (props) => { // eslint-disable-next-line react/prop-types - const { label, closable, onClose, value } = props; + const { closable, onClose, value } = props; const onPreventMouseDown = (event) => { event.preventDefault(); event.stopPropagation(); }; const selectedItem = - type === EntityType.GlossaryTerm ? selectedTerms.find((term) => term.urn === value).component : label; + type === EntityType.GlossaryTerm + ? selectedTerms.find((term) => term.urn === value).component + : selectedTags.find((term) => term.urn === value).component; return ( option.props.value === urn); setSelectedTerms([...selectedTerms, { urn, component: }]); + setSelectedTags([ + ...selectedTags, + { urn, component: }, + ]); }; // When a Tag or term search result is deselected, remove the urn from the Owners @@ -191,6 +199,7 @@ export default function AddTagsTermsModal({ setInputValue(''); setIsFocusedOnInput(true); setSelectedTerms(selectedTerms.filter((term) => term.urn !== urn)); + setSelectedTags(selectedTags.filter((term) => term.urn !== urn)); }; // Function to handle the modal action's @@ -276,6 +285,25 @@ export default function AddTagsTermsModal({ setSelectedTerms([...selectedTerms, { urn, component: }]); } + function selectTag(urn: string, displayName: string, result: SearchResult) { + setIsFocusedOnInput(false); + const newUrns = [...(urns || []), urn]; + setUrns(newUrns); + setSelectedTags([ + ...selectedTags, + { + urn, + component: ( + + ), + }, + ]); + } + function clearInput() { setInputValue(''); setTimeout(() => setIsFocusedOnInput(true), 0); // call after click outside @@ -286,6 +314,8 @@ export default function AddTagsTermsModal({ } const isShowingGlossaryBrowser = !inputValue && type === EntityType.GlossaryTerm && isFocusedOnInput; + const isShowingTagBrowser = + !inputValue && tagSearchResults.length === 0 && type === EntityType.Tag && isFocusedOnInput; return ( setIsFocusedOnInput(true)} onBlur={handleBlur} - dropdownStyle={isShowingGlossaryBrowser || !inputValue ? { display: 'none' } : {}} + dropdownStyle={ + isShowingGlossaryBrowser || isShowingTagBrowser || !inputValue ? { display: 'none' } : {} + } > {tagSearchOptions} + + + ); diff --git a/datahub-web-react/src/app/shared/tags/TagBrowser.tsx b/datahub-web-react/src/app/shared/tags/TagBrowser.tsx new file mode 100644 index 0000000000000..079308771267f --- /dev/null +++ b/datahub-web-react/src/app/shared/tags/TagBrowser.tsx @@ -0,0 +1,80 @@ +import React from 'react'; +import styled from 'styled-components'; +import { useGetSearchResultsForMultipleQuery } from '../../../graphql/search.generated'; +import { useEntityRegistry } from '../../useEntityRegistry'; +import { EntityType, SearchResult } from '../../../types.generated'; +import { ANTD_GRAY } from '../../entity/shared/constants'; + +const TagWrapper = styled.div` + color: #262626; + font-size: 12px; + max-height: calc(100% - 47px); + padding: 5px; + overflow: auto; +`; + +const nameStyles = ` + color: #262626; + display: inline-block; + height: 100%; + padding: 3px 4px; + width: 100%; +`; + +export const NameWrapper = styled.span<{ showSelectStyles?: boolean }>` + ${nameStyles} + + &:hover { + ${(props) => + props.showSelectStyles && + ` + background-color: ${ANTD_GRAY[3]}; + cursor: pointer; + `} + } +`; + +interface Props { + selectTag?: (urn: string, displayName: string, result: SearchResult) => void; +} + +export default function TagBrowser({ selectTag }: Props) { + const entityRegistry = useEntityRegistry(); + const { data } = useGetSearchResultsForMultipleQuery({ + variables: { + input: { + types: [EntityType.Tag], + query: '*', + start: 0, + count: 5, + }, + }, + }); + const tagsResult = data?.searchAcrossEntities?.searchResults; + + const handleSelectTag = (urn: string, displayName: string, tag: SearchResult) => { + if (selectTag) { + selectTag(urn, displayName, tag); + } + }; + + return ( +
+ {tagsResult?.map((tag) => { + const displayName = entityRegistry.getDisplayName(tag.entity.type, tag.entity); + return ( + + { + handleSelectTag(tag.entity.urn, displayName, tag); + }} + > + {displayName} + + + ); + })} +
+ ); +} From e5922eb17f07fbf8e4ef8ba1e82d1489c6bde468 Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Mon, 13 Jun 2022 10:08:02 +0530 Subject: [PATCH 02/28] Added colors in tag suggestions --- datahub-web-react/src/app/shared/tags/TagBrowser.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/datahub-web-react/src/app/shared/tags/TagBrowser.tsx b/datahub-web-react/src/app/shared/tags/TagBrowser.tsx index 079308771267f..c30786bfd2e3f 100644 --- a/datahub-web-react/src/app/shared/tags/TagBrowser.tsx +++ b/datahub-web-react/src/app/shared/tags/TagBrowser.tsx @@ -2,8 +2,9 @@ import React from 'react'; import styled from 'styled-components'; import { useGetSearchResultsForMultipleQuery } from '../../../graphql/search.generated'; import { useEntityRegistry } from '../../useEntityRegistry'; -import { EntityType, SearchResult } from '../../../types.generated'; +import { EntityType, SearchResult, Tag } from '../../../types.generated'; import { ANTD_GRAY } from '../../entity/shared/constants'; +import TagLabel from '../TagLabel'; const TagWrapper = styled.div` color: #262626; @@ -70,7 +71,11 @@ export default function TagBrowser({ selectTag }: Props) { handleSelectTag(tag.entity.urn, displayName, tag); }} > - {displayName} + ); From b67c7c14d49921f1308ab09104712116f63f3fdf Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Mon, 13 Jun 2022 10:27:13 +0530 Subject: [PATCH 03/28] Variable Name Modification --- .../src/app/shared/tags/AddTagsTermsModal.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx b/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx index 4a02e236992f3..4fb5d89b14c23 100644 --- a/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx +++ b/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx @@ -62,7 +62,7 @@ export default function AddTagsTermsModal({ const [disableAdd, setDisableAdd] = useState(false); const [urns, setUrns] = useState([]); const [selectedTerms, setSelectedTerms] = useState([]); - const [selectedTags, setSelectedTags] = useState([]); + const [selectedTagsFromBrowse, setSelectedTagsFromBrowse] = useState([]); const [isFocusedOnInput, setIsFocusedOnInput] = useState(false); const [addTagsMutation] = useAddTagsMutation(); @@ -135,7 +135,7 @@ export default function AddTagsTermsModal({ const selectedItem = type === EntityType.GlossaryTerm ? selectedTerms.find((term) => term.urn === value).component - : selectedTags.find((term) => term.urn === value).component; + : selectedTagsFromBrowse.find((term) => term.urn === value).component; return ( option.props.value === urn); setSelectedTerms([...selectedTerms, { urn, component: }]); - setSelectedTags([ - ...selectedTags, + setSelectedTagsFromBrowse([ + ...selectedTagsFromBrowse, { urn, component: }, ]); }; @@ -199,7 +199,7 @@ export default function AddTagsTermsModal({ setInputValue(''); setIsFocusedOnInput(true); setSelectedTerms(selectedTerms.filter((term) => term.urn !== urn)); - setSelectedTags(selectedTags.filter((term) => term.urn !== urn)); + setSelectedTagsFromBrowse(selectedTagsFromBrowse.filter((term) => term.urn !== urn)); }; // Function to handle the modal action's @@ -285,12 +285,12 @@ export default function AddTagsTermsModal({ setSelectedTerms([...selectedTerms, { urn, component: }]); } - function selectTag(urn: string, displayName: string, result: SearchResult) { + function selectTagFromBrowse(urn: string, displayName: string, result: SearchResult) { setIsFocusedOnInput(false); const newUrns = [...(urns || []), urn]; setUrns(newUrns); - setSelectedTags([ - ...selectedTags, + setSelectedTagsFromBrowse([ + ...selectedTagsFromBrowse, { urn, component: ( @@ -371,7 +371,7 @@ export default function AddTagsTermsModal({ - + From dabfd53c1c884cd02d354bf52824177ff819b385 Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Mon, 13 Jun 2022 10:38:36 +0530 Subject: [PATCH 04/28] Changed internal CSS to page specific --- .../sidebar/Ownership/AddOwnersModal.tsx | 24 +++++++-------- .../src/app/shared/tags/AddTagsTermsModal.tsx | 29 +++++++++---------- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx index 9702612126bfc..2c74146a20752 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx @@ -35,6 +35,14 @@ const SelectInput = styled(Select)` } `; +const StyleTag = styled(Tag)` + padding: 0px 7px 0px 0px; + margin-right: 3px; + display: flex; + justify-content: start; + align-items: center; +`; + type Props = { urn: string; type: EntityType; @@ -65,6 +73,7 @@ export const AddOwnersModal = ({ const ownershipTypes = OWNERSHIP_DISPLAY_TYPES; const [selectedOwners, setSelectedOwners] = useState([]); const [selectedOwnerType, setSelectedOwnerType] = useState(defaultOwnerType || OwnershipType.None); + // const [selectedOwnersFromBrowse, setSelectedOwnersFromBrowse] = useState([]); // User and group dropdown search results! const [userSearch, { data: userSearchData }] = useGetSearchResultsLazyQuery(); @@ -218,20 +227,9 @@ export const AddOwnersModal = ({ event.stopPropagation(); }; return ( - + {label} - + ); }; diff --git a/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx b/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx index 4fb5d89b14c23..6b4f30517e3a1 100644 --- a/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx +++ b/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx @@ -28,6 +28,17 @@ const TagSelect = styled(Select)` width: 480px; `; +const StyleTag = styled(CustomTag)` + margin-right: 3px; + display: flex; + justify-content: start; + align-items: center; + white-space: nowrap; + opacity: 1; + color: #434343; + line-height: 16px; +`; + export const BrowserWrapper = styled.div<{ isHidden: boolean }>` background-color: white; border-radius: 5px; @@ -138,23 +149,9 @@ export default function AddTagsTermsModal({ : selectedTagsFromBrowse.find((term) => term.urn === value).component; return ( - + {selectedItem} - + ); }; From 87d9e767d51aef44c17574d30d98f9e5e8d5dcc0 Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Mon, 13 Jun 2022 17:36:31 +0530 Subject: [PATCH 05/28] Created started file and use Owner Label --- .../src/app/domain/DomainBrowser.tsx | 5 ++ .../sidebar/Ownership/AddOwnersModal.tsx | 29 +------ .../sidebar/Ownership/OwnerBrowser.tsx | 85 +++++++++++++++++++ .../src/app/shared/DomainLabel.tsx | 5 ++ .../src/app/shared/OwnerLabel.tsx | 34 ++++++++ .../src/app/shared/tags/AddTagsTermsModal.tsx | 2 +- .../src/app/shared/tags/TagBrowser.tsx | 14 +-- 7 files changed, 139 insertions(+), 35 deletions(-) create mode 100644 datahub-web-react/src/app/domain/DomainBrowser.tsx create mode 100644 datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/OwnerBrowser.tsx create mode 100644 datahub-web-react/src/app/shared/DomainLabel.tsx create mode 100644 datahub-web-react/src/app/shared/OwnerLabel.tsx diff --git a/datahub-web-react/src/app/domain/DomainBrowser.tsx b/datahub-web-react/src/app/domain/DomainBrowser.tsx new file mode 100644 index 0000000000000..6c7e715e3d844 --- /dev/null +++ b/datahub-web-react/src/app/domain/DomainBrowser.tsx @@ -0,0 +1,5 @@ +import React from 'react'; + +export const DomainBrowser = () => { + return
DomainBrowser
; +}; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx index 2c74146a20752..786e0fdb05ca7 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx @@ -10,24 +10,11 @@ import { SearchResult, } from '../../../../../../../types.generated'; import { useEntityRegistry } from '../../../../../../useEntityRegistry'; -import { CustomAvatar } from '../../../../../../shared/avatar'; import analytics, { EventType, EntityActionType } from '../../../../../../analytics'; import { OWNERSHIP_DISPLAY_TYPES } from './ownershipUtils'; import { useAddOwnersMutation } from '../../../../../../../graphql/mutations.generated'; import { useGetSearchResultsLazyQuery } from '../../../../../../../graphql/search.generated'; - -const SearchResultContainer = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - padding: 2px; -`; - -const SearchResultContent = styled.div` - display: flex; - justify-content: center; - align-items: center; -`; +import { OwnerLabel } from '../../../../../../shared/OwnerLabel'; const SelectInput = styled(Select)` > .ant-select-selector { @@ -157,19 +144,7 @@ export const AddOwnersModal = ({ ? (result.entity as CorpUser).editableProperties?.pictureLink || undefined : undefined; const displayName = entityRegistry.getDisplayName(result.entity.type, result.entity); - return ( - - - -
{displayName}
-
-
- ); + return ; }; const onModalClose = () => { diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/OwnerBrowser.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/OwnerBrowser.tsx new file mode 100644 index 0000000000000..3a98333a7626a --- /dev/null +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/OwnerBrowser.tsx @@ -0,0 +1,85 @@ +import React from 'react'; +import styled from 'styled-components'; +import { useGetSearchResultsForMultipleQuery } from '../../../../../../../graphql/search.generated'; +import { SearchResult, EntityType, CorpUser } from '../../../../../../../types.generated'; +import { useEntityRegistry } from '../../../../../../useEntityRegistry'; +import { OwnerLabel } from '../../../../../../shared/OwnerLabel'; +import { ANTD_GRAY } from '../../../../constants'; + +const OwnersBrowseWrapper = styled.div` + color: #262626; + font-size: 12px; + max-height: calc(100% - 47px); + padding: 5px; + overflow: auto; +`; + +const nameStyles = ` + color: #262626; + display: inline-block; + height: 100%; + padding: 3px 4px; + width: 100%; +`; + +export const OwnersContentWrapper = styled.span<{ showSelectStyles?: boolean }>` + ${nameStyles} + + &:hover { + ${(props) => + props.showSelectStyles && + ` + background-color: ${ANTD_GRAY[3]}; + cursor: pointer; + `} + } +`; + +interface Props { + selectBrowseOwner?: (urn: string, result: SearchResult) => void; +} + +export default function OwnerBrowser({ selectBrowseOwner }: Props) { + const entityRegistry = useEntityRegistry(); + const { data } = useGetSearchResultsForMultipleQuery({ + variables: { + input: { + types: [EntityType.CorpGroup, EntityType.CorpUser], + query: '*', + start: 0, + count: 5, + }, + }, + }); + const ownersResult = data?.searchAcrossEntities?.searchResults; + + const handleSelectBrowseOwner = (urn: string, ownerResult: SearchResult) => { + if (selectBrowseOwner) { + selectBrowseOwner(urn, ownerResult); + } + }; + + return ( +
+ {ownersResult?.map((ownerResult) => { + const displayName = entityRegistry.getDisplayName(ownerResult.entity.type, ownerResult.entity); + const avatarUrl = + ownerResult.entity.type === EntityType.CorpUser + ? (ownerResult.entity as CorpUser).editableProperties?.pictureLink || undefined + : undefined; + return ( + + { + handleSelectBrowseOwner(ownerResult.entity.urn, ownerResult); + }} + > + + + + ); + })} +
+ ); +} diff --git a/datahub-web-react/src/app/shared/DomainLabel.tsx b/datahub-web-react/src/app/shared/DomainLabel.tsx new file mode 100644 index 0000000000000..34d859cc90b22 --- /dev/null +++ b/datahub-web-react/src/app/shared/DomainLabel.tsx @@ -0,0 +1,5 @@ +import React from 'react'; + +export const DomainLabel = () => { + return
DomainLabel
; +}; diff --git a/datahub-web-react/src/app/shared/OwnerLabel.tsx b/datahub-web-react/src/app/shared/OwnerLabel.tsx new file mode 100644 index 0000000000000..de3c03dea2ba4 --- /dev/null +++ b/datahub-web-react/src/app/shared/OwnerLabel.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import styled from 'styled-components'; +import { EntityType } from '../../types.generated'; +import { CustomAvatar } from './avatar'; + +const OwnerContainerWrapper = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + padding: 2px; +`; + +const OwnerContentWrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; +`; + +type Props = { + name: string; + avatarUrl: string | undefined; + type: EntityType; +}; + +export const OwnerLabel = ({ name, avatarUrl, type }: Props) => { + return ( + + + +
{name}
+
+
+ ); +}; diff --git a/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx b/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx index 6b4f30517e3a1..9d0668073e282 100644 --- a/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx +++ b/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx @@ -368,7 +368,7 @@ export default function AddTagsTermsModal({ - + diff --git a/datahub-web-react/src/app/shared/tags/TagBrowser.tsx b/datahub-web-react/src/app/shared/tags/TagBrowser.tsx index c30786bfd2e3f..4cd1045053cfd 100644 --- a/datahub-web-react/src/app/shared/tags/TagBrowser.tsx +++ b/datahub-web-react/src/app/shared/tags/TagBrowser.tsx @@ -36,10 +36,10 @@ export const NameWrapper = styled.span<{ showSelectStyles?: boolean }>` `; interface Props { - selectTag?: (urn: string, displayName: string, result: SearchResult) => void; + selectBrowseTag?: (urn: string, displayName: string, result: SearchResult) => void; } -export default function TagBrowser({ selectTag }: Props) { +export default function TagBrowser({ selectBrowseTag }: Props) { const entityRegistry = useEntityRegistry(); const { data } = useGetSearchResultsForMultipleQuery({ variables: { @@ -53,9 +53,9 @@ export default function TagBrowser({ selectTag }: Props) { }); const tagsResult = data?.searchAcrossEntities?.searchResults; - const handleSelectTag = (urn: string, displayName: string, tag: SearchResult) => { - if (selectTag) { - selectTag(urn, displayName, tag); + const handleSelectBrowseTag = (urn: string, displayName: string, tag: SearchResult) => { + if (selectBrowseTag) { + selectBrowseTag(urn, displayName, tag); } }; @@ -66,9 +66,9 @@ export default function TagBrowser({ selectTag }: Props) { return ( { - handleSelectTag(tag.entity.urn, displayName, tag); + handleSelectBrowseTag(tag.entity.urn, displayName, tag); }} > Date: Tue, 14 Jun 2022 11:41:40 +0530 Subject: [PATCH 06/28] Added Owner suggestion --- .../sidebar/Ownership/AddOwnersModal.tsx | 241 ++++++++++++------ .../src/app/shared/recommendation.tsx | 16 ++ 2 files changed, 183 insertions(+), 74 deletions(-) create mode 100644 datahub-web-react/src/app/shared/recommendation.tsx diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx index 786e0fdb05ca7..435dc166a30bb 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx @@ -15,6 +15,8 @@ import { OWNERSHIP_DISPLAY_TYPES } from './ownershipUtils'; import { useAddOwnersMutation } from '../../../../../../../graphql/mutations.generated'; import { useGetSearchResultsLazyQuery } from '../../../../../../../graphql/search.generated'; import { OwnerLabel } from '../../../../../../shared/OwnerLabel'; +import OwnerBrowser from './OwnerBrowser'; +import ClickOutside from '../../../../../../shared/ClickOutside'; const SelectInput = styled(Select)` > .ant-select-selector { @@ -30,6 +32,24 @@ const StyleTag = styled(Tag)` align-items: center; `; +export const BrowserWrapper = styled.div<{ isHidden: boolean }>` + background-color: white; + border-radius: 5px; + box-shadow: 0 3px 6px -4px rgb(0 0 0 / 12%), 0 6px 16px 0 rgb(0 0 0 / 8%), 0 9px 28px 8px rgb(0 0 0 / 5%); + max-height: 380px; + overflow: auto; + position: absolute; + transition: opacity 0.2s; + width: 480px; + z-index: 1051; + ${(props) => + props.isHidden && + ` + opacity: 0; + height: 0; + `} +`; + type Props = { urn: string; type: EntityType; @@ -60,7 +80,9 @@ export const AddOwnersModal = ({ const ownershipTypes = OWNERSHIP_DISPLAY_TYPES; const [selectedOwners, setSelectedOwners] = useState([]); const [selectedOwnerType, setSelectedOwnerType] = useState(defaultOwnerType || OwnershipType.None); - // const [selectedOwnersFromBrowse, setSelectedOwnersFromBrowse] = useState([]); + const [selectedOwnersFromBrowse, setSelectedOwnersFromBrowse] = useState([]); + const [inputValue, setInputValue] = useState(''); + const [isFocusedOnInput, setIsFocusedOnInput] = useState(false); // User and group dropdown search results! const [userSearch, { data: userSearchData }] = useGetSearchResultsLazyQuery(); @@ -78,6 +100,33 @@ export const AddOwnersModal = ({ } }, [ownershipTypes]); + // Invokes the search API as the owner types + const handleSearch = (entityType: EntityType, text: string, searchQuery: any) => { + if (text.length > 2) { + searchQuery({ + variables: { + input: { + type: entityType, + query: text, + start: 0, + count: 5, + }, + }, + }); + } + }; + + // Invokes the user search API for both users and groups. + const handleActorSearch = (text: string) => { + handleSearch(EntityType.CorpUser, text, userSearch); + handleSearch(EntityType.CorpGroup, text, groupSearch); + }; + + // When a owner type is selected, set the type as selected type. + const onSelectOwnerType = (newType: OwnershipType) => { + setSelectedOwnerType(newType); + }; + /** * When a owner search result is selected, add the new owner to the selectedOwners * value: {ownerUrn: string, ownerEntityType: EntityType} @@ -88,6 +137,11 @@ export const AddOwnersModal = ({ .map((result) => result.entity); if (filteredActors.length) { const actor = filteredActors[0]; + const displayName = entityRegistry.getDisplayName(actor.type, actor); + const avatarUrl = + actor.type === EntityType.CorpUser + ? (actor as CorpUser).editableProperties?.pictureLink || undefined + : undefined; const ownerEntityType = actor && actor.type === EntityType.CorpGroup ? OwnerEntityType.CorpGroup : OwnerEntityType.CorpUser; const newValues = [ @@ -101,40 +155,23 @@ export const AddOwnersModal = ({ }, ]; setSelectedOwners(newValues); + setSelectedOwnersFromBrowse([ + ...selectedOwnersFromBrowse, + { + urn: selectedValue.value, + component: , + }, + ]); } }; // When a owner search result is deselected, remove the Owner const onDeselectOwner = (selectedValue: { key: string; label: React.ReactNode; value: string }) => { - const newValues = selectedOwners.filter((owner) => owner.label !== selectedValue.value); + const newValues = selectedOwners.filter((owner) => owner.label !== selectedValue.label); setSelectedOwners(newValues); - }; - - // When a owner type is selected, set the type as selected type. - const onSelectOwnerType = (newType: OwnershipType) => { - setSelectedOwnerType(newType); - }; - - // Invokes the search API as the owner types - const handleSearch = (entityType: EntityType, text: string, searchQuery: any) => { - if (text.length > 2) { - searchQuery({ - variables: { - input: { - type: entityType, - query: text, - start: 0, - count: 5, - }, - }, - }); - } - }; - - // Invokes the user search API for both users and groups. - const handleActorSearch = (text: string) => { - handleSearch(EntityType.CorpUser, text, userSearch); - handleSearch(EntityType.CorpGroup, text, groupSearch); + setInputValue(''); + setIsFocusedOnInput(true); + setSelectedOwnersFromBrowse(selectedOwnersFromBrowse.filter((owner) => owner.urn !== selectedValue.label)); }; // Renders a search result in the select dropdown. @@ -196,18 +233,57 @@ export const AddOwnersModal = ({ const tagRender = (props) => { // eslint-disable-next-line react/prop-types - const { label, closable, onClose } = props; + const { closable, onClose, value } = props; const onPreventMouseDown = (event) => { event.preventDefault(); event.stopPropagation(); }; + // eslint-disable-next-line react/prop-types + const selectedItem = selectedOwnersFromBrowse.find((owner) => owner.urn === value.ownerUrn).component; return ( - {label} + {selectedItem} ); }; + const selectBrowseOwner = (browseUrn: string, result: SearchResult) => { + setIsFocusedOnInput(false); + const avatarUrl = + result.entity.type === EntityType.CorpUser + ? (result.entity as CorpUser).editableProperties?.pictureLink || undefined + : undefined; + const displayName = entityRegistry.getDisplayName(result.entity.type, result.entity); + const newValues = [ + ...selectedOwners, + { + label: browseUrn, + value: { + ownerUrn: browseUrn, + ownerEntityType: result.entity.type, + }, + }, + ]; + setSelectedOwners(newValues); + setSelectedOwnersFromBrowse([ + ...selectedOwnersFromBrowse, + { + urn: browseUrn, + component: , + }, + ]); + }; + + function clearInput() { + setInputValue(''); + setTimeout(() => setIsFocusedOnInput(true), 0); // call after click outside + } + + function handleBlur() { + setInputValue(''); + } + + const isShowingOwnerBrowser = !inputValue && isFocusedOnInput; return ( } > -
- Owner}> - Find a user or group - - onSelectOwner(asset)} - onDeselect={(asset: any) => onDeselectOwner(asset)} - onSearch={handleActorSearch} - tagRender={tagRender} - > - {combinedSearchResults?.map((result) => ( - - {renderSearchResult(result)} - - ))} - - - - {!hideOwnerType && ( - Type}> - Choose an owner type - - + + + + - )} -
+ {!hideOwnerType && ( + Type}> + Choose an owner type + + + + + )} + +
); }; diff --git a/datahub-web-react/src/app/shared/recommendation.tsx b/datahub-web-react/src/app/shared/recommendation.tsx new file mode 100644 index 0000000000000..2a2114147f49d --- /dev/null +++ b/datahub-web-react/src/app/shared/recommendation.tsx @@ -0,0 +1,16 @@ +import { useGetSearchResultsForMultipleQuery } from '../../graphql/search.generated'; +import { EntityType } from '../../types.generated'; + +export function GetTagRecommendation() { + const { data } = useGetSearchResultsForMultipleQuery({ + variables: { + input: { + types: [EntityType.Tag], + query: '*', + start: 0, + count: 5, + }, + }, + }); + return data?.searchAcrossEntities?.searchResults; +} From 1608caf8e8271c3e85076d8cc52a8a86d0f7622c Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Tue, 14 Jun 2022 13:08:14 +0530 Subject: [PATCH 07/28] Added the recommended tags in select input field --- .../src/app/shared/tags/AddTagsTermsModal.tsx | 58 ++++++------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx b/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx index 9d0668073e282..58b8067320476 100644 --- a/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx +++ b/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx @@ -13,7 +13,7 @@ import TagLabel from '../TagLabel'; import GlossaryBrowser from '../../glossary/GlossaryBrowser/GlossaryBrowser'; import ClickOutside from '../ClickOutside'; import { useEntityRegistry } from '../../useEntityRegistry'; -import TagBrowser from './TagBrowser'; +import { GetTagRecommendation } from '../recommendation'; type AddTagsModalProps = { visible: boolean; @@ -73,7 +73,6 @@ export default function AddTagsTermsModal({ const [disableAdd, setDisableAdd] = useState(false); const [urns, setUrns] = useState([]); const [selectedTerms, setSelectedTerms] = useState([]); - const [selectedTagsFromBrowse, setSelectedTagsFromBrowse] = useState([]); const [isFocusedOnInput, setIsFocusedOnInput] = useState(false); const [addTagsMutation] = useAddTagsMutation(); @@ -119,17 +118,26 @@ export default function AddTagsTermsModal({ ); }; - const tagSearchOptions = tagSearchResults.map((result) => { + // TO DO: Why It is not working in useEffect + const recommendedTagData = GetTagRecommendation(); + + let tagSearchOptions: any[] | undefined = tagSearchResults.map((result) => { return renderSearchResult(result); }); + if (!inputValue && type === EntityType.Tag && isFocusedOnInput) { + tagSearchOptions = recommendedTagData?.map((tag) => { + return renderSearchResult(tag); + }); + } + const inputExistsInTagSearch = tagSearchResults.some((result: SearchResult) => { const displayName = entityRegistry.getDisplayName(result.entity.type, result.entity); return displayName.toLowerCase() === inputValue.toLowerCase(); }); if (!inputExistsInTagSearch && inputValue.length > 0 && type === EntityType.Tag && urns.length === 0) { - tagSearchOptions.push( + tagSearchOptions?.push( Create {inputValue} , @@ -138,15 +146,13 @@ export default function AddTagsTermsModal({ const tagRender = (props) => { // eslint-disable-next-line react/prop-types - const { closable, onClose, value } = props; + const { label, closable, onClose, value } = props; const onPreventMouseDown = (event) => { event.preventDefault(); event.stopPropagation(); }; const selectedItem = - type === EntityType.GlossaryTerm - ? selectedTerms.find((term) => term.urn === value).component - : selectedTagsFromBrowse.find((term) => term.urn === value).component; + type === EntityType.GlossaryTerm ? selectedTerms.find((term) => term.urn === value).component : label; return ( @@ -181,12 +187,8 @@ export default function AddTagsTermsModal({ } const newUrns = [...(urns || []), urn]; setUrns(newUrns); - const selectedSearchOption = tagSearchOptions.find((option) => option.props.value === urn); + const selectedSearchOption = tagSearchOptions?.find((option) => option.props.value === urn); setSelectedTerms([...selectedTerms, { urn, component: }]); - setSelectedTagsFromBrowse([ - ...selectedTagsFromBrowse, - { urn, component: }, - ]); }; // When a Tag or term search result is deselected, remove the urn from the Owners @@ -196,7 +198,6 @@ export default function AddTagsTermsModal({ setInputValue(''); setIsFocusedOnInput(true); setSelectedTerms(selectedTerms.filter((term) => term.urn !== urn)); - setSelectedTagsFromBrowse(selectedTagsFromBrowse.filter((term) => term.urn !== urn)); }; // Function to handle the modal action's @@ -282,25 +283,6 @@ export default function AddTagsTermsModal({ setSelectedTerms([...selectedTerms, { urn, component: }]); } - function selectTagFromBrowse(urn: string, displayName: string, result: SearchResult) { - setIsFocusedOnInput(false); - const newUrns = [...(urns || []), urn]; - setUrns(newUrns); - setSelectedTagsFromBrowse([ - ...selectedTagsFromBrowse, - { - urn, - component: ( - - ), - }, - ]); - } - function clearInput() { setInputValue(''); setTimeout(() => setIsFocusedOnInput(true), 0); // call after click outside @@ -311,8 +293,6 @@ export default function AddTagsTermsModal({ } const isShowingGlossaryBrowser = !inputValue && type === EntityType.GlossaryTerm && isFocusedOnInput; - const isShowingTagBrowser = - !inputValue && tagSearchResults.length === 0 && type === EntityType.Tag && isFocusedOnInput; return ( setIsFocusedOnInput(false)}> setIsFocusedOnInput(true)} onBlur={handleBlur} - dropdownStyle={ - isShowingGlossaryBrowser || isShowingTagBrowser || !inputValue ? { display: 'none' } : {} - } + dropdownStyle={isShowingGlossaryBrowser ? { display: 'none' } : {}} > {tagSearchOptions} - - - ); From c4064327096f3d0d5dd23029bd8ad17e1cdd6829 Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Tue, 14 Jun 2022 13:14:41 +0530 Subject: [PATCH 08/28] Remmoved Tag Browse and stash the owners code --- .../sidebar/Ownership/AddOwnersModal.tsx | 288 +++++++----------- .../src/app/shared/recommendation.tsx | 14 + .../src/app/shared/tags/TagBrowser.tsx | 85 ------ 3 files changed, 125 insertions(+), 262 deletions(-) delete mode 100644 datahub-web-react/src/app/shared/tags/TagBrowser.tsx diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx index 435dc166a30bb..9702612126bfc 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx @@ -10,44 +10,29 @@ import { SearchResult, } from '../../../../../../../types.generated'; import { useEntityRegistry } from '../../../../../../useEntityRegistry'; +import { CustomAvatar } from '../../../../../../shared/avatar'; import analytics, { EventType, EntityActionType } from '../../../../../../analytics'; import { OWNERSHIP_DISPLAY_TYPES } from './ownershipUtils'; import { useAddOwnersMutation } from '../../../../../../../graphql/mutations.generated'; import { useGetSearchResultsLazyQuery } from '../../../../../../../graphql/search.generated'; -import { OwnerLabel } from '../../../../../../shared/OwnerLabel'; -import OwnerBrowser from './OwnerBrowser'; -import ClickOutside from '../../../../../../shared/ClickOutside'; -const SelectInput = styled(Select)` - > .ant-select-selector { - height: 36px; - } +const SearchResultContainer = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + padding: 2px; `; -const StyleTag = styled(Tag)` - padding: 0px 7px 0px 0px; - margin-right: 3px; +const SearchResultContent = styled.div` display: flex; - justify-content: start; + justify-content: center; align-items: center; `; -export const BrowserWrapper = styled.div<{ isHidden: boolean }>` - background-color: white; - border-radius: 5px; - box-shadow: 0 3px 6px -4px rgb(0 0 0 / 12%), 0 6px 16px 0 rgb(0 0 0 / 8%), 0 9px 28px 8px rgb(0 0 0 / 5%); - max-height: 380px; - overflow: auto; - position: absolute; - transition: opacity 0.2s; - width: 480px; - z-index: 1051; - ${(props) => - props.isHidden && - ` - opacity: 0; - height: 0; - `} +const SelectInput = styled(Select)` + > .ant-select-selector { + height: 36px; + } `; type Props = { @@ -80,9 +65,6 @@ export const AddOwnersModal = ({ const ownershipTypes = OWNERSHIP_DISPLAY_TYPES; const [selectedOwners, setSelectedOwners] = useState([]); const [selectedOwnerType, setSelectedOwnerType] = useState(defaultOwnerType || OwnershipType.None); - const [selectedOwnersFromBrowse, setSelectedOwnersFromBrowse] = useState([]); - const [inputValue, setInputValue] = useState(''); - const [isFocusedOnInput, setIsFocusedOnInput] = useState(false); // User and group dropdown search results! const [userSearch, { data: userSearchData }] = useGetSearchResultsLazyQuery(); @@ -100,33 +82,6 @@ export const AddOwnersModal = ({ } }, [ownershipTypes]); - // Invokes the search API as the owner types - const handleSearch = (entityType: EntityType, text: string, searchQuery: any) => { - if (text.length > 2) { - searchQuery({ - variables: { - input: { - type: entityType, - query: text, - start: 0, - count: 5, - }, - }, - }); - } - }; - - // Invokes the user search API for both users and groups. - const handleActorSearch = (text: string) => { - handleSearch(EntityType.CorpUser, text, userSearch); - handleSearch(EntityType.CorpGroup, text, groupSearch); - }; - - // When a owner type is selected, set the type as selected type. - const onSelectOwnerType = (newType: OwnershipType) => { - setSelectedOwnerType(newType); - }; - /** * When a owner search result is selected, add the new owner to the selectedOwners * value: {ownerUrn: string, ownerEntityType: EntityType} @@ -137,11 +92,6 @@ export const AddOwnersModal = ({ .map((result) => result.entity); if (filteredActors.length) { const actor = filteredActors[0]; - const displayName = entityRegistry.getDisplayName(actor.type, actor); - const avatarUrl = - actor.type === EntityType.CorpUser - ? (actor as CorpUser).editableProperties?.pictureLink || undefined - : undefined; const ownerEntityType = actor && actor.type === EntityType.CorpGroup ? OwnerEntityType.CorpGroup : OwnerEntityType.CorpUser; const newValues = [ @@ -155,23 +105,40 @@ export const AddOwnersModal = ({ }, ]; setSelectedOwners(newValues); - setSelectedOwnersFromBrowse([ - ...selectedOwnersFromBrowse, - { - urn: selectedValue.value, - component: , - }, - ]); } }; // When a owner search result is deselected, remove the Owner const onDeselectOwner = (selectedValue: { key: string; label: React.ReactNode; value: string }) => { - const newValues = selectedOwners.filter((owner) => owner.label !== selectedValue.label); + const newValues = selectedOwners.filter((owner) => owner.label !== selectedValue.value); setSelectedOwners(newValues); - setInputValue(''); - setIsFocusedOnInput(true); - setSelectedOwnersFromBrowse(selectedOwnersFromBrowse.filter((owner) => owner.urn !== selectedValue.label)); + }; + + // When a owner type is selected, set the type as selected type. + const onSelectOwnerType = (newType: OwnershipType) => { + setSelectedOwnerType(newType); + }; + + // Invokes the search API as the owner types + const handleSearch = (entityType: EntityType, text: string, searchQuery: any) => { + if (text.length > 2) { + searchQuery({ + variables: { + input: { + type: entityType, + query: text, + start: 0, + count: 5, + }, + }, + }); + } + }; + + // Invokes the user search API for both users and groups. + const handleActorSearch = (text: string) => { + handleSearch(EntityType.CorpUser, text, userSearch); + handleSearch(EntityType.CorpGroup, text, groupSearch); }; // Renders a search result in the select dropdown. @@ -181,7 +148,19 @@ export const AddOwnersModal = ({ ? (result.entity as CorpUser).editableProperties?.pictureLink || undefined : undefined; const displayName = entityRegistry.getDisplayName(result.entity.type, result.entity); - return ; + return ( + + + +
{displayName}
+
+
+ ); }; const onModalClose = () => { @@ -233,57 +212,29 @@ export const AddOwnersModal = ({ const tagRender = (props) => { // eslint-disable-next-line react/prop-types - const { closable, onClose, value } = props; + const { label, closable, onClose } = props; const onPreventMouseDown = (event) => { event.preventDefault(); event.stopPropagation(); }; - // eslint-disable-next-line react/prop-types - const selectedItem = selectedOwnersFromBrowse.find((owner) => owner.urn === value.ownerUrn).component; return ( - - {selectedItem} - + + {label} + ); }; - const selectBrowseOwner = (browseUrn: string, result: SearchResult) => { - setIsFocusedOnInput(false); - const avatarUrl = - result.entity.type === EntityType.CorpUser - ? (result.entity as CorpUser).editableProperties?.pictureLink || undefined - : undefined; - const displayName = entityRegistry.getDisplayName(result.entity.type, result.entity); - const newValues = [ - ...selectedOwners, - { - label: browseUrn, - value: { - ownerUrn: browseUrn, - ownerEntityType: result.entity.type, - }, - }, - ]; - setSelectedOwners(newValues); - setSelectedOwnersFromBrowse([ - ...selectedOwnersFromBrowse, - { - urn: browseUrn, - component: , - }, - ]); - }; - - function clearInput() { - setInputValue(''); - setTimeout(() => setIsFocusedOnInput(true), 0); // call after click outside - } - - function handleBlur() { - setInputValue(''); - } - - const isShowingOwnerBrowser = !inputValue && isFocusedOnInput; return ( } > - setIsFocusedOnInput(false)}> -
- Owner}> - Find a user or group - - onSelectOwner(asset)} - onDeselect={(asset: any) => onDeselectOwner(asset)} - onSearch={(value: string) => { - // eslint-disable-next-line react/prop-types - handleActorSearch(value.trim()); - // eslint-disable-next-line react/prop-types - setInputValue(value.trim()); - }} - tagRender={tagRender} - onClear={clearInput} - onFocus={() => setIsFocusedOnInput(true)} - onBlur={handleBlur} - dropdownStyle={isShowingOwnerBrowser || !inputValue ? { display: 'none' } : {}} + + Owner}> + Find a user or group + + onSelectOwner(asset)} + onDeselect={(asset: any) => onDeselectOwner(asset)} + onSearch={handleActorSearch} + tagRender={tagRender} + > + {combinedSearchResults?.map((result) => ( + + {renderSearchResult(result)} + + ))} + + + + {!hideOwnerType && ( + Type}> + Choose an owner type + + - {!hideOwnerType && ( - Type}> - Choose an owner type - - - - - )} - -
+ )} +
); }; diff --git a/datahub-web-react/src/app/shared/recommendation.tsx b/datahub-web-react/src/app/shared/recommendation.tsx index 2a2114147f49d..dea4aaaaf319e 100644 --- a/datahub-web-react/src/app/shared/recommendation.tsx +++ b/datahub-web-react/src/app/shared/recommendation.tsx @@ -14,3 +14,17 @@ export function GetTagRecommendation() { }); return data?.searchAcrossEntities?.searchResults; } + +export function GetOwnerRecommendation() { + const { data } = useGetSearchResultsForMultipleQuery({ + variables: { + input: { + types: [EntityType.CorpGroup, EntityType.CorpUser], + query: '*', + start: 0, + count: 5, + }, + }, + }); + return data?.searchAcrossEntities?.searchResults; +} diff --git a/datahub-web-react/src/app/shared/tags/TagBrowser.tsx b/datahub-web-react/src/app/shared/tags/TagBrowser.tsx deleted file mode 100644 index 4cd1045053cfd..0000000000000 --- a/datahub-web-react/src/app/shared/tags/TagBrowser.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; -import { useGetSearchResultsForMultipleQuery } from '../../../graphql/search.generated'; -import { useEntityRegistry } from '../../useEntityRegistry'; -import { EntityType, SearchResult, Tag } from '../../../types.generated'; -import { ANTD_GRAY } from '../../entity/shared/constants'; -import TagLabel from '../TagLabel'; - -const TagWrapper = styled.div` - color: #262626; - font-size: 12px; - max-height: calc(100% - 47px); - padding: 5px; - overflow: auto; -`; - -const nameStyles = ` - color: #262626; - display: inline-block; - height: 100%; - padding: 3px 4px; - width: 100%; -`; - -export const NameWrapper = styled.span<{ showSelectStyles?: boolean }>` - ${nameStyles} - - &:hover { - ${(props) => - props.showSelectStyles && - ` - background-color: ${ANTD_GRAY[3]}; - cursor: pointer; - `} - } -`; - -interface Props { - selectBrowseTag?: (urn: string, displayName: string, result: SearchResult) => void; -} - -export default function TagBrowser({ selectBrowseTag }: Props) { - const entityRegistry = useEntityRegistry(); - const { data } = useGetSearchResultsForMultipleQuery({ - variables: { - input: { - types: [EntityType.Tag], - query: '*', - start: 0, - count: 5, - }, - }, - }); - const tagsResult = data?.searchAcrossEntities?.searchResults; - - const handleSelectBrowseTag = (urn: string, displayName: string, tag: SearchResult) => { - if (selectBrowseTag) { - selectBrowseTag(urn, displayName, tag); - } - }; - - return ( -
- {tagsResult?.map((tag) => { - const displayName = entityRegistry.getDisplayName(tag.entity.type, tag.entity); - return ( - - { - handleSelectBrowseTag(tag.entity.urn, displayName, tag); - }} - > - - - - ); - })} -
- ); -} From 913c40e7747649130bd178e86215962ae3dc854b Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Wed, 15 Jun 2022 10:32:25 +0530 Subject: [PATCH 09/28] Recommended Owners in select input --- .../src/app/domain/DomainBrowser.tsx | 5 - .../sidebar/Ownership/AddOwnersModal.tsx | 228 +++++++++--------- .../sidebar/Ownership/OwnerBrowser.tsx | 85 ------- .../src/app/shared/tags/AddTagsTermsModal.tsx | 12 +- 4 files changed, 124 insertions(+), 206 deletions(-) delete mode 100644 datahub-web-react/src/app/domain/DomainBrowser.tsx delete mode 100644 datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/OwnerBrowser.tsx diff --git a/datahub-web-react/src/app/domain/DomainBrowser.tsx b/datahub-web-react/src/app/domain/DomainBrowser.tsx deleted file mode 100644 index 6c7e715e3d844..0000000000000 --- a/datahub-web-react/src/app/domain/DomainBrowser.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import React from 'react'; - -export const DomainBrowser = () => { - return
DomainBrowser
; -}; diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx index 9702612126bfc..8c76dc36a0754 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx @@ -10,24 +10,13 @@ import { SearchResult, } from '../../../../../../../types.generated'; import { useEntityRegistry } from '../../../../../../useEntityRegistry'; -import { CustomAvatar } from '../../../../../../shared/avatar'; import analytics, { EventType, EntityActionType } from '../../../../../../analytics'; import { OWNERSHIP_DISPLAY_TYPES } from './ownershipUtils'; import { useAddOwnersMutation } from '../../../../../../../graphql/mutations.generated'; import { useGetSearchResultsLazyQuery } from '../../../../../../../graphql/search.generated'; - -const SearchResultContainer = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - padding: 2px; -`; - -const SearchResultContent = styled.div` - display: flex; - justify-content: center; - align-items: center; -`; +import { GetOwnerRecommendation } from '../../../../../../shared/recommendation'; +import ClickOutside from '../../../../../../shared/ClickOutside'; +import { OwnerLabel } from '../../../../../../shared/OwnerLabel'; const SelectInput = styled(Select)` > .ant-select-selector { @@ -61,10 +50,12 @@ export const AddOwnersModal = ({ refetch, }: Props) => { const entityRegistry = useEntityRegistry(); + const [inputValue, setInputValue] = useState(''); const [addOwnersMutation] = useAddOwnersMutation(); const ownershipTypes = OWNERSHIP_DISPLAY_TYPES; const [selectedOwners, setSelectedOwners] = useState([]); const [selectedOwnerType, setSelectedOwnerType] = useState(defaultOwnerType || OwnershipType.None); + const [isFocusedOnInput, setIsFocusedOnInput] = useState(false); // User and group dropdown search results! const [userSearch, { data: userSearchData }] = useGetSearchResultsLazyQuery(); @@ -76,49 +67,14 @@ export const AddOwnersModal = ({ // Add owners Form const [form] = Form.useForm(); + const recommendedOwnersData = GetOwnerRecommendation(); + useEffect(() => { if (ownershipTypes) { setSelectedOwnerType(ownershipTypes[0].type); } }, [ownershipTypes]); - /** - * When a owner search result is selected, add the new owner to the selectedOwners - * value: {ownerUrn: string, ownerEntityType: EntityType} - */ - const onSelectOwner = (selectedValue: { key: string; label: React.ReactNode; value: string }) => { - const filteredActors = combinedSearchResults - .filter((result) => result.entity.urn === selectedValue.value) - .map((result) => result.entity); - if (filteredActors.length) { - const actor = filteredActors[0]; - const ownerEntityType = - actor && actor.type === EntityType.CorpGroup ? OwnerEntityType.CorpGroup : OwnerEntityType.CorpUser; - const newValues = [ - ...selectedOwners, - { - label: selectedValue.value, - value: { - ownerUrn: selectedValue.value, - ownerEntityType, - }, - }, - ]; - setSelectedOwners(newValues); - } - }; - - // When a owner search result is deselected, remove the Owner - const onDeselectOwner = (selectedValue: { key: string; label: React.ReactNode; value: string }) => { - const newValues = selectedOwners.filter((owner) => owner.label !== selectedValue.value); - setSelectedOwners(newValues); - }; - - // When a owner type is selected, set the type as selected type. - const onSelectOwnerType = (newType: OwnershipType) => { - setSelectedOwnerType(newType); - }; - // Invokes the search API as the owner types const handleSearch = (entityType: EntityType, text: string, searchQuery: any) => { if (text.length > 2) { @@ -149,27 +105,91 @@ export const AddOwnersModal = ({ : undefined; const displayName = entityRegistry.getDisplayName(result.entity.type, result.entity); return ( - - - -
{displayName}
-
-
+ + + ); }; + const ownerResult = !inputValue || inputValue.length === 0 ? recommendedOwnersData : combinedSearchResults; + + console.log('isFocusedOnInput::', isFocusedOnInput); + const ownerSearchOptions = ownerResult?.map((result) => { + return renderSearchResult(result); + }); + const onModalClose = () => { + setInputValue(''); setSelectedOwners([]); setSelectedOwnerType(defaultOwnerType || OwnershipType.None); form.resetFields(); onCloseModal(); }; + /** + * When a owner search result is selected, add the new owner to the selectedOwners + * value: {ownerUrn: string, ownerEntityType: EntityType} + */ + const onSelectOwner = (selectedValue: { key: string; label: React.ReactNode; value: string }) => { + const filteredActors = ownerResult + ?.filter((result) => result.entity.urn === selectedValue.value) + .map((result) => result.entity); + if (filteredActors?.length) { + const actor = filteredActors[0]; + const ownerEntityType = + actor && actor.type === EntityType.CorpGroup ? OwnerEntityType.CorpGroup : OwnerEntityType.CorpUser; + const newValues = [ + ...selectedOwners, + { + label: selectedValue.value, + value: { + ownerUrn: selectedValue.value, + ownerEntityType, + }, + }, + ]; + setSelectedOwners(newValues); + } + }; + + // When a owner search result is deselected, remove the Owner + const onDeselectOwner = (selectedValue: { key: string; label: React.ReactNode; value: string }) => { + setInputValue(''); + setIsFocusedOnInput(true); + const newValues = selectedOwners.filter((owner) => owner.label !== selectedValue.value); + setSelectedOwners(newValues); + }; + + // When a owner type is selected, set the type as selected type. + const onSelectOwnerType = (newType: OwnershipType) => { + setSelectedOwnerType(newType); + }; + + const tagRender = (props) => { + // eslint-disable-next-line react/prop-types + const { label, closable, onClose } = props; + const onPreventMouseDown = (event) => { + event.preventDefault(); + event.stopPropagation(); + }; + return ( + + {label} + + ); + }; + // Function to handle the modal action's const onOk = async () => { if (selectedOwners.length === 0) { @@ -210,30 +230,14 @@ export const AddOwnersModal = ({ } }; - const tagRender = (props) => { - // eslint-disable-next-line react/prop-types - const { label, closable, onClose } = props; - const onPreventMouseDown = (event) => { - event.preventDefault(); - event.stopPropagation(); - }; - return ( - - {label} - - ); - }; + function clearInput() { + setInputValue(''); + setTimeout(() => setIsFocusedOnInput(true), 0); // call after click outside + } + + function handleBlur() { + setInputValue(''); + } return (
- Owner}> - Find a user or group - - onSelectOwner(asset)} - onDeselect={(asset: any) => onDeselectOwner(asset)} - onSearch={handleActorSearch} - tagRender={tagRender} - > - {combinedSearchResults?.map((result) => ( - - {renderSearchResult(result)} - - ))} - + setIsFocusedOnInput(false)}> + Owner}> + Find a user or group + + onSelectOwner(asset)} + onDeselect={(asset: any) => onDeselectOwner(asset)} + onSearch={(value: string) => { + // eslint-disable-next-line react/prop-types + handleActorSearch(value.trim()); + // eslint-disable-next-line react/prop-types + setInputValue(value.trim()); + }} + tagRender={tagRender} + value={selectedOwners} + onClear={clearInput} + onFocus={() => setIsFocusedOnInput(true)} + onBlur={handleBlur} + > + {ownerSearchOptions} + + - + {!hideOwnerType && ( Type}> Choose an owner type diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/OwnerBrowser.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/OwnerBrowser.tsx deleted file mode 100644 index 3a98333a7626a..0000000000000 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/OwnerBrowser.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; -import { useGetSearchResultsForMultipleQuery } from '../../../../../../../graphql/search.generated'; -import { SearchResult, EntityType, CorpUser } from '../../../../../../../types.generated'; -import { useEntityRegistry } from '../../../../../../useEntityRegistry'; -import { OwnerLabel } from '../../../../../../shared/OwnerLabel'; -import { ANTD_GRAY } from '../../../../constants'; - -const OwnersBrowseWrapper = styled.div` - color: #262626; - font-size: 12px; - max-height: calc(100% - 47px); - padding: 5px; - overflow: auto; -`; - -const nameStyles = ` - color: #262626; - display: inline-block; - height: 100%; - padding: 3px 4px; - width: 100%; -`; - -export const OwnersContentWrapper = styled.span<{ showSelectStyles?: boolean }>` - ${nameStyles} - - &:hover { - ${(props) => - props.showSelectStyles && - ` - background-color: ${ANTD_GRAY[3]}; - cursor: pointer; - `} - } -`; - -interface Props { - selectBrowseOwner?: (urn: string, result: SearchResult) => void; -} - -export default function OwnerBrowser({ selectBrowseOwner }: Props) { - const entityRegistry = useEntityRegistry(); - const { data } = useGetSearchResultsForMultipleQuery({ - variables: { - input: { - types: [EntityType.CorpGroup, EntityType.CorpUser], - query: '*', - start: 0, - count: 5, - }, - }, - }); - const ownersResult = data?.searchAcrossEntities?.searchResults; - - const handleSelectBrowseOwner = (urn: string, ownerResult: SearchResult) => { - if (selectBrowseOwner) { - selectBrowseOwner(urn, ownerResult); - } - }; - - return ( -
- {ownersResult?.map((ownerResult) => { - const displayName = entityRegistry.getDisplayName(ownerResult.entity.type, ownerResult.entity); - const avatarUrl = - ownerResult.entity.type === EntityType.CorpUser - ? (ownerResult.entity as CorpUser).editableProperties?.pictureLink || undefined - : undefined; - return ( - - { - handleSelectBrowseOwner(ownerResult.entity.urn, ownerResult); - }} - > - - - - ); - })} -
- ); -} diff --git a/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx b/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx index 58b8067320476..f7fe13abeb62e 100644 --- a/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx +++ b/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx @@ -118,19 +118,15 @@ export default function AddTagsTermsModal({ ); }; - // TO DO: Why It is not working in useEffect const recommendedTagData = GetTagRecommendation(); - let tagSearchOptions: any[] | undefined = tagSearchResults.map((result) => { + const tagResult = + (!inputValue || inputValue.length === 0) && type === EntityType.Tag ? recommendedTagData : tagSearchResults; + + const tagSearchOptions = tagResult?.map((result) => { return renderSearchResult(result); }); - if (!inputValue && type === EntityType.Tag && isFocusedOnInput) { - tagSearchOptions = recommendedTagData?.map((tag) => { - return renderSearchResult(tag); - }); - } - const inputExistsInTagSearch = tagSearchResults.some((result: SearchResult) => { const displayName = entityRegistry.getDisplayName(result.entity.type, result.entity); return displayName.toLowerCase() === inputValue.toLowerCase(); From ebe27e9ec3adabf6b6f07b0fd272f6bfa95b4fe1 Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Wed, 15 Jun 2022 15:20:35 +0530 Subject: [PATCH 10/28] Fixed UI issue --- .../containers/profile/sidebar/Ownership/AddOwnersModal.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx index 8c76dc36a0754..228e81b2ae223 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx @@ -118,6 +118,9 @@ export const AddOwnersModal = ({ return renderSearchResult(result); }); + console.log('ownerSearchOptions::', ownerSearchOptions); + console.log('recommendedOwnersData::', recommendedOwnersData); + const onModalClose = () => { setInputValue(''); setSelectedOwners([]); @@ -269,6 +272,7 @@ export const AddOwnersModal = ({ placeholder="Search for users or groups..." showSearch filterOption={false} + defaultActiveFirstOption={false} onSelect={(asset: any) => onSelectOwner(asset)} onDeselect={(asset: any) => onDeselectOwner(asset)} onSearch={(value: string) => { From ea8eb7943857a5f645b0aac523d165ef8237c598 Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Wed, 15 Jun 2022 15:41:05 +0530 Subject: [PATCH 11/28] Fixed UI issue --- .../sidebar/Ownership/AddOwnersModal.tsx | 104 +++++++++--------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx index 228e81b2ae223..11b6c1521c2f1 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { Button, Form, message, Modal, Select, Tag, Typography } from 'antd'; import styled from 'styled-components'; @@ -15,7 +15,6 @@ import { OWNERSHIP_DISPLAY_TYPES } from './ownershipUtils'; import { useAddOwnersMutation } from '../../../../../../../graphql/mutations.generated'; import { useGetSearchResultsLazyQuery } from '../../../../../../../graphql/search.generated'; import { GetOwnerRecommendation } from '../../../../../../shared/recommendation'; -import ClickOutside from '../../../../../../shared/ClickOutside'; import { OwnerLabel } from '../../../../../../shared/OwnerLabel'; const SelectInput = styled(Select)` @@ -24,6 +23,14 @@ const SelectInput = styled(Select)` } `; +const StyleTag = styled(Tag)` + padding: 0px 7px 0px 0px; + margin-right: 3px; + display: flex; + justify-content: start; + align-items: center; +`; + type Props = { urn: string; type: EntityType; @@ -55,7 +62,6 @@ export const AddOwnersModal = ({ const ownershipTypes = OWNERSHIP_DISPLAY_TYPES; const [selectedOwners, setSelectedOwners] = useState([]); const [selectedOwnerType, setSelectedOwnerType] = useState(defaultOwnerType || OwnershipType.None); - const [isFocusedOnInput, setIsFocusedOnInput] = useState(false); // User and group dropdown search results! const [userSearch, { data: userSearchData }] = useGetSearchResultsLazyQuery(); @@ -67,6 +73,14 @@ export const AddOwnersModal = ({ // Add owners Form const [form] = Form.useForm(); + const inputEl = useRef(null); + + useEffect(() => { + if (inputEl && inputEl.current) { + (inputEl.current as any).focus(); + } + }); + const recommendedOwnersData = GetOwnerRecommendation(); useEffect(() => { @@ -113,14 +127,10 @@ export const AddOwnersModal = ({ const ownerResult = !inputValue || inputValue.length === 0 ? recommendedOwnersData : combinedSearchResults; - console.log('isFocusedOnInput::', isFocusedOnInput); const ownerSearchOptions = ownerResult?.map((result) => { return renderSearchResult(result); }); - console.log('ownerSearchOptions::', ownerSearchOptions); - console.log('recommendedOwnersData::', recommendedOwnersData); - const onModalClose = () => { setInputValue(''); setSelectedOwners([]); @@ -134,6 +144,9 @@ export const AddOwnersModal = ({ * value: {ownerUrn: string, ownerEntityType: EntityType} */ const onSelectOwner = (selectedValue: { key: string; label: React.ReactNode; value: string }) => { + if (inputEl && inputEl.current) { + (inputEl.current as any).blur(); + } const filteredActors = ownerResult ?.filter((result) => result.entity.urn === selectedValue.value) .map((result) => result.entity); @@ -158,7 +171,6 @@ export const AddOwnersModal = ({ // When a owner search result is deselected, remove the Owner const onDeselectOwner = (selectedValue: { key: string; label: React.ReactNode; value: string }) => { setInputValue(''); - setIsFocusedOnInput(true); const newValues = selectedOwners.filter((owner) => owner.label !== selectedValue.value); setSelectedOwners(newValues); }; @@ -176,20 +188,9 @@ export const AddOwnersModal = ({ event.stopPropagation(); }; return ( - + {label} - + ); }; @@ -235,7 +236,6 @@ export const AddOwnersModal = ({ function clearInput() { setInputValue(''); - setTimeout(() => setIsFocusedOnInput(true), 0); // call after click outside } function handleBlur() { @@ -260,38 +260,36 @@ export const AddOwnersModal = ({ } > - setIsFocusedOnInput(false)}> - Owner}> - Find a user or group - - onSelectOwner(asset)} - onDeselect={(asset: any) => onDeselectOwner(asset)} - onSearch={(value: string) => { - // eslint-disable-next-line react/prop-types - handleActorSearch(value.trim()); - // eslint-disable-next-line react/prop-types - setInputValue(value.trim()); - }} - tagRender={tagRender} - value={selectedOwners} - onClear={clearInput} - onFocus={() => setIsFocusedOnInput(true)} - onBlur={handleBlur} - > - {ownerSearchOptions} - - + Owner}> + Find a user or group + + onSelectOwner(asset)} + onDeselect={(asset: any) => onDeselectOwner(asset)} + onSearch={(value: string) => { + // eslint-disable-next-line react/prop-types + handleActorSearch(value.trim()); + // eslint-disable-next-line react/prop-types + setInputValue(value.trim()); + }} + tagRender={tagRender} + value={selectedOwners} + onClear={clearInput} + onBlur={handleBlur} + > + {ownerSearchOptions} + - +
{!hideOwnerType && ( Type}> Choose an owner type From e49e704f8284cff0660cbe4ec930a2bcca193af1 Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Wed, 15 Jun 2022 16:28:53 +0530 Subject: [PATCH 12/28] Added recommendation on Domain select --- .../profile/sidebar/Domain/SetDomainModal.tsx | 178 ++++++++++-------- .../sidebar/Domain/SidebarDomainSection.tsx | 2 +- .../src/app/shared/DomainLabel.tsx | 28 ++- .../src/app/shared/recommendation.tsx | 14 ++ 4 files changed, 140 insertions(+), 82 deletions(-) diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx index d0db0fe5be440..4455a48f288b1 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx @@ -1,45 +1,39 @@ -import { Button, Form, message, Modal, Select, Tag } from 'antd'; import React, { useRef, useState } from 'react'; +import { Button, Form, message, Modal, Select, Tag } from 'antd'; import styled from 'styled-components'; -import { Link } from 'react-router-dom'; + import { useGetSearchResultsLazyQuery } from '../../../../../../../graphql/search.generated'; import { EntityType, SearchResult } from '../../../../../../../types.generated'; import { useSetDomainMutation } from '../../../../../../../graphql/mutations.generated'; import { useEntityRegistry } from '../../../../../../useEntityRegistry'; import { useEntityData } from '../../../../EntityContext'; import { useEnterKeyListener } from '../../../../../../shared/useEnterKeyListener'; +import { GetDomainRecommendation } from '../../../../../../shared/recommendation'; +import { DomainLabel } from '../../../../../../shared/DomainLabel'; type Props = { visible: boolean; - onClose: () => void; + onCloseModal: () => void; refetch?: () => Promise; }; -const SearchResultContainer = styled.div` - display: flex; - justify-content: space-between; - align-items: center; - padding: 12px; -`; - -const SearchResultContent = styled.div` - display: flex; - justify-content: start; - align-items: center; -`; - -const SearchResultDisplayName = styled.div` - margin-left: 12px; -`; - type SelectedDomain = { displayName: string; type: EntityType; urn: string; }; -export const SetDomainModal = ({ visible, onClose, refetch }: Props) => { +const StyleTag = styled(Tag)` + padding: 0px 7px; + margin-right: 3px; + display: flex; + justify-content: start; + align-items: center; +`; + +export const SetDomainModal = ({ visible, onCloseModal, refetch }: Props) => { const entityRegistry = useEntityRegistry(); + const [inputValue, setInputValue] = useState(''); const { urn } = useEntityData(); const [selectedDomain, setSelectedDomain] = useState(undefined); const [domainSearch, { data: domainSearchData }] = useGetSearchResultsLazyQuery(); @@ -48,35 +42,45 @@ export const SetDomainModal = ({ visible, onClose, refetch }: Props) => { const inputEl = useRef(null); - const onOk = async () => { - if (!selectedDomain) { - return; - } - try { - await setDomainMutation({ + const recommendedDomainsData = GetDomainRecommendation(); + + const handleSearch = (text: string) => { + if (text.length > 2) { + domainSearch({ variables: { - entityUrn: urn, - domainUrn: selectedDomain.urn, + input: { + type: EntityType.Domain, + query: text, + start: 0, + count: 5, + }, }, }); - message.success({ content: 'Updated Domain!', duration: 2 }); - } catch (e: unknown) { - message.destroy(); - if (e instanceof Error) { - message.error({ content: `Failed to set Domain: \n ${e.message || ''}`, duration: 3 }); - } } - setSelectedDomain(undefined); - refetch?.(); - onClose(); }; + // Renders a search result in the select dropdown. + const renderSearchResult = (result: SearchResult) => { + const displayName = entityRegistry.getDisplayName(result.entity.type, result.entity); + return ( + + + + ); + }; + + const domainResult = !inputValue || inputValue.length === 0 ? recommendedDomainsData : domainSearchResults; + + const domainSearchOptions = domainResult?.map((result) => { + return renderSearchResult(result); + }); + const onSelectDomain = (newUrn: string) => { if (inputEl && inputEl.current) { (inputEl.current as any).blur(); } const filteredDomains = - domainSearchResults?.filter((result) => result.entity.urn === newUrn).map((result) => result.entity) || []; + domainResult?.filter((result) => result.entity.urn === newUrn).map((result) => result.entity) || []; if (filteredDomains.length) { const domain = filteredDomains[0]; setSelectedDomain({ @@ -87,56 +91,66 @@ export const SetDomainModal = ({ visible, onClose, refetch }: Props) => { } }; - const handleSearch = (text: string) => { - if (text.length > 2) { - domainSearch({ + const onOk = async () => { + if (!selectedDomain) { + return; + } + try { + await setDomainMutation({ variables: { - input: { - type: EntityType.Domain, - query: text, - start: 0, - count: 5, - }, + entityUrn: urn, + domainUrn: selectedDomain.urn, }, }); + message.success({ content: 'Updated Domain!', duration: 2 }); + } catch (e: unknown) { + message.destroy(); + if (e instanceof Error) { + message.error({ content: `Failed to set Domain: \n ${e.message || ''}`, duration: 3 }); + } } + setSelectedDomain(undefined); + refetch?.(); + onCloseModal(); + }; + + const tagRender = (props) => { + // eslint-disable-next-line react/prop-types + const { label, closable, onClose } = props; + const onPreventMouseDown = (event) => { + event.preventDefault(); + event.stopPropagation(); + }; + return ( + + {label} + + ); }; + const selectValue = (selectedDomain && [selectedDomain?.displayName]) || []; + // Handle the Enter press useEnterKeyListener({ querySelectorToExecuteClick: '#setDomainButton', }); - const renderSearchResult = (result: SearchResult) => { - const displayName = entityRegistry.getDisplayName(result.entity.type, result.entity); - return ( - - - -
{displayName}
-
-
- `/${entityRegistry.getPathName(result.entity.type)}/${result.entity.urn}`} - > - View - {' '} -
- ); - }; + function clearInput() { + setInputValue(''); + } - const selectValue = (selectedDomain && [selectedDomain?.displayName]) || []; + function handleBlur() { + setInputValue(''); + } return ( - - { - setShowAddModal(false); - }} - /> + {showAddModal && ( + { + setShowAddModal(false); + }} + /> + )} ); }; From 969095afa52fc2ee9148e6ae464472f80a0a4ce7 Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Fri, 24 Jun 2022 10:51:44 +0530 Subject: [PATCH 20/28] Optimize the code --- .../entity/group/GroupOwnerSideBarSection.tsx | 21 ++++++++++--------- .../profile/sidebar/Domain/SetDomainModal.tsx | 5 ++--- .../sidebar/Domain/SidebarDomainSection.tsx | 1 - .../sidebar/Ownership/AddOwnersModal.tsx | 13 ++---------- .../sidebar/Ownership/SidebarOwnerSection.tsx | 1 - .../src/app/shared/TagStyleEntity.tsx | 21 ++++++++++--------- 6 files changed, 26 insertions(+), 36 deletions(-) diff --git a/datahub-web-react/src/app/entity/group/GroupOwnerSideBarSection.tsx b/datahub-web-react/src/app/entity/group/GroupOwnerSideBarSection.tsx index 1708d6f5aa62b..2cf84bc375c0c 100644 --- a/datahub-web-react/src/app/entity/group/GroupOwnerSideBarSection.tsx +++ b/datahub-web-react/src/app/entity/group/GroupOwnerSideBarSection.tsx @@ -50,16 +50,17 @@ export default function GroupOwnerSideBarSection({ urn, ownership, refetch }: Pr )} - { - setShowAddModal(false); - }} - /> + {showAddModal && ( + { + setShowAddModal(false); + }} + /> + )} ); } diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx index a5d0348833358..5a1a082982e78 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx @@ -12,7 +12,6 @@ import { useGetRecommendations } from '../../../../../../shared/recommendation'; import { DomainLabel } from '../../../../../../shared/DomainLabel'; type Props = { - visible: boolean; onCloseModal: () => void; refetch?: () => Promise; }; @@ -31,7 +30,7 @@ const StyleTag = styled(Tag)` align-items: center; `; -export const SetDomainModal = ({ visible, onCloseModal, refetch }: Props) => { +export const SetDomainModal = ({ onCloseModal, refetch }: Props) => { const entityRegistry = useEntityRegistry(); const { urn } = useEntityData(); const [inputValue, setInputValue] = useState(''); @@ -140,7 +139,7 @@ export const SetDomainModal = ({ visible, onCloseModal, refetch }: Props) => { return ( diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection.tsx index 7b5171b115c56..f8e574dd025f4 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SidebarDomainSection.tsx @@ -75,7 +75,6 @@ export const SidebarDomainSection = () => { {showModal && ( { setShowModal(false); diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx index 8bf2544c02ed8..b89f86c067855 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Ownership/AddOwnersModal.tsx @@ -28,7 +28,6 @@ const StyleTag = styled(Tag)` type Props = { urn: string; type: EntityType; - visible: boolean; defaultOwnerType?: OwnershipType; hideOwnerType?: boolean | undefined; onCloseModal: () => void; @@ -41,15 +40,7 @@ type SelectedOwner = { value; }; -export const AddOwnersModal = ({ - urn, - type, - visible, - hideOwnerType, - defaultOwnerType, - onCloseModal, - refetch, -}: Props) => { +export const AddOwnersModal = ({ urn, type, hideOwnerType, defaultOwnerType, onCloseModal, refetch }: Props) => { const entityRegistry = useEntityRegistry(); const [inputValue, setInputValue] = useState(''); const [addOwnersMutation] = useAddOwnersMutation(); @@ -219,7 +210,7 @@ export const AddOwnersModal = ({ return ( { defaultOwnerType={properties?.defaultOwnerType} hideOwnerType={properties?.hideOwnerType || false} type={entityType} - visible={showAddModal} refetch={refetch} onCloseModal={() => { setShowAddModal(false); diff --git a/datahub-web-react/src/app/shared/TagStyleEntity.tsx b/datahub-web-react/src/app/shared/TagStyleEntity.tsx index 23460ccef8dc9..7a246d9ed839e 100644 --- a/datahub-web-react/src/app/shared/TagStyleEntity.tsx +++ b/datahub-web-react/src/app/shared/TagStyleEntity.tsx @@ -414,16 +414,17 @@ export default function TagStyleEntity({ urn, useGetSearchResults = useWrappedSe
- { - setShowAddModal(false); - }} - urn={urn} - type={EntityType.Tag} - /> + {showAddModal && ( + { + setShowAddModal(false); + }} + urn={urn} + type={EntityType.Tag} + /> + )}
From 027283f39a9e99051dbfb6f1e97321c0a87d6452 Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Fri, 24 Jun 2022 11:51:06 +0530 Subject: [PATCH 21/28] Optimize the code --- .../containers/profile/sidebar/Domain/SetDomainModal.tsx | 4 +--- .../containers/profile/sidebar/Ownership/AddOwnersModal.tsx | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx index 5a1a082982e78..2a22b283902bd 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx @@ -40,12 +40,10 @@ export const SetDomainModal = ({ onCloseModal, refetch }: Props) => { domainSearchData?.search?.searchResults?.map((searchResult) => searchResult.entity) || []; const [setDomainMutation] = useSetDomainMutation(); const [recommendedData] = useGetRecommendations([EntityType.Domain]); - const [form] = Form.useForm(); const onModalClose = () => { setInputValue(''); setSelectedDomain(undefined); - form.resetFields(); onCloseModal(); }; @@ -152,7 +150,7 @@ export const SetDomainModal = ({ onCloseModal, refetch }: Props) => { } > - + onSelectDomain(domainUrn)} @@ -163,6 +168,7 @@ export const SetDomainModal = ({ onCloseModal, refetch }: Props) => { // eslint-disable-next-line react/prop-types setInputValue(value.trim()); }} + ref={inputEl} value={selectValue} tagRender={tagRender} > From f7ffb2267f59ff59b70e2cb1b0a5bc465a5ae201 Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Fri, 24 Jun 2022 23:47:04 +0530 Subject: [PATCH 25/28] Worked on defocusing from select after select --- .../profile/sidebar/Domain/SetDomainModal.tsx | 3 +- .../sidebar/Ownership/AddOwnersModal.tsx | 12 ++++++- .../src/app/shared/tags/AddTagsTermsModal.tsx | 31 ++++++++++++++++--- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx index 8322faf4f17b0..7fa0bcf7e0e77 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx @@ -40,6 +40,7 @@ export const SetDomainModal = ({ onCloseModal, refetch }: Props) => { domainSearchData?.search?.searchResults?.map((searchResult) => searchResult.entity) || []; const [setDomainMutation] = useSetDomainMutation(); const [recommendedData] = useGetRecommendations([EntityType.Domain]); + const inputEl = useRef(null); const onModalClose = () => { setInputValue(''); @@ -78,7 +79,6 @@ export const SetDomainModal = ({ onCloseModal, refetch }: Props) => { return renderSearchResult(result); }); - const inputEl = useRef(null); const onSelectDomain = (newUrn: string) => { if (inputEl && inputEl.current) { (inputEl.current as any).blur(); @@ -158,7 +158,6 @@ export const SetDomainModal = ({ onCloseModal, refetch }: Props) => { onSelectDomain(domainUrn)} onSearch={(value: string) => { @@ -170,6 +177,7 @@ export const SetDomainModal = ({ onCloseModal, refetch }: Props) => { ref={inputEl} value={selectValue} tagRender={tagRender} + onBlur={handleBlur} > {domainSearchOptions} From 73d52756030e6e80cca625d80fe32b0b1e4f9ec5 Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Sat, 25 Jun 2022 00:43:08 +0530 Subject: [PATCH 27/28] Fixed logo issue --- .../containers/profile/sidebar/Domain/SetDomainModal.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx index 4e03523ceaac9..afd634326cd8b 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/sidebar/Domain/SetDomainModal.tsx @@ -94,6 +94,11 @@ export const SetDomainModal = ({ onCloseModal, refetch }: Props) => { } }; + const onDeselectDomain = () => { + setInputValue(''); + setSelectedDomain(undefined); + }; + const onOk = async () => { if (!selectedDomain) { return; @@ -165,9 +170,11 @@ export const SetDomainModal = ({ onCloseModal, refetch }: Props) => { defaultOpen filterOption={false} showSearch + mode="multiple" defaultActiveFirstOption={false} placeholder="Search for Domains..." onSelect={(domainUrn: any) => onSelectDomain(domainUrn)} + onDeselect={onDeselectDomain} onSearch={(value: string) => { // eslint-disable-next-line react/prop-types handleSearch(value.trim()); From fda9da02209b59247411309ae8f6ded3f3b126f5 Mon Sep 17 00:00:00 2001 From: Ankit Keshari Date: Tue, 28 Jun 2022 11:48:12 +0530 Subject: [PATCH 28/28] Create Tag test --- datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx b/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx index 7216c656b22f3..9101ad34029d0 100644 --- a/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx +++ b/datahub-web-react/src/app/shared/tags/AddTagsTermsModal.tsx @@ -178,9 +178,6 @@ export default function AddTagsTermsModal({ // When a Tag or term search result is selected, add the urn to the Urns const onSelectValue = (urn: string) => { - if (inputEl && inputEl.current) { - (inputEl.current as any).blur(); - } if (urn === CREATE_TAG_VALUE) { setShowCreateModal(true); return; @@ -203,6 +200,9 @@ export default function AddTagsTermsModal({ ), }, ]); + if (inputEl && inputEl.current) { + (inputEl.current as any).blur(); + } }; // When a Tag or term search result is deselected, remove the urn from the Owners