diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-cancel-outline.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-cancel-outline.svg new file mode 100644 index 00000000000..98de743bd6e --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-cancel-outline.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataAssets/DataAssetsHeader/DataAssetsHeader.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataAssets/DataAssetsHeader/DataAssetsHeader.component.tsx index c963b7cab46..f8cbeb90a2b 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataAssets/DataAssetsHeader/DataAssetsHeader.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataAssets/DataAssetsHeader/DataAssetsHeader.component.tsx @@ -11,7 +11,16 @@ * limitations under the License. */ import Icon from '@ant-design/icons'; -import { Button, Col, Divider, Row, Space, Tooltip, Typography } from 'antd'; +import { + Button, + Col, + Divider, + Row, + Space, + Tag, + Tooltip, + Typography, +} from 'antd'; import ButtonGroup from 'antd/lib/button/button-group'; import { AxiosError } from 'axios'; import classNames from 'classnames'; @@ -46,6 +55,7 @@ import { import { ServiceCategory } from '../../../enums/service.enum'; import { LineageLayer } from '../../../generated/configuration/lineageSettings'; import { Container } from '../../../generated/entity/data/container'; +import { ContractExecutionStatus } from '../../../generated/entity/data/dataContract'; import { Table } from '../../../generated/entity/data/table'; import { Thread } from '../../../generated/entity/feed/thread'; import { useApplicationStore } from '../../../hooks/useApplicationStore'; @@ -62,6 +72,7 @@ import { import EntityLink from '../../../utils/EntityLink'; import entityUtilClassBase from '../../../utils/EntityUtilClassBase'; import { + getDataContractStatusIcon, getEntityFeedLink, getEntityName, getEntityVoteStatus, @@ -100,6 +111,7 @@ export const DataAssetsHeader = ({ showDomain = true, afterDeleteAction, dataAsset, + dataContract, onUpdateVote, onOwnerUpdate, onTierUpdate, @@ -421,6 +433,25 @@ export const DataAssetsHeader = ({ selectedUserSuggestions, ]); + const dataContractLatestResultButton = useMemo(() => { + if (dataContract?.latestResult?.status === ContractExecutionStatus.Failed) { + return ( + + {getDataContractStatusIcon(dataContract?.latestResult?.status)} + {t('label.entity-failed', { + entity: t('label.contract'), + })} + + ); + } + + return null; + }, [dataContract]); + const triggerTheAutoPilotApplication = useCallback(async () => { try { setIsAutoPilotTriggering(true); @@ -517,6 +548,8 @@ export const DataAssetsHeader = ({ data-testid="asset-header-btn-group" size="small"> {triggerAutoPilotApplicationButton} + {dataContractLatestResultButton} + {onUpdateVote && ( { + if (!latestContractResults) { + return DefaultIcon; + } + const isRuleFailed = + latestContractResults?.semanticsValidation?.failedRules?.find( + (rule) => rule.ruleName === semanticName + ); + + if (isRuleFailed) { + return FailIcon; + } + + return CheckIcon; + }; + const getTestCaseStatusIcon = (record: TestCase) => ( ) : ( - constraintStatus.map((item) => ( -
-
- + <> + {latestContractResults?.result && ( + + )} -
- - {item.label} - -
- - {item.desc} - - - {item.time} + {constraintStatus.map((item) => ( +
+
+ + +
+ + {item.label} +
+ + {item.desc} + + + {item.time} + +
-
- -
- )) + +
+ ))} + )} @@ -450,7 +480,12 @@ const ContractDetail: React.FC<{
{(contract?.semantics ?? []).map((item) => (
- + {item.name}{' '} {item.description} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataContract/ContractSemanticFormTab/ContractSemanticFormTab.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataContract/ContractSemanticFormTab/ContractSemanticFormTab.tsx index 7688b912498..4d06b1b2d90 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataContract/ContractSemanticFormTab/ContractSemanticFormTab.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataContract/ContractSemanticFormTab/ContractSemanticFormTab.tsx @@ -12,12 +12,14 @@ */ import Icon, { ArrowLeftOutlined, ArrowRightOutlined } from '@ant-design/icons'; +import { Actions } from '@react-awesome-query-builder/antd'; import { FieldErrorProps } from '@rjsf/utils'; import { Button, Col, Form, Input, Row, Switch, Typography } from 'antd'; import Card from 'antd/lib/card/Card'; import TextArea from 'antd/lib/input/TextArea'; import classNames from 'classnames'; -import { useEffect, useRef, useState } from 'react'; +import { isNull } from 'lodash'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ReactComponent as PlusIcon } from '../../../assets/svg/x-colored.svg'; import { EntityType } from '../../../enums/entity.enum'; @@ -40,25 +42,34 @@ export const ContractSemanticFormTab: React.FC<{ const [form] = Form.useForm(); const semanticsData = Form.useWatch('semantics', form); const [editingKey, setEditingKey] = useState(null); + const [queryBuilderAddRule, setQueryBuilderAddRule] = useState(); const addFunctionRef = useRef<((defaultValue?: any) => void) | null>(null); + const handleAddQueryBuilderRule = (actionFunctions: Actions) => { + setQueryBuilderAddRule(actionFunctions); + }; + const handleAddSemantic = () => { addFunctionRef.current?.({ name: '', description: '', rule: '', - enabled: false, + enabled: true, }); setEditingKey(semanticsData.length); }; + const handleAddNewRule = useCallback(() => { + queryBuilderAddRule?.addRule([]); + }, [queryBuilderAddRule]); + useEffect(() => { form.setFieldsValue({ semantics: [ { name: '', description: '', - enabled: false, + enabled: true, rule: '', }, ], @@ -88,7 +99,7 @@ export const ContractSemanticFormTab: React.FC<{