Index pattern management UI -> TypeScript and New Platform Ready (create edit field) (#63836)

* Converted to react. Moved routes to edit_index_pattern

* Added withRouter for navigation. Fixed index_header.

* Fixed comments

* Fixed comments.

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Uladzislau Lasitsa 2020-04-20 19:03:01 +03:00 committed by GitHub
parent 784b8beb2f
commit e8c42095d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 227 additions and 192 deletions

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.
*/
export const TAB_INDEXED_FIELDS = 'indexedFields';
export const TAB_SCRIPTED_FIELDS = 'scriptedFields';
export const TAB_SOURCE_FILTERS = 'sourceFilters';

View file

@ -1,180 +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 { IndexPatternField } from '../../../../../../../../../plugins/data/public';
import { RegistryFieldFormatEditorsProvider } from 'ui/registry/field_format_editors';
import { docTitle } from 'ui/doc_title';
import { KbnUrlProvider } from 'ui/url';
import uiRoutes from 'ui/routes';
import { toastNotifications } from 'ui/notify';
import { npStart } from 'ui/new_platform';
import template from './create_edit_field.html';
import { getEditFieldBreadcrumbs, getCreateFieldBreadcrumbs } from '../../breadcrumbs';
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { FieldEditor } from 'ui/field_editor';
import { I18nContext } from 'ui/i18n';
import { i18n } from '@kbn/i18n';
import { IndexHeader } from '../index_header';
const REACT_FIELD_EDITOR_ID = 'reactFieldEditor';
const renderFieldEditor = (
$scope,
indexPattern,
field,
{ getConfig, $http, fieldFormatEditors, redirectAway }
) => {
$scope.$$postDigest(() => {
const node = document.getElementById(REACT_FIELD_EDITOR_ID);
if (!node) {
return;
}
render(
<I18nContext>
<IndexHeader indexPattern={indexPattern} />
<FieldEditor
indexPattern={indexPattern}
field={field}
helpers={{
getConfig,
$http,
fieldFormatEditors,
redirectAway,
}}
/>
</I18nContext>,
node
);
});
};
const destroyFieldEditor = () => {
const node = document.getElementById(REACT_FIELD_EDITOR_ID);
node && unmountComponentAtNode(node);
};
uiRoutes
.when('/management/kibana/index_patterns/:indexPatternId/field/:fieldName*', {
mode: 'edit',
k7Breadcrumbs: getEditFieldBreadcrumbs,
})
.when('/management/kibana/index_patterns/:indexPatternId/create-field/', {
mode: 'create',
k7Breadcrumbs: getCreateFieldBreadcrumbs,
})
.defaults(/management\/kibana\/index_patterns\/[^\/]+\/(field|create-field)(\/|$)/, {
template,
mapBreadcrumbs($route, breadcrumbs) {
const { indexPattern } = $route.current.locals;
return breadcrumbs.map(crumb => {
if (crumb.id !== indexPattern.id) {
return crumb;
}
return {
...crumb,
display: indexPattern.title,
};
});
},
resolve: {
indexPattern: function($route, Promise, redirectWhenMissing) {
const { indexPatterns } = npStart.plugins.data;
return Promise.resolve(indexPatterns.get($route.current.params.indexPatternId)).catch(
redirectWhenMissing('/management/kibana/index_patterns')
);
},
},
controllerAs: 'fieldSettings',
controller: function FieldEditorPageController(
$scope,
$route,
$timeout,
$http,
Private,
config
) {
const getConfig = (...args) => config.get(...args);
const fieldFormatEditors = Private(RegistryFieldFormatEditorsProvider);
const kbnUrl = Private(KbnUrlProvider);
this.mode = $route.current.mode;
this.indexPattern = $route.current.locals.indexPattern;
if (this.mode === 'edit') {
const fieldName = $route.current.params.fieldName;
this.field = this.indexPattern.fields.getByName(fieldName);
if (!this.field) {
const message = i18n.translate('kbn.management.editIndexPattern.scripted.noFieldLabel', {
defaultMessage:
"'{indexPatternTitle}' index pattern doesn't have a scripted field called '{fieldName}'",
values: { indexPatternTitle: this.indexPattern.title, fieldName },
});
toastNotifications.add(message);
kbnUrl.redirectToRoute(this.indexPattern, 'edit');
return;
}
} else if (this.mode === 'create') {
this.field = new IndexPatternField(this.indexPattern, {
scripted: true,
type: 'number',
});
} else {
const errorMessage = i18n.translate(
'kbn.management.editIndexPattern.scripted.unknownModeErrorMessage',
{
defaultMessage: 'unknown fieldSettings mode {mode}',
values: { mode: this.mode },
}
);
throw new Error(errorMessage);
}
const fieldName =
this.field.name ||
i18n.translate('kbn.management.editIndexPattern.scripted.newFieldPlaceholder', {
defaultMessage: 'New Scripted Field',
});
docTitle.change([fieldName, this.indexPattern.title]);
renderFieldEditor($scope, this.indexPattern, this.field, {
getConfig,
$http,
fieldFormatEditors,
redirectAway: () => {
$timeout(() => {
kbnUrl.changeToRoute(
this.indexPattern,
this.field.scripted ? 'scriptedFields' : 'indexedFields'
);
});
},
});
$scope.$on('$destroy', () => {
destroyFieldEditor();
});
},
});

View file

@ -0,0 +1,111 @@
/*
* 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 { withRouter, RouteComponentProps } from 'react-router-dom';
// @ts-ignore
import { FieldEditor } from 'ui/field_editor';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { IndexHeader } from '../index_header';
import { IndexPattern, IndexPatternField } from '../../../../../../../../../plugins/data/public';
import { ChromeDocTitle, NotificationsStart } from '../../../../../../../../../core/public';
import { TAB_SCRIPTED_FIELDS, TAB_INDEXED_FIELDS } from '../constants';
interface CreateEditFieldProps extends RouteComponentProps {
indexPattern: IndexPattern;
mode?: string;
fieldName?: string;
fieldFormatEditors: any;
getConfig: (name: string) => any;
services: {
notifications: NotificationsStart;
docTitle: ChromeDocTitle;
http: Function;
};
}
const newFieldPlaceholder = i18n.translate(
'kbn.management.editIndexPattern.scripted.newFieldPlaceholder',
{
defaultMessage: 'New Scripted Field',
}
);
export const CreateEditField = withRouter(
({
indexPattern,
mode,
fieldName,
fieldFormatEditors,
getConfig,
services,
history,
}: CreateEditFieldProps) => {
const field =
mode === 'edit' && fieldName
? indexPattern.fields.getByName(fieldName)
: new IndexPatternField(indexPattern, {
scripted: true,
type: 'number',
});
const url = `/management/kibana/index_patterns/${indexPattern.id}`;
if (mode === 'edit') {
if (!field) {
const message = i18n.translate('kbn.management.editIndexPattern.scripted.noFieldLabel', {
defaultMessage:
"'{indexPatternTitle}' index pattern doesn't have a scripted field called '{fieldName}'",
values: { indexPatternTitle: indexPattern.title, fieldName },
});
services.notifications.toasts.addWarning(message);
history.push(url);
}
}
const docFieldName = field?.name || newFieldPlaceholder;
services.docTitle.change([docFieldName, indexPattern.title]);
const redirectAway = () => {
history.push(`${url}?_a=(tab:${field?.scripted ? TAB_SCRIPTED_FIELDS : TAB_INDEXED_FIELDS})`);
};
return (
<EuiFlexGroup direction="column">
<EuiFlexItem>
<IndexHeader indexPattern={indexPattern} defaultIndex={getConfig('defaultIndex')} />
</EuiFlexItem>
<EuiFlexItem>
<FieldEditor
indexPattern={indexPattern}
field={field}
helpers={{
getConfig,
$http: services.http,
fieldFormatEditors,
redirectAway,
}}
/>
</EuiFlexItem>
</EuiFlexGroup>
);
}
);

View file

@ -18,15 +18,18 @@
*/
import _ from 'lodash';
import { HashRouter } from 'react-router-dom';
import { IndexHeader } from './index_header';
import './create_edit_field';
import { CreateEditField } from './create_edit_field';
import { docTitle } from 'ui/doc_title';
import { KbnUrlProvider } from 'ui/url';
import { IndicesEditSectionsProvider } from './edit_sections';
import { fatalError, toastNotifications } from 'ui/notify';
import { RegistryFieldFormatEditorsProvider } from 'ui/registry/field_format_editors';
import uiRoutes from 'ui/routes';
import { uiModules } from 'ui/modules';
import template from './edit_index_pattern.html';
import createEditFieldtemplate from './create_edit_field.html';
import { fieldWildcardMatcher } from '../../../../../../../../plugins/kibana_utils/public';
import { subscribeWithScope } from '../../../../../../../../plugins/kibana_legacy/public';
import React from 'react';
@ -37,8 +40,12 @@ import { ScriptedFieldsTable } from './scripted_fields_table';
import { i18n } from '@kbn/i18n';
import { I18nContext } from 'ui/i18n';
import { npStart } from 'ui/new_platform';
import { getEditBreadcrumbs } from '../breadcrumbs';
import {
getEditBreadcrumbs,
getEditFieldBreadcrumbs,
getCreateFieldBreadcrumbs,
} from '../breadcrumbs';
import { TAB_INDEXED_FIELDS, TAB_SCRIPTED_FIELDS, TAB_SOURCE_FILTERS } from './constants';
import { createEditIndexPatternPageStateContainer } from './edit_index_pattern_state_container';
const REACT_SOURCE_FILTERS_DOM_ELEMENT_ID = 'reactSourceFiltersTable';
@ -46,10 +53,6 @@ const REACT_INDEXED_FIELDS_DOM_ELEMENT_ID = 'reactIndexedFieldsTable';
const REACT_SCRIPTED_FIELDS_DOM_ELEMENT_ID = 'reactScriptedFieldsTable';
const REACT_INDEX_HEADER_DOM_ELEMENT_ID = 'reactIndexHeader';
const TAB_INDEXED_FIELDS = 'indexedFields';
const TAB_SCRIPTED_FIELDS = 'scriptedFields';
const TAB_SOURCE_FILTERS = 'sourceFilters';
const EDIT_FIELD_PATH = '/management/kibana/index_patterns/{{indexPattern.id}}/field/{{name}}';
function updateSourceFiltersTable($scope) {
@ -425,3 +428,84 @@ uiModules
renderIndexHeader($scope, config);
});
// routes for create edit field. Will be removed after migartion all component to react.
const REACT_FIELD_EDITOR_ID = 'reactFieldEditor';
const renderCreateEditField = ($scope, $route, getConfig, $http, fieldFormatEditors) => {
$scope.$$postDigest(() => {
const node = document.getElementById(REACT_FIELD_EDITOR_ID);
if (!node) {
return;
}
render(
<HashRouter>
<I18nContext>
<CreateEditField
indexPattern={$route.current.locals.indexPattern}
mode={$route.current.mode}
fieldName={$route.current.params.fieldName}
fieldFormatEditors={fieldFormatEditors}
getConfig={getConfig}
services={{
http: $http,
notifications: npStart.core.notifications,
docTitle: npStart.core.chrome.docTitle,
}}
/>
</I18nContext>
</HashRouter>,
node
);
});
};
const destroyCreateEditField = () => {
const node = document.getElementById(REACT_FIELD_EDITOR_ID);
node && unmountComponentAtNode(node);
};
uiRoutes
.when('/management/kibana/index_patterns/:indexPatternId/field/:fieldName*', {
mode: 'edit',
k7Breadcrumbs: getEditFieldBreadcrumbs,
})
.when('/management/kibana/index_patterns/:indexPatternId/create-field/', {
mode: 'create',
k7Breadcrumbs: getCreateFieldBreadcrumbs,
})
.defaults(/management\/kibana\/index_patterns\/[^\/]+\/(field|create-field)(\/|$)/, {
template: createEditFieldtemplate,
mapBreadcrumbs($route, breadcrumbs) {
const { indexPattern } = $route.current.locals;
return breadcrumbs.map(crumb => {
if (crumb.id !== indexPattern.id) {
return crumb;
}
return {
...crumb,
display: indexPattern.title,
};
});
},
resolve: {
indexPattern: function($route, Promise, redirectWhenMissing) {
const { indexPatterns } = npStart.plugins.data;
return Promise.resolve(indexPatterns.get($route.current.params.indexPatternId)).catch(
redirectWhenMissing('/management/kibana/index_patterns')
);
},
},
controllerAs: 'fieldSettings',
controller: function FieldEditorPageController($scope, $route, $http, Private, config) {
const getConfig = (...args) => config.get(...args);
const fieldFormatEditors = Private(RegistryFieldFormatEditorsProvider);
renderCreateEditField($scope, $route, getConfig, $http, fieldFormatEditors);
$scope.$on('$destroy', () => {
destroyCreateEditField();
});
},
});

View file

@ -30,8 +30,8 @@ import {
import { IIndexPattern } from '../../../../../../../../../plugins/data/public';
interface IndexHeaderProps {
defaultIndex: string;
indexPattern: IIndexPattern;
defaultIndex?: string;
setDefault?: () => void;
refreshFields?: () => void;
deleteIndexPattern?: () => void;
@ -77,7 +77,7 @@ export function IndexHeader({
<EuiIcon size="xl" type="starFilled" />
</EuiFlexItem>
)}
<EuiFlexItem style={{ marginLeft: 0 }}>
<EuiFlexItem style={defaultIndex === indexPattern.id ? { marginLeft: 0 } : {}}>
<EuiTitle>
<h1 data-test-subj="indexPatternTitle">{indexPattern.title}</h1>
</EuiTitle>

View file

@ -2244,7 +2244,6 @@
"kbn.management.editIndexPattern.scripted.table.nameHeader": "名前",
"kbn.management.editIndexPattern.scripted.table.scriptDescription": "フィールドのスクリプトです",
"kbn.management.editIndexPattern.scripted.table.scriptHeader": "スクリプト",
"kbn.management.editIndexPattern.scripted.unknownModeErrorMessage": "不明なフィールド設定モード {mode}",
"kbn.management.editIndexPattern.scriptedHeader": "スクリプトフィールド",
"kbn.management.editIndexPattern.scriptedLabel": "ビジュアライゼーションにスクリプトフィールドを使用し、ドキュメントに表示させることができます。但し、スクリプトフィールドは検索できません。",
"kbn.management.editIndexPattern.setDefaultAria": "デフォルトのインデックスに設定",

View file

@ -2245,7 +2245,6 @@
"kbn.management.editIndexPattern.scripted.table.nameHeader": "名称",
"kbn.management.editIndexPattern.scripted.table.scriptDescription": "字段的脚本",
"kbn.management.editIndexPattern.scripted.table.scriptHeader": "脚本",
"kbn.management.editIndexPattern.scripted.unknownModeErrorMessage": "未知 fieldSettings 模式 {mode}",
"kbn.management.editIndexPattern.scriptedHeader": "脚本字段",
"kbn.management.editIndexPattern.scriptedLabel": "可以在可视化中使用脚本字段,并在您的文档中显示它们。但是,您不能搜索脚本字段。",
"kbn.management.editIndexPattern.setDefaultAria": "设置为默认索引",