mirror of https://github.com/grafana/grafana
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 designpull/86812/head
parent
de589b98c7
commit
f6e472f879
|
@ -0,0 +1,63 @@ |
||||
import React, { PropsWithChildren, useState, createContext, useContext, useEffect } from 'react'; |
||||
|
||||
import { config } from '@grafana/runtime'; |
||||
import { useSelector } from 'app/types'; |
||||
|
||||
import { selectRichHistorySettings } from '../state/selectors'; |
||||
|
||||
export enum Tabs { |
||||
QueryLibrary = 'Query library', |
||||
RichHistory = 'Query history', |
||||
Starred = 'Starred', |
||||
Settings = 'Settings', |
||||
} |
||||
|
||||
type QueryLibraryContextType = { |
||||
selectedTab?: Tabs; |
||||
setSelectedTab: (tab: Tabs) => void; |
||||
queryLibraryAvailable: boolean; |
||||
drawerOpened: boolean; |
||||
setDrawerOpened: (value: boolean) => void; |
||||
}; |
||||
|
||||
export const QueriesDrawerContext = createContext<QueryLibraryContextType>({ |
||||
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<Tabs | undefined>( |
||||
queryLibraryAvailable ? Tabs.QueryLibrary : undefined |
||||
); |
||||
const [drawerOpened, setDrawerOpened] = useState<boolean>(false); |
||||
|
||||
const settings = useSelector(selectRichHistorySettings); |
||||
|
||||
useEffect(() => { |
||||
if (settings && !queryLibraryAvailable) { |
||||
setSelectedTab(settings.starredTabAsFirstTab ? Tabs.Starred : Tabs.RichHistory); |
||||
} |
||||
}, [settings, setSelectedTab, queryLibraryAvailable]); |
||||
|
||||
return ( |
||||
<QueriesDrawerContext.Provider |
||||
value={{ |
||||
queryLibraryAvailable, |
||||
selectedTab, |
||||
setSelectedTab, |
||||
drawerOpened, |
||||
setDrawerOpened, |
||||
}} |
||||
> |
||||
{children} |
||||
</QueriesDrawerContext.Provider> |
||||
); |
||||
} |
@ -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 = ( |
||||
<Menu> |
||||
<Menu.Item label={i18n.queryLibrary} onClick={() => toggle(Tabs.QueryLibrary)} /> |
||||
<Menu.Item label={i18n.queryHistory} onClick={() => toggle(Tabs.RichHistory)} /> |
||||
</Menu> |
||||
); |
||||
|
||||
return ( |
||||
<ButtonGroup> |
||||
<ToolbarButton |
||||
icon="book" |
||||
variant={drawerOpened ? 'active' : 'canvas'} |
||||
onClick={() => setDrawerOpened(!drawerOpened)} |
||||
> |
||||
{variant === 'full' ? selectedTab : undefined} |
||||
</ToolbarButton> |
||||
{drawerOpened ? ( |
||||
<Button |
||||
className={styles.close} |
||||
variant="secondary" |
||||
icon="times" |
||||
onClick={() => setDrawerOpened(false)} |
||||
></Button> |
||||
) : ( |
||||
<Dropdown overlay={menu}> |
||||
<ToolbarButton className={styles.toggle} variant="canvas" icon="angle-down" /> |
||||
</Dropdown> |
||||
)} |
||||
</ButtonGroup> |
||||
); |
||||
} |
||||
|
||||
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 } }), |
||||
}); |
@ -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>(Tabs.QueryLibrary); |
||||
const [drawerOpened, setDrawerOpened] = useState<boolean>(false); |
||||
|
||||
return ( |
||||
<QueriesDrawerContext.Provider |
||||
value={{ |
||||
queryLibraryAvailable: props.queryLibraryAvailable || false, |
||||
selectedTab, |
||||
setSelectedTab, |
||||
drawerOpened, |
||||
setDrawerOpened: (value) => { |
||||
props.setDrawerOpened?.(value); |
||||
setDrawerOpened(value); |
||||
}, |
||||
}} |
||||
> |
||||
{props.children} |
||||
</QueriesDrawerContext.Provider> |
||||
); |
||||
} |
@ -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'), |
||||
}; |
Loading…
Reference in new issue