[Discover] Update document explorer callout wording (#128556)

- Adding a new callout when Document explorer is active, linking to documentation
Co-authored-by: Matthias Wilhelm <matthias.wilhelm@elastic.co>
This commit is contained in:
Dmitry Tomashevich 2022-03-30 12:19:46 +05:00 committed by GitHub
parent 4f070b3435
commit d0c06b0112
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 239 additions and 30 deletions

View file

@ -6,7 +6,7 @@
* Side Public License, v 1. * Side Public License, v 1.
*/ */
import React, { useCallback, useState } from 'react'; import React, { useCallback, useMemo, useState } from 'react';
import './document_explorer_callout.scss'; import './document_explorer_callout.scss';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react'; import { FormattedMessage } from '@kbn/i18n-react';
@ -17,7 +17,9 @@ import {
EuiFlexGroup, EuiFlexGroup,
EuiFlexItem, EuiFlexItem,
EuiLink, EuiLink,
useEuiTheme,
} from '@elastic/eui'; } from '@elastic/eui';
import { css } from '@emotion/react';
import { useDiscoverServices } from '../../../../utils/use_discover_services'; import { useDiscoverServices } from '../../../../utils/use_discover_services';
import { DOC_TABLE_LEGACY } from '../../../../../common'; import { DOC_TABLE_LEGACY } from '../../../../../common';
import { Storage } from '../../../../../../kibana_utils/public'; import { Storage } from '../../../../../../kibana_utils/public';
@ -32,7 +34,11 @@ const updateStoredCalloutState = (newState: boolean, storage: Storage) => {
storage.set(CALLOUT_STATE_KEY, newState); storage.set(CALLOUT_STATE_KEY, newState);
}; };
/**
* The callout that's displayed when Document explorer is disabled
*/
export const DocumentExplorerCallout = () => { export const DocumentExplorerCallout = () => {
const { euiTheme } = useEuiTheme();
const { storage, capabilities, docLinks, addBasePath } = useDiscoverServices(); const { storage, capabilities, docLinks, addBasePath } = useDiscoverServices();
const [calloutClosed, setCalloutClosed] = useState(getStoredCalloutState(storage)); const [calloutClosed, setCalloutClosed] = useState(getStoredCalloutState(storage));
@ -41,6 +47,13 @@ export const DocumentExplorerCallout = () => {
setCalloutClosed(true); setCalloutClosed(true);
}, [storage]); }, [storage]);
const semiBoldStyle = useMemo(
() => css`
font-weight: ${euiTheme.font.weight.semiBold};
`,
[euiTheme.font.weight.semiBold]
);
if (calloutClosed || !capabilities.advancedSettings.save) { if (calloutClosed || !capabilities.advancedSettings.save) {
return null; return null;
} }
@ -54,7 +67,17 @@ export const DocumentExplorerCallout = () => {
<p> <p>
<FormattedMessage <FormattedMessage
id="discover.docExplorerCallout.bodyMessage" id="discover.docExplorerCallout.bodyMessage"
defaultMessage="Quickly sort, select, and compare data, resize columns, and view documents in fullscreen with the Document Explorer." defaultMessage="Quickly sort, select, and compare data, resize columns, and view documents in fullscreen with the {documentExplorer}."
values={{
documentExplorer: (
<span css={semiBoldStyle}>
<FormattedMessage
id="discover.docExplorerCallout.documentExplorer"
defaultMessage="Document Explorer"
/>
</span>
),
}}
/> />
</p> </p>
<EuiFlexGroup <EuiFlexGroup
@ -75,7 +98,7 @@ export const DocumentExplorerCallout = () => {
/> />
</EuiButton> </EuiButton>
</EuiFlexItem> </EuiFlexItem>
<EuiFlexItem> <EuiFlexItem grow={false}>
<EuiLink href={docLinks.links.discover.documentExplorer}> <EuiLink href={docLinks.links.discover.documentExplorer}>
<FormattedMessage <FormattedMessage
id="discover.docExplorerCallout.learnMore" id="discover.docExplorerCallout.learnMore"

View file

@ -0,0 +1,60 @@
/*
* 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-helpers';
import { KibanaContextProvider } from '../../../../../../kibana_react/public';
import {
CALLOUT_STATE_KEY,
DocumentExplorerUpdateCallout,
} from './document_explorer_update_callout';
import { LocalStorageMock } from '../../../../__mocks__/local_storage_mock';
import { DiscoverServices } from '../../../../build_services';
const defaultServices = {
addBasePath: () => '',
docLinks: { links: { discover: { documentExplorer: '' } } },
capabilities: { advancedSettings: { save: true } },
storage: new LocalStorageMock({ [CALLOUT_STATE_KEY]: false }),
} as unknown as DiscoverServices;
const mount = (services: DiscoverServices) => {
return mountWithIntl(
<KibanaContextProvider services={services}>
<DocumentExplorerUpdateCallout />
</KibanaContextProvider>
);
};
describe('Document Explorer Update 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();
});
});

View file

@ -0,0 +1,124 @@
/*
* 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, useMemo, 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,
useEuiTheme,
} from '@elastic/eui';
import { css } from '@emotion/react';
import { useDiscoverServices } from '../../../../utils/use_discover_services';
import { Storage } from '../../../../../../kibana_utils/public';
export const CALLOUT_STATE_KEY = 'discover:docExplorerUpdateCalloutClosed';
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);
};
/**
* The callout that's displayed when Document explorer is enabled
*/
export const DocumentExplorerUpdateCallout = () => {
const { euiTheme } = useEuiTheme();
const { storage, capabilities, docLinks } = useDiscoverServices();
const [calloutClosed, setCalloutClosed] = useState(getStoredCalloutState(storage));
const semiBoldStyle = useMemo(
() => css`
font-weight: ${euiTheme.font.weight.semiBold};
`,
[euiTheme.font.weight.semiBold]
);
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.docExplorerUpdateCallout.bodyMessage"
defaultMessage="Experience the new {documentExplorer}. Understand the shape of your data with {fieldStatistics}."
values={{
fieldStatistics: (
<span css={semiBoldStyle}>
<FormattedMessage
id="discover.docExplorerUpdateCallout.fieldStatistics"
defaultMessage="Field Statistics"
/>
</span>
),
documentExplorer: (
<span css={semiBoldStyle}>
<FormattedMessage
id="discover.docExplorerUpdateCallout.documentExplorer"
defaultMessage="Document Explorer"
/>
</span>
),
}}
/>
</p>
<EuiButton
iconType="tableDensityNormal"
size="s"
href={docLinks.links.discover.documentExplorer}
>
<FormattedMessage
id="discover.docExplorerUpdateCallout.learnMore"
defaultMessage="Learn more"
/>
</EuiButton>
</EuiCallOut>
);
};
function CalloutTitle({ onCloseCallout }: { onCloseCallout: () => void }) {
return (
<EuiFlexGroup justifyContent="spaceBetween" gutterSize="none" responsive={false}>
<EuiFlexItem grow={false}>
<FormattedMessage
id="discover.docExplorerUpdateCallout.headerMessage"
defaultMessage="A better way to explore"
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButtonIcon
aria-label={i18n.translate('discover.docExplorerUpdateCallout.closeButtonAriaLabel', {
defaultMessage: 'Close',
})}
onClick={onCloseCallout}
type="button"
iconType="cross"
/>
</EuiFlexItem>
</EuiFlexGroup>
);
}

View file

@ -34,6 +34,7 @@ import { DocTableInfinite } from '../../../../components/doc_table/doc_table_inf
import { SortPairArr } from '../../../../components/doc_table/lib/get_sort'; import { SortPairArr } from '../../../../components/doc_table/lib/get_sort';
import { ElasticSearchHit } from '../../../../types'; import { ElasticSearchHit } from '../../../../types';
import { DocumentExplorerCallout } from '../document_explorer_callout'; import { DocumentExplorerCallout } from '../document_explorer_callout';
import { DocumentExplorerUpdateCallout } from '../document_explorer_callout/document_explorer_update_callout';
const DocTableInfiniteMemoized = React.memo(DocTableInfinite); const DocTableInfiniteMemoized = React.memo(DocTableInfinite);
const DataGridMemoized = React.memo(DiscoverGrid); const DataGridMemoized = React.memo(DiscoverGrid);
@ -156,30 +157,33 @@ function DiscoverDocumentsComponent({
)} )}
{!isLegacy && ( {!isLegacy && (
<div className="dscDiscoverGrid"> <div className="dscDiscoverGrid">
<DataGridMemoized <>
ariaLabelledBy="documentsAriaLabel" <DocumentExplorerUpdateCallout />
columns={columns} <DataGridMemoized
expandedDoc={expandedDoc} ariaLabelledBy="documentsAriaLabel"
indexPattern={indexPattern} columns={columns}
isLoading={isLoading} expandedDoc={expandedDoc}
rows={rows} indexPattern={indexPattern}
sort={(state.sort as SortPairArr[]) || []} isLoading={isLoading}
sampleSize={sampleSize} rows={rows}
searchDescription={savedSearch.description} sort={(state.sort as SortPairArr[]) || []}
searchTitle={savedSearch.title} sampleSize={sampleSize}
setExpandedDoc={setExpandedDoc} searchDescription={savedSearch.description}
showTimeCol={showTimeCol} searchTitle={savedSearch.title}
settings={state.grid} setExpandedDoc={setExpandedDoc}
onAddColumn={onAddColumn} showTimeCol={showTimeCol}
onFilter={onAddFilter as DocViewFilterFn} settings={state.grid}
onRemoveColumn={onRemoveColumn} onAddColumn={onAddColumn}
onSetColumns={onSetColumns} onFilter={onAddFilter as DocViewFilterFn}
onSort={onSort} onRemoveColumn={onRemoveColumn}
onResize={onResize} onSetColumns={onSetColumns}
useNewFieldsApi={useNewFieldsApi} onSort={onSort}
rowHeightState={state.rowHeight} onResize={onResize}
onUpdateRowHeight={onUpdateRowHeight} useNewFieldsApi={useNewFieldsApi}
/> rowHeightState={state.rowHeight}
onUpdateRowHeight={onUpdateRowHeight}
/>
</>
</div> </div>
)} )}
</EuiFlexItem> </EuiFlexItem>

View file

@ -171,7 +171,7 @@ export const getUiSettings: (docLinks: DocLinksServiceSetup) => Record<string, U
'The Document Explorer offers better data sorting, resizable columns, and a full screen view.', 'The Document Explorer offers better data sorting, resizable columns, and a full screen view.',
values: { values: {
documentExplorerDocs: documentExplorerDocs:
`<a href=${docLinks.links.discover.documentExplorer} `<a href=${docLinks.links.discover.documentExplorer} style="font-weight: 600;"
target="_blank" rel="noopener">` + target="_blank" rel="noopener">` +
i18n.translate('discover.advancedSettings.documentExplorerLinkText', { i18n.translate('discover.advancedSettings.documentExplorerLinkText', {
defaultMessage: 'Document Explorer', defaultMessage: 'Document Explorer',

View file

@ -2720,7 +2720,6 @@
"discover.doc.loadingDescription": "読み込み中…", "discover.doc.loadingDescription": "読み込み中…",
"discover.doc.somethingWentWrongDescription": "{indexName}が見つかりません。", "discover.doc.somethingWentWrongDescription": "{indexName}が見つかりません。",
"discover.doc.somethingWentWrongDescriptionAddon": "インデックスが存在することを確認してください。", "discover.doc.somethingWentWrongDescriptionAddon": "インデックスが存在することを確認してください。",
"discover.docExplorerCallout.bodyMessage": "ドキュメントエクスプローラーでは、データの並べ替え、選択、比較のほか、列のサイズ変更やドキュメントの全画面表示をすばやく実行できます。",
"discover.docExplorerCallout.closeButtonAriaLabel": "閉じる", "discover.docExplorerCallout.closeButtonAriaLabel": "閉じる",
"discover.docExplorerCallout.headerMessage": "より効率的な探索方法", "discover.docExplorerCallout.headerMessage": "より効率的な探索方法",
"discover.docExplorerCallout.tryDocumentExplorer": "ドキュメントエクスプローラーを試す", "discover.docExplorerCallout.tryDocumentExplorer": "ドキュメントエクスプローラーを試す",

View file

@ -2725,7 +2725,6 @@
"discover.doc.loadingDescription": "正在加载……", "discover.doc.loadingDescription": "正在加载……",
"discover.doc.somethingWentWrongDescription": "{indexName} 缺失。", "discover.doc.somethingWentWrongDescription": "{indexName} 缺失。",
"discover.doc.somethingWentWrongDescriptionAddon": "请确保索引存在。", "discover.doc.somethingWentWrongDescriptionAddon": "请确保索引存在。",
"discover.docExplorerCallout.bodyMessage": "使用 Document Explorer 快速排序、选择和比较数据,调整列大小并以全屏方式查看文档。",
"discover.docExplorerCallout.closeButtonAriaLabel": "关闭", "discover.docExplorerCallout.closeButtonAriaLabel": "关闭",
"discover.docExplorerCallout.headerMessage": "更好的浏览方式", "discover.docExplorerCallout.headerMessage": "更好的浏览方式",
"discover.docExplorerCallout.tryDocumentExplorer": "试用 Document Explorer", "discover.docExplorerCallout.tryDocumentExplorer": "试用 Document Explorer",