diff --git a/packages/kbn-unified-doc-viewer/src/components/doc_viewer/__snapshots__/doc_viewer.test.tsx.snap b/packages/kbn-unified-doc-viewer/src/components/doc_viewer/__snapshots__/doc_viewer.test.tsx.snap index 3bbf6a09a5019..582f07fbeb950 100644 --- a/packages/kbn-unified-doc-viewer/src/components/doc_viewer/__snapshots__/doc_viewer.test.tsx.snap +++ b/packages/kbn-unified-doc-viewer/src/components/doc_viewer/__snapshots__/doc_viewer.test.tsx.snap @@ -7,6 +7,7 @@ exports[` Render with 3 different tabs 1`] = ` > 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('', () => { test('Render with 3 different tabs', () => { @@ -59,4 +76,57 @@ describe('', () => { 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(); + + 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(); + + 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(); + + expect(screen.getByTestId('docViewerTab-test1').getAttribute('aria-selected')).toBe('true'); + expect(screen.getByTestId('docViewerTab-test2').getAttribute('aria-selected')).toBe('false'); + + mockTestInitialLocalStorageValue = undefined; + }); }); diff --git a/packages/kbn-unified-doc-viewer/src/components/doc_viewer/doc_viewer.tsx b/packages/kbn-unified-doc-viewer/src/components/doc_viewer/doc_viewer.tsx index 74fbfcf0a6133..b139fae0b3f18 100644 --- a/packages/kbn-unified-doc-viewer/src/components/doc_viewer/doc_viewer.tsx +++ b/packages/kbn-unified-doc-viewer/src/components/doc_viewer/doc_viewer.tsx @@ -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: ( (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 (
- +
); } diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx index b6183c496342e..283c00eabae27 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx @@ -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';