From f59b21e951bfad9d8f79b665771eff43dba8a2bc Mon Sep 17 00:00:00 2001 From: Ankit keshari <86347578+Ankit-Keshari-Vituity@users.noreply.github.com> Date: Tue, 26 Jul 2022 05:04:15 +0530 Subject: [PATCH] refactor(ui): Adding checkbox option to select multiple results at once. (#5422) --- .../styled/search/EmbeddedListSearch.tsx | 11 +- .../search/EmbeddedListSearchHeader.tsx | 37 +++- .../search/EmbeddedListSearchResults.tsx | 10 + .../styled/search/SearchActionMenu.tsx | 55 ++++++ .../styled/search/SearchExtendedMenu.tsx | 27 ++- .../src/app/preview/DefaultPreviewCard.tsx | 11 +- .../renderer/component/EntityNameList.tsx | 172 +++++++++++++----- .../src/app/shared/tags/TagTermGroup.tsx | 2 +- 8 files changed, 273 insertions(+), 52 deletions(-) create mode 100644 datahub-web-react/src/app/entity/shared/components/styled/search/SearchActionMenu.tsx diff --git a/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearch.tsx b/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearch.tsx index 17c58a2e7e..313f940b30 100644 --- a/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearch.tsx +++ b/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearch.tsx @@ -4,6 +4,7 @@ import { useHistory, useLocation, useParams } from 'react-router'; import { message } from 'antd'; import styled from 'styled-components'; import { ApolloError } from '@apollo/client'; +import type { CheckboxValueType } from 'antd/es/checkbox/Group'; import { useEntityRegistry } from '../../../../../useEntityRegistry'; import { EntityType, FacetFilterInput } from '../../../../../../types.generated'; @@ -97,6 +98,9 @@ export const EmbeddedListSearch = ({ const [showFilters, setShowFilters] = useState(defaultShowFilters || false); + const [showSelectMode, setShowSelectMode] = useState(false); + const [checkedSearchResults, setCheckedSearchResults] = useState([]); + const { refetch } = useGetSearchResults({ variables: { input: { @@ -184,11 +188,13 @@ export const EmbeddedListSearch = ({ onSearch={onSearch} placeholderText={placeholderText} onToggleFilters={toggleFilters} - showDownloadCsvButton callSearchOnVariables={callSearchOnVariables} entityFilters={entityFilters} filters={finalFilters} query={query} + showSelectMode={showSelectMode} + setShowSelectMode={setShowSelectMode} + checkedSearchResults={checkedSearchResults} /> ); diff --git a/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearchHeader.tsx b/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearchHeader.tsx index 9dfe3a93b1..a02963083d 100644 --- a/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearchHeader.tsx +++ b/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearchHeader.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { Button, Typography } from 'antd'; -import { FilterOutlined } from '@ant-design/icons'; +import { CloseCircleOutlined, FilterOutlined } from '@ant-design/icons'; +import type { CheckboxValueType } from 'antd/es/checkbox/Group'; import styled from 'styled-components'; import TabToolbar from '../TabToolbar'; import { SearchBar } from '../../../../../search/SearchBar'; @@ -8,6 +9,7 @@ import { useEntityRegistry } from '../../../../../useEntityRegistry'; import { EntityType, FacetFilterInput, SearchAcrossEntitiesInput } from '../../../../../../types.generated'; import { SearchResultsInterface } from './types'; import SearchExtendedMenu from './SearchExtendedMenu'; +// import SearchActionMenu from './SearchActionMenu'; const HeaderContainer = styled.div` display: flex; @@ -25,28 +27,38 @@ const SearchMenuContainer = styled.div` margin-left: 10px; `; +const SelectedText = styled(Typography.Text)` + width: 70px; + top: 5px; + position: relative; +`; + type Props = { onSearch: (q: string) => void; onToggleFilters: () => void; placeholderText?: string | null; - showDownloadCsvButton?: boolean; callSearchOnVariables: (variables: { input: SearchAcrossEntitiesInput; }) => Promise; entityFilters: EntityType[]; filters: FacetFilterInput[]; query: string; + setShowSelectMode: (showSelectMode: boolean) => any; + showSelectMode: boolean; + checkedSearchResults: CheckboxValueType[]; }; export default function EmbeddedListSearchHeader({ onSearch, onToggleFilters, placeholderText, - showDownloadCsvButton, callSearchOnVariables, entityFilters, filters, query, + setShowSelectMode, + showSelectMode, + checkedSearchResults, }: Props) { const entityRegistry = useEntityRegistry(); @@ -62,6 +74,7 @@ export default function EmbeddedListSearchHeader({ Filters + {showSelectMode && {`${checkedSearchResults.length} selected`}} {/* TODO: in the future, when we add more menu items, we'll show this always */} - {showDownloadCsvButton && ( + {showSelectMode ? ( + <> + + {/* + + */} + + ) : ( )} diff --git a/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearchResults.tsx b/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearchResults.tsx index 50c1d95788..1b02f37d03 100644 --- a/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearchResults.tsx +++ b/datahub-web-react/src/app/entity/shared/components/styled/search/EmbeddedListSearchResults.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { Pagination, Typography } from 'antd'; import styled from 'styled-components'; +import type { CheckboxValueType } from 'antd/es/checkbox/Group'; import { FacetFilterInput, FacetMetadata, SearchResults as SearchResultType } from '../../../../../../types.generated'; import { SearchFilters } from '../../../../../search/SearchFilters'; import { SearchCfg } from '../../../../../../conf'; @@ -94,6 +95,9 @@ interface Props { showFilters?: boolean; onChangeFilters: (filters: Array) => void; onChangePage: (page: number) => void; + showSelectMode: boolean; + setCheckedSearchResults: (checkedSearchResults: Array) => any; + checkedSearchResults: CheckboxValueType[]; } export const EmbeddedListSearchResults = ({ @@ -105,6 +109,9 @@ export const EmbeddedListSearchResults = ({ showFilters, onChangeFilters, onChangePage, + showSelectMode, + setCheckedSearchResults, + checkedSearchResults, }: Props) => { const pageStart = searchResponse?.start || 0; const pageSize = searchResponse?.count || 0; @@ -151,6 +158,9 @@ export const EmbeddedListSearchResults = ({ degree: searchResult['degree'], })) || [] } + showSelectMode={showSelectMode} + setCheckedSearchResults={setCheckedSearchResults} + checkedSearchResults={checkedSearchResults} /> )} diff --git a/datahub-web-react/src/app/entity/shared/components/styled/search/SearchActionMenu.tsx b/datahub-web-react/src/app/entity/shared/components/styled/search/SearchActionMenu.tsx new file mode 100644 index 0000000000..1734fced24 --- /dev/null +++ b/datahub-web-react/src/app/entity/shared/components/styled/search/SearchActionMenu.tsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { Button, Dropdown, Menu } from 'antd'; +import { MoreOutlined, PlusOutlined } from '@ant-design/icons'; +import styled from 'styled-components'; +import type { CheckboxValueType } from 'antd/es/checkbox/Group'; + +const MenuIcon = styled(MoreOutlined)` + font-size: 15px; + height: 20px; +`; + +const SelectButton = styled(Button)` + font-size: 12px; + padding-left: 12px; + padding-right: 12px; +`; + +type Props = { + checkedSearchResults: CheckboxValueType[]; +}; + +// currently only contains Download As Csv but will be extended to contain other actions as well +export default function SearchActionMenu({ checkedSearchResults }: Props) { + console.log('checkedSearchResults:: ', checkedSearchResults); + const menu = ( + + + + + Add Tags + + + + + + Add Terms + + + + + + Add Owners + + + + ); + + return ( + <> + + + + + ); +} diff --git a/datahub-web-react/src/app/entity/shared/components/styled/search/SearchExtendedMenu.tsx b/datahub-web-react/src/app/entity/shared/components/styled/search/SearchExtendedMenu.tsx index 363d4da1c2..0066fc0991 100644 --- a/datahub-web-react/src/app/entity/shared/components/styled/search/SearchExtendedMenu.tsx +++ b/datahub-web-react/src/app/entity/shared/components/styled/search/SearchExtendedMenu.tsx @@ -1,6 +1,8 @@ import React, { useState } from 'react'; import { Dropdown, Menu } from 'antd'; import { MoreOutlined } from '@ant-design/icons'; +// import { Button, Dropdown, Menu } from 'antd'; +// import { MoreOutlined, SelectOutlined } from '@ant-design/icons'; import styled from 'styled-components'; import { EntityType, FacetFilterInput, SearchAcrossEntitiesInput } from '../../../../../../types.generated'; import { SearchResultsInterface } from './types'; @@ -12,6 +14,12 @@ const MenuIcon = styled(MoreOutlined)` height: 20px; `; +// const SelectButton = styled(Button)` +// font-size: 12px; +// padding-left: 12px; +// padding-right: 12px; +// `; + type Props = { callSearchOnVariables: (variables: { input: SearchAcrossEntitiesInput; @@ -19,13 +27,22 @@ type Props = { entityFilters: EntityType[]; filters: FacetFilterInput[]; query: string; + setShowSelectMode?: (showSelectMode: boolean) => any; }; // currently only contains Download As Csv but will be extended to contain other actions as well -export default function SearchExtendedMenu({ callSearchOnVariables, entityFilters, filters, query }: Props) { +export default function SearchExtendedMenu({ + callSearchOnVariables, + entityFilters, + filters, + query, + setShowSelectMode, +}: Props) { const [isDownloadingCsv, setIsDownloadingCsv] = useState(false); const [showDownloadAsCsvModal, setShowDownloadAsCsvModal] = useState(false); + // TO DO: Need to implement Select Mode + console.log('setShowSelectMode:', setShowSelectMode); const menu = ( @@ -34,6 +51,14 @@ export default function SearchExtendedMenu({ callSearchOnVariables, entityFilter setShowDownloadAsCsvModal={setShowDownloadAsCsvModal} /> + {/* + {setShowSelectMode && ( + setShowSelectMode(true)}> + + Select... + + )} + */} ); diff --git a/datahub-web-react/src/app/preview/DefaultPreviewCard.tsx b/datahub-web-react/src/app/preview/DefaultPreviewCard.tsx index c95cc37b58..d0c07082a0 100644 --- a/datahub-web-react/src/app/preview/DefaultPreviewCard.tsx +++ b/datahub-web-react/src/app/preview/DefaultPreviewCard.tsx @@ -10,11 +10,11 @@ import { GlossaryTerms, SearchInsight, Container, - Domain, ParentContainersResult, Maybe, CorpUser, Deprecation, + Domain, } from '../../types.generated'; import TagTermGroup from '../shared/tags/TagTermGroup'; import { ANTD_GRAY } from '../entity/shared/constants'; @@ -176,7 +176,7 @@ interface Props { insights?: Array | null; glossaryTerms?: GlossaryTerms; container?: Container; - domain?: Domain | null; + domain?: Domain | undefined | null; entityCount?: number; dataTestID?: string; titleSizePx?: number; @@ -239,8 +239,13 @@ export default function DefaultPreviewCard({ const { parentContainersRef, areContainersTruncated } = useParentContainersTruncation(container); + const onPreventMouseDown = (event) => { + event.preventDefault(); + event.stopPropagation(); + }; + return ( - + .ant-checkbox-group-item { + display: block; + margin-right: 0; + } + &&& .ant-checkbox { + display: inline-block; + position: relative; + top: 48px; + } +`; + +const LabelContainer = styled.span` + position: relative; + left: 24px; + bottom: 6px; + * { + pointer-events: none; + } +`; + type Props = { // additional data about the search result that is not part of the entity used to enrich the // presentation of the entity. For example, metadata about how the entity is related for the case @@ -60,9 +89,19 @@ type Props = { additionalPropertiesList?: Array; entities: Array; onClick?: (index: number) => void; + showSelectMode?: boolean; + setCheckedSearchResults?: (checkedSearchResults: Array) => any; + checkedSearchResults?: CheckboxValueType[]; }; -export const EntityNameList = ({ additionalPropertiesList, entities, onClick }: Props) => { +export const EntityNameList = ({ + additionalPropertiesList, + entities, + onClick, + showSelectMode, + setCheckedSearchResults, + checkedSearchResults, +}: Props) => { const entityRegistry = useEntityRegistry(); if ( additionalPropertiesList?.length !== undefined && @@ -74,46 +113,95 @@ export const EntityNameList = ({ additionalPropertiesList, entities, onClick }: { additionalPropertiesList, entities }, ); } + + const onChange = (checkedValues: CheckboxValueType[]) => { + setCheckedSearchResults?.(checkedValues); + }; + + const options = entities.map((entity, index) => { + const additionalProperties = additionalPropertiesList?.[index]; + const genericProps = entityRegistry.getGenericEntityProperties(entity.type, entity); + const platformLogoUrl = genericProps?.platform?.properties?.logoUrl; + const platformName = + genericProps?.platform?.properties?.displayName || capitalizeFirstLetter(genericProps?.platform?.name); + const entityTypeName = entityRegistry.getEntityName(entity.type); + const displayName = entityRegistry.getDisplayName(entity.type, entity); + const url = entityRegistry.getEntityUrl(entity.type, entity.urn); + const fallbackIcon = entityRegistry.getIcon(entity.type, 18, IconStyleType.ACCENT); + const subType = genericProps?.subTypes?.typeNames?.length && genericProps?.subTypes?.typeNames[0]; + const entityCount = genericProps?.entityCount; + return { + label: ( + + onClick?.(index)} + entityCount={entityCount} + degree={additionalProperties?.degree} + /> + + + ), + value: entity.urn, + }; + }); + return ( - { - const additionalProperties = additionalPropertiesList?.[index]; - const genericProps = entityRegistry.getGenericEntityProperties(entity.type, entity); - const platformLogoUrl = genericProps?.platform?.properties?.logoUrl; - const platformName = - genericProps?.platform?.properties?.displayName || - capitalizeFirstLetter(genericProps?.platform?.name); - const entityTypeName = entityRegistry.getEntityName(entity.type); - const displayName = entityRegistry.getDisplayName(entity.type, entity); - const url = entityRegistry.getEntityUrl(entity.type, entity.urn); - const fallbackIcon = entityRegistry.getIcon(entity.type, 18, IconStyleType.ACCENT); - const subType = genericProps?.subTypes?.typeNames?.length && genericProps?.subTypes?.typeNames[0]; - const entityCount = genericProps?.entityCount; - return ( - <> - - onClick?.(index)} - entityCount={entityCount} - degree={additionalProperties?.degree} - /> - - - - ); - }} - /> + <> + {showSelectMode ? ( + + ) : ( + { + const additionalProperties = additionalPropertiesList?.[index]; + const genericProps = entityRegistry.getGenericEntityProperties(entity.type, entity); + const platformLogoUrl = genericProps?.platform?.properties?.logoUrl; + const platformName = + genericProps?.platform?.properties?.displayName || + capitalizeFirstLetter(genericProps?.platform?.name); + const entityTypeName = entityRegistry.getEntityName(entity.type); + const displayName = entityRegistry.getDisplayName(entity.type, entity); + const url = entityRegistry.getEntityUrl(entity.type, entity.urn); + const fallbackIcon = entityRegistry.getIcon(entity.type, 18, IconStyleType.ACCENT); + const subType = + genericProps?.subTypes?.typeNames?.length && genericProps?.subTypes?.typeNames[0]; + const entityCount = genericProps?.entityCount; + return ( + <> + + onClick?.(index)} + entityCount={entityCount} + degree={additionalProperties?.degree} + /> + + + + ); + }} + /> + )} + ); }; diff --git a/datahub-web-react/src/app/shared/tags/TagTermGroup.tsx b/datahub-web-react/src/app/shared/tags/TagTermGroup.tsx index 0f74072739..f7667149be 100644 --- a/datahub-web-react/src/app/shared/tags/TagTermGroup.tsx +++ b/datahub-web-react/src/app/shared/tags/TagTermGroup.tsx @@ -26,7 +26,7 @@ type Props = { editableTags?: GlobalTags | null; editableGlossaryTerms?: GlossaryTerms | null; uneditableGlossaryTerms?: GlossaryTerms | null; - domain?: Domain | null; + domain?: Domain | undefined | null; canRemove?: boolean; canAddTag?: boolean; canAddTerm?: boolean;