Clean up top nav \ search bar \ query bar directives (#41636) (#41761)

* Move timepicker (to be deprecated) into old kbn_top_nav

* Deleted search-bar and query-bar directives!

* moved search bar to kibana_react (it's a generic react component, not a service)

* translations

* Moved superDatePicker directive to kbn_top_nav (to be deprecated)
Deleted unused react_component directives call-out and tool-bar-search-box

* TS test fix

* Delete relative options
This commit is contained in:
Liza Katz 2019-07-23 16:59:23 +03:00 committed by GitHub
parent b6093548df
commit 44a574bcff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 50 additions and 317 deletions

View file

@ -2,6 +2,7 @@
"paths": {
"common.ui": "src/legacy/ui",
"data": "src/legacy/core_plugins/data",
"kibana_react": "src/legacy/core_plugins/kibana_react",
"server": "src/legacy/server",
"console": "src/legacy/core_plugins/console",
"core": "src/core",

View file

@ -18,3 +18,5 @@
*/
export { FilterService, FilterSetup } from './filter_service';
export { FilterBar } from './filter_bar';

View file

@ -24,7 +24,6 @@
// @ts-ignore
import { renderersRegistry } from 'plugins/interpreter/registries';
import { ExpressionsService, ExpressionsSetup } from './expressions';
import { SearchService, SearchSetup } from './search';
import { QueryService, QuerySetup } from './query';
import { FilterService, FilterSetup } from './filter';
import { IndexPatternsService, IndexPatternsSetup } from './index_patterns';
@ -34,14 +33,12 @@ export class DataPlugin {
private readonly expressions: ExpressionsService;
private readonly filter: FilterService;
private readonly indexPatterns: IndexPatternsService;
private readonly search: SearchService;
private readonly query: QueryService;
constructor() {
this.indexPatterns = new IndexPatternsService();
this.filter = new FilterService();
this.query = new QueryService();
this.search = new SearchService();
this.expressions = new ExpressionsService();
}
@ -61,7 +58,6 @@ export class DataPlugin {
filter: this.filter.setup({
indexPatterns: indexPatternsService.indexPatterns,
}),
search: this.search.setup(),
query: this.query.setup(),
};
}
@ -70,7 +66,6 @@ export class DataPlugin {
this.expressions.stop();
this.indexPatterns.stop();
this.filter.stop();
this.search.stop();
this.query.stop();
}
}
@ -80,7 +75,6 @@ export interface DataSetup {
expressions: ExpressionsSetup;
indexPatterns: IndexPatternsSetup;
filter: FilterSetup;
search: SearchSetup;
query: QuerySetup;
}
@ -89,8 +83,8 @@ export { ExpressionRenderer, ExpressionRendererProps, ExpressionRunner } from '.
/** @public types */
export { IndexPattern, StaticIndexPattern, StaticIndexPatternField, Field } from './index_patterns';
export { Query } from './query';
export { SearchBar, SearchBarProps } from './search';
export { Query, QueryBar } from './query';
export { FilterBar } from './filter';
export { FilterManager, FilterStateManager, uniqFilters } from './filter/filter_manager';
/** @public static code */

View file

@ -17,4 +17,4 @@
* under the License.
*/
export { QueryService, QuerySetup, Query } from './query_service';
export * from './query_service';

View file

@ -1,38 +0,0 @@
/*
* 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 'ngreact';
import { wrapInI18nContext } from 'ui/i18n';
import { uiModules } from 'ui/modules';
import { QueryBar } from '../components';
const app = uiModules.get('app/data', ['react']);
export function setupDirective() {
app.directive('queryBar', (reactDirective, localStorage) => {
return reactDirective(
wrapInI18nContext(QueryBar),
undefined,
{},
{
store: localStorage,
}
);
});
}

View file

@ -22,7 +22,4 @@ export { fromUser } from './lib/from_user';
export { toUser } from './lib/to_user';
export { getQueryLog } from './lib/get_query_log';
// @ts-ignore
export { setupDirective } from './directive';
export { Query } from '../../../../../../plugins/data/common/query/types';

View file

@ -17,15 +17,7 @@
* under the License.
*/
import { once } from 'lodash';
import {
QueryBar,
QueryBarInput,
fromUser,
toUser,
getQueryLog,
setupDirective as setupQueryBarDirective,
} from './query_bar';
import { QueryBar, QueryBarInput, fromUser, toUser, getQueryLog } from './query_bar';
/**
* Query Service
@ -35,7 +27,6 @@ import {
export class QueryService {
public setup() {
return {
loadLegacyDirectives: once(setupQueryBarDirective),
helpers: {
fromUser,
toUser,
@ -56,4 +47,4 @@ export class QueryService {
/** @public */
export type QuerySetup = ReturnType<QueryService['setup']>;
export { Query } from './query_bar';
export { Query, QueryBar } from './query_bar';

View file

@ -1,22 +0,0 @@
/*
* 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 { SearchService, SearchSetup } from './search_service';
export * from './search_bar';

View file

@ -1,61 +0,0 @@
/*
* 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 'ngreact';
import { wrapInI18nContext } from 'ui/i18n';
import { uiModules } from 'ui/modules';
import { SearchBar } from '../components';
const app = uiModules.get('app/data', ['react']);
export function setupDirective() {
app.directive('searchBar', (reactDirective, localStorage) => {
return reactDirective(
wrapInI18nContext(SearchBar),
[
['query', { watchDepth: 'reference' }],
['store', { watchDepth: 'reference' }],
['intl', { watchDepth: 'reference' }],
['onQuerySubmit', { watchDepth: 'reference' }],
['onFiltersUpdated', { watchDepth: 'reference' }],
['onRefreshChange', { watchDepth: 'reference' }],
['indexPatterns', { watchDepth: 'collection' }],
['filters', { watchDepth: 'collection' }],
'appName',
'screenTitle',
'showFilterBar',
'showQueryBar',
'showDatePicker',
'dateRangeFrom',
'dateRangeTo',
'isRefreshPaused',
'refreshInterval',
'disableAutoFocus',
'showAutoRefreshOnly',
],
{},
{
store: localStorage,
},
);
});
}

View file

@ -1,43 +0,0 @@
/*
* 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 { once } from 'lodash';
import { SearchBar, setupDirective as setupSearchBarDirective } from './search_bar';
/**
* Search Service
* @internal
*/
export class SearchService {
public setup() {
return {
ui: {
SearchBar,
},
loadLegacyDirectives: once(setupSearchBarDirective),
};
}
public stop() {
// nothing to do here yet
}
}
/** @public */
export type SearchSetup = ReturnType<SearchService['setup']>;

View file

@ -40,7 +40,6 @@ import { uiModules } from 'ui/modules';
import 'ui/capabilities/route_setup';
import { data } from 'plugins/data/setup';
data.search.loadLegacyDirectives();
data.filter.loadLegacyDirectives();
const app = uiModules.get('app/dashboard', [

View file

@ -71,9 +71,6 @@ import { getRootBreadcrumbs, getSavedSearchBreadcrumbs } from '../breadcrumbs';
import { buildVislibDimensions } from 'ui/visualize/loader/pipeline_helpers/build_pipeline';
import 'ui/capabilities/route_setup';
import { data } from 'plugins/data/setup';
data.search.loadLegacyDirectives();
const fetchStatuses = {
UNINITIALIZED: 'uninitialized',
LOADING: 'loading',

View file

@ -60,7 +60,6 @@ import './context';
import 'ui/vislib';
import 'ui/agg_response';
import 'ui/agg_types';
import 'ui/timepicker';
import { showAppRedirectNotification } from 'ui/notify';
import 'leaflet';

View file

@ -30,7 +30,6 @@ import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory } from 'ui/r
import { getLandingBreadcrumbs, getWizardStep1Breadcrumbs } from './breadcrumbs';
import { data } from 'plugins/data/setup';
data.search.loadLegacyDirectives();
data.filter.loadLegacyDirectives();
uiRoutes

View file

@ -24,3 +24,4 @@
/** @public types */
export { TopNavMenu, TopNavMenuData } from './top_nav_menu';
export { SearchBar, SearchBarProps } from './search_bar';

View file

@ -21,14 +21,9 @@ import React from 'react';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { SearchBar } from './search_bar';
jest.mock('../../../filter/filter_bar', () => {
jest.mock('../../../../data/public', () => {
return {
FilterBar: () => <div className="filterBar"></div>,
};
});
jest.mock('../../../query/query_bar', () => {
return {
QueryBar: () => <div className="queryBar"></div>,
};
});

View file

@ -26,9 +26,7 @@ import React, { Component } from 'react';
import ResizeObserver from 'resize-observer-polyfill';
import { Storage } from 'ui/storage';
import { IndexPattern } from '../../../index_patterns';
import { Query, QueryBar } from '../../../query/query_bar';
import { FilterBar } from '../../../filter/filter_bar';
import { IndexPattern, Query, QueryBar, FilterBar } from '../../../../data/public';
interface DateRange {
from: string;
@ -110,16 +108,16 @@ class SearchBarUI extends Component<SearchBarProps, State> {
private getFilterTriggerButton() {
const filtersAppliedText = this.props.intl.formatMessage({
id: 'data.search.searchBar.filtersButtonFiltersAppliedTitle',
id: 'kibana_react.search.searchBar.filtersButtonFiltersAppliedTitle',
defaultMessage: 'filters applied.',
});
const clickToShowOrHideText = this.state.isFiltersVisible
? this.props.intl.formatMessage({
id: 'data.search.searchBar.filtersButtonClickToShowTitle',
id: 'kibana_react.search.searchBar.filtersButtonClickToShowTitle',
defaultMessage: 'Select to hide',
})
: this.props.intl.formatMessage({
id: 'data.search.searchBar.filtersButtonClickToHideTitle',
id: 'kibana_react.search.searchBar.filtersButtonClickToHideTitle',
defaultMessage: 'Select to show',
});

View file

@ -18,6 +18,3 @@
*/
export * from './components';
// @ts-ignore
export { setupDirective } from './directive';

View file

@ -22,7 +22,7 @@ import { TopNavMenu } from './top_nav_menu';
import { TopNavMenuData } from './top_nav_menu_data';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
jest.mock('../../../../core_plugins/data/public', () => {
jest.mock('../search_bar', () => {
return {
SearchBar: () => <div className="searchBar"></div>,
SearchBarProps: {},

View file

@ -23,7 +23,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { I18nProvider } from '@kbn/i18n/react';
import { TopNavMenuData } from './top_nav_menu_data';
import { TopNavMenuItem } from './top_nav_menu_item';
import { SearchBar, SearchBarProps } from '../../../../core_plugins/data/public';
import { SearchBar, SearchBarProps } from '../search_bar';
type Props = Partial<SearchBarProps> & {
name: string;

View file

@ -18,8 +18,7 @@
*/
import moment from 'moment';
import { i18n } from '@kbn/i18n';
import { pluck, get, clone } from 'lodash';
import { relativeOptions } from '../../../../../ui/public/timepicker/relative_options';
import { get } from 'lodash';
import { GTE_INTERVAL_RE } from '../../../common/interval_regexp';
import { parseEsInterval } from '../../../../data/common/parse_es_interval';
@ -37,7 +36,8 @@ export const unitLookup = {
};
export const convertIntervalIntoUnit = (interval, hasTranslateUnitString = true) => {
const units = pluck(clone(relativeOptions).reverse(), 'value').filter(s => /^[smhdwMy]$/.test(s));
// Iterate units from biggest to smallest
const units = Object.keys(unitLookup).reverse();
const duration = moment.duration(interval, 'ms');
for (let i = 0; i < units.length; i++) {

View file

@ -55,7 +55,7 @@
import _ from 'lodash';
import angular from 'angular';
import '../timepicker';
import './timepicker';
import '../watch_multi';
import '../directives/input_focus';
import { uiModules } from '../modules';

View file

@ -17,12 +17,35 @@
* under the License.
*/
import { uiModules } from '../modules';
import { uiModules } from '../../modules';
import toggleHtml from './kbn_global_timepicker.html';
import { timefilter } from 'ui/timefilter';
import { timeHistory } from 'ui/timefilter/time_history';
import {
EuiSuperDatePicker,
} from '@elastic/eui';
uiModules
.get('kibana')
.directive('superDatePicker', reactDirective => reactDirective(EuiSuperDatePicker, [
'start',
'end',
'isPaused',
'refreshInterval',
'commonlyUsedRanges',
'dateFormat',
'recentlyUsedRanges',
'onTimeChange',
'onRefreshChange',
'isAutoRefreshOnly',
'commonlyUsedRanges',
'dateFormat',
'recentlyUsedRanges',
]));
uiModules
.get('kibana')
.directive('kbnGlobalTimepicker', (globalState, config) => {

View file

@ -19,44 +19,19 @@
import 'ngreact';
import {
KuiToolBarSearchBox,
} from '@kbn/ui-framework/components';
import {
EuiConfirmModal,
EuiIcon,
EuiIconTip,
EuiCallOut,
EuiSuperDatePicker,
} from '@elastic/eui';
import { uiModules } from './modules';
const app = uiModules.get('app/kibana', ['react']);
app.directive('toolBarSearchBox', reactDirective => reactDirective(KuiToolBarSearchBox));
app.directive('confirmModal', reactDirective => reactDirective(EuiConfirmModal));
app.directive('icon', reactDirective => reactDirective(EuiIcon));
app.directive('iconTip', reactDirective => reactDirective(EuiIconTip, ['content', 'type', 'position', 'title', 'color']));
app.directive('callOut', reactDirective => reactDirective(EuiCallOut, ['title', 'color', 'size', 'iconType', 'children']));
app.directive('superDatePicker', reactDirective => reactDirective(EuiSuperDatePicker, [
'start',
'end',
'isPaused',
'refreshInterval',
'commonlyUsedRanges',
'dateFormat',
'recentlyUsedRanges',
'onTimeChange',
'onRefreshChange',
'isAutoRefreshOnly',
'commonlyUsedRanges',
'dateFormat',
'recentlyUsedRanges',
]));

View file

@ -1,39 +0,0 @@
/*
* 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 { i18n } from '@kbn/i18n';
export const relativeOptions = [
{ text: i18n.translate('common.ui.timepicker.relOpts.secondsAgo', { defaultMessage: 'Seconds ago' }), value: 's' },
{ text: i18n.translate('common.ui.timepicker.relOpts.minutesAgo', { defaultMessage: 'Minutes ago' }), value: 'm' },
{ text: i18n.translate('common.ui.timepicker.relOpts.hoursAgo', { defaultMessage: 'Hours ago' }), value: 'h' },
{ text: i18n.translate('common.ui.timepicker.relOpts.daysAgo', { defaultMessage: 'Days ago' }), value: 'd' },
{ text: i18n.translate('common.ui.timepicker.relOpts.weeksAgo', { defaultMessage: 'Weeks ago' }), value: 'w' },
{ text: i18n.translate('common.ui.timepicker.relOpts.monthsAgo', { defaultMessage: 'Months ago' }), value: 'M' },
{ text: i18n.translate('common.ui.timepicker.relOpts.yearsAgo', { defaultMessage: 'Years ago' }), value: 'y' },
{ text: i18n.translate('common.ui.timepicker.relOpts.secondsFromNow', { defaultMessage: 'Seconds from now' }), value: 's+' },
{ text: i18n.translate('common.ui.timepicker.relOpts.minutesFromNow', { defaultMessage: 'Minutes from now' }), value: 'm+' },
{ text: i18n.translate('common.ui.timepicker.relOpts.hoursFromNow', { defaultMessage: 'Hours from now' }), value: 'h+' },
{ text: i18n.translate('common.ui.timepicker.relOpts.daysFromNow', { defaultMessage: 'Days from now' }), value: 'd+' },
{ text: i18n.translate('common.ui.timepicker.relOpts.weeksFromNow', { defaultMessage: 'Weeks from now' }), value: 'w+' },
{ text: i18n.translate('common.ui.timepicker.relOpts.monthsFromNow', { defaultMessage: 'Months from now' }), value: 'M+' },
{ text: i18n.translate('common.ui.timepicker.relOpts.yearsFromNow', { defaultMessage: 'Years from now' }), value: 'y+' },
];

View file

@ -36,7 +36,6 @@ import 'plugins/kibana/dashboard';
import 'ui/vislib';
import 'ui/agg_response';
import 'ui/agg_types';
import 'ui/timepicker';
import 'leaflet';
import { npStart } from 'ui/new_platform';

View file

@ -35,9 +35,6 @@ import mapTemplate from './angular/map.html';
import { MapListing } from './components/map_listing';
import { recentlyAccessed } from 'ui/persisted_log';
import { data } from 'plugins/data/setup';
data.query.loadLegacyDirectives();
const app = uiModules.get('app/maps', ['ngRoute', 'react']);
app.directive('mapListing', function (reactDirective) {

View file

@ -568,20 +568,6 @@
"common.ui.stateManagement.unableToParseUrlErrorMessage": "URL をパースできません",
"common.ui.stateManagement.unableToRestoreUrlErrorMessage": "URL を完全に復元できません。共有機能を使用していることを確認してください。",
"common.ui.stateManagement.unableToStoreHistoryInSessionErrorMessage": "セッションがいっぱいで安全に削除できるアイテムが見つからないため、Kibana は履歴アイテムを保存できません。\n\nこれは大抵新規タブに移動することで解決されますが、より大きな問題が原因である可能性もあります。このメッセージが定期的に表示される場合は、{gitHubIssuesUrl} で問題を報告してください。",
"common.ui.timepicker.relOpts.daysAgo": "日前",
"common.ui.timepicker.relOpts.daysFromNow": "現在からの日数",
"common.ui.timepicker.relOpts.hoursAgo": "時間前",
"common.ui.timepicker.relOpts.hoursFromNow": "現在からの時間数",
"common.ui.timepicker.relOpts.minutesAgo": "分前",
"common.ui.timepicker.relOpts.minutesFromNow": "現在からの分数",
"common.ui.timepicker.relOpts.monthsAgo": "か月前",
"common.ui.timepicker.relOpts.monthsFromNow": "現在からの月数",
"common.ui.timepicker.relOpts.secondsAgo": "秒前",
"common.ui.timepicker.relOpts.secondsFromNow": "現在からの秒数",
"common.ui.timepicker.relOpts.weeksAgo": "週間前",
"common.ui.timepicker.relOpts.weeksFromNow": "現在からの週数",
"common.ui.timepicker.relOpts.yearsAgo": "年前",
"common.ui.timepicker.relOpts.yearsFromNow": "現在からの年数",
"common.ui.topNav.closeAriaLabel": "閉じる",
"common.ui.topNav.toggleViewAriaLabel": "{optLabel} ビューを切り替える",
"common.ui.url.replacementFailedErrorMessage": "置換に失敗、未解決の表現式: {expr}",
@ -841,9 +827,9 @@
"data.query.queryBar.syntaxOptionsDescription": "{docsLink} (KQL) は、シンプルなクエリ構文とスクリプトフィールドのサポートを提供します。また、KQL はベーシックライセンス以上をご利用の場合、自動入力も提供します。KQL をオフにすると、Kibana は Lucene を使用します。",
"data.query.queryBar.syntaxOptionsDescription.docsLinkText": "こちら",
"data.query.queryBar.syntaxOptionsTitle": "構文オプション",
"data.search.searchBar.filtersButtonClickToHideTitle": "選択して表示",
"data.search.searchBar.filtersButtonClickToShowTitle": "選択して非表示",
"data.search.searchBar.filtersButtonFiltersAppliedTitle": "フィルターが適用されました。",
"kibana_react.search.searchBar.filtersButtonClickToHideTitle": "選択して表示",
"kibana_react.search.searchBar.filtersButtonClickToShowTitle": "選択して非表示",
"kibana_react.search.searchBar.filtersButtonFiltersAppliedTitle": "フィルターが適用されました。",
"embeddableApi.actionPanel.title": "オプション",
"embeddableApi.actions.applyFilterActionTitle": "現在のビューにフィルターを適用",
"embeddableApi.addPanel.createNew": "新規 {factoryName} を作成",

View file

@ -568,20 +568,6 @@
"common.ui.stateManagement.unableToParseUrlErrorMessage": "无法解析 URL",
"common.ui.stateManagement.unableToRestoreUrlErrorMessage": "无法完整还原 URL确保使用共享功能。",
"common.ui.stateManagement.unableToStoreHistoryInSessionErrorMessage": "Kibana 无法将历史记录项存储在您的会话中,因为其已满,并且似乎没有任何可安全删除的项。\n\n通常可通过移至新的标签页来解决此问题但这会导致更大的问题。如果您有规律地看到此消息请在 {gitHubIssuesUrl} 提交问题。",
"common.ui.timepicker.relOpts.daysAgo": "天前",
"common.ui.timepicker.relOpts.daysFromNow": "自现在开始的天数",
"common.ui.timepicker.relOpts.hoursAgo": "小时前",
"common.ui.timepicker.relOpts.hoursFromNow": "自现在开始的小时数",
"common.ui.timepicker.relOpts.minutesAgo": "分钟前",
"common.ui.timepicker.relOpts.minutesFromNow": "自现在开始的分钟数",
"common.ui.timepicker.relOpts.monthsAgo": "个月前",
"common.ui.timepicker.relOpts.monthsFromNow": "自现在开始的月份数",
"common.ui.timepicker.relOpts.secondsAgo": "秒前",
"common.ui.timepicker.relOpts.secondsFromNow": "自现在开始的秒数",
"common.ui.timepicker.relOpts.weeksAgo": "周前",
"common.ui.timepicker.relOpts.weeksFromNow": "自现在开始的周数",
"common.ui.timepicker.relOpts.yearsAgo": "年前",
"common.ui.timepicker.relOpts.yearsFromNow": "自现在开始的年数",
"common.ui.topNav.closeAriaLabel": "关闭",
"common.ui.topNav.toggleViewAriaLabel": "切换 {optLabel} 视图",
"common.ui.url.replacementFailedErrorMessage": "替换失败,未解析的表达式:{expr}",
@ -842,9 +828,9 @@
"data.query.queryBar.syntaxOptionsDescription": "{docsLink} (KQL) 提供简化查询语法并支持脚本字段。如果您具有基本许可或更高级别的许可KQL 还提供自动填充功能。如果关闭 KQLKibana 将使用 Lucene。",
"data.query.queryBar.syntaxOptionsDescription.docsLinkText": "此处",
"data.query.queryBar.syntaxOptionsTitle": "语法选项",
"data.search.searchBar.filtersButtonClickToHideTitle": "选择以显示",
"data.search.searchBar.filtersButtonClickToShowTitle": "选择以隐藏",
"data.search.searchBar.filtersButtonFiltersAppliedTitle": "个筛选已应用。",
"kibana_react.search.searchBar.filtersButtonClickToHideTitle": "选择以显示",
"kibana_react.search.searchBar.filtersButtonClickToShowTitle": "选择以隐藏",
"kibana_react.search.searchBar.filtersButtonFiltersAppliedTitle": "个筛选已应用。",
"embeddableApi.actionPanel.title": "选项",
"embeddableApi.actions.applyFilterActionTitle": "将筛选应用于当前视图",
"embeddableApi.addPanel.createNew": "创建新的{factoryName}",