mirror of
https://github.com/grafana/grafana.git
synced 2025-01-02 12:17:01 -06:00
Make content outline visible and in expanded mode by default (#90283)
* Make content outline visible and in expanded mode by default * Clean up unused args * Save content outline visibility in local storage * Add test * Expanded state relies on local storage;
This commit is contained in:
parent
6ff21726b7
commit
51afb2e484
@ -1,6 +1,8 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { store } from '@grafana/data';
|
||||
|
||||
import { ContentOutline } from './ContentOutline';
|
||||
|
||||
jest.mock('./ContentOutlineContext', () => ({
|
||||
@ -73,15 +75,15 @@ const setup = (mergeSingleChild = false) => {
|
||||
describe('<ContentOutline />', () => {
|
||||
it('toggles content on button click', async () => {
|
||||
setup();
|
||||
let showContentOutlineButton = screen.getByRole('button', { name: 'Expand outline' });
|
||||
let showContentOutlineButton = screen.getByRole('button', { name: 'Collapse outline' });
|
||||
expect(showContentOutlineButton).toBeInTheDocument();
|
||||
|
||||
await userEvent.click(showContentOutlineButton);
|
||||
const hideContentOutlineButton = screen.getByRole('button', { name: 'Collapse outline' });
|
||||
const hideContentOutlineButton = screen.getByRole('button', { name: 'Expand outline' });
|
||||
expect(hideContentOutlineButton).toBeInTheDocument();
|
||||
|
||||
await userEvent.click(hideContentOutlineButton);
|
||||
showContentOutlineButton = screen.getByRole('button', { name: 'Expand outline' });
|
||||
showContentOutlineButton = screen.getByRole('button', { name: 'Collapse outline' });
|
||||
expect(showContentOutlineButton).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@ -157,4 +159,15 @@ describe('<ContentOutline />', () => {
|
||||
|
||||
expect(unregisterMock).toHaveBeenCalledWith('item-2-1');
|
||||
});
|
||||
|
||||
it('should retrieve the last expanded state from local storage', async () => {
|
||||
const getBoolMock = jest.spyOn(store, 'getBool').mockReturnValue(false);
|
||||
setup();
|
||||
const collapseContentOutlineButton = screen.queryByRole('button', { name: 'Collapse outline' });
|
||||
const expandContentOutlineButton = screen.queryByRole('button', { name: 'Expand outline' });
|
||||
expect(collapseContentOutlineButton).not.toBeInTheDocument();
|
||||
expect(expandContentOutlineButton).toBeInTheDocument();
|
||||
|
||||
getBoolMock.mockRestore();
|
||||
});
|
||||
});
|
||||
|
@ -2,12 +2,11 @@ import { css, cx } from '@emotion/css';
|
||||
import { Fragment, useEffect, useRef, useState } from 'react';
|
||||
import { useToggle, useScroll } from 'react-use';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { GrafanaTheme2, store } from '@grafana/data';
|
||||
import { reportInteraction } from '@grafana/runtime';
|
||||
import { useStyles2, PanelContainer, CustomScrollbar } from '@grafana/ui';
|
||||
|
||||
import { ContentOutlineItemContextProps, useContentOutlineContext } from './ContentOutlineContext';
|
||||
import { ITEM_TYPES } from './ContentOutlineItem';
|
||||
import { ContentOutlineItemButton } from './ContentOutlineItemButton';
|
||||
|
||||
function scrollableChildren(item: ContentOutlineItemContextProps) {
|
||||
@ -35,8 +34,15 @@ function shouldBeActive(
|
||||
}
|
||||
}
|
||||
|
||||
export const CONTENT_OUTLINE_LOCAL_STORAGE_KEYS = {
|
||||
visible: 'grafana.explore.contentOutline.visible',
|
||||
expanded: 'grafana.explore.contentOutline.expanded',
|
||||
};
|
||||
|
||||
export function ContentOutline({ scroller, panelId }: { scroller: HTMLElement | undefined; panelId: string }) {
|
||||
const [contentOutlineExpanded, toggleContentOutlineExpanded] = useToggle(false);
|
||||
const [contentOutlineExpanded, toggleContentOutlineExpanded] = useToggle(
|
||||
store.getBool(CONTENT_OUTLINE_LOCAL_STORAGE_KEYS.expanded, true)
|
||||
);
|
||||
const styles = useStyles2(getStyles, contentOutlineExpanded);
|
||||
const scrollerRef = useRef(scroller || null);
|
||||
const { y: verticalScroll } = useScroll(scrollerRef);
|
||||
@ -57,12 +63,7 @@ export function ContentOutline({ scroller, panelId }: { scroller: HTMLElement |
|
||||
}, {});
|
||||
});
|
||||
|
||||
const scrollIntoView = (
|
||||
ref: HTMLElement | null,
|
||||
itemPanelId: string,
|
||||
itemType: ITEM_TYPES | undefined,
|
||||
customOffsetTop = 0
|
||||
) => {
|
||||
const scrollIntoView = (ref: HTMLElement | null, customOffsetTop = 0) => {
|
||||
let scrollValue = 0;
|
||||
let el: HTMLElement | null | undefined = ref;
|
||||
|
||||
@ -88,10 +89,10 @@ export function ContentOutline({ scroller, panelId }: { scroller: HTMLElement |
|
||||
});
|
||||
|
||||
if (activeParent) {
|
||||
scrollIntoView(activeParent.ref, activeParent.panelId, activeParent.type, activeParent.customTopOffset);
|
||||
scrollIntoView(activeParent.ref, activeParent.customTopOffset);
|
||||
}
|
||||
} else {
|
||||
scrollIntoView(item.ref, item.panelId, item.type, item.customTopOffset);
|
||||
scrollIntoView(item.ref, item.customTopOffset);
|
||||
reportInteraction('explore_toolbar_contentoutline_clicked', {
|
||||
item: 'select_section',
|
||||
type: item.panelId,
|
||||
@ -100,6 +101,7 @@ export function ContentOutline({ scroller, panelId }: { scroller: HTMLElement |
|
||||
};
|
||||
|
||||
const toggle = () => {
|
||||
store.set(CONTENT_OUTLINE_LOCAL_STORAGE_KEYS.expanded, !contentOutlineExpanded);
|
||||
toggleContentOutlineExpanded();
|
||||
reportInteraction('explore_toolbar_contentoutline_clicked', {
|
||||
item: 'outline',
|
||||
|
@ -2,7 +2,15 @@ import { render, screen } from '@testing-library/react';
|
||||
import { Props as AutoSizerProps } from 'react-virtualized-auto-sizer';
|
||||
import { TestProvider } from 'test/helpers/TestProvider';
|
||||
|
||||
import { CoreApp, createTheme, DataSourceApi, EventBusSrv, LoadingState, PluginExtensionTypes } from '@grafana/data';
|
||||
import {
|
||||
CoreApp,
|
||||
createTheme,
|
||||
DataSourceApi,
|
||||
EventBusSrv,
|
||||
LoadingState,
|
||||
PluginExtensionTypes,
|
||||
store,
|
||||
} from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { usePluginLinkExtensions } from '@grafana/runtime';
|
||||
import { configureStore } from 'app/store/configureStore';
|
||||
@ -225,4 +233,14 @@ describe('Explore', () => {
|
||||
expect(dataSourcePicker).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Content Outline', () => {
|
||||
it('should retrieve the last visible state from local storage', async () => {
|
||||
const getBoolMock = jest.spyOn(store, 'getBool').mockReturnValue(false);
|
||||
setup();
|
||||
const showContentOutlineButton = screen.queryByRole('button', { name: 'Collapse outline' });
|
||||
expect(showContentOutlineButton).not.toBeInTheDocument();
|
||||
getBoolMock.mockRestore();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -14,6 +14,7 @@ import {
|
||||
QueryFixAction,
|
||||
RawTimeRange,
|
||||
SplitOpenOptions,
|
||||
store,
|
||||
SupplementaryQueryType,
|
||||
} from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
@ -34,7 +35,7 @@ import { StoreState } from 'app/types';
|
||||
|
||||
import { getTimeZone } from '../profile/state/selectors';
|
||||
|
||||
import { ContentOutline } from './ContentOutline/ContentOutline';
|
||||
import { CONTENT_OUTLINE_LOCAL_STORAGE_KEYS, ContentOutline } from './ContentOutline/ContentOutline';
|
||||
import { ContentOutlineContextProvider } from './ContentOutline/ContentOutlineContext';
|
||||
import { ContentOutlineItem } from './ContentOutline/ContentOutlineItem';
|
||||
import { CorrelationHelper } from './CorrelationHelper';
|
||||
@ -147,7 +148,7 @@ export class Explore extends PureComponent<Props, ExploreState> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
contentOutlineVisible: false,
|
||||
contentOutlineVisible: store.getBool(CONTENT_OUTLINE_LOCAL_STORAGE_KEYS.visible, true),
|
||||
};
|
||||
this.graphEventBus = props.eventBus.newScopedBus('graph', { onlyLocal: false });
|
||||
this.logsEventBus = props.eventBus.newScopedBus('logs', { onlyLocal: false });
|
||||
@ -175,6 +176,7 @@ export class Explore extends PureComponent<Props, ExploreState> {
|
||||
};
|
||||
|
||||
onContentOutlineToogle = () => {
|
||||
store.set(CONTENT_OUTLINE_LOCAL_STORAGE_KEYS.visible, !this.state.contentOutlineVisible);
|
||||
this.setState((state) => {
|
||||
reportInteraction('explore_toolbar_contentoutline_clicked', {
|
||||
item: 'outline',
|
||||
|
Loading…
Reference in New Issue
Block a user