mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-02 05:33:49 +00:00
parent
0dcf9d7ab3
commit
6d32257765
@ -79,7 +79,7 @@ import org.openmetadata.service.util.ResultList;
|
|||||||
@Collection(name = "dataProducts", order = 4) // initialize after user resource
|
@Collection(name = "dataProducts", order = 4) // initialize after user resource
|
||||||
public class DataProductResource extends EntityResource<DataProduct, DataProductRepository> {
|
public class DataProductResource extends EntityResource<DataProduct, DataProductRepository> {
|
||||||
public static final String COLLECTION_PATH = "/v1/dataProducts/";
|
public static final String COLLECTION_PATH = "/v1/dataProducts/";
|
||||||
static final String FIELDS = "domain,owners,experts,assets";
|
static final String FIELDS = "domain,owners,experts,assets,extension";
|
||||||
|
|
||||||
public DataProductResource(Authorizer authorizer, Limits limits) {
|
public DataProductResource(Authorizer authorizer, Limits limits) {
|
||||||
super(Entity.DATA_PRODUCT, authorizer, limits);
|
super(Entity.DATA_PRODUCT, authorizer, limits);
|
||||||
|
@ -228,6 +228,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"extension": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"totalVotes": {
|
"totalVotes": {
|
||||||
"type": "long",
|
"type": "long",
|
||||||
"null_value": 0
|
"null_value": 0
|
||||||
|
@ -226,6 +226,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"extension": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"totalVotes": {
|
"totalVotes": {
|
||||||
"type": "long",
|
"type": "long",
|
||||||
"null_value": 0
|
"null_value": 0
|
||||||
|
@ -203,6 +203,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"extension": {
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
"totalVotes": {
|
"totalVotes": {
|
||||||
"type": "long",
|
"type": "long",
|
||||||
"null_value": 0
|
"null_value": 0
|
||||||
|
@ -50,6 +50,10 @@
|
|||||||
"description": "Data assets collection that is part of this data product.",
|
"description": "Data assets collection that is part of this data product.",
|
||||||
"$ref": "../../type/entityReferenceList.json",
|
"$ref": "../../type/entityReferenceList.json",
|
||||||
"default": null
|
"default": null
|
||||||
|
},
|
||||||
|
"extension": {
|
||||||
|
"description": "Entity extension data with custom attributes added to the entity.",
|
||||||
|
"$ref": "../../type/basic.json#/definitions/entityExtension"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
"title": "DataProduct",
|
"title": "DataProduct",
|
||||||
"description": "A `Data Product` or `Data as a Product` is a logical unit that contains all components to process and store data for analytical or data-intensive use cases made available to data consumers.",
|
"description": "A `Data Product` or `Data as a Product` is a logical unit that contains all components to process and store data for analytical or data-intensive use cases made available to data consumers.",
|
||||||
|
"$comment": "@om-entity-type",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"javaType": "org.openmetadata.schema.entity.domains.DataProduct",
|
"javaType": "org.openmetadata.schema.entity.domains.DataProduct",
|
||||||
"javaInterfaces": ["org.openmetadata.schema.EntityInterface"],
|
"javaInterfaces": ["org.openmetadata.schema.EntityInterface"],
|
||||||
@ -66,6 +67,10 @@
|
|||||||
"changeDescription": {
|
"changeDescription": {
|
||||||
"description": "Change that lead to this version of the entity.",
|
"description": "Change that lead to this version of the entity.",
|
||||||
"$ref": "../../type/entityHistory.json#/definitions/changeDescription"
|
"$ref": "../../type/entityHistory.json#/definitions/changeDescription"
|
||||||
|
},
|
||||||
|
"extension": {
|
||||||
|
"description": "Entity extension data with custom attributes added to the entity.",
|
||||||
|
"$ref": "../../type/basic.json#/definitions/entityExtension"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["id", "name", "description"],
|
"required": ["id", "name", "description"],
|
||||||
|
@ -28,6 +28,7 @@ export const CustomPropertySupportedEntityList = [
|
|||||||
EntityTypeEndpoint.DataModel,
|
EntityTypeEndpoint.DataModel,
|
||||||
EntityTypeEndpoint.API_COLLECTION,
|
EntityTypeEndpoint.API_COLLECTION,
|
||||||
EntityTypeEndpoint.API_ENDPOINT,
|
EntityTypeEndpoint.API_ENDPOINT,
|
||||||
|
EntityTypeEndpoint.DATA_PRODUCT,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const ENTITY_REFERENCE_PROPERTIES = [
|
export const ENTITY_REFERENCE_PROPERTIES = [
|
||||||
@ -268,6 +269,40 @@ export const CUSTOM_PROPERTIES_ENTITIES = {
|
|||||||
entityObj: {},
|
entityObj: {},
|
||||||
entityApiType: 'apiEndpoints',
|
entityApiType: 'apiEndpoints',
|
||||||
},
|
},
|
||||||
|
entity_dataProduct: {
|
||||||
|
name: 'dataProduct',
|
||||||
|
description: 'This is Data Product custom property',
|
||||||
|
integerValue: '23',
|
||||||
|
stringValue: 'This is string propery',
|
||||||
|
markdownValue: 'This is markdown value',
|
||||||
|
enumConfig: {
|
||||||
|
values: ['enum1', 'enum2', 'enum3'],
|
||||||
|
multiSelect: false,
|
||||||
|
},
|
||||||
|
dateFormatConfig: 'yyyy-MM-dd',
|
||||||
|
dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss',
|
||||||
|
timeFormatConfig: 'HH:mm:ss',
|
||||||
|
entityReferenceConfig: ['User', 'Team'],
|
||||||
|
entityObj: {},
|
||||||
|
entityApiType: 'dataProducts',
|
||||||
|
},
|
||||||
|
entity_dashboardDataModel: {
|
||||||
|
name: 'dataModel',
|
||||||
|
description: 'This is Data Model custom property',
|
||||||
|
integerValue: '23',
|
||||||
|
stringValue: 'This is string propery',
|
||||||
|
markdownValue: 'This is markdown value',
|
||||||
|
enumConfig: {
|
||||||
|
values: ['enum1', 'enum2', 'enum3'],
|
||||||
|
multiSelect: false,
|
||||||
|
},
|
||||||
|
dateFormatConfig: 'yyyy-MM-dd',
|
||||||
|
dateTimeFormatConfig: 'yyyy-MM-dd HH:mm:ss',
|
||||||
|
timeFormatConfig: 'HH:mm:ss',
|
||||||
|
entityReferenceConfig: ['User', 'Team'],
|
||||||
|
entityObj: {},
|
||||||
|
entityApiType: 'dashboardDataModels',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CUSTOM_PROPERTY_INVALID_NAMES = {
|
export const CUSTOM_PROPERTY_INVALID_NAMES = {
|
||||||
|
@ -70,6 +70,8 @@ export enum GlobalSettingOptions {
|
|||||||
APIS = 'apiServices',
|
APIS = 'apiServices',
|
||||||
API_COLLECTIONS = 'apiCollections',
|
API_COLLECTIONS = 'apiCollections',
|
||||||
API_ENDPOINTS = 'apiEndpoints',
|
API_ENDPOINTS = 'apiEndpoints',
|
||||||
|
DATA_PRODUCTS = 'dataProducts',
|
||||||
|
DASHBOARD_DATA_MODEL = 'dashboardDataModels',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SETTINGS_OPTIONS_PATH = {
|
export const SETTINGS_OPTIONS_PATH = {
|
||||||
@ -241,4 +243,12 @@ export const SETTING_CUSTOM_PROPERTIES_PATH = {
|
|||||||
GlobalSettingsMenuCategory.CUSTOM_PROPERTIES,
|
GlobalSettingsMenuCategory.CUSTOM_PROPERTIES,
|
||||||
`${GlobalSettingsMenuCategory.CUSTOM_PROPERTIES}.${GlobalSettingOptions.API_ENDPOINTS}`,
|
`${GlobalSettingsMenuCategory.CUSTOM_PROPERTIES}.${GlobalSettingOptions.API_ENDPOINTS}`,
|
||||||
],
|
],
|
||||||
|
[GlobalSettingOptions.DATA_PRODUCTS]: [
|
||||||
|
GlobalSettingsMenuCategory.CUSTOM_PROPERTIES,
|
||||||
|
`${GlobalSettingsMenuCategory.CUSTOM_PROPERTIES}.${GlobalSettingOptions.DATA_PRODUCTS}`,
|
||||||
|
],
|
||||||
|
[GlobalSettingOptions.DASHBOARD_DATA_MODEL]: [
|
||||||
|
GlobalSettingsMenuCategory.CUSTOM_PROPERTIES,
|
||||||
|
`${GlobalSettingsMenuCategory.CUSTOM_PROPERTIES}.${GlobalSettingOptions.DASHBOARD_DATA_MODEL}`,
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
@ -21,6 +21,7 @@ import { ENTITY_PATH } from '../../support/entity/Entity.interface';
|
|||||||
import { UserClass } from '../../support/user/UserClass';
|
import { UserClass } from '../../support/user/UserClass';
|
||||||
import { performAdminLogin } from '../../utils/admin';
|
import { performAdminLogin } from '../../utils/admin';
|
||||||
import { getApiContext, redirectToHomePage } from '../../utils/common';
|
import { getApiContext, redirectToHomePage } from '../../utils/common';
|
||||||
|
import { CustomPropertyTypeByName } from '../../utils/customProperty';
|
||||||
import {
|
import {
|
||||||
addAssetsToDataProduct,
|
addAssetsToDataProduct,
|
||||||
addAssetsToDomain,
|
addAssetsToDomain,
|
||||||
@ -132,6 +133,54 @@ test.describe('Domains', () => {
|
|||||||
await afterAction();
|
await afterAction();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Add, Update custom properties for data product', async ({ page }) => {
|
||||||
|
test.slow(true);
|
||||||
|
|
||||||
|
const properties = Object.values(CustomPropertyTypeByName);
|
||||||
|
const titleText = properties.join(', ');
|
||||||
|
|
||||||
|
const { afterAction, apiContext } = await getApiContext(page);
|
||||||
|
const domain = new Domain();
|
||||||
|
const dataProduct1 = new DataProduct(domain);
|
||||||
|
await domain.create(apiContext);
|
||||||
|
await sidebarClick(page, SidebarItem.DOMAIN);
|
||||||
|
await page.reload();
|
||||||
|
|
||||||
|
await test.step(
|
||||||
|
'Create DataProduct and custom properties for it',
|
||||||
|
async () => {
|
||||||
|
await selectDomain(page, domain.data);
|
||||||
|
await createDataProduct(page, dataProduct1.data);
|
||||||
|
await dataProduct1.prepareCustomProperty(apiContext);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
await test.step(`Set ${titleText} Custom Property`, async () => {
|
||||||
|
for (const type of properties) {
|
||||||
|
await dataProduct1.updateCustomProperty(
|
||||||
|
page,
|
||||||
|
dataProduct1.customPropertyValue[type].property,
|
||||||
|
dataProduct1.customPropertyValue[type].value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await test.step(`Update ${titleText} Custom Property`, async () => {
|
||||||
|
for (const type of properties) {
|
||||||
|
await dataProduct1.updateCustomProperty(
|
||||||
|
page,
|
||||||
|
dataProduct1.customPropertyValue[type].property,
|
||||||
|
dataProduct1.customPropertyValue[type].newValue
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await dataProduct1.cleanupCustomProperty(apiContext);
|
||||||
|
await dataProduct1.delete(apiContext);
|
||||||
|
await domain.delete(apiContext);
|
||||||
|
await afterAction();
|
||||||
|
});
|
||||||
|
|
||||||
test('Switch domain from navbar and check domain query call warp in quotes', async ({
|
test('Switch domain from navbar and check domain query call warp in quotes', async ({
|
||||||
page,
|
page,
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
import { APIRequestContext } from '@playwright/test';
|
import { APIRequestContext } from '@playwright/test';
|
||||||
import { uuid } from '../../utils/common';
|
import { uuid } from '../../utils/common';
|
||||||
|
import { EntityTypeEndpoint } from '../entity/Entity.interface';
|
||||||
|
import { EntityClass } from '../entity/EntityClass';
|
||||||
import { Domain } from './Domain';
|
import { Domain } from './Domain';
|
||||||
|
|
||||||
type UserTeamRef = {
|
type UserTeamRef = {
|
||||||
@ -30,7 +32,7 @@ type ResponseDataType = {
|
|||||||
experts?: UserTeamRef[];
|
experts?: UserTeamRef[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export class DataProduct {
|
export class DataProduct extends EntityClass {
|
||||||
id = uuid();
|
id = uuid();
|
||||||
data: ResponseDataType = {
|
data: ResponseDataType = {
|
||||||
name: `PW%dataProduct.${this.id}`,
|
name: `PW%dataProduct.${this.id}`,
|
||||||
@ -44,6 +46,7 @@ export class DataProduct {
|
|||||||
responseData: ResponseDataType;
|
responseData: ResponseDataType;
|
||||||
|
|
||||||
constructor(domain: Domain, name?: string) {
|
constructor(domain: Domain, name?: string) {
|
||||||
|
super(EntityTypeEndpoint.DATA_PRODUCT);
|
||||||
this.data.domain = domain.data.name;
|
this.data.domain = domain.data.name;
|
||||||
this.data.name = name ?? this.data.name;
|
this.data.name = name ?? this.data.name;
|
||||||
// eslint-disable-next-line no-useless-escape
|
// eslint-disable-next-line no-useless-escape
|
||||||
|
@ -37,6 +37,7 @@ export enum EntityTypeEndpoint {
|
|||||||
User = 'users',
|
User = 'users',
|
||||||
API_COLLECTION = 'apiCollections',
|
API_COLLECTION = 'apiCollections',
|
||||||
API_ENDPOINT = 'apiEndpoints',
|
API_ENDPOINT = 'apiEndpoints',
|
||||||
|
DATA_PRODUCT = 'dataProducts',
|
||||||
}
|
}
|
||||||
|
|
||||||
export type EntityDataType = {
|
export type EntityDataType = {
|
||||||
@ -62,4 +63,5 @@ export enum ENTITY_PATH {
|
|||||||
'dashboard/datamodels' = 'dashboardDataModel',
|
'dashboard/datamodels' = 'dashboardDataModel',
|
||||||
'apiCollections' = 'apiCollection',
|
'apiCollections' = 'apiCollection',
|
||||||
'apiEndpoints' = 'apiEndpoint',
|
'apiEndpoints' = 'apiEndpoint',
|
||||||
|
'dataProducts' = 'dataProduct',
|
||||||
}
|
}
|
||||||
|
@ -407,11 +407,11 @@ const DataModelDetails = ({
|
|||||||
entityDetails={dataModelData}
|
entityDetails={dataModelData}
|
||||||
entityType={EntityType.DASHBOARD_DATA_MODEL}
|
entityType={EntityType.DASHBOARD_DATA_MODEL}
|
||||||
handleExtensionUpdate={handelExtensionUpdate}
|
handleExtensionUpdate={handelExtensionUpdate}
|
||||||
hasEditAccess={dataModelPermissions.ViewAll}
|
hasEditAccess={
|
||||||
hasPermission={
|
|
||||||
dataModelPermissions.EditAll ||
|
dataModelPermissions.EditAll ||
|
||||||
dataModelPermissions.EditCustomFields
|
dataModelPermissions.EditCustomFields
|
||||||
}
|
}
|
||||||
|
hasPermission={dataModelPermissions.ViewAll}
|
||||||
isVersionView={false}
|
isVersionView={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -43,7 +43,7 @@ import {
|
|||||||
OperationPermission,
|
OperationPermission,
|
||||||
ResourceEntity,
|
ResourceEntity,
|
||||||
} from '../../../context/PermissionProvider/PermissionProvider.interface';
|
} from '../../../context/PermissionProvider/PermissionProvider.interface';
|
||||||
import { EntityType } from '../../../enums/entity.enum';
|
import { EntityTabs, EntityType } from '../../../enums/entity.enum';
|
||||||
import { SearchIndex } from '../../../enums/search.enum';
|
import { SearchIndex } from '../../../enums/search.enum';
|
||||||
import {
|
import {
|
||||||
ChangeDescription,
|
ChangeDescription,
|
||||||
@ -69,6 +69,7 @@ import {
|
|||||||
getEncodedFqn,
|
getEncodedFqn,
|
||||||
} from '../../../utils/StringsUtils';
|
} from '../../../utils/StringsUtils';
|
||||||
import { showErrorToast } from '../../../utils/ToastUtils';
|
import { showErrorToast } from '../../../utils/ToastUtils';
|
||||||
|
import { CustomPropertyTable } from '../../common/CustomPropertyTable/CustomPropertyTable';
|
||||||
import { ManageButtonItemLabel } from '../../common/ManageButtonContentItem/ManageButtonContentItem.component';
|
import { ManageButtonItemLabel } from '../../common/ManageButtonContentItem/ManageButtonContentItem.component';
|
||||||
import ResizablePanels from '../../common/ResizablePanels/ResizablePanels';
|
import ResizablePanels from '../../common/ResizablePanels/ResizablePanels';
|
||||||
import TabsLabel from '../../common/TabsLabel/TabsLabel.component';
|
import TabsLabel from '../../common/TabsLabel/TabsLabel.component';
|
||||||
@ -353,9 +354,20 @@ const DataProductsDetailsPage = ({
|
|||||||
fetchDataProductAssets();
|
fetchDataProductAssets();
|
||||||
}
|
}
|
||||||
if (activeKey !== activeTab) {
|
if (activeKey !== activeTab) {
|
||||||
history.push(
|
const path = isVersionsView
|
||||||
getEntityDetailsPath(EntityType.DATA_PRODUCT, dataProductFqn, activeKey)
|
? getVersionPath(
|
||||||
|
EntityType.DATA_PRODUCT,
|
||||||
|
dataProductFqn,
|
||||||
|
toString(dataProduct.version),
|
||||||
|
activeKey
|
||||||
|
)
|
||||||
|
: getEntityDetailsPath(
|
||||||
|
EntityType.DATA_PRODUCT,
|
||||||
|
dataProductFqn,
|
||||||
|
activeKey
|
||||||
);
|
);
|
||||||
|
|
||||||
|
history.push(path);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -375,6 +387,16 @@ const DataProductsDetailsPage = ({
|
|||||||
setPreviewAsset(asset);
|
setPreviewAsset(asset);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handelExtensionUpdate = useCallback(
|
||||||
|
async (updatedDataProduct: DataProduct) => {
|
||||||
|
await onUpdate({
|
||||||
|
...(dataProduct as DataProduct),
|
||||||
|
extension: updatedDataProduct.extension,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[onUpdate, dataProduct]
|
||||||
|
);
|
||||||
|
|
||||||
const tabs = useMemo(() => {
|
const tabs = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@ -388,8 +410,15 @@ const DataProductsDetailsPage = ({
|
|||||||
children: (
|
children: (
|
||||||
<DocumentationTab
|
<DocumentationTab
|
||||||
domain={dataProduct}
|
domain={dataProduct}
|
||||||
|
editCustomAttributePermission={
|
||||||
|
(dataProductPermission.EditAll ||
|
||||||
|
dataProductPermission.EditCustomFields) &&
|
||||||
|
!isVersionsView
|
||||||
|
}
|
||||||
isVersionsView={isVersionsView}
|
isVersionsView={isVersionsView}
|
||||||
type={DocumentationEntity.DATA_PRODUCT}
|
type={DocumentationEntity.DATA_PRODUCT}
|
||||||
|
viewAllPermission={dataProductPermission.ViewAll}
|
||||||
|
onExtensionUpdate={handelExtensionUpdate}
|
||||||
onUpdate={(data: Domain | DataProduct) =>
|
onUpdate={(data: Domain | DataProduct) =>
|
||||||
onUpdate(data as DataProduct)
|
onUpdate(data as DataProduct)
|
||||||
}
|
}
|
||||||
@ -450,6 +479,31 @@ const DataProductsDetailsPage = ({
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
|
{
|
||||||
|
label: (
|
||||||
|
<TabsLabel
|
||||||
|
id={EntityTabs.CUSTOM_PROPERTIES}
|
||||||
|
name={t('label.custom-property-plural')}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
key: EntityTabs.CUSTOM_PROPERTIES,
|
||||||
|
children: (
|
||||||
|
<div className="p-md">
|
||||||
|
<CustomPropertyTable<EntityType.DATA_PRODUCT>
|
||||||
|
entityDetails={dataProduct}
|
||||||
|
entityType={EntityType.DATA_PRODUCT}
|
||||||
|
handleExtensionUpdate={handelExtensionUpdate}
|
||||||
|
hasEditAccess={
|
||||||
|
(dataProductPermission.EditAll ||
|
||||||
|
dataProductPermission.EditCustomFields) &&
|
||||||
|
!isVersionsView
|
||||||
|
}
|
||||||
|
hasPermission={dataProductPermission.ViewAll}
|
||||||
|
isVersionView={isVersionsView}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
}, [
|
}, [
|
||||||
dataProductPermission,
|
dataProductPermission,
|
||||||
@ -459,6 +513,7 @@ const DataProductsDetailsPage = ({
|
|||||||
handleAssetSave,
|
handleAssetSave,
|
||||||
assetCount,
|
assetCount,
|
||||||
activeTab,
|
activeTab,
|
||||||
|
handelExtensionUpdate,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -109,6 +109,7 @@ const DataProductsPage = () => {
|
|||||||
TabSpecificField.OWNERS,
|
TabSpecificField.OWNERS,
|
||||||
TabSpecificField.EXPERTS,
|
TabSpecificField.EXPERTS,
|
||||||
TabSpecificField.ASSETS,
|
TabSpecificField.ASSETS,
|
||||||
|
TabSpecificField.EXTENSION,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
setDataProduct(data);
|
setDataProduct(data);
|
||||||
|
@ -42,6 +42,7 @@ import {
|
|||||||
getOwnerVersionLabel,
|
getOwnerVersionLabel,
|
||||||
} from '../../../../utils/EntityVersionUtils';
|
} from '../../../../utils/EntityVersionUtils';
|
||||||
import { checkPermission } from '../../../../utils/PermissionsUtils';
|
import { checkPermission } from '../../../../utils/PermissionsUtils';
|
||||||
|
import { CustomPropertyTable } from '../../../common/CustomPropertyTable/CustomPropertyTable';
|
||||||
import FormItemLabel from '../../../common/Form/FormItemLabel';
|
import FormItemLabel from '../../../common/Form/FormItemLabel';
|
||||||
import ResizablePanels from '../../../common/ResizablePanels/ResizablePanels';
|
import ResizablePanels from '../../../common/ResizablePanels/ResizablePanels';
|
||||||
import TagButton from '../../../common/TagButton/TagButton.component';
|
import TagButton from '../../../common/TagButton/TagButton.component';
|
||||||
@ -54,6 +55,9 @@ import {
|
|||||||
const DocumentationTab = ({
|
const DocumentationTab = ({
|
||||||
domain,
|
domain,
|
||||||
onUpdate,
|
onUpdate,
|
||||||
|
onExtensionUpdate,
|
||||||
|
editCustomAttributePermission,
|
||||||
|
viewAllPermission,
|
||||||
isVersionsView = false,
|
isVersionsView = false,
|
||||||
type = DocumentationEntity.DOMAIN,
|
type = DocumentationEntity.DOMAIN,
|
||||||
}: DocumentationTabProps) => {
|
}: DocumentationTabProps) => {
|
||||||
@ -353,6 +357,20 @@ const DocumentationTab = ({
|
|||||||
)}
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{domain && type === DocumentationEntity.DATA_PRODUCT && (
|
||||||
|
<Col data-testid="custom-properties-right-panel" span="24">
|
||||||
|
<CustomPropertyTable<EntityType.DATA_PRODUCT>
|
||||||
|
isRenderedInRightPanel
|
||||||
|
entityDetails={domain as DataProduct}
|
||||||
|
entityType={EntityType.DATA_PRODUCT}
|
||||||
|
handleExtensionUpdate={onExtensionUpdate}
|
||||||
|
hasEditAccess={Boolean(editCustomAttributePermission)}
|
||||||
|
hasPermission={Boolean(viewAllPermission)}
|
||||||
|
maxDataCap={5}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
)}
|
||||||
</Row>
|
</Row>
|
||||||
),
|
),
|
||||||
minWidth: 320,
|
minWidth: 320,
|
||||||
|
@ -18,6 +18,9 @@ export interface DocumentationTabProps {
|
|||||||
onUpdate: (value: Domain | DataProduct) => Promise<void>;
|
onUpdate: (value: Domain | DataProduct) => Promise<void>;
|
||||||
isVersionsView?: boolean;
|
isVersionsView?: boolean;
|
||||||
type?: DocumentationEntity;
|
type?: DocumentationEntity;
|
||||||
|
onExtensionUpdate?: (updatedDataProduct: DataProduct) => Promise<void>;
|
||||||
|
editCustomAttributePermission?: boolean;
|
||||||
|
viewAllPermission?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DocumentationEntity {
|
export enum DocumentationEntity {
|
||||||
|
@ -26,6 +26,7 @@ import { SearchIndex } from '../../../generated/entity/data/searchIndex';
|
|||||||
import { StoredProcedure } from '../../../generated/entity/data/storedProcedure';
|
import { StoredProcedure } from '../../../generated/entity/data/storedProcedure';
|
||||||
import { Table } from '../../../generated/entity/data/table';
|
import { Table } from '../../../generated/entity/data/table';
|
||||||
import { Topic } from '../../../generated/entity/data/topic';
|
import { Topic } from '../../../generated/entity/data/topic';
|
||||||
|
import { DataProduct } from '../../../generated/entity/domains/dataProduct';
|
||||||
import { EntityReference } from '../../../generated/entity/type';
|
import { EntityReference } from '../../../generated/entity/type';
|
||||||
import { CustomProperty } from '../../../generated/type/customProperty';
|
import { CustomProperty } from '../../../generated/type/customProperty';
|
||||||
|
|
||||||
@ -44,6 +45,7 @@ export type ExtentionEntities = {
|
|||||||
[EntityType.DASHBOARD_DATA_MODEL]: DashboardDataModel;
|
[EntityType.DASHBOARD_DATA_MODEL]: DashboardDataModel;
|
||||||
[EntityType.API_COLLECTION]: APICollection;
|
[EntityType.API_COLLECTION]: APICollection;
|
||||||
[EntityType.API_ENDPOINT]: APIEndpoint;
|
[EntityType.API_ENDPOINT]: APIEndpoint;
|
||||||
|
[EntityType.DATA_PRODUCT]: DataProduct;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ExtentionEntitiesKeys = keyof ExtentionEntities;
|
export type ExtentionEntitiesKeys = keyof ExtentionEntities;
|
||||||
|
@ -74,6 +74,7 @@ export enum GlobalSettingOptions {
|
|||||||
APIS = 'apiServices',
|
APIS = 'apiServices',
|
||||||
API_COLLECTIONS = 'apiCollections',
|
API_COLLECTIONS = 'apiCollections',
|
||||||
API_ENDPOINTS = 'apiEndpoints',
|
API_ENDPOINTS = 'apiEndpoints',
|
||||||
|
DATA_PRODUCT = 'dataProducts',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GLOBAL_SETTING_PERMISSION_RESOURCES = [
|
export const GLOBAL_SETTING_PERMISSION_RESOURCES = [
|
||||||
|
@ -118,6 +118,12 @@ export const PAGE_HEADERS = {
|
|||||||
entity: i18n.t('label.dashboard-data-model-plural'),
|
entity: i18n.t('label.dashboard-data-model-plural'),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
DATA_PRODUCT_CUSTOM_ATTRIBUTES: {
|
||||||
|
header: i18n.t('label.data-product-plural'),
|
||||||
|
subHeader: i18n.t('message.define-custom-property-for-entity', {
|
||||||
|
entity: i18n.t('label.data-product-plural'),
|
||||||
|
}),
|
||||||
|
},
|
||||||
PIPELINES_CUSTOM_ATTRIBUTES: {
|
PIPELINES_CUSTOM_ATTRIBUTES: {
|
||||||
header: i18n.t('label.pipeline-plural'),
|
header: i18n.t('label.pipeline-plural'),
|
||||||
subHeader: i18n.t('message.define-custom-property-for-entity', {
|
subHeader: i18n.t('message.define-custom-property-for-entity', {
|
||||||
|
@ -532,6 +532,7 @@ export const ENTITY_PATH = {
|
|||||||
dashboardDataModels: 'dashboardDataModel',
|
dashboardDataModels: 'dashboardDataModel',
|
||||||
apiCollections: 'apiCollection',
|
apiCollections: 'apiCollection',
|
||||||
apiEndpoints: 'apiEndpoint',
|
apiEndpoints: 'apiEndpoint',
|
||||||
|
dataProducts: 'dataProduct',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const VALIDATION_MESSAGES = {
|
export const VALIDATION_MESSAGES = {
|
||||||
|
@ -157,6 +157,9 @@ const CustomEntityDetailV1 = () => {
|
|||||||
case ENTITY_PATH.dashboardDataModels:
|
case ENTITY_PATH.dashboardDataModels:
|
||||||
return PAGE_HEADERS.DASHBOARD_DATA_MODEL_CUSTOM_ATTRIBUTES;
|
return PAGE_HEADERS.DASHBOARD_DATA_MODEL_CUSTOM_ATTRIBUTES;
|
||||||
|
|
||||||
|
case ENTITY_PATH.dataProducts:
|
||||||
|
return PAGE_HEADERS.DATA_PRODUCT_CUSTOM_ATTRIBUTES;
|
||||||
|
|
||||||
case ENTITY_PATH.pipelines:
|
case ENTITY_PATH.pipelines:
|
||||||
return PAGE_HEADERS.PIPELINES_CUSTOM_ATTRIBUTES;
|
return PAGE_HEADERS.PIPELINES_CUSTOM_ATTRIBUTES;
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import { ReactComponent as BotIcon } from '../assets/svg/bot-colored.svg';
|
|||||||
import { ReactComponent as AppearanceIcon } from '../assets/svg/custom-logo-colored.svg';
|
import { ReactComponent as AppearanceIcon } from '../assets/svg/custom-logo-colored.svg';
|
||||||
import { ReactComponent as CustomDashboardLogoIcon } from '../assets/svg/customize-landing-page-colored.svg';
|
import { ReactComponent as CustomDashboardLogoIcon } from '../assets/svg/customize-landing-page-colored.svg';
|
||||||
import { ReactComponent as DashboardIcon } from '../assets/svg/dashboard-colored.svg';
|
import { ReactComponent as DashboardIcon } from '../assets/svg/dashboard-colored.svg';
|
||||||
|
import { ReactComponent as DashboardDataModelIcon } from '../assets/svg/data-model.svg';
|
||||||
import { ReactComponent as DatabaseIcon } from '../assets/svg/database-colored.svg';
|
import { ReactComponent as DatabaseIcon } from '../assets/svg/database-colored.svg';
|
||||||
import { ReactComponent as SchemaIcon } from '../assets/svg/database-schema.svg';
|
import { ReactComponent as SchemaIcon } from '../assets/svg/database-schema.svg';
|
||||||
import { ReactComponent as EmailIcon } from '../assets/svg/email-colored.svg';
|
import { ReactComponent as EmailIcon } from '../assets/svg/email-colored.svg';
|
||||||
@ -26,6 +27,7 @@ import { ReactComponent as GlossaryIcon } from '../assets/svg/glossary-colored.s
|
|||||||
import { ReactComponent as APICollectionIcon } from '../assets/svg/ic-api-collection.svg';
|
import { ReactComponent as APICollectionIcon } from '../assets/svg/ic-api-collection.svg';
|
||||||
import { ReactComponent as APIEndpointIcon } from '../assets/svg/ic-api-endpoint.svg';
|
import { ReactComponent as APIEndpointIcon } from '../assets/svg/ic-api-endpoint.svg';
|
||||||
import { ReactComponent as IconAPI } from '../assets/svg/ic-api-service.svg';
|
import { ReactComponent as IconAPI } from '../assets/svg/ic-api-service.svg';
|
||||||
|
import { ReactComponent as DataProductIcon } from '../assets/svg/ic-data-product.svg';
|
||||||
import { ReactComponent as LoginIcon } from '../assets/svg/login-colored.svg';
|
import { ReactComponent as LoginIcon } from '../assets/svg/login-colored.svg';
|
||||||
import { ReactComponent as OpenMetadataIcon } from '../assets/svg/logo-monogram.svg';
|
import { ReactComponent as OpenMetadataIcon } from '../assets/svg/logo-monogram.svg';
|
||||||
import { ReactComponent as MessagingIcon } from '../assets/svg/messaging-colored.svg';
|
import { ReactComponent as MessagingIcon } from '../assets/svg/messaging-colored.svg';
|
||||||
@ -378,6 +380,24 @@ class GlobalSettingsClassBase {
|
|||||||
key: `${GlobalSettingsMenuCategory.CUSTOM_PROPERTIES}.${GlobalSettingOptions.API_ENDPOINTS}`,
|
key: `${GlobalSettingsMenuCategory.CUSTOM_PROPERTIES}.${GlobalSettingOptions.API_ENDPOINTS}`,
|
||||||
icon: APIEndpointIcon,
|
icon: APIEndpointIcon,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: t('label.data-product'),
|
||||||
|
description: t('message.define-custom-property-for-entity', {
|
||||||
|
entity: t('label.data-product'),
|
||||||
|
}),
|
||||||
|
isProtected: Boolean(isAdminUser),
|
||||||
|
key: `${GlobalSettingsMenuCategory.CUSTOM_PROPERTIES}.${GlobalSettingOptions.DATA_PRODUCT}`,
|
||||||
|
icon: DataProductIcon,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('label.dashboard-data-model-plural'),
|
||||||
|
description: t('message.define-custom-property-for-entity', {
|
||||||
|
entity: t('label.dashboard-data-model-plural'),
|
||||||
|
}),
|
||||||
|
isProtected: Boolean(isAdminUser),
|
||||||
|
key: `${GlobalSettingsMenuCategory.CUSTOM_PROPERTIES}.${GlobalSettingOptions.DASHBOARD_DATA_MODEL}`,
|
||||||
|
icon: DashboardDataModelIcon,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: t('label.database'),
|
label: t('label.database'),
|
||||||
description: t('message.define-custom-property-for-entity', {
|
description: t('message.define-custom-property-for-entity', {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user