From 65ce173d3fd4a98f7763200cdddb80009a23d59b Mon Sep 17 00:00:00 2001 From: Ashley Harrison Date: Fri, 18 Oct 2024 13:58:54 +0100 Subject: [PATCH] SingleTopNav: Handle explore action placement (#94812) * move query library + share buttons to toolbar * add share text to button * need spacer when not in singleTopNav * fix unit tests * use secondary button styling when singleTopNav is enabled --- public/app/features/explore/ExplorePage.tsx | 8 +--- .../app/features/explore/ExploreToolbar.tsx | 34 ++++++++++---- .../app/features/explore/SecondaryActions.tsx | 4 +- .../features/explore/ShortLinkButtonMenu.tsx | 45 ++++++++++--------- .../features/explore/spec/helper/setup.tsx | 13 +++--- public/app/routes/RoutesWrapper.tsx | 33 +++++++------- public/locales/en-US/grafana.json | 1 + public/locales/pseudo-LOCALE/grafana.json | 1 + 8 files changed, 83 insertions(+), 56 deletions(-) diff --git a/public/app/features/explore/ExplorePage.tsx b/public/app/features/explore/ExplorePage.tsx index f5f4c9b6ccc..1764a81ed16 100644 --- a/public/app/features/explore/ExplorePage.tsx +++ b/public/app/features/explore/ExplorePage.tsx @@ -21,7 +21,7 @@ import { CorrelationEditorModeBar } from './CorrelationEditorModeBar'; import { ExploreActions } from './ExploreActions'; import { ExploreDrawer } from './ExploreDrawer'; import { ExplorePaneContainer } from './ExplorePaneContainer'; -import { QueriesDrawerContextProvider, useQueriesDrawerContext } from './QueriesDrawer/QueriesDrawerContext'; +import { useQueriesDrawerContext } from './QueriesDrawer/QueriesDrawerContext'; import { QUERY_LIBRARY_LOCAL_STORAGE_KEYS } from './QueryLibrary/QueryLibrary'; import { queryLibraryTrackAddFromQueryRow } from './QueryLibrary/QueryLibraryAnalyticsEvents'; import { QueryTemplateForm } from './QueryLibrary/QueryTemplateForm'; @@ -37,11 +37,7 @@ const MIN_PANE_WIDTH = 200; const QUERY_LIBRARY_ACTION_KEY = 'queryLibraryAction'; export default function ExplorePage(props: GrafanaRouteComponentProps<{}, ExploreQueryParams>) { - return ( - - - - ); + return ; } function ExplorePageContent(props: GrafanaRouteComponentProps<{}, ExploreQueryParams>) { diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx index 1a08b894354..9345d58b2c1 100644 --- a/public/app/features/explore/ExploreToolbar.tsx +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -4,6 +4,7 @@ import { useMemo } from 'react'; import { shallowEqual } from 'react-redux'; import { DataSourceInstanceSettings, RawTimeRange, GrafanaTheme2 } from '@grafana/data'; +import { Components } from '@grafana/e2e-selectors'; import { config, reportInteraction } from '@grafana/runtime'; import { defaultIntervals, @@ -26,6 +27,7 @@ import { getFiscalYearStartMonth, getTimeZone } from '../profile/state/selectors import { ExploreTimeControls } from './ExploreTimeControls'; import { LiveTailButton } from './LiveTailButton'; +import { useQueriesDrawerContext } from './QueriesDrawer/QueriesDrawerContext'; import { QueriesDrawerDropdown } from './QueriesDrawer/QueriesDrawerDropdown'; import { ShortLinkButtonMenu } from './ShortLinkButtonMenu'; import { ToolbarExtensionPoint } from './extensions/ToolbarExtensionPoint'; @@ -90,6 +92,7 @@ export function ExploreToolbar({ exploreId, onChangeTime, onContentOutlineToogle const isCorrelationsEditorMode = correlationDetails?.editorMode || false; const isLeftPane = useSelector(isLeftPaneSelector(exploreId)); const isSingleTopNav = config.featureToggles.singleTopNav; + const { drawerOpened, setDrawerOpened, queryLibraryAvailable } = useQueriesDrawerContext(); const shouldRotateSplitIcon = useMemo( () => (isLeftPane && isLargerPane) || (!isLeftPane && !isLargerPane), @@ -202,16 +205,32 @@ export function ExploreToolbar({ exploreId, onChangeTime, onContentOutlineToogle dispatch(changeRefreshInterval({ exploreId, refreshInterval })); }; - const navBarActions = [,
]; + const navBarActions = []; + + if (isSingleTopNav) { + if (queryLibraryAvailable) { + navBarActions.unshift(); + } else { + navBarActions.unshift( + setDrawerOpened(!drawerOpened)} + data-testid={Components.QueryTab.queryHistoryButton} + icon="history" + > + Query history + + ); + } + } else { + navBarActions.push(
); + } return (
{refreshInterval && } - {!isSingleTopNav && ( -
- -
- )} + , - isSingleTopNav && , ].filter(Boolean)} forceShowLeftItems > {[ - , + !isSingleTopNav && , !splitted ? ( diff --git a/public/app/features/explore/ShortLinkButtonMenu.tsx b/public/app/features/explore/ShortLinkButtonMenu.tsx index ef1d7c6cdd2..61e07be02be 100644 --- a/public/app/features/explore/ShortLinkButtonMenu.tsx +++ b/public/app/features/explore/ShortLinkButtonMenu.tsx @@ -2,8 +2,8 @@ import { useState } from 'react'; import { IconName } from '@grafana/data'; import { reportInteraction, config } from '@grafana/runtime'; -import { ToolbarButton, Dropdown, Menu, Stack, ToolbarButtonRow, MenuGroup } from '@grafana/ui'; -import { t } from 'app/core/internationalization'; +import { ToolbarButton, Dropdown, Menu, MenuGroup, ButtonGroup } from '@grafana/ui'; +import { t, Trans } from 'app/core/internationalization'; import { copyStringToClipboard } from 'app/core/utils/explore'; import { createAndCopyShortLink } from 'app/core/utils/shortLinks'; import { useSelector } from 'app/types'; @@ -39,6 +39,7 @@ export function ShortLinkButtonMenu() { const panes = useSelector(selectPanes); const [isOpen, setIsOpen] = useState(false); const [lastSelected, setLastSelected] = useState(defaultMode); + const isSingleTopNav = config.featureToggles.singleTopNav; const onCopyLink = (shorten: boolean, absTime: boolean, url?: string) => { if (shorten) { createAndCopyShortLink(url || global.location.href); @@ -131,27 +132,29 @@ export function ShortLinkButtonMenu() { // we need the Toolbar button click to be an action separate from opening/closing the menu return ( - - + + { + const url = lastSelected.getUrl(); + onCopyLink(lastSelected.shorten, lastSelected.absTime, url); + }} + aria-label={t('explore.toolbar.copy-shortened-link', 'Copy shortened URL')} + > + {isSingleTopNav && Share} + + { - const url = lastSelected.getUrl(); - onCopyLink(lastSelected.shorten, lastSelected.absTime, url); - }} - aria-label={t('explore.toolbar.copy-shortened-link', 'Copy shortened URL')} + variant={isSingleTopNav ? 'canvas' : 'default'} + isOpen={isOpen} + aria-label={t('explore.toolbar.copy-shortened-link-menu', 'Open copy link options')} /> - - - - - + + ); } diff --git a/public/app/features/explore/spec/helper/setup.tsx b/public/app/features/explore/spec/helper/setup.tsx index 69ba506324a..95343074143 100644 --- a/public/app/features/explore/spec/helper/setup.tsx +++ b/public/app/features/explore/spec/helper/setup.tsx @@ -43,6 +43,7 @@ import { LokiQuery } from '../../../../plugins/datasource/loki/types'; import { ExploreQueryParams } from '../../../../types'; import { initialUserState } from '../../../profile/state/reducers'; import ExplorePage from '../../ExplorePage'; +import { QueriesDrawerContextProvider } from '../../QueriesDrawer/QueriesDrawerContext'; type DatasourceSetup = { settings: DataSourceInstanceSettings; api: DataSourceApi }; @@ -174,11 +175,13 @@ export function setupExplore(options?: SetupOptions): { - } - /> + + } + /> + diff --git a/public/app/routes/RoutesWrapper.tsx b/public/app/routes/RoutesWrapper.tsx index 68d12a38236..94ecc4f54b0 100644 --- a/public/app/routes/RoutesWrapper.tsx +++ b/public/app/routes/RoutesWrapper.tsx @@ -12,6 +12,7 @@ import { AppChrome } from '../core/components/AppChrome/AppChrome'; import { AppNotificationList } from '../core/components/AppNotifications/AppNotificationList'; import { ModalsContextProvider } from '../core/context/ModalsContextProvider'; import { useSidecar } from '../core/context/SidecarContext'; +import { QueriesDrawerContextProvider } from '../features/explore/QueriesDrawer/QueriesDrawerContext'; import AppRootPage from '../features/plugins/components/AppRootPage'; import { createLocationStorageHistory } from './utils'; @@ -26,22 +27,24 @@ export function RouterWrapper(props: RouterWrapperProps) { - - - - - - {props.pageBanners.map((Banner, index) => ( - + + + + + + + {props.pageBanners.map((Banner, index) => ( + + ))} + {props.routes} + + {props.bodyRenderHooks.map((Hook, index) => ( + ))} - {props.routes} - - {props.bodyRenderHooks.map((Hook, index) => ( - - ))} - - - + + + + diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 3dcb63832eb..89f2baedfe0 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -1018,6 +1018,7 @@ "copy-links-normal-category": "Normal URL links", "copy-shortened-link": "Copy shortened URL", "copy-shortened-link-abs-time": "Copy absolute shortened URL", + "copy-shortened-link-label": "Share", "copy-shortened-link-menu": "Open copy link options", "refresh-picker-cancel": "Cancel", "refresh-picker-run": "Run query", diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index 61d3fdb3314..ed74cc46f30 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -1018,6 +1018,7 @@ "copy-links-normal-category": "Ńőřmäľ ŮŖĿ ľįʼnĸş", "copy-shortened-link": "Cőpy şĥőřŧęʼnęđ ŮŖĿ", "copy-shortened-link-abs-time": "Cőpy äþşőľūŧę şĥőřŧęʼnęđ ŮŖĿ", + "copy-shortened-link-label": "Ŝĥäřę", "copy-shortened-link-menu": "Øpęʼn čőpy ľįʼnĸ őpŧįőʼnş", "refresh-picker-cancel": "Cäʼnčęľ", "refresh-picker-run": "Ŗūʼn qūęřy",