From 507087a0702402c6e18a5b95572ba5665c64bee8 Mon Sep 17 00:00:00 2001 From: kevinkarchacryl Date: Thu, 12 Dec 2024 08:13:08 -0500 Subject: [PATCH 1/3] feat(glossary): support multiple ownership types (#12050) Co-authored-by: Aseem Bansal --- .../source/metadata/business_glossary.py | 53 ++-- .../custom_ownership_urns.yml | 38 +++ .../custom_ownership_urns_golden.json | 188 ++++++++++++ .../multiple_owners_different_types.yml | 39 +++ ...ultiple_owners_different_types_golden.json | 138 +++++++++ .../multiple_owners_same_type.yml | 37 +++ .../multiple_owners_same_type_golden.json | 142 +++++++++ .../business-glossary/single_owner_types.yml | 39 +++ .../single_owner_types_golden.json | 278 ++++++++++++++++++ .../test_business_glossary.py | 128 ++++++++ 10 files changed, 1062 insertions(+), 18 deletions(-) create mode 100644 metadata-ingestion/tests/integration/business-glossary/custom_ownership_urns.yml create mode 100644 metadata-ingestion/tests/integration/business-glossary/custom_ownership_urns_golden.json create mode 100644 metadata-ingestion/tests/integration/business-glossary/multiple_owners_different_types.yml create mode 100644 metadata-ingestion/tests/integration/business-glossary/multiple_owners_different_types_golden.json create mode 100644 metadata-ingestion/tests/integration/business-glossary/multiple_owners_same_type.yml create mode 100644 metadata-ingestion/tests/integration/business-glossary/multiple_owners_same_type_golden.json create mode 100644 metadata-ingestion/tests/integration/business-glossary/single_owner_types.yml create mode 100644 metadata-ingestion/tests/integration/business-glossary/single_owner_types_golden.json diff --git a/metadata-ingestion/src/datahub/ingestion/source/metadata/business_glossary.py b/metadata-ingestion/src/datahub/ingestion/source/metadata/business_glossary.py index 79ec47a7efb2c2..26a0331e1e5767 100644 --- a/metadata-ingestion/src/datahub/ingestion/source/metadata/business_glossary.py +++ b/metadata-ingestion/src/datahub/ingestion/source/metadata/business_glossary.py @@ -45,6 +45,9 @@ class Owners(ConfigModel): groups: Optional[List[str]] = None +OwnersMultipleTypes = Union[List[Owners], Owners] + + class KnowledgeCard(ConfigModel): url: Optional[str] = None label: Optional[str] = None @@ -57,7 +60,7 @@ class GlossaryTermConfig(ConfigModel): term_source: Optional[str] = None source_ref: Optional[str] = None source_url: Optional[str] = None - owners: Optional[Owners] = None + owners: Optional[OwnersMultipleTypes] = None inherits: Optional[List[str]] = None contains: Optional[List[str]] = None values: Optional[List[str]] = None @@ -74,7 +77,7 @@ class GlossaryNodeConfig(ConfigModel): id: Optional[str] = None name: str description: str - owners: Optional[Owners] = None + owners: Optional[OwnersMultipleTypes] = None terms: Optional[List["GlossaryTermConfig"]] = None nodes: Optional[List["GlossaryNodeConfig"]] = None knowledge_links: Optional[List[KnowledgeCard]] = None @@ -88,7 +91,7 @@ class DefaultConfig(ConfigModel): """Holds defaults for populating fields in glossary terms""" source: Optional[str] = None - owners: Owners + owners: OwnersMultipleTypes url: Optional[str] = None source_type: str = "INTERNAL" @@ -153,30 +156,44 @@ def make_glossary_term_urn( return "urn:li:glossaryTerm:" + create_id(path, default_id, enable_auto_id) -def get_owners(owners: Owners) -> models.OwnershipClass: - ownership_type, ownership_type_urn = validate_ownership_type(owners.type) +def get_owners_multiple_types(owners: OwnersMultipleTypes) -> models.OwnershipClass: + """Allows owner types to be a list and maintains backward compatibility""" + if isinstance(owners, Owners): + return models.OwnershipClass(owners=list(get_owners(owners))) + + owners_meta: List[models.OwnerClass] = [] + for owner in owners: + owners_meta.extend(get_owners(owner)) + + return models.OwnershipClass(owners=owners_meta) + + +def get_owners(owners: Owners) -> Iterable[models.OwnerClass]: + actual_type = owners.type or models.OwnershipTypeClass.DEVELOPER + + if actual_type.startswith("urn:li:ownershipType:"): + ownership_type: str = "CUSTOM" + ownership_type_urn: Optional[str] = actual_type + else: + ownership_type, ownership_type_urn = validate_ownership_type(actual_type) + if owners.typeUrn is not None: ownership_type_urn = owners.typeUrn - owners_meta: List[models.OwnerClass] = [] + if owners.users is not None: - owners_meta = owners_meta + [ - models.OwnerClass( + for o in owners.users: + yield models.OwnerClass( owner=make_user_urn(o), type=ownership_type, typeUrn=ownership_type_urn, ) - for o in owners.users - ] if owners.groups is not None: - owners_meta = owners_meta + [ - models.OwnerClass( + for o in owners.groups: + yield models.OwnerClass( owner=make_group_urn(o), type=ownership_type, typeUrn=ownership_type_urn, ) - for o in owners.groups - ] - return models.OwnershipClass(owners=owners_meta) def get_mces( @@ -185,7 +202,7 @@ def get_mces( ingestion_config: BusinessGlossarySourceConfig, ctx: PipelineContext, ) -> Iterable[Union[MetadataChangeProposalWrapper, models.MetadataChangeEventClass]]: - root_owners = get_owners(glossary.owners) + root_owners = get_owners_multiple_types(glossary.owners) if glossary.nodes: for node in glossary.nodes: @@ -270,7 +287,7 @@ def get_mces_from_node( node_owners = parentOwners if glossaryNode.owners is not None: assert glossaryNode.owners is not None - node_owners = get_owners(glossaryNode.owners) + node_owners = get_owners_multiple_types(glossaryNode.owners) node_snapshot = models.GlossaryNodeSnapshotClass( urn=node_urn, @@ -426,7 +443,7 @@ def get_mces_from_term( ownership: models.OwnershipClass = parentOwnership if glossaryTerm.owners is not None: assert glossaryTerm.owners is not None - ownership = get_owners(glossaryTerm.owners) + ownership = get_owners_multiple_types(glossaryTerm.owners) aspects.append(ownership) if glossaryTerm.domain is not None: diff --git a/metadata-ingestion/tests/integration/business-glossary/custom_ownership_urns.yml b/metadata-ingestion/tests/integration/business-glossary/custom_ownership_urns.yml new file mode 100644 index 00000000000000..94aae6999a3f50 --- /dev/null +++ b/metadata-ingestion/tests/integration/business-glossary/custom_ownership_urns.yml @@ -0,0 +1,38 @@ +version: "1" +source: DataHub +owners: + users: + - mjames +url: "https://github.com/datahub-project/datahub/" + +nodes: + - name: Custom URN Types + description: Testing custom ownership URN types + owners: + - type: urn:li:ownershipType:custom_type_1 + users: + - user1 + groups: + - group1 + - type: urn:li:ownershipType:custom_type_2 + users: + - user2 + terms: + - name: Mixed URN Types + description: Term with custom URN types + owners: + - type: urn:li:ownershipType:custom_type_3 + users: + - user3 + - type: urn:li:ownershipType:custom_type_4 + groups: + - group2 + - name: Mixed Standard and URN + description: Term with both standard and URN types + owners: + - type: DEVELOPER + users: + - dev1 + - type: urn:li:ownershipType:custom_type_5 + groups: + - group3 \ No newline at end of file diff --git a/metadata-ingestion/tests/integration/business-glossary/custom_ownership_urns_golden.json b/metadata-ingestion/tests/integration/business-glossary/custom_ownership_urns_golden.json new file mode 100644 index 00000000000000..2fc3de77efd8eb --- /dev/null +++ b/metadata-ingestion/tests/integration/business-glossary/custom_ownership_urns_golden.json @@ -0,0 +1,188 @@ +[ +{ + "proposedSnapshot": { + "com.linkedin.pegasus2avro.metadata.snapshot.GlossaryNodeSnapshot": { + "urn": "urn:li:glossaryNode:Custom URN Types", + "aspects": [ + { + "com.linkedin.pegasus2avro.glossary.GlossaryNodeInfo": { + "customProperties": {}, + "definition": "Testing custom ownership URN types", + "name": "Custom URN Types" + } + }, + { + "com.linkedin.pegasus2avro.common.Ownership": { + "owners": [ + { + "owner": "urn:li:corpuser:user1", + "type": "CUSTOM", + "typeUrn": "urn:li:ownershipType:custom_type_1" + }, + { + "owner": "urn:li:corpGroup:group1", + "type": "CUSTOM", + "typeUrn": "urn:li:ownershipType:custom_type_1" + }, + { + "owner": "urn:li:corpuser:user2", + "type": "CUSTOM", + "typeUrn": "urn:li:ownershipType:custom_type_2" + } + ], + "ownerTypes": {}, + "lastModified": { + "time": 0, + "actor": "urn:li:corpuser:unknown" + } + } + } + ] + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-dlsmlo", + "lastRunId": "no-run-id-provided" + } +}, +{ + "proposedSnapshot": { + "com.linkedin.pegasus2avro.metadata.snapshot.GlossaryTermSnapshot": { + "urn": "urn:li:glossaryTerm:Custom URN Types.Mixed URN Types", + "aspects": [ + { + "com.linkedin.pegasus2avro.glossary.GlossaryTermInfo": { + "customProperties": {}, + "name": "Mixed URN Types", + "definition": "Term with custom URN types", + "parentNode": "urn:li:glossaryNode:Custom URN Types", + "termSource": "INTERNAL", + "sourceRef": "DataHub", + "sourceUrl": "https://github.com/datahub-project/datahub/" + } + }, + { + "com.linkedin.pegasus2avro.common.Ownership": { + "owners": [ + { + "owner": "urn:li:corpuser:user3", + "type": "CUSTOM", + "typeUrn": "urn:li:ownershipType:custom_type_3" + }, + { + "owner": "urn:li:corpGroup:group2", + "type": "CUSTOM", + "typeUrn": "urn:li:ownershipType:custom_type_4" + } + ], + "ownerTypes": {}, + "lastModified": { + "time": 0, + "actor": "urn:li:corpuser:unknown" + } + } + } + ] + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-dlsmlo", + "lastRunId": "no-run-id-provided" + } +}, +{ + "proposedSnapshot": { + "com.linkedin.pegasus2avro.metadata.snapshot.GlossaryTermSnapshot": { + "urn": "urn:li:glossaryTerm:Custom URN Types.Mixed Standard and URN", + "aspects": [ + { + "com.linkedin.pegasus2avro.glossary.GlossaryTermInfo": { + "customProperties": {}, + "name": "Mixed Standard and URN", + "definition": "Term with both standard and URN types", + "parentNode": "urn:li:glossaryNode:Custom URN Types", + "termSource": "INTERNAL", + "sourceRef": "DataHub", + "sourceUrl": "https://github.com/datahub-project/datahub/" + } + }, + { + "com.linkedin.pegasus2avro.common.Ownership": { + "owners": [ + { + "owner": "urn:li:corpuser:dev1", + "type": "DEVELOPER" + }, + { + "owner": "urn:li:corpGroup:group3", + "type": "CUSTOM", + "typeUrn": "urn:li:ownershipType:custom_type_5" + } + ], + "ownerTypes": {}, + "lastModified": { + "time": 0, + "actor": "urn:li:corpuser:unknown" + } + } + } + ] + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-dlsmlo", + "lastRunId": "no-run-id-provided" + } +}, +{ + "entityType": "glossaryNode", + "entityUrn": "urn:li:glossaryNode:Custom URN Types", + "changeType": "UPSERT", + "aspectName": "status", + "aspect": { + "json": { + "removed": false + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-dlsmlo", + "lastRunId": "no-run-id-provided" + } +}, +{ + "entityType": "glossaryTerm", + "entityUrn": "urn:li:glossaryTerm:Custom URN Types.Mixed Standard and URN", + "changeType": "UPSERT", + "aspectName": "status", + "aspect": { + "json": { + "removed": false + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-dlsmlo", + "lastRunId": "no-run-id-provided" + } +}, +{ + "entityType": "glossaryTerm", + "entityUrn": "urn:li:glossaryTerm:Custom URN Types.Mixed URN Types", + "changeType": "UPSERT", + "aspectName": "status", + "aspect": { + "json": { + "removed": false + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-dlsmlo", + "lastRunId": "no-run-id-provided" + } +} +] \ No newline at end of file diff --git a/metadata-ingestion/tests/integration/business-glossary/multiple_owners_different_types.yml b/metadata-ingestion/tests/integration/business-glossary/multiple_owners_different_types.yml new file mode 100644 index 00000000000000..efcc594f758fa8 --- /dev/null +++ b/metadata-ingestion/tests/integration/business-glossary/multiple_owners_different_types.yml @@ -0,0 +1,39 @@ +version: "1" +source: DataHub +owners: + users: + - mjames +url: "https://github.com/datahub-project/datahub/" + +nodes: + - name: Different Owner Types + description: Testing multiple owners with different types + owners: + - type: DEVELOPER + users: + - dev1 + groups: + - engineering + - type: DATAOWNER + users: + - owner1 + groups: + - data_stewards + - type: PRODUCER + users: + - producer1 + terms: + - name: Mixed Ownership + description: Term with different owner types + owners: + - type: STAKEHOLDER + users: + - stakeholder1 + groups: + - business + - type: DEVELOPER + users: + - dev2 + - type: DATAOWNER + groups: + - compliance \ No newline at end of file diff --git a/metadata-ingestion/tests/integration/business-glossary/multiple_owners_different_types_golden.json b/metadata-ingestion/tests/integration/business-glossary/multiple_owners_different_types_golden.json new file mode 100644 index 00000000000000..4cec348708291a --- /dev/null +++ b/metadata-ingestion/tests/integration/business-glossary/multiple_owners_different_types_golden.json @@ -0,0 +1,138 @@ +[ +{ + "proposedSnapshot": { + "com.linkedin.pegasus2avro.metadata.snapshot.GlossaryNodeSnapshot": { + "urn": "urn:li:glossaryNode:Different Owner Types", + "aspects": [ + { + "com.linkedin.pegasus2avro.glossary.GlossaryNodeInfo": { + "customProperties": {}, + "definition": "Testing multiple owners with different types", + "name": "Different Owner Types" + } + }, + { + "com.linkedin.pegasus2avro.common.Ownership": { + "owners": [ + { + "owner": "urn:li:corpuser:dev1", + "type": "DEVELOPER" + }, + { + "owner": "urn:li:corpGroup:engineering", + "type": "DEVELOPER" + }, + { + "owner": "urn:li:corpuser:owner1", + "type": "DATAOWNER" + }, + { + "owner": "urn:li:corpGroup:data_stewards", + "type": "DATAOWNER" + }, + { + "owner": "urn:li:corpuser:producer1", + "type": "PRODUCER" + } + ], + "ownerTypes": {}, + "lastModified": { + "time": 0, + "actor": "urn:li:corpuser:unknown" + } + } + } + ] + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-2te9j9", + "lastRunId": "no-run-id-provided" + } +}, +{ + "proposedSnapshot": { + "com.linkedin.pegasus2avro.metadata.snapshot.GlossaryTermSnapshot": { + "urn": "urn:li:glossaryTerm:Different Owner Types.Mixed Ownership", + "aspects": [ + { + "com.linkedin.pegasus2avro.glossary.GlossaryTermInfo": { + "customProperties": {}, + "name": "Mixed Ownership", + "definition": "Term with different owner types", + "parentNode": "urn:li:glossaryNode:Different Owner Types", + "termSource": "INTERNAL", + "sourceRef": "DataHub", + "sourceUrl": "https://github.com/datahub-project/datahub/" + } + }, + { + "com.linkedin.pegasus2avro.common.Ownership": { + "owners": [ + { + "owner": "urn:li:corpuser:stakeholder1", + "type": "STAKEHOLDER" + }, + { + "owner": "urn:li:corpGroup:business", + "type": "STAKEHOLDER" + }, + { + "owner": "urn:li:corpuser:dev2", + "type": "DEVELOPER" + }, + { + "owner": "urn:li:corpGroup:compliance", + "type": "DATAOWNER" + } + ], + "ownerTypes": {}, + "lastModified": { + "time": 0, + "actor": "urn:li:corpuser:unknown" + } + } + } + ] + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-2te9j9", + "lastRunId": "no-run-id-provided" + } +}, +{ + "entityType": "glossaryNode", + "entityUrn": "urn:li:glossaryNode:Different Owner Types", + "changeType": "UPSERT", + "aspectName": "status", + "aspect": { + "json": { + "removed": false + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-2te9j9", + "lastRunId": "no-run-id-provided" + } +}, +{ + "entityType": "glossaryTerm", + "entityUrn": "urn:li:glossaryTerm:Different Owner Types.Mixed Ownership", + "changeType": "UPSERT", + "aspectName": "status", + "aspect": { + "json": { + "removed": false + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-2te9j9", + "lastRunId": "no-run-id-provided" + } +} +] \ No newline at end of file diff --git a/metadata-ingestion/tests/integration/business-glossary/multiple_owners_same_type.yml b/metadata-ingestion/tests/integration/business-glossary/multiple_owners_same_type.yml new file mode 100644 index 00000000000000..8fb093b8b58993 --- /dev/null +++ b/metadata-ingestion/tests/integration/business-glossary/multiple_owners_same_type.yml @@ -0,0 +1,37 @@ +version: "1" +source: DataHub +owners: + users: + - mjames +url: "https://github.com/datahub-project/datahub/" + +nodes: + - name: Multiple Owners + description: Testing multiple owners with same type + owners: + - type: DEVELOPER + users: + - dev1 + - dev2 + groups: + - engineering + - type: DEVELOPER + users: + - dev3 + groups: + - qa + terms: + - name: Multiple Dev Owners + description: Term owned by multiple developers + owners: + - type: DEVELOPER + users: + - dev4 + - dev5 + groups: + - platform + - type: DEVELOPER + users: + - dev6 + groups: + - infra \ No newline at end of file diff --git a/metadata-ingestion/tests/integration/business-glossary/multiple_owners_same_type_golden.json b/metadata-ingestion/tests/integration/business-glossary/multiple_owners_same_type_golden.json new file mode 100644 index 00000000000000..9342682510d84b --- /dev/null +++ b/metadata-ingestion/tests/integration/business-glossary/multiple_owners_same_type_golden.json @@ -0,0 +1,142 @@ +[ +{ + "proposedSnapshot": { + "com.linkedin.pegasus2avro.metadata.snapshot.GlossaryNodeSnapshot": { + "urn": "urn:li:glossaryNode:Multiple Owners", + "aspects": [ + { + "com.linkedin.pegasus2avro.glossary.GlossaryNodeInfo": { + "customProperties": {}, + "definition": "Testing multiple owners with same type", + "name": "Multiple Owners" + } + }, + { + "com.linkedin.pegasus2avro.common.Ownership": { + "owners": [ + { + "owner": "urn:li:corpuser:dev1", + "type": "DEVELOPER" + }, + { + "owner": "urn:li:corpuser:dev2", + "type": "DEVELOPER" + }, + { + "owner": "urn:li:corpGroup:engineering", + "type": "DEVELOPER" + }, + { + "owner": "urn:li:corpuser:dev3", + "type": "DEVELOPER" + }, + { + "owner": "urn:li:corpGroup:qa", + "type": "DEVELOPER" + } + ], + "ownerTypes": {}, + "lastModified": { + "time": 0, + "actor": "urn:li:corpuser:unknown" + } + } + } + ] + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-0l66l7", + "lastRunId": "no-run-id-provided" + } +}, +{ + "proposedSnapshot": { + "com.linkedin.pegasus2avro.metadata.snapshot.GlossaryTermSnapshot": { + "urn": "urn:li:glossaryTerm:Multiple Owners.Multiple Dev Owners", + "aspects": [ + { + "com.linkedin.pegasus2avro.glossary.GlossaryTermInfo": { + "customProperties": {}, + "name": "Multiple Dev Owners", + "definition": "Term owned by multiple developers", + "parentNode": "urn:li:glossaryNode:Multiple Owners", + "termSource": "INTERNAL", + "sourceRef": "DataHub", + "sourceUrl": "https://github.com/datahub-project/datahub/" + } + }, + { + "com.linkedin.pegasus2avro.common.Ownership": { + "owners": [ + { + "owner": "urn:li:corpuser:dev4", + "type": "DEVELOPER" + }, + { + "owner": "urn:li:corpuser:dev5", + "type": "DEVELOPER" + }, + { + "owner": "urn:li:corpGroup:platform", + "type": "DEVELOPER" + }, + { + "owner": "urn:li:corpuser:dev6", + "type": "DEVELOPER" + }, + { + "owner": "urn:li:corpGroup:infra", + "type": "DEVELOPER" + } + ], + "ownerTypes": {}, + "lastModified": { + "time": 0, + "actor": "urn:li:corpuser:unknown" + } + } + } + ] + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-0l66l7", + "lastRunId": "no-run-id-provided" + } +}, +{ + "entityType": "glossaryNode", + "entityUrn": "urn:li:glossaryNode:Multiple Owners", + "changeType": "UPSERT", + "aspectName": "status", + "aspect": { + "json": { + "removed": false + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-0l66l7", + "lastRunId": "no-run-id-provided" + } +}, +{ + "entityType": "glossaryTerm", + "entityUrn": "urn:li:glossaryTerm:Multiple Owners.Multiple Dev Owners", + "changeType": "UPSERT", + "aspectName": "status", + "aspect": { + "json": { + "removed": false + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-0l66l7", + "lastRunId": "no-run-id-provided" + } +} +] \ No newline at end of file diff --git a/metadata-ingestion/tests/integration/business-glossary/single_owner_types.yml b/metadata-ingestion/tests/integration/business-glossary/single_owner_types.yml new file mode 100644 index 00000000000000..22fc24e6695bc2 --- /dev/null +++ b/metadata-ingestion/tests/integration/business-glossary/single_owner_types.yml @@ -0,0 +1,39 @@ +version: "1" +source: DataHub +url: "https://github.com/datahub-project/datahub/" +owners: + users: + - mjames + +nodes: + - name: Single Owner Types + description: Testing different single owner types + owners: + type: DEVELOPER + users: + - dev1 + terms: + - name: Developer Owned + description: Term owned by developer + owners: + type: DEVELOPER + users: + - dev2 + - name: Data Owner Owned + description: Term owned by data owner + owners: + type: DATAOWNER + users: + - dataowner1 + - name: Producer Owned + description: Term owned by producer + owners: + type: PRODUCER + users: + - producer1 + - name: Stakeholder Owned + description: Term owned by stakeholder + owners: + type: STAKEHOLDER + groups: + - stakeholders \ No newline at end of file diff --git a/metadata-ingestion/tests/integration/business-glossary/single_owner_types_golden.json b/metadata-ingestion/tests/integration/business-glossary/single_owner_types_golden.json new file mode 100644 index 00000000000000..006e77f523a10b --- /dev/null +++ b/metadata-ingestion/tests/integration/business-glossary/single_owner_types_golden.json @@ -0,0 +1,278 @@ +[ +{ + "proposedSnapshot": { + "com.linkedin.pegasus2avro.metadata.snapshot.GlossaryNodeSnapshot": { + "urn": "urn:li:glossaryNode:Single Owner Types", + "aspects": [ + { + "com.linkedin.pegasus2avro.glossary.GlossaryNodeInfo": { + "customProperties": {}, + "definition": "Testing different single owner types", + "name": "Single Owner Types" + } + }, + { + "com.linkedin.pegasus2avro.common.Ownership": { + "owners": [ + { + "owner": "urn:li:corpuser:dev1", + "type": "DEVELOPER" + } + ], + "ownerTypes": {}, + "lastModified": { + "time": 0, + "actor": "urn:li:corpuser:unknown" + } + } + } + ] + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-ruwyic", + "lastRunId": "no-run-id-provided" + } +}, +{ + "proposedSnapshot": { + "com.linkedin.pegasus2avro.metadata.snapshot.GlossaryTermSnapshot": { + "urn": "urn:li:glossaryTerm:Single Owner Types.Developer Owned", + "aspects": [ + { + "com.linkedin.pegasus2avro.glossary.GlossaryTermInfo": { + "customProperties": {}, + "name": "Developer Owned", + "definition": "Term owned by developer", + "parentNode": "urn:li:glossaryNode:Single Owner Types", + "termSource": "INTERNAL", + "sourceRef": "DataHub", + "sourceUrl": "https://github.com/datahub-project/datahub/" + } + }, + { + "com.linkedin.pegasus2avro.common.Ownership": { + "owners": [ + { + "owner": "urn:li:corpuser:dev2", + "type": "DEVELOPER" + } + ], + "ownerTypes": {}, + "lastModified": { + "time": 0, + "actor": "urn:li:corpuser:unknown" + } + } + } + ] + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-ruwyic", + "lastRunId": "no-run-id-provided" + } +}, +{ + "proposedSnapshot": { + "com.linkedin.pegasus2avro.metadata.snapshot.GlossaryTermSnapshot": { + "urn": "urn:li:glossaryTerm:Single Owner Types.Data Owner Owned", + "aspects": [ + { + "com.linkedin.pegasus2avro.glossary.GlossaryTermInfo": { + "customProperties": {}, + "name": "Data Owner Owned", + "definition": "Term owned by data owner", + "parentNode": "urn:li:glossaryNode:Single Owner Types", + "termSource": "INTERNAL", + "sourceRef": "DataHub", + "sourceUrl": "https://github.com/datahub-project/datahub/" + } + }, + { + "com.linkedin.pegasus2avro.common.Ownership": { + "owners": [ + { + "owner": "urn:li:corpuser:dataowner1", + "type": "DATAOWNER" + } + ], + "ownerTypes": {}, + "lastModified": { + "time": 0, + "actor": "urn:li:corpuser:unknown" + } + } + } + ] + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-ruwyic", + "lastRunId": "no-run-id-provided" + } +}, +{ + "proposedSnapshot": { + "com.linkedin.pegasus2avro.metadata.snapshot.GlossaryTermSnapshot": { + "urn": "urn:li:glossaryTerm:Single Owner Types.Producer Owned", + "aspects": [ + { + "com.linkedin.pegasus2avro.glossary.GlossaryTermInfo": { + "customProperties": {}, + "name": "Producer Owned", + "definition": "Term owned by producer", + "parentNode": "urn:li:glossaryNode:Single Owner Types", + "termSource": "INTERNAL", + "sourceRef": "DataHub", + "sourceUrl": "https://github.com/datahub-project/datahub/" + } + }, + { + "com.linkedin.pegasus2avro.common.Ownership": { + "owners": [ + { + "owner": "urn:li:corpuser:producer1", + "type": "PRODUCER" + } + ], + "ownerTypes": {}, + "lastModified": { + "time": 0, + "actor": "urn:li:corpuser:unknown" + } + } + } + ] + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-ruwyic", + "lastRunId": "no-run-id-provided" + } +}, +{ + "proposedSnapshot": { + "com.linkedin.pegasus2avro.metadata.snapshot.GlossaryTermSnapshot": { + "urn": "urn:li:glossaryTerm:Single Owner Types.Stakeholder Owned", + "aspects": [ + { + "com.linkedin.pegasus2avro.glossary.GlossaryTermInfo": { + "customProperties": {}, + "name": "Stakeholder Owned", + "definition": "Term owned by stakeholder", + "parentNode": "urn:li:glossaryNode:Single Owner Types", + "termSource": "INTERNAL", + "sourceRef": "DataHub", + "sourceUrl": "https://github.com/datahub-project/datahub/" + } + }, + { + "com.linkedin.pegasus2avro.common.Ownership": { + "owners": [ + { + "owner": "urn:li:corpGroup:stakeholders", + "type": "STAKEHOLDER" + } + ], + "ownerTypes": {}, + "lastModified": { + "time": 0, + "actor": "urn:li:corpuser:unknown" + } + } + } + ] + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-ruwyic", + "lastRunId": "no-run-id-provided" + } +}, +{ + "entityType": "glossaryNode", + "entityUrn": "urn:li:glossaryNode:Single Owner Types", + "changeType": "UPSERT", + "aspectName": "status", + "aspect": { + "json": { + "removed": false + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-ruwyic", + "lastRunId": "no-run-id-provided" + } +}, +{ + "entityType": "glossaryTerm", + "entityUrn": "urn:li:glossaryTerm:Single Owner Types.Data Owner Owned", + "changeType": "UPSERT", + "aspectName": "status", + "aspect": { + "json": { + "removed": false + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-ruwyic", + "lastRunId": "no-run-id-provided" + } +}, +{ + "entityType": "glossaryTerm", + "entityUrn": "urn:li:glossaryTerm:Single Owner Types.Developer Owned", + "changeType": "UPSERT", + "aspectName": "status", + "aspect": { + "json": { + "removed": false + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-ruwyic", + "lastRunId": "no-run-id-provided" + } +}, +{ + "entityType": "glossaryTerm", + "entityUrn": "urn:li:glossaryTerm:Single Owner Types.Producer Owned", + "changeType": "UPSERT", + "aspectName": "status", + "aspect": { + "json": { + "removed": false + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-ruwyic", + "lastRunId": "no-run-id-provided" + } +}, +{ + "entityType": "glossaryTerm", + "entityUrn": "urn:li:glossaryTerm:Single Owner Types.Stakeholder Owned", + "changeType": "UPSERT", + "aspectName": "status", + "aspect": { + "json": { + "removed": false + } + }, + "systemMetadata": { + "lastObserved": 1586847600000, + "runId": "datahub-business-glossary-2020_04_14-07_00_00-ruwyic", + "lastRunId": "no-run-id-provided" + } +} +] \ No newline at end of file diff --git a/metadata-ingestion/tests/integration/business-glossary/test_business_glossary.py b/metadata-ingestion/tests/integration/business-glossary/test_business_glossary.py index 73b90df65c04fe..74cf9aa3b528f2 100644 --- a/metadata-ingestion/tests/integration/business-glossary/test_business_glossary.py +++ b/metadata-ingestion/tests/integration/business-glossary/test_business_glossary.py @@ -71,6 +71,134 @@ def test_glossary_ingest( ) +@freeze_time(FROZEN_TIME) +@pytest.mark.integration +def test_single_owner_types( + mock_datahub_graph_instance, + pytestconfig, + tmp_path, + mock_time, +): + """Test basic single owner cases with different ownership types""" + test_resources_dir = pytestconfig.rootpath / "tests/integration/business-glossary" + output_mces_path: str = f"{tmp_path}/single_owner_types.json" + golden_mces_path: str = f"{test_resources_dir}/single_owner_types_golden.json" + + pipeline = Pipeline.create( + get_default_recipe( + glossary_yml_file_path=f"{test_resources_dir}/single_owner_types.yml", + event_output_file_path=output_mces_path, + enable_auto_id=False, + ) + ) + pipeline.ctx.graph = mock_datahub_graph_instance + pipeline.run() + pipeline.raise_from_status() + + mce_helpers.check_golden_file( + pytestconfig, + output_path=output_mces_path, + golden_path=golden_mces_path, + ) + + +@freeze_time(FROZEN_TIME) +@pytest.mark.integration +def test_multiple_owners_same_type( + mock_datahub_graph_instance, + pytestconfig, + tmp_path, + mock_time, +): + """Test multiple owners all having the same type""" + test_resources_dir = pytestconfig.rootpath / "tests/integration/business-glossary" + output_mces_path: str = f"{tmp_path}/multiple_owners_same_type.json" + golden_mces_path: str = ( + f"{test_resources_dir}/multiple_owners_same_type_golden.json" + ) + + pipeline = Pipeline.create( + get_default_recipe( + glossary_yml_file_path=f"{test_resources_dir}/multiple_owners_same_type.yml", + event_output_file_path=output_mces_path, + enable_auto_id=False, + ) + ) + pipeline.ctx.graph = mock_datahub_graph_instance + pipeline.run() + pipeline.raise_from_status() + + mce_helpers.check_golden_file( + pytestconfig, + output_path=output_mces_path, + golden_path=golden_mces_path, + ) + + +@freeze_time(FROZEN_TIME) +@pytest.mark.integration +def test_multiple_owners_different_types( + mock_datahub_graph_instance, + pytestconfig, + tmp_path, + mock_time, +): + """Test multiple owners with different types""" + test_resources_dir = pytestconfig.rootpath / "tests/integration/business-glossary" + output_mces_path: str = f"{tmp_path}/multiple_owners_different_types.json" + golden_mces_path: str = ( + f"{test_resources_dir}/multiple_owners_different_types_golden.json" + ) + + pipeline = Pipeline.create( + get_default_recipe( + glossary_yml_file_path=f"{test_resources_dir}/multiple_owners_different_types.yml", + event_output_file_path=output_mces_path, + enable_auto_id=False, + ) + ) + pipeline.ctx.graph = mock_datahub_graph_instance + pipeline.run() + pipeline.raise_from_status() + + mce_helpers.check_golden_file( + pytestconfig, + output_path=output_mces_path, + golden_path=golden_mces_path, + ) + + +@freeze_time(FROZEN_TIME) +@pytest.mark.integration +def test_custom_ownership_urns( + mock_datahub_graph_instance, + pytestconfig, + tmp_path, + mock_time, +): + """Test custom ownership URNs""" + test_resources_dir = pytestconfig.rootpath / "tests/integration/business-glossary" + output_mces_path: str = f"{tmp_path}/custom_ownership_urns.json" + golden_mces_path: str = f"{test_resources_dir}/custom_ownership_urns_golden.json" + + pipeline = Pipeline.create( + get_default_recipe( + glossary_yml_file_path=f"{test_resources_dir}/custom_ownership_urns.yml", + event_output_file_path=output_mces_path, + enable_auto_id=False, + ) + ) + pipeline.ctx.graph = mock_datahub_graph_instance + pipeline.run() + pipeline.raise_from_status() + + mce_helpers.check_golden_file( + pytestconfig, + output_path=output_mces_path, + golden_path=golden_mces_path, + ) + + @freeze_time(FROZEN_TIME) def test_auto_id_creation_on_reserved_char(): id_: str = business_glossary.create_id(["pii", "secure % password"], None, False) From edca8eae99be2412758ef6fa946c641c4cd16cbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20G=C3=B3mez=20Villamor?= Date: Thu, 12 Dec 2024 15:03:30 +0100 Subject: [PATCH 2/3] feat(datahub-client): additionally generates java8 artefacts (#12106) --- .github/workflows/publish-datahub-jars.yml | 49 +++++++++++++++++++ .../java/datahub-client/build.gradle | 6 +++ 2 files changed, 55 insertions(+) diff --git a/.github/workflows/publish-datahub-jars.yml b/.github/workflows/publish-datahub-jars.yml index eb57c29e151ae6..5aec66bc33bb67 100644 --- a/.github/workflows/publish-datahub-jars.yml +++ b/.github/workflows/publish-datahub-jars.yml @@ -196,3 +196,52 @@ jobs: echo signingKey=$SIGNING_KEY >> gradle.properties ./gradlew -PreleaseVersion=${{ needs.setup.outputs.tag }} :metadata-integration:java:custom-plugin-lib:publish ./gradlew :metadata-integration:java:custom-plugin-lib:closeAndReleaseRepository --info + publish-java8: + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + needs: ["check-secret", "setup"] + if: ${{ needs.check-secret.outputs.publish-enabled == 'true' }} + steps: + - uses: acryldata/sane-checkout-action@v3 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: "zulu" + java-version: 17 + - uses: gradle/actions/setup-gradle@v3 + - uses: actions/setup-python@v5 + with: + python-version: "3.10" + cache: "pip" + - name: checkout upstream repo + run: | + git remote add upstream https://github.com/datahub-project/datahub.git + git fetch upstream --tags --force --filter=tree:0 + - name: publish datahub-client jar snapshot + if: ${{ github.event_name != 'release' }} + env: + RELEASE_USERNAME: ${{ secrets.RELEASE_USERNAME }} + RELEASE_PASSWORD: ${{ secrets.RELEASE_PASSWORD }} + SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} + SIGNING_KEY: ${{ secrets.SIGNING_KEY }} + NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }} + NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} + run: | + echo signingKey=$SIGNING_KEY >> gradle.properties + ./gradlew :metadata-integration:java:datahub-client:printVersion -PjavaClassVersionDefault=8 -ParchiveAppendix=java8 + ./gradlew :metadata-integration:java:datahub-client:publish -PjavaClassVersionDefault=8 -ParchiveAppendix=java8 + - name: release datahub-client jar + if: ${{ github.event_name == 'release' }} + env: + RELEASE_USERNAME: ${{ secrets.RELEASE_USERNAME }} + RELEASE_PASSWORD: ${{ secrets.RELEASE_PASSWORD }} + SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} + SIGNING_KEY: ${{ secrets.SIGNING_KEY }} + NEXUS_USERNAME: ${{ secrets.NEXUS_USERNAME }} + NEXUS_PASSWORD: ${{ secrets.NEXUS_PASSWORD }} + run: | + echo signingKey=$SIGNING_KEY >> gradle.properties + ./gradlew -PreleaseVersion=${{ needs.setup.outputs.tag }} :metadata-integration:java:datahub-client:publish -PjavaClassVersionDefault=8 -ParchiveAppendix=java8 + ./gradlew :metadata-integration:java:datahub-client:closeAndReleaseRepository --info -PjavaClassVersionDefault=8 -ParchiveAppendix=java8 \ No newline at end of file diff --git a/metadata-integration/java/datahub-client/build.gradle b/metadata-integration/java/datahub-client/build.gradle index 2535d091f6ce52..7dad21a6417fc4 100644 --- a/metadata-integration/java/datahub-client/build.gradle +++ b/metadata-integration/java/datahub-client/build.gradle @@ -13,6 +13,9 @@ import org.apache.tools.ant.filters.ReplaceTokens jar { + if (project.hasProperty('archiveAppendix')) { + archiveAppendix.set(project.archiveAppendix) + } archiveClassifier = "lib" } @@ -98,6 +101,9 @@ task checkShadowJar(type: Exec) { shadowJar { zip64 = true + if (project.hasProperty('archiveAppendix')) { + archiveAppendix.set(project.archiveAppendix) + } archiveClassifier = '' // preventing java multi-release JAR leakage // https://github.com/johnrengelman/shadow/issues/729 From 3d7560585f14a8b5b0a9dd9d393f0643e1f59d58 Mon Sep 17 00:00:00 2001 From: Aseem Bansal Date: Thu, 12 Dec 2024 20:49:25 +0530 Subject: [PATCH 3/3] fix(ui): dereference errors (#12034) --- datahub-web-react/src/App.tsx | 2 +- datahub-web-react/src/app/AdminConsole.tsx | 4 ++-- .../components/AnalyticsPage.tsx | 4 ++-- .../nestedDomains/domainNavigator/DomainNode.tsx | 2 +- .../src/app/embed/lookup/useGetEntityByUrl.ts | 2 +- .../profile/BusinessAttributeRelatedEntity.tsx | 2 +- .../src/app/entity/chart/ChartEntity.tsx | 6 +++--- .../src/app/entity/dashboard/DashboardEntity.tsx | 6 +++--- .../src/app/entity/dataFlow/DataFlowEntity.tsx | 2 +- .../src/app/entity/dataJob/DataJobEntity.tsx | 2 +- .../src/app/entity/dataJob/tabs/RunsTab.tsx | 4 ++-- .../src/app/entity/dataset/DatasetEntity.tsx | 2 +- .../app/entity/dataset/profile/OperationsTab.tsx | 4 ++-- .../profile/schema/utils/schemaTitleRenderer.tsx | 2 +- .../entity/dataset/profile/schema/utils/utils.ts | 2 +- .../domain/DataProductsTab/DataProductsTab.tsx | 2 +- .../profile/AddRelatedTermsModal.tsx | 5 ++++- .../profile/GlossaryRelatedEntity.tsx | 2 +- .../entity/mlFeatureTable/profile/Sources.tsx | 4 ++-- .../mlModel/profile/MlModelFeaturesTab.tsx | 2 +- .../src/app/entity/ownership/OwnershipList.tsx | 2 +- .../shared/EntityDropdown/DomainParentSelect.tsx | 2 +- .../shared/EntityDropdown/NodeParentSelect.tsx | 2 +- .../useHandleMoveDomainComplete.ts | 2 +- .../shared/__tests__/siblingsUtils.test.ts | 8 ++++---- .../CreateERModelRelationModal.tsx | 4 ++-- .../ERModelRelationship/ERModelRelationUtils.tsx | 2 +- .../styled/ERModelRelationship/EditableCell.tsx | 2 +- .../profile/nav/ProfileNavBrowsePathV2.tsx | 2 +- .../sidebar/DataProduct/SetDataProductModal.tsx | 2 +- .../profile/sidebar/FormInfo/useGetPromptInfo.ts | 4 ++-- .../containers/profile/sidebar/FormInfo/utils.ts | 6 +++--- .../entity/shared/containers/profile/utils.ts | 2 +- .../embed/UpstreamHealth/FailingAssertions.tsx | 2 +- .../entity/shared/embed/UpstreamHealth/utils.ts | 2 +- .../entityForm/EntityFormContextProvider.tsx | 2 +- .../src/app/entity/shared/entityForm/Form.tsx | 4 ++-- .../prompts/StructuredPropertyPrompt/utils.ts | 2 +- .../schemaFieldPrompts/SchemaFieldPrompts.tsx | 2 +- .../useShouldShowVerificationPrompt.ts | 2 +- .../tabs/Dataset/AccessManagement/utils.tsx | 4 ++-- .../shared/tabs/Dataset/Schema/SchemaTable.tsx | 2 +- .../Schema/components/ForeignKeyLabel.tsx | 2 +- .../Schema/components/PropertyTypeLabel.tsx | 4 ++-- .../SchemaFieldDrawer/FieldProperties.tsx | 2 +- .../SchemaFieldDrawer/SchemaFieldDrawer.tsx | 2 +- .../Schema/utils/useDescriptionRenderer.tsx | 2 +- .../Schema/utils/useTagsAndTermsRenderer.tsx | 2 +- .../useTagsAndTermsRendererFeatureTable.tsx | 2 +- .../Validations/DatasetAssertionDetails.tsx | 2 +- .../contract/FreshnessScheduleSummary.tsx | 2 +- .../Validations/contract/builder/utils.ts | 4 ++-- .../shared/tabs/Entity/ChartDashboardsTab.tsx | 2 +- .../shared/tabs/Entity/DashboardChartsTab.tsx | 2 +- .../shared/tabs/Entity/DashboardDatasetsTab.tsx | 2 +- .../shared/tabs/Entity/DataFlowJobsTab.tsx | 2 +- .../weaklyTypedAspects/DynamicPropertiesTab.tsx | 2 +- .../Incident/components/IncidentListItem.tsx | 8 ++++---- .../shared/tabs/Lineage/ColumnLineageSelect.tsx | 2 +- ...wnloadScrollAcrossLineageSearchResultsHook.ts | 14 +++++++------- .../shared/tabs/ML/MlFeatureFeatureTableTab.tsx | 2 +- .../tabs/ML/MlPrimaryKeyFeatureTableTab.tsx | 2 +- .../shared/tabs/Properties/Edit/EditColumn.tsx | 2 +- .../Edit/EditStructuredPropertyModal.tsx | 2 +- .../entity/shared/tabs/Properties/NameColumn.tsx | 2 +- .../shared/tabs/Properties/ValuesColumn.tsx | 2 +- .../src/app/entity/user/UserProfile.tsx | 4 ++-- .../src/app/entity/view/builder/ViewBuilder.tsx | 4 +++- datahub-web-react/src/app/entity/view/utils.ts | 2 +- .../src/app/glossary/BusinessGlossaryPage.tsx | 4 ++-- .../app/glossary/GlossaryBrowser/NodeItem.tsx | 2 +- .../src/app/glossary/__tests__/utils.test.ts | 2 +- datahub-web-react/src/app/glossary/utils.ts | 4 ++-- .../src/app/home/HomePageHeader.tsx | 2 +- .../src/app/ingest/ManageIngestionPage.tsx | 2 +- .../app/ingest/source/IngestionSourceList.tsx | 4 ++-- .../app/ingest/source/IngestionSourceTable.tsx | 12 ++++++------ .../source/builder/RecipeForm/RecipeForm.tsx | 2 +- .../RecipeForm/SecretField/SecretField.tsx | 2 +- .../TestConnection/TestConnectionModal.tsx | 6 +++--- .../executions/IngestionSourceExecutionList.tsx | 2 +- .../src/app/lineage/LineageEntityColumns.tsx | 2 +- .../src/app/lineage/LineageExplorer.tsx | 2 +- .../src/app/lineage/manage/AddEntityEdge.tsx | 2 +- .../src/app/lineage/utils/columnLineageUtils.ts | 2 +- .../src/app/lineage/utils/layoutTree.ts | 16 ++++++++-------- .../app/permissions/policy/PolicyActorForm.tsx | 2 +- .../src/app/permissions/roles/ManageRoles.tsx | 6 +++--- .../app/permissions/roles/RoleDetailsModal.tsx | 4 ++-- .../search/AdvancedFilterSelectValueModal.tsx | 12 ++++++------ datahub-web-react/src/app/search/SearchBar.tsx | 2 +- .../src/app/search/filters/utils.tsx | 2 +- .../app/search/sidebar/useBrowsePagination.tsx | 2 +- ...eDownloadScrollAcrossEntitiesSearchResults.ts | 4 ++-- .../src/app/settings/AccessTokens.tsx | 4 ++-- .../src/app/settings/SettingsPage.tsx | 6 +++--- .../src/app/shared/admin/HeaderLinks.tsx | 4 ++-- .../AddBusinessAttributeModal.tsx | 2 +- .../src/app/shared/tags/AddTagsTermsModal.tsx | 2 +- .../src/providers/EducationStepsProvider.tsx | 2 +- 100 files changed, 165 insertions(+), 160 deletions(-) diff --git a/datahub-web-react/src/App.tsx b/datahub-web-react/src/App.tsx index 2fdd7c8ed68004..81f137417f1f8a 100644 --- a/datahub-web-react/src/App.tsx +++ b/datahub-web-react/src/App.tsx @@ -79,7 +79,7 @@ export const InnerApp: React.VFC = () => { - {useCustomTheme().theme?.content.title} + {useCustomTheme().theme?.content?.title} diff --git a/datahub-web-react/src/app/AdminConsole.tsx b/datahub-web-react/src/app/AdminConsole.tsx index f6395a3bd3cb8a..a79575c3d88d78 100644 --- a/datahub-web-react/src/app/AdminConsole.tsx +++ b/datahub-web-react/src/app/AdminConsole.tsx @@ -37,8 +37,8 @@ export const AdminConsole = (): JSX.Element => { const [adminConsoleOpen, setAdminConsoleOpen] = useState(false); const { config } = useAppConfig(); - const isAnalyticsEnabled = config?.analyticsConfig.enabled; - const isPoliciesEnabled = config?.policiesConfig.enabled; + const isAnalyticsEnabled = config?.analyticsConfig?.enabled; + const isPoliciesEnabled = config?.policiesConfig?.enabled; const showAnalytics = (isAnalyticsEnabled && me && me?.platformPrivileges?.viewAnalytics) || false; const showPolicyBuilder = (isPoliciesEnabled && me && me?.platformPrivileges?.managePolicies) || false; diff --git a/datahub-web-react/src/app/analyticsDashboard/components/AnalyticsPage.tsx b/datahub-web-react/src/app/analyticsDashboard/components/AnalyticsPage.tsx index bf0e5af2427bbb..f139ef7368a74d 100644 --- a/datahub-web-react/src/app/analyticsDashboard/components/AnalyticsPage.tsx +++ b/datahub-web-react/src/app/analyticsDashboard/components/AnalyticsPage.tsx @@ -121,11 +121,11 @@ export const AnalyticsPage = () => { placeholder="Select a domain" onChange={onDomainChange} filterOption={(input, option) => - option?.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 + option?.children?.toLowerCase()?.indexOf(input.toLowerCase()) >= 0 } > All - {domainData?.listDomains?.domains.map((domainChoice) => ( + {domainData?.listDomains?.domains?.map((domainChoice) => ( {domainChoice?.properties?.name} diff --git a/datahub-web-react/src/app/domain/nestedDomains/domainNavigator/DomainNode.tsx b/datahub-web-react/src/app/domain/nestedDomains/domainNavigator/DomainNode.tsx index bf70bd043fd4a1..82977eff4f95bc 100644 --- a/datahub-web-react/src/app/domain/nestedDomains/domainNavigator/DomainNode.tsx +++ b/datahub-web-react/src/app/domain/nestedDomains/domainNavigator/DomainNode.tsx @@ -83,7 +83,7 @@ export default function DomainNode({ domain, numDomainChildren, domainUrnToHide, const hasDomainChildren = useHasDomainChildren({ domainUrn: domain.urn, numDomainChildren }); const shouldAutoOpen = useMemo( - () => !isInSelectMode && entityData?.parentDomains?.domains.some((parent) => parent.urn === domain.urn), + () => !isInSelectMode && entityData?.parentDomains?.domains?.some((parent) => parent.urn === domain.urn), [isInSelectMode, entityData, domain.urn], ); diff --git a/datahub-web-react/src/app/embed/lookup/useGetEntityByUrl.ts b/datahub-web-react/src/app/embed/lookup/useGetEntityByUrl.ts index f11a3a02b43448..49136c39fd2424 100644 --- a/datahub-web-react/src/app/embed/lookup/useGetEntityByUrl.ts +++ b/datahub-web-react/src/app/embed/lookup/useGetEntityByUrl.ts @@ -31,7 +31,7 @@ const useGetEntityByUrl = (externalUrl: string) => { const getLookupData = () => { if (!data) return {} as const; - const entities = data.searchAcrossEntities?.searchResults.map((result) => result.entity) ?? []; + const entities = data.searchAcrossEntities?.searchResults?.map((result) => result.entity) ?? []; const notFound = entities.length === 0; const foundMultiple = entities.length > 1; const entity = entities.length === 1 ? entities[0] : null; diff --git a/datahub-web-react/src/app/entity/businessAttribute/profile/BusinessAttributeRelatedEntity.tsx b/datahub-web-react/src/app/entity/businessAttribute/profile/BusinessAttributeRelatedEntity.tsx index 46d9d4ea51d245..a73b36d6922279 100644 --- a/datahub-web-react/src/app/entity/businessAttribute/profile/BusinessAttributeRelatedEntity.tsx +++ b/datahub-web-react/src/app/entity/businessAttribute/profile/BusinessAttributeRelatedEntity.tsx @@ -18,7 +18,7 @@ export default function BusinessAttributeRelatedEntity() { ]) || []; - entityData?.isAChildren?.relationships.forEach((businessAttribute) => { + entityData?.isAChildren?.relationships?.forEach((businessAttribute) => { const childUrn = businessAttribute.entity?.urn; if (childUrn) { diff --git a/datahub-web-react/src/app/entity/chart/ChartEntity.tsx b/datahub-web-react/src/app/entity/chart/ChartEntity.tsx index 70fe8a5e7c7c23..b20116f615556d 100644 --- a/datahub-web-react/src/app/entity/chart/ChartEntity.tsx +++ b/datahub-web-react/src/app/entity/chart/ChartEntity.tsx @@ -142,9 +142,9 @@ export class ChartEntity implements Entity { component: EmbedTab, display: { visible: (_, chart: GetChartQuery) => - !!chart?.chart?.embed?.renderUrl && chart?.chart?.platform.urn === LOOKER_URN, + !!chart?.chart?.embed?.renderUrl && chart?.chart?.platform?.urn === LOOKER_URN, enabled: (_, chart: GetChartQuery) => - !!chart?.chart?.embed?.renderUrl && chart?.chart?.platform.urn === LOOKER_URN, + !!chart?.chart?.embed?.renderUrl && chart?.chart?.platform?.urn === LOOKER_URN, }, }, { @@ -170,7 +170,7 @@ export class ChartEntity implements Entity { name: 'Incidents', component: IncidentTab, getDynamicName: (_, chart) => { - const activeIncidentCount = chart?.chart?.activeIncidents.total; + const activeIncidentCount = chart?.chart?.activeIncidents?.total; return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`; }, }, diff --git a/datahub-web-react/src/app/entity/dashboard/DashboardEntity.tsx b/datahub-web-react/src/app/entity/dashboard/DashboardEntity.tsx index 7d0275f60435a9..c35b1f90ee9c00 100644 --- a/datahub-web-react/src/app/entity/dashboard/DashboardEntity.tsx +++ b/datahub-web-react/src/app/entity/dashboard/DashboardEntity.tsx @@ -149,10 +149,10 @@ export class DashboardEntity implements Entity { display: { visible: (_, dashboard: GetDashboardQuery) => !!dashboard?.dashboard?.embed?.renderUrl && - dashboard?.dashboard?.platform.urn === LOOKER_URN, + dashboard?.dashboard?.platform?.urn === LOOKER_URN, enabled: (_, dashboard: GetDashboardQuery) => !!dashboard?.dashboard?.embed?.renderUrl && - dashboard?.dashboard?.platform.urn === LOOKER_URN, + dashboard?.dashboard?.platform?.urn === LOOKER_URN, }, }, { @@ -170,7 +170,7 @@ export class DashboardEntity implements Entity { name: 'Incidents', component: IncidentTab, getDynamicName: (_, dashboard) => { - const activeIncidentCount = dashboard?.dashboard?.activeIncidents.total; + const activeIncidentCount = dashboard?.dashboard?.activeIncidents?.total; return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`; }, }, diff --git a/datahub-web-react/src/app/entity/dataFlow/DataFlowEntity.tsx b/datahub-web-react/src/app/entity/dataFlow/DataFlowEntity.tsx index 42555a0dd3f37d..3c03dfb65ccbcd 100644 --- a/datahub-web-react/src/app/entity/dataFlow/DataFlowEntity.tsx +++ b/datahub-web-react/src/app/entity/dataFlow/DataFlowEntity.tsx @@ -92,7 +92,7 @@ export class DataFlowEntity implements Entity { name: 'Incidents', component: IncidentTab, getDynamicName: (_, dataFlow) => { - const activeIncidentCount = dataFlow?.dataFlow?.activeIncidents.total; + const activeIncidentCount = dataFlow?.dataFlow?.activeIncidents?.total; return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`; }, }, diff --git a/datahub-web-react/src/app/entity/dataJob/DataJobEntity.tsx b/datahub-web-react/src/app/entity/dataJob/DataJobEntity.tsx index 503acf7652dfa6..5b1aaeaef76d5b 100644 --- a/datahub-web-react/src/app/entity/dataJob/DataJobEntity.tsx +++ b/datahub-web-react/src/app/entity/dataJob/DataJobEntity.tsx @@ -112,7 +112,7 @@ export class DataJobEntity implements Entity { name: 'Incidents', component: IncidentTab, getDynamicName: (_, dataJob) => { - const activeIncidentCount = dataJob?.dataJob?.activeIncidents.total; + const activeIncidentCount = dataJob?.dataJob?.activeIncidents?.total; return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`; }, }, diff --git a/datahub-web-react/src/app/entity/dataJob/tabs/RunsTab.tsx b/datahub-web-react/src/app/entity/dataJob/tabs/RunsTab.tsx index 5cd621719ce8fd..f00e3402c8ed4c 100644 --- a/datahub-web-react/src/app/entity/dataJob/tabs/RunsTab.tsx +++ b/datahub-web-react/src/app/entity/dataJob/tabs/RunsTab.tsx @@ -129,8 +129,8 @@ export const RunsTab = () => { name: run?.name, status: run?.state?.[0]?.status, resultType: run?.state?.[0]?.result?.resultType, - inputs: run?.inputs?.relationships.map((relationship) => relationship.entity), - outputs: run?.outputs?.relationships.map((relationship) => relationship.entity), + inputs: run?.inputs?.relationships?.map((relationship) => relationship.entity), + outputs: run?.outputs?.relationships?.map((relationship) => relationship.entity), externalUrl: run?.externalUrl, })); if (loading) { diff --git a/datahub-web-react/src/app/entity/dataset/DatasetEntity.tsx b/datahub-web-react/src/app/entity/dataset/DatasetEntity.tsx index 35ed3ffcc4c532..abf8e732c47d61 100644 --- a/datahub-web-react/src/app/entity/dataset/DatasetEntity.tsx +++ b/datahub-web-react/src/app/entity/dataset/DatasetEntity.tsx @@ -217,7 +217,7 @@ export class DatasetEntity implements Entity { name: 'Incidents', component: IncidentTab, getDynamicName: (_, dataset) => { - const activeIncidentCount = dataset?.dataset?.activeIncidents.total; + const activeIncidentCount = dataset?.dataset?.activeIncidents?.total; return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`; }, }, diff --git a/datahub-web-react/src/app/entity/dataset/profile/OperationsTab.tsx b/datahub-web-react/src/app/entity/dataset/profile/OperationsTab.tsx index 78ec334f071ba4..d3371d3790d028 100644 --- a/datahub-web-react/src/app/entity/dataset/profile/OperationsTab.tsx +++ b/datahub-web-react/src/app/entity/dataset/profile/OperationsTab.tsx @@ -195,8 +195,8 @@ export const OperationsTab = () => { status: run?.state?.[0]?.status, resultType: run?.state?.[0]?.result?.resultType, duration: run?.state?.[0]?.durationMillis, - inputs: run?.inputs?.relationships.map((relationship) => relationship.entity), - outputs: run?.outputs?.relationships.map((relationship) => relationship.entity), + inputs: run?.inputs?.relationships?.map((relationship) => relationship.entity), + outputs: run?.outputs?.relationships?.map((relationship) => relationship.entity), externalUrl: run?.externalUrl, parentTemplate: run?.parentTemplate?.relationships?.[0]?.entity, })); diff --git a/datahub-web-react/src/app/entity/dataset/profile/schema/utils/schemaTitleRenderer.tsx b/datahub-web-react/src/app/entity/dataset/profile/schema/utils/schemaTitleRenderer.tsx index 3d03b6306454d8..fdd03622fc0e19 100644 --- a/datahub-web-react/src/app/entity/dataset/profile/schema/utils/schemaTitleRenderer.tsx +++ b/datahub-web-react/src/app/entity/dataset/profile/schema/utils/schemaTitleRenderer.tsx @@ -69,7 +69,7 @@ export default function useSchemaTitleRenderer( ?.filter( (constraint) => (constraint?.sourceFields?.filter( - (sourceField) => sourceField?.fieldPath.trim() === fieldPath.trim(), + (sourceField) => sourceField?.fieldPath?.trim() === fieldPath.trim(), ).length || 0) > 0, ) .map((constraint) => ( diff --git a/datahub-web-react/src/app/entity/dataset/profile/schema/utils/utils.ts b/datahub-web-react/src/app/entity/dataset/profile/schema/utils/utils.ts index 51cb8ab0245196..9d719ae25e2bed 100644 --- a/datahub-web-react/src/app/entity/dataset/profile/schema/utils/utils.ts +++ b/datahub-web-react/src/app/entity/dataset/profile/schema/utils/utils.ts @@ -37,7 +37,7 @@ export function convertEditableSchemaMetadataForUpdate( ): EditableSchemaMetadataUpdate { return { editableSchemaFieldInfo: - editableSchemaMetadata?.editableSchemaFieldInfo.map((editableSchemaFieldInfo) => ({ + editableSchemaMetadata?.editableSchemaFieldInfo?.map((editableSchemaFieldInfo) => ({ fieldPath: editableSchemaFieldInfo?.fieldPath, description: editableSchemaFieldInfo?.description, globalTags: { tags: convertTagsForUpdate(editableSchemaFieldInfo?.globalTags?.tags || []) }, diff --git a/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductsTab.tsx b/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductsTab.tsx index c834597e41a6d5..15cc99127f3500 100644 --- a/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductsTab.tsx +++ b/datahub-web-react/src/app/entity/domain/DataProductsTab/DataProductsTab.tsx @@ -70,7 +70,7 @@ export default function DataProductsTab() { }, }); const totalResults = data?.searchAcrossEntities?.total || 0; - const searchResults = data?.searchAcrossEntities?.searchResults.map((r) => r.entity) || []; + const searchResults = data?.searchAcrossEntities?.searchResults?.map((r) => r.entity) || []; const dataProducts = [...createdDataProducts, ...searchResults]; const displayedDataProducts = dataProducts .map( diff --git a/datahub-web-react/src/app/entity/glossaryTerm/profile/AddRelatedTermsModal.tsx b/datahub-web-react/src/app/entity/glossaryTerm/profile/AddRelatedTermsModal.tsx index a609dc4cca599d..9131af265a7516 100644 --- a/datahub-web-react/src/app/entity/glossaryTerm/profile/AddRelatedTermsModal.tsx +++ b/datahub-web-react/src/app/entity/glossaryTerm/profile/AddRelatedTermsModal.tsx @@ -104,7 +104,10 @@ function AddRelatedTermsModal(props: Props) { const newUrns = [...selectedUrns, urn]; setSelectedUrns(newUrns); const selectedSearchOption = tagSearchOptions.find((option) => option.props.value === urn); - setSelectedTerms([...selectedTerms, { urn, component: }]); + setSelectedTerms([ + ...selectedTerms, + { urn, component: }, + ]); }; // When a Tag or term search result is deselected, remove the urn from the Owners diff --git a/datahub-web-react/src/app/entity/glossaryTerm/profile/GlossaryRelatedEntity.tsx b/datahub-web-react/src/app/entity/glossaryTerm/profile/GlossaryRelatedEntity.tsx index 098e97e526fd84..6959fc082f7346 100644 --- a/datahub-web-react/src/app/entity/glossaryTerm/profile/GlossaryRelatedEntity.tsx +++ b/datahub-web-react/src/app/entity/glossaryTerm/profile/GlossaryRelatedEntity.tsx @@ -22,7 +22,7 @@ export default function GlossaryRelatedEntity() { ]) || []; - entityData?.isAChildren?.relationships.forEach((term) => { + entityData?.isAChildren?.relationships?.forEach((term) => { const childUrn = term.entity?.urn; if (childUrn) { diff --git a/datahub-web-react/src/app/entity/mlFeatureTable/profile/Sources.tsx b/datahub-web-react/src/app/entity/mlFeatureTable/profile/Sources.tsx index eb114e9774e294..56c0fcbb602003 100644 --- a/datahub-web-react/src/app/entity/mlFeatureTable/profile/Sources.tsx +++ b/datahub-web-react/src/app/entity/mlFeatureTable/profile/Sources.tsx @@ -35,14 +35,14 @@ export default function SourcesView() { features?.reduce((accumulator: Array, feature) => { if (feature.__typename === 'MLFeature' && feature.properties?.sources) { // eslint-disable-next-line array-callback-return - feature.properties?.sources.map((source: Dataset | null) => { + feature.properties?.sources?.map((source: Dataset | null) => { if (source && accumulator.findIndex((dataset) => dataset.urn === source?.urn) === -1) { accumulator.push(source); } }); } else if (feature.__typename === 'MLPrimaryKey' && feature.properties?.sources) { // eslint-disable-next-line array-callback-return - feature.properties?.sources.map((source: Dataset | null) => { + feature.properties?.sources?.map((source: Dataset | null) => { if (source && accumulator.findIndex((dataset) => dataset.urn === source?.urn) === -1) { accumulator.push(source); } diff --git a/datahub-web-react/src/app/entity/mlModel/profile/MlModelFeaturesTab.tsx b/datahub-web-react/src/app/entity/mlModel/profile/MlModelFeaturesTab.tsx index b8dc64793c2256..7fd719177d1516 100644 --- a/datahub-web-react/src/app/entity/mlModel/profile/MlModelFeaturesTab.tsx +++ b/datahub-web-react/src/app/entity/mlModel/profile/MlModelFeaturesTab.tsx @@ -9,7 +9,7 @@ export default function MlModelFeaturesTab() { const entity = useBaseEntity() as GetMlModelQuery; const model = entity && entity.mlModel; - const features = model?.features?.relationships.map((relationship) => relationship.entity) as Array< + const features = model?.features?.relationships?.map((relationship) => relationship.entity) as Array< MlFeature | MlPrimaryKey >; diff --git a/datahub-web-react/src/app/entity/ownership/OwnershipList.tsx b/datahub-web-react/src/app/entity/ownership/OwnershipList.tsx index 8d6e109d2bca36..3d7904a5c55052 100644 --- a/datahub-web-react/src/app/entity/ownership/OwnershipList.tsx +++ b/datahub-web-react/src/app/entity/ownership/OwnershipList.tsx @@ -64,7 +64,7 @@ export const OwnershipList = () => { }); const totalOwnershipTypes = data?.listOwnershipTypes?.total || 0; const ownershipTypes = - data?.listOwnershipTypes?.ownershipTypes.filter((type) => type.urn !== 'urn:li:ownershipType:none') || []; + data?.listOwnershipTypes?.ownershipTypes?.filter((type) => type.urn !== 'urn:li:ownershipType:none') || []; const onClickCreateOwnershipType = () => { setShowOwnershipBuilder(true); diff --git a/datahub-web-react/src/app/entity/shared/EntityDropdown/DomainParentSelect.tsx b/datahub-web-react/src/app/entity/shared/EntityDropdown/DomainParentSelect.tsx index d43b04ec11a165..1e918757e46192 100644 --- a/datahub-web-react/src/app/entity/shared/EntityDropdown/DomainParentSelect.tsx +++ b/datahub-web-react/src/app/entity/shared/EntityDropdown/DomainParentSelect.tsx @@ -23,7 +23,7 @@ export function filterResultsForMove(entity: Domain, entityUrn: string) { return ( entity.urn !== entityUrn && entity.__typename === 'Domain' && - !entity.parentDomains?.domains.some((node) => node.urn === entityUrn) + !entity.parentDomains?.domains?.some((node) => node.urn === entityUrn) ); } diff --git a/datahub-web-react/src/app/entity/shared/EntityDropdown/NodeParentSelect.tsx b/datahub-web-react/src/app/entity/shared/EntityDropdown/NodeParentSelect.tsx index 7227354a465695..3746c5f6b95f82 100644 --- a/datahub-web-react/src/app/entity/shared/EntityDropdown/NodeParentSelect.tsx +++ b/datahub-web-react/src/app/entity/shared/EntityDropdown/NodeParentSelect.tsx @@ -22,7 +22,7 @@ export function filterResultsForMove(entity: GlossaryNode, entityUrn: string) { return ( entity.urn !== entityUrn && entity.__typename === 'GlossaryNode' && - !entity.parentNodes?.nodes.some((node) => node.urn === entityUrn) + !entity.parentNodes?.nodes?.some((node) => node.urn === entityUrn) ); } diff --git a/datahub-web-react/src/app/entity/shared/EntityDropdown/useHandleMoveDomainComplete.ts b/datahub-web-react/src/app/entity/shared/EntityDropdown/useHandleMoveDomainComplete.ts index 81f19331e18b77..2d9c346e18d5b4 100644 --- a/datahub-web-react/src/app/entity/shared/EntityDropdown/useHandleMoveDomainComplete.ts +++ b/datahub-web-react/src/app/entity/shared/EntityDropdown/useHandleMoveDomainComplete.ts @@ -13,7 +13,7 @@ export function useHandleMoveDomainComplete() { if (!entityData) return; const domain = entityData as Domain; - const oldParentUrn = domain.parentDomains?.domains.length ? domain.parentDomains.domains[0].urn : undefined; + const oldParentUrn = domain.parentDomains?.domains?.length ? domain.parentDomains.domains[0].urn : undefined; analytics.event({ type: EventType.MoveDomainEvent, diff --git a/datahub-web-react/src/app/entity/shared/__tests__/siblingsUtils.test.ts b/datahub-web-react/src/app/entity/shared/__tests__/siblingsUtils.test.ts index 00e89e5943c176..f3b857ab2ef3be 100644 --- a/datahub-web-react/src/app/entity/shared/__tests__/siblingsUtils.test.ts +++ b/datahub-web-react/src/app/entity/shared/__tests__/siblingsUtils.test.ts @@ -203,10 +203,10 @@ describe('siblingUtils', () => { // merges schema metadata properly by fieldPath expect(combinedData.dataset.schemaMetadata?.fields).toHaveLength(4); - expect(combinedData.dataset.schemaMetadata?.fields[0].fieldPath).toEqual('new_one'); - expect(combinedData.dataset.schemaMetadata?.fields[1].fieldPath).toEqual('DUPLICATE_FIELD'); - expect(combinedData.dataset.schemaMetadata?.fields[2].fieldPath).toEqual('user_id'); - expect(combinedData.dataset.schemaMetadata?.fields[3].fieldPath).toEqual('user_name'); + expect(combinedData.dataset.schemaMetadata?.fields[0]?.fieldPath).toEqual('new_one'); + expect(combinedData.dataset.schemaMetadata?.fields[1]?.fieldPath).toEqual('DUPLICATE_FIELD'); + expect(combinedData.dataset.schemaMetadata?.fields[2]?.fieldPath).toEqual('user_id'); + expect(combinedData.dataset.schemaMetadata?.fields[3]?.fieldPath).toEqual('user_name'); // will overwrite string properties w/ primary expect(combinedData.dataset.editableProperties.description).toEqual('secondary description'); diff --git a/datahub-web-react/src/app/entity/shared/components/styled/ERModelRelationship/CreateERModelRelationModal.tsx b/datahub-web-react/src/app/entity/shared/components/styled/ERModelRelationship/CreateERModelRelationModal.tsx index ea40fb71818033..de22daeeedd817 100644 --- a/datahub-web-react/src/app/entity/shared/components/styled/ERModelRelationship/CreateERModelRelationModal.tsx +++ b/datahub-web-react/src/app/entity/shared/components/styled/ERModelRelationship/CreateERModelRelationModal.tsx @@ -241,9 +241,9 @@ export const CreateERModelRelationModal = ({ }; const table1NameBusiness = getDatasetName(table1Dataset); - const table1NameTech = table1Dataset?.name || table1Dataset?.urn.split(',').at(1) || ''; + const table1NameTech = table1Dataset?.name || table1Dataset?.urn?.split(',').at(1) || ''; const table2NameBusiness = getDatasetName(table2Dataset); - const table2NameTech = table2Dataset?.name || table2Dataset?.urn.split(',').at(1) || ''; + const table2NameTech = table2Dataset?.name || table2Dataset?.urn?.split(',').at(1) || ''; const handleAdd = () => { const newData: ERModelRelationDataType = { diff --git a/datahub-web-react/src/app/entity/shared/components/styled/ERModelRelationship/ERModelRelationUtils.tsx b/datahub-web-react/src/app/entity/shared/components/styled/ERModelRelationship/ERModelRelationUtils.tsx index e7a242daa5121a..0eb198aec48033 100644 --- a/datahub-web-react/src/app/entity/shared/components/styled/ERModelRelationship/ERModelRelationUtils.tsx +++ b/datahub-web-react/src/app/entity/shared/components/styled/ERModelRelationship/ERModelRelationUtils.tsx @@ -68,6 +68,6 @@ export function getDatasetName(datainput: any): string { datainput?.editableProperties?.name || datainput?.properties?.name || datainput?.name || - datainput?.urn.split(',').at(1) + datainput?.urn?.split(',').at(1) ); } diff --git a/datahub-web-react/src/app/entity/shared/components/styled/ERModelRelationship/EditableCell.tsx b/datahub-web-react/src/app/entity/shared/components/styled/ERModelRelationship/EditableCell.tsx index a190d9090cc8c4..4320aacd53e4af 100644 --- a/datahub-web-react/src/app/entity/shared/components/styled/ERModelRelationship/EditableCell.tsx +++ b/datahub-web-react/src/app/entity/shared/components/styled/ERModelRelationship/EditableCell.tsx @@ -53,7 +53,7 @@ export const EditableCell = ({