Spaces -> Client to NP (#54298)

* moves

* updates to support spaces client in NP

* fixing MLs import

* update karma mock

* remove unnecessary setup license

* fix merge from master

* moving management app registration to NP

* move space selector app to NP

* remove unused xpackMain legacy dependency

* hide spaces management if not authorized

* additional testing

* additional cleanup

* additional testing

* use NP advancedSettings plugin

* Apply suggestions from code review

Co-Authored-By: Aleh Zasypkin <aleh.zasypkin@gmail.com>

* start addressing PR feedback

* reverting logic to determine serverBasePath

* removing spaces mock

* mantain BWC with old management links

* add types to management mock

* address remaining PR feedback

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com>
This commit is contained in:
Larry Gregory 2020-02-10 09:15:57 -05:00 committed by GitHub
parent bcbb16d1f3
commit 974a51d104
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
206 changed files with 1459 additions and 1591 deletions

View file

@ -25,9 +25,9 @@ const componentType = ComponentRegistry.componentType;
export const advancedSettingsMock = {
createSetupContract() {
return { register, componentType };
return { component: { register, componentType } };
},
createStartContract() {
return { get, componentType };
return { component: { get, componentType } };
},
};

View file

@ -0,0 +1,38 @@
/*
* 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 { featureCatalogueRegistryMock } from '../services/feature_catalogue/feature_catalogue_registry.mock';
import { environmentServiceMock } from '../services/environment/environment.mock';
import { configSchema } from '../../config';
const createSetupContract = () => ({
featureCatalogue: featureCatalogueRegistryMock.createSetup(),
environment: environmentServiceMock.createSetup(),
config: configSchema.validate({}),
});
const createStartContract = () => ({
featureCatalogue: featureCatalogueRegistryMock.createStart(),
environment: environmentServiceMock.createStart(),
});
export const homePluginMock = {
createSetupContract,
createStartContract,
};

View file

@ -17,10 +17,26 @@
* under the License.
*/
const createStartContract = () => ({
import { ManagementSetup, ManagementStart } from '../types';
const createSetupContract = (): DeeplyMockedKeys<ManagementSetup> => ({
sections: {
register: jest.fn(),
getSection: jest.fn(),
getAllSections: jest.fn(),
},
});
const createStartContract = (): DeeplyMockedKeys<ManagementStart> => ({
legacy: {},
sections: {
getSection: jest.fn(),
getAllSections: jest.fn(),
navigateToApp: jest.fn(),
},
});
export const managementPluginMock = {
createSetupContract,
createStartContract,
};

View file

@ -5,8 +5,8 @@
*/
import { Request } from 'hapi';
import { Space } from '../../../../../plugins/spaces/server';
import { LegacySpacesPlugin } from '../../../spaces';
import { Space } from '../../../spaces/common/model/space';
interface GetActiveSpaceResponse {
valid: boolean;

View file

@ -1,28 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export const DEFAULT_SPACE_ID = `default`;
/**
* The minimum number of spaces required to show a search control.
*/
export const SPACE_SEARCH_COUNT_THRESHOLD = 8;
/**
* The maximum number of characters allowed in the Space Avatar's initials
*/
export const MAX_SPACE_INITIALS = 2;
/**
* The type name used within the Monitoring index to publish spaces stats.
* @type {string}
*/
export const KIBANA_SPACES_STATS_TYPE = 'spaces';
/**
* The path to enter a space.
*/
export const ENTER_SPACE_PATH = '/spaces/enter';

View file

@ -1,8 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export { isReservedSpace } from './is_reserved_space';
export { MAX_SPACE_INITIALS } from './constants';

View file

@ -1,34 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { isReservedSpace } from './is_reserved_space';
import { Space } from './model/space';
test('it returns true for reserved spaces', () => {
const space: Space = {
id: '',
name: '',
disabledFeatures: [],
_reserved: true,
};
expect(isReservedSpace(space)).toEqual(true);
});
test('it returns false for non-reserved spaces', () => {
const space: Space = {
id: '',
name: '',
disabledFeatures: [],
};
expect(isReservedSpace(space)).toEqual(false);
});
test('it handles empty input', () => {
// @ts-ignore
expect(isReservedSpace()).toEqual(false);
});

View file

@ -1,18 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { get } from 'lodash';
import { Space } from './model/space';
/**
* Returns whether the given Space is reserved or not.
*
* @param space the space
* @returns boolean
*/
export function isReservedSpace(space?: Partial<Space> | null): boolean {
return get(space, '_reserved', false);
}

View file

@ -1,16 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
export interface Space {
id: string;
name: string;
description?: string;
color?: string;
initials?: string;
disabledFeatures: string[];
_reserved?: boolean;
imageUrl?: string;
}

View file

@ -17,7 +17,7 @@ import { wrapError } from './server/lib/errors';
import { migrateToKibana660 } from './server/lib/migrations';
// @ts-ignore
import { watchStatusAndLicenseToInitialize } from '../../server/lib/watch_status_and_license_to_initialize';
import { initSpaceSelectorView, initEnterSpaceView } from './server/routes/views';
import { initEnterSpaceView } from './server/routes/views';
export interface LegacySpacesPlugin {
getSpaceId: (request: Legacy.Request) => ReturnType<SpacesServiceSetup['getSpaceId']>;
@ -50,15 +50,7 @@ export const spaces = (kibana: Record<string, any>) =>
uiExports: {
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
managementSections: [],
apps: [
{
id: 'space_selector',
title: 'Spaces',
main: 'plugins/spaces/space_selector',
url: 'space_selector',
hidden: true,
},
],
apps: [],
hacks: ['plugins/spaces/legacy'],
mappings,
migrations: {
@ -131,11 +123,9 @@ export const spaces = (kibana: Record<string, any>) =>
create: (pluginId: string) =>
new AuditLogger(server, pluginId, server.config(), server.plugins.xpack_main.info),
},
xpackMain: server.plugins.xpack_main,
});
initEnterSpaceView(server);
initSpaceSelectorView(server);
watchStatusAndLicenseToInitialize(server.plugins.xpack_main, this, async () => {
await createDefaultSpace();

View file

@ -1,18 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
jest.mock('../../../xpack_main/public/services/xpack_info', () => {
return {
xpackInfo: {
get: jest.fn().mockImplementation((key: string) => {
if (key === 'features.security.showLinks') {
return true;
}
throw new Error(`unexpected key: ${key}`);
}),
},
};
});

View file

@ -1,16 +1,4 @@
// Import the EUI global scope so we can use EUI constants
@import 'src/legacy/ui/public/styles/_styling_constants';
/* Spaces plugin styles */
// Prefix all styles with "spc" to avoid conflicts.
// Examples
// spcChart
// spcChart__legend
// spcChart__legend--small
// spcChart__legend-isLoading
@import './management/index';
@import './nav_control/index';
@import './space_selector/index';
@import './copy_saved_objects_to_space/index';
@import '../../../../plugins/spaces/public/index';

View file

@ -4,23 +4,25 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { npSetup, npStart } from 'ui/new_platform';
import { SavedObjectsManagementAction } from 'src/legacy/core_plugins/management/public';
import { npSetup } from 'ui/new_platform';
import routes from 'ui/routes';
import { SpacesPluginSetup } from '../../../../plugins/spaces/public';
import { setup as managementSetup } from '../../../../../src/legacy/core_plugins/management/public/legacy';
import { plugin } from '.';
import { SpacesPlugin, PluginsSetup, PluginsStart } from './plugin';
import './management/legacy_page_routes';
const spacesPlugin: SpacesPlugin = plugin();
const pluginsSetup: PluginsSetup = {
home: npSetup.plugins.home,
management: managementSetup,
advancedSettings: npSetup.plugins.advancedSettings,
const legacyAPI = {
registerSavedObjectsManagementAction: (action: SavedObjectsManagementAction) => {
managementSetup.savedObjects.registry.register(action);
},
};
const pluginsStart: PluginsStart = {
management: npStart.plugins.management,
};
const spaces = (npSetup.plugins as any).spaces as SpacesPluginSetup;
if (spaces) {
spaces.registerLegacyAPI(legacyAPI);
export const setup = spacesPlugin.setup(npSetup.core, pluginsSetup);
export const start = spacesPlugin.start(npStart.core, pluginsStart);
routes.when('/management/spaces/list', { redirectTo: '/management/kibana/spaces' });
routes.when('/management/spaces/create', { redirectTo: '/management/kibana/spaces/create' });
routes.when('/management/spaces/edit/:spaceId', {
redirectTo: '/management/kibana/spaces/edit/:spaceId',
});
}

View file

@ -1,33 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SecureSpaceMessage doesn't render if security is not enabled 1`] = `""`;
exports[`SecureSpaceMessage renders if security is enabled 1`] = `
<Fragment>
<EuiHorizontalRule />
<EuiText
className="eui-textCenter"
>
<p>
<FormattedMessage
defaultMessage="Want to assign a role to a space? Go to {rolesLink}."
id="xpack.spaces.management.secureSpaceMessage.howToAssignRoleToSpaceDescription"
values={
Object {
"rolesLink": <ForwardRef
aria-label="Roles management page"
href="#/management/security/roles"
>
<FormattedMessage
defaultMessage="Roles"
id="xpack.spaces.management.secureSpaceMessage.rolesLinkText"
values={Object {}}
/>
</ForwardRef>,
}
}
/>
</p>
</EuiText>
</Fragment>
`;

View file

@ -1,34 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { SecureSpaceMessage } from './secure_space_message';
let mockShowLinks: boolean = true;
jest.mock('../../../../../xpack_main/public/services/xpack_info', () => {
return {
xpackInfo: {
get: jest.fn().mockImplementation((key: string) => {
if (key === 'features.security.showLinks') {
return mockShowLinks;
}
throw new Error(`unexpected key: ${key}`);
}),
},
};
});
describe('SecureSpaceMessage', () => {
it(`doesn't render if security is not enabled`, () => {
mockShowLinks = false;
expect(shallowWithIntl(<SecureSpaceMessage />)).toMatchSnapshot();
});
it(`renders if security is enabled`, () => {
mockShowLinks = true;
expect(shallowWithIntl(<SecureSpaceMessage />)).toMatchSnapshot();
});
});

View file

@ -1,47 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { EuiHorizontalRule, EuiLink, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import React, { Fragment } from 'react';
// @ts-ignore
import { xpackInfo } from '../../../../../xpack_main/public/services/xpack_info';
export const SecureSpaceMessage = ({}) => {
const showSecurityLinks = xpackInfo.get('features.security.showLinks');
if (showSecurityLinks) {
const rolesLinkTextAriaLabel = i18n.translate(
'xpack.spaces.management.secureSpaceMessage.rolesLinkTextAriaLabel',
{ defaultMessage: 'Roles management page' }
);
return (
<Fragment>
<EuiHorizontalRule />
<EuiText className="eui-textCenter">
<p>
<FormattedMessage
id="xpack.spaces.management.secureSpaceMessage.howToAssignRoleToSpaceDescription"
defaultMessage="Want to assign a role to a space? Go to {rolesLink}."
values={{
rolesLink: (
<EuiLink href="#/management/security/roles" aria-label={rolesLinkTextAriaLabel}>
<FormattedMessage
id="xpack.spaces.management.secureSpaceMessage.rolesLinkText"
defaultMessage="Roles"
/>
</EuiLink>
),
}}
/>
</p>
</EuiText>
</Fragment>
);
}
return null;
};

View file

@ -1,324 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EnabledFeatures renders as expected 1`] = `
<SectionPanel
collapsible={true}
data-test-subj="enabled-features-panel"
description="Customize visible features"
initiallyCollapsed={true}
intl={
Object {
"defaultFormats": Object {},
"defaultLocale": "en",
"formatDate": [Function],
"formatHTMLMessage": [Function],
"formatMessage": [Function],
"formatNumber": [Function],
"formatPlural": [Function],
"formatRelative": [Function],
"formatTime": [Function],
"formats": Object {
"date": Object {
"full": Object {
"day": "numeric",
"month": "long",
"weekday": "long",
"year": "numeric",
},
"long": Object {
"day": "numeric",
"month": "long",
"year": "numeric",
},
"medium": Object {
"day": "numeric",
"month": "short",
"year": "numeric",
},
"short": Object {
"day": "numeric",
"month": "numeric",
"year": "2-digit",
},
},
"number": Object {
"currency": Object {
"style": "currency",
},
"percent": Object {
"style": "percent",
},
},
"relative": Object {
"days": Object {
"units": "day",
},
"hours": Object {
"units": "hour",
},
"minutes": Object {
"units": "minute",
},
"months": Object {
"units": "month",
},
"seconds": Object {
"units": "second",
},
"years": Object {
"units": "year",
},
},
"time": Object {
"full": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
"timeZoneName": "short",
},
"long": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
"timeZoneName": "short",
},
"medium": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
},
"short": Object {
"hour": "numeric",
"minute": "numeric",
},
},
},
"formatters": Object {
"getDateTimeFormat": [Function],
"getMessageFormat": [Function],
"getNumberFormat": [Function],
"getPluralFormat": [Function],
"getRelativeFormat": [Function],
},
"locale": "en",
"messages": Object {},
"now": [Function],
"onError": [Function],
"textComponent": Symbol(react.fragment),
"timeZone": null,
}
}
title={
<span>
<FormattedMessage
defaultMessage="Customize feature display"
id="xpack.spaces.management.enabledSpaceFeatures.enabledFeaturesSectionMessage"
values={Object {}}
/>
<EuiText
color="danger"
size="s"
style={
Object {
"display": "inline-block",
}
}
>
<em>
<FormattedMessage
defaultMessage="(no features visible)"
id="xpack.spaces.management.enabledSpaceFeatures.noFeaturesEnabledMessage"
values={Object {}}
/>
</em>
</EuiText>
</span>
}
>
<EuiFlexGroup>
<EuiFlexItem>
<EuiTitle
size="xs"
>
<h3>
<FormattedMessage
defaultMessage="Control which features are visible in this space."
id="xpack.spaces.management.enabledSpaceFeatures.enableFeaturesInSpaceMessage"
values={Object {}}
/>
</h3>
</EuiTitle>
<EuiSpacer
size="s"
/>
<EuiText
color="subdued"
size="s"
>
<p>
<FormattedMessage
defaultMessage="The feature is hidden in the UI, but is not disabled."
id="xpack.spaces.management.enabledSpaceFeatures.notASecurityMechanismMessage"
values={Object {}}
/>
</p>
<p>
<FormattedMessage
defaultMessage="Want to secure access? Go to {rolesLink}."
id="xpack.spaces.management.enabledSpaceFeatures.goToRolesLink"
values={
Object {
"rolesLink": <ForwardRef
href="#/management/security/roles"
>
<FormattedMessage
defaultMessage="Roles"
id="xpack.spaces.management.enabledSpaceFeatures.rolesLinkText"
values={Object {}}
/>
</ForwardRef>,
}
}
/>
</p>
</EuiText>
</EuiFlexItem>
<EuiFlexItem>
<FeatureTable
features={
Array [
Object {
"app": Array [],
"icon": "spacesApp",
"id": "feature-1",
"name": "Feature 1",
"privileges": Object {},
},
Object {
"app": Array [],
"icon": "spacesApp",
"id": "feature-2",
"name": "Feature 2",
"privileges": Object {},
},
]
}
intl={
Object {
"defaultFormats": Object {},
"defaultLocale": "en",
"formatDate": [Function],
"formatHTMLMessage": [Function],
"formatMessage": [Function],
"formatNumber": [Function],
"formatPlural": [Function],
"formatRelative": [Function],
"formatTime": [Function],
"formats": Object {
"date": Object {
"full": Object {
"day": "numeric",
"month": "long",
"weekday": "long",
"year": "numeric",
},
"long": Object {
"day": "numeric",
"month": "long",
"year": "numeric",
},
"medium": Object {
"day": "numeric",
"month": "short",
"year": "numeric",
},
"short": Object {
"day": "numeric",
"month": "numeric",
"year": "2-digit",
},
},
"number": Object {
"currency": Object {
"style": "currency",
},
"percent": Object {
"style": "percent",
},
},
"relative": Object {
"days": Object {
"units": "day",
},
"hours": Object {
"units": "hour",
},
"minutes": Object {
"units": "minute",
},
"months": Object {
"units": "month",
},
"seconds": Object {
"units": "second",
},
"years": Object {
"units": "year",
},
},
"time": Object {
"full": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
"timeZoneName": "short",
},
"long": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
"timeZoneName": "short",
},
"medium": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
},
"short": Object {
"hour": "numeric",
"minute": "numeric",
},
},
},
"formatters": Object {
"getDateTimeFormat": [Function],
"getMessageFormat": [Function],
"getNumberFormat": [Function],
"getPluralFormat": [Function],
"getRelativeFormat": [Function],
},
"locale": "en",
"messages": Object {},
"now": [Function],
"onError": [Function],
"textComponent": Symbol(react.fragment),
"timeZone": null,
}
}
onChange={[MockFunction]}
space={
Object {
"disabledFeatures": Array [
"feature-1",
"feature-2",
],
"id": "my-space",
"name": "my space",
}
}
/>
</EuiFlexItem>
</EuiFlexGroup>
</SectionPanel>
`;

View file

@ -1,149 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
// @ts-ignore
import template from 'plugins/spaces/management/template.html';
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { I18nContext } from 'ui/i18n';
// @ts-ignore
import routes from 'ui/routes';
import { MANAGEMENT_BREADCRUMB } from 'ui/management/breadcrumbs';
import { npStart } from 'ui/new_platform';
import { ManageSpacePage } from './edit_space';
import { SpacesGridPage } from './spaces_grid';
import { start as spacesNPStart } from '../legacy';
import { Space } from '../../common/model/space';
const reactRootNodeId = 'manageSpacesReactRoot';
function getListBreadcrumbs() {
return [
MANAGEMENT_BREADCRUMB,
{
text: 'Spaces',
href: '#/management/spaces/list',
},
];
}
function getCreateBreadcrumbs() {
return [
...getListBreadcrumbs(),
{
text: 'Create',
},
];
}
function getEditBreadcrumbs(space?: Space) {
return [
...getListBreadcrumbs(),
{
text: space ? space.name : '...',
},
];
}
routes.when('/management/spaces/list', {
template,
k7Breadcrumbs: getListBreadcrumbs,
requireUICapability: 'management.kibana.spaces',
controller($scope: any) {
$scope.$$postDigest(() => {
const domNode = document.getElementById(reactRootNodeId);
const { spacesManager } = spacesNPStart;
render(
<I18nContext>
<SpacesGridPage
spacesManager={spacesManager!}
capabilities={npStart.core.application.capabilities}
/>
</I18nContext>,
domNode
);
// unmount react on controller destroy
$scope.$on('$destroy', () => {
if (domNode) {
unmountComponentAtNode(domNode);
}
});
});
},
});
routes.when('/management/spaces/create', {
template,
k7Breadcrumbs: getCreateBreadcrumbs,
requireUICapability: 'management.kibana.spaces',
controller($scope: any) {
$scope.$$postDigest(() => {
const domNode = document.getElementById(reactRootNodeId);
const { spacesManager } = spacesNPStart;
render(
<I18nContext>
<ManageSpacePage
spacesManager={spacesManager!}
capabilities={npStart.core.application.capabilities}
/>
</I18nContext>,
domNode
);
// unmount react on controller destroy
$scope.$on('$destroy', () => {
if (domNode) {
unmountComponentAtNode(domNode);
}
});
});
},
});
routes.when('/management/spaces/edit', {
redirectTo: '/management/spaces/list',
});
routes.when('/management/spaces/edit/:spaceId', {
template,
k7Breadcrumbs: () => getEditBreadcrumbs(),
requireUICapability: 'management.kibana.spaces',
controller($scope: any, $route: any) {
$scope.$$postDigest(async () => {
const domNode = document.getElementById(reactRootNodeId);
const { spaceId } = $route.current.params;
const { spacesManager } = await spacesNPStart;
render(
<I18nContext>
<ManageSpacePage
spaceId={spaceId}
spacesManager={spacesManager!}
onLoadSpace={space => {
npStart.core.chrome.setBreadcrumbs(getEditBreadcrumbs(space));
}}
capabilities={npStart.core.application.capabilities}
/>
</I18nContext>,
domNode
);
// unmount react on controller destroy
$scope.$on('$destroy', () => {
if (domNode) {
unmountComponentAtNode(domNode);
}
});
});
},
});

View file

@ -1,123 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { ManagementService } from '.';
const mockSections = {
getSection: jest.fn(),
getAllSections: jest.fn(),
navigateToApp: jest.fn(),
};
describe('ManagementService', () => {
describe('#start', () => {
it('registers the spaces management page under the kibana section', () => {
const mockKibanaSection = {
hasItem: jest.fn().mockReturnValue(false),
register: jest.fn(),
};
const managementStart = {
legacy: {
getSection: jest.fn().mockReturnValue(mockKibanaSection),
},
sections: mockSections,
};
const deps = {
managementStart,
};
const service = new ManagementService();
service.start(deps);
expect(deps.managementStart.legacy.getSection).toHaveBeenCalledTimes(1);
expect(deps.managementStart.legacy.getSection).toHaveBeenCalledWith('kibana');
expect(mockKibanaSection.register).toHaveBeenCalledTimes(1);
expect(mockKibanaSection.register).toHaveBeenCalledWith('spaces', {
name: 'spacesManagementLink',
order: 10,
display: 'Spaces',
url: `#/management/spaces/list`,
});
});
it('will not register the spaces management page twice', () => {
const mockKibanaSection = {
hasItem: jest.fn().mockReturnValue(true),
register: jest.fn(),
};
const managementStart = {
legacy: {
getSection: jest.fn().mockReturnValue(mockKibanaSection),
},
sections: mockSections,
};
const deps = {
managementStart,
};
const service = new ManagementService();
service.start(deps);
expect(mockKibanaSection.register).toHaveBeenCalledTimes(0);
});
it('will not register the spaces management page if the kibana section is missing', () => {
const managementStart = {
legacy: {
getSection: jest.fn().mockReturnValue(undefined),
},
sections: mockSections,
};
const deps = {
managementStart,
};
const service = new ManagementService();
service.start(deps);
expect(deps.managementStart.legacy.getSection).toHaveBeenCalledTimes(1);
});
});
describe('#stop', () => {
it('deregisters the spaces management page', () => {
const mockKibanaSection = {
hasItem: jest
.fn()
.mockReturnValueOnce(false)
.mockReturnValueOnce(true),
register: jest.fn(),
deregister: jest.fn(),
};
const managementStart = {
legacy: {
getSection: jest.fn().mockReturnValue(mockKibanaSection),
},
sections: mockSections,
};
const deps = {
managementStart,
};
const service = new ManagementService();
service.start(deps);
service.stop();
expect(mockKibanaSection.register).toHaveBeenCalledTimes(1);
expect(mockKibanaSection.deregister).toHaveBeenCalledTimes(1);
expect(mockKibanaSection.deregister).toHaveBeenCalledWith('spaces');
});
});
});

View file

@ -1,37 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { i18n } from '@kbn/i18n';
import { ManagementStart } from 'src/plugins/management/public';
interface StartDeps {
managementStart: ManagementStart;
}
const MANAGE_SPACES_KEY = 'spaces';
export class ManagementService {
private kibanaSection!: any;
public start({ managementStart }: StartDeps) {
this.kibanaSection = managementStart.legacy.getSection('kibana');
if (this.kibanaSection && !this.kibanaSection.hasItem(MANAGE_SPACES_KEY)) {
this.kibanaSection.register(MANAGE_SPACES_KEY, {
name: 'spacesManagementLink',
order: 10,
display: i18n.translate('xpack.spaces.displayName', {
defaultMessage: 'Spaces',
}),
url: `#/management/spaces/list`,
});
}
}
public stop() {
if (this.kibanaSection && this.kibanaSection.hasItem(MANAGE_SPACES_KEY)) {
this.kibanaSection.deregister(MANAGE_SPACES_KEY);
}
}
}

View file

@ -1,3 +0,0 @@
<kbn-management-app section="kibana/manage_spaces" omit-breadcrumb-pages="['edit']">
<div id="manageSpacesReactRoot" />
</kbn-management-app>

View file

@ -1,43 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SpacesDescription renders without crashing 1`] = `
<EuiContextMenuPanel
className="spcDescription"
hasFocus={true}
id="foo"
items={Array []}
title="Spaces"
>
<EuiText
className="spcDescription__text"
>
<p>
Organize your dashboards and other saved objects into meaningful categories.
</p>
</EuiText>
<div
className="spcDescription__manageButtonWrapper"
key="manageSpacesButton"
>
<ManageSpacesButton
capabilities={
Object {
"catalogue": Object {},
"management": Object {},
"navLinks": Object {},
"spaces": Object {
"manage": true,
},
}
}
onClick={[MockFunction]}
size="s"
style={
Object {
"width": "100%",
}
}
/>
</div>
</EuiContextMenuPanel>
`;

View file

@ -1,30 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { shallow } from 'enzyme';
import React from 'react';
import { SpacesDescription } from './spaces_description';
describe('SpacesDescription', () => {
it('renders without crashing', () => {
expect(
shallow(
<SpacesDescription
id={'foo'}
capabilities={{
navLinks: {},
management: {},
catalogue: {},
spaces: {
manage: true,
},
}}
onManageSpacesClick={jest.fn()}
/>
)
).toMatchSnapshot();
});
});

View file

@ -1,76 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { CoreSetup, CoreStart, Plugin } from 'src/core/public';
import { HomePublicPluginSetup } from 'src/plugins/home/public';
import { ManagementSetup } from 'src/legacy/core_plugins/management/public';
import { ManagementStart } from 'src/plugins/management/public';
import { AdvancedSettingsSetup } from 'src/plugins/advanced_settings/public';
import { SpacesManager } from './spaces_manager';
import { initSpacesNavControl } from './nav_control';
import { createSpacesFeatureCatalogueEntry } from './create_feature_catalogue_entry';
import { CopySavedObjectsToSpaceService } from './copy_saved_objects_to_space';
import { AdvancedSettingsService } from './advanced_settings';
import { ManagementService } from './management';
export interface SpacesPluginStart {
spacesManager: SpacesManager | null;
}
export interface PluginsSetup {
home?: HomePublicPluginSetup;
management: ManagementSetup;
advancedSettings: AdvancedSettingsSetup;
}
export interface PluginsStart {
management: ManagementStart;
}
export class SpacesPlugin implements Plugin<void, SpacesPluginStart, PluginsSetup> {
private spacesManager!: SpacesManager;
private managementService?: ManagementService;
public setup(core: CoreSetup, plugins: PluginsSetup) {
const serverBasePath = core.injectedMetadata.getInjectedVar('serverBasePath') as string;
this.spacesManager = new SpacesManager(serverBasePath, core.http);
const copySavedObjectsToSpaceService = new CopySavedObjectsToSpaceService();
copySavedObjectsToSpaceService.setup({
spacesManager: this.spacesManager,
managementSetup: plugins.management,
});
const advancedSettingsService = new AdvancedSettingsService();
advancedSettingsService.setup({
getActiveSpace: () => this.spacesManager.getActiveSpace(),
componentRegistry: plugins.advancedSettings.component,
});
if (plugins.home) {
plugins.home.featureCatalogue.register(createSpacesFeatureCatalogueEntry());
}
}
public start(core: CoreStart, plugins: PluginsStart) {
initSpacesNavControl(this.spacesManager, core);
this.managementService = new ManagementService();
this.managementService.start({ managementStart: plugins.management });
return {
spacesManager: this.spacesManager,
};
}
public stop() {
if (this.managementService) {
this.managementService.stop();
this.managementService = undefined;
}
}
}

View file

@ -1,43 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
// @ts-ignore
import template from 'plugins/spaces/space_selector/space_selector.html';
import chrome from 'ui/chrome';
import { I18nContext } from 'ui/i18n';
// @ts-ignore
import { uiModules } from 'ui/modules';
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { SpaceSelector } from './space_selector';
import { start as spacesNPStart } from '../legacy';
const module = uiModules.get('spaces_selector', []);
module.controller('spacesSelectorController', ($scope: any) => {
$scope.$$postDigest(() => {
const domNode = document.getElementById('spaceSelectorRoot');
const { spacesManager } = spacesNPStart;
render(
<I18nContext>
<SpaceSelector spacesManager={spacesManager!} />
</I18nContext>,
domNode
);
// unmount react on controller destroy
$scope.$on('$destroy', () => {
if (domNode) {
unmountComponentAtNode(domNode);
}
});
});
});
chrome.setVisible(false).setRootTemplate(template);

View file

@ -1,3 +0,0 @@
<div ng-controller="spacesSelectorController" id="spaceSelectorRootWrap">
<div id="spaceSelectorRoot" />
</div>

View file

@ -5,7 +5,7 @@
*/
import { Legacy } from 'kibana';
import { ENTER_SPACE_PATH } from '../../../common/constants';
import { ENTER_SPACE_PATH } from '../../../../../../plugins/spaces/common/constants';
import { wrapError } from '../../lib/errors';
export function initEnterSpaceView(server: Legacy.Server) {

View file

@ -4,5 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
export { initSpaceSelectorView } from './space_selector';
export { initEnterSpaceView } from './enter_space';

View file

@ -1,19 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { Legacy } from 'kibana';
export function initSpaceSelectorView(server: Legacy.Server) {
const spaceSelector = server.getHiddenUiAppById('space_selector');
server.route({
method: 'GET',
path: '/spaces/space_selector',
async handler(request, h) {
return (await h.renderAppWithDefaultConfig(spaceSelector)).takeover();
},
});
}

View file

@ -5,3 +5,5 @@
*/
export { SecurityLicenseService, SecurityLicense } from './license_service';
export { SecurityLicenseFeatures } from './license_features';

View file

@ -8,7 +8,6 @@ import { act } from '@testing-library/react';
import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers';
import { AuthenticatedUser } from '../../common/model';
import { AccountManagementPage } from './account_management_page';
import { coreMock } from 'src/core/public/mocks';
import { mockAuthenticatedUser } from '../../common/model/authenticated_user.mock';
import { securityMock } from '../mocks';

View file

@ -10,6 +10,7 @@ import { SecurityPlugin, SecurityPluginSetup, SecurityPluginStart } from './plug
export { SecurityPluginSetup, SecurityPluginStart };
export { SessionInfo } from './types';
export { AuthenticatedUser } from '../common/model';
export { SecurityLicense, SecurityLicenseFeatures } from '../common/licensing';
export const plugin: PluginInitializer<SecurityPluginSetup, SecurityPluginStart> = () =>
new SecurityPlugin();

View file

@ -9,7 +9,6 @@ import React from 'react';
import { act } from '@testing-library/react';
import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers';
import { Capabilities } from 'src/core/public';
import { Space } from '../../../../../spaces/common/model/space';
import { Feature } from '../../../../../features/public';
// These modules should be moved into a common directory
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
@ -28,6 +27,7 @@ import { dataPluginMock } from '../../../../../../../src/plugins/data/public/moc
import { licenseMock } from '../../../../common/licensing/index.mock';
import { userAPIClientMock } from '../../users/index.mock';
import { rolesAPIClientMock, indicesAPIClientMock, privilegesAPIClientMock } from '../index.mock';
import { Space } from '../../../../../spaces/public';
const buildFeatures = () => {
return [

View file

@ -37,7 +37,7 @@ import {
NotificationsStart,
} from 'src/core/public';
import { IndexPatternsContract } from '../../../../../../../src/plugins/data/public';
import { Space } from '../../../../../spaces/common/model/space';
import { Space } from '../../../../../spaces/public';
import { Feature } from '../../../../../features/public';
import {
KibanaPrivileges,

View file

@ -6,7 +6,7 @@
import React, { Component } from 'react';
import { Capabilities } from 'src/core/public';
import { Space } from '../../../../../../../spaces/common/model/space';
import { Space } from '../../../../../../../spaces/public';
import { Feature } from '../../../../../../../features/public';
import { KibanaPrivileges, Role } from '../../../../../../common/model';
import { KibanaPrivilegeCalculatorFactory } from './kibana_privilege_calculator';

View file

@ -7,7 +7,7 @@
import { EuiButtonEmpty, EuiInMemoryTable } from '@elastic/eui';
import React from 'react';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { Space } from '../../../../../../../../spaces/common/model/space';
import { Space } from '../../../../../../../../spaces/public';
import { Feature } from '../../../../../../../../features/public';
import { KibanaPrivileges, Role } from '../../../../../../../common/model';
import { KibanaPrivilegeCalculatorFactory } from '../kibana_privilege_calculator';

View file

@ -19,8 +19,7 @@ import {
} from '@elastic/eui';
import { FormattedMessage, InjectedIntl } from '@kbn/i18n/react';
import React, { Component, Fragment } from 'react';
import { SpaceAvatar } from '../../../../../../../../../legacy/plugins/spaces/public/space_avatar';
import { Space } from '../../../../../../../../spaces/common/model/space';
import { Space, SpaceAvatar } from '../../../../../../../../spaces/public';
import { Feature } from '../../../../../../../../features/public';
import { FeaturesPrivileges, Role } from '../../../../../../../common/model';
import { CalculatedPrivilege } from '../kibana_privilege_calculator';

View file

@ -24,7 +24,7 @@ import {
} from '@elastic/eui';
import { FormattedMessage, InjectedIntl } from '@kbn/i18n/react';
import React, { Component, Fragment } from 'react';
import { Space } from '../../../../../../../../spaces/common/model/space';
import { Space } from '../../../../../../../../spaces/public';
import { Feature } from '../../../../../../../../features/public';
import { KibanaPrivileges, Role, copyRole } from '../../../../../../../common/model';
import {

View file

@ -13,8 +13,7 @@ import {
} from '@elastic/eui';
import { FormattedMessage, InjectedIntl } from '@kbn/i18n/react';
import React, { Component } from 'react';
import { getSpaceColor } from '../../../../../../../../../legacy/plugins/spaces/public/space_avatar';
import { Space } from '../../../../../../../../spaces/common/model/space';
import { Space, getSpaceColor } from '../../../../../../../../spaces/public';
import {
FeaturesPrivileges,
Role,

View file

@ -15,7 +15,7 @@ import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
import _ from 'lodash';
import React, { Component, Fragment } from 'react';
import { Capabilities } from 'src/core/public';
import { Space } from '../../../../../../../../spaces/common/model/space';
import { Space } from '../../../../../../../../spaces/public';
import { Feature } from '../../../../../../../../features/public';
import { KibanaPrivileges, Role, isReservedRole } from '../../../../../../../common/model';
import { KibanaPrivilegeCalculatorFactory } from '../kibana_privilege_calculator';

View file

@ -7,8 +7,7 @@
import { EuiComboBox, EuiComboBoxOptionProps, EuiHealth, EuiHighlight } from '@elastic/eui';
import { InjectedIntl } from '@kbn/i18n/react';
import React, { Component } from 'react';
import { getSpaceColor } from '../../../../../../../../../legacy/plugins/spaces/public/space_avatar';
import { Space } from '../../../../../../../../spaces/common/model/space';
import { Space, getSpaceColor } from '../../../../../../../../spaces/public';
const spaceToOption = (space?: Space, currentSelection?: 'global' | 'spaces') => {
if (!space) {

View file

@ -14,9 +14,8 @@ import {
} from '@elastic/eui';
import { FormattedMessage, InjectedIntl } from '@kbn/i18n/react';
import React, { Component } from 'react';
import { SpaceAvatar } from '../../../../../../../legacy/plugins/spaces/public/space_avatar';
import { Space, SpaceAvatar } from '../../../../../../spaces/public';
import { SPACE_SEARCH_COUNT_THRESHOLD } from '../../../../../../spaces/common';
import { Space } from '../../../../../../spaces/common/model/space';
interface Props {
spaces: Space[];

View file

@ -10,7 +10,6 @@ import { EditUserPage } from './edit_user_page';
import React from 'react';
import { User, Role } from '../../../../common/model';
import { ReactWrapper } from 'enzyme';
import { coreMock } from '../../../../../../../src/core/public/mocks';
import { mockAuthenticatedUser } from '../../../../common/model/authenticated_user.mock';
import { securityMock } from '../../../mocks';

View file

@ -6,11 +6,13 @@
import { authenticationMock } from './authentication/index.mock';
import { createSessionTimeoutMock } from './session/session_timeout.mock';
import { licenseMock } from '../common/licensing/index.mock';
function createSetupMock() {
return {
authc: authenticationMock.createSetup(),
sessionTimeout: createSessionTimeoutMock(),
license: licenseMock.create(),
};
}

View file

@ -107,10 +107,11 @@ export class SecurityPlugin
return {
authc: this.authc,
sessionTimeout: this.sessionTimeout,
license,
};
}
public start(core: CoreStart, { data, management }: PluginStartDependencies) {
public start(core: CoreStart, { management }: PluginStartDependencies) {
this.sessionTimeout.start();
this.navControlService.start({ core });

View file

@ -4,7 +4,7 @@
"kibanaVersion": "kibana",
"configPath": ["xpack", "spaces"],
"requiredPlugins": ["features", "licensing"],
"optionalPlugins": ["security", "home", "usageCollection"],
"optionalPlugins": ["advancedSettings", "home", "management", "security", "usageCollection"],
"server": true,
"ui": false
"ui": true
}

View file

@ -5,7 +5,7 @@
*/
import { AdvancedSettingsService } from './advanced_settings_service';
import { advancedSettingsMock } from '../../../../../../src/plugins/advanced_settings/public/mocks';
import { advancedSettingsMock } from '../../../../../src/plugins/advanced_settings/public/mocks';
const componentRegistryMock = advancedSettingsMock.createSetupContract();
@ -14,7 +14,7 @@ describe('Advanced Settings Service', () => {
it('registers space-aware components to augment the advanced settings screen', () => {
const deps = {
getActiveSpace: jest.fn().mockResolvedValue({ id: 'foo', name: 'foo-space' }),
componentRegistry: componentRegistryMock,
componentRegistry: componentRegistryMock.component,
};
const advancedSettingsService = new AdvancedSettingsService();
@ -22,13 +22,13 @@ describe('Advanced Settings Service', () => {
expect(deps.componentRegistry.register).toHaveBeenCalledTimes(2);
expect(deps.componentRegistry.register).toHaveBeenCalledWith(
componentRegistryMock.componentType.PAGE_TITLE_COMPONENT,
componentRegistryMock.component.componentType.PAGE_TITLE_COMPONENT,
expect.any(Function),
true
);
expect(deps.componentRegistry.register).toHaveBeenCalledWith(
componentRegistryMock.componentType.PAGE_SUBTITLE_COMPONENT,
componentRegistryMock.component.componentType.PAGE_SUBTITLE_COMPONENT,
expect.any(Function),
true
);

View file

@ -4,9 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import { AdvancedSettingsSetup } from 'src/plugins/advanced_settings/public';
import { Space } from '../../common/model/space';
import { AdvancedSettingsTitle, AdvancedSettingsSubtitle } from './components';
import { AdvancedSettingsSetup } from '../../../../../../src/plugins/advanced_settings/public';
interface SetupDeps {
getActiveSpace: () => Promise<Space>;

View file

@ -7,7 +7,7 @@
import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { useState, useEffect } from 'react';
import { Space } from '../../../../../../../plugins/spaces/common/model/space';
import { Space } from '../../../../common/model/space';
import { SpaceAvatar } from '../../../space_avatar';
interface Props {

View file

@ -5,7 +5,6 @@
*/
import { i18n } from '@kbn/i18n';
import { npSetup } from 'ui/new_platform';
let spacesFeatureDescription: string;
@ -19,6 +18,3 @@ export const getSpacesFeatureDescription = () => {
return spacesFeatureDescription;
};
export const getManageSpacesUrl = () =>
npSetup.core.http.basePath.prepend(`/app/kibana#/management/spaces/list`);

View file

@ -6,7 +6,7 @@
import React from 'react';
import Boom from 'boom';
import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers';
import { mockManagementPlugin } from '../../../../../../../src/legacy/core_plugins/management/public/np_ready/mocks';
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';
@ -17,9 +17,9 @@ import { act } from '@testing-library/react';
import { ProcessingCopyToSpace } from './processing_copy_to_space';
import { spacesManagerMock } from '../../spaces_manager/mocks';
import { SpacesManager } from '../../spaces_manager';
import { ToastNotifications } from 'ui/notify/toasts/toast_notifications';
import { ToastsApi } from 'src/core/public';
jest.mock('../../../../../../../src/legacy/core_plugins/management/public/legacy', () => ({
jest.mock('../../../../../../src/legacy/core_plugins/management/public/legacy', () => ({
setup: mockManagementPlugin.createSetupContract(),
start: mockManagementPlugin.createStartContract(),
}));
@ -86,7 +86,7 @@ const setup = async (opts: SetupOpts = {}) => {
<CopySavedObjectsToSpaceFlyout
savedObject={savedObjectToCopy}
spacesManager={(mockSpacesManager as unknown) as SpacesManager}
toastNotifications={(mockToastNotifications as unknown) as ToastNotifications}
toastNotifications={(mockToastNotifications as unknown) as ToastsApi}
onClose={onClose}
/>
);

View file

@ -21,12 +21,12 @@ import {
import { mapValues } from 'lodash';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { ToastNotifications } from 'ui/notify/toasts/toast_notifications';
import { SavedObjectsManagementRecord } from '../../../../../../../src/legacy/core_plugins/management/public';
import { ToastsStart } from 'src/core/public';
import {
SavedObjectsManagementRecord,
ProcessedImportResponse,
processImportResponse,
} from '../../../../../../../src/legacy/core_plugins/management/public';
} from '../../../../../../src/legacy/core_plugins/management/public';
import { Space } from '../../../common/model/space';
import { SpacesManager } from '../../spaces_manager';
import { ProcessingCopyToSpace } from './processing_copy_to_space';
@ -38,7 +38,7 @@ interface Props {
onClose: () => void;
savedObject: SavedObjectsManagementRecord;
spacesManager: SpacesManager;
toastNotifications: ToastNotifications;
toastNotifications: ToastsStart;
}
export const CopySavedObjectsToSpaceFlyout = (props: Props) => {

View file

@ -8,7 +8,7 @@ import React, { Fragment } from 'react';
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 { ProcessedImportResponse } from '../../../../../../src/legacy/core_plugins/management/public';
import { ImportRetry } from '../types';
interface Props {

View file

@ -13,8 +13,10 @@ 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 {
SavedObjectsManagementRecord,
ProcessedImportResponse,
} from '../../../../../../src/legacy/core_plugins/management/public';
import { Space } from '../../../common/model/space';
import { CopyOptions, ImportRetry } from '../types';
import { SpaceResult } from './space_result';

View file

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

View file

@ -8,7 +8,7 @@ import React from 'react';
import { EuiText, EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { SummarizedCopyToSpaceResult } from '../index';
import { SavedObjectsManagementRecord } from '../../../../../../../src/legacy/core_plugins/management/public';
import { SavedObjectsManagementRecord } from '../../../../../../src/legacy/core_plugins/management/public';
import { Space } from '../../../common/model/space';
import { CopyStatusIndicator } from './copy_status_indicator';
import { ImportRetry } from '../types';

View file

@ -5,11 +5,11 @@
*/
import React from 'react';
import { i18n } from '@kbn/i18n';
import { toastNotifications } from 'ui/notify';
import { NotificationsStart } from 'src/core/public';
import {
SavedObjectsManagementAction,
SavedObjectsManagementRecord,
} from '../../../../../../src/legacy/core_plugins/management/public';
} from '../../../../../src/legacy/core_plugins/management/public';
import { CopySavedObjectsToSpaceFlyout } from './components';
import { SpacesManager } from '../spaces_manager';
@ -30,7 +30,10 @@ export class CopyToSpaceSavedObjectsManagementAction extends SavedObjectsManagem
},
};
constructor(private readonly spacesManager: SpacesManager) {
constructor(
private readonly spacesManager: SpacesManager,
private readonly notifications: NotificationsStart
) {
super();
}
@ -43,7 +46,7 @@ export class CopyToSpaceSavedObjectsManagementAction extends SavedObjectsManagem
onClose={this.onClose}
savedObject={this.record}
spacesManager={this.spacesManager}
toastNotifications={toastNotifications}
toastNotifications={this.notifications.toasts}
/>
);
};

View file

@ -8,12 +8,14 @@ import { ManagementSetup } from 'src/legacy/core_plugins/management/public';
import { CopyToSpaceSavedObjectsManagementAction } from './copy_saved_objects_to_space_action';
import { spacesManagerMock } from '../spaces_manager/mocks';
import { CopySavedObjectsToSpaceService } from '.';
import { notificationServiceMock } from 'src/core/public/mocks';
describe('CopySavedObjectsToSpaceService', () => {
describe('#setup', () => {
it('registers the CopyToSpaceSavedObjectsManagementAction', () => {
const deps = {
spacesManager: spacesManagerMock.create(),
notificationsSetup: notificationServiceMock.createSetupContract(),
// we don't have a proper NP mock for this yet
managementSetup: ({
savedObjects: {

View file

@ -5,17 +5,19 @@
*/
import { ManagementSetup } from 'src/legacy/core_plugins/management/public';
import { NotificationsSetup } from 'src/core/public';
import { CopyToSpaceSavedObjectsManagementAction } from './copy_saved_objects_to_space_action';
import { SpacesManager } from '../spaces_manager';
interface SetupDeps {
spacesManager: SpacesManager;
managementSetup: ManagementSetup;
managementSetup: Pick<ManagementSetup, 'savedObjects'>;
notificationsSetup: NotificationsSetup;
}
export class CopySavedObjectsToSpaceService {
public setup({ spacesManager, managementSetup }: SetupDeps) {
const action = new CopyToSpaceSavedObjectsManagementAction(spacesManager);
public setup({ spacesManager, managementSetup, notificationsSetup }: SetupDeps) {
const action = new CopyToSpaceSavedObjectsManagementAction(spacesManager, notificationsSetup);
managementSetup.savedObjects.registry.register(action);
}
}

View file

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

View file

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

View file

@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n';
import {
FeatureCatalogueEntry,
FeatureCatalogueCategory,
} from '../../../../../src/plugins/home/public';
} from '../../../../src/plugins/home/public';
import { getSpacesFeatureDescription } from './constants';
export const createSpacesFeatureCatalogueEntry = (): FeatureCatalogueEntry => {
@ -19,7 +19,7 @@ export const createSpacesFeatureCatalogueEntry = (): FeatureCatalogueEntry => {
}),
description: getSpacesFeatureDescription(),
icon: 'spacesApp',
path: '/app/kibana#/management/spaces/list',
path: '/app/kibana#/management/kibana/spaces',
showOnHomePage: true,
category: FeatureCatalogueCategory.ADMIN,
};

View file

@ -0,0 +1,16 @@
// Import the EUI global scope so we can use EUI constants
@import 'src/legacy/ui/public/styles/_styling_constants';
/* Spaces plugin styles */
// Prefix all styles with "spc" to avoid conflicts.
// Examples
// spcChart
// spcChart__legend
// spcChart__legend--small
// spcChart__legend-isLoading
@import './management/index';
@import './nav_control/index';
@import './space_selector/index';
@import './copy_saved_objects_to_space/index';

View file

@ -5,7 +5,11 @@
*/
import { SpacesPlugin } from './plugin';
export { SpaceAvatar } from './space_avatar';
export { Space } from '../common/model/space';
export { SpaceAvatar, getSpaceColor, getSpaceImageUrl, getSpaceInitials } from './space_avatar';
export { SpacesPluginSetup, SpacesPluginStart } from './plugin';
export const plugin = () => {
return new SpacesPlugin();

View file

@ -0,0 +1,40 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { EuiHorizontalRule, EuiLink, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import React, { Fragment } from 'react';
export const SecureSpaceMessage = () => {
const rolesLinkTextAriaLabel = i18n.translate(
'xpack.spaces.management.secureSpaceMessage.rolesLinkTextAriaLabel',
{ defaultMessage: 'Roles management page' }
);
return (
<Fragment>
<EuiHorizontalRule />
<EuiText className="eui-textCenter">
<p>
<FormattedMessage
id="xpack.spaces.management.secureSpaceMessage.howToAssignRoleToSpaceDescription"
defaultMessage="Want to assign a role to a space? Go to {rolesLink}."
values={{
rolesLink: (
<EuiLink href="#/management/security/roles" aria-label={rolesLinkTextAriaLabel}>
<FormattedMessage
id="xpack.spaces.management.secureSpaceMessage.rolesLinkText"
defaultMessage="Roles"
/>
</EuiLink>
),
}}
/>
</p>
</EuiText>
</Fragment>
);
};

Some files were not shown because too many files have changed in this diff Show more