diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataContractInheritance.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataContractInheritance.spec.ts
index b57f7761ac6b..4857ee9c3747 100644
--- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataContractInheritance.spec.ts
+++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataContractInheritance.spec.ts
@@ -71,7 +71,8 @@ const DATA_PRODUCT_SLA = {
const fillContractDetailsForm = async (
page: Page,
contractName: string,
- description: string
+ description: string,
+ status?: 'Draft' | 'In Review' | 'Approved'
) => {
await page.getByTestId('contract-name').fill(contractName);
await page.fill('.om-block-editor[contenteditable="true"]', description);
@@ -82,6 +83,14 @@ const fillContractDetailsForm = async (
await firstOwner.click();
await expect(page.getByTestId('user-tag')).toBeVisible();
+
+ if (status) {
+ await page.getByTestId('contract-status').click();
+ await expect(
+ page.locator(`.contract-status-dropdown [title="${status}"]`)
+ ).toBeVisible();
+ await page.locator(`.contract-status-dropdown [title="${status}"]`).click();
+ }
};
const fillTermsOfServiceForm = async (page: Page, termsContent: string) => {
@@ -440,7 +449,8 @@ test.describe('Data Contract Inheritance', () => {
await fillContractDetailsForm(
page,
DATA_PRODUCT_CONTRACT_DETAILS.name,
- DATA_PRODUCT_CONTRACT_DETAILS.description
+ DATA_PRODUCT_CONTRACT_DETAILS.description,
+ 'Approved'
);
});
@@ -565,7 +575,8 @@ test.describe('Data Contract Inheritance', () => {
await fillContractDetailsForm(
page,
`dp_partial_${uuid()}`,
- 'Data Product contract for partial inheritance'
+ 'Data Product contract for partial inheritance',
+ 'Approved'
);
});
@@ -683,7 +694,8 @@ test.describe('Data Contract Inheritance', () => {
await fillContractDetailsForm(
page,
`dp_sla_edit_test_${uuid()}`,
- 'Data Product contract with SLA for edit test'
+ 'Data Product contract with SLA for edit test',
+ 'Approved'
);
});
@@ -860,7 +872,8 @@ test.describe('Data Contract Inheritance', () => {
await fillContractDetailsForm(
page,
DP_CONTRACT_DETAILS.name,
- DP_CONTRACT_DETAILS.description
+ DP_CONTRACT_DETAILS.description,
+ 'Approved'
);
await fillTermsOfServiceForm(page, DP_CONTRACT_DETAILS.termsOfService);
@@ -1000,7 +1013,8 @@ test.describe('Data Contract Inheritance', () => {
await fillContractDetailsForm(
page,
DP_CONTRACT_DETAILS.name,
- DP_CONTRACT_DETAILS.description
+ DP_CONTRACT_DETAILS.description,
+ 'Approved'
);
await saveContract(page);
@@ -1069,7 +1083,8 @@ test.describe('Data Contract Inheritance', () => {
await fillContractDetailsForm(
page,
DP_CONTRACT_DETAILS.name,
- DP_CONTRACT_DETAILS.description
+ DP_CONTRACT_DETAILS.description,
+ 'Approved'
);
await saveContract(page);
@@ -1150,7 +1165,8 @@ test.describe('Data Contract Inheritance', () => {
await fillContractDetailsForm(
page,
DP_CONTRACT_DETAILS.name,
- DP_CONTRACT_DETAILS.description
+ DP_CONTRACT_DETAILS.description,
+ 'Approved'
);
await saveContract(page);
@@ -1250,7 +1266,8 @@ test.describe('Data Contract Inheritance', () => {
await fillContractDetailsForm(
page,
DP_CONTRACT_DETAILS.name,
- DP_CONTRACT_DETAILS.description
+ DP_CONTRACT_DETAILS.description,
+ 'Approved'
);
await fillTermsOfServiceForm(page, DP_CONTRACT_DETAILS.termsOfService);
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataContract/AddDataContract/AddDataContract.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataContract/AddDataContract/AddDataContract.test.tsx
index e297b9fe9a79..5ffeb2ee7ecc 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DataContract/AddDataContract/AddDataContract.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DataContract/AddDataContract/AddDataContract.test.tsx
@@ -17,10 +17,10 @@ import { EDataContractTab } from '../../../constants/DataContract.constants';
import { EntityType } from '../../../enums/entity.enum';
import {
DataContract,
+ EntityStatus,
SemanticsRule,
} from '../../../generated/entity/data/dataContract';
import { Column, Table } from '../../../generated/entity/data/table';
-import { EntityStatus } from '../../../generated/entity/domains/dataProduct';
import { EntityReference } from '../../../generated/entity/type';
import { createContract, updateContract } from '../../../rest/contractAPI';
import { showErrorToast, showSuccessToast } from '../../../utils/ToastUtils';
@@ -96,6 +96,10 @@ jest.mock('../ContractDetailFormTab/ContractDetailFormTab', () => ({
+
)),
@@ -442,7 +446,7 @@ describe('AddDataContract', () => {
type: EntityType.TABLE,
},
semantics: undefined, // validSemantics - undefined when no semantics provided
- entityStatus: EntityStatus.Approved,
+ entityStatus: EntityStatus.Draft,
})
);
expect(showSuccessToast).toHaveBeenCalledWith(
@@ -474,7 +478,7 @@ describe('AddDataContract', () => {
type: EntityType.TABLE,
},
semantics: undefined, // validSemantics - undefined when no semantics provided
- entityStatus: EntityStatus.Approved,
+ entityStatus: EntityStatus.Draft,
})
);
expect(showSuccessToast).toHaveBeenCalledWith(
@@ -483,6 +487,32 @@ describe('AddDataContract', () => {
expect(mockOnSave).toHaveBeenCalled();
});
+ it('should use selected entity status when creating a contract', async () => {
+ render();
+
+ const changeButton = screen.getByText('Change');
+ await act(async () => {
+ fireEvent.click(changeButton);
+ });
+
+ const statusButton = screen.getByText('Change Status');
+ await act(async () => {
+ fireEvent.click(statusButton);
+ });
+
+ const saveButton = screen.getByTestId('save-contract-btn');
+
+ await act(async () => {
+ fireEvent.click(saveButton);
+ });
+
+ expect(createContract).toHaveBeenCalledWith(
+ expect.objectContaining({
+ entityStatus: EntityStatus.InReview,
+ })
+ );
+ });
+
it('should call updateContract for existing contract with JSON patch', async () => {
render(
({
@@ -47,6 +51,10 @@ jest.mock('react-i18next', () => ({
const translations: Record = {
'label.contract-title': 'Contract Title',
'label.owner-plural': 'Owners',
+ 'label.status': 'Status',
+ 'label.draft': 'Draft label',
+ 'label.in-review': 'In Review label',
+ 'label.approved': 'Approved label',
'label.description': 'Description',
'label.contract-detail-plural': 'Contract Details',
'message.contract-detail-plural-description': 'Enter contract details',
@@ -99,6 +107,7 @@ describe('ContractDetailFormTab', () => {
expect(screen.getByText('Enter contract details')).toBeInTheDocument();
expect(screen.getByText('Contract Title')).toBeInTheDocument();
+ expect(screen.getByText('Status')).toBeInTheDocument();
expect(screen.getByText('Owners')).toBeInTheDocument();
expect(screen.getByText('Description')).toBeInTheDocument();
});
@@ -127,6 +136,7 @@ describe('ContractDetailFormTab', () => {
render();
expect(screen.getByText('Contract Title')).toBeInTheDocument();
+ expect(screen.getByText('Status')).toBeInTheDocument();
expect(screen.getByText('Description')).toBeInTheDocument();
expect(screen.getByText('Owners')).toBeInTheDocument();
});
@@ -261,6 +271,21 @@ describe('ContractDetailFormTab', () => {
name: 'owners',
label: 'Owners',
}),
+ expect.objectContaining({
+ formItemProps: {
+ initialValue: EntityStatus.Draft,
+ },
+ name: 'entityStatus',
+ label: 'Status',
+ props: expect.objectContaining({
+ options: [
+ { label: 'Draft label', value: EntityStatus.Draft },
+ { label: 'In Review label', value: EntityStatus.InReview },
+ { label: 'Approved label', value: EntityStatus.Approved },
+ ],
+ }),
+ type: FieldTypes.SELECT,
+ }),
expect.objectContaining({
name: 'description',
label: 'Description',
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataContract/ContractDetailFormTab/ContractDetailFormTab.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataContract/ContractDetailFormTab/ContractDetailFormTab.tsx
index 9dd6684c712b..cf547a7a8f02 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DataContract/ContractDetailFormTab/ContractDetailFormTab.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DataContract/ContractDetailFormTab/ContractDetailFormTab.tsx
@@ -16,13 +16,31 @@ import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { ReactComponent as RightIcon } from '../../../assets/svg/right-arrow.svg';
import { EntityType } from '../../../enums/entity.enum';
-import { DataContract } from '../../../generated/entity/data/dataContract';
+import {
+ DataContract,
+ EntityStatus,
+} from '../../../generated/entity/data/dataContract';
import { useEntityRules } from '../../../hooks/useEntityRules';
import { FieldProp, FieldTypes } from '../../../interface/FormUtils.interface';
import { getEntityName } from '../../../utils/EntityNameUtils';
import { generateFormFields } from '../../../utils/formUtils';
import './contract-detail-form-tab.less';
+const DATA_CONTRACT_STATUS_OPTION_KEYS = [
+ {
+ labelKey: 'label.draft',
+ value: EntityStatus.Draft,
+ },
+ {
+ labelKey: 'label.in-review',
+ value: EntityStatus.InReview,
+ },
+ {
+ labelKey: 'label.approved',
+ value: EntityStatus.Approved,
+ },
+];
+
export const ContractDetailFormTab: React.FC<{
initialValues?: Partial;
onNext: () => void;
@@ -40,6 +58,12 @@ export const ContractDetailFormTab: React.FC<{
const { t } = useTranslation();
const [form] = Form.useForm();
const { entityRules } = useEntityRules(EntityType.TABLE);
+ const dataContractStatusOptions = DATA_CONTRACT_STATUS_OPTION_KEYS.map(
+ ({ labelKey, value }) => ({
+ label: t(labelKey),
+ value,
+ })
+ );
const fields: FieldProp[] = [
{
@@ -55,6 +79,22 @@ export const ContractDetailFormTab: React.FC<{
'data-testid': 'contract-name',
},
},
+ {
+ label: t('label.status'),
+ id: 'entityStatus',
+ name: 'entityStatus',
+ type: FieldTypes.SELECT,
+ required: false,
+ placeholder: t('label.select-field', { field: t('label.status') }),
+ props: {
+ 'data-testid': 'contract-status',
+ options: dataContractStatusOptions,
+ popupClassName: 'contract-status-dropdown',
+ },
+ formItemProps: {
+ initialValue: initialValues?.entityStatus ?? EntityStatus.Draft,
+ },
+ },
{
label: t('label.owner-plural'),
name: 'owners',
@@ -95,6 +135,7 @@ export const ContractDetailFormTab: React.FC<{
form.setFieldsValue({
name: getEntityName(initialValues),
description: initialValues.description,
+ entityStatus: initialValues.entityStatus ?? EntityStatus.Draft,
owners: initialValues.owners,
});
}