diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java index 8cbae16cac3e8b..a0579d4f2b75e2 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/DatasetType.java @@ -92,7 +92,8 @@ public class DatasetType SUB_TYPES_ASPECT_NAME, APPLICATION_MEMBERSHIP_ASPECT_NAME, VERSION_PROPERTIES_ASPECT_NAME, - LOGICAL_PARENT_ASPECT_NAME); + LOGICAL_PARENT_ASPECT_NAME, + ASSET_SETTINGS_ASPECT_NAME); private static final Set FACET_FIELDS = ImmutableSet.of("origin", "platform"); private static final String ENTITY_NAME = "dataset"; diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/mappers/DatasetMapper.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/mappers/DatasetMapper.java index 44fb645a961cff..68e65fb8ba44ff 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/mappers/DatasetMapper.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/dataset/mappers/DatasetMapper.java @@ -31,6 +31,7 @@ import com.linkedin.datahub.graphql.generated.EntityType; import com.linkedin.datahub.graphql.generated.FabricType; import com.linkedin.datahub.graphql.types.application.ApplicationAssociationMapper; +import com.linkedin.datahub.graphql.types.common.mappers.AssetSettingsMapper; import com.linkedin.datahub.graphql.types.common.mappers.BrowsePathsV2Mapper; import com.linkedin.datahub.graphql.types.common.mappers.CustomPropertiesMapper; import com.linkedin.datahub.graphql.types.common.mappers.DataPlatformInstanceAspectMapper; @@ -65,6 +66,7 @@ import com.linkedin.metadata.key.DatasetKey; import com.linkedin.schema.EditableSchemaMetadata; import com.linkedin.schema.SchemaMetadata; +import com.linkedin.settings.asset.AssetSettings; import com.linkedin.structured.StructuredProperties; import java.util.Optional; import javax.annotation.Nonnull; @@ -209,6 +211,10 @@ public Dataset apply( logicalParent -> UrnToEntityMapper.map(context, logicalParent.getDestinationUrn())) .orElse(null))); + mappingHelper.mapToResult( + ASSET_SETTINGS_ASPECT_NAME, + ((entity, dataMap) -> + entity.setSettings(AssetSettingsMapper.map(new AssetSettings(dataMap))))); if (context != null && !canView(context.getOperationContext(), entityUrn)) { return AuthorizationUtils.restrictEntity(mappingHelper.getResult(), Dataset.class); diff --git a/datahub-graphql-core/src/main/resources/settings.graphql b/datahub-graphql-core/src/main/resources/settings.graphql index 6ef0f33867a027..1aef259b14dc5d 100644 --- a/datahub-graphql-core/src/main/resources/settings.graphql +++ b/datahub-graphql-core/src/main/resources/settings.graphql @@ -84,3 +84,10 @@ extend type GlossaryNode { """ settings: AssetSettings } + +extend type Dataset { + """ + Settings associated with this asset + """ + settings: AssetSettings +} diff --git a/datahub-web-react/src/Mocks.tsx b/datahub-web-react/src/Mocks.tsx index 774c6cc79eabf0..b5a0c71611e890 100644 --- a/datahub-web-react/src/Mocks.tsx +++ b/datahub-web-react/src/Mocks.tsx @@ -360,6 +360,7 @@ export const dataset1 = { structuredProperties: null, forms: null, activeIncidents: null, + settings: null, }; export const dataset2 = { @@ -460,6 +461,7 @@ export const dataset2 = { structuredProperties: null, forms: null, activeIncidents: null, + settings: null, }; export const dataset3 = { @@ -725,6 +727,7 @@ export const dataset3 = { upstream: null, downstream: null, versionProperties: null, + settings: null, } as Dataset; export const dataset3WithSchema = { diff --git a/datahub-web-react/src/app/entityV2/dataset/DatasetEntity.tsx b/datahub-web-react/src/app/entityV2/dataset/DatasetEntity.tsx index a22ae82222b547..9dbb0b812865b8 100644 --- a/datahub-web-react/src/app/entityV2/dataset/DatasetEntity.tsx +++ b/datahub-web-react/src/app/entityV2/dataset/DatasetEntity.tsx @@ -43,6 +43,7 @@ import { getDataForEntityType } from '@app/entityV2/shared/containers/profile/ut import EmbeddedProfile from '@app/entityV2/shared/embed/EmbeddedProfile'; import SidebarNotesSection from '@app/entityV2/shared/sidebarSection/SidebarNotesSection'; import SidebarStructuredProperties from '@app/entityV2/shared/sidebarSection/SidebarStructuredProperties'; +import { SUMMARY_TAB_ICON } from '@app/entityV2/shared/summary/HeaderComponents'; import AccessManagement from '@app/entityV2/shared/tabs/Dataset/AccessManagement/AccessManagement'; import QueriesTab from '@app/entityV2/shared/tabs/Dataset/Queries/QueriesTab'; import { SchemaTab } from '@app/entityV2/shared/tabs/Dataset/Schema/SchemaTab'; @@ -54,12 +55,15 @@ import { EmbedTab } from '@app/entityV2/shared/tabs/Embed/EmbedTab'; import { IncidentTab } from '@app/entityV2/shared/tabs/Incident/IncidentTab'; import { LineageTab } from '@app/entityV2/shared/tabs/Lineage/LineageTab'; import { PropertiesTab } from '@app/entityV2/shared/tabs/Properties/PropertiesTab'; +import { EntityTab } from '@app/entityV2/shared/types'; import { SidebarTitleActionType, getDatasetLastUpdatedMs, getFirstSubType, isOutputPort, } from '@app/entityV2/shared/utils'; +import SummaryTab from '@app/entityV2/summary/SummaryTab'; +import { useShowDatasetSummaryPage } from '@app/entityV2/summary/useShowDatasetSummaryPage'; import { DBT_URN } from '@app/ingest/source/builder/constants'; import { MatchedFieldList } from '@app/searchV2/matches/MatchedFieldList'; import { matchedFieldPathsRenderer } from '@app/searchV2/matches/matchedFieldPathsRenderer'; @@ -147,133 +151,7 @@ export class DatasetEntity implements Entity { subHeader={{ component: DatasetStatsSummarySubHeader, }} - tabs={[ - { - name: 'Columns', - component: SchemaTab, - icon: LayoutOutlined, - getCount: useGetColumnTabCount, - }, - { - name: 'View Definition', - component: ViewDefinitionTab, - icon: CodeOutlined, - display: { - visible: (_, dataset: GetDatasetQuery) => - !!dataset?.dataset?.viewProperties?.logic || - !!dataset?.dataset?.subTypes?.typeNames - ?.map((t) => t.toLocaleLowerCase()) - .includes(SUBTYPES.VIEW.toLocaleLowerCase()), - enabled: (_, dataset: GetDatasetQuery) => !!dataset?.dataset?.viewProperties?.logic, - }, - }, - { - name: 'Documentation', - component: DocumentationTab, - icon: FileOutlined, - }, - { - name: 'Preview', - component: EmbedTab, - icon: EyeOutlined, - display: { - visible: (_, dataset: GetDatasetQuery) => !!dataset?.dataset?.embed?.renderUrl, - enabled: (_, dataset: GetDatasetQuery) => !!dataset?.dataset?.embed?.renderUrl, - }, - }, - { - name: 'Lineage', - component: LineageTab, - icon: PartitionOutlined, - }, - { - name: 'Access', - component: AccessManagement, - icon: UnlockOutlined, - display: { - visible: (_, _1) => this.appconfig().config.featureFlags.showAccessManagement, - enabled: (_, _2) => true, - }, - }, - { - name: 'Properties', - component: PropertiesTab, - icon: UnorderedListOutlined, - getCount: (_, dataset: GetDatasetQuery) => { - const customPropertiesCount = dataset?.dataset?.properties?.customProperties?.length || 0; - const structuredPropertiesCount = - dataset?.dataset?.structuredProperties?.properties?.length || 0; - const propertiesCount = customPropertiesCount + structuredPropertiesCount; - return propertiesCount; - }, - }, - { - name: 'Queries', - component: QueriesTab, - icon: ConsoleSqlOutlined, - display: { - visible: (_, _1) => true, - enabled: (_, _2) => true, - }, - }, - { - name: 'Stats', - component: StatsTabWrapper, - icon: FundOutlined, - display: { - visible: (_, _1) => true, - enabled: (_, dataset: GetDatasetQuery) => - (dataset?.dataset?.latestFullTableProfile?.length || 0) > 0 || - (dataset?.dataset?.latestPartitionProfile?.length || 0) > 0 || - (dataset?.dataset?.usageStats?.buckets?.length || 0) > 0 || - (dataset?.dataset?.operations?.length || 0) > 0, - }, - }, - { - name: QUALITY_TAB_NAME, - component: AcrylValidationsTab, // Use SaaS specific Validations Tab. - icon: CheckCircleOutlined, - }, - { - name: GOVERNANCE_TAB_NAME, - icon: () => ( - - - - ), - component: GovernanceTab, - getCount: (_, dataset) => { - const passingTests = dataset?.dataset?.testResults?.passing || []; - const failingTests = dataset?.dataset?.testResults?.failing || []; - return passingTests.length + failingTests.length; - }, - }, - { - name: 'Runs', // TODO: Rename this to DatasetRunsTab. - component: OperationsTab, - display: { - visible: (_, dataset: GetDatasetQuery) => { - return (dataset?.dataset?.runs?.total || 0) > 0; - }, - enabled: (_, dataset: GetDatasetQuery) => { - return (dataset?.dataset?.runs?.total || 0) > 0; - }, - }, - }, - { - name: 'Incidents', - icon: WarningOutlined, - component: IncidentTab, - getCount: (_, dataset) => { - return dataset?.dataset?.activeIncidents?.total; - }, - }, - ]} + tabs={this.getProfileTabs()} sidebarSections={this.getSidebarSections()} sidebarTabs={this.getSidebarTabs()} /> @@ -377,6 +255,149 @@ export class DatasetEntity implements Entity { }; }; + getProfileTabs = (): EntityTab[] => { + const showSummaryTab = useShowDatasetSummaryPage(); + return [ + ...(showSummaryTab + ? [ + { + name: 'Summary', + component: SummaryTab, + icon: SUMMARY_TAB_ICON, + }, + ] + : []), + { + name: 'Columns', + component: SchemaTab, + icon: LayoutOutlined, + getCount: useGetColumnTabCount, + }, + { + name: 'View Definition', + component: ViewDefinitionTab, + icon: CodeOutlined, + display: { + visible: (_, dataset: GetDatasetQuery) => + !!dataset?.dataset?.viewProperties?.logic || + !!dataset?.dataset?.subTypes?.typeNames + ?.map((t) => t.toLocaleLowerCase()) + .includes(SUBTYPES.VIEW.toLocaleLowerCase()), + enabled: (_, dataset: GetDatasetQuery) => !!dataset?.dataset?.viewProperties?.logic, + }, + }, + ...(!showSummaryTab + ? [ + { + name: 'Documentation', + component: DocumentationTab, + icon: FileOutlined, + }, + ] + : []), + { + name: 'Preview', + component: EmbedTab, + icon: EyeOutlined, + display: { + visible: (_, dataset: GetDatasetQuery) => !!dataset?.dataset?.embed?.renderUrl, + enabled: (_, dataset: GetDatasetQuery) => !!dataset?.dataset?.embed?.renderUrl, + }, + }, + { + name: 'Lineage', + component: LineageTab, + icon: PartitionOutlined, + }, + { + name: 'Access', + component: AccessManagement, + icon: UnlockOutlined, + display: { + visible: (_, _1) => this.appconfig().config.featureFlags.showAccessManagement, + enabled: (_, _2) => true, + }, + }, + { + name: 'Properties', + component: PropertiesTab, + icon: UnorderedListOutlined, + getCount: (_, dataset: GetDatasetQuery) => { + const customPropertiesCount = dataset?.dataset?.properties?.customProperties?.length || 0; + const structuredPropertiesCount = dataset?.dataset?.structuredProperties?.properties?.length || 0; + const propertiesCount = customPropertiesCount + structuredPropertiesCount; + return propertiesCount; + }, + }, + { + name: 'Queries', + component: QueriesTab, + icon: ConsoleSqlOutlined, + display: { + visible: (_, _1) => true, + enabled: (_, _2) => true, + }, + }, + { + name: 'Stats', + component: StatsTabWrapper, + icon: FundOutlined, + display: { + visible: (_, _1) => true, + enabled: (_, dataset: GetDatasetQuery) => + (dataset?.dataset?.latestFullTableProfile?.length || 0) > 0 || + (dataset?.dataset?.latestPartitionProfile?.length || 0) > 0 || + (dataset?.dataset?.usageStats?.buckets?.length || 0) > 0 || + (dataset?.dataset?.operations?.length || 0) > 0, + }, + }, + { + name: QUALITY_TAB_NAME, + component: AcrylValidationsTab, // Use SaaS specific Validations Tab. + icon: CheckCircleOutlined, + }, + { + name: GOVERNANCE_TAB_NAME, + icon: () => ( + + + + ), + component: GovernanceTab, + getCount: (_, dataset) => { + const passingTests = dataset?.dataset?.testResults?.passing || []; + const failingTests = dataset?.dataset?.testResults?.failing || []; + return passingTests.length + failingTests.length; + }, + }, + { + name: 'Runs', // TODO: Rename this to DatasetRunsTab. + component: OperationsTab, + display: { + visible: (_, dataset: GetDatasetQuery) => { + return (dataset?.dataset?.runs?.total || 0) > 0; + }, + enabled: (_, dataset: GetDatasetQuery) => { + return (dataset?.dataset?.runs?.total || 0) > 0; + }, + }, + }, + { + name: 'Incidents', + icon: WarningOutlined, + component: IncidentTab, + getCount: (_, dataset) => { + return dataset?.dataset?.activeIncidents?.total; + }, + }, + ]; + }; + renderPreview = (previewType: PreviewType, data: Dataset) => { const genericProperties = this.getGenericEntityProperties(data); const platformNames = genericProperties?.siblingPlatforms?.map( diff --git a/datahub-web-react/src/app/entityV2/summary/properties/hooks/__tests__/useBasicAssetProperties.test.ts b/datahub-web-react/src/app/entityV2/summary/properties/hooks/__tests__/useBasicAssetProperties.test.ts index b205c9aec2778f..6cbbeaff892cbc 100644 --- a/datahub-web-react/src/app/entityV2/summary/properties/hooks/__tests__/useBasicAssetProperties.test.ts +++ b/datahub-web-react/src/app/entityV2/summary/properties/hooks/__tests__/useBasicAssetProperties.test.ts @@ -53,7 +53,7 @@ describe('useBasicAssetProperties', () => { }); it('should return an empty array for other entity types', () => { - (useEntityContext as any).mockReturnValue({ entityType: EntityType.Dataset }); + (useEntityContext as any).mockReturnValue({ entityType: EntityType.Chart }); const { result } = renderHook(() => useBasicAssetProperties()); expect(result.current).toEqual([]); }); diff --git a/datahub-web-react/src/app/entityV2/summary/properties/hooks/useBasicAssetProperties.ts b/datahub-web-react/src/app/entityV2/summary/properties/hooks/useBasicAssetProperties.ts index a35440262ad7e8..0d7100e62b7716 100644 --- a/datahub-web-react/src/app/entityV2/summary/properties/hooks/useBasicAssetProperties.ts +++ b/datahub-web-react/src/app/entityV2/summary/properties/hooks/useBasicAssetProperties.ts @@ -24,6 +24,8 @@ export default function useBasicAssetProperties() { return [CREATED_PROPERTY, OWNERS_PROPERTY]; case EntityType.DataProduct: return [CREATED_PROPERTY, OWNERS_PROPERTY, DOMAIN_PROPERTY, TAGS_PROPERTY, TERMS_PROPERTY]; + case EntityType.Dataset: + return [CREATED_PROPERTY, OWNERS_PROPERTY, DOMAIN_PROPERTY, TAGS_PROPERTY, TERMS_PROPERTY]; default: return []; } diff --git a/datahub-web-react/src/app/homeV3/context/hooks/utils/utils.test.ts b/datahub-web-react/src/app/homeV3/context/hooks/utils/utils.test.ts index 72f51ddc7ec8d6..40625842082769 100644 --- a/datahub-web-react/src/app/homeV3/context/hooks/utils/utils.test.ts +++ b/datahub-web-react/src/app/homeV3/context/hooks/utils/utils.test.ts @@ -124,7 +124,7 @@ describe('getDefaultSummaryPageTemplate', () => { }); it('should return template with empty arrays for unsupported entity types', () => { - const result = getDefaultSummaryPageTemplate(EntityType.Dataset); + const result = getDefaultSummaryPageTemplate(EntityType.Chart); expect(result).toEqual({ urn: 'urn:li:dataHubPageTemplate:asset_summary_default', diff --git a/datahub-web-react/src/app/homeV3/context/hooks/utils/utils.ts b/datahub-web-react/src/app/homeV3/context/hooks/utils/utils.ts index 6843dd633c8f27..6b379e9d2f7bf4 100644 --- a/datahub-web-react/src/app/homeV3/context/hooks/utils/utils.ts +++ b/datahub-web-react/src/app/homeV3/context/hooks/utils/utils.ts @@ -35,6 +35,9 @@ export function getDefaultSummaryPageTemplate(entityType: EntityType): PageTempl rows = [{ modules: [CHILD_HIERARCHY_MODULE] }]; summaryElements = [CREATED, OWNERS]; break; + case EntityType.Dataset: + summaryElements = [CREATED, OWNERS, DOMAIN, TAGS, GLOSSARY_TERMS]; + break; default: break; } diff --git a/datahub-web-react/src/graphql/dataset.graphql b/datahub-web-react/src/graphql/dataset.graphql index f095e217af49d1..e710db92b1e4b1 100644 --- a/datahub-web-react/src/graphql/dataset.graphql +++ b/datahub-web-react/src/graphql/dataset.graphql @@ -229,6 +229,9 @@ fragment nonSiblingDatasetFields on Dataset { } ...notes ...entityProfileVersionProperties + settings { + ...AssetSettingsFields + } } query getRecentQueries($urn: String!) { diff --git a/metadata-models/src/main/resources/entity-registry.yml b/metadata-models/src/main/resources/entity-registry.yml index a4d0035926b0f4..9a4ec476b46c0b 100644 --- a/metadata-models/src/main/resources/entity-registry.yml +++ b/metadata-models/src/main/resources/entity-registry.yml @@ -52,6 +52,7 @@ entities: - versionProperties - icebergCatalogInfo - logicalParent + - assetSettings - name: dataHubPolicy doc: DataHub Policies represent access policies granted to users or groups on metadata operations like edit, view etc. category: internal