From f6e472f8797cde4dfdc3ab4f1fc3fc5969b7c8fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Jamr=C3=B3z?= Date: Wed, 24 Apr 2024 10:32:11 +0200 Subject: [PATCH] Explore: Show a drawer with tabs for the library and query history (#86279) * Create basic feature toggle * Rename context to reflect it contains query history and query library * Update icons and variants * Rename hooks * Update tests * Fix mock * Add tracking * Turn button into a toggle * Make dropdown active as well This is required to have better UI and an indication of selected state in split view * Update Query Library icon This is to make it consistent with the toolbar button * Hide query history button when query library is available This is to avoid confusing UX with 2 button triggering the drawer but with slightly different behavior * Make the drawer bigger for query library To avoid confusion for current users and test it internally a bit more it's behind a feature toggle. Bigger drawer may obstruct the view and add more friction in the UX. * Fix tests The test was failing because queryLibraryAvailable was set to true for tests. This change makes it more explicit what use case is being tested * Remove active state underline from the dropdown * Allow closing Query Library drawer from the toolbar * Simplify dropdown design --- .../feature-toggles/index.md | 1 + .../src/types/featureToggles.gen.ts | 1 + pkg/services/featuremgmt/registry.go | 8 +++ pkg/services/featuremgmt/toggles_gen.csv | 1 + pkg/services/featuremgmt/toggles_gen.go | 4 ++ pkg/services/featuremgmt/toggles_gen.json | 17 ++++- public/app/features/explore/Explore.test.tsx | 4 +- public/app/features/explore/Explore.tsx | 11 +--- public/app/features/explore/ExploreDrawer.tsx | 7 +- public/app/features/explore/ExplorePage.tsx | 23 ++++--- .../app/features/explore/ExploreToolbar.tsx | 2 + .../QueriesDrawer/QueriesDrawerContext.tsx | 63 ++++++++++++++++++ .../QueriesDrawer/QueriesDrawerDropdown.tsx | 66 +++++++++++++++++++ .../features/explore/QueriesDrawer/mocks.tsx | 30 +++++++++ .../features/explore/QueriesDrawer/utils.ts | 6 ++ .../app/features/explore/QueryRows.test.tsx | 1 - .../explore/RichHistory/RichHistory.test.tsx | 4 +- .../explore/RichHistory/RichHistory.tsx | 23 ++++--- .../RichHistory/RichHistoryContainer.test.tsx | 2 - .../RichHistory/RichHistoryContainer.tsx | 28 +++++--- .../explore/SecondaryActions.test.tsx | 51 ++++++++------ .../app/features/explore/SecondaryActions.tsx | 15 +++-- public/app/features/explore/state/main.ts | 10 --- .../app/features/explore/state/selectors.ts | 4 +- public/app/types/explore.ts | 5 -- public/locales/en-US/grafana.json | 1 + public/locales/pseudo-LOCALE/grafana.json | 1 + 27 files changed, 300 insertions(+), 89 deletions(-) create mode 100644 public/app/features/explore/QueriesDrawer/QueriesDrawerContext.tsx create mode 100644 public/app/features/explore/QueriesDrawer/QueriesDrawerDropdown.tsx create mode 100644 public/app/features/explore/QueriesDrawer/mocks.tsx create mode 100644 public/app/features/explore/QueriesDrawer/utils.ts diff --git a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md index 4a9c62d7e94..9c71a50e4d3 100644 --- a/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md +++ b/docs/sources/setup-grafana/configure-grafana/feature-toggles/index.md @@ -176,6 +176,7 @@ Experimental features might be changed or removed without prior notice. | `expressionParser` | Enable new expression parser | | `accessActionSets` | Introduces action sets for resource permissions | | `disableNumericMetricsSortingInExpressions` | In server-side expressions, disable the sorting of numeric-kind metrics by their metric name or labels. | +| `queryLibrary` | Enables Query Library feature in Explore | ## Development feature toggles diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index ecdc7a62038..7fbc72bfdf3 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -180,4 +180,5 @@ export interface FeatureToggles { accessActionSets?: boolean; disableNumericMetricsSortingInExpressions?: boolean; grafanaManagedRecordingRules?: boolean; + queryLibrary?: boolean; } diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index 81948562368..8f9af951279 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -1211,6 +1211,14 @@ var ( HideFromDocs: true, HideFromAdminPage: true, }, + { + Name: "queryLibrary", + Description: "Enables Query Library feature in Explore", + Stage: FeatureStageExperimental, + Owner: grafanaExploreSquad, + FrontendOnly: false, + AllowSelfServe: false, + }, } ) diff --git a/pkg/services/featuremgmt/toggles_gen.csv b/pkg/services/featuremgmt/toggles_gen.csv index 8527a1865ac..fe1848088b8 100644 --- a/pkg/services/featuremgmt/toggles_gen.csv +++ b/pkg/services/featuremgmt/toggles_gen.csv @@ -161,3 +161,4 @@ cloudWatchNewLabelParsing,GA,@grafana/aws-datasources,false,false,false accessActionSets,experimental,@grafana/identity-access-team,false,false,false disableNumericMetricsSortingInExpressions,experimental,@grafana/observability-metrics,false,true,false grafanaManagedRecordingRules,experimental,@grafana/alerting-squad,false,false,false +queryLibrary,experimental,@grafana/explore-squad,false,false,false diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index d98b2823705..658e9d58dbd 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -654,4 +654,8 @@ const ( // FlagGrafanaManagedRecordingRules // Enables Grafana-managed recording rules. FlagGrafanaManagedRecordingRules = "grafanaManagedRecordingRules" + + // FlagQueryLibrary + // Enables Query Library feature in Explore + FlagQueryLibrary = "queryLibrary" ) diff --git a/pkg/services/featuremgmt/toggles_gen.json b/pkg/services/featuremgmt/toggles_gen.json index 9ee35efc3e3..d72a6888c07 100644 --- a/pkg/services/featuremgmt/toggles_gen.json +++ b/pkg/services/featuremgmt/toggles_gen.json @@ -2088,6 +2088,21 @@ "hideFromAdminPage": true, "hideFromDocs": true } + }, + { + "metadata": { + "name": "queryLibrary", + "resourceVersion": "1713260947272", + "creationTimestamp": "2024-04-16T07:18:28Z", + "annotations": { + "grafana.app/updatedTimestamp": "2024-04-16 09:49:07.272595 +0000 UTC" + } + }, + "spec": { + "description": "Enables Query Library feature in Explore", + "stage": "experimental", + "codeowner": "@grafana/explore-squad" + } } ] -} \ No newline at end of file +} diff --git a/public/app/features/explore/Explore.test.tsx b/public/app/features/explore/Explore.test.tsx index d004eb99473..70de7d816ad 100644 --- a/public/app/features/explore/Explore.test.tsx +++ b/public/app/features/explore/Explore.test.tsx @@ -10,7 +10,7 @@ import { configureStore } from 'app/store/configureStore'; import { ContentOutlineContextProvider } from './ContentOutline/ContentOutlineContext'; import { Explore, Props } from './Explore'; -import { changeShowQueryHistory, initialExploreState } from './state/main'; +import { initialExploreState } from './state/main'; import { scanStopAction } from './state/query'; import { createEmptyQueryResponse, makeExplorePaneState } from './state/utils'; @@ -100,8 +100,6 @@ const dummyProps: Props = { setSupplementaryQueryEnabled: jest.fn(), correlationEditorDetails: undefined, correlationEditorHelperData: undefined, - showQueryHistory: false, - changeShowQueryHistory: changeShowQueryHistory, }; jest.mock('@grafana/runtime/src/services/dataSourceSrv', () => { diff --git a/public/app/features/explore/Explore.tsx b/public/app/features/explore/Explore.tsx index 6726e92a4e3..91313cd2e3f 100644 --- a/public/app/features/explore/Explore.tsx +++ b/public/app/features/explore/Explore.tsx @@ -56,7 +56,7 @@ import { SecondaryActions } from './SecondaryActions'; import TableContainer from './Table/TableContainer'; import { TraceViewContainer } from './TraceView/TraceViewContainer'; import { changeSize } from './state/explorePane'; -import { changeShowQueryHistory, splitOpen } from './state/main'; +import { splitOpen } from './state/main'; import { addQueryRow, modifyQueries, @@ -304,10 +304,6 @@ export class Explore extends React.PureComponent { updateTimeRange({ exploreId, absoluteRange }); }; - toggleShowQueryHistory = () => { - this.props.changeShowQueryHistory(!this.props.showQueryHistory); - }; - onSplitOpen = (panelType: string) => { return async (options?: SplitOpenOptions) => { this.props.splitOpen(options); @@ -535,7 +531,6 @@ export class Explore extends React.PureComponent { showLogsSample, correlationEditorDetails, correlationEditorHelperData, - showQueryHistory, showQueryInspector, setShowQueryInspector, } = this.props; @@ -603,10 +598,8 @@ export class Explore extends React.PureComponent { //TODO:unification addQueryRowButtonHidden={false} richHistoryRowButtonHidden={richHistoryRowButtonHidden} - richHistoryButtonActive={showQueryHistory} queryInspectorButtonActive={showQueryInspector} onClickAddQueryRowButton={this.onClickAddQueryRowButton} - onClickRichHistoryButton={this.toggleShowQueryHistory} onClickQueryInspectorButton={() => setShowQueryInspector(!showQueryInspector)} /> @@ -721,7 +714,6 @@ function mapStateToProps(state: StoreState, { exploreId }: ExploreProps) { showLogsSample, correlationEditorHelperData, correlationEditorDetails: explore.correlationEditorDetails, - showQueryHistory: explore.showQueryHistory, }; } @@ -735,7 +727,6 @@ const mapDispatchToProps = { addQueryRow, splitOpen, setSupplementaryQueryEnabled, - changeShowQueryHistory, }; const connector = connect(mapStateToProps, mapDispatchToProps); diff --git a/public/app/features/explore/ExploreDrawer.tsx b/public/app/features/explore/ExploreDrawer.tsx index 03c595e88a4..af4c41922e4 100644 --- a/public/app/features/explore/ExploreDrawer.tsx +++ b/public/app/features/explore/ExploreDrawer.tsx @@ -10,18 +10,21 @@ import { getDragStyles, useStyles2, useTheme2 } from '@grafana/ui'; export interface Props { children: React.ReactNode; onResize?: ResizeCallback; + initialHeight?: string; } export function ExploreDrawer(props: Props) { - const { children, onResize } = props; + const { children, onResize, initialHeight } = props; const theme = useTheme2(); const styles = useStyles2(getStyles); const dragStyles = getDragStyles(theme); + const height = initialHeight || `${theme.components.horizontalDrawer.defaultHeight}px`; + return ( ) { + return ( + + + + ); +} + +function ExplorePageContent(props: GrafanaRouteComponentProps<{}, ExploreQueryParams>) { const styles = useStyles2(getStyles); const theme = useTheme2(); useTimeSrvFix(); @@ -40,13 +48,12 @@ export default function ExplorePage(props: GrafanaRouteComponentProps<{}, Explor useExplorePageTitle(props.queryParams); const { chrome } = useGrafana(); const navModel = useNavModel('explore'); - const dispatch = useDispatch(); const { updateSplitSize, widthCalc } = useSplitSizeUpdater(MIN_PANE_WIDTH); const panes = useSelector(selectPanesEntries); const hasSplit = useSelector(isSplit); const correlationDetails = useSelector(selectCorrelationDetails); - const showQueryHistory = useSelector(selectShowQueryHistory); + const { drawerOpened, setDrawerOpened, queryLibraryAvailable } = useQueriesDrawerContext(); const showCorrelationEditorBar = config.featureToggles.correlations && (correlationDetails?.editorMode || false); useEffect(() => { @@ -89,11 +96,11 @@ export default function ExplorePage(props: GrafanaRouteComponentProps<{}, Explor ); })} - {showQueryHistory && ( - + {drawerOpened && ( + { - dispatch(changeShowQueryHistory(false)); + setDrawerOpened(false); }} /> diff --git a/public/app/features/explore/ExploreToolbar.tsx b/public/app/features/explore/ExploreToolbar.tsx index f88010d9d6b..b762b57b6f5 100644 --- a/public/app/features/explore/ExploreToolbar.tsx +++ b/public/app/features/explore/ExploreToolbar.tsx @@ -26,6 +26,7 @@ import { getFiscalYearStartMonth, getTimeZone } from '../profile/state/selectors import { ExploreTimeControls } from './ExploreTimeControls'; import { LiveTailButton } from './LiveTailButton'; +import { QueriesDrawerDropdown } from './QueriesDrawer/QueriesDrawerDropdown'; import { ShortLinkButtonMenu } from './ShortLinkButtonMenu'; import { ToolbarExtensionPoint } from './extensions/ToolbarExtensionPoint'; import { changeDatasource } from './state/datasource'; @@ -238,6 +239,7 @@ export function ExploreToolbar({ exploreId, onChangeTime, onContentOutlineToogle forceShowLeftItems > {[ + , !splitted ? ( void; + queryLibraryAvailable: boolean; + drawerOpened: boolean; + setDrawerOpened: (value: boolean) => void; +}; + +export const QueriesDrawerContext = createContext({ + selectedTab: undefined, + setSelectedTab: () => {}, + queryLibraryAvailable: false, + drawerOpened: false, + setDrawerOpened: () => {}, +}); + +export function useQueriesDrawerContext() { + return useContext(QueriesDrawerContext); +} + +export function QueriesDrawerContextProvider({ children }: PropsWithChildren) { + const queryLibraryAvailable = config.featureToggles.queryLibrary === true; + const [selectedTab, setSelectedTab] = useState( + queryLibraryAvailable ? Tabs.QueryLibrary : undefined + ); + const [drawerOpened, setDrawerOpened] = useState(false); + + const settings = useSelector(selectRichHistorySettings); + + useEffect(() => { + if (settings && !queryLibraryAvailable) { + setSelectedTab(settings.starredTabAsFirstTab ? Tabs.Starred : Tabs.RichHistory); + } + }, [settings, setSelectedTab, queryLibraryAvailable]); + + return ( + + {children} + + ); +} diff --git a/public/app/features/explore/QueriesDrawer/QueriesDrawerDropdown.tsx b/public/app/features/explore/QueriesDrawer/QueriesDrawerDropdown.tsx new file mode 100644 index 00000000000..238cfc06da1 --- /dev/null +++ b/public/app/features/explore/QueriesDrawer/QueriesDrawerDropdown.tsx @@ -0,0 +1,66 @@ +import { css } from '@emotion/css'; +import React from 'react'; + +import { Button, ButtonGroup, Dropdown, Menu, ToolbarButton } from '@grafana/ui'; +import { useStyles2 } from '@grafana/ui/'; + +import { Tabs, useQueriesDrawerContext } from './QueriesDrawerContext'; +import { i18n } from './utils'; + +type Props = { + variant: 'compact' | 'full'; +}; + +export function QueriesDrawerDropdown({ variant }: Props) { + const { selectedTab, setSelectedTab, queryLibraryAvailable, drawerOpened, setDrawerOpened } = + useQueriesDrawerContext(); + + const styles = useStyles2(getStyles); + + if (!queryLibraryAvailable) { + return undefined; + } + + function toggle(tab: Tabs) { + setSelectedTab(tab); + setDrawerOpened(false); + setDrawerOpened(true); + } + + const menu = ( + + toggle(Tabs.QueryLibrary)} /> + toggle(Tabs.RichHistory)} /> + + ); + + return ( + + setDrawerOpened(!drawerOpened)} + > + {variant === 'full' ? selectedTab : undefined} + + {drawerOpened ? ( + + ) : ( + + + + )} + + ); +} + +const getStyles = () => ({ + toggle: css({ width: '36px' }), + // tweaking icon position so it's nicely aligned when dropdown turns into a close button + close: css({ width: '36px', '> svg': { position: 'relative', left: 2 } }), +}); diff --git a/public/app/features/explore/QueriesDrawer/mocks.tsx b/public/app/features/explore/QueriesDrawer/mocks.tsx new file mode 100644 index 00000000000..ed9d5ceb590 --- /dev/null +++ b/public/app/features/explore/QueriesDrawer/mocks.tsx @@ -0,0 +1,30 @@ +import React, { PropsWithChildren, useState } from 'react'; + +import { QueriesDrawerContext, Tabs } from './QueriesDrawerContext'; + +type Props = { + setDrawerOpened?: (value: boolean) => {}; + queryLibraryAvailable?: boolean; +} & PropsWithChildren; + +export function QueriesDrawerContextProviderMock(props: Props) { + const [selectedTab, setSelectedTab] = useState(Tabs.QueryLibrary); + const [drawerOpened, setDrawerOpened] = useState(false); + + return ( + { + props.setDrawerOpened?.(value); + setDrawerOpened(value); + }, + }} + > + {props.children} + + ); +} diff --git a/public/app/features/explore/QueriesDrawer/utils.ts b/public/app/features/explore/QueriesDrawer/utils.ts new file mode 100644 index 00000000000..fa77d88fe13 --- /dev/null +++ b/public/app/features/explore/QueriesDrawer/utils.ts @@ -0,0 +1,6 @@ +import { t } from 'app//core/internationalization'; + +export const i18n = { + queryLibrary: t('explore.rich-history.query-library', 'Query library'), + queryHistory: t('explore.rich-history.query-history', 'Query history'), +}; diff --git a/public/app/features/explore/QueryRows.test.tsx b/public/app/features/explore/QueryRows.test.tsx index 07e6d5881d2..a65ebe6c18a 100644 --- a/public/app/features/explore/QueryRows.test.tsx +++ b/public/app/features/explore/QueryRows.test.tsx @@ -52,7 +52,6 @@ function setup(queries: DataQuery[]) { const leftState = makeExplorePaneState(); const initialState: ExploreState = { richHistory: [], - showQueryHistory: false, panes: { left: { ...leftState, diff --git a/public/app/features/explore/RichHistory/RichHistory.test.tsx b/public/app/features/explore/RichHistory/RichHistory.test.tsx index 35987fa1773..ff53cbd57f4 100644 --- a/public/app/features/explore/RichHistory/RichHistory.test.tsx +++ b/public/app/features/explore/RichHistory/RichHistory.test.tsx @@ -4,7 +4,9 @@ import { TestProvider } from 'test/helpers/TestProvider'; import { SortOrder } from 'app/core/utils/richHistory'; -import { RichHistory, RichHistoryProps, Tabs } from './RichHistory'; +import { Tabs } from '../QueriesDrawer/QueriesDrawerContext'; + +import { RichHistory, RichHistoryProps } from './RichHistory'; jest.mock('../state/selectors', () => ({ selectExploreDSMaps: jest.fn().mockReturnValue({ dsToExplore: [] }) })); diff --git a/public/app/features/explore/RichHistory/RichHistory.tsx b/public/app/features/explore/RichHistory/RichHistory.tsx index fc0158b6220..8382edc323b 100644 --- a/public/app/features/explore/RichHistory/RichHistory.tsx +++ b/public/app/features/explore/RichHistory/RichHistory.tsx @@ -3,23 +3,19 @@ import React, { useState, useEffect } from 'react'; import { SelectableValue } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; -import { TabbedContainer, TabConfig } from '@grafana/ui'; +import { EmptyState, TabbedContainer, TabConfig } from '@grafana/ui'; import { t } from 'app/core/internationalization'; import { SortOrder, RichHistorySearchFilters, RichHistorySettings } from 'app/core/utils/richHistory'; import { RichHistoryQuery } from 'app/types/explore'; import { supportedFeatures } from '../../../core/history/richHistoryStorageProvider'; +import { Tabs, useQueriesDrawerContext } from '../QueriesDrawer/QueriesDrawerContext'; +import { i18n } from '../QueriesDrawer/utils'; import { RichHistoryQueriesTab } from './RichHistoryQueriesTab'; import { RichHistorySettingsTab } from './RichHistorySettingsTab'; import { RichHistoryStarredTab } from './RichHistoryStarredTab'; -export enum Tabs { - RichHistory = 'Query history', - Starred = 'Starred', - Settings = 'Settings', -} - export const getSortOrderOptions = () => [ { label: t('explore.rich-history.newest-first', 'Newest first'), value: SortOrder.Descending }, @@ -49,6 +45,8 @@ export function RichHistory(props: RichHistoryProps) { const [loading, setLoading] = useState(false); + const { queryLibraryAvailable } = useQueriesDrawerContext(); + const updateSettings = (settingsToUpdate: Partial) => { props.updateHistorySettings({ ...props.richHistorySettings, ...settingsToUpdate }); }; @@ -84,8 +82,15 @@ export function RichHistory(props: RichHistoryProps) { setLoading(false); }, [richHistory]); + const QueryLibraryTab: TabConfig = { + label: i18n.queryLibrary, + value: Tabs.QueryLibrary, + content: , + icon: 'book', + }; + const QueriesTab: TabConfig = { - label: t('explore.rich-history.query-history', 'Query history'), + label: i18n.queryHistory, value: Tabs.RichHistory, content: ( ({ @@ -27,7 +26,6 @@ jest.mock('../state/selectors', () => ({ selectExploreDSMaps: jest.fn().mockRetu const setup = (propOverrides?: Partial) => { const props: Props = { richHistory: [], - firstTab: Tabs.RichHistory, deleteRichHistory: jest.fn(), initRichHistory: jest.fn(), loadRichHistory: jest.fn(), diff --git a/public/app/features/explore/RichHistory/RichHistoryContainer.tsx b/public/app/features/explore/RichHistory/RichHistoryContainer.tsx index acaf618b636..ed14ac0b352 100644 --- a/public/app/features/explore/RichHistory/RichHistoryContainer.tsx +++ b/public/app/features/explore/RichHistory/RichHistoryContainer.tsx @@ -1,5 +1,5 @@ // Libraries -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; import { connect, ConnectedProps } from 'react-redux'; import { config, reportInteraction } from '@grafana/runtime'; @@ -9,6 +9,7 @@ import { Trans } from 'app/core/internationalization'; import { StoreState } from 'app/types'; // Components, enums +import { useQueriesDrawerContext } from '../QueriesDrawer/QueriesDrawerContext'; import { deleteRichHistory, initRichHistory, @@ -19,7 +20,7 @@ import { updateHistorySearchFilters, } from '../state/history'; -import { RichHistory, Tabs } from './RichHistory'; +import { RichHistory } from './RichHistory'; //Actions @@ -28,11 +29,9 @@ function mapStateToProps(state: StoreState) { const richHistorySearchFilters = explore.richHistorySearchFilters; const { richHistorySettings, richHistory, richHistoryTotal } = explore; - const firstTab = richHistorySettings?.starredTabAsFirstTab ? Tabs.Starred : Tabs.RichHistory; return { richHistory, richHistoryTotal, - firstTab, richHistorySettings, richHistorySearchFilters, }; @@ -61,7 +60,6 @@ export function RichHistoryContainer(props: Props) { const { richHistory, richHistoryTotal, - firstTab, deleteRichHistory, initRichHistory, loadRichHistory, @@ -76,12 +74,22 @@ export function RichHistoryContainer(props: Props) { useEffect(() => { initRichHistory(); - reportInteraction('grafana_explore_query_history_opened', { - queryHistoryEnabled: config.queryHistoryEnabled, - }); }, [initRichHistory]); - if (!richHistorySettings) { + const { selectedTab } = useQueriesDrawerContext(); + const [tracked, setTracked] = useState(false); + + useEffect(() => { + if (!tracked) { + setTracked(true); + reportInteraction('grafana_explore_query_history_opened', { + queryHistoryEnabled: config.queryHistoryEnabled, + selectedTab, + }); + } + }, [tracked, selectedTab]); + + if (!richHistorySettings || !selectedTab) { return ( Loading... @@ -93,7 +101,7 @@ export function RichHistoryContainer(props: Props) { { it('should render component with three buttons', () => { - render( - - ); + render(); expect(screen.getByRole('button', { name: /Add query/i })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /Query history/i })).toBeInTheDocument(); @@ -22,13 +17,14 @@ describe('SecondaryActions', () => { it('should not render hidden elements', () => { render( - + + + ); expect(screen.queryByRole('button', { name: /Add query/i })).not.toBeInTheDocument(); @@ -36,12 +32,25 @@ describe('SecondaryActions', () => { expect(screen.getByRole('button', { name: /Query inspector/i })).toBeInTheDocument(); }); + it('should not render query history button when query library is available', () => { + render( + + + + ); + + expect(screen.queryByRole('button', { name: /Query history/i })).not.toBeInTheDocument(); + }); + it('should disable add row button if addQueryRowButtonDisabled=true', () => { render( ); @@ -59,11 +68,12 @@ describe('SecondaryActions', () => { const onClickQueryInspector = jest.fn(); render( - + + + ); await user.click(screen.getByRole('button', { name: /Add query/i })); @@ -71,6 +81,7 @@ describe('SecondaryActions', () => { await user.click(screen.getByRole('button', { name: /Query history/i })); expect(onClickHistory).toBeCalledTimes(1); + expect(onClickHistory).toBeCalledWith(true); await user.click(screen.getByRole('button', { name: /Query inspector/i })); expect(onClickQueryInspector).toBeCalledTimes(1); diff --git a/public/app/features/explore/SecondaryActions.tsx b/public/app/features/explore/SecondaryActions.tsx index d5c29d43e2e..cdba3e51854 100644 --- a/public/app/features/explore/SecondaryActions.tsx +++ b/public/app/features/explore/SecondaryActions.tsx @@ -6,15 +6,15 @@ import { Components } from '@grafana/e2e-selectors'; import { ToolbarButton, useTheme2 } from '@grafana/ui'; import { t, Trans } from 'app/core/internationalization'; +import { useQueriesDrawerContext } from './QueriesDrawer/QueriesDrawerContext'; + type Props = { addQueryRowButtonDisabled?: boolean; addQueryRowButtonHidden?: boolean; richHistoryRowButtonHidden?: boolean; - richHistoryButtonActive?: boolean; queryInspectorButtonActive?: boolean; onClickAddQueryRowButton: () => void; - onClickRichHistoryButton: () => void; onClickQueryInspectorButton: () => void; }; @@ -32,6 +32,11 @@ const getStyles = (theme: GrafanaTheme2) => { export function SecondaryActions(props: Props) { const theme = useTheme2(); const styles = getStyles(theme); + const { drawerOpened, setDrawerOpened, queryLibraryAvailable } = useQueriesDrawerContext(); + + // When queryLibraryAvailable=true we show the button in the toolbar (see QueriesDrawerDropdown) + const showHistoryButton = !props.richHistoryRowButtonHidden && !queryLibraryAvailable; + return (
{!props.addQueryRowButtonHidden && ( @@ -45,11 +50,11 @@ export function SecondaryActions(props: Props) { Add query )} - {!props.richHistoryRowButtonHidden && ( + {showHistoryButton && ( setDrawerOpened(!drawerOpened)} data-testid={Components.QueryTab.queryHistoryButton} icon="history" > diff --git a/public/app/features/explore/state/main.ts b/public/app/features/explore/state/main.ts index 07c234fa634..2f453f17c25 100644 --- a/public/app/features/explore/state/main.ts +++ b/public/app/features/explore/state/main.ts @@ -124,8 +124,6 @@ export const changeCorrelationEditorDetails = createAction('explore/changeShowQueryHistory'); - export interface NavigateToExploreDependencies { timeRange: TimeRange; getExploreUrl: (args: GetExploreUrlArguments) => Promise; @@ -169,7 +167,6 @@ export const initialExploreState: ExploreState = { largerExploreId: undefined, maxedExploreId: undefined, evenSplitPanes: true, - showQueryHistory: false, richHistory: [], }; @@ -323,13 +320,6 @@ export const exploreReducer = (state = initialExploreState, action: AnyAction): }; } - if (changeShowQueryHistory.match(action)) { - return { - ...state, - showQueryHistory: action.payload, - }; - } - const exploreId: string | undefined = action.payload?.exploreId; if (typeof exploreId === 'string') { return { diff --git a/public/app/features/explore/state/selectors.ts b/public/app/features/explore/state/selectors.ts index a475e8b5b04..9f5ea7f86df 100644 --- a/public/app/features/explore/state/selectors.ts +++ b/public/app/features/explore/state/selectors.ts @@ -7,6 +7,8 @@ import { ExploreItemState, StoreState } from 'app/types'; export const selectPanes = (state: Pick) => state.explore.panes; export const selectExploreRoot = (state: Pick) => state.explore; +export const selectRichHistorySettings = (state: Pick) => state.explore.richHistorySettings; + export const selectPanesEntries = createSelector< [(state: Pick) => Record], Array<[string, ExploreItemState]> @@ -26,8 +28,6 @@ export const getExploreItemSelector = (exploreId: string) => createSelector(sele export const selectCorrelationDetails = createSelector(selectExploreRoot, (state) => state.correlationEditorDetails); -export const selectShowQueryHistory = createSelector(selectExploreRoot, (state) => state.showQueryHistory); - export const selectExploreDSMaps = createSelector(selectPanesEntries, (panes) => { const exploreDSMap = panes .map(([exploreId, pane]) => { diff --git a/public/app/types/explore.ts b/public/app/types/explore.ts index 3f91e26c6d4..865d656e3dc 100644 --- a/public/app/types/explore.ts +++ b/public/app/types/explore.ts @@ -63,11 +63,6 @@ export interface ExploreState { panes: Record; - /** - * Is the drawer for query history showing - */ - showQueryHistory: boolean; - /** * History of all queries */ diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index bc911111504..b14cc1fe96e 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -472,6 +472,7 @@ "newest-first": "Newest first", "oldest-first": "Oldest first", "query-history": "Query history", + "query-library": "Query library", "settings": "Settings", "starred": "Starred" }, diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index 64daa25d135..65abad5652f 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -472,6 +472,7 @@ "newest-first": "Ńęŵęşŧ ƒįřşŧ", "oldest-first": "Øľđęşŧ ƒįřşŧ", "query-history": "Qūęřy ĥįşŧőřy", + "query-library": "Qūęřy ľįþřäřy", "settings": "Ŝęŧŧįʼnģş", "starred": "Ŝŧäřřęđ" },