Fixes #16498 : Support custom properties for Data Products (#17641)

This commit is contained in:
sonika-shah 2024-08-31 09:43:37 +05:30 committed by GitHub
parent 0dcf9d7ab3
commit 6d32257765
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 235 additions and 8 deletions

View File

@ -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);

View File

@ -228,6 +228,9 @@
} }
} }
}, },
"extension": {
"type": "object"
},
"totalVotes": { "totalVotes": {
"type": "long", "type": "long",
"null_value": 0 "null_value": 0

View File

@ -226,6 +226,9 @@
} }
} }
}, },
"extension": {
"type": "object"
},
"totalVotes": { "totalVotes": {
"type": "long", "type": "long",
"null_value": 0 "null_value": 0

View File

@ -203,6 +203,9 @@
} }
} }
}, },
"extension": {
"type": "object"
},
"totalVotes": { "totalVotes": {
"type": "long", "type": "long",
"null_value": 0 "null_value": 0

View File

@ -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": [

View File

@ -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"],

View File

@ -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 = {

View File

@ -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}`,
],
}; };

View File

@ -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,
}) => { }) => {

View File

@ -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

View File

@ -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',
} }

View File

@ -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>

View File

@ -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(() => {

View File

@ -109,6 +109,7 @@ const DataProductsPage = () => {
TabSpecificField.OWNERS, TabSpecificField.OWNERS,
TabSpecificField.EXPERTS, TabSpecificField.EXPERTS,
TabSpecificField.ASSETS, TabSpecificField.ASSETS,
TabSpecificField.EXTENSION,
], ],
}); });
setDataProduct(data); setDataProduct(data);

View File

@ -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,

View File

@ -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 {

View File

@ -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;

View File

@ -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 = [

View File

@ -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', {

View File

@ -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 = {

View File

@ -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;

View File

@ -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', {