diff --git a/pkg/services/navtree/navtreeimpl/navtree.go b/pkg/services/navtree/navtreeimpl/navtree.go index c626890566..71ce06ec79 100644 --- a/pkg/services/navtree/navtreeimpl/navtree.go +++ b/pkg/services/navtree/navtreeimpl/navtree.go @@ -21,7 +21,6 @@ import ( "github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore" pref "github.com/grafana/grafana/pkg/services/preference" "github.com/grafana/grafana/pkg/services/star" - "github.com/grafana/grafana/pkg/services/supportbundles/supportbundlesimpl" "github.com/grafana/grafana/pkg/setting" ) @@ -132,33 +131,31 @@ func (s *ServiceImpl) GetNavTree(c *contextmodel.ReqContext, prefs *pref.Prefere }) } - if s.cfg.ProfileEnabled && c.IsSignedIn { + if s.cfg.ProfileEnabled && c.IsSignedIn && false { treeRoot.AddSection(s.getProfileNode(c)) } _, uaIsDisabledForOrg := s.cfg.UnifiedAlerting.DisabledOrgs[c.SignedInUser.GetOrgID()] uaVisibleForOrg := s.cfg.UnifiedAlerting.IsEnabled() && !uaIsDisabledForOrg - if uaVisibleForOrg { + if uaVisibleForOrg && false { if alertingSection := s.buildAlertNavLinks(c); alertingSection != nil { treeRoot.AddSection(alertingSection) } } - if connectionsSection := s.buildDataConnectionsNavLink(c); connectionsSection != nil { + if connectionsSection := s.buildDataConnectionsNavLink(c); connectionsSection != nil && false { treeRoot.AddSection(connectionsSection) } orgAdminNode, err := s.getAdminNode(c) - if orgAdminNode != nil && len(orgAdminNode.Children) > 0 { + if orgAdminNode != nil && len(orgAdminNode.Children) > 0 && false { treeRoot.AddSection(orgAdminNode) } else if err != nil { return nil, err } - s.addHelpLinks(treeRoot, c) - if err := s.addAppLinks(treeRoot, c); err != nil { return nil, err } @@ -205,44 +202,6 @@ func (s *ServiceImpl) getHomeNode(c *contextmodel.ReqContext, prefs *pref.Prefer return homeNode } -func isSupportBundlesEnabled(s *ServiceImpl) bool { - return s.cfg.SectionWithEnvOverrides("support_bundles").Key("enabled").MustBool(true) -} - -func (s *ServiceImpl) addHelpLinks(treeRoot *navtree.NavTreeRoot, c *contextmodel.ReqContext) { - if s.cfg.HelpEnabled { - // The version subtitle is set later by NavTree.ApplyHelpVersion - helpNode := &navtree.NavLink{ - Text: "Help", - Id: "help", - Url: "#", - Icon: "question-circle", - SortWeight: navtree.WeightHelp, - Children: []*navtree.NavLink{}, - } - - treeRoot.AddSection(helpNode) - - hasAccess := ac.HasAccess(s.accessControl, c) - supportBundleAccess := ac.EvalAny( - ac.EvalPermission(supportbundlesimpl.ActionRead), - ac.EvalPermission(supportbundlesimpl.ActionCreate), - ) - - if isSupportBundlesEnabled(s) && hasAccess(supportBundleAccess) { - supportBundleNode := &navtree.NavLink{ - Text: "Support bundles", - Id: "support-bundles", - Url: "/support-bundles", - Icon: "wrench", - SortWeight: navtree.WeightHelp, - } - - helpNode.Children = append(helpNode.Children, supportBundleNode) - } - } -} - func (s *ServiceImpl) getProfileNode(c *contextmodel.ReqContext) *navtree.NavLink { // Only set login if it's different from the name var login string diff --git a/public/app/core/components/AppChrome/AppChrome.tsx b/public/app/core/components/AppChrome/AppChrome.tsx index 79d177e7f7..53894398fc 100644 --- a/public/app/core/components/AppChrome/AppChrome.tsx +++ b/public/app/core/components/AppChrome/AppChrome.tsx @@ -7,11 +7,14 @@ import { config, locationSearchToObject, locationService } from '@grafana/runtim import { useStyles2, LinkButton, useTheme2 } from '@grafana/ui'; import { useGrafana } from 'app/core/context/GrafanaContext'; import { useMediaQueryChange } from 'app/core/hooks/useMediaQueryChange'; +import { contextSrv } from 'app/core/services/context_srv'; import store from 'app/core/store'; import { CommandPalette } from 'app/features/commandPalette/CommandPalette'; import { useOpspilotMetadata } from 'app/intergral/useOpspilotMetadata'; import { KioskMode } from 'app/types'; +import { useIntercom } from '../../../intergral/intercom'; + import { AppChromeMenu } from './AppChromeMenu'; import { DOCKED_LOCAL_STORAGE_KEY, DOCKED_MENU_OPEN_LOCAL_STORAGE_KEY } from './AppChromeService'; import { MegaMenu } from './MegaMenu/MegaMenu'; @@ -29,6 +32,28 @@ export function AppChrome({ children, hideSearchBar }: Props) { const theme = useTheme2(); const styles = useStyles2(getStyles, searchBarHidden); + const hideIntercomStyle = css` + #intercom-container { + display: none !important; + } +`; + + // Fetch user info + const user = { + name: contextSrv.user?.name || '', + email: contextSrv.user?.email || '', + }; + + // Use the Intercom hook + useIntercom(user.name, user.email); + + useEffect(() => { + document.body.classList.add(hideIntercomStyle); + return () => { + document.body.classList.remove(hideIntercomStyle); + }; + }, [hideIntercomStyle]); + const dockedMenuBreakpoint = theme.breakpoints.values.xl; const dockedMenuLocalStorageState = store.getBool(DOCKED_LOCAL_STORAGE_KEY, true); const menuDockedAndOpen = !state.chromeless && state.megaMenuDocked && state.megaMenuOpen; @@ -155,13 +180,13 @@ const getStyles = (theme: GrafanaTheme2, searchBarHidden: boolean) => { }, config.featureToggles.bodyScrolling ? { - position: 'fixed', - height: `calc(100% - ${searchBarHidden ? TOP_BAR_LEVEL_HEIGHT : TOP_BAR_LEVEL_HEIGHT * 2}px)`, - zIndex: 1, - } + position: 'fixed', + height: `calc(100% - ${searchBarHidden ? TOP_BAR_LEVEL_HEIGHT : TOP_BAR_LEVEL_HEIGHT * 2}px)`, + zIndex: 1, + } : { - zIndex: theme.zIndex.navbarFixed, - } + zIndex: theme.zIndex.navbarFixed, + } ), topNav: css({ display: 'flex', diff --git a/public/app/core/components/AppChrome/NavToolbar/NavToolbar.tsx b/public/app/core/components/AppChrome/NavToolbar/NavToolbar.tsx index a642dff063..81b4522e52 100644 --- a/public/app/core/components/AppChrome/NavToolbar/NavToolbar.tsx +++ b/public/app/core/components/AppChrome/NavToolbar/NavToolbar.tsx @@ -3,13 +3,13 @@ import * as React from 'react'; import { GrafanaTheme2, NavModelItem } from '@grafana/data'; import { Components } from '@grafana/e2e-selectors'; -import { ToolbarButton, useStyles2 } from '@grafana/ui'; -import { t } from 'app/core/internationalization'; +import { useStyles2 } from '@grafana/ui'; import { HOME_NAV_ID } from 'app/core/reducers/navModel'; import { useSelector } from 'app/types'; import { Breadcrumbs } from '../../Breadcrumbs/Breadcrumbs'; import { buildBreadcrumbs } from '../../Breadcrumbs/utils'; +import { TopSearchBarCommandPaletteTrigger } from '../TopBar/TopSearchBarCommandPaletteTrigger'; import { TOP_BAR_LEVEL_HEIGHT } from '../types'; export const TOGGLE_BUTTON_ID = 'mega-menu-toggle'; @@ -37,17 +37,14 @@ export function NavToolbar({ return (
- + +
+
+ +
+
{actions} - {searchBarHidden && ( - - )}
); @@ -64,8 +61,9 @@ const getStyles = (theme: GrafanaTheme2) => { }), pageToolbar: css({ height: TOP_BAR_LEVEL_HEIGHT, - display: 'flex', - padding: theme.spacing(0, 1, 0, 2), + display: 'grid', + gridTemplateColumns: 'auto 1fr auto', // This creates a three-column layout + padding: theme.spacing(0, 2), alignItems: 'center', borderBottom: `1px solid ${theme.colors.border.weak}`, }), @@ -86,8 +84,23 @@ const getStyles = (theme: GrafanaTheme2) => { minWidth: 0, '.body-drawer-open &': { - display: 'none', + [theme.breakpoints.down('md')]: { + display: 'none', + } }, }), + searchWrapper: css({ + display: 'flex', + justifyContent: 'center', // Center the search bar + width: '100%', + maxWidth: '550px', // Adjust as needed + margin: '0 auto', // Center the wrapper itself + }), + centerWrapper: css({ + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + width: '100%', + }), }; }; diff --git a/public/app/intergral/intercom.ts b/public/app/intergral/intercom.ts new file mode 100644 index 0000000000..2c4edb8cc7 --- /dev/null +++ b/public/app/intergral/intercom.ts @@ -0,0 +1,72 @@ +import { useEffect } from 'react'; + +// Declare Intercom as a global function +declare global { + interface Window { + Intercom: any; + } +} + +export function useIntercom(userName: string, userEmail: string) { + useEffect(() => { + // Check if we're in a browser environment + if (typeof window === 'undefined' || typeof document === 'undefined') { + console.warn('Intercom setup aborted: Not in a browser environment'); + return; + } + + // Intercom setup function + const setupIntercom = () => { + (function() { + let w = window as any; + let ic = w.Intercom; + if (typeof ic === "function") { + ic('reattach_activator'); + ic('update', w.intercomSettings); + } else { + let d = document; + let i = function () { + (i as any).c(arguments); + }; + (i as any).q = []; + (i as any).c = function(args: any) { + (i as any).q.push(args); + }; + w.Intercom = i; + let l = function () { + let s = d.createElement('script'); + s.type = 'text/javascript'; + s.async = true; + s.src = 'https://widget.intercom.io/widget/ok1wowgi'; + let x = d.getElementsByTagName('script')[0]; + let parent = x?.parentNode || document.body + parent.insertBefore(s, x || null); + }; + if (document.readyState === 'complete') { + l(); + } else if (w.attachEvent) { + w.attachEvent('onload', l); + } else { + w.addEventListener('load', l, false); + } + } + })(); + + window.Intercom("boot", { + api_base: "https://api-iam.intercom.io", + app_id: "ok1wowgi", + name: userName, + email: userEmail, + }); + }; + + setupIntercom(); + + // Cleanup function + return () => { + if (window.Intercom) { + window.Intercom('shutdown'); + } + }; + }, [userName, userEmail]); // Re-run if userName or userEmail changes +}