mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Discover] Add document explorer callout (#123814)
* [Discover] add document explorer callout * [Discover] fix mobile view * [Discover] fix lint * [Discover] apply suggestions * Update src/plugins/discover/public/application/main/components/document_explorer_callout/document_explorer_callout.tsx Co-authored-by: Matthias Wilhelm <ankertal@gmail.com> * [Discover] add unit tests, fix read only advanced settings case * [Discover] apply suggestions Co-authored-by: Matthias Wilhelm <ankertal@gmail.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
9f239dc0a7
commit
41e756c989
6 changed files with 206 additions and 16 deletions
26
src/plugins/discover/public/__mocks__/local_storage_mock.ts
Normal file
26
src/plugins/discover/public/__mocks__/local_storage_mock.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export class LocalStorageMock {
|
||||
private store: Record<string, unknown>;
|
||||
constructor(defaultStore: Record<string, unknown>) {
|
||||
this.store = defaultStore;
|
||||
}
|
||||
clear() {
|
||||
this.store = {};
|
||||
}
|
||||
get(key: string) {
|
||||
return this.store[key] || null;
|
||||
}
|
||||
set(key: string, value: unknown) {
|
||||
this.store[key] = String(value);
|
||||
}
|
||||
remove(key: string) {
|
||||
delete this.store[key];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
.dscDocumentExplorerCallout {
|
||||
.euiCallOutHeader__title {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import './document_explorer_callout.scss';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { EuiButton, EuiButtonIcon, EuiCallOut, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { useDiscoverServices } from '../../../../utils/use_discover_services';
|
||||
import { DOC_TABLE_LEGACY } from '../../../../../common';
|
||||
import { Storage } from '../../../../../../kibana_utils/public';
|
||||
|
||||
export const CALLOUT_STATE_KEY = 'discover:docExplorerCalloutClosed';
|
||||
|
||||
const getStoredCalloutState = (storage: Storage): boolean => {
|
||||
const calloutClosed = storage.get(CALLOUT_STATE_KEY);
|
||||
return Boolean(calloutClosed);
|
||||
};
|
||||
const updateStoredCalloutState = (newState: boolean, storage: Storage) => {
|
||||
storage.set(CALLOUT_STATE_KEY, newState);
|
||||
};
|
||||
|
||||
export const DocumentExplorerCallout = () => {
|
||||
const { storage, capabilities, addBasePath } = useDiscoverServices();
|
||||
const [calloutClosed, setCalloutClosed] = useState(getStoredCalloutState(storage));
|
||||
|
||||
const onCloseCallout = useCallback(() => {
|
||||
updateStoredCalloutState(true, storage);
|
||||
setCalloutClosed(true);
|
||||
}, [storage]);
|
||||
|
||||
if (calloutClosed || !capabilities.advancedSettings.save) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiCallOut
|
||||
className="dscDocumentExplorerCallout"
|
||||
title={<CalloutTitle onCloseCallout={onCloseCallout} />}
|
||||
iconType="search"
|
||||
>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="discover.docExplorerCallout.bodyMessage"
|
||||
defaultMessage="Quickly sort, select, and compare data, resize columns, and view documents in fullscreen with the Document Explorer."
|
||||
/>
|
||||
</p>
|
||||
<p>
|
||||
<EuiButton
|
||||
iconType="tableDensityNormal"
|
||||
size="s"
|
||||
href={addBasePath(`/app/management/kibana/settings?query=${DOC_TABLE_LEGACY}`)}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="discover.docExplorerCallout.tryDocumentExplorer"
|
||||
defaultMessage="Try Document Explorer"
|
||||
/>
|
||||
</EuiButton>
|
||||
</p>
|
||||
</EuiCallOut>
|
||||
);
|
||||
};
|
||||
|
||||
function CalloutTitle({ onCloseCallout }: { onCloseCallout: () => void }) {
|
||||
return (
|
||||
<EuiFlexGroup justifyContent="spaceBetween" gutterSize="none" responsive={false}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<FormattedMessage
|
||||
id="discover.docExplorerCallout.headerMessage"
|
||||
defaultMessage="A better way to explore"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButtonIcon
|
||||
aria-label={i18n.translate('discover.docExplorerCallout.closeButtonAriaLabel', {
|
||||
defaultMessage: 'Close',
|
||||
})}
|
||||
onClick={onCloseCallout}
|
||||
type="button"
|
||||
iconType="cross"
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { mountWithIntl } from '@kbn/test/jest';
|
||||
import { KibanaContextProvider } from '../../../../../../kibana_react/public';
|
||||
import { CALLOUT_STATE_KEY, DocumentExplorerCallout } from './document_explorer_callout';
|
||||
import { LocalStorageMock } from '../../../../__mocks__/local_storage_mock';
|
||||
import { DiscoverServices } from '../../../../build_services';
|
||||
|
||||
const defaultServices = {
|
||||
addBasePath: () => '',
|
||||
capabilities: { advancedSettings: { save: true } },
|
||||
storage: new LocalStorageMock({ [CALLOUT_STATE_KEY]: false }),
|
||||
} as unknown as DiscoverServices;
|
||||
|
||||
const mount = (services: DiscoverServices) => {
|
||||
return mountWithIntl(
|
||||
<KibanaContextProvider services={services}>
|
||||
<DocumentExplorerCallout />
|
||||
</KibanaContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
describe('Document Explorer callout', () => {
|
||||
it('should render callout', () => {
|
||||
const result = mount(defaultServices);
|
||||
|
||||
expect(result.find('.dscDocumentExplorerCallout').exists()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not render callout for user without permissions', () => {
|
||||
const services = {
|
||||
...defaultServices,
|
||||
capabilities: { advancedSettings: { save: false } },
|
||||
} as unknown as DiscoverServices;
|
||||
const result = mount(services);
|
||||
|
||||
expect(result.find('.dscDocumentExplorerCallout').exists()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not render callout of it was closed', () => {
|
||||
const services = {
|
||||
...defaultServices,
|
||||
storage: new LocalStorageMock({ [CALLOUT_STATE_KEY]: true }),
|
||||
} as unknown as DiscoverServices;
|
||||
const result = mount(services);
|
||||
|
||||
expect(result.find('.dscDocumentExplorerCallout').exists()).toBeFalsy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { DocumentExplorerCallout } from './document_explorer_callout';
|
|
@ -33,6 +33,7 @@ import { useDataState } from '../../utils/use_data_state';
|
|||
import { DocTableInfinite } from '../../../../components/doc_table/doc_table_infinite';
|
||||
import { SortPairArr } from '../../../../components/doc_table/lib/get_sort';
|
||||
import { ElasticSearchHit } from '../../../../types';
|
||||
import { DocumentExplorerCallout } from '../document_explorer_callout';
|
||||
|
||||
const DocTableInfiniteMemoized = React.memo(DocTableInfinite);
|
||||
const DataGridMemoized = React.memo(DiscoverGrid);
|
||||
|
@ -126,22 +127,25 @@ function DiscoverDocumentsComponent({
|
|||
</h2>
|
||||
</EuiScreenReaderOnly>
|
||||
{isLegacy && rows && rows.length && (
|
||||
<DocTableInfiniteMemoized
|
||||
columns={columns}
|
||||
indexPattern={indexPattern}
|
||||
rows={rows}
|
||||
sort={state.sort || []}
|
||||
isLoading={isLoading}
|
||||
searchDescription={savedSearch.description}
|
||||
sharedItemTitle={savedSearch.title}
|
||||
onAddColumn={onAddColumn}
|
||||
onFilter={onAddFilter as DocViewFilterFn}
|
||||
onMoveColumn={onMoveColumn}
|
||||
onRemoveColumn={onRemoveColumn}
|
||||
onSort={onSort}
|
||||
useNewFieldsApi={useNewFieldsApi}
|
||||
dataTestSubj="discoverDocTable"
|
||||
/>
|
||||
<>
|
||||
<DocumentExplorerCallout />
|
||||
<DocTableInfiniteMemoized
|
||||
columns={columns}
|
||||
indexPattern={indexPattern}
|
||||
rows={rows}
|
||||
sort={state.sort || []}
|
||||
isLoading={isLoading}
|
||||
searchDescription={savedSearch.description}
|
||||
sharedItemTitle={savedSearch.title}
|
||||
onAddColumn={onAddColumn}
|
||||
onFilter={onAddFilter as DocViewFilterFn}
|
||||
onMoveColumn={onMoveColumn}
|
||||
onRemoveColumn={onRemoveColumn}
|
||||
onSort={onSort}
|
||||
useNewFieldsApi={useNewFieldsApi}
|
||||
dataTestSubj="discoverDocTable"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{!isLegacy && (
|
||||
<div className="dscDiscoverGrid">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue