ui/management -> new platform (#45747) (#52545)

Created management plugin under core_plugins.
Filled the plugin with 2 services: IndexPatternManagementService and SavedObjectsManagementService.
Removed related codes in ui/management and changed the paths.
This commit is contained in:
Matthew Kime 2019-12-09 14:14:27 -06:00 committed by GitHub
parent 80d35bdd10
commit eec700909e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
56 changed files with 927 additions and 457 deletions

View file

@ -17,6 +17,7 @@
"kbn": "src/legacy/core_plugins/kibana",
"kbnDocViews": "src/legacy/core_plugins/kbn_doc_views",
"kbnVislibVisTypes": "src/legacy/core_plugins/kbn_vislib_vis_types",
"management": "src/legacy/core_plugins/management",
"kibana_react": "src/legacy/core_plugins/kibana_react",
"kibana-react": "src/plugins/kibana_react",
"kibana_utils": "src/plugins/kibana_utils",

View file

@ -50,8 +50,6 @@ export class StepTimeField extends Component {
constructor(props) {
super(props);
const { getIndexPatternType, getIndexPatternName } = props.indexPatternCreationType;
this.state = {
error: '',
timeFields: [],
@ -61,8 +59,8 @@ export class StepTimeField extends Component {
isFetchingTimeFields: false,
isCreating: false,
indexPatternId: '',
indexPatternType: getIndexPatternType(),
indexPatternName: getIndexPatternName(),
indexPatternType: props.indexPatternCreationType.getIndexPatternType(),
indexPatternName: props.indexPatternCreationType.getIndexPatternName(),
};
}

View file

@ -21,7 +21,7 @@ import { SavedObjectsClientProvider } from 'ui/saved_objects';
import uiRoutes from 'ui/routes';
import angularTemplate from './angular_template.html';
import 'ui/index_patterns';
import { IndexPatternCreationFactory } from 'ui/management/index_pattern_creation';
import { setup as managementSetup } from '../../../../../../management/public/legacy';
import { getCreateBreadcrumbs } from '../breadcrumbs';
import { renderCreateIndexPatternWizard, destroyCreateIndexPatternWizard } from './render';
@ -35,8 +35,9 @@ uiRoutes.when('/management/kibana/index_pattern', {
const Private = $injector.get('Private');
$scope.$$postDigest(() => {
const $routeParams = $injector.get('$routeParams');
const indexPatternCreationProvider = Private(IndexPatternCreationFactory)($routeParams.type);
const indexPatternCreationType = indexPatternCreationProvider.getType();
const indexPatternCreationType = managementSetup.indexPattern.creation.getType(
$routeParams.type
);
const services = {
config: $injector.get('config'),
es: $injector.get('es'),
@ -52,12 +53,9 @@ uiRoutes.when('/management/kibana/index_pattern', {
const initialQuery = $routeParams.id ? decodeURIComponent($routeParams.id) : undefined;
renderCreateIndexPatternWizard(
initialQuery,
services
);
renderCreateIndexPatternWizard(initialQuery, services);
});
$scope.$on('$destroy', destroyCreateIndexPatternWizard);
}
},
});

View file

@ -28,7 +28,7 @@ import uiRoutes from 'ui/routes';
import { uiModules } from 'ui/modules';
import template from './edit_index_pattern.html';
import { fieldWildcardMatcher } from 'ui/field_wildcard';
import { IndexPatternListFactory } from 'ui/management/index_pattern_list';
import { setup as managementSetup } from '../../../../../../management/public/legacy';
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { SourceFiltersTable } from './source_filters_table';
@ -58,13 +58,17 @@ function updateSourceFiltersTable($scope, $state) {
filterFilter={$scope.fieldFilter}
fieldWildcardMatcher={$scope.fieldWildcardMatcher}
onAddOrRemoveFilter={() => {
$scope.editSections = $scope.editSectionsProvider($scope.indexPattern, $scope.fieldFilter, $scope.indexPatternListProvider);
$scope.editSections = $scope.editSectionsProvider(
$scope.indexPattern,
$scope.fieldFilter,
$scope.indexPatternListProvider
);
$scope.refreshFilters();
$scope.$apply();
}}
/>
</I18nContext>,
node,
node
);
});
} else {
@ -77,7 +81,6 @@ function destroySourceFiltersTable() {
node && unmountComponentAtNode(node);
}
function updateScriptedFieldsTable($scope, $state) {
if ($state.tab === 'scriptedFields') {
$scope.$$postDigest(() => {
@ -100,13 +103,17 @@ function updateScriptedFieldsTable($scope, $state) {
getRouteHref: (obj, route) => $scope.kbnUrl.getRouteHref(obj, route),
}}
onRemoveField={() => {
$scope.editSections = $scope.editSectionsProvider($scope.indexPattern, $scope.fieldFilter, $scope.indexPatternListProvider);
$scope.editSections = $scope.editSectionsProvider(
$scope.indexPattern,
$scope.fieldFilter,
$scope.indexPatternListProvider
);
$scope.refreshFilters();
$scope.$apply();
}}
/>
</I18nContext>,
node,
node
);
});
} else {
@ -144,7 +151,7 @@ function updateIndexedFieldsTable($scope, $state) {
}}
/>
</I18nContext>,
node,
node
);
});
} else {
@ -157,34 +164,36 @@ function destroyIndexedFieldsTable() {
node && unmountComponentAtNode(node);
}
uiRoutes
.when('/management/kibana/index_patterns/:indexPatternId', {
template,
k7Breadcrumbs: getEditBreadcrumbs,
resolve: {
indexPattern: function ($route, Promise, redirectWhenMissing, indexPatterns) {
return Promise.resolve(indexPatterns.get($route.current.params.indexPatternId))
.catch(redirectWhenMissing('/management/kibana/index_patterns'));
}
uiRoutes.when('/management/kibana/index_patterns/:indexPatternId', {
template,
k7Breadcrumbs: getEditBreadcrumbs,
resolve: {
indexPattern: function ($route, Promise, redirectWhenMissing, indexPatterns) {
return Promise.resolve(indexPatterns.get($route.current.params.indexPatternId)).catch(
redirectWhenMissing('/management/kibana/index_patterns')
);
},
});
},
});
uiModules.get('apps/management')
uiModules
.get('apps/management')
.controller('managementIndexPatternsEdit', function (
$scope, $location, $route, Promise, config, indexPatterns, Private, AppState, confirmModal) {
const $state = $scope.state = new AppState();
const indexPatternListProvider = Private(IndexPatternListFactory)();
$scope.fieldWildcardMatcher = (...args) => fieldWildcardMatcher(...args, config.get('metaFields'));
$scope.editSectionsProvider = Private(IndicesEditSectionsProvider);
$scope.kbnUrl = Private(KbnUrlProvider);
$scope.indexPattern = $route.current.locals.indexPattern;
$scope.indexPatternListProvider = indexPatternListProvider;
$scope.indexPattern.tags = indexPatternListProvider.getIndexPatternTags(
$scope.indexPatternListProvider = managementSetup.indexPattern.list;
$scope.indexPattern.tags = managementSetup.indexPattern.list.getIndexPatternTags(
$scope.indexPattern,
$scope.indexPattern.id === config.get('defaultIndex')
);
$scope.getFieldInfo = indexPatternListProvider.getFieldInfo;
$scope.getFieldInfo = managementSetup.indexPattern.list.getFieldInfo.bind(
managementSetup.indexPattern.list
);
docTitle.change($scope.indexPattern.title);
const otherPatterns = _.filter($route.current.locals.indexPatterns, pattern => {
@ -192,7 +201,11 @@ uiModules.get('apps/management')
});
$scope.$watch('indexPattern.fields', function () {
$scope.editSections = $scope.editSectionsProvider($scope.indexPattern, $scope.fieldFilter, indexPatternListProvider);
$scope.editSections = $scope.editSectionsProvider(
$scope.indexPattern,
$scope.fieldFilter,
managementSetup.indexPattern.list
);
$scope.refreshFilters();
$scope.fields = $scope.indexPattern.getNonScriptedFields();
updateIndexedFieldsTable($scope, $state);
@ -243,26 +256,26 @@ uiModules.get('apps/management')
});
$scope.$watchCollection('indexPattern.fields', function () {
$scope.conflictFields = $scope.indexPattern.fields
.filter(field => field.type === 'conflict');
$scope.conflictFields = $scope.indexPattern.fields.filter(field => field.type === 'conflict');
});
$scope.refreshFields = function () {
const confirmMessage = i18n.translate('kbn.management.editIndexPattern.refreshLabel', {
defaultMessage: 'This action resets the popularity counter of each field.'
defaultMessage: 'This action resets the popularity counter of each field.',
});
const confirmModalOptions = {
confirmButtonText: i18n.translate('kbn.management.editIndexPattern.refreshButton', { defaultMessage: 'Refresh' }),
confirmButtonText: i18n.translate('kbn.management.editIndexPattern.refreshButton', {
defaultMessage: 'Refresh',
}),
onConfirm: async () => {
await $scope.indexPattern.init(true);
$scope.fields = $scope.indexPattern.getNonScriptedFields();
},
title: i18n.translate('kbn.management.editIndexPattern.refreshHeader', { defaultMessage: 'Refresh field list?' })
title: i18n.translate('kbn.management.editIndexPattern.refreshHeader', {
defaultMessage: 'Refresh field list?',
}),
};
confirmModal(
confirmMessage,
confirmModalOptions
);
confirmModal(confirmMessage, confirmModalOptions);
};
$scope.removePattern = function () {
@ -283,9 +296,13 @@ uiModules.get('apps/management')
}
const confirmModalOptions = {
confirmButtonText: i18n.translate('kbn.management.editIndexPattern.deleteButton', { defaultMessage: 'Delete' }),
confirmButtonText: i18n.translate('kbn.management.editIndexPattern.deleteButton', {
defaultMessage: 'Delete',
}),
onConfirm: doRemove,
title: i18n.translate('kbn.management.editIndexPattern.deleteHeader', { defaultMessage: 'Delete index pattern?' })
title: i18n.translate('kbn.management.editIndexPattern.deleteHeader', {
defaultMessage: 'Delete index pattern?',
}),
};
confirmModal('', confirmModalOptions);
};
@ -297,7 +314,8 @@ uiModules.get('apps/management')
$scope.setIndexPatternsTimeField = function (field) {
if (field.type !== 'date') {
const errorMessage = i18n.translate('kbn.management.editIndexPattern.notDateErrorMessage', {
defaultMessage: 'That field is a {fieldType} not a date.', values: { fieldType: field.type }
defaultMessage: 'That field is a {fieldType} not a date.',
values: { fieldType: field.type },
});
toastNotifications.addDanger(errorMessage);
return;
@ -307,12 +325,16 @@ uiModules.get('apps/management')
};
$scope.$watch('fieldFilter', () => {
$scope.editSections = $scope.editSectionsProvider($scope.indexPattern, $scope.fieldFilter, indexPatternListProvider);
$scope.editSections = $scope.editSectionsProvider(
$scope.indexPattern,
$scope.fieldFilter,
managementSetup.indexPattern.list
);
if ($scope.fieldFilter === undefined) {
return;
}
switch($state.tab) {
switch ($state.tab) {
case 'indexedFields':
updateIndexedFieldsTable($scope, $state);
case 'scriptedFields':

View file

@ -18,8 +18,7 @@
*/
import { management } from 'ui/management';
import { IndexPatternListFactory } from 'ui/management/index_pattern_list';
import { IndexPatternCreationFactory } from 'ui/management/index_pattern_creation';
import { setup as managementSetup } from '../../../../../management/public/legacy';
import './create_index_pattern_wizard';
import './edit_index_pattern';
import uiRoutes from 'ui/routes';
@ -28,7 +27,10 @@ import indexTemplate from './index.html';
import indexPatternListTemplate from './list.html';
import { IndexPatternTable } from './index_pattern_table';
import { SavedObjectsClientProvider } from 'ui/saved_objects';
import { FeatureCatalogueRegistryProvider, FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
import {
FeatureCatalogueRegistryProvider,
FeatureCatalogueCategory,
} from 'ui/registry/feature_catalogue';
import { i18n } from '@kbn/i18n';
import { I18nContext } from 'ui/i18n';
import { UICapabilitiesProvider } from 'ui/capabilities/react';
@ -39,11 +41,7 @@ import { render, unmountComponentAtNode } from 'react-dom';
const INDEX_PATTERN_LIST_DOM_ELEMENT_ID = 'indexPatternListReact';
export function updateIndexPatternList(
indexPatterns,
kbnUrl,
indexPatternCreationOptions,
) {
export function updateIndexPatternList(indexPatterns, kbnUrl, indexPatternCreationOptions) {
const node = document.getElementById(INDEX_PATTERN_LIST_DOM_ELEMENT_ID);
if (!node) {
return;
@ -59,7 +57,7 @@ export function updateIndexPatternList(
/>
</UICapabilitiesProvider>
</I18nContext>,
node,
node
);
}
@ -72,55 +70,56 @@ const indexPatternsResolutions = {
indexPatterns: function (Private) {
const savedObjectsClient = Private(SavedObjectsClientProvider);
return savedObjectsClient.find({
type: 'index-pattern',
fields: ['title', 'type'],
perPage: 10000
}).then(response => response.savedObjects);
}
return savedObjectsClient
.find({
type: 'index-pattern',
fields: ['title', 'type'],
perPage: 10000,
})
.then(response => response.savedObjects);
},
};
// add a dependency to all of the subsection routes
uiRoutes
.defaults(/management\/kibana\/(index_patterns|index_pattern)/, {
resolve: indexPatternsResolutions,
requireUICapability: 'management.kibana.index_patterns',
badge: uiCapabilities => {
if (uiCapabilities.indexPatterns.save) {
return undefined;
}
return {
text: i18n.translate('kbn.management.indexPatterns.badge.readOnly.text', {
defaultMessage: 'Read only',
}),
tooltip: i18n.translate('kbn.management.indexPatterns.badge.readOnly.tooltip', {
defaultMessage: 'Unable to save index patterns',
}),
iconType: 'glasses'
};
uiRoutes.defaults(/management\/kibana\/(index_patterns|index_pattern)/, {
resolve: indexPatternsResolutions,
requireUICapability: 'management.kibana.index_patterns',
badge: uiCapabilities => {
if (uiCapabilities.indexPatterns.save) {
return undefined;
}
});
uiRoutes
.when('/management/kibana/index_patterns', {
template: indexPatternListTemplate,
k7Breadcrumbs: getListBreadcrumbs
});
return {
text: i18n.translate('kbn.management.indexPatterns.badge.readOnly.text', {
defaultMessage: 'Read only',
}),
tooltip: i18n.translate('kbn.management.indexPatterns.badge.readOnly.tooltip', {
defaultMessage: 'Unable to save index patterns',
}),
iconType: 'glasses',
};
},
});
uiRoutes.when('/management/kibana/index_patterns', {
template: indexPatternListTemplate,
k7Breadcrumbs: getListBreadcrumbs,
});
// wrapper directive, which sets some global stuff up like the left nav
uiModules.get('apps/management')
.directive('kbnManagementIndexPatterns', function ($route, config, kbnUrl, Private) {
uiModules
.get('apps/management')
.directive('kbnManagementIndexPatterns', function ($route, config, kbnUrl) {
return {
restrict: 'E',
transclude: true,
template: indexTemplate,
link: async function ($scope) {
const indexPatternListProvider = Private(IndexPatternListFactory)();
const indexPatternCreationProvider = Private(IndexPatternCreationFactory)();
const indexPatternCreationOptions = await indexPatternCreationProvider.getIndexPatternCreationOptions((url) => {
$scope.$evalAsync(() => kbnUrl.change(url));
});
const indexPatternCreationOptions = await managementSetup.indexPattern.creation.getIndexPatternCreationOptions(
url => {
$scope.$evalAsync(() => kbnUrl.change(url));
}
);
const renderList = () => {
$scope.indexPatternList =
@ -129,7 +128,7 @@ uiModules.get('apps/management')
const id = pattern.id;
const title = pattern.get('title');
const isDefault = $scope.defaultIndex === id;
const tags = indexPatternListProvider.getIndexPatternTags(
const tags = managementSetup.indexPattern.list.getIndexPatternTags(
pattern,
isDefault
);
@ -165,25 +164,30 @@ uiModules.get('apps/management')
$scope.$watch('defaultIndex', () => renderList());
config.bindToScope($scope, 'defaultIndex');
$scope.$apply();
}
},
};
});
management.getSection('kibana').register('index_patterns', {
display: i18n.translate('kbn.management.indexPattern.sectionsHeader', { defaultMessage: 'Index Patterns' }),
display: i18n.translate('kbn.management.indexPattern.sectionsHeader', {
defaultMessage: 'Index Patterns',
}),
order: 0,
url: '#/management/kibana/index_patterns/'
url: '#/management/kibana/index_patterns/',
});
FeatureCatalogueRegistryProvider.register(() => {
return {
id: 'index_patterns',
title: i18n.translate('kbn.management.indexPatternHeader', { defaultMessage: 'Index Patterns' }),
description: i18n.translate('kbn.management.indexPatternLabel',
{ defaultMessage: 'Manage the index patterns that help retrieve your data from Elasticsearch.' }),
title: i18n.translate('kbn.management.indexPatternHeader', {
defaultMessage: 'Index Patterns',
}),
description: i18n.translate('kbn.management.indexPatternLabel', {
defaultMessage: 'Manage the index patterns that help retrieve your data from Elasticsearch.',
}),
icon: 'indexPatternApp',
path: '/app/kibana#/management/kibana/index_patterns',
showOnHomePage: true,
category: FeatureCatalogueCategory.ADMIN
category: FeatureCatalogueCategory.ADMIN,
};
});

View file

@ -19,6 +19,7 @@
import React from 'react';
import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers';
import { mockManagementPlugin } from '../../../../../../../../management/public/np_ready/mocks';
import { Query } from '@elastic/eui';
import { ObjectsTable, POSSIBLE_TYPES } from '../objects_table';
@ -29,6 +30,11 @@ import { extractExportDetails } from '../../../lib/extract_export_details';
jest.mock('ui/kfetch', () => ({ kfetch: jest.fn() }));
jest.mock('../../../../../../../../management/public/legacy', () => ({
setup: mockManagementPlugin.createSetupContract(),
start: mockManagementPlugin.createStartContract(),
}));
jest.mock('../../../lib/find_objects', () => ({
findObjects: jest.fn(),
}));

View file

@ -19,7 +19,7 @@
import React from 'react';
import { shallowWithI18nProvider } from 'test_utils/enzyme_helpers';
import { mockManagementPlugin } from '../../../../../../../../../../management/public/np_ready/mocks';
import { Flyout } from '../flyout';
jest.mock('ui/kfetch', () => ({ kfetch: jest.fn() }));
@ -48,6 +48,11 @@ jest.mock('../../../../../lib/resolve_saved_objects', () => ({
saveObjects: jest.fn(),
}));
jest.mock('../../../../../../../../../../management/public/legacy', () => ({
setup: mockManagementPlugin.createSetupContract(),
start: mockManagementPlugin.createStartContract(),
}));
jest.mock('ui/notify', () => ({}));
const defaultProps = {

View file

@ -21,6 +21,7 @@ import React from 'react';
import { shallowWithI18nProvider, mountWithI18nProvider } from 'test_utils/enzyme_helpers';
import { findTestSubject } from '@elastic/eui/lib/test';
import { keyCodes } from '@elastic/eui/lib/services';
import { mockManagementPlugin } from '../../../../../../../../../../management/public/np_ready/mocks';
jest.mock('ui/kfetch', () => ({ kfetch: jest.fn() }));
@ -28,6 +29,11 @@ jest.mock('ui/chrome', () => ({
addBasePath: () => '',
}));
jest.mock('../../../../../../../../../../management/public/legacy', () => ({
setup: mockManagementPlugin.createSetupContract(),
start: mockManagementPlugin.createStartContract(),
}));
import { Table } from '../table';
const defaultProps = {

View file

@ -18,7 +18,7 @@
*/
import chrome from 'ui/chrome';
import { SavedObjectsManagementActionRegistry } from 'ui/management/saved_objects_management';
import { setup as managementSetup } from '../../../../../../../../../management/public/legacy';
import React, { PureComponent, Fragment } from 'react';
import PropTypes from 'prop-types';
@ -79,7 +79,7 @@ export class Table extends PureComponent {
constructor(props) {
super(props);
this.extraActions = SavedObjectsManagementActionRegistry.get();
this.extraActions = managementSetup.savedObjects.registry.get();
}
onChange = ({ query, error }) => {

View file

@ -0,0 +1,37 @@
/*
* 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 { resolve } from 'path';
import { Legacy } from '../../../../kibana';
// eslint-disable-next-line import/no-default-export
export default function ManagementPlugin(kibana: any) {
const config: Legacy.PluginSpecOptions = {
id: 'management',
publicDir: resolve(__dirname, 'public'),
config: (Joi: any) => {
return Joi.object({
enabled: Joi.boolean().default(true),
}).default();
},
init: (server: Legacy.Server) => ({}),
};
return new kibana.Plugin(config);
}

View file

@ -0,0 +1,5 @@
{
"name": "management",
"version": "kibana"
}

View file

@ -17,13 +17,24 @@
* under the License.
*/
export { SavedObjectsManagementActionRegistry } from './saved_objects_management_action_registry';
/**
* Static np-ready code, re-exported here so consumers can import from
* `src/legacy/core_plugins/management/public`
*
* @public
*/
export {
ManagementSetup,
ManagementStart,
plugin,
IndexPatternCreationConfig,
IndexPatternListConfig,
SavedObjectsManagementAction,
SavedObjectsManagementRecord,
SavedObjectsManagementRecordReference,
} from './saved_objects_management_action';
} from './np_ready';
export {
processImportResponse,
ProcessedImportResponse,
} from '../../../../core_plugins/kibana/public/management/sections/objects/lib/process_import_response';
} from '../../kibana/public/management/sections/objects/lib/process_import_response';

View file

@ -0,0 +1,45 @@
/*
* 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.
*/
/**
* New Platform Shim
*
* In this file, we import any legacy dependencies we have, and shim them into
* our plugin by manually constructing the values that the new platform will
* eventually be passing to the `setup/start` method of our plugin definition.
*
* The idea is that our `plugin.ts` can stay "pure" and not contain any legacy
* world code. Then when it comes time to migrate to the new platform, we can
* simply delete this shim file.
*
* We are also calling `setup/start` here and exporting our public contract so that
* other legacy plugins are able to import from '../core_plugins/visualizations/legacy'
* and receive the response value of the `setup/start` contract, mimicking the
* data that will eventually be injected by the new platform.
*/
import { PluginInitializerContext } from 'src/core/public';
import { npSetup, npStart } from 'ui/new_platform';
import { plugin } from '.';
const pluginInstance = plugin({} as PluginInitializerContext);
export const setup = pluginInstance.setup(npSetup.core, {});
export const start = pluginInstance.start(npStart.core, {});

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.
*/
/**
* Management Plugin - public
*
* This is the entry point for the entire client-side public contract of the plugin.
* If something is not explicitly exported here, you can safely assume it is private
* to the plugin and not considered stable.
*
* All stateful contracts will be injected by the platform at runtime, and are defined
* in the setup/start interfaces in `plugin.ts`. The remaining items exported here are
* either types, or static code.
*/
import { PluginInitializerContext } from 'src/core/public';
import { ManagementPlugin } from './plugin';
export { ManagementSetup, ManagementStart } from './plugin';
export function plugin(initializerContext: PluginInitializerContext) {
return new ManagementPlugin(initializerContext);
}
export {
IndexPatternCreationConfig,
IndexPatternListConfig,
} from './services/index_pattern_management';
export {
SavedObjectsManagementAction,
SavedObjectsManagementRecord,
} from './services/saved_objects_management';

View file

@ -0,0 +1,66 @@
/*
* 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 { PluginInitializerContext } from 'src/core/public';
import { coreMock } from '../../../../../core/public/mocks';
import { ManagementSetup, ManagementStart, ManagementPlugin } from './plugin';
const createSetupContract = (): ManagementSetup => ({
indexPattern: {
creation: {
add: jest.fn(),
getType: jest.fn(),
getIndexPatternCreationOptions: jest.fn(),
} as any,
list: {
add: jest.fn(),
getIndexPatternTags: jest.fn(),
getFieldInfo: jest.fn(),
areScriptedFieldsEnabled: jest.fn(),
} as any,
},
savedObjects: {
registry: {
register: jest.fn(),
has: jest.fn(),
get: jest.fn(() => []),
},
},
});
const createStartContract = (): ManagementStart => ({});
const createInstance = async () => {
const plugin = new ManagementPlugin({} as PluginInitializerContext);
const setup = plugin.setup(coreMock.createSetup(), {});
const doStart = () => plugin.start(coreMock.createStart(), {});
return {
plugin,
setup,
doStart,
};
};
export const mockManagementPlugin = {
createSetupContract,
createStartContract,
createInstance,
};

View file

@ -0,0 +1,67 @@
/*
* 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 { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core/public';
import { IndexPatternManagementService, IndexPatternManagementSetup } from './services';
import {
SavedObjectsManagementService,
SavedObjectsManagementServiceSetup,
} from './services/saved_objects_management';
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface ManagementPluginSetupDependencies {}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
interface ManagementPluginStartDependencies {}
export interface ManagementSetup {
indexPattern: IndexPatternManagementSetup;
savedObjects: SavedObjectsManagementServiceSetup;
}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface ManagementStart {}
export class ManagementPlugin
implements
Plugin<
ManagementSetup,
ManagementStart,
ManagementPluginSetupDependencies,
ManagementPluginStartDependencies
> {
private readonly indexPattern = new IndexPatternManagementService();
private readonly savedObjects = new SavedObjectsManagementService();
constructor(initializerContext: PluginInitializerContext) {}
public setup(core: CoreSetup, deps: ManagementPluginSetupDependencies) {
return {
indexPattern: this.indexPattern.setup({ httpClient: core.http }),
savedObjects: this.savedObjects.setup(),
};
}
public start(core: CoreStart, plugins: ManagementPluginStartDependencies) {
return {};
}
public stop() {
this.indexPattern.stop();
}
}

View file

@ -17,5 +17,5 @@
* under the License.
*/
export const indexPatternTypes = [];
export const addIndexPatternType = (type) => indexPatternTypes.push(type);
export * from './index_pattern_management';
export * from './saved_objects_management';

View file

@ -19,17 +19,39 @@
import { i18n } from '@kbn/i18n';
const indexPatternTypeName = i18n.translate('common.ui.management.editIndexPattern.createIndex.defaultTypeName',
{ defaultMessage: 'index pattern' });
const indexPatternTypeName = i18n.translate(
'management.editIndexPattern.createIndex.defaultTypeName',
{ defaultMessage: 'index pattern' }
);
const indexPatternButtonText = i18n.translate('common.ui.management.editIndexPattern.createIndex.defaultButtonText',
{ defaultMessage: 'Standard index pattern' });
const indexPatternButtonText = i18n.translate(
'management.editIndexPattern.createIndex.defaultButtonText',
{ defaultMessage: 'Standard index pattern' }
);
const indexPatternButtonDescription = i18n.translate('common.ui.management.editIndexPattern.createIndex.defaultButtonDescription',
{ defaultMessage: 'Perform full aggregations against any data' });
const indexPatternButtonDescription = i18n.translate(
'management.editIndexPattern.createIndex.defaultButtonDescription',
{ defaultMessage: 'Perform full aggregations against any data' }
);
export type UrlHandler = (url: string) => void;
export interface IndexPatternCreationOption {
text: string;
description: string;
testSubj: string;
onClick: () => void;
isBeta?: boolean;
}
export class IndexPatternCreationConfig {
static key = 'default';
public readonly key = 'default';
protected type?: string;
protected name: string;
protected showSystemIndices: boolean;
protected httpClient: object | null;
protected isBeta: boolean;
constructor({
type = undefined,
@ -37,6 +59,12 @@ export class IndexPatternCreationConfig {
showSystemIndices = true,
httpClient = null,
isBeta = false,
}: {
type?: string;
name?: string;
showSystemIndices?: boolean;
httpClient?: object | null;
isBeta?: boolean;
}) {
this.type = type;
this.name = name;
@ -45,7 +73,9 @@ export class IndexPatternCreationConfig {
this.isBeta = isBeta;
}
async getIndexPatternCreationOption(urlHandler) {
public async getIndexPatternCreationOption(
urlHandler: UrlHandler
): Promise<IndexPatternCreationOption> {
return {
text: indexPatternButtonText,
description: indexPatternButtonDescription,
@ -56,39 +86,39 @@ export class IndexPatternCreationConfig {
};
}
getIndexPatternType = () => {
public getIndexPatternType() {
return this.type;
}
getIndexPatternName = () => {
public getIndexPatternName() {
return this.name;
}
getIsBeta = () => {
public getIsBeta() {
return this.isBeta;
}
getShowSystemIndices = () => {
public getShowSystemIndices() {
return this.showSystemIndices;
}
getIndexTags() {
public getIndexTags() {
return [];
}
checkIndicesForErrors = () => {
public checkIndicesForErrors() {
return undefined;
}
getIndexPatternMappings = () => {
public getIndexPatternMappings() {
return {};
}
renderPrompt = () => {
public renderPrompt() {
return null;
}
getFetchForWildcardOptions = () => {
public getFetchForWildcardOptions() {
return {};
}
}

View file

@ -17,10 +17,5 @@
* under the License.
*/
import { uiRegistry } from 'ui/registry/_registry';
export const IndexPatternListConfigRegistry = uiRegistry({
name: 'indexPatternList',
index: ['name'],
order: ['order'],
});
export { IndexPatternCreationConfig } from './config';
export { IndexPatternCreationManager } from './manager';

View file

@ -0,0 +1,61 @@
/*
* 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 { HttpServiceBase } from '../../../../../../../../core/public';
import { IndexPatternCreationConfig, UrlHandler, IndexPatternCreationOption } from './config';
export class IndexPatternCreationManager {
private configs: IndexPatternCreationConfig[];
constructor(private readonly httpClient: HttpServiceBase) {
this.configs = [];
}
public add(Config: typeof IndexPatternCreationConfig) {
const config = new Config({ httpClient: this.httpClient });
if (this.configs.findIndex(c => c.key === config.key) !== -1) {
throw new Error(`${config.key} exists in IndexPatternCreationManager.`);
}
this.configs.push(config);
}
public getType(key: string | undefined): IndexPatternCreationConfig | null {
if (key) {
const index = this.configs.findIndex(config => config.key === key);
return this.configs[index] || null;
} else {
return this.getType('default');
}
}
public async getIndexPatternCreationOptions(urlHandler: UrlHandler) {
const options: IndexPatternCreationOption[] = [];
await Promise.all(
this.configs.map(async config => {
const option = config.getIndexPatternCreationOption
? await config.getIndexPatternCreationOption(urlHandler)
: null;
if (option) {
options.push(option);
}
})
);
return options;
}
}

View file

@ -17,7 +17,6 @@
* under the License.
*/
import { IndexPatternCreationConfig } from './index_pattern_creation_config';
import { addIndexPatternType } from './index_pattern_types';
addIndexPatternType(IndexPatternCreationConfig);
export * from './index_pattern_management_service';
export { IndexPatternCreationConfig } from './creation';
export { IndexPatternListConfig } from './list';

View file

@ -0,0 +1,53 @@
/*
* 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 { HttpServiceBase } from '../../../../../../../core/public';
import { IndexPatternCreationManager, IndexPatternCreationConfig } from './creation';
import { IndexPatternListManager, IndexPatternListConfig } from './list';
interface SetupDependencies {
httpClient: HttpServiceBase;
}
/**
* Index patterns management service
*
* @internal
*/
export class IndexPatternManagementService {
public setup({ httpClient }: SetupDependencies) {
const creation = new IndexPatternCreationManager(httpClient);
const list = new IndexPatternListManager();
creation.add(IndexPatternCreationConfig);
list.add(IndexPatternListConfig);
return {
creation,
list,
};
}
public stop() {
// nothing to do here yet.
}
}
/** @internal */
export type IndexPatternManagementSetup = ReturnType<IndexPatternManagementService['setup']>;

View file

@ -0,0 +1,51 @@
/*
* 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';
import { IIndexPattern, IFieldType } from 'src/plugins/data/public';
export interface IndexPatternTag {
key: string;
name: string;
}
export class IndexPatternListConfig {
public readonly key = 'default';
public getIndexPatternTags(indexPattern: IIndexPattern, isDefault: boolean): IndexPatternTag[] {
return isDefault
? [
{
key: 'default',
name: i18n.translate('management.editIndexPattern.list.defaultIndexPatternListName', {
defaultMessage: 'Default',
}),
},
]
: [];
}
public getFieldInfo(indexPattern: IIndexPattern, field: IFieldType): string[] {
return [];
}
public areScriptedFieldsEnabled(indexPattern: IIndexPattern): boolean {
return true;
}
}

View file

@ -17,7 +17,5 @@
* under the License.
*/
import { IndexPatternListConfig } from './index_pattern_list_config';
import { IndexPatternListConfigRegistry } from './index_pattern_list_config_registry';
IndexPatternListConfigRegistry.register(() => IndexPatternListConfig);
export { IndexPatternListConfig } from './config';
export { IndexPatternListManager } from './manager';

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 { IIndexPattern, IFieldType } from 'src/plugins/data/public';
import { IndexPatternListConfig, IndexPatternTag } from './config';
export class IndexPatternListManager {
private configs: IndexPatternListConfig[];
constructor() {
this.configs = [];
}
public add(Config: typeof IndexPatternListConfig) {
const config = new Config();
if (this.configs.findIndex(c => c.key === config.key) !== -1) {
throw new Error(`${config.key} exists in IndexPatternListManager.`);
}
this.configs.push(config);
}
public getIndexPatternTags(indexPattern: IIndexPattern, isDefault: boolean) {
return this.configs.reduce((tags: IndexPatternTag[], config) => {
return config.getIndexPatternTags
? tags.concat(config.getIndexPatternTags(indexPattern, isDefault))
: tags;
}, []);
}
public getFieldInfo(indexPattern: IIndexPattern, field: IFieldType): string[] {
return this.configs.reduce((info: string[], config) => {
return config.getFieldInfo ? info.concat(config.getFieldInfo(indexPattern, field)) : info;
}, []);
}
public areScriptedFieldsEnabled(indexPattern: IIndexPattern): boolean {
return this.configs.every(config => {
return config.areScriptedFieldsEnabled ? config.areScriptedFieldsEnabled(indexPattern) : true;
});
}
}

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 * from './saved_objects_management_action_registry';
export * from './saved_objects_management_action';
export * from './saved_objects_management_service';

View file

@ -17,7 +17,7 @@
* under the License.
*/
import { ReactNode } from '@elastic/eui/node_modules/@types/react';
import { ReactNode } from 'react';
export interface SavedObjectsManagementRecordReference {
type: string;

View file

@ -16,22 +16,17 @@
* specific language governing permissions and limitations
* under the License.
*/
import { SavedObjectsManagementActionRegistry } from './saved_objects_management_action_registry';
export class IndexPatternListConfig {
static key = 'default';
getIndexPatternTags = (indexPattern, isDefault) => {
return isDefault ? [{
key: 'default',
name: 'Default',
}] : [];
export class SavedObjectsManagementService {
public setup() {
return {
registry: SavedObjectsManagementActionRegistry,
};
}
getFieldInfo = () => {
return [];
}
areScriptedFieldsEnabled = () => {
return true;
}
public stop() {}
}
/** @internal */
export type SavedObjectsManagementServiceSetup = ReturnType<SavedObjectsManagementService['setup']>;

View file

@ -1,23 +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 './register';
export { IndexPatternCreationFactory } from './index_pattern_creation';
export { IndexPatternCreationConfig } from './index_pattern_creation_config';
export { indexPatternTypes, addIndexPatternType } from './index_pattern_types';

View file

@ -1,54 +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 { indexPatternTypes } from './index_pattern_types';
class IndexPatternCreation {
constructor(httpClient, type) {
this._allTypes = indexPatternTypes.map(Plugin => new Plugin({ httpClient }));
this._setCurrentType(type);
}
_setCurrentType = (type) => {
const index = type ? indexPatternTypes.findIndex(Plugin => Plugin.key === type) : -1;
this._currentType = index > -1 && this._allTypes[index] ? this._allTypes[index] : null;
}
getType = () => {
return this._currentType || null;
}
getIndexPatternCreationOptions = async (urlHandler) => {
const options = [];
await Promise.all(this._allTypes.map(async type => {
const option = type.getIndexPatternCreationOption ? await type.getIndexPatternCreationOption(urlHandler) : null;
if(option) {
options.push(option);
}
}));
return options;
}
}
export const IndexPatternCreationFactory = (Private, $http) => {
return (type = 'default') => {
const indexPatternCreationProvider = new IndexPatternCreation($http, type);
return indexPatternCreationProvider;
};
};

View file

@ -1,23 +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 './register';
export { IndexPatternListFactory } from './index_pattern_list';
export { IndexPatternListConfig } from './index_pattern_list_config';
export { IndexPatternListConfigRegistry } from './index_pattern_list_config_registry';

View file

@ -1,52 +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 { IndexPatternListConfigRegistry } from './index_pattern_list_config_registry';
class IndexPatternList {
constructor(registry) {
this._plugins = registry.inOrder.map(Plugin => new Plugin());
}
getIndexPatternTags = (indexPattern, isDefault) => {
return this._plugins.reduce((tags, plugin) => {
return plugin.getIndexPatternTags ? tags.concat(plugin.getIndexPatternTags(indexPattern, isDefault)) : tags;
}, []);
}
getFieldInfo = (indexPattern, field) => {
return this._plugins.reduce((info, plugin) => {
return plugin.getFieldInfo ? info.concat(plugin.getFieldInfo(indexPattern, field)) : info;
}, []);
}
areScriptedFieldsEnabled = (indexPattern) => {
return this._plugins.every((plugin) => {
return plugin.areScriptedFieldsEnabled ? plugin.areScriptedFieldsEnabled(indexPattern) : true;
});
}
}
export const IndexPatternListFactory = (Private) => {
return function () {
const indexPatternListRegistry = Private(IndexPatternListConfigRegistry);
const indexPatternListProvider = new IndexPatternList(indexPatternListRegistry);
return indexPatternListProvider;
};
};

View file

@ -42,7 +42,7 @@ export class ManagementSection {
this.id = id;
this.items = new IndexedArray({
index: ['id'],
order: ['order']
order: ['order'],
});
this.visible = true;
this.disabled = false;
@ -51,13 +51,14 @@ export class ManagementSection {
this.url = '';
assign(this, options);
}
get visibleItems() {
return this.items.inOrder.filter(item => {
const capabilityManagementSection = capabilities.get().management[this.id];
const itemCapability = capabilityManagementSection ? capabilityManagementSection[item.id] : null;
const itemCapability = capabilityManagementSection
? capabilityManagementSection[item.id]
: null;
return item.visible && itemCapability !== false;
});
@ -95,10 +96,10 @@ export class ManagementSection {
}
/**
* Deregisters a section
*
* @param {string} id
*/
* Deregisters a section
*
* @param {string} id
*/
deregister(id) {
this.items.remove(item => item.id === id);
listeners.forEach(fn => fn(this.items));

View file

@ -24,10 +24,10 @@ jest.mock('ui/capabilities', () => ({
kibana: {
sampleFeature1: true,
sampleFeature2: false,
}
}
})
}
},
},
}),
},
}));
import { ManagementSection } from './section';
@ -115,7 +115,9 @@ describe('ManagementSection', () => {
it('calls listener when item added', () => {
let listerCalled = false;
const listenerFn = () => { listerCalled = true; };
const listenerFn = () => {
listerCalled = true;
};
section.addListener(listenerFn);
section.register('about');
@ -131,12 +133,12 @@ describe('ManagementSection', () => {
section.register('about');
});
it ('deregisters an existing section', () => {
it('deregisters an existing section', () => {
section.deregister('about');
expect(section.items).toHaveLength(0);
});
it ('allows deregistering a section more than once', () => {
it('allows deregistering a section more than once', () => {
section.deregister('about');
section.deregister('about');
expect(section.items).toHaveLength(0);
@ -144,7 +146,9 @@ describe('ManagementSection', () => {
it('calls listener when item added', () => {
let listerCalled = false;
const listenerFn = () => { listerCalled = true; };
const listenerFn = () => {
listerCalled = true;
};
section.addListener(listenerFn);
section.deregister('about');
@ -202,7 +206,9 @@ describe('ManagementSection', () => {
});
it('can be ordered', () => {
const ids = section.items.inOrder.map((i) => { return i.id; });
const ids = section.items.inOrder.map(i => {
return i.id;
});
expect(ids).toEqual(['one', 'two', 'three']);
});
});
@ -256,20 +262,26 @@ describe('ManagementSection', () => {
});
it('maintains the order', () => {
const ids = section.visibleItems.map((i) => { return i.id; });
const ids = section.visibleItems.map(i => {
return i.id;
});
expect(ids).toEqual(['one', 'two', 'three']);
});
it('does not include hidden items', () => {
section.getSection('two').hide();
const ids = section.visibleItems.map((i) => { return i.id; });
const ids = section.visibleItems.map(i => {
return i.id;
});
expect(ids).toEqual(['one', 'three']);
});
it('does not include visible items hidden via uiCapabilities', () => {
section.register('sampleFeature2', { order: 4, visible: true });
const ids = section.visibleItems.map((i) => { return i.id; });
const ids = section.visibleItems.map(i => {
return i.id;
});
expect(ids).toEqual(['one', 'two', 'three']);
});
});

View file

@ -22,15 +22,15 @@ import { i18n } from '@kbn/i18n';
export const management = new ManagementSection('management', {
display: i18n.translate('common.ui.management.displayName', {
defaultMessage: 'Management'
})
defaultMessage: 'Management',
}),
});
management.register('data', {
display: i18n.translate('common.ui.management.connectDataDisplayName', {
defaultMessage: 'Connect Data'
defaultMessage: 'Connect Data',
}),
order: 0
order: 0,
});
management.register('elasticsearch', {

View file

@ -4,9 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { addIndexPatternType } from 'ui/management/index_pattern_creation';
import { setup as managementSetup } from '../../../../../../src/legacy/core_plugins/management/public/legacy';
import { RollupIndexPatternCreationConfig } from './rollup_index_pattern_creation_config';
export function initIndexPatternCreation() {
addIndexPatternType(RollupIndexPatternCreationConfig);
managementSetup.indexPattern.creation.add(RollupIndexPatternCreationConfig);
}

View file

@ -5,32 +5,44 @@
*/
import React from 'react';
import { IndexPatternCreationConfig } from 'ui/management/index_pattern_creation';
import { IndexPatternCreationConfig } from '../../../../../../src/legacy/core_plugins/management/public';
import { RollupPrompt } from './components/rollup_prompt';
import { setHttpClient, getRollupIndices } from '../services/api';
import { i18n } from '@kbn/i18n';
const rollupIndexPatternTypeName = i18n.translate('xpack.rollupJobs.editRollupIndexPattern.createIndex.defaultTypeName',
{ defaultMessage: 'rollup index pattern' });
const rollupIndexPatternTypeName = i18n.translate(
'xpack.rollupJobs.editRollupIndexPattern.createIndex.defaultTypeName',
{ defaultMessage: 'rollup index pattern' }
);
const rollupIndexPatternButtonText = i18n.translate('xpack.rollupJobs.editRollupIndexPattern.createIndex.defaultButtonText',
{ defaultMessage: 'Rollup index pattern' });
const rollupIndexPatternButtonText = i18n.translate(
'xpack.rollupJobs.editRollupIndexPattern.createIndex.defaultButtonText',
{ defaultMessage: 'Rollup index pattern' }
);
const rollupIndexPatternButtonDescription = i18n.translate('xpack.rollupJobs.editRollupIndexPattern.createIndex.defaultButtonDescription',
{ defaultMessage: 'Perform limited aggregations against summarized data' });
const rollupIndexPatternButtonDescription = i18n.translate(
'xpack.rollupJobs.editRollupIndexPattern.createIndex.defaultButtonDescription',
{ defaultMessage: 'Perform limited aggregations against summarized data' }
);
const rollupIndexPatternNoMatchError = i18n.translate('xpack.rollupJobs.editRollupIndexPattern.createIndex.noMatchError',
{ defaultMessage: 'Rollup index pattern error: must match one rollup index' });
const rollupIndexPatternNoMatchError = i18n.translate(
'xpack.rollupJobs.editRollupIndexPattern.createIndex.noMatchError',
{ defaultMessage: 'Rollup index pattern error: must match one rollup index' }
);
const rollupIndexPatternTooManyMatchesError = i18n.translate('xpack.rollupJobs.editRollupIndexPattern.createIndex.tooManyMatchesError',
{ defaultMessage: 'Rollup index pattern error: can only match one rollup index' });
const rollupIndexPatternTooManyMatchesError = i18n.translate(
'xpack.rollupJobs.editRollupIndexPattern.createIndex.tooManyMatchesError',
{ defaultMessage: 'Rollup index pattern error: can only match one rollup index' }
);
const rollupIndexPatternIndexLabel = i18n.translate('xpack.rollupJobs.editRollupIndexPattern.createIndex.indexLabel',
{ defaultMessage: 'Rollup' });
const rollupIndexPatternIndexLabel = i18n.translate(
'xpack.rollupJobs.editRollupIndexPattern.createIndex.indexLabel',
{ defaultMessage: 'Rollup' }
);
export class RollupIndexPatternCreationConfig extends IndexPatternCreationConfig {
static key = 'rollup';
key = 'rollup';
constructor(options) {
super({
@ -60,76 +72,85 @@ export class RollupIndexPatternCreationConfig extends IndexPatternCreationConfig
async getIndexPatternCreationOption(urlHandler) {
await this.settingUp;
return this.rollupIndices && this.rollupIndices.length ? {
text: rollupIndexPatternButtonText,
description: rollupIndexPatternButtonDescription,
testSubj: `createRollupIndexPatternButton`,
isBeta: this.isBeta,
onClick: () => {
urlHandler('/management/kibana/index_pattern?type=rollup');
},
} : null;
return this.rollupIndices && this.rollupIndices.length
? {
text: rollupIndexPatternButtonText,
description: rollupIndexPatternButtonDescription,
testSubj: `createRollupIndexPatternButton`,
isBeta: this.isBeta,
onClick: () => {
urlHandler('/management/kibana/index_pattern?type=rollup');
},
}
: null;
}
isRollupIndex = (indexName) => {
isRollupIndex = indexName => {
return this.rollupIndices.includes(indexName);
}
};
getIndexTags(indexName) {
return this.isRollupIndex(indexName) ? [{
key: this.type,
name: rollupIndexPatternIndexLabel,
}] : [];
return this.isRollupIndex(indexName)
? [
{
key: this.type,
name: rollupIndexPatternIndexLabel,
},
]
: [];
}
checkIndicesForErrors = (indices) => {
checkIndicesForErrors = indices => {
this.rollupIndex = null;
if(!indices || !indices.length) {
if (!indices || !indices.length) {
return;
}
const rollupIndices = indices.filter(index => this.isRollupIndex(index.name));
if(!rollupIndices.length) {
if (!rollupIndices.length) {
return [rollupIndexPatternNoMatchError];
} else if(rollupIndices.length > 1) {
} else if (rollupIndices.length > 1) {
return [rollupIndexPatternTooManyMatchesError];
}
const rollupIndexName = rollupIndices[0].name;
const error = this.rollupIndicesCapabilities[rollupIndexName].error;
if(error) {
const errorMessage = i18n.translate('xpack.rollupJobs.editRollupIndexPattern.createIndex.uncaughtError', {
defaultMessage: 'Rollup index pattern error: {error}',
values: {
error
if (error) {
const errorMessage = i18n.translate(
'xpack.rollupJobs.editRollupIndexPattern.createIndex.uncaughtError',
{
defaultMessage: 'Rollup index pattern error: {error}',
values: {
error,
},
}
});
);
return [errorMessage];
}
this.rollupIndex = rollupIndexName;
}
};
getIndexPatternMappings = () => {
return this.rollupIndex ? {
type: this.type,
typeMeta: {
params: {
rollup_index: this.rollupIndex,
return this.rollupIndex
? {
type: this.type,
typeMeta: {
params: {
rollup_index: this.rollupIndex,
},
aggs: this.rollupIndicesCapabilities[this.rollupIndex].aggs,
},
aggs: this.rollupIndicesCapabilities[this.rollupIndex].aggs,
},
} : {};
}
}
: {};
};
renderPrompt = () => {
return (
<RollupPrompt />
);
}
return <RollupPrompt />;
};
getFetchForWildcardOptions = () => {
return {
@ -138,5 +159,5 @@ export class RollupIndexPatternCreationConfig extends IndexPatternCreationConfig
rollup_index: this.rollupIndex,
},
};
}
};
}

View file

@ -4,9 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { IndexPatternListConfigRegistry } from 'ui/management/index_pattern_list';
import { setup as managementSetup } from '../../../../../../src/legacy/core_plugins/management/public/legacy';
import { RollupIndexPatternListConfig } from './rollup_index_pattern_list_config';
export function initIndexPatternList() {
IndexPatternListConfigRegistry.register(() => RollupIndexPatternListConfig);
managementSetup.indexPattern.list.add(RollupIndexPatternListConfig);
}

View file

@ -3,49 +3,59 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { IndexPatternListConfig } from 'ui/management/index_pattern_list';
import { IndexPatternListConfig } from '../../../../../../src/legacy/core_plugins/management/public';
function isRollup(indexPattern) {
return indexPattern.type === 'rollup' || (indexPattern.get && indexPattern.get('type') === 'rollup');
return (
indexPattern.type === 'rollup' || (indexPattern.get && indexPattern.get('type') === 'rollup')
);
}
export class RollupIndexPatternListConfig extends IndexPatternListConfig {
static key = 'rollup';
key = 'rollup';
getIndexPatternTags = (indexPattern) => {
return isRollup(indexPattern) ? [{
key: 'rollup',
name: 'Rollup',
}] : [];
}
getIndexPatternTags = indexPattern => {
return isRollup(indexPattern)
? [
{
key: 'rollup',
name: 'Rollup',
},
]
: [];
};
getFieldInfo = (indexPattern, field) => {
if(!isRollup(indexPattern)) {
if (!isRollup(indexPattern)) {
return [];
}
const allAggs = indexPattern.typeMeta && indexPattern.typeMeta.aggs;
const fieldAggs = allAggs && Object.keys(allAggs).filter(agg => allAggs[agg][field]);
if(!fieldAggs || !fieldAggs.length) {
if (!fieldAggs || !fieldAggs.length) {
return [];
}
return ['Rollup aggregations:'].concat(fieldAggs.map(aggName => {
const agg = allAggs[aggName][field];
switch(aggName) {
case 'date_histogram':
return `${aggName} (interval: ${agg.interval}, ${agg.delay ? `delay: ${agg.delay},` : ''} ${agg.time_zone})`;
break;
case 'histogram':
return `${aggName} (interval: ${agg.interval})`;
default:
return aggName;
}
}));
}
return ['Rollup aggregations:'].concat(
fieldAggs.map(aggName => {
const agg = allAggs[aggName][field];
switch (aggName) {
case 'date_histogram':
return `${aggName} (interval: ${agg.interval}, ${
agg.delay ? `delay: ${agg.delay},` : ''
} ${agg.time_zone})`;
break;
case 'histogram':
return `${aggName} (interval: ${agg.interval})`;
default:
return aggName;
}
})
);
};
areScriptedFieldsEnabled = (indexPattern) => {
areScriptedFieldsEnabled = indexPattern => {
return !isRollup(indexPattern);
}
};
}

View file

@ -3,15 +3,12 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import chrome from 'ui/chrome';
let httpClient;
export const setHttpClient = (client) => {
export const setHttpClient = client => {
httpClient = client;
};
const apiPrefix = chrome.addBasePath('/api/rollup');
export async function getRollupIndices() {
const response = await httpClient.get(`${apiPrefix}/indices`);
return response.data || {};
const response = await httpClient.get('/api/rollup/indices');
return response || {};
}

View file

@ -4,12 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import { i18n } from '@kbn/i18n';
import { toastNotifications } from 'ui/notify';
import {
SavedObjectsManagementAction,
SavedObjectsManagementRecord,
} from 'ui/management/saved_objects_management';
import { i18n } from '@kbn/i18n';
import { toastNotifications } from 'ui/notify';
} from '../../../../../../../src/legacy/core_plugins/management/public';
import { CopySavedObjectsToSpaceFlyout } from '../../views/management/components/copy_saved_objects_to_space';
import { Space } from '../../../common/model/space';
import { SpacesManager } from '../spaces_manager';

View file

@ -5,7 +5,7 @@
*/
import { summarizeCopyResult } from './summarize_copy_result';
import { ProcessedImportResponse } from 'ui/management/saved_objects_management';
import { ProcessedImportResponse } from '../../../../../../../src/legacy/core_plugins/management/public';
const createSavedObjectsManagementRecord = () => ({
type: 'dashboard',

View file

@ -4,10 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
import {
ProcessedImportResponse,
SavedObjectsManagementRecord,
} from 'ui/management/saved_objects_management';
import { SavedObjectsManagementRecord } from '../../../../../../../src/legacy/core_plugins/management/public';
import { ProcessedImportResponse } from '../../../../../../../src/legacy/core_plugins/management/public';
export interface SummarizedSavedObjectResult {
type: string;

View file

@ -5,7 +5,7 @@
*/
import { EventEmitter } from 'events';
import { kfetch } from 'ui/kfetch';
import { SavedObjectsManagementRecord } from 'ui/management/saved_objects_management';
import { SavedObjectsManagementRecord } from '../../../../../../src/legacy/core_plugins/management/public';
import { Space } from '../../common/model/space';
import { GetSpacePurpose } from '../../common/model/types';
import { CopySavedObjectsToSpaceResponse } from './copy_saved_objects_to_space/types';

View file

@ -6,6 +6,7 @@
import React from 'react';
import Boom from 'boom';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { mockManagementPlugin } from '../../../../../../../../../src/legacy/core_plugins/management/public/np_ready/mocks';
import { CopySavedObjectsToSpaceFlyout } from './copy_to_space_flyout';
import { CopyToSpaceForm } from './copy_to_space_form';
import { EuiLoadingSpinner, EuiEmptyPrompt } from '@elastic/eui';
@ -18,6 +19,11 @@ import { spacesManagerMock } from '../../../../lib/mocks';
import { SpacesManager } from '../../../../lib';
import { ToastNotifications } from 'ui/notify/toasts/toast_notifications';
jest.mock('../../../../../../../../../src/legacy/core_plugins/management/public/legacy', () => ({
setup: mockManagementPlugin.createSetupContract(),
start: mockManagementPlugin.createStartContract(),
}));
interface SetupOpts {
mockSpaces?: Space[];
returnBeforeSpacesLoad?: boolean;

View file

@ -21,12 +21,12 @@ import {
import { mapValues } from 'lodash';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import {
SavedObjectsManagementRecord,
processImportResponse,
ProcessedImportResponse,
} from 'ui/management/saved_objects_management';
import { ToastNotifications } from 'ui/notify/toasts/toast_notifications';
import { SavedObjectsManagementRecord } from '../../../../../../../../../src/legacy/core_plugins/management/public';
import {
ProcessedImportResponse,
processImportResponse,
} from '../../../../../../../../../src/legacy/core_plugins/management/public';
import { Space } from '../../../../../common/model/space';
import { SpacesManager } from '../../../../lib';
import { ProcessingCopyToSpace } from './processing_copy_to_space';

View file

@ -5,10 +5,10 @@
*/
import React, { Fragment } from 'react';
import { ProcessedImportResponse } from 'ui/management/saved_objects_management';
import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiStat, EuiHorizontalRule } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { ProcessedImportResponse } from '../../../../../../../../../src/legacy/core_plugins/management/public';
import { ImportRetry } from '../../../../lib/copy_saved_objects_to_space/types';
interface Props {

View file

@ -5,10 +5,6 @@
*/
import React, { Fragment } from 'react';
import {
ProcessedImportResponse,
SavedObjectsManagementRecord,
} from 'ui/management/saved_objects_management';
import {
EuiSpacer,
EuiText,
@ -17,6 +13,8 @@ import {
EuiHorizontalRule,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { SavedObjectsManagementRecord } from '../../../../../../../../../src/legacy/core_plugins/management/public';
import { ProcessedImportResponse } from '../../../../../../../../../src/legacy/core_plugins/management/public';
import { summarizeCopyResult } from '../../../../lib/copy_saved_objects_to_space';
import { Space } from '../../../../../common/model/space';
import { CopyOptions, ImportRetry } from '../../../../lib/copy_saved_objects_to_space/types';

View file

@ -6,7 +6,7 @@
import React from 'react';
import { EuiAccordion, EuiFlexGroup, EuiFlexItem, EuiText, EuiSpacer } from '@elastic/eui';
import { SavedObjectsManagementRecord } from 'ui/management/saved_objects_management';
import { SavedObjectsManagementRecord } from '../../../../../../../../../src/legacy/core_plugins/management/public';
import { SummarizedCopyToSpaceResult } from '../../../../lib/copy_saved_objects_to_space';
import { SpaceAvatar } from '../../../../components';
import { Space } from '../../../../../common/model/space';

View file

@ -5,10 +5,10 @@
*/
import React from 'react';
import { SavedObjectsManagementRecord } from 'ui/management/saved_objects_management';
import { SummarizedCopyToSpaceResult } from 'plugins/spaces/lib/copy_saved_objects_to_space';
import { EuiText, EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { SavedObjectsManagementRecord } from '../../../../../../../../../src/legacy/core_plugins/management/public';
import { Space } from '../../../../../common/model/space';
import { CopyStatusIndicator } from './copy_status_indicator';
import { ImportRetry } from '../../../../lib/copy_saved_objects_to_space/types';

View file

@ -12,9 +12,9 @@ import {
PAGE_TITLE_COMPONENT,
registerSettingsComponent,
} from 'ui/management';
import { SavedObjectsManagementActionRegistry } from 'ui/management/saved_objects_management';
// @ts-ignore
import routes from 'ui/routes';
import { setup as managementSetup } from '../../../../../../../src/legacy/core_plugins/management/public/legacy';
import { SpacesManager } from '../../lib';
import { AdvancedSettingsSubtitle } from './components/advanced_settings_subtitle';
import { AdvancedSettingsTitle } from './components/advanced_settings_title';
@ -54,8 +54,8 @@ routes.defaults(/\/management/, {
);
// This route resolve function executes any time the management screen is loaded, and we want to ensure
// that this action is only registered once.
if (!SavedObjectsManagementActionRegistry.has(action.id)) {
SavedObjectsManagementActionRegistry.register(action);
if (!managementSetup.savedObjects.registry.has(action.id)) {
managementSetup.savedObjects.registry.register(action);
}
// Customize Advanced Settings

View file

@ -463,9 +463,9 @@
"common.ui.management.breadcrumb": "管理",
"common.ui.management.connectDataDisplayName": "データに接続",
"common.ui.management.displayName": "管理",
"common.ui.management.editIndexPattern.createIndex.defaultButtonDescription": "すべてのデータに完全集約を実行",
"common.ui.management.editIndexPattern.createIndex.defaultButtonText": "標準インデックスパターン",
"common.ui.management.editIndexPattern.createIndex.defaultTypeName": "インデックスパターン",
"management.editIndexPattern.createIndex.defaultButtonDescription": "すべてのデータに完全集約を実行",
"management.editIndexPattern.createIndex.defaultButtonText": "標準インデックスパターン",
"management.editIndexPattern.createIndex.defaultTypeName": "インデックスパターン",
"common.ui.management.nav.menu": "管理メニュー",
"common.ui.modals.cancelButtonLabel": "キャンセル",
"common.ui.notify.fatalError.errorStatusMessage": "エラー {errStatus} {errStatusText}: {errMessage}",

View file

@ -463,9 +463,9 @@
"common.ui.management.breadcrumb": "管理",
"common.ui.management.connectDataDisplayName": "连接数据",
"common.ui.management.displayName": "管理",
"common.ui.management.editIndexPattern.createIndex.defaultButtonDescription": "对任何数据执行完全聚合",
"common.ui.management.editIndexPattern.createIndex.defaultButtonText": "标准索引模式",
"common.ui.management.editIndexPattern.createIndex.defaultTypeName": "索引模式",
"management.editIndexPattern.createIndex.defaultButtonDescription": "对任何数据执行完全聚合",
"management.editIndexPattern.createIndex.defaultButtonText": "标准索引模式",
"management.editIndexPattern.createIndex.defaultTypeName": "索引模式",
"common.ui.management.nav.menu": "管理菜单",
"common.ui.modals.cancelButtonLabel": "取消",
"common.ui.notify.fatalError.errorStatusMessage": "错误 {errStatus} {errStatusText}{errMessage}",

View file

@ -153,10 +153,10 @@ export default async function ({ readConfigFile }) {
pathname: '/app/uptime',
},
apm: {
pathname: '/app/apm'
pathname: '/app/apm',
},
ml: {
pathname: '/app/ml'
pathname: '/app/ml',
},
rollupJob: {
pathname: '/app/kibana',