diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/config/AppConfigResolver.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/config/AppConfigResolver.java index 026ac719f0..876f3f08c8 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/config/AppConfigResolver.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/config/AppConfigResolver.java @@ -7,6 +7,8 @@ import com.linkedin.datahub.graphql.featureflags.FeatureFlags; import com.linkedin.datahub.graphql.generated.AnalyticsConfig; import com.linkedin.datahub.graphql.generated.AppConfig; import com.linkedin.datahub.graphql.generated.AuthConfig; +import com.linkedin.datahub.graphql.generated.EntityProfileConfig; +import com.linkedin.datahub.graphql.generated.EntityProfilesConfig; import com.linkedin.datahub.graphql.generated.EntityType; import com.linkedin.datahub.graphql.generated.FeatureFlagsConfig; import com.linkedin.datahub.graphql.generated.IdentityManagementConfig; @@ -133,6 +135,15 @@ public class AppConfigResolver implements DataFetcher { isNameEditable tabs={[ { + id: EntityProfileTab.DOMAIN_ENTITIES_TAB, name: 'Entities', component: DomainEntitiesTab, }, { + id: EntityProfileTab.DOCUMENTATION_TAB, name: 'Documentation', component: DocumentationTab, }, { + id: EntityProfileTab.DATA_PRODUCTS_TAB, name: 'Data Products', component: DataProductsTab, }, diff --git a/datahub-web-react/src/app/entity/shared/constants.ts b/datahub-web-react/src/app/entity/shared/constants.ts index ba399dd287..bc40ba871e 100644 --- a/datahub-web-react/src/app/entity/shared/constants.ts +++ b/datahub-web-react/src/app/entity/shared/constants.ts @@ -93,3 +93,10 @@ export const GLOSSARY_ENTITY_TYPES = [EntityType.GlossaryTerm, EntityType.Glossa export const DEFAULT_SYSTEM_ACTOR_URNS = ['urn:li:corpuser:__datahub_system', 'urn:li:corpuser:unknown']; export const VIEW_ENTITY_PAGE = 'VIEW_ENTITY_PAGE'; + +// only values for Domain Entity for custom configurable default tab +export enum EntityProfileTab { + DOMAIN_ENTITIES_TAB = 'DOMAIN_ENTITIES_TAB', + DOCUMENTATION_TAB = 'DOCUMENTATION_TAB', + DATA_PRODUCTS_TAB = 'DATA_PRODUCTS_TAB', +} diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/EntityProfile.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/EntityProfile.tsx index f6e839d727..8a559013c8 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/EntityProfile.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/EntityProfile.tsx @@ -8,6 +8,7 @@ import { Message } from '../../../../shared/Message'; import { getEntityPath, getOnboardingStepIdsForEntityType, + sortEntityProfileTabs, useRoutedTab, useUpdateGlossaryEntityDataOnChange, } from './utils'; @@ -43,6 +44,7 @@ import { LINEAGE_GRAPH_INTRO_ID, LINEAGE_GRAPH_TIME_FILTER_ID, } from '../../../../onboarding/config/LineageGraphOnboardingConfig'; +import { useAppConfig } from '../../../../useAppConfig'; type Props = { urn: string; @@ -168,8 +170,10 @@ export const EntityProfile = ({ const isHideSiblingMode = useIsSeparateSiblingsMode(); const entityRegistry = useEntityRegistry(); const history = useHistory(); + const appConfig = useAppConfig(); const isCompact = React.useContext(CompactContext); const tabsWithDefaults = tabs.map((tab) => ({ ...tab, display: { ...defaultTabDisplayConfig, ...tab.display } })); + const sortedTabs = sortEntityProfileTabs(appConfig.config, entityType, tabsWithDefaults); const sideBarSectionsWithDefaults = sidebarSections.map((sidebarSection) => ({ ...sidebarSection, display: { ...defaultSidebarSection, ...sidebarSection.display }, @@ -235,7 +239,7 @@ export const EntityProfile = ({ }, })) || []; - const visibleTabs = [...tabsWithDefaults, ...autoRenderTabs].filter((tab) => + const visibleTabs = [...sortedTabs, ...autoRenderTabs].filter((tab) => tab.display?.visible(entityData, dataPossiblyCombinedWithSiblings), ); diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/utils.ts b/datahub-web-react/src/app/entity/shared/containers/profile/utils.ts index 625272aec2..fabf0b2c51 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/utils.ts +++ b/datahub-web-react/src/app/entity/shared/containers/profile/utils.ts @@ -2,7 +2,7 @@ import { useEffect } from 'react'; import { useLocation } from 'react-router'; import queryString from 'query-string'; import { isEqual } from 'lodash'; -import { EntityType } from '../../../../../types.generated'; +import { AppConfig, EntityType } from '../../../../../types.generated'; import useIsLineageMode from '../../../../lineage/utils/useIsLineageMode'; import { useEntityRegistry } from '../../../../useEntityRegistry'; import EntityRegistry from '../../../EntityRegistry'; @@ -202,3 +202,22 @@ export function getOnboardingStepIdsForEntityType(entityType: EntityType): strin return []; } } + +function sortTabsWithDefaultTabId(tabs: EntityTab[], defaultTabId: string) { + return tabs.sort((tabA, tabB) => { + if (tabA.id === defaultTabId) return -1; + if (tabB.id === defaultTabId) return 1; + return 0; + }); +} + +export function sortEntityProfileTabs(appConfig: AppConfig, entityType: EntityType, tabs: EntityTab[]) { + const sortedTabs = [...tabs]; + + if (entityType === EntityType.Domain && appConfig.visualConfig.entityProfiles?.domain?.defaultTab) { + const defaultTabId = appConfig.visualConfig.entityProfiles?.domain.defaultTab; + sortTabsWithDefaultTabId(sortedTabs, defaultTabId); + } + + return sortedTabs; +} diff --git a/datahub-web-react/src/app/entity/shared/types.ts b/datahub-web-react/src/app/entity/shared/types.ts index 9b7c794840..e36f5050a2 100644 --- a/datahub-web-react/src/app/entity/shared/types.ts +++ b/datahub-web-react/src/app/entity/shared/types.ts @@ -48,6 +48,7 @@ export type EntityTab = { enabled: (GenericEntityProperties, T) => boolean; // Whether the tab is enabled on the UI. Defaults to true. }; properties?: any; + id?: string; }; export type EntitySidebarSection = { diff --git a/datahub-web-react/src/appConfigContext.tsx b/datahub-web-react/src/appConfigContext.tsx index 6866278838..3b34b108ec 100644 --- a/datahub-web-react/src/appConfigContext.tsx +++ b/datahub-web-react/src/appConfigContext.tsx @@ -24,6 +24,9 @@ export const DEFAULT_APP_CONFIG = { queriesTab: { queriesTabResultSize: 5, }, + entityProfile: { + domainDefaultTab: null, + }, }, authConfig: { tokenAuthEnabled: false, diff --git a/datahub-web-react/src/graphql/app.graphql b/datahub-web-react/src/graphql/app.graphql index f62822047f..4b1295f102 100644 --- a/datahub-web-react/src/graphql/app.graphql +++ b/datahub-web-react/src/graphql/app.graphql @@ -40,6 +40,11 @@ query appConfig { queriesTab { queriesTabResultSize } + entityProfiles { + domain { + defaultTab + } + } } telemetryConfig { enableThirdPartyLogging diff --git a/metadata-io/src/main/java/com/linkedin/metadata/config/EntityProfileConfig.java b/metadata-io/src/main/java/com/linkedin/metadata/config/EntityProfileConfig.java new file mode 100644 index 0000000000..7c4394d07b --- /dev/null +++ b/metadata-io/src/main/java/com/linkedin/metadata/config/EntityProfileConfig.java @@ -0,0 +1,12 @@ +package com.linkedin.metadata.config; + +import lombok.Data; + + +@Data +public class EntityProfileConfig { + /** + * The default tab to show first on a Domain entity profile. Defaults to React code sorting if not present. + */ + public String domainDefaultTab; +} diff --git a/metadata-io/src/main/java/com/linkedin/metadata/config/VisualConfiguration.java b/metadata-io/src/main/java/com/linkedin/metadata/config/VisualConfiguration.java index 6505fdf29d..d1c357186e 100644 --- a/metadata-io/src/main/java/com/linkedin/metadata/config/VisualConfiguration.java +++ b/metadata-io/src/main/java/com/linkedin/metadata/config/VisualConfiguration.java @@ -17,4 +17,9 @@ public class VisualConfiguration { * Queries tab related configurations */ public QueriesTabConfig queriesTab; + + /** + * Queries tab related configurations + */ + public EntityProfileConfig entityProfile; } diff --git a/metadata-service/factories/src/main/resources/application.yml b/metadata-service/factories/src/main/resources/application.yml index 59f34e0b6e..18f042b65d 100644 --- a/metadata-service/factories/src/main/resources/application.yml +++ b/metadata-service/factories/src/main/resources/application.yml @@ -108,6 +108,9 @@ visualConfig: assets: logoUrl: ${REACT_APP_LOGO_URL:/assets/platforms/datahublogo.png} faviconUrl: ${REACT_APP_FAVICON_URL:/assets/favicon.ico} + entityProfile: + # we only support default tab for domains right now. In order to implement for other entities, update React code + domainDefaultTab: ${DOMAIN_DEFAULT_TAB:} # set to DOCUMENTATION_TAB to show documentation tab first # Storage Layer