diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AdvancedSearch/AdvancedSearch.constants.ts b/openmetadata-ui/src/main/resources/ui/src/components/AdvancedSearch/AdvancedSearch.constants.ts index 3f9685a4464..ad878f8f253 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/AdvancedSearch/AdvancedSearch.constants.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/AdvancedSearch/AdvancedSearch.constants.ts @@ -24,6 +24,7 @@ import AntdConfig from 'react-awesome-query-builder/lib/config/antd'; import { suggestQuery } from '../../axiosAPIs/searchAPI'; import { SuggestionField } from '../../enums/AdvancedSearch.enum'; import { SearchIndex } from '../../enums/search.enum'; +import { renderAdvanceSearchButtons } from '../../utils/AdvancedSearchUtils'; const BaseConfig = AntdConfig as BasicConfig; @@ -33,14 +34,27 @@ const BaseConfig = AntdConfig as BasicConfig; export const emptyJsonTree: JsonTree = { id: QbUtils.uuid(), type: 'group', + properties: { + conjunction: 'AND', + not: false, + }, children1: { [QbUtils.uuid()]: { - type: 'rule', + type: 'group', properties: { - field: null, - operator: null, - value: [], - valueSrc: [], + conjunction: 'AND', + not: false, + }, + children1: { + [QbUtils.uuid()]: { + type: 'rule', + properties: { + field: null, + operator: null, + value: [], + valueSrc: [], + }, + }, }, }, }, @@ -66,6 +80,11 @@ export const autocomplete: ( hasMore: false, })); +const mainWidgetProps = { + fullWidth: true, + valueLabel: i18next.t('label.criteria') + ':', +}; + /** * Common fields that exit for all searchable entities */ @@ -83,6 +102,7 @@ const commonQueryBuilderFields: Fields = { name: { label: 'username', type: 'select', + mainWidgetProps, fieldSettings: { asyncFetch: autocomplete([SearchIndex.USER, SearchIndex.TEAM]), }, @@ -90,10 +110,12 @@ const commonQueryBuilderFields: Fields = { displayName: { label: 'name', type: 'text', + mainWidgetProps, }, type: { label: 'type', type: 'select', + mainWidgetProps, fieldSettings: { listValues: [ { value: 'user', title: 'User' }, @@ -107,6 +129,7 @@ const commonQueryBuilderFields: Fields = { 'tags.tagFQN': { label: 'Tags', type: 'select', + mainWidgetProps, fieldSettings: { asyncFetch: autocomplete([SearchIndex.TAG, SearchIndex.GLOSSARY]), }, @@ -115,6 +138,7 @@ const commonQueryBuilderFields: Fields = { 'tier.tagFQN': { label: 'Tier', type: 'select', + mainWidgetProps, fieldSettings: { asyncFetch: autocomplete([SearchIndex.TAG, SearchIndex.GLOSSARY]), }, @@ -132,6 +156,7 @@ const serviceQueryBuilderFields: Fields = { name: { label: 'name', type: 'select', + mainWidgetProps, fieldSettings: { asyncFetch: autocomplete(SearchIndex.TABLE, SuggestionField.SERVICE), }, @@ -156,6 +181,7 @@ const tableQueryBuilderFields: Fields = { name: { label: 'name', type: 'select', + mainWidgetProps, fieldSettings: { asyncFetch: autocomplete(SearchIndex.TABLE, SuggestionField.DATABASE), }, @@ -175,6 +201,7 @@ const tableQueryBuilderFields: Fields = { name: { label: 'name', type: 'select', + mainWidgetProps, fieldSettings: { asyncFetch: autocomplete(SearchIndex.TABLE, SuggestionField.SCHEMA), }, @@ -190,6 +217,7 @@ const tableQueryBuilderFields: Fields = { name: { label: 'Table', type: 'select', + mainWidgetProps, fieldSettings: { asyncFetch: autocomplete(SearchIndex.TABLE, SuggestionField.ROOT), }, @@ -202,6 +230,7 @@ const tableQueryBuilderFields: Fields = { name: { label: 'name', type: 'select', + mainWidgetProps, fieldSettings: { asyncFetch: autocomplete(SearchIndex.TABLE, SuggestionField.COLUMN), }, @@ -209,10 +238,12 @@ const tableQueryBuilderFields: Fields = { dataType: { label: 'data type', type: 'text', + mainWidgetProps, }, constraint: { label: 'constraint', type: 'text', + mainWidgetProps, }, }, }, @@ -287,9 +318,12 @@ const initialConfigWithoutFields: BasicConfig = { ...BaseConfig.settings, showLabels: true, canReorder: false, + renderSize: 'medium', fieldLabel: i18next.t('label.description') + ':', operatorLabel: i18next.t('label.condition') + ':', + showNot: false, valueLabel: i18next.t('label.criteria') + ':', + renderButton: renderAdvanceSearchButtons, }, }; diff --git a/openmetadata-ui/src/main/resources/ui/src/styles/components/react-awesome-query.less b/openmetadata-ui/src/main/resources/ui/src/styles/components/react-awesome-query.less index cb5bbb20899..1786e31d1d7 100644 --- a/openmetadata-ui/src/main/resources/ui/src/styles/components/react-awesome-query.less +++ b/openmetadata-ui/src/main/resources/ui/src/styles/components/react-awesome-query.less @@ -15,41 +15,140 @@ &.query-builder { margin: 0; font: inherit; - } - - .group--children { - padding-left: 0; - } - - .group-or-rule-container { - padding-right: 10px; - padding-left: 10px; - // border: 1px solid #dde3ea; + overflow: visible; } .group-or-rule-container.group-container { - padding: 0px 12px; + padding-right: 0px; } - .group-or-rule-container.group-container, - .group-or-rule-container.rule-container { - .group.group-or-rule, - .rule.group-or-rule { - background: #f9fbfc; - /* table */ - - border: 1px solid #dde3ea; - border-radius: 4px; - box-sizing: border-box; - - &:not(:first-child) { - padding: 16px 8px; + & > .group-or-rule-container.group-container { + & > .group.group-or-rule { + & > .group--header + .group--children { + padding-left: 0; } } - - .rule.group-or-rule { - padding: 0; + } + .group-or-rule-container.group-container { + & > .group.group-or-rule { + background-color: transparent; border: none; + + & > .group--header { + margin: 0; + padding: 0; + + .group--conjunctions { + position: absolute; + left: 0px; + top: 0px; + .ant-btn-group button span { + text-transform: uppercase; + } + } + + .action.action--ADD-RULE { + display: none; + } + .action.action--DELETE { + position: absolute; + top: 10px; + right: 10px; + } + + .action.action--ADD-GROUP { + position: absolute; + bottom: 8px; + z-index: 1; + max-width: 128px; + border-color: #7147e8; + border-radius: 4px; + left: 0; + right: 0; + margin: auto; + } + } + } + } + + .ant-btn-group { + position: initial; + } + + .rule--body { + margin-right: 96px; + } + + .group--children { + padding-top: 22px; + padding-bottom: 22px; + + .group-or-rule-container.group-container, + .group-or-rule-container.rule-container { + .group.group-or-rule, + .rule.group-or-rule { + background: #f9fbfc; + /* table */ + + border: 1px solid #dde3ea; + border-radius: 4px; + box-sizing: border-box; + + &:not(:first-child) { + padding: 16px 8px; + } + } + + .group.group-or-rule { + .group--header { + .group--conjunctions { + position: absolute; + right: 36px; + top: 62px; + left: auto; + z-index: 1; + + .ant-btn-group button span { + text-transform: uppercase; + } + } + + .action.action--ADD-RULE { + position: absolute; + right: 36px; + bottom: 32px; + z-index: 1; + display: block; + border-color: #7147e8; + border-radius: 4px; + } + + .action.action--ADD-GROUP { + display: none; + } + + .action.action--DELETE { + position: absolute; + right: 10px; + bottom: 10px; + z-index: 1; + + font-size: 16px; + } + } + } + + .rule.group-or-rule { + padding: 0; + border: none; + + .rule--header { + .ant-btn-group { + align-self: end; + margin-bottom: 8px; + } + } + } } } } diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchUtils.ts b/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchUtils.tsx similarity index 58% rename from openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchUtils.ts rename to openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchUtils.tsx index d7a18208067..7de7a430095 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchUtils.ts +++ b/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchUtils.tsx @@ -11,7 +11,16 @@ * limitations under the License. */ +import Icon, { + CloseCircleOutlined, + DeleteOutlined, + PlusOutlined, +} from '@ant-design/icons'; +import { Button } from 'antd'; +import i18next from 'i18next'; import { isUndefined } from 'lodash'; +import React from 'react'; +import { RenderSettings } from 'react-awesome-query-builder'; import { ALL_DROPDOWN_ITEMS, COMMON_DROPDOWN_ITEMS, @@ -77,3 +86,56 @@ export const getAdvancedField = (field: string) => { return; } }; + +export const renderAdvanceSearchButtons: RenderSettings['renderButton'] = ( + props +) => { + const type = props?.type; + + if (type === 'delRule') { + return ( + + } + onClick={props?.onClick} + /> + ); + } else if (type === 'addRule') { + return ( + + ); + } else if (type === 'addGroup') { + return ( + + ); + } else if (type === 'delGroup') { + return ( + + } + onClick={props?.onClick} + /> + ); + } + + return <>; +};