Supported Contract Execution Chart Summary Card (#22735)

* Supported the contract execution chart card in Contract Page

* pending localization keys

* minor improvenent around message

* localization keys

* decrease the chart size and fix some localizaion keys

* added contract in persona tab and added beta lable in table contract tab and preference data asset rule tab

* fix some styling around form

(cherry picked from commit 98276fe8adca2da359e829022be3977fa8bbc345)
This commit is contained in:
Ashish Gupta 2025-08-05 10:09:00 +05:30
parent b156cf2390
commit f2fec4df10
34 changed files with 518 additions and 70 deletions

View File

@ -0,0 +1,4 @@
<svg viewBox="0 0 20 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.2979 2C16.9904 2 17.5 2.62979 17.5 3.33399V15.7862C17.5 16.7 16.8405 17.5 15.9639 17.5H3.53613C2.65949 17.5 2 16.7 2 15.7862V3.33399C2 2.62979 2.50964 2 3.20215 2H16.2979ZM2.93945 15.7862C2.93945 16.2108 3.23675 16.5 3.53613 16.5H6.85352V13.875H2.93945V15.7862ZM12.6465 16.5H15.9639C16.2632 16.5 16.5605 16.2108 16.5605 15.7862V13.875H12.6465V16.5ZM7.79297 16.5H11.707V13.875H7.79297V16.5ZM12.6465 12.875H16.5605V10.25H12.6465V12.875ZM7.79297 12.875H11.707V10.25H7.79297V12.875ZM2.93945 12.875H6.85352V10.25H2.93945V12.875ZM12.6465 9.25H16.5605V6.625H12.6465V9.25ZM7.79297 9.25H11.707V6.625H7.79297V9.25ZM2.93945 9.25H6.85352V6.625H2.93945V9.25ZM3.20215 3C3.08694 3 2.93945 3.11897 2.93945 3.33399V5.625H16.5605V3.33399C16.5605 3.11897 16.4131 3 16.2979 3H3.20215Z" fill="currentColor" stroke="currentColor" stroke-width="0.5"/>
</svg>

After

Width:  |  Height:  |  Size: 923 B

View File

@ -19,7 +19,7 @@ import { useTranslation } from 'react-i18next';
import { ReactComponent as ContractIcon } from '../../../assets/svg/ic-contract.svg';
import { ReactComponent as QualityIcon } from '../../../assets/svg/policies.svg';
import { ReactComponent as SemanticsIcon } from '../../../assets/svg/semantics.svg';
import { ReactComponent as TableIcon } from '../../../assets/svg/table-grey.svg';
import { ReactComponent as TableIcon } from '../../../assets/svg/table-outline.svg';
import {
DataContractMode,
EDataContractTab,
@ -220,7 +220,10 @@ const AddDataContract: React.FC<{
</Typography.Paragraph>
</div>
<div>
<Button type="default" onClick={onCancel}>
<Button
className="add-contract-cancel-button"
type="default"
onClick={onCancel}>
{t('label.cancel')}
</Button>
<Button

View File

@ -36,19 +36,28 @@
padding: @size-xs @size-sm;
border: 1px solid @grey-300;
border-radius: 8px;
font-weight: 600;
gap: 4px;
font-weight: @font-semibold;
box-shadow: 0px 1px 2px 0px @grey-27, 0px -2px 0px 0px @grey-27 inset,
0px 0px 0px 1px @grey-27 inset;
box-shadow: 0px 1px 2px 0px @grey-27;
box-shadow: 0px -2px 0px 0px @grey-27 inset;
box-shadow: 0px 0px 0px 1px @grey-27 inset;
.anticon {
margin-top: 2px;
margin-left: 6px;
}
}
.contract-prev-button {
color: @grey-700;
svg {
stroke: @grey-400;
color: @grey-400;
}
&:hover {
background: @grey-100;
svg {
color: @grey-700;
}
}
}
.ant-tabs-left-content {
@ -217,6 +226,7 @@
input[type='text'] {
padding: 8px 14px;
color: @grey-700;
font-weight: 500;
border: 1px solid @grey-300;
border-radius: 8px;
box-shadow: 0 1px 2px 0px @grey-27;
@ -240,6 +250,7 @@
.ant-select-selection-search {
input[type='search'] {
height: 40px;
font-weight: 500;
}
}
}
@ -255,6 +266,21 @@
}
.add-contract-card {
.add-contract-card-header {
.ant-btn.add-contract-cancel-button {
margin-right: 8px;
border: 1px solid @grey-300;
color: @grey-700;
font-weight: 600;
box-shadow: 0px 1px 2px 0px @grey-27, 0px -2px 0px 0px @grey-27 inset,
0px 0px 0px 1px @grey-27 inset;
}
.ant-btn.add-contract-save-button {
font-weight: 600;
}
}
.add-contract-card-title {
font-size: 18px;
font-weight: 600;
@ -280,6 +306,7 @@
color: @grey-700;
box-shadow: 0px 1px 2px 0px @grey-27;
border: 1px solid @grey-300;
font-weight: 500;
}
.ant-select-selector,
@ -287,6 +314,7 @@
border: 1px solid @grey-300;
padding: 4px 12px !important;
color: @grey-700;
font-weight: 500;
height: 40px !important;
box-shadow: 0 1px 2px 0px @grey-27;

View File

@ -10,10 +10,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { PlusOutlined, RightOutlined } from '@ant-design/icons';
import Icon, { PlusOutlined } from '@ant-design/icons';
import { Button, Card, Form, Typography } from 'antd';
import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { ReactComponent as RightIcon } from '../../../assets/svg/right-arrow.svg';
import { DataContract } from '../../../generated/entity/data/dataContract';
import { EntityReference } from '../../../generated/type/entityReference';
import {
@ -118,14 +119,18 @@ export const ContractDetailFormTab: React.FC<{
</Form>
</div>
</Card>
<div className="d-flex justify-end m-t-md">
<div className="d-flex justify-between m-t-md">
<Button className="contract-prev-button" type="default">
{t('label.contract-detail-plural')}
</Button>
<Button
className="contract-next-button"
htmlType="submit"
type="primary"
onClick={onNext}>
{nextLabel ?? t('label.next')}
<RightOutlined height={15} width={8} />
<Icon component={RightIcon} />
</Button>
</div>
</>

View File

@ -28,6 +28,7 @@ import classNames from 'classnames';
import { isEmpty } from 'lodash';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import { Cell, Pie, PieChart } from 'recharts';
import { ReactComponent as EditIcon } from '../../../assets/svg/edit-new-thick.svg';
import { ReactComponent as EmptyContractIcon } from '../../../assets/svg/empty-contract.svg';
@ -67,6 +68,10 @@ import {
} from '../../../utils/DataContract/DataContractUtils';
import { getRelativeTime } from '../../../utils/date-time/DateTimeUtils';
import { getEntityName } from '../../../utils/EntityUtils';
import {
getTestCaseDetailPagePath,
getTestSuitePath,
} from '../../../utils/RouterUtils';
import { pruneEmptyChildren } from '../../../utils/TableUtils';
import { showErrorToast, showSuccessToast } from '../../../utils/ToastUtils';
import AlertBar from '../../AlertBar/AlertBar';
@ -78,6 +83,7 @@ import RichTextEditorPreviewerNew from '../../common/RichTextEditor/RichTextEdit
import { StatusType } from '../../common/StatusBadge/StatusBadge.interface';
import StatusBadgeV2 from '../../common/StatusBadge/StatusBadgeV2.component';
import Table from '../../common/Table/Table';
import ContractExecutionChart from '../ContractExecutionChart/ContractExecutionChart.component';
import ContractViewSwitchTab from '../ContractViewSwitchTab/ContractViewSwitchTab.component';
import ContractYaml from '../ContractYaml/ContractYaml.component';
import './contract-detail.less';
@ -254,16 +260,18 @@ const ContractDetail: React.FC<{
downloadContractYamlFile(contract);
}, [contract]);
const handleRunNow = () => {
const handleRunNow = async () => {
if (contract?.id) {
setValidateLoading(true);
validateContractById(contract.id)
.then(() =>
showSuccessToast('Contract validation trigger successfully.')
)
.finally(() => {
setValidateLoading(false);
});
try {
setValidateLoading(true);
await validateContractById(contract.id);
showSuccessToast(t('message.contract-validation-trigger-successfully'));
fetchLatestContractResults();
} catch (err) {
showErrorToast(err as AxiosError);
} finally {
setValidateLoading(false);
}
}
};
@ -624,42 +632,51 @@ const ContractDetail: React.FC<{
) : (
<div className="data-quality-card-container">
{showTestCaseSummaryChart && (
<div className="data-quality-chart-container">
{testCaseSummaryChartItems.map((item) => (
<div
className="data-quality-chart-item"
key={item.label}>
<Typography.Text className="chart-label">
{item.label}
</Typography.Text>
<Link
className="data-quality-chart-container-link"
to={getTestSuitePath(
contract?.testSuite?.fullyQualifiedName ?? ''
)}>
<div className="data-quality-chart-container">
{testCaseSummaryChartItems.map((item) => (
<div
className="data-quality-chart-item"
key={item.label}>
<Typography.Text className="chart-label">
{item.label}
</Typography.Text>
<PieChart height={120} width={120}>
<Pie
cx="50%"
cy="50%"
data={item.chartData}
dataKey="value"
innerRadius={40}
outerRadius={50}>
{item.chartData.map((entry, index) => (
<Cell
fill={entry.color}
key={`cell-${index}`}
/>
))}
</Pie>
<text
className="chart-center-text"
dominantBaseline="middle"
textAnchor="middle"
x="50%"
y="50%">
{item.value}
</text>
</PieChart>
</div>
))}
</div>
<PieChart
className="data-quality-chart-pie-chart"
height={120}
width={120}>
<Pie
cx="50%"
cy="50%"
data={item.chartData}
dataKey="value"
innerRadius={40}
outerRadius={50}>
{item.chartData.map((entry, index) => (
<Cell
fill={entry.color}
key={`cell-${index}`}
/>
))}
</Pie>
<text
className="chart-center-text"
dominantBaseline="middle"
textAnchor="middle"
x="50%"
y="50%">
{item.value}
</text>
</PieChart>
</div>
))}
</div>{' '}
</Link>
)}
<Space direction="vertical">
@ -670,9 +687,16 @@ const ContractDetail: React.FC<{
key={item.id}>
{getTestCaseStatusIcon(item)}
<div className="data-quality-item-content">
<Typography.Text className="data-quality-item-name">
{item.name}
</Typography.Text>
<Link
className="data-quality-item-name-link"
to={getTestCaseDetailPagePath(
item.fullyQualifiedName ?? ''
)}>
<Typography.Text className="data-quality-item-name">
{item.name}
</Typography.Text>
</Link>
<Typography.Text className="data-quality-item-description">
<RichTextEditorPreviewerNew
markdown={item.description ?? ''}
@ -689,6 +713,13 @@ const ContractDetail: React.FC<{
</ExpandableCard>
</Col>
)}
{/* Contract Execution Chart */}
{contract.id && contract.latestResult?.resultId && (
<Col span={24}>
<ContractExecutionChart contract={contract} />
</Col>
)}
</Row>
</Col>
</Row>

View File

@ -99,6 +99,14 @@
font-size: 14px;
font-weight: 500;
}
&.success {
border-color: @green-16;
}
&.version {
border-color: @purple-7;
}
}
}
}
@ -214,6 +222,16 @@
}
.data-quality-card-container {
.data-quality-chart-pie-chart {
cursor: pointer !important;
}
.data-quality-chart-container-link {
text-decoration: none;
color: @grey-900;
cursor: pointer;
}
.chart-label {
font-size: 16px;
font-weight: 600;
@ -252,12 +270,21 @@
.data-quality-item-content {
display: flex;
flex-direction: column;
}
.data-quality-item-name {
font-size: 14px;
font-weight: 600;
color: @grey-900;
.data-quality-item-name-link {
text-decoration: none;
cursor: pointer;
.data-quality-item-name {
font-size: 14px;
font-weight: 600;
color: @grey-900;
&:hover {
color: @primary-color;
}
}
}
}
.data-quality-item-description {

View File

@ -0,0 +1,25 @@
/*
* Copyright 2025 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { DataContractResult } from '../../../generated/entity/datacontract/dataContractResult';
import { Paging } from '../../../generated/type/paging';
export interface ContractAllResult {
data: DataContractResult[];
paging: Paging;
}
export interface ContractResultFilter {
startTs: number;
endTs: number;
limit?: number;
}

View File

@ -0,0 +1,185 @@
/*
* Copyright 2025 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Tooltip, Typography } from 'antd';
import { AxiosError } from 'axios';
import { isEqual, pick } from 'lodash';
import { DateRangeObject } from 'Models';
import { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
Bar,
BarChart,
CartesianGrid,
Legend,
Rectangle,
ResponsiveContainer,
XAxis,
} from 'recharts';
import { GREEN_3, RED_3, YELLOW_2 } from '../../../constants/Color.constants';
import { PROFILER_FILTER_RANGE } from '../../../constants/profiler.constant';
import { DataContract } from '../../../generated/entity/data/dataContract';
import { DataContractResult } from '../../../generated/entity/datacontract/dataContractResult';
import { ContractExecutionStatus } from '../../../generated/type/contractExecutionStatus';
import { getAllContractResults } from '../../../rest/contractAPI';
import {
formatDateTime,
getCurrentMillis,
getEpochMillisForPastDays,
} from '../../../utils/date-time/DateTimeUtils';
import { showErrorToast } from '../../../utils/ToastUtils';
import DatePickerMenu from '../../common/DatePickerMenu/DatePickerMenu.component';
import ExpandableCard from '../../common/ExpandableCard/ExpandableCard';
import Loader from '../../common/Loader/Loader';
import './contract-execution-chart.less';
const ContractExecutionChart = ({ contract }: { contract: DataContract }) => {
const { t } = useTranslation();
const defaultRange = useMemo(
() => ({
initialRange: {
startTs: getEpochMillisForPastDays(
PROFILER_FILTER_RANGE.last30days.days
),
endTs: getCurrentMillis(),
},
key: 'last30days',
title: PROFILER_FILTER_RANGE.last30days.title,
}),
[]
);
const [contractExecutionResultList, setContractExecutionResultList] =
useState<DataContractResult[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [dateRangeObject, setDateRangeObject] = useState<DateRangeObject>(
defaultRange.initialRange
);
const fetchAllContractResults = async (dateRangeObj: DateRangeObject) => {
try {
setIsLoading(true);
const results = await getAllContractResults(contract.id, {
...pick(dateRangeObj, ['startTs', 'endTs']),
});
setContractExecutionResultList(results.data);
} catch (err) {
showErrorToast(err as AxiosError);
} finally {
setIsLoading(false);
}
};
const processedChartData = useMemo(() => {
return contractExecutionResultList.map((item) => {
return {
name: item.timestamp,
failed:
item.contractExecutionStatus === ContractExecutionStatus.Failed
? 1
: 0,
success:
item.contractExecutionStatus === ContractExecutionStatus.Success
? 1
: 0,
aborted:
item.contractExecutionStatus === ContractExecutionStatus.Aborted
? 1
: 0,
};
});
}, [contractExecutionResultList]);
const handleDateRangeChange = (value: DateRangeObject) => {
if (!isEqual(value, dateRangeObject)) {
setDateRangeObject(value);
}
};
useEffect(() => {
fetchAllContractResults(dateRangeObject);
}, [dateRangeObject]);
return (
<ExpandableCard
cardProps={{
className: 'expandable-card-contract',
title: (
<div className="contract-card-title-container">
<Typography.Text className="contract-card-title">
{t('label.contract-execution-history')}
</Typography.Text>
<Typography.Text className="contract-card-description">
{t('message.contract-execution-history-description')}
</Typography.Text>
</div>
),
}}>
<div className="expandable-card-contract-body contract-execution-chart-container">
{isLoading ? (
<Loader />
) : (
<>
<DatePickerMenu
showSelectedCustomRange
defaultDateRange={pick(defaultRange, ['key', 'title'])}
handleDateRangeChange={handleDateRangeChange}
/>
<ResponsiveContainer height="100%" width="100%">
<BarChart
data={processedChartData}
height={200}
margin={{
top: 5,
right: 30,
left: 20,
bottom: 5,
}}
width={500}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis
dataKey="name"
domain={['min', 'max']}
tickFormatter={formatDateTime}
/>
<Tooltip />
<Legend />
<Bar
activeBar={<Rectangle fill={GREEN_3} stroke={GREEN_3} />}
dataKey="success"
fill={GREEN_3}
name={t('label.success')}
/>
<Bar
activeBar={<Rectangle fill={RED_3} stroke={RED_3} />}
dataKey="failed"
fill={RED_3}
name={t('label.failed')}
/>
<Bar
activeBar={<Rectangle fill={YELLOW_2} stroke={YELLOW_2} />}
dataKey="aborted"
fill={YELLOW_2}
name={t('label.aborted')}
/>
</BarChart>
</ResponsiveContainer>
</>
)}
</div>
</ExpandableCard>
);
};
export default ContractExecutionChart;

View File

@ -0,0 +1,19 @@
/*
* Copyright 2025 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.contract-execution-chart-container {
height: 360px;
display: flex;
flex-direction: column;
gap: 16px;
align-items: end;
}

View File

@ -10,13 +10,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Icon from '@ant-design/icons';
import { Button, Card, Tag, Typography } from 'antd';
import { ColumnsType } from 'antd/lib/table';
import { isEmpty, pick } from 'lodash';
import { Key, useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ReactComponent as LeftOutlined } from '../../../assets/svg/left-arrow.svg';
import { ReactComponent as RightOutlined } from '../../../assets/svg/right-arrow.svg';
import { ReactComponent as RightIcon } from '../../../assets/svg/right-arrow.svg';
import { FQN_SEPARATOR_CHAR } from '../../../constants/char.constants';
import {
NO_DATA_PLACEHOLDER,
@ -313,7 +314,7 @@ export const ContractSchemaFormTab: React.FC<{
type="primary"
onClick={onNext}>
{nextLabel ?? t('label.next')}
<RightOutlined height={15} width={8} />
<Icon component={RightIcon} />
</Button>
</div>
</>

View File

@ -23,7 +23,7 @@ import { useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ReactComponent as DeleteIcon } from '../../../assets/svg/ic-trash.svg';
import { ReactComponent as LeftOutlined } from '../../../assets/svg/left-arrow.svg';
import { ReactComponent as RightOutlined } from '../../../assets/svg/right-arrow.svg';
import { ReactComponent as RightIcon } from '../../../assets/svg/right-arrow.svg';
import { ReactComponent as PlusIcon } from '../../../assets/svg/x-colored.svg';
import { EntityType } from '../../../enums/entity.enum';
import { DataContract } from '../../../generated/entity/data/dataContract';
@ -225,7 +225,7 @@ export const ContractSemanticFormTab: React.FC<{
{...field}
label={t('label.description')}
name={[field.name, 'description']}>
<TextArea />
<TextArea rows={4} />
</Form.Item>
</Col>
<Col span={24}>
@ -332,7 +332,7 @@ export const ContractSemanticFormTab: React.FC<{
type="primary"
onClick={onNext}>
{nextLabel ?? t('label.next')}
<RightOutlined height={15} width={8} />
<Icon component={RightIcon} />
</Button>
</div>
</>

View File

@ -49,6 +49,29 @@
.enable-form-item {
margin-bottom: 0;
.ant-switch {
margin-left: 2px;
width: 44px;
height: 24px;
.ant-switch-handle {
width: 16px;
height: 16px;
top: 4px;
left: 4px;
&::before {
border-radius: 20px;
}
}
}
.ant-switch-checked {
.ant-switch-handle {
left: calc(100% - 16px - 4px);
}
}
}
> div:first-child {
@ -123,6 +146,29 @@
.semantic-form-item-content {
padding: 20px;
.ant-switch {
margin-left: 2px;
width: 36px;
height: 20px;
.ant-switch-handle {
width: 14px;
height: 14px;
top: 3px;
left: 3px;
&::before {
border-radius: 20px;
}
}
}
.ant-switch-checked {
.ant-switch-handle {
left: calc(100% - 14px - 4px);
}
}
}
}
}

View File

@ -287,6 +287,7 @@
"container-plural": "Container",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "Vertragsausführungsverlauf",
"contract-status": "Vertragsstatus",
"contract-title": "Contract Title",
"conversation": "Konversation",
@ -1856,7 +1857,9 @@
"connection-test-warning": "Der Test der Verbindung war teilweise erfolgreich: Einige Schritte hatten Fehler, es werden nur teilweise Metadaten übernommen.",
"consumer-aligned-domain-type-description": "Domains, die Daten aus mehreren quellenbezogenen Quellen sammeln und kuratieren, um aggregierte Daten und Datenprodukte bereitzustellen, wie z. B. Customer 360, Kundensitzungen usw., damit andere Domains sie nutzen können.",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "Gibt den Gesamtstatus für bestehende Prüfungen an",
"contract-validation-trigger-successfully": "Vertragsvalidierung erfolgreich ausgelöst.",
"copied-to-clipboard": "In die Zwischenablage kopiert",
"copy-to-clipboard": "Link in die Zwischenablage kopiert",
"create-contract-description": "Erstellen Sie einen Vertrag basierend auf allen Metadaten, die Sie für diese Entität erhalten haben.",

View File

@ -287,6 +287,7 @@
"container-plural": "Containers",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "Contract Execution History",
"contract-status": "Contract Status",
"contract-title": "Contract Title",
"conversation": "Conversation",
@ -1856,7 +1857,9 @@
"connection-test-warning": "Test connection partially successful: Some steps had failures, we will only ingest partial metadata.",
"consumer-aligned-domain-type-description": "Domains that are user-facing where the end product of a combination of data from various domains are available for business users or data citizens for data-driven decision-making.",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "Provides the over all status for existing checks",
"contract-validation-trigger-successfully": "Contract validation trigger successfully.",
"copied-to-clipboard": "Copied to the clipboard",
"copy-to-clipboard": "Copy to clipboard",
"create-contract-description": "Create a contract based on all the metadata which you got for this entity.",

View File

@ -287,6 +287,7 @@
"container-plural": "Contenedores",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "Historial de ejecución del contrato",
"contract-status": "Estado del contrato",
"contract-title": "Contract Title",
"conversation": "Conversación",
@ -1856,7 +1857,9 @@
"connection-test-warning": "La prueba de conexión fue parcialmente exitosa: Algunos pasos tuvieron fallas, solo ingrearemos metadatos parciales.",
"consumer-aligned-domain-type-description": "Dominios que son orientados al usuario donde el producto final de una combinación de datos de varios dominios está disponible para los usuarios comerciales o ciudadanos de datos para la toma de decisiones basada en datos.",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "Proporciona el estado general para las verificaciones existentes",
"contract-validation-trigger-successfully": "Contrato de validación activado correctamente.",
"copied-to-clipboard": "Copiado al portapapeles",
"copy-to-clipboard": "Enlace copiado al portapapeles",
"create-contract-description": "Cree un contrato basado en todos los metadatos que ha obtenido para esta entidad.",

View File

@ -287,6 +287,7 @@
"container-plural": "Conteneurs",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "Historique d'exécution du contrat",
"contract-status": "Statut du contrat",
"contract-title": "Contract Title",
"conversation": "Conversation",
@ -1856,7 +1857,9 @@
"connection-test-warning": "Le test de connexion a réussi partiellement : Certaines étapes ont échoué, nous n'ingérerons que les métadonnées partielles.",
"consumer-aligned-domain-type-description": "Domaines qui concentrent les données analytiques reflétant les faits métiers générés par les systèmes opérationnels et appelées produits de données natifs.",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "Provides the over all status for existing checks",
"contract-validation-trigger-successfully": "Validation du contrat déclenchée avec succès.",
"copied-to-clipboard": "Copié dans le presse-papiers",
"copy-to-clipboard": "Lien copié dans le presse-papiers",
"create-contract-description": "Créer un contrat basé sur toutes les métadonnées que vous avez obtenues pour cette entité.",

View File

@ -287,6 +287,7 @@
"container-plural": "Contedores",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "Historial de ejecución do contrato",
"contract-status": "Estado do contrato",
"contract-title": "Contract Title",
"conversation": "Conversa",
@ -1856,7 +1857,9 @@
"connection-test-warning": "Proba de conexión parcialmente exitosa: Algúns pasos fallaron, só inxeriremos metadatos parciais.",
"consumer-aligned-domain-type-description": "Dominios orientados ao usuario onde o produto final dunha combinación de datos de varios dominios está dispoñible para os usuarios empresariais ou cidadáns de datos para a toma de decisións baseada en datos.",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "Proporciona o estado xeral para as verificacións existentes",
"contract-validation-trigger-successfully": "Validación do contrato activada correctamente.",
"copied-to-clipboard": "Copiado ao portapapeis",
"copy-to-clipboard": "Copiar ao portapapeis",
"create-contract-description": "Cree un contrato baseado en todos os metadatos que obtiveches para esta entidade.",

View File

@ -287,6 +287,7 @@
"container-plural": "אחסון (Storage)",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "סטטוס ביצוע חוזה",
"contract-status": "סטטוס חוזה",
"contract-title": "Contract Title",
"conversation": "דיון",
@ -1856,7 +1857,9 @@
"connection-test-warning": "בדיקת החיבור הצליחה באופן חלקי: ישנם כמה שלבים שכשלו, ונקלטו נתוני מטה-דאטה חלקיים בלבד.",
"consumer-aligned-domain-type-description": "תחומים המולחמים שהתוצאה הסופית של שילוב של נתונים ממגוון תחומים זמינה למשתמשי העסקים או אזרחי המידע לקבלת החלטות עסקיות מבוססות נתוני ",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "מספק את הסטטוס הכללי עבור בדיקות קיימות",
"contract-validation-trigger-successfully": "חוזה נתונים נבדק בהצלחה.",
"copied-to-clipboard": "הועתק ללוח",
"copy-to-clipboard": "קישור הועתק ללוח",
"create-contract-description": "צור חוזה המבוסס על כל המטא-דאטה שקיבלת עבור ישות זו.",

View File

@ -287,6 +287,7 @@
"container-plural": "コンテナ",
"contract": "契約",
"contract-detail-plural": "契約詳細",
"contract-execution-history": "契約実行履歴",
"contract-status": "契約ステータス",
"contract-title": "契約タイトル",
"conversation": "会話",
@ -1856,7 +1857,9 @@
"connection-test-warning": "接続テストは一部成功しました:いくつかのステップで失敗があり、一部のメタデータのみが取り込まれます。",
"consumer-aligned-domain-type-description": "さまざまなドメインから統合されたデータの最終成果物が、ビジネスユーザーやデータ市民に提供され、意思決定に使われるユーザー向けのドメイン。",
"contract-detail-plural-description": "データアセットに対する期待値を定めた契約。",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "Provides the over all status for existing checks",
"contract-validation-trigger-successfully": "契約の検証が正常にトリガーされました。",
"copied-to-clipboard": "クリップボードにコピーしました",
"copy-to-clipboard": "リンクをクリップボードにコピーしました",
"create-contract-description": "Create a contract based on all the metadata which you got for this entity.",

View File

@ -287,6 +287,7 @@
"container-plural": "컨테이너들",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "계약 실행 기록",
"contract-status": "계약 상태",
"contract-title": "Contract Title",
"conversation": "대화",
@ -1856,7 +1857,9 @@
"connection-test-warning": "연결 테스트가 부분적으로 성공했습니다: 일부 단계에서 실패가 있었으며, 부분적인 메타데이터만 수집할 것입니다.",
"consumer-aligned-domain-type-description": "소스 정렬된 여러 데이터를 수집하고 큐레이션하여 다른 도메인이 소비할 수 있는 집계된 데이터와 데이터 제품(예: 고객 360, 고객 세션 등)을 제공하는 도메인입니다.",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "기존 검사에 대한 전체 상태를 제공합니다",
"contract-validation-trigger-successfully": "계약 검증이 성공적으로 트리거되었습니다.",
"copied-to-clipboard": "클립보드에 복사됨",
"copy-to-clipboard": "클립보드에 복사",
"create-contract-description": "이 엔터티에 대해 얻은 모든 메타데이터를 기반으로 계약을 생성합니다.",

View File

@ -287,6 +287,7 @@
"container-plural": "कंटेनर",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "करार चालवणी इतिहास",
"contract-status": "करार स्थिती",
"contract-title": "Contract Title",
"conversation": "संभाषण",
@ -1856,7 +1857,9 @@
"connection-test-warning": "कनेक्शन चाचणी अंशतः यशस्वी: काही चरणांमध्ये अयशस्वीता आली, आम्ही फक्त आंशिक मेटाडेटा अंतर्ग्रहण करू.",
"consumer-aligned-domain-type-description": "डोमेन्स जे वापरकर्त्यांना सामोरे जातात जिथे विविध डोमेन्समधील डेटाचे संयोजन व्यवसाय वापरकर्त्यांसाठी किंवा डेटा नागरिकांसाठी डेटा-चालित निर्णय घेण्यासाठी उपलब्ध आहे.",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "विद्यमान तपासण्यांसाठी एकूण स्थिती प्रदान करते",
"contract-validation-trigger-successfully": "करार सत्यापन सफलतापूर्वक चालविले.",
"copied-to-clipboard": "क्लिपबोर्डवर कॉपी केले",
"copy-to-clipboard": "क्लिपबोर्डवर कॉपी करा",
"create-contract-description": "या एंटिटीसाठी तुम्हाला मिळालेल्या सर्व मेटाडेटावर आधारित करार तयार करा.",

View File

@ -287,6 +287,7 @@
"container-plural": "Containers",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "Contractuitvoeringsgeschiedenis",
"contract-status": "Contractstatus",
"contract-title": "Contract Title",
"conversation": "Gesprek",
@ -1856,7 +1857,9 @@
"connection-test-warning": "Testconnectie gedeeltelijk succesvol: Sommige stappen hadden fouten, we zullen slechts gedeeltelijke metadata binnenhalen.",
"consumer-aligned-domain-type-description": "Domeinen die zichtbaar zijn voor de gebruiker waar het eindproduct van een combinatie van data uit verschillende domeinen beschikbaar is voor zakelijke gebruikers of data citizens voor datagedreven besluitvorming.",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "Biedt de algehele status voor bestaande controles",
"contract-validation-trigger-successfully": "Contractvalidatie succesvol geactiveerd.",
"copied-to-clipboard": "Gekopieerd naar het klembord",
"copy-to-clipboard": "Koppeling gekopieerd naar klembord",
"create-contract-description": "Maak een contract op basis van alle metadata die u voor deze entiteit hebt verkregen.",

View File

@ -287,6 +287,7 @@
"container-plural": "ظرف‌ها",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "تاریخچه اجرای قرارداد",
"contract-status": "وضعیت قرارداد",
"contract-title": "Contract Title",
"conversation": "مکالمه",
@ -1856,7 +1857,9 @@
"connection-test-warning": "آزمون اتصال به صورت جزئی موفقیت‌آمیز بود: برخی از مراحل با شکست مواجه شدند، ما فقط متادیتای جزئی را وارد خواهیم کرد.",
"consumer-aligned-domain-type-description": "دامنه‌هایی که کاربر محور هستند و محصول نهایی ترکیب داده‌ها از دامنه‌های مختلف در اختیار کاربران تجاری یا شهروندان داده برای تصمیم‌گیری مبتنی بر داده قرار می‌گیر",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "وضعیت کلی برای بررسی‌های موجود فراهم می‌کند",
"contract-validation-trigger-successfully": "بررسی قرارداد با موفقیت انجام شد.",
"copied-to-clipboard": "به حافظه موقت کپی شد",
"copy-to-clipboard": "کپی به حافظه موقت",
"create-contract-description": "قراردادی بر اساس تمام متادیتایی که برای این موجودیت به دست آورده‌اید ایجاد کنید.",

View File

@ -287,6 +287,7 @@
"container-plural": "Contêineres",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "Histórico de execução do contrato",
"contract-status": "Status do contrato",
"contract-title": "Contract Title",
"conversation": "Conversa",
@ -1856,7 +1857,9 @@
"connection-test-warning": "Teste de conexão parcialmente bem-sucedido: Algumas etapas falharam, apenas ingestaremos metadados parciais.",
"consumer-aligned-domain-type-description": "Domínios que são voltados para o usuário, onde o produto final de uma combinação de dados de vários domínios está disponível para usuários de negócios ou cidadãos de dados para tomada de decisões baseada em dados.",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "Fornece o status geral para as verificações existentes",
"contract-validation-trigger-successfully": "Validação de contrato acionada com sucesso.",
"copied-to-clipboard": "Copiado para a área de transferência",
"copy-to-clipboard": "Link copiado para a área de transferência",
"create-contract-description": "Crie um contrato com base em todos os metadados que você obteve para esta entidade.",

View File

@ -287,6 +287,7 @@
"container-plural": "Contentores",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "Histórico de execução do contrato",
"contract-status": "Estado do contrato",
"contract-title": "Contract Title",
"conversation": "Conversa",
@ -1856,7 +1857,9 @@
"connection-test-warning": "Teste de conexão parcialmente bem-sucedido: Algumas etapas falharam, apenas ingestaremos metadados parciais.",
"consumer-aligned-domain-type-description": "Domínios que são voltados para o utilizador, onde o produto final de uma combinação de dados de vários domínios está disponível para Utilizadores de negócios ou cidadãos de dados para tomada de decisões baseada em dados.",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "Fornece o status geral para as verificações existentes",
"contract-validation-trigger-successfully": "Validação de contrato acionada com sucesso.",
"copied-to-clipboard": "Copiado para a área de transferência",
"copy-to-clipboard": "Link copiado para a área de transferência",
"create-contract-description": "Crie um contrato com base em todos os metadados que você obteve para esta entidade.",

View File

@ -287,6 +287,7 @@
"container-plural": "Контейнеры",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "История выполнения контракта",
"contract-status": "Статус контракта",
"contract-title": "Contract Title",
"conversation": "Обсуждение",
@ -1856,7 +1857,9 @@
"connection-test-warning": "Тестовое соединение частично успешно: на некоторых этапах были сбои, мы будем принимать только частичные метаданные.",
"consumer-aligned-domain-type-description": "Домены, ориентированные на пользователя, в которых конечный продукт объединения данных из различных доменов доступен корпоративным пользователям или заинтересованным лицам для принятия решений на основе данных.",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "Предоставляет общий статус для существующих проверок",
"contract-validation-trigger-successfully": "Проверка контракта успешно запущена.",
"copied-to-clipboard": "Скопировано в буфер обмена",
"copy-to-clipboard": "Ссылка скопирована в буфер обмена",
"create-contract-description": "Создайте контракт на основе всех метаданных, которые вы получили для этой сущности.",

View File

@ -287,6 +287,7 @@
"container-plural": "คอนเทนเนอร์",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "ประวัติการดำเนินการสัญญา",
"contract-status": "สถานะสัญญา",
"contract-title": "Contract Title",
"conversation": "การสนทนา",
@ -1856,7 +1857,9 @@
"connection-test-warning": "การทดสอบการเชื่อมต่อต partially successful: ขั้นตอนบางส่วนล้มเหลว เราจะนำเข้าข้อมูลเมตาส่วนนั้นเท่านั้น",
"consumer-aligned-domain-type-description": "โดเมนที่เป็นการมอบหมายให้ผู้ใช้โดยที่ผลิตภัณฑ์สุดท้ายของการรวมข้อมูลจากโดเมนต่าง ๆ พร้อมให้บริการแก่ผู้ใช้ธุรกิจหรือประชาชนข้อมูลเพื่อการตัดสินใจที่ขับเคลื่อนด้วยข้อมูล",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "ให้สถานะโดยรวมสำหรับการตรวจสอบที่มีอยู่",
"contract-validation-trigger-successfully": "การตรวจสอบสัญญาทำงานสำเร็จ",
"copied-to-clipboard": "คัดลอกไปที่คลิปบอร์ด",
"copy-to-clipboard": "คัดลอกไปที่คลิปบอร์ด",
"create-contract-description": "สร้างสัญญาตามเมทาดาต้าทั้งหมดที่คุณได้รับสำหรับเอนทิตีนี้",

View File

@ -287,6 +287,7 @@
"container-plural": "Konteynerler",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "Sözleşme Yürütme Geçmişi",
"contract-status": "Sözleşme Durumu",
"contract-title": "Contract Title",
"conversation": "Konuşma",
@ -1856,7 +1857,9 @@
"connection-test-warning": "Bağlantı testi kısmen başarılı: Bazı adımlarda hatalar oluştu, yalnızca kısmi metadata alacağız.",
"consumer-aligned-domain-type-description": "Çeşitli alanlardan gelen verilerin birleşiminin son ürününün iş kullanıcıları veya veri vatandaşları için veri odaklı karar verme amacıyla kullanılabildiği, kullanıcıya yönelik alan adları.",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "Mevcut kontroller için genel durumu sağlar",
"contract-validation-trigger-successfully": "Sözleşme doğrulama başarıyla tetiklendi.",
"copied-to-clipboard": "Panoya kopyalandı",
"copy-to-clipboard": "Panoya kopyala",
"create-contract-description": "Bu varlık için elde ettiğiniz tüm metadatalara dayalı bir sözleşme oluşturun.",

View File

@ -287,6 +287,7 @@
"container-plural": "存储容器",
"contract": "Contract",
"contract-detail-plural": "Contract Details",
"contract-execution-history": "合同执行历史",
"contract-status": "合同状态",
"contract-title": "Contract Title",
"conversation": "对话",
@ -1856,7 +1857,9 @@
"connection-test-warning": "连接测试部分成功:部分步骤失败, 只能提取部分元数据",
"consumer-aligned-domain-type-description": "面向用户的域, 在这些域中, 来自不同域的数据组合的最终产品可供商业用户或数据公民进行数据驱动决策.",
"contract-detail-plural-description": "A contract specifying expectations for a data asset.",
"contract-execution-history-description": "View all the contract execution results over time",
"contract-status-description": "提供现有检查的总体状态",
"contract-validation-trigger-successfully": "合同验证触发成功。",
"copied-to-clipboard": "已复制到剪贴板",
"copy-to-clipboard": "链接已复制到剪贴板",
"create-contract-description": "基于您为此实体获得的所有元数据创建合同。",

View File

@ -10,6 +10,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
ContractAllResult,
ContractResultFilter,
} from '../components/DataContract/ContractDetailTab/contract.interface';
import { EntityType } from '../enums/entity.enum';
import { CreateDataContract } from '../generated/api/data/createDataContract';
import { DataContract } from '../generated/entity/data/dataContract';
@ -113,7 +117,21 @@ export const getContractResultByResultId = async (
export const getLatestContractResults = async (contractId: string) => {
const response = await APIClient.get<DataContractResult>(
`/dataContracts/${contractId}/results`
`/dataContracts/${contractId}/results/latest`
);
return response.data;
};
export const getAllContractResults = async (
contractId: string,
params: ContractResultFilter
) => {
const response = await APIClient.get<ContractAllResult>(
`/dataContracts/${contractId}/results`,
{
params,
}
);
return response.data;

View File

@ -95,6 +95,8 @@
@purple-4: #efedfe80;
@purple-5: #6941c6;
@purple-6: #f9f5ff;
@purple-7: #e9d7fe;
@blue-1: #ebf6fe;
@blue-2: #3ca2f4;
@blue-3: #0950c5;

View File

@ -567,6 +567,7 @@ class GlobalSettingsClassBase {
isProtected: Boolean(isAdminUser),
key: `${GlobalSettingsMenuCategory.PREFERENCES}.${GlobalSettingOptions.DATA_ASSET_RULES}`,
icon: DataAssetRulesIcon,
isBeta: true,
},
],
},

View File

@ -101,6 +101,7 @@ class TableClassBase {
EntityTabs.LINEAGE,
EntityTabs.DBT,
EntityTabs.VIEW_DEFINITION,
EntityTabs.CONTRACT,
EntityTabs.CUSTOM_PROPERTIES,
].map((tab: EntityTabs) => ({
id: tab,

View File

@ -966,6 +966,7 @@ export const getTableDetailPageBaseTabs = ({
{
label: (
<TabsLabel
isBeta
id={EntityTabs.CONTRACT}
isActive={activeTab === EntityTabs.CONTRACT}
name={get(labelMap, EntityTabs.CONTRACT, t('label.contract'))}