diff --git a/conf/defaults.ini b/conf/defaults.ini index 8504f1b8735..3f0a03de907 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -890,6 +890,16 @@ max_annotations_to_keep = # Enable the Explore section enabled = true +#################################### Help ############################# +[help] +# Enable the Help section +enabled = true + +#################################### Profile ############################# +[profile] +# Enable the Profile section +enabled = true + #################################### Query History ############################# [query_history] # Enable the Query history diff --git a/conf/sample.ini b/conf/sample.ini index b83d6ed8824..d56075fd037 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -872,6 +872,16 @@ # Enable the Explore section ;enabled = true +#################################### Help ############################# +[help] +# Enable the Help section +;enabled = true + +#################################### Profile ############################# +[profile] +# Enable the Profile section +;enabled = true + #################################### Query History ############################# [query_history] # Enable the Query history diff --git a/docs/sources/administration/configuration.md b/docs/sources/administration/configuration.md index ea43dff2807..c44ce31b24a 100644 --- a/docs/sources/administration/configuration.md +++ b/docs/sources/administration/configuration.md @@ -1345,6 +1345,22 @@ For more information about this feature, refer to [Explore]({{< relref "../explo Enable or disable the Explore section. Default is `enabled`. +## [help] + +Configures the help section. + +### enabled + +Enable or disable the Help section. Default is `enabled`. + +## [profile] + +Configures the Profile section. + +### enabled + +Enable or disable the Profile section. Default is `enabled`. + ## [metrics] For detailed instructions, refer to [Internal Grafana metrics]({{< relref "view-server/internal-metrics.md" >}}). diff --git a/packages/grafana-data/src/types/config.ts b/packages/grafana-data/src/types/config.ts index cca149159ca..241a2b63058 100644 --- a/packages/grafana-data/src/types/config.ts +++ b/packages/grafana-data/src/types/config.ts @@ -111,6 +111,8 @@ export interface GrafanaConfig { alertingMinInterval: number; authProxyEnabled: boolean; exploreEnabled: boolean; + helpEnabled: boolean; + profileEnabled: boolean; ldapEnabled: boolean; sigV4AuthEnabled: boolean; samlEnabled: boolean; diff --git a/packages/grafana-runtime/src/config.ts b/packages/grafana-runtime/src/config.ts index bb3edef57a9..9831ae904b5 100644 --- a/packages/grafana-runtime/src/config.ts +++ b/packages/grafana-runtime/src/config.ts @@ -44,6 +44,8 @@ export class GrafanaBootConfig implements GrafanaConfig { angularSupportEnabled = false; authProxyEnabled = false; exploreEnabled = false; + helpEnabled = false; + profileEnabled = false; ldapEnabled = false; sigV4AuthEnabled = false; samlEnabled = false; diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index 166de771e65..cc609bb2dda 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -105,6 +105,8 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *models.ReqContext) (map[string]i "verifyEmailEnabled": setting.VerifyEmailEnabled, "sigV4AuthEnabled": setting.SigV4AuthEnabled, "exploreEnabled": setting.ExploreEnabled, + "helpEnabled": setting.HelpEnabled, + "profileEnabled": setting.ProfileEnabled, "queryHistoryEnabled": hs.Cfg.QueryHistoryEnabled, "googleAnalyticsId": setting.GoogleAnalyticsId, "rudderstackWriteKey": setting.RudderstackWriteKey, diff --git a/pkg/api/index.go b/pkg/api/index.go index 0d81142e4a0..8d959182067 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -221,9 +221,7 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto }) } - if c.IsSignedIn { - navTree = append(navTree, hs.getProfileNode(c)) - } + navTree = hs.addProfile(navTree, c) _, uaIsDisabledForOrg := hs.Cfg.UnifiedAlerting.DisabledOrgs[c.OrgId] uaVisibleForOrg := hs.Cfg.UnifiedAlerting.IsEnabled() && !uaIsDisabledForOrg @@ -364,25 +362,39 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto navTree = append(navTree, serverAdminNode) } - helpVersion := fmt.Sprintf(`%s v%s (%s)`, setting.ApplicationName, setting.BuildVersion, setting.BuildCommit) - if hs.Cfg.AnonymousHideVersion && !c.IsSignedIn { - helpVersion = setting.ApplicationName - } - - navTree = append(navTree, &dtos.NavLink{ - Text: "Help", - SubTitle: helpVersion, - Id: "help", - Url: "#", - Icon: "question-circle", - SortWeight: dtos.WeightHelp, - Section: dtos.NavSectionConfig, - Children: []*dtos.NavLink{}, - }) + navTree = hs.addHelpLinks(navTree, c) return navTree, nil } +func (hs *HTTPServer) addProfile(navTree []*dtos.NavLink, c *models.ReqContext) []*dtos.NavLink { + if setting.ProfileEnabled && c.IsSignedIn { + navTree = append(navTree, hs.getProfileNode(c)) + } + return navTree +} + +func (hs *HTTPServer) addHelpLinks(navTree []*dtos.NavLink, c *models.ReqContext) []*dtos.NavLink { + if setting.HelpEnabled { + helpVersion := fmt.Sprintf(`%s v%s (%s)`, setting.ApplicationName, setting.BuildVersion, setting.BuildCommit) + if hs.Cfg.AnonymousHideVersion && !c.IsSignedIn { + helpVersion = setting.ApplicationName + } + + navTree = append(navTree, &dtos.NavLink{ + Text: "Help", + SubTitle: helpVersion, + Id: "help", + Url: "#", + Icon: "question-circle", + SortWeight: dtos.WeightHelp, + Section: dtos.NavSectionConfig, + Children: []*dtos.NavLink{}, + }) + } + return navTree +} + func (hs *HTTPServer) buildSavedItemsNavLinks(c *models.ReqContext) ([]*dtos.NavLink, error) { savedItemsChildNavs := []*dtos.NavLink{} diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index 346e1945ac6..c7786fe3014 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -171,6 +171,12 @@ var ( // Explore UI ExploreEnabled bool + // Help UI + HelpEnabled bool + + // Profile UI + ProfileEnabled bool + // Grafana.NET URL GrafanaComUrl string @@ -943,6 +949,12 @@ func (cfg *Cfg) Load(args CommandLineArgs) error { explore := iniFile.Section("explore") ExploreEnabled = explore.Key("enabled").MustBool(true) + help := iniFile.Section("help") + HelpEnabled = help.Key("enabled").MustBool(true) + + profile := iniFile.Section("profile") + ProfileEnabled = profile.Key("enabled").MustBool(true) + queryHistory := iniFile.Section("query_history") cfg.QueryHistoryEnabled = queryHistory.Key("enabled").MustBool(false) diff --git a/public/app/features/profile/FeatureTogglePage.tsx b/public/app/features/profile/FeatureTogglePage.tsx new file mode 100644 index 00000000000..1b7b3be5a2e --- /dev/null +++ b/public/app/features/profile/FeatureTogglePage.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import Page from 'app/core/components/Page/Page'; +import { useNavModel } from 'app/core/hooks/useNavModel'; + +export default function FeatureTogglePage() { + const navModel = useNavModel('profile-settings'); + + return ( + + +

Profile is not enabled.

+ Enable profile in the Grafana config file. +
+
+            {`[profile]
+enable = true
+`}
+          
+
+
+
+ ); +} diff --git a/public/app/features/profile/routes.tsx b/public/app/features/profile/routes.tsx new file mode 100644 index 00000000000..48029f75dc8 --- /dev/null +++ b/public/app/features/profile/routes.tsx @@ -0,0 +1,39 @@ +import { SafeDynamicImport } from 'app/core/components/DynamicImports/SafeDynamicImport'; +import { config } from 'app/core/config'; +import { RouteDescriptor } from 'app/core/navigation/types'; +import { uniq } from 'lodash'; + +const profileRoutes: RouteDescriptor[] = [ + { + path: '/profile', + component: SafeDynamicImport( + () => import(/* webpackChunkName: "UserProfileEditPage" */ 'app/features/profile/UserProfileEditPage') + ), + }, + { + path: '/profile/password', + component: SafeDynamicImport( + () => import(/* webPackChunkName: "ChangePasswordPage" */ 'app/features/profile/ChangePasswordPage') + ), + }, + { + path: '/profile/select-org', + component: SafeDynamicImport( + () => import(/* webpackChunkName: "SelectOrgPage" */ 'app/features/org/SelectOrgPage') + ), + }, +]; + +export function getProfileRoutes(cfg = config): RouteDescriptor[] { + if (cfg.profileEnabled) { + return profileRoutes; + } + + const uniquePaths = uniq(profileRoutes.map((route) => route.path)); + return uniquePaths.map((path) => ({ + path, + component: SafeDynamicImport( + () => import(/* webpackChunkName: "Profile feature toggle page"*/ 'app/features/profile/FeatureTogglePage') + ), + })); +} diff --git a/public/app/routes/routes.tsx b/public/app/routes/routes.tsx index 967dac17f75..022b0b42aee 100644 --- a/public/app/routes/routes.tsx +++ b/public/app/routes/routes.tsx @@ -12,6 +12,7 @@ import { getRoutes as getPluginCatalogRoutes } from 'app/features/plugins/admin/ import { contextSrv } from 'app/core/services/context_srv'; import { getLiveRoutes } from 'app/features/live/pages/routes'; import { getAlertingRoutes } from 'app/features/alerting/routes'; +import { getProfileRoutes } from 'app/features/profile/routes'; import { ServiceAccountPage } from 'app/features/serviceaccounts/ServiceAccountPage'; export const extraRoutes: RouteDescriptor[] = []; @@ -247,24 +248,6 @@ export function getAppRoutes(): RouteDescriptor[] { ), component: SafeDynamicImport(() => import(/* webpackChunkName: "TeamPages" */ 'app/features/teams/TeamPages')), }, - { - path: '/profile', - component: SafeDynamicImport( - () => import(/* webpackChunkName: "UserProfileEditPage" */ 'app/features/profile/UserProfileEditPage') - ), - }, - { - path: '/profile/password', - component: SafeDynamicImport( - () => import(/* webPackChunkName: "ChangePasswordPage" */ 'app/features/profile/ChangePasswordPage') - ), - }, - { - path: '/profile/select-org', - component: SafeDynamicImport( - () => import(/* webpackChunkName: "SelectOrgPage" */ 'app/features/org/SelectOrgPage') - ), - }, // ADMIN { @@ -436,6 +419,7 @@ export function getAppRoutes(): RouteDescriptor[] { ...getPluginCatalogRoutes(), ...getLiveRoutes(), ...getAlertingRoutes(), + ...getProfileRoutes(), ...extraRoutes, { path: '/*',