mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[OneDiscover][DocViewer] Remember the last active tab (#189806)
- Closes https://github.com/elastic/kibana/issues/188717 ## Summary With this PR the last active DocViewer tab is going to be stored in local storage under `unifiedDocViewer:initialTab` and restored when opening the flyout next time. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
parent
a2b365168e
commit
36d0ae7121
4 changed files with 96 additions and 7 deletions
|
@ -7,6 +7,7 @@ exports[`<DocViewer /> Render <DocViewer/> with 3 different tabs 1`] = `
|
|||
>
|
||||
<EuiTabbedContent
|
||||
autoFocus="initial"
|
||||
onTabClick={[Function]}
|
||||
size="s"
|
||||
tabs={
|
||||
Array [
|
||||
|
|
|
@ -8,11 +8,28 @@
|
|||
|
||||
import React from 'react';
|
||||
import { mount, shallow } from 'enzyme';
|
||||
import { DocViewer } from './doc_viewer';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { findTestSubject } from '@elastic/eui/lib/test';
|
||||
import type { DocViewRenderProps } from '../../types';
|
||||
import { buildDataTableRecord } from '@kbn/discover-utils';
|
||||
import { DocViewer, INITIAL_TAB } from './doc_viewer';
|
||||
import type { DocViewRenderProps } from '../../types';
|
||||
import { DocViewsRegistry } from '../..';
|
||||
import { dataViewMock, esHitsMockWithSort } from '@kbn/discover-utils/src/__mocks__';
|
||||
|
||||
const records = esHitsMockWithSort.map((hit) => buildDataTableRecord(hit, dataViewMock));
|
||||
|
||||
const mockSetLocalStorage = jest.fn();
|
||||
const mockLocalStorageKey = INITIAL_TAB;
|
||||
let mockTestInitialLocalStorageValue: string | undefined;
|
||||
|
||||
jest.mock('react-use/lib/useLocalStorage', () => {
|
||||
return jest.fn((key: string, initialValue: number) => {
|
||||
if (key !== mockLocalStorageKey) {
|
||||
throw new Error(`Unexpected key: ${key}`);
|
||||
}
|
||||
return [mockTestInitialLocalStorageValue ?? initialValue, mockSetLocalStorage];
|
||||
});
|
||||
});
|
||||
|
||||
describe('<DocViewer />', () => {
|
||||
test('Render <DocViewer/> with 3 different tabs', () => {
|
||||
|
@ -59,4 +76,57 @@ describe('<DocViewer />', () => {
|
|||
const errorMsgComponent = findTestSubject(wrapper, 'docViewerError');
|
||||
expect(errorMsgComponent.text()).toMatch(new RegExp(`${errorMsg}`));
|
||||
});
|
||||
|
||||
test('should save active tab to local storage', () => {
|
||||
const registry = new DocViewsRegistry();
|
||||
registry.add({ id: 'test1', order: 10, title: 'Render function', render: jest.fn() });
|
||||
registry.add({ id: 'test2', order: 20, title: 'Render function', render: jest.fn() });
|
||||
|
||||
render(<DocViewer docViews={registry.getAll()} hit={records[0]} dataView={dataViewMock} />);
|
||||
|
||||
expect(screen.getByTestId('docViewerTab-test1').getAttribute('aria-selected')).toBe('true');
|
||||
expect(screen.getByTestId('docViewerTab-test2').getAttribute('aria-selected')).toBe('false');
|
||||
|
||||
screen.getByTestId('docViewerTab-test2').click();
|
||||
|
||||
expect(screen.getByTestId('docViewerTab-test1').getAttribute('aria-selected')).toBe('false');
|
||||
expect(screen.getByTestId('docViewerTab-test2').getAttribute('aria-selected')).toBe('true');
|
||||
expect(mockSetLocalStorage).toHaveBeenCalledWith('kbn_doc_viewer_tab_test2');
|
||||
|
||||
screen.getByTestId('docViewerTab-test1').click();
|
||||
|
||||
expect(screen.getByTestId('docViewerTab-test1').getAttribute('aria-selected')).toBe('true');
|
||||
expect(screen.getByTestId('docViewerTab-test2').getAttribute('aria-selected')).toBe('false');
|
||||
expect(mockSetLocalStorage).toHaveBeenCalledWith('kbn_doc_viewer_tab_test1');
|
||||
});
|
||||
|
||||
test('should restore active tab from local storage', () => {
|
||||
const registry = new DocViewsRegistry();
|
||||
registry.add({ id: 'test1', order: 10, title: 'Render function', render: jest.fn() });
|
||||
registry.add({ id: 'test2', order: 20, title: 'Render function', render: jest.fn() });
|
||||
|
||||
mockTestInitialLocalStorageValue = 'kbn_doc_viewer_tab_test2';
|
||||
|
||||
render(<DocViewer docViews={registry.getAll()} hit={records[0]} dataView={dataViewMock} />);
|
||||
|
||||
expect(screen.getByTestId('docViewerTab-test1').getAttribute('aria-selected')).toBe('false');
|
||||
expect(screen.getByTestId('docViewerTab-test2').getAttribute('aria-selected')).toBe('true');
|
||||
|
||||
mockTestInitialLocalStorageValue = undefined;
|
||||
});
|
||||
|
||||
test('should not restore a tab from local storage if unavailable', () => {
|
||||
const registry = new DocViewsRegistry();
|
||||
registry.add({ id: 'test1', order: 10, title: 'Render function', render: jest.fn() });
|
||||
registry.add({ id: 'test2', order: 20, title: 'Render function', render: jest.fn() });
|
||||
|
||||
mockTestInitialLocalStorageValue = 'kbn_doc_viewer_tab_test3';
|
||||
|
||||
render(<DocViewer docViews={registry.getAll()} hit={records[0]} dataView={dataViewMock} />);
|
||||
|
||||
expect(screen.getByTestId('docViewerTab-test1').getAttribute('aria-selected')).toBe('true');
|
||||
expect(screen.getByTestId('docViewerTab-test2').getAttribute('aria-selected')).toBe('false');
|
||||
|
||||
mockTestInitialLocalStorageValue = undefined;
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,11 +6,14 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiTabbedContent } from '@elastic/eui';
|
||||
import React, { useCallback } from 'react';
|
||||
import { EuiTabbedContent, EuiTabbedContentTab } from '@elastic/eui';
|
||||
import useLocalStorage from 'react-use/lib/useLocalStorage';
|
||||
import { DocViewerTab } from './doc_viewer_tab';
|
||||
import type { DocView, DocViewRenderProps } from '../../types';
|
||||
|
||||
export const INITIAL_TAB = 'unifiedDocViewer:initialTab';
|
||||
|
||||
export interface DocViewerProps extends DocViewRenderProps {
|
||||
docViews: DocView[];
|
||||
}
|
||||
|
@ -26,7 +29,7 @@ export function DocViewer({ docViews, ...renderProps }: DocViewerProps) {
|
|||
.filter(({ enabled }) => enabled) // Filter out disabled doc views
|
||||
.map(({ id, title, render, component }: DocView) => {
|
||||
return {
|
||||
id: `kbn_doc_viewer_tab_${id}`,
|
||||
id: `kbn_doc_viewer_tab_${id}`, // `id` value is used to persist the selected tab in localStorage
|
||||
name: title,
|
||||
content: (
|
||||
<DocViewerTab
|
||||
|
@ -41,6 +44,16 @@ export function DocViewer({ docViews, ...renderProps }: DocViewerProps) {
|
|||
};
|
||||
});
|
||||
|
||||
const [initialTabId, setInitialTabId] = useLocalStorage<string>(INITIAL_TAB);
|
||||
const initialSelectedTab = initialTabId ? tabs.find(({ id }) => id === initialTabId) : undefined;
|
||||
|
||||
const onTabClick = useCallback(
|
||||
(tab: EuiTabbedContentTab) => {
|
||||
setInitialTabId(tab.id);
|
||||
},
|
||||
[setInitialTabId]
|
||||
);
|
||||
|
||||
if (!tabs.length) {
|
||||
// There's a minimum of 2 tabs active in Discover.
|
||||
// This condition takes care of unit tests with 0 tabs.
|
||||
|
@ -49,7 +62,12 @@ export function DocViewer({ docViews, ...renderProps }: DocViewerProps) {
|
|||
|
||||
return (
|
||||
<div className="kbnDocViewer" data-test-subj="kbnDocViewer">
|
||||
<EuiTabbedContent size="s" tabs={tabs} />
|
||||
<EuiTabbedContent
|
||||
size="s"
|
||||
tabs={tabs}
|
||||
initialSelectedTab={initialSelectedTab}
|
||||
onTabClick={onTabClick}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ const DEFAULT_PAGE_SIZE = 25;
|
|||
const PINNED_FIELDS_KEY = 'discover:pinnedFields';
|
||||
const PAGE_SIZE = 'discover:pageSize';
|
||||
const SEARCH_TEXT = 'discover:searchText';
|
||||
const HIDE_NULL_VALUES = 'discover:hideNullValues';
|
||||
const HIDE_NULL_VALUES = 'unifiedDocViewer:hideNullValues';
|
||||
|
||||
const GRID_COLUMN_FIELD_NAME = 'name';
|
||||
const GRID_COLUMN_FIELD_VALUE = 'value';
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue