Migrate doc view part of discover (#58094)

This commit is contained in:
Joe Reuter 2020-03-24 07:27:15 +01:00 committed by GitHub
parent 6de7f2a62b
commit 3e26777965
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
65 changed files with 606 additions and 168 deletions

View file

@ -3,6 +3,7 @@
"common.ui": "src/legacy/ui",
"console": "src/plugins/console",
"core": "src/core",
"discover": "src/plugins/discover",
"dashboard": "src/plugins/dashboard",
"data": "src/plugins/data",
"embeddableApi": "src/plugins/embeddable",

View file

@ -1233,11 +1233,11 @@ This table shows where these uiExports have moved to in the New Platform. In mos
| `chromeNavControls` | [`core.chrome.navControls.register{Left,Right}`](/docs/development/core/public/kibana-plugin-public.chromenavcontrols.md) | |
| `contextMenuActions` | | Should be an API on the devTools plugin. |
| `devTools` | | |
| `docViews` | | |
| `docViews` | [`plugins.discover.docViews.addDocView`](./src/plugins/discover/public/doc_views) | Should be an API on the discover plugin. |
| `embeddableActions` | | Should be an API on the embeddables plugin. |
| `embeddableFactories` | | Should be an API on the embeddables plugin. |
| `fieldFormatEditors` | | |
| `fieldFormats` | [`plugins.data.fieldFormats`](./src/plugins/data/public/field_formats) | |
| `fieldFormatEditors` | | |
| `fieldFormats` | [`plugins.data.fieldFormats`](./src/plugins/data/public/field_formats) | |
| `hacks` | n/a | Just run the code in your plugin's `start` method. |
| `home` | [`plugins.home.featureCatalogue.register`](./src/plugins/home/public/feature_catalogue) | Must add `home` as a dependency in your kibana.json. |
| `indexManagement` | | Should be an API on the indexManagement plugin. |

View file

@ -35,10 +35,13 @@ import {
import { DiscoverStartPlugins } from './plugin';
import { SharePluginStart } from '../../../../../plugins/share/public';
import { DocViewsRegistry } from './np_ready/doc_views/doc_views_registry';
import { ChartsPluginStart } from '../../../../../plugins/charts/public';
import { VisualizationsStart } from '../../../visualizations/public';
import { createSavedSearchesLoader, SavedSearch } from '../../../../../plugins/discover/public';
import {
createSavedSearchesLoader,
DocViewerComponent,
SavedSearch,
} from '../../../../../plugins/discover/public';
export interface DiscoverServices {
addBasePath: (path: string) => string;
@ -47,7 +50,7 @@ export interface DiscoverServices {
core: CoreStart;
data: DataPublicPluginStart;
docLinks: DocLinksStart;
docViewsRegistry: DocViewsRegistry;
DocViewer: DocViewerComponent;
history: History;
theme: ChartsPluginStart['theme'];
filterManager: FilterManager;
@ -64,8 +67,7 @@ export interface DiscoverServices {
}
export async function buildServices(
core: CoreStart,
plugins: DiscoverStartPlugins,
docViewsRegistry: DocViewsRegistry
plugins: DiscoverStartPlugins
): Promise<DiscoverServices> {
const services = {
savedObjectsClient: core.savedObjects.client,
@ -81,7 +83,7 @@ export async function buildServices(
core,
data: plugins.data,
docLinks: core.docLinks,
docViewsRegistry,
DocViewer: plugins.discover.docViews.DocViewer,
history: createHashHistory(),
theme: plugins.charts.theme,
filterManager: plugins.data.query.filterManager,

View file

@ -75,7 +75,6 @@ export {
EsQuerySortValue,
SortDirection,
} from '../../../../../plugins/data/public';
export { ElasticSearchHit } from './np_ready/doc_views/doc_views_types';
export { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities';
// @ts-ignore
export { buildPointSeriesData } from 'ui/agg_response/point_series/point_series';

View file

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import { FieldName } from './field_name/field_name';
import { FieldName } from '../../../../../../../../plugins/discover/public';
import { getServices, wrapInI18nContext } from '../../../kibana_services';
export function FieldNameDirectiveProvider(reactDirective) {

View file

@ -17,11 +17,15 @@
* under the License.
*/
import { DocViewer } from '../components/doc_viewer/doc_viewer';
import React from 'react';
import { getServices } from '../../kibana_services';
export function createDocViewerDirective(reactDirective: any) {
return reactDirective(
DocViewer,
(props: any) => {
const { DocViewer } = getServices();
return <DocViewer {...props} />;
},
[
'hit',
['indexPattern', { watchDepth: 'reference' }],

View file

@ -1,3 +1,2 @@
@import 'fetch_error/index';
@import 'field_chooser/index';
@import 'doc_viewer/index';

View file

@ -24,19 +24,13 @@ import { ReactWrapper } from 'enzyme';
import { findTestSubject } from '@elastic/eui/lib/test';
import { Doc, DocProps } from './doc';
jest.mock('../doc_viewer/doc_viewer', () => ({
DocViewer: () => null,
}));
jest.mock('../../../kibana_services', () => {
return {
getServices: () => ({
metadata: {
branch: 'test',
},
getDocViewsSorted: () => {
return [];
},
DocViewer: () => null,
}),
};
});

View file

@ -20,9 +20,9 @@ import React from 'react';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiCallOut, EuiLink, EuiLoadingSpinner, EuiPageContent } from '@elastic/eui';
import { IndexPatternsContract } from 'src/plugins/data/public';
import { DocViewer } from '../doc_viewer/doc_viewer';
import { ElasticRequestState, useEsDocSearch } from './use_es_doc_search';
import { ElasticSearchHit, getServices } from '../../../kibana_services';
import { getServices } from '../../../kibana_services';
import { ElasticSearchHit } from '../../../../../../../../plugins/discover/public';
export interface ElasticSearchResult {
hits: {
@ -61,6 +61,7 @@ export interface DocProps {
}
export function Doc(props: DocProps) {
const { DocViewer } = getServices();
const [reqState, hit, indexPattern] = useEsDocSearch(props);
return (

View file

@ -17,8 +17,9 @@
* under the License.
*/
import { useEffect, useState } from 'react';
import { ElasticSearchHit, IndexPattern } from '../../../kibana_services';
import { IndexPattern } from '../../../kibana_services';
import { DocProps } from './doc';
import { ElasticSearchHit } from '../../../../../../../../plugins/discover/public';
export enum ElasticRequestState {
Loading,

View file

@ -19,7 +19,6 @@
import { BehaviorSubject } from 'rxjs';
import { filter, map } from 'rxjs/operators';
import { i18n } from '@kbn/i18n';
import { AppMountParameters, CoreSetup, CoreStart, Plugin } from 'kibana/public';
import angular, { auto } from 'angular';
import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public';
@ -41,10 +40,7 @@ import {
KibanaLegacySetup,
AngularRenderedAppUpdater,
} from '../../../../../plugins/kibana_legacy/public';
import { DocViewsRegistry } from './np_ready/doc_views/doc_views_registry';
import { DocViewInput, DocViewInputFn } from './np_ready/doc_views/doc_views_types';
import { DocViewTable } from './np_ready/components/table/table';
import { JsonCodeBlock } from './np_ready/components/json_code_block/json_code_block';
import { DiscoverSetup, DiscoverStart } from '../../../../../plugins/discover/public';
import { HomePublicPluginSetup } from '../../../../../plugins/home/public';
import {
VisualizationsStart,
@ -52,15 +48,6 @@ import {
} from '../../../visualizations/public/np_ready/public';
import { createKbnUrlTracker } from '../../../../../plugins/kibana_utils/public';
/**
* These are the interfaces with your public contracts. You should export these
* for other plugins to use in _their_ `SetupDeps`/`StartDeps` interfaces.
* @public
*/
export interface DiscoverSetup {
addDocView(docViewRaw: DocViewInput | DocViewInputFn): void;
}
export type DiscoverStart = void;
export interface DiscoverSetupPlugins {
uiActions: UiActionsSetup;
embeddable: EmbeddableSetup;
@ -68,6 +55,7 @@ export interface DiscoverSetupPlugins {
home: HomePublicPluginSetup;
visualizations: VisualizationsSetup;
data: DataPublicPluginSetup;
discover: DiscoverSetup;
}
export interface DiscoverStartPlugins {
uiActions: UiActionsStart;
@ -78,6 +66,7 @@ export interface DiscoverStartPlugins {
share: SharePluginStart;
inspector: any;
visualizations: VisualizationsStart;
discover: DiscoverStart;
}
const innerAngularName = 'app/discover';
const embeddableAngularName = 'app/discoverEmbeddable';
@ -87,10 +76,9 @@ const embeddableAngularName = 'app/discoverEmbeddable';
* There are 2 kinds of Angular bootstrapped for rendering, additionally to the main Angular
* Discover provides embeddables, those contain a slimmer Angular
*/
export class DiscoverPlugin implements Plugin<DiscoverSetup, DiscoverStart> {
export class DiscoverPlugin implements Plugin<void, void> {
private servicesInitialized: boolean = false;
private innerAngularInitialized: boolean = false;
private docViewsRegistry: DocViewsRegistry | null = null;
private embeddableInjector: auto.IInjectorService | null = null;
private getEmbeddableInjector: (() => Promise<auto.IInjectorService>) | null = null;
private appStateUpdater = new BehaviorSubject<AngularRenderedAppUpdater>(() => ({}));
@ -103,7 +91,7 @@ export class DiscoverPlugin implements Plugin<DiscoverSetup, DiscoverStart> {
public initializeInnerAngular?: () => void;
public initializeServices?: () => Promise<{ core: CoreStart; plugins: DiscoverStartPlugins }>;
setup(core: CoreSetup<DiscoverStartPlugins>, plugins: DiscoverSetupPlugins): DiscoverSetup {
setup(core: CoreSetup<DiscoverStartPlugins>, plugins: DiscoverSetupPlugins) {
const { appMounted, appUnMounted, stop: stopUrlTracker } = createKbnUrlTracker({
baseUrl: core.http.basePath.prepend('/app/kibana'),
defaultSubUrl: '#/discover',
@ -130,21 +118,7 @@ export class DiscoverPlugin implements Plugin<DiscoverSetup, DiscoverStart> {
};
this.getEmbeddableInjector = this.getInjector.bind(this);
this.docViewsRegistry = new DocViewsRegistry(this.getEmbeddableInjector);
this.docViewsRegistry.addDocView({
title: i18n.translate('kbn.discover.docViews.table.tableTitle', {
defaultMessage: 'Table',
}),
order: 10,
component: DocViewTable,
});
this.docViewsRegistry.addDocView({
title: i18n.translate('kbn.discover.docViews.json.jsonTitle', {
defaultMessage: 'JSON',
}),
order: 20,
component: JsonCodeBlock,
});
plugins.discover.docViews.setAngularInjectorGetter(this.getEmbeddableInjector);
plugins.kibanaLegacy.registerLegacyApp({
id: 'discover',
title: 'Discover',
@ -172,14 +146,10 @@ export class DiscoverPlugin implements Plugin<DiscoverSetup, DiscoverStart> {
},
});
registerFeature(plugins.home);
this.registerEmbeddable(core, plugins);
return {
addDocView: this.docViewsRegistry.addDocView.bind(this.docViewsRegistry),
};
}
start(core: CoreStart, plugins: DiscoverStartPlugins): DiscoverStart {
start(core: CoreStart, plugins: DiscoverStartPlugins) {
// we need to register the application service at setup, but to render it
// there are some start dependencies necessary, for this reason
// initializeInnerAngular + initializeServices are assigned at start and used
@ -198,7 +168,7 @@ export class DiscoverPlugin implements Plugin<DiscoverSetup, DiscoverStart> {
if (this.servicesInitialized) {
return { core, plugins };
}
const services = await buildServices(core, plugins, this.docViewsRegistry!);
const services = await buildServices(core, plugins);
setServices(services);
this.servicesInitialized = true;

View file

@ -271,6 +271,12 @@ export const npSetup = {
}),
},
},
discover: {
docViews: {
addDocView: sinon.fake(),
setAngularInjectorGetter: sinon.fake(),
},
},
visTypeVega: {
config: sinon.fake(),
},
@ -459,6 +465,11 @@ export const npStart = {
useChartsTheme: sinon.fake(),
},
},
discover: {
docViews: {
DocViewer: () => null,
},
},
},
};

View file

@ -65,6 +65,7 @@ import {
NavigationPublicPluginStart,
} from '../../../../plugins/navigation/public';
import { VisTypeVegaSetup } from '../../../../plugins/vis_type_vega/public';
import { DiscoverSetup, DiscoverStart } from '../../../../plugins/discover/public';
export interface PluginsSetup {
bfetch: BfetchPublicSetup;
@ -83,6 +84,7 @@ export interface PluginsSetup {
advancedSettings: AdvancedSettingsSetup;
management: ManagementSetup;
visTypeVega: VisTypeVegaSetup;
discover: DiscoverSetup;
telemetry?: TelemetryPluginSetup;
}
@ -100,6 +102,7 @@ export interface PluginsStart {
share: SharePluginStart;
management: ManagementStart;
advancedSettings: AdvancedSettingsStart;
discover: DiscoverStart;
telemetry?: TelemetryPluginStart;
}

View file

@ -0,0 +1,6 @@
{
"id": "discover",
"version": "kibana",
"server": false,
"ui": true
}

View file

@ -0,0 +1 @@
@import 'doc_viewer/index';

View file

@ -21,37 +21,33 @@ import { mount, shallow } from 'enzyme';
import { DocViewer } from './doc_viewer';
// @ts-ignore
import { findTestSubject } from '@elastic/eui/lib/test';
import { getServices } from '../../../kibana_services';
import { getDocViewsRegistry } from '../../services';
import { DocViewRenderProps } from '../../doc_views/doc_views_types';
jest.mock('../../../kibana_services', () => {
jest.mock('../../services', () => {
let registry: any[] = [];
return {
getServices: () => ({
docViewsRegistry: {
addDocView(view: any) {
registry.push(view);
},
getDocViewsSorted() {
return registry;
},
getDocViewsRegistry: () => ({
addDocView(view: any) {
registry.push(view);
},
getDocViewsSorted() {
return registry;
},
resetRegistry: () => {
registry = [];
},
}),
formatMsg: (x: any) => String(x),
formatStack: (x: any) => String(x),
};
});
beforeEach(() => {
(getServices() as any).resetRegistry();
(getDocViewsRegistry() as any).resetRegistry();
jest.clearAllMocks();
});
test('Render <DocViewer/> with 3 different tabs', () => {
const registry = getServices().docViewsRegistry;
const registry = getDocViewsRegistry();
registry.addDocView({ order: 10, title: 'Render function', render: jest.fn() });
registry.addDocView({ order: 20, title: 'React component', component: () => <div>test</div> });
registry.addDocView({ order: 30, title: 'Invalid doc view' });
@ -69,7 +65,7 @@ test('Render <DocViewer/> with 1 tab displaying error message', () => {
return null;
}
const registry = getServices().docViewsRegistry;
const registry = getDocViewsRegistry();
registry.addDocView({
order: 10,
title: 'React component',

View file

@ -18,7 +18,7 @@
*/
import React from 'react';
import { EuiTabbedContent } from '@elastic/eui';
import { getServices } from '../../../kibana_services';
import { getDocViewsRegistry } from '../../services';
import { DocViewerTab } from './doc_viewer_tab';
import { DocView, DocViewRenderProps } from '../../doc_views/doc_views_types';
@ -29,7 +29,7 @@ import { DocView, DocViewRenderProps } from '../../doc_views/doc_views_types';
* a `render` function.
*/
export function DocViewer(renderProps: DocViewRenderProps) {
const { docViewsRegistry } = getServices();
const docViewsRegistry = getDocViewsRegistry();
const tabs = docViewsRegistry
.getDocViewsSorted(renderProps.hit)
.map(({ title, render, component }: DocView, idx: number) => {

View file

@ -18,7 +18,7 @@
*/
import React from 'react';
import { EuiCallOut, EuiCodeBlock } from '@elastic/eui';
import { formatMsg, formatStack } from '../../../kibana_services';
import { formatMsg, formatStack } from '../../../../kibana_legacy/public';
interface Props {
error: Error | string;

View file

@ -20,8 +20,8 @@ import React from 'react';
import classNames from 'classnames';
import { EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui';
import { FieldIcon, FieldIconProps } from '../../../../../../../../../plugins/kibana_react/public';
import { shortenDottedString } from '../../../helpers';
import { FieldIcon, FieldIconProps } from '../../../../kibana_react/public';
import { shortenDottedString } from '../../helpers';
import { getFieldTypeName } from './field_type_name';
// property field is provided at discover's field chooser

View file

@ -21,52 +21,52 @@ import { i18n } from '@kbn/i18n';
export function getFieldTypeName(type: string) {
switch (type) {
case 'boolean':
return i18n.translate('kbn.discover.fieldNameIcons.booleanAriaLabel', {
return i18n.translate('discover.fieldNameIcons.booleanAriaLabel', {
defaultMessage: 'Boolean field',
});
case 'conflict':
return i18n.translate('kbn.discover.fieldNameIcons.conflictFieldAriaLabel', {
return i18n.translate('discover.fieldNameIcons.conflictFieldAriaLabel', {
defaultMessage: 'Conflicting field',
});
case 'date':
return i18n.translate('kbn.discover.fieldNameIcons.dateFieldAriaLabel', {
return i18n.translate('discover.fieldNameIcons.dateFieldAriaLabel', {
defaultMessage: 'Date field',
});
case 'geo_point':
return i18n.translate('kbn.discover.fieldNameIcons.geoPointFieldAriaLabel', {
return i18n.translate('discover.fieldNameIcons.geoPointFieldAriaLabel', {
defaultMessage: 'Geo point field',
});
case 'geo_shape':
return i18n.translate('kbn.discover.fieldNameIcons.geoShapeFieldAriaLabel', {
return i18n.translate('discover.fieldNameIcons.geoShapeFieldAriaLabel', {
defaultMessage: 'Geo shape field',
});
case 'ip':
return i18n.translate('kbn.discover.fieldNameIcons.ipAddressFieldAriaLabel', {
return i18n.translate('discover.fieldNameIcons.ipAddressFieldAriaLabel', {
defaultMessage: 'IP address field',
});
case 'murmur3':
return i18n.translate('kbn.discover.fieldNameIcons.murmur3FieldAriaLabel', {
return i18n.translate('discover.fieldNameIcons.murmur3FieldAriaLabel', {
defaultMessage: 'Murmur3 field',
});
case 'number':
return i18n.translate('kbn.discover.fieldNameIcons.numberFieldAriaLabel', {
return i18n.translate('discover.fieldNameIcons.numberFieldAriaLabel', {
defaultMessage: 'Number field',
});
case 'source':
// Note that this type is currently not provided, type for _source is undefined
return i18n.translate('kbn.discover.fieldNameIcons.sourceFieldAriaLabel', {
return i18n.translate('discover.fieldNameIcons.sourceFieldAriaLabel', {
defaultMessage: 'Source field',
});
case 'string':
return i18n.translate('kbn.discover.fieldNameIcons.stringFieldAriaLabel', {
return i18n.translate('discover.fieldNameIcons.stringFieldAriaLabel', {
defaultMessage: 'String field',
});
case 'nested':
return i18n.translate('kbn.discover.fieldNameIcons.nestedFieldAriaLabel', {
return i18n.translate('discover.fieldNameIcons.nestedFieldAriaLabel', {
defaultMessage: 'Nested field',
});
default:
return i18n.translate('kbn.discover.fieldNameIcons.unknownFieldAriaLabel', {
return i18n.translate('discover.fieldNameIcons.unknownFieldAriaLabel', {
defaultMessage: 'Unknown field',
});
}

View file

@ -19,7 +19,7 @@
import React from 'react';
import { shallow } from 'enzyme';
import { JsonCodeBlock } from './json_code_block';
import { IndexPattern } from '../../../kibana_services';
import { IndexPattern } from '../../../../data/public';
it('returns the `JsonCodeEditor` component', () => {
const props = {

View file

@ -22,7 +22,7 @@ import { i18n } from '@kbn/i18n';
import { DocViewRenderProps } from '../../doc_views/doc_views_types';
export function JsonCodeBlock({ hit }: DocViewRenderProps) {
const label = i18n.translate('kbn.discover.docViews.json.codeEditorAriaLabel', {
const label = i18n.translate('discover.docViews.json.codeEditorAriaLabel', {
defaultMessage: 'Read only JSON view of an elasticsearch document',
});
return (

View file

@ -21,10 +21,7 @@ import { mount } from 'enzyme';
// @ts-ignore
import { findTestSubject } from '@elastic/eui/lib/test';
import { DocViewTable } from './table';
import { IndexPattern, indexPatterns } from '../../../kibana_services';
jest.mock('ui/new_platform');
import { indexPatterns, IndexPattern } from '../../../../data/public';
const indexPattern = {
fields: [

View file

@ -26,7 +26,7 @@ import { DocViewTableRowBtnCollapse } from './table_row_btn_collapse';
import { DocViewTableRowBtnFilterExists } from './table_row_btn_filter_exists';
import { DocViewTableRowIconNoMapping } from './table_row_icon_no_mapping';
import { DocViewTableRowIconUnderscore } from './table_row_icon_underscore';
import { FieldName } from '../../angular/directives/field_name/field_name';
import { FieldName } from '../field_name/field_name';
export interface Props {
field: string;

View file

@ -26,7 +26,7 @@ export interface Props {
}
export function DocViewTableRowBtnCollapse({ onClick, isCollapsed }: Props) {
const label = i18n.translate('kbn.discover.docViews.table.toggleFieldDetails', {
const label = i18n.translate('discover.docViews.table.toggleFieldDetails', {
defaultMessage: 'Toggle field details',
});
return (

View file

@ -29,12 +29,12 @@ export interface Props {
export function DocViewTableRowBtnFilterAdd({ onClick, disabled = false }: Props) {
const tooltipContent = disabled ? (
<FormattedMessage
id="kbn.discover.docViews.table.unindexedFieldsCanNotBeSearchedTooltip"
id="discover.docViews.table.unindexedFieldsCanNotBeSearchedTooltip"
defaultMessage="Unindexed fields can not be searched"
/>
) : (
<FormattedMessage
id="kbn.discover.docViews.table.filterForValueButtonTooltip"
id="discover.docViews.table.filterForValueButtonTooltip"
defaultMessage="Filter for value"
/>
);
@ -42,7 +42,7 @@ export function DocViewTableRowBtnFilterAdd({ onClick, disabled = false }: Props
return (
<EuiToolTip content={tooltipContent}>
<EuiButtonIcon
aria-label={i18n.translate('kbn.discover.docViews.table.filterForValueButtonAriaLabel', {
aria-label={i18n.translate('discover.docViews.table.filterForValueButtonAriaLabel', {
defaultMessage: 'Filter for value',
})}
className="kbnDocViewer__actionButton"

View file

@ -35,18 +35,18 @@ export function DocViewTableRowBtnFilterExists({
const tooltipContent = disabled ? (
scripted ? (
<FormattedMessage
id="kbn.discover.docViews.table.unableToFilterForPresenceOfScriptedFieldsTooltip"
id="discover.docViews.table.unableToFilterForPresenceOfScriptedFieldsTooltip"
defaultMessage="Unable to filter for presence of scripted fields"
/>
) : (
<FormattedMessage
id="kbn.discover.docViews.table.unableToFilterForPresenceOfMetaFieldsTooltip"
id="discover.docViews.table.unableToFilterForPresenceOfMetaFieldsTooltip"
defaultMessage="Unable to filter for presence of meta fields"
/>
)
) : (
<FormattedMessage
id="kbn.discover.docViews.table.filterForFieldPresentButtonTooltip"
id="discover.docViews.table.filterForFieldPresentButtonTooltip"
defaultMessage="Filter for field present"
/>
);
@ -54,12 +54,9 @@ export function DocViewTableRowBtnFilterExists({
return (
<EuiToolTip content={tooltipContent}>
<EuiButtonIcon
aria-label={i18n.translate(
'kbn.discover.docViews.table.filterForFieldPresentButtonAriaLabel',
{
defaultMessage: 'Filter for field present',
}
)}
aria-label={i18n.translate('discover.docViews.table.filterForFieldPresentButtonAriaLabel', {
defaultMessage: 'Filter for field present',
})}
onClick={onClick}
className="kbnDocViewer__actionButton"
data-test-subj="addExistsFilterButton"

View file

@ -29,12 +29,12 @@ export interface Props {
export function DocViewTableRowBtnFilterRemove({ onClick, disabled = false }: Props) {
const tooltipContent = disabled ? (
<FormattedMessage
id="kbn.discover.docViews.table.unindexedFieldsCanNotBeSearchedTooltip"
id="discover.docViews.table.unindexedFieldsCanNotBeSearchedTooltip"
defaultMessage="Unindexed fields can not be searched"
/>
) : (
<FormattedMessage
id="kbn.discover.docViews.table.filterOutValueButtonTooltip"
id="discover.docViews.table.filterOutValueButtonTooltip"
defaultMessage="Filter out value"
/>
);
@ -42,7 +42,7 @@ export function DocViewTableRowBtnFilterRemove({ onClick, disabled = false }: Pr
return (
<EuiToolTip content={tooltipContent}>
<EuiButtonIcon
aria-label={i18n.translate('kbn.discover.docViews.table.filterOutValueButtonAriaLabel', {
aria-label={i18n.translate('discover.docViews.table.filterOutValueButtonAriaLabel', {
defaultMessage: 'Filter out value',
})}
className="kbnDocViewer__actionButton"

View file

@ -31,12 +31,9 @@ export function DocViewTableRowBtnToggleColumn({ onClick, active, disabled = fal
if (disabled) {
return (
<EuiButtonIcon
aria-label={i18n.translate(
'kbn.discover.docViews.table.toggleColumnInTableButtonAriaLabel',
{
defaultMessage: 'Toggle column in table',
}
)}
aria-label={i18n.translate('discover.docViews.table.toggleColumnInTableButtonAriaLabel', {
defaultMessage: 'Toggle column in table',
})}
className="kbnDocViewer__actionButton"
data-test-subj="toggleColumnButton"
disabled
@ -49,18 +46,15 @@ export function DocViewTableRowBtnToggleColumn({ onClick, active, disabled = fal
<EuiToolTip
content={
<FormattedMessage
id="kbn.discover.docViews.table.toggleColumnInTableButtonTooltip"
id="discover.docViews.table.toggleColumnInTableButtonTooltip"
defaultMessage="Toggle column in table"
/>
}
>
<EuiButtonIcon
aria-label={i18n.translate(
'kbn.discover.docViews.table.toggleColumnInTableButtonAriaLabel',
{
defaultMessage: 'Toggle column in table',
}
)}
aria-label={i18n.translate('discover.docViews.table.toggleColumnInTableButtonAriaLabel', {
defaultMessage: 'Toggle column in table',
})}
aria-pressed={active}
onClick={onClick}
className="kbnDocViewer__actionButton"

View file

@ -21,14 +21,11 @@ import { EuiIconTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
export function DocViewTableRowIconNoMapping() {
const ariaLabel = i18n.translate(
'kbn.discover.docViews.table.noCachedMappingForThisFieldAriaLabel',
{
defaultMessage: 'Warning',
}
);
const ariaLabel = i18n.translate('discover.docViews.table.noCachedMappingForThisFieldAriaLabel', {
defaultMessage: 'Warning',
});
const tooltipContent = i18n.translate(
'kbn.discover.docViews.table.noCachedMappingForThisFieldTooltip',
'discover.docViews.table.noCachedMappingForThisFieldTooltip',
{
defaultMessage:
'No cached mapping for this field. Refresh field list from the Management > Index Patterns page',

View file

@ -22,13 +22,13 @@ import { i18n } from '@kbn/i18n';
export function DocViewTableRowIconUnderscore() {
const ariaLabel = i18n.translate(
'kbn.discover.docViews.table.fieldNamesBeginningWithUnderscoreUnsupportedAriaLabel',
'discover.docViews.table.fieldNamesBeginningWithUnderscoreUnsupportedAriaLabel',
{
defaultMessage: 'Warning',
}
);
const tooltipContent = i18n.translate(
'kbn.discover.docViews.table.fieldNamesBeginningWithUnderscoreUnsupportedTooltip',
'discover.docViews.table.fieldNamesBeginningWithUnderscoreUnsupportedTooltip',
{
defaultMessage: 'Field names beginning with {underscoreSign} are not supported',
values: { underscoreSign: '_' },

View file

@ -23,8 +23,11 @@ import { DocView, DocViewInput, ElasticSearchHit, DocViewInputFn } from './doc_v
export class DocViewsRegistry {
private docViews: DocView[] = [];
private angularInjectorGetter: (() => Promise<auto.IInjectorService>) | null = null;
constructor(private getInjector: () => Promise<auto.IInjectorService>) {}
setAngularInjectorGetter(injectorGetter: () => Promise<auto.IInjectorService>) {
this.angularInjectorGetter = injectorGetter;
}
/**
* Extends and adds the given doc view to the registry array
@ -33,7 +36,12 @@ export class DocViewsRegistry {
const docView = typeof docViewRaw === 'function' ? docViewRaw() : docViewRaw;
if (docView.directive) {
// convert angular directive to render function for backwards compatibility
docView.render = convertDirectiveToRenderFn(docView.directive, this.getInjector);
docView.render = convertDirectiveToRenderFn(docView.directive, () => {
if (!this.angularInjectorGetter) {
throw new Error('Angular was not initialized');
}
return this.angularInjectorGetter();
});
}
if (typeof docView.shouldShow !== 'function') {
docView.shouldShow = () => true;

View file

@ -18,10 +18,10 @@
*/
import { ComponentType } from 'react';
import { IScope } from 'angular';
import { IndexPattern } from '../../kibana_services';
import { IndexPattern } from '../../../data/public';
export interface AngularDirective {
controller: (scope: AngularScope) => void;
controller: (...injectedServices: any[]) => void;
template: string;
}
@ -51,13 +51,14 @@ export interface DocViewRenderProps {
onAddColumn?: (columnName: string) => void;
onRemoveColumn?: (columnName: string) => void;
}
export type DocViewerComponent = ComponentType<DocViewRenderProps>;
export type DocViewRenderFn = (
domeNode: HTMLDivElement,
renderProps: DocViewRenderProps
) => () => void;
export interface DocViewInput {
component?: ComponentType<DocViewRenderProps>;
component?: DocViewerComponent;
directive?: AngularDirective;
order: number;
render?: DocViewRenderFn;

View file

@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
export { shortenDottedString } from './shorten_dotted_string';

View file

@ -0,0 +1,26 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
const DOT_PREFIX_RE = /(.).+?\./g;
/**
* Convert a dot.notated.string into a short
* version (d.n.string)
*/
export const shortenDottedString = (input: string) => input.replace(DOT_PREFIX_RE, '$1.');

View file

@ -0,0 +1 @@
@import 'components/index';

View file

@ -17,5 +17,18 @@
* under the License.
*/
import { DiscoverPlugin } from './plugin';
export { DiscoverSetup, DiscoverStart } from './plugin';
export { DocViewTable } from './components/table/table';
export { JsonCodeBlock } from './components/json_code_block/json_code_block';
export { DocViewInput, DocViewInputFn, DocViewerComponent } from './doc_views/doc_views_types';
export { FieldName } from './components/field_name/field_name';
export * from './doc_views/doc_views_types';
export function plugin() {
return new DiscoverPlugin();
}
export { createSavedSearchesLoader } from './saved_searches/saved_searches';
export { SavedSearchLoader, SavedSearch } from './saved_searches/types';

View file

@ -0,0 +1,47 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { DiscoverSetup, DiscoverStart } from '.';
export type Setup = jest.Mocked<DiscoverSetup>;
export type Start = jest.Mocked<DiscoverStart>;
const createSetupContract = (): Setup => {
const setupContract: Setup = {
docViews: {
addDocView: jest.fn(),
setAngularInjectorGetter: jest.fn(),
},
};
return setupContract;
};
const createStartContract = (): Start => {
const startContract: Start = {
docViews: {
DocViewer: jest.fn(() => null),
},
};
return startContract;
};
export const discoverPluginMock = {
createSetupContract,
createStartContract,
};

View file

@ -0,0 +1,110 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
import { i18n } from '@kbn/i18n';
import { auto } from 'angular';
import { CoreSetup, Plugin } from 'kibana/public';
import { DocViewInput, DocViewInputFn, DocViewRenderProps } from './doc_views/doc_views_types';
import { DocViewsRegistry } from './doc_views/doc_views_registry';
import { DocViewTable } from './components/table/table';
import { JsonCodeBlock } from './components/json_code_block/json_code_block';
import { DocViewer } from './components/doc_viewer/doc_viewer';
import { setDocViewsRegistry } from './services';
import './index.scss';
/**
* @public
*/
export interface DiscoverSetup {
docViews: {
/**
* Add new doc view shown along with table view and json view in the details of each document in Discover.
* Both react and angular doc views are supported.
* @param docViewRaw
*/
addDocView(docViewRaw: DocViewInput | DocViewInputFn): void;
/**
* Set the angular injector for bootstrapping angular doc views. This is only exposed temporarily to aid
* migration to the new platform and will be removed soon.
* @deprecated
* @param injectorGetter
*/
setAngularInjectorGetter(injectorGetter: () => Promise<auto.IInjectorService>): void;
};
}
/**
* @public
*/
export interface DiscoverStart {
docViews: {
/**
* Component rendering all the doc views for a given document.
* This is only exposed temporarily to aid migration to the new platform and will be removed soon.
* @deprecated
*/
DocViewer: React.ComponentType<DocViewRenderProps>;
};
}
/**
* Contains Discover, one of the oldest parts of Kibana
* There are 2 kinds of Angular bootstrapped for rendering, additionally to the main Angular
* Discover provides embeddables, those contain a slimmer Angular
*/
export class DiscoverPlugin implements Plugin<DiscoverSetup, DiscoverStart> {
private docViewsRegistry: DocViewsRegistry | null = null;
setup(core: CoreSetup): DiscoverSetup {
this.docViewsRegistry = new DocViewsRegistry();
setDocViewsRegistry(this.docViewsRegistry);
this.docViewsRegistry.addDocView({
title: i18n.translate('discover.docViews.table.tableTitle', {
defaultMessage: 'Table',
}),
order: 10,
component: DocViewTable,
});
this.docViewsRegistry.addDocView({
title: i18n.translate('discover.docViews.json.jsonTitle', {
defaultMessage: 'JSON',
}),
order: 20,
component: JsonCodeBlock,
});
return {
docViews: {
addDocView: this.docViewsRegistry.addDocView.bind(this.docViewsRegistry),
setAngularInjectorGetter: this.docViewsRegistry.setAngularInjectorGetter.bind(
this.docViewsRegistry
),
},
};
}
start() {
return {
docViews: {
DocViewer,
},
};
}
}

View file

@ -16,7 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
import { createSavedObjectClass, SavedObjectKibanaServices } from '../../../saved_objects/public';
import {
createSavedObjectClass,
SavedObject,
SavedObjectKibanaServices,
} from '../../../saved_objects/public';
export function createSavedSearchClass(services: SavedObjectKibanaServices) {
const SavedObjectClass = createSavedObjectClass(services);
@ -66,5 +70,5 @@ export function createSavedSearchClass(services: SavedObjectKibanaServices) {
}
}
return SavedSearch;
return SavedSearch as new (id: string) => SavedObject;
}

View file

@ -0,0 +1,25 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { createGetterSetter } from '../../kibana_utils/common';
import { DocViewsRegistry } from './doc_views/doc_views_registry';
export const [getDocViewsRegistry, setDocViewsRegistry] = createGetterSetter<DocViewsRegistry>(
'DocViewsRegistry'
);

View file

@ -39,6 +39,7 @@ export default async function({ readConfigFile }) {
require.resolve('./test_suites/core_plugins'),
require.resolve('./test_suites/management'),
require.resolve('./test_suites/bfetch_explorer'),
require.resolve('./test_suites/doc_views'),
],
services: {
...functionalConfig.get('services'),

View file

@ -0,0 +1,8 @@
{
"id": "docViewPlugin",
"version": "0.0.1",
"kibanaVersion": "kibana",
"server": false,
"ui": true,
"requiredPlugins": ["discover"]
}

View file

@ -0,0 +1,17 @@
{
"name": "docViewPlugin",
"version": "1.0.0",
"main": "target/test/plugin_functional/plugins/doc_views_plugin",
"kibana": {
"version": "kibana",
"templateVersion": "1.0.0"
},
"license": "Apache-2.0",
"scripts": {
"kbn": "node ../../../../scripts/kbn.js",
"build": "rm -rf './target' && tsc"
},
"devDependencies": {
"typescript": "3.7.2"
}
}

View file

@ -0,0 +1,22 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { DocViewsPlugin } from './plugin';
export const plugin = () => new DocViewsPlugin();

View file

@ -0,0 +1,60 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import angular from 'angular';
import React from 'react';
import { Plugin, CoreSetup } from 'kibana/public';
import { DiscoverSetup } from '../../../../../src/plugins/discover/public';
angular.module('myDocView', []).directive('myHit', () => ({
restrict: 'E',
scope: {
hit: '=hit',
},
template: '<h1 data-test-subj="angular-docview">{{hit._index}}</h1>',
}));
function MyHit(props: { index: string }) {
return <h1 data-test-subj="react-docview">{props.index}</h1>;
}
export class DocViewsPlugin implements Plugin<void, void> {
public setup(core: CoreSetup, { discover }: { discover: DiscoverSetup }) {
discover.docViews.addDocView({
directive: {
controller: function MyController($injector: any) {
$injector.loadNewModules(['myDocView']);
},
template: `<my-hit hit="hit"></my-hit>`,
},
order: 1,
title: 'Angular doc view',
});
discover.docViews.addDocView({
component: props => {
return <MyHit index={props.hit._index as string} />;
},
order: 2,
title: 'React doc view',
});
}
public start() {}
}

View file

@ -0,0 +1,14 @@
{
"extends": "../../../../tsconfig.json",
"compilerOptions": {
"outDir": "./target",
"skipLibCheck": true
},
"include": [
"index.ts",
"public/**/*.ts",
"public/**/*.tsx",
"../../../../typings/**/*"
],
"exclude": []
}

View file

@ -0,0 +1,57 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import expect from '@kbn/expect';
import { PluginFunctionalProviderContext } from '../../services';
// eslint-disable-next-line import/no-default-export
export default function({ getService, getPageObjects }: PluginFunctionalProviderContext) {
const testSubjects = getService('testSubjects');
const find = getService('find');
const PageObjects = getPageObjects(['common', 'discover', 'timePicker']);
describe('custom doc views', function() {
before(async () => {
await PageObjects.common.navigateToApp('discover');
await PageObjects.timePicker.setDefaultAbsoluteRange();
});
it('should show custom doc views', async () => {
await testSubjects.click('docTableExpandToggleColumn');
const angularTab = await find.byButtonText('Angular doc view');
const reactTab = await find.byButtonText('React doc view');
expect(await angularTab.isDisplayed()).to.be(true);
expect(await reactTab.isDisplayed()).to.be(true);
});
it('should render angular doc view', async () => {
const angularTab = await find.byButtonText('Angular doc view');
await angularTab.click();
const angularContent = await testSubjects.find('angular-docview');
expect(await angularContent.getVisibleText()).to.be('logstash-2015.09.22');
});
it('should render react doc view', async () => {
const reactTab = await find.byButtonText('React doc view');
await reactTab.click();
const reactContent = await testSubjects.find('react-docview');
expect(await reactContent.getVisibleText()).to.be('logstash-2015.09.22');
});
});
}

View file

@ -0,0 +1,31 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { PluginFunctionalProviderContext } from '../../services';
export default function({ getService, loadTestFile }: PluginFunctionalProviderContext) {
const esArchiver = getService('esArchiver');
describe('doc views', function() {
before(async () => {
await esArchiver.loadIfNeeded('../functional/fixtures/es_archiver/discover');
});
loadTestFile(require.resolve('./doc_views'));
});
}

View file

@ -464,6 +464,17 @@
"data.search.searchBar.savedQueryPopoverSavedQueryListItemDescriptionAriaLabel": "{savedQueryName} の説明",
"data.search.searchBar.savedQueryPopoverSavedQueryListItemSelectedButtonAriaLabel": "選択されたクエリボタン {savedQueryName} を保存しました。変更を破棄するには押してください。",
"data.search.searchBar.savedQueryPopoverTitleText": "保存されたクエリ",
"discover.fieldNameIcons.booleanAriaLabel": "ブールフィールド",
"discover.fieldNameIcons.conflictFieldAriaLabel": "矛盾フィールド",
"discover.fieldNameIcons.dateFieldAriaLabel": "日付フィールド",
"discover.fieldNameIcons.geoPointFieldAriaLabel": "地理ポイント",
"discover.fieldNameIcons.geoShapeFieldAriaLabel": "地理情報図形",
"discover.fieldNameIcons.ipAddressFieldAriaLabel": "IP アドレスフィールド",
"discover.fieldNameIcons.murmur3FieldAriaLabel": "Murmur3 フィールド",
"discover.fieldNameIcons.numberFieldAriaLabel": "数値フィールド",
"discover.fieldNameIcons.sourceFieldAriaLabel": "ソースフィールド",
"discover.fieldNameIcons.stringFieldAriaLabel": "文字列フィールド",
"discover.fieldNameIcons.unknownFieldAriaLabel": "不明なフィールド",
"charts.colormaps.bluesText": "青",
"charts.colormaps.greensText": "緑",
"charts.colormaps.greenToRedText": "緑から赤",
@ -1075,17 +1086,6 @@
"kbn.discover.fieldChooser.searchPlaceHolder": "検索フィールド",
"kbn.discover.fieldChooser.toggleFieldFilterButtonHideAriaLabel": "フィールド設定を非表示",
"kbn.discover.fieldChooser.toggleFieldFilterButtonShowAriaLabel": "フィールド設定を表示",
"kbn.discover.fieldNameIcons.booleanAriaLabel": "ブールフィールド",
"kbn.discover.fieldNameIcons.conflictFieldAriaLabel": "矛盾フィールド",
"kbn.discover.fieldNameIcons.dateFieldAriaLabel": "日付フィールド",
"kbn.discover.fieldNameIcons.geoPointFieldAriaLabel": "地理ポイント",
"kbn.discover.fieldNameIcons.geoShapeFieldAriaLabel": "地理情報図形",
"kbn.discover.fieldNameIcons.ipAddressFieldAriaLabel": "IP アドレスフィールド",
"kbn.discover.fieldNameIcons.murmur3FieldAriaLabel": "Murmur3 フィールド",
"kbn.discover.fieldNameIcons.numberFieldAriaLabel": "数値フィールド",
"kbn.discover.fieldNameIcons.sourceFieldAriaLabel": "ソースフィールド",
"kbn.discover.fieldNameIcons.stringFieldAriaLabel": "文字列フィールド",
"kbn.discover.fieldNameIcons.unknownFieldAriaLabel": "不明なフィールド",
"kbn.discover.histogram.partialData.bucketTooltipText": "選択された時間範囲にはこのバケット全体は含まれていませんが、一部データが含まれている可能性があります。",
"kbn.discover.histogramOfFoundDocumentsAriaLabel": "発見されたドキュメントのヒストグラム",
"kbn.discover.hitsPluralTitle": "{hits, plural, one {ヒット} other {ヒット}}",

View file

@ -464,6 +464,17 @@
"data.search.searchBar.savedQueryPopoverSavedQueryListItemDescriptionAriaLabel": "{savedQueryName} 描述",
"data.search.searchBar.savedQueryPopoverSavedQueryListItemSelectedButtonAriaLabel": "已保存查询按钮已选择 {savedQueryName}。按下可清除任何更改。",
"data.search.searchBar.savedQueryPopoverTitleText": "已保存查询",
"discover.fieldNameIcons.booleanAriaLabel": "布尔字段",
"discover.fieldNameIcons.conflictFieldAriaLabel": "冲突字段",
"discover.fieldNameIcons.dateFieldAriaLabel": "日期字段",
"discover.fieldNameIcons.geoPointFieldAriaLabel": "地理位置点字段",
"discover.fieldNameIcons.geoShapeFieldAriaLabel": "几何形状字段",
"discover.fieldNameIcons.ipAddressFieldAriaLabel": "IP 地址字段",
"discover.fieldNameIcons.murmur3FieldAriaLabel": "Murmur3 字段",
"discover.fieldNameIcons.numberFieldAriaLabel": "数字字段",
"discover.fieldNameIcons.sourceFieldAriaLabel": "源字段",
"discover.fieldNameIcons.stringFieldAriaLabel": "字符串字段",
"discover.fieldNameIcons.unknownFieldAriaLabel": "未知字段",
"charts.colormaps.bluesText": "蓝色",
"charts.colormaps.greensText": "绿色",
"charts.colormaps.greenToRedText": "绿到红",
@ -1075,17 +1086,6 @@
"kbn.discover.fieldChooser.searchPlaceHolder": "搜索字段",
"kbn.discover.fieldChooser.toggleFieldFilterButtonHideAriaLabel": "隐藏字段设置",
"kbn.discover.fieldChooser.toggleFieldFilterButtonShowAriaLabel": "显示字段设置",
"kbn.discover.fieldNameIcons.booleanAriaLabel": "布尔字段",
"kbn.discover.fieldNameIcons.conflictFieldAriaLabel": "冲突字段",
"kbn.discover.fieldNameIcons.dateFieldAriaLabel": "日期字段",
"kbn.discover.fieldNameIcons.geoPointFieldAriaLabel": "地理位置点字段",
"kbn.discover.fieldNameIcons.geoShapeFieldAriaLabel": "几何形状字段",
"kbn.discover.fieldNameIcons.ipAddressFieldAriaLabel": "IP 地址字段",
"kbn.discover.fieldNameIcons.murmur3FieldAriaLabel": "Murmur3 字段",
"kbn.discover.fieldNameIcons.numberFieldAriaLabel": "数字字段",
"kbn.discover.fieldNameIcons.sourceFieldAriaLabel": "源字段",
"kbn.discover.fieldNameIcons.stringFieldAriaLabel": "字符串字段",
"kbn.discover.fieldNameIcons.unknownFieldAriaLabel": "未知字段",
"kbn.discover.histogram.partialData.bucketTooltipText": "选定的时间范围不包括此整个存储桶,其可能包含部分数据。",
"kbn.discover.histogramOfFoundDocumentsAriaLabel": "已找到文档的直方图",
"kbn.discover.hitsPluralTitle": "{hits, plural, one {次命中} other {次命中}}",