diff --git a/.eslintignore b/.eslintignore
index c4fb806b6d394c..86a01b68ecab1f 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -9,6 +9,7 @@ bower_components
/built_assets
/html_docs
/src/plugins/data/common/es_query/kuery/ast/_generated_/**
+/src/legacy/core_plugins/vis_type_timelion/public/_generated_/**
src/legacy/core_plugins/vis_type_vislib/public/vislib/__tests__/lib/fixtures/mock_data
/src/legacy/ui/public/angular-bootstrap
/src/legacy/ui/public/flot-charts
diff --git a/docs/development/core/public/kibana-plugin-public.chromenavlinks.update.md b/docs/development/core/public/kibana-plugin-public.chromenavlinks.update.md
index d1cd2d3b049501..155d149f334a17 100644
--- a/docs/development/core/public/kibana-plugin-public.chromenavlinks.update.md
+++ b/docs/development/core/public/kibana-plugin-public.chromenavlinks.update.md
@@ -1,30 +1,30 @@
-
-
-[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ChromeNavLinks](./kibana-plugin-public.chromenavlinks.md) > [update](./kibana-plugin-public.chromenavlinks.update.md)
-
-## ChromeNavLinks.update() method
-
-> Warning: This API is now obsolete.
->
-> Uses the [AppBase.updater$](./kibana-plugin-public.appbase.updater_.md) property when registering your application with [ApplicationSetup.register()](./kibana-plugin-public.applicationsetup.register.md) instead.
->
-
-Update the navlink for the given id with the updated attributes. Returns the updated navlink or `undefined` if it does not exist.
-
-Signature:
-
-```typescript
-update(id: string, values: ChromeNavLinkUpdateableFields): ChromeNavLink | undefined;
-```
-
-## Parameters
-
-| Parameter | Type | Description |
-| --- | --- | --- |
-| id | string
| |
-| values | ChromeNavLinkUpdateableFields
| |
-
-Returns:
-
-`ChromeNavLink | undefined`
-
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [ChromeNavLinks](./kibana-plugin-public.chromenavlinks.md) > [update](./kibana-plugin-public.chromenavlinks.update.md)
+
+## ChromeNavLinks.update() method
+
+> Warning: This API is now obsolete.
+>
+> Uses the [AppBase.updater$](./kibana-plugin-public.appbase.updater_.md) property when registering your application with [ApplicationSetup.register()](./kibana-plugin-public.applicationsetup.register.md) instead.
+>
+
+Update the navlink for the given id with the updated attributes. Returns the updated navlink or `undefined` if it does not exist.
+
+Signature:
+
+```typescript
+update(id: string, values: ChromeNavLinkUpdateableFields): ChromeNavLink | undefined;
+```
+
+## Parameters
+
+| Parameter | Type | Description |
+| --- | --- | --- |
+| id | string
| |
+| values | ChromeNavLinkUpdateableFields
| |
+
+Returns:
+
+`ChromeNavLink | undefined`
+
diff --git a/docs/development/core/public/kibana-plugin-public.corestart.fatalerrors.md b/docs/development/core/public/kibana-plugin-public.corestart.fatalerrors.md
new file mode 100644
index 00000000000000..540b17b5a6f0b3
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.corestart.fatalerrors.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [CoreStart](./kibana-plugin-public.corestart.md) > [fatalErrors](./kibana-plugin-public.corestart.fatalerrors.md)
+
+## CoreStart.fatalErrors property
+
+[FatalErrorsStart](./kibana-plugin-public.fatalerrorsstart.md)
+
+Signature:
+
+```typescript
+fatalErrors: FatalErrorsStart;
+```
diff --git a/docs/development/core/public/kibana-plugin-public.corestart.md b/docs/development/core/public/kibana-plugin-public.corestart.md
index e561ee313f1000..83af82d590c364 100644
--- a/docs/development/core/public/kibana-plugin-public.corestart.md
+++ b/docs/development/core/public/kibana-plugin-public.corestart.md
@@ -19,6 +19,7 @@ export interface CoreStart
| [application](./kibana-plugin-public.corestart.application.md) | ApplicationStart
| [ApplicationStart](./kibana-plugin-public.applicationstart.md) |
| [chrome](./kibana-plugin-public.corestart.chrome.md) | ChromeStart
| [ChromeStart](./kibana-plugin-public.chromestart.md) |
| [docLinks](./kibana-plugin-public.corestart.doclinks.md) | DocLinksStart
| [DocLinksStart](./kibana-plugin-public.doclinksstart.md) |
+| [fatalErrors](./kibana-plugin-public.corestart.fatalerrors.md) | FatalErrorsStart
| [FatalErrorsStart](./kibana-plugin-public.fatalerrorsstart.md) |
| [http](./kibana-plugin-public.corestart.http.md) | HttpStart
| [HttpStart](./kibana-plugin-public.httpstart.md) |
| [i18n](./kibana-plugin-public.corestart.i18n.md) | I18nStart
| [I18nStart](./kibana-plugin-public.i18nstart.md) |
| [injectedMetadata](./kibana-plugin-public.corestart.injectedmetadata.md) | {
getInjectedVar: (name: string, defaultValue?: any) => unknown;
}
| exposed temporarily until https://github.com/elastic/kibana/issues/41990 done use \*only\* to retrieve config values. There is no way to set injected values in the new platform. Use the legacy platform API instead. |
diff --git a/docs/development/core/public/kibana-plugin-public.fatalerrorsstart.md b/docs/development/core/public/kibana-plugin-public.fatalerrorsstart.md
new file mode 100644
index 00000000000000..a8ece7dcb7e02d
--- /dev/null
+++ b/docs/development/core/public/kibana-plugin-public.fatalerrorsstart.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [kibana-plugin-public](./kibana-plugin-public.md) > [FatalErrorsStart](./kibana-plugin-public.fatalerrorsstart.md)
+
+## FatalErrorsStart type
+
+FatalErrors stop the Kibana Public Core and displays a fatal error screen with details about the Kibana build and the error.
+
+Signature:
+
+```typescript
+export declare type FatalErrorsStart = FatalErrorsSetup;
+```
diff --git a/docs/development/core/public/kibana-plugin-public.md b/docs/development/core/public/kibana-plugin-public.md
index 27ca9f2d9fd577..27037d46926c18 100644
--- a/docs/development/core/public/kibana-plugin-public.md
+++ b/docs/development/core/public/kibana-plugin-public.md
@@ -129,6 +129,7 @@ The plugin integrates with the core system via lifecycle events: `setup`
| [ChromeHelpExtensionMenuGitHubLink](./kibana-plugin-public.chromehelpextensionmenugithublink.md) | |
| [ChromeHelpExtensionMenuLink](./kibana-plugin-public.chromehelpextensionmenulink.md) | |
| [ChromeNavLinkUpdateableFields](./kibana-plugin-public.chromenavlinkupdateablefields.md) | |
+| [FatalErrorsStart](./kibana-plugin-public.fatalerrorsstart.md) | FatalErrors stop the Kibana Public Core and displays a fatal error screen with details about the Kibana build and the error. |
| [HandlerContextType](./kibana-plugin-public.handlercontexttype.md) | Extracts the type of the first argument of a [HandlerFunction](./kibana-plugin-public.handlerfunction.md) to represent the type of the context. |
| [HandlerFunction](./kibana-plugin-public.handlerfunction.md) | A function that accepts a context object and an optional number of additional arguments. Used for the generic types in [IContextContainer](./kibana-plugin-public.icontextcontainer.md) |
| [HandlerParameters](./kibana-plugin-public.handlerparameters.md) | Extracts the types of the additional arguments of a [HandlerFunction](./kibana-plugin-public.handlerfunction.md), excluding the [HandlerContextType](./kibana-plugin-public.handlercontexttype.md). |
diff --git a/docs/development/core/server/kibana-plugin-server.coresetup.getstartservices.md b/docs/development/core/server/kibana-plugin-server.coresetup.getstartservices.md
new file mode 100644
index 00000000000000..b05d28899f9d23
--- /dev/null
+++ b/docs/development/core/server/kibana-plugin-server.coresetup.getstartservices.md
@@ -0,0 +1,17 @@
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [CoreSetup](./kibana-plugin-server.coresetup.md) > [getStartServices](./kibana-plugin-server.coresetup.getstartservices.md)
+
+## CoreSetup.getStartServices() method
+
+Allows plugins to get access to APIs available in start inside async handlers. Promise will not resolve until Core and plugin dependencies have completed `start`. This should only be used inside handlers registered during `setup` that will only be executed after `start` lifecycle.
+
+Signature:
+
+```typescript
+getStartServices(): Promise<[CoreStart, TPluginsStart]>;
+```
+Returns:
+
+`Promise<[CoreStart, TPluginsStart]>`
+
diff --git a/docs/development/core/server/kibana-plugin-server.coresetup.md b/docs/development/core/server/kibana-plugin-server.coresetup.md
index 3f7f5b727ee804..c36d649837e8a8 100644
--- a/docs/development/core/server/kibana-plugin-server.coresetup.md
+++ b/docs/development/core/server/kibana-plugin-server.coresetup.md
@@ -1,26 +1,32 @@
-
-
-[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [CoreSetup](./kibana-plugin-server.coresetup.md)
-
-## CoreSetup interface
-
-Context passed to the plugins `setup` method.
-
-Signature:
-
-```typescript
-export interface CoreSetup
-```
-
-## Properties
-
-| Property | Type | Description |
-| --- | --- | --- |
-| [capabilities](./kibana-plugin-server.coresetup.capabilities.md) | CapabilitiesSetup
| [CapabilitiesSetup](./kibana-plugin-server.capabilitiessetup.md) |
-| [context](./kibana-plugin-server.coresetup.context.md) | ContextSetup
| [ContextSetup](./kibana-plugin-server.contextsetup.md) |
-| [elasticsearch](./kibana-plugin-server.coresetup.elasticsearch.md) | ElasticsearchServiceSetup
| [ElasticsearchServiceSetup](./kibana-plugin-server.elasticsearchservicesetup.md) |
-| [http](./kibana-plugin-server.coresetup.http.md) | HttpServiceSetup
| [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) |
-| [savedObjects](./kibana-plugin-server.coresetup.savedobjects.md) | SavedObjectsServiceSetup
| [SavedObjectsServiceSetup](./kibana-plugin-server.savedobjectsservicesetup.md) |
-| [uiSettings](./kibana-plugin-server.coresetup.uisettings.md) | UiSettingsServiceSetup
| [UiSettingsServiceSetup](./kibana-plugin-server.uisettingsservicesetup.md) |
-| [uuid](./kibana-plugin-server.coresetup.uuid.md) | UuidServiceSetup
| [UuidServiceSetup](./kibana-plugin-server.uuidservicesetup.md) |
-
+
+
+[Home](./index.md) > [kibana-plugin-server](./kibana-plugin-server.md) > [CoreSetup](./kibana-plugin-server.coresetup.md)
+
+## CoreSetup interface
+
+Context passed to the plugins `setup` method.
+
+Signature:
+
+```typescript
+export interface CoreSetup
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [capabilities](./kibana-plugin-server.coresetup.capabilities.md) | CapabilitiesSetup
| [CapabilitiesSetup](./kibana-plugin-server.capabilitiessetup.md) |
+| [context](./kibana-plugin-server.coresetup.context.md) | ContextSetup
| [ContextSetup](./kibana-plugin-server.contextsetup.md) |
+| [elasticsearch](./kibana-plugin-server.coresetup.elasticsearch.md) | ElasticsearchServiceSetup
| [ElasticsearchServiceSetup](./kibana-plugin-server.elasticsearchservicesetup.md) |
+| [http](./kibana-plugin-server.coresetup.http.md) | HttpServiceSetup
| [HttpServiceSetup](./kibana-plugin-server.httpservicesetup.md) |
+| [savedObjects](./kibana-plugin-server.coresetup.savedobjects.md) | SavedObjectsServiceSetup
| [SavedObjectsServiceSetup](./kibana-plugin-server.savedobjectsservicesetup.md) |
+| [uiSettings](./kibana-plugin-server.coresetup.uisettings.md) | UiSettingsServiceSetup
| [UiSettingsServiceSetup](./kibana-plugin-server.uisettingsservicesetup.md) |
+| [uuid](./kibana-plugin-server.coresetup.uuid.md) | UuidServiceSetup
| [UuidServiceSetup](./kibana-plugin-server.uuidservicesetup.md) |
+
+## Methods
+
+| Method | Description |
+| --- | --- |
+| [getStartServices()](./kibana-plugin-server.coresetup.getstartservices.md) | Allows plugins to get access to APIs available in start inside async handlers. Promise will not resolve until Core and plugin dependencies have completed start
. This should only be used inside handlers registered during setup
that will only be executed after start
lifecycle. |
+
diff --git a/src/core/public/application/__snapshots__/application_service.test.ts.snap b/src/core/public/application/__snapshots__/application_service.test.ts.snap
new file mode 100644
index 00000000000000..376b320b64ea9a
--- /dev/null
+++ b/src/core/public/application/__snapshots__/application_service.test.ts.snap
@@ -0,0 +1,84 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`#start() getComponent returns renderable JSX tree 1`] = `
+
+`;
diff --git a/src/core/public/application/application_service.test.ts b/src/core/public/application/application_service.test.ts
index 4672a42c9eb060..54489fbd182b47 100644
--- a/src/core/public/application/application_service.test.ts
+++ b/src/core/public/application/application_service.test.ts
@@ -525,17 +525,7 @@ describe('#start()', () => {
const { getComponent } = await service.start(startDeps);
expect(() => shallow(createElement(getComponent))).not.toThrow();
- expect(getComponent()).toMatchInlineSnapshot(`
-
- `);
+ expect(getComponent()).toMatchSnapshot();
});
it('renders null when in legacy mode', async () => {
diff --git a/src/core/public/application/application_service.tsx b/src/core/public/application/application_service.tsx
index c69b96274aa95e..4d714c8f9dad2d 100644
--- a/src/core/public/application/application_service.tsx
+++ b/src/core/public/application/application_service.tsx
@@ -19,7 +19,7 @@
import React from 'react';
import { BehaviorSubject, Observable, Subject, Subscription } from 'rxjs';
-import { map, takeUntil } from 'rxjs/operators';
+import { map, shareReplay, takeUntil } from 'rxjs/operators';
import { createBrowserHistory, History } from 'history';
import { InjectedMetadataSetup } from '../injected_metadata';
@@ -256,6 +256,11 @@ export class ApplicationService {
)
.subscribe(apps => applications$.next(apps));
+ const applicationStatuses$ = applications$.pipe(
+ map(apps => new Map([...apps.entries()].map(([id, app]) => [id, app.status!]))),
+ shareReplay(1)
+ );
+
return {
applications$,
capabilities,
@@ -264,11 +269,6 @@ export class ApplicationService {
getUrlForApp: (appId, { path }: { path?: string } = {}) =>
getAppUrl(availableMounters, appId, path),
navigateToApp: async (appId, { path, state }: { path?: string; state?: any } = {}) => {
- const app = applications$.value.get(appId);
- if (app && app.status !== AppStatus.accessible) {
- // should probably redirect to the error page instead
- throw new Error(`Trying to navigate to an inaccessible application: ${appId}`);
- }
if (await this.shouldNavigate(overlays)) {
this.appLeaveHandlers.delete(this.currentAppId$.value!);
this.navigate!(getAppUrl(availableMounters, appId, path), state);
@@ -283,6 +283,7 @@ export class ApplicationService {
);
diff --git a/src/core/public/application/integration_tests/router.test.tsx b/src/core/public/application/integration_tests/router.test.tsx
index cc71cf8722df4d..4d83ab67810afa 100644
--- a/src/core/public/application/integration_tests/router.test.tsx
+++ b/src/core/public/application/integration_tests/router.test.tsx
@@ -18,15 +18,18 @@
*/
import React from 'react';
+import { BehaviorSubject } from 'rxjs';
import { createMemoryHistory, History, createHashHistory } from 'history';
import { AppRouter, AppNotFound } from '../ui';
import { EitherApp, MockedMounterMap, MockedMounterTuple } from '../test_types';
import { createRenderer, createAppMounter, createLegacyAppMounter } from './utils';
+import { AppStatus } from '../types';
describe('AppContainer', () => {
let mounters: MockedMounterMap;
let history: History;
+ let appStatuses$: BehaviorSubject
}
>
@@ -121,7 +119,7 @@ export class ElasticsearchPrivileges extends Component {
id="xpack.security.management.editRole.elasticSearchPrivileges.howToBeSubmittedOnBehalfOfOtherUsersDescription"
defaultMessage="Allow requests to be submitted on the behalf of other users. "
/>
- {this.learnMore(documentationLinks.esRunAsPrivileges)}
+ {this.learnMore(docLinks.getESRunAsPrivilegesDocUrl())}
}
>
@@ -165,7 +163,7 @@ export class ElasticsearchPrivileges extends Component {
id="xpack.security.management.editRole.elasticSearchPrivileges.controlAccessToClusterDataDescription"
defaultMessage="Control access to the data in your cluster. "
/>
- {this.learnMore(documentationLinks.esIndicesPrivileges)}
+ {this.learnMore(docLinks.getESIndicesPrivilegesDocUrl())}
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.test.tsx
similarity index 99%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.test.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.test.tsx
index 6d386fd78a11b1..5e2da513143653 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.test.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.test.tsx
@@ -6,7 +6,7 @@
import { EuiButtonIcon, EuiTextArea } from '@elastic/eui';
import React from 'react';
import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
-import { RoleValidator } from '../../../lib/validate_role';
+import { RoleValidator } from '../../validate_role';
import { IndexPrivilegeForm } from './index_privilege_form';
test('it renders without crashing', () => {
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.tsx
similarity index 98%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.tsx
index bafc56dc167ea5..15e0367c2b6dc1 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privilege_form.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privilege_form.tsx
@@ -19,8 +19,8 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import _ from 'lodash';
import React, { ChangeEvent, Component, Fragment } from 'react';
-import { RoleIndexPrivilege } from '../../../../../../../common/model';
-import { RoleValidator } from '../../../lib/validate_role';
+import { RoleIndexPrivilege } from '../../../../../../common/model';
+import { RoleValidator } from '../../validate_role';
const fromOption = (option: any) => option.label;
const toOption = (value: string) => ({ label: value });
@@ -164,7 +164,6 @@ export class IndexPrivilegeForm extends Component {
{!isReadOnlyRole && (
{
- // @ts-ignore missing "compressed" prop definition
{
}
return (
- // @ts-ignore
{!this.props.isReadOnlyRole && (
{
- // @ts-ignore missing "compressed" proptype
new Promise(setImmediate);
test('it renders without crashing', async () => {
+ const license = licenseMock.create();
+ license.getFeatures.mockReturnValue({
+ allowRoleFieldLevelSecurity: true,
+ allowRoleDocumentLevelSecurity: true,
+ } as any);
+
const props = {
role: {
name: '',
@@ -25,14 +34,13 @@ test('it renders without crashing', async () => {
run_as: [],
},
},
- httpClient: jest.fn(),
onChange: jest.fn(),
indexPatterns: [],
editable: true,
- allowDocumentLevelSecurity: true,
- allowFieldLevelSecurity: true,
validator: new RoleValidator(),
availableIndexPrivileges: ['all', 'read', 'write', 'index'],
+ indicesAPIClient: indicesAPIClientMock.create(),
+ license,
};
const wrapper = shallowWithIntl();
await flushPromises();
@@ -40,6 +48,12 @@ test('it renders without crashing', async () => {
});
test('it renders a IndexPrivilegeForm for each privilege on the role', async () => {
+ const license = licenseMock.create();
+ license.getFeatures.mockReturnValue({
+ allowRoleFieldLevelSecurity: true,
+ allowRoleDocumentLevelSecurity: true,
+ } as any);
+
const props = {
role: {
name: '',
@@ -59,14 +73,13 @@ test('it renders a IndexPrivilegeForm for each privilege on the role', async ()
run_as: [],
},
},
- httpClient: jest.fn(),
onChange: jest.fn(),
indexPatterns: [],
editable: true,
- allowDocumentLevelSecurity: true,
- allowFieldLevelSecurity: true,
validator: new RoleValidator(),
availableIndexPrivileges: ['all', 'read', 'write', 'index'],
+ indicesAPIClient: indicesAPIClientMock.create(),
+ license,
};
const wrapper = mountWithIntl();
await flushPromises();
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privileges.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.tsx
similarity index 84%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privileges.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.tsx
index f09084ad2bb382..2c745067fede2d 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privileges.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/es/index_privileges.tsx
@@ -5,19 +5,23 @@
*/
import _ from 'lodash';
import React, { Component, Fragment } from 'react';
-import { Role, RoleIndexPrivilege } from '../../../../../../../common/model';
-import { isReadOnlyRole, isRoleEnabled } from '../../../../../../lib/role_utils';
-import { getFields } from '../../../../../../objects';
-import { RoleValidator } from '../../../lib/validate_role';
+import {
+ Role,
+ RoleIndexPrivilege,
+ isReadOnlyRole,
+ isRoleEnabled,
+} from '../../../../../../common/model';
+import { SecurityLicense } from '../../../../../../common/licensing';
+import { IndicesAPIClient } from '../../../indices_api_client';
+import { RoleValidator } from '../../validate_role';
import { IndexPrivilegeForm } from './index_privilege_form';
interface Props {
role: Role;
indexPatterns: string[];
availableIndexPrivileges: string[];
- allowDocumentLevelSecurity: boolean;
- allowFieldLevelSecurity: boolean;
- httpClient: any;
+ indicesAPIClient: PublicMethodsOf;
+ license: SecurityLicense;
onChange: (role: Role) => void;
validator: RoleValidator;
}
@@ -43,20 +47,16 @@ export class IndexPrivileges extends Component {
public render() {
const { indices = [] } = this.props.role.elasticsearch;
- const {
- indexPatterns,
- allowDocumentLevelSecurity,
- allowFieldLevelSecurity,
- availableIndexPrivileges,
- } = this.props;
+ const { indexPatterns, license, availableIndexPrivileges } = this.props;
+ const { allowRoleDocumentLevelSecurity, allowRoleFieldLevelSecurity } = license.getFeatures();
const props = {
indexPatterns,
// If editing an existing role while that has been disabled, always show the FLS/DLS fields because currently
// a role is only marked as disabled if it has FLS/DLS setup (usually before the user changed to a license that
// doesn't permit FLS/DLS).
- allowDocumentLevelSecurity: allowDocumentLevelSecurity || !isRoleEnabled(this.props.role),
- allowFieldLevelSecurity: allowFieldLevelSecurity || !isRoleEnabled(this.props.role),
+ allowDocumentLevelSecurity: allowRoleDocumentLevelSecurity || !isRoleEnabled(this.props.role),
+ allowFieldLevelSecurity: allowRoleFieldLevelSecurity || !isRoleEnabled(this.props.role),
isReadOnlyRole: isReadOnlyRole(this.props.role),
};
@@ -171,7 +171,7 @@ export class IndexPrivileges extends Component {
try {
return {
- [pattern]: await getFields(this.props.httpClient, pattern),
+ [pattern]: await this.props.indicesAPIClient.getFields(pattern),
};
} catch (e) {
return {
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/index.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/index.ts
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/index.ts
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/index.ts
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/kibana_privileges_region.test.tsx.snap b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/__snapshots__/kibana_privileges_region.test.tsx.snap
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/__snapshots__/kibana_privileges_region.test.tsx.snap
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/__snapshots__/kibana_privileges_region.test.tsx.snap
diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/_index.scss b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/_index.scss
new file mode 100644
index 00000000000000..19547c0e1953e0
--- /dev/null
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/_index.scss
@@ -0,0 +1,2 @@
+@import './feature_table/index';
+@import './space_aware_privilege_section/index';
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/lib/constants.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/constants.ts
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/lib/constants.ts
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/constants.ts
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/feature_table/__snapshots__/feature_table.test.tsx.snap b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/__snapshots__/feature_table.test.tsx.snap
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/feature_table/__snapshots__/feature_table.test.tsx.snap
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/__snapshots__/feature_table.test.tsx.snap
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/feature_table/_index.scss b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/_change_all_privileges.scss
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/feature_table/_index.scss
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/_change_all_privileges.scss
diff --git a/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/_index.scss b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/_index.scss
new file mode 100644
index 00000000000000..6a96553742819f
--- /dev/null
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/_index.scss
@@ -0,0 +1 @@
+@import './change_all_privileges';
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/feature_table/change_all_privileges.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.tsx
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/feature_table/change_all_privileges.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/change_all_privileges.tsx
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/feature_table/feature_table.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx
similarity index 94%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/feature_table/feature_table.test.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx
index 9648bf1d111bf4..dea42e16f99d42 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/feature_table/feature_table.test.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.test.tsx
@@ -3,12 +3,11 @@
* 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 { EuiInMemoryTable } from '@elastic/eui';
import React from 'react';
import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
-import { FeaturesPrivileges, KibanaPrivileges, Role } from '../../../../../../../../common/model';
-import { KibanaPrivilegeCalculatorFactory } from '../../../../../../../lib/kibana_privilege_calculator';
+import { FeaturesPrivileges, KibanaPrivileges, Role } from '../../../../../../../common/model';
+import { KibanaPrivilegeCalculatorFactory } from '../kibana_privilege_calculator';
import { FeatureTable } from './feature_table';
const defaultPrivilegeDefinition = new KibanaPrivileges({
@@ -113,7 +112,6 @@ describe('FeatureTable', () => {
onChange={jest.fn()}
onChangeAll={jest.fn()}
spacesIndex={0}
- intl={null as any}
/>
);
@@ -141,7 +139,6 @@ describe('FeatureTable', () => {
onChange={jest.fn()}
onChangeAll={jest.fn()}
spacesIndex={-1}
- intl={null as any}
/>
);
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/feature_table/feature_table.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx
similarity index 91%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/feature_table/feature_table.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx
index a05dc687fce4ac..8283efe23260af 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/feature_table/feature_table.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/feature_table/feature_table.tsx
@@ -4,28 +4,27 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import _ from 'lodash';
+import React, { Component } from 'react';
import {
- // @ts-ignore
EuiButtonGroup,
EuiIcon,
EuiIconTip,
- // @ts-ignore
EuiInMemoryTable,
EuiText,
IconType,
} from '@elastic/eui';
-import { FormattedMessage, InjectedIntl } from '@kbn/i18n/react';
-import _ from 'lodash';
-import React, { Component } from 'react';
-import { Feature } from '../../../../../../../../../../../plugins/features/public';
-import { FeaturesPrivileges, KibanaPrivileges, Role } from '../../../../../../../../common/model';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { Feature } from '../../../../../../../../features/public';
+import { FeaturesPrivileges, KibanaPrivileges, Role } from '../../../../../../../common/model';
import {
AllowedPrivilege,
CalculatedPrivilege,
PrivilegeExplanation,
-} from '../../../../../../../lib/kibana_privilege_calculator';
-import { isGlobalPrivilegeDefinition } from '../../../../../../../lib/privilege_utils';
-import { NO_PRIVILEGE_VALUE } from '../../../../lib/constants';
+} from '../kibana_privilege_calculator';
+import { isGlobalPrivilegeDefinition } from '../../../privilege_utils';
+import { NO_PRIVILEGE_VALUE } from '../constants';
import { PrivilegeDisplay } from '../space_aware_privilege_section/privilege_display';
import { ChangeAllPrivilegesControl } from './change_all_privileges';
@@ -36,7 +35,6 @@ interface Props {
allowedPrivileges: AllowedPrivilege;
rankedFeaturePrivileges: FeaturesPrivileges;
kibanaPrivileges: KibanaPrivileges;
- intl: InjectedIntl;
spacesIndex: number;
onChange: (featureId: string, privileges: string[]) => void;
onChangeAll: (privileges: string[]) => void;
@@ -100,9 +98,7 @@ export class FeatureTable extends Component {
const availablePrivileges = Object.values(rankedFeaturePrivileges)[0];
return (
- // @ts-ignore missing responsive from typedef
{
private getColumns = (availablePrivileges: string[]) => [
{
field: 'feature',
- name: this.props.intl.formatMessage({
- id: 'xpack.security.management.editRole.featureTable.enabledRoleFeaturesFeatureColumnTitle',
- defaultMessage: 'Feature',
- }),
+ name: i18n.translate(
+ 'xpack.security.management.editRole.featureTable.enabledRoleFeaturesFeatureColumnTitle',
+ { defaultMessage: 'Feature' }
+ ),
render: (feature: TableFeature) => {
let tooltipElement = null;
if (feature.privilegesTooltip) {
@@ -239,9 +235,7 @@ export class FeatureTable extends Component {
});
return (
- // @ts-ignore missing name from typedef
void;
validator: RoleValidator;
- intl: InjectedIntl;
}
export class KibanaPrivilegesRegion extends Component {
@@ -81,7 +79,6 @@ export class KibanaPrivilegesRegion extends Component {
privilegeCalculatorFactory={privilegeCalculatorFactory}
onChange={onChange}
editable={editable}
- intl={this.props.intl}
/>
);
}
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/__snapshots__/simple_privilege_section.test.tsx.snap b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/__snapshots__/simple_privilege_section.test.tsx.snap
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/__snapshots__/simple_privilege_section.test.tsx.snap
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/__snapshots__/simple_privilege_section.test.tsx.snap
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/index.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/index.ts
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/index.ts
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/index.ts
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/privilege_selector.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/privilege_selector.tsx
similarity index 95%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/privilege_selector.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/privilege_selector.tsx
index 135419cc9a10d2..bda0227372c094 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/privilege_selector.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/privilege_selector.tsx
@@ -6,7 +6,7 @@
import { EuiSelect } from '@elastic/eui';
import React, { ChangeEvent, Component } from 'react';
-import { NO_PRIVILEGE_VALUE } from '../../../../lib/constants';
+import { NO_PRIVILEGE_VALUE } from '../constants';
interface Props {
['data-test-subj']: string;
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx
similarity index 95%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx
index f97fa93294ff5b..db1e3cfd616212 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.test.tsx
@@ -3,13 +3,13 @@
* 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 { EuiButtonGroup, EuiButtonGroupProps, EuiComboBox, EuiSuperSelect } from '@elastic/eui';
import React from 'react';
import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
-import { Feature } from '../../../../../../../../../../../plugins/features/public';
-import { KibanaPrivileges, Role } from '../../../../../../../../common/model';
-import { KibanaPrivilegeCalculatorFactory } from '../../../../../../../lib/kibana_privilege_calculator';
+import { Feature } from '../../../../../../../../features/public';
+import { KibanaPrivileges, Role } from '../../../../../../../common/model';
+import { KibanaPrivilegeCalculatorFactory } from '../kibana_privilege_calculator';
import { SimplePrivilegeSection } from './simple_privilege_section';
import { UnsupportedSpacePrivilegesWarning } from './unsupported_space_privileges_warning';
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/simple_privilege_section.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.tsx
similarity index 94%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/simple_privilege_section.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.tsx
index 7768dc769a32f7..2221fc6bab2797 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/simple_privilege_section.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/simple_privilege_section.tsx
@@ -6,21 +6,24 @@
import {
EuiComboBox,
- // @ts-ignore
EuiDescribedFormGroup,
EuiFormRow,
EuiSuperSelect,
EuiText,
} from '@elastic/eui';
-import { FormattedMessage, InjectedIntl } from '@kbn/i18n/react';
+import { FormattedMessage } from '@kbn/i18n/react';
import React, { Component, Fragment } from 'react';
-import { Feature } from '../../../../../../../../../../../plugins/features/public';
-import { KibanaPrivileges, Role, RoleKibanaPrivilege } from '../../../../../../../../common/model';
-import { KibanaPrivilegeCalculatorFactory } from '../../../../../../../lib/kibana_privilege_calculator';
-import { isGlobalPrivilegeDefinition } from '../../../../../../../lib/privilege_utils';
-import { copyRole } from '../../../../../../../lib/role_utils';
-import { CUSTOM_PRIVILEGE_VALUE, NO_PRIVILEGE_VALUE } from '../../../../lib/constants';
+import { Feature } from '../../../../../../../../features/public';
+import {
+ KibanaPrivileges,
+ Role,
+ RoleKibanaPrivilege,
+ copyRole,
+} from '../../../../../../../common/model';
+import { KibanaPrivilegeCalculatorFactory } from '../kibana_privilege_calculator';
+import { isGlobalPrivilegeDefinition } from '../../../privilege_utils';
+import { CUSTOM_PRIVILEGE_VALUE, NO_PRIVILEGE_VALUE } from '../constants';
import { FeatureTable } from '../feature_table';
import { UnsupportedSpacePrivilegesWarning } from './unsupported_space_privileges_warning';
@@ -31,7 +34,6 @@ interface Props {
features: Feature[];
onChange: (role: Role) => void;
editable: boolean;
- intl: InjectedIntl;
}
interface State {
@@ -230,7 +232,6 @@ export class SimplePrivilegeSection extends Component {
allowedPrivileges={allowedPrivileges}
rankedFeaturePrivileges={privilegeCalculator.rankedFeaturePrivileges}
features={this.props.features}
- intl={this.props.intl}
onChange={this.onFeaturePrivilegeChange}
onChangeAll={this.onChangeAllFeaturePrivileges}
spacesIndex={this.props.role.kibana.findIndex(k => isGlobalPrivilegeDefinition(k))}
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/unsupported_space_privileges_warning.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/unsupported_space_privileges_warning.tsx
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/simple_privilege_section/unsupported_space_privileges_warning.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/simple_privilege_section/unsupported_space_privileges_warning.tsx
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__fixtures__/index.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/__fixtures__/index.ts
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__fixtures__/index.ts
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/__fixtures__/index.ts
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__fixtures__/raw_kibana_privileges.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/__fixtures__/raw_kibana_privileges.ts
similarity index 94%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__fixtures__/raw_kibana_privileges.ts
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/__fixtures__/raw_kibana_privileges.ts
index d412ba63403e19..428836c9f181b9 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__fixtures__/raw_kibana_privileges.ts
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/__fixtures__/raw_kibana_privileges.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { RawKibanaPrivileges } from '../../../../../../../../../common/model';
+import { RawKibanaPrivileges } from '../../../../../../../../common/model';
export const rawKibanaPrivileges: RawKibanaPrivileges = {
global: {
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__snapshots__/privilege_display.test.tsx.snap b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/__snapshots__/privilege_display.test.tsx.snap
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__snapshots__/privilege_display.test.tsx.snap
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/__snapshots__/privilege_display.test.tsx.snap
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__snapshots__/privilege_space_form.test.tsx.snap b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/__snapshots__/privilege_space_form.test.tsx.snap
similarity index 82%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__snapshots__/privilege_space_form.test.tsx.snap
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/__snapshots__/privilege_space_form.test.tsx.snap
index c20a391cdb20c5..e9f2f946e98859 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__snapshots__/privilege_space_form.test.tsx.snap
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/__snapshots__/privilege_space_form.test.tsx.snap
@@ -351,108 +351,6 @@ exports[` renders without crashing 1`] = `
}
disabled={true}
features={Array []}
- 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,
- }
- }
kibanaPrivileges={
KibanaPrivileges {
"rawKibanaPrivileges": Object {
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__snapshots__/space_aware_privilege_section.test.tsx.snap b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/__snapshots__/space_aware_privilege_section.test.tsx.snap
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/__snapshots__/space_aware_privilege_section.test.tsx.snap
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/__snapshots__/space_aware_privilege_section.test.tsx.snap
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/_index.scss b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/_index.scss
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/_index.scss
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/_index.scss
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/_privilege_matrix.scss b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/_privilege_matrix.scss
similarity index 87%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/_privilege_matrix.scss
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/_privilege_matrix.scss
index 5f9fbced5ee6ac..8f47727fdf8d62 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/_privilege_matrix.scss
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/_privilege_matrix.scss
@@ -9,6 +9,6 @@
.secPrivilegeMatrix__row--isBasePrivilege,
.secPrivilegeMatrix__cell--isGlobalPrivilege,
-.secPrivilegeTable__row--isGlobalSpace, {
+.secPrivilegeTable__row--isGlobalSpace {
background-color: $euiColorLightestShade;
}
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/index.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/index.ts
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/index.ts
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/index.ts
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_display.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_display.test.tsx
similarity index 96%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_display.test.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_display.test.tsx
index 62e22050132fd7..c6268e19abfd1f 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_display.test.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_display.test.tsx
@@ -7,7 +7,7 @@
import { EuiIconTip, EuiText, EuiToolTip } from '@elastic/eui';
import React from 'react';
import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
-import { PRIVILEGE_SOURCE } from '../../../../../../../lib/kibana_privilege_calculator';
+import { PRIVILEGE_SOURCE } from '../kibana_privilege_calculator';
import { PrivilegeDisplay } from './privilege_display';
describe('PrivilegeDisplay', () => {
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_display.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_display.tsx
similarity index 96%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_display.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_display.tsx
index 6af7672f6fef86..55ac99da4c8c16 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_display.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_display.tsx
@@ -7,11 +7,8 @@ import { EuiIcon, EuiIconTip, EuiText, IconType, PropsOf, EuiToolTip } from '@el
import { FormattedMessage } from '@kbn/i18n/react';
import _ from 'lodash';
import React, { ReactNode, FC } from 'react';
-import {
- PRIVILEGE_SOURCE,
- PrivilegeExplanation,
-} from '../../../../../../../lib/kibana_privilege_calculator';
-import { NO_PRIVILEGE_VALUE } from '../../../../lib/constants';
+import { PRIVILEGE_SOURCE, PrivilegeExplanation } from '../kibana_privilege_calculator';
+import { NO_PRIVILEGE_VALUE } from '../constants';
interface Props extends PropsOf {
privilege: string | string[] | undefined;
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_matrix.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_matrix.test.tsx
similarity index 89%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_matrix.test.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_matrix.test.tsx
index ee121caa13a2af..16aad4826ae44c 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_matrix.test.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_matrix.test.tsx
@@ -3,14 +3,14 @@
* 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 { EuiButtonEmpty, EuiInMemoryTable } from '@elastic/eui';
import React from 'react';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
-import { Space } from '../../../../../../../../../spaces/common/model/space';
-import { Feature } from '../../../../../../../../../../../plugins/features/public';
-import { KibanaPrivileges, Role } from '../../../../../../../../common/model';
-import { KibanaPrivilegeCalculatorFactory } from '../../../../../../..//lib/kibana_privilege_calculator';
+import { Space } from '../../../../../../../../spaces/common/model/space';
+import { Feature } from '../../../../../../../../features/public';
+import { KibanaPrivileges, Role } from '../../../../../../../common/model';
+import { KibanaPrivilegeCalculatorFactory } from '../kibana_privilege_calculator';
import { PrivilegeMatrix } from './privilege_matrix';
describe('PrivilegeMatrix', () => {
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_matrix.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_matrix.tsx
similarity index 93%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_matrix.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_matrix.tsx
index 962487312c83df..b3449e32c6c917 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_matrix.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_matrix.tsx
@@ -8,7 +8,6 @@ import {
EuiButtonEmpty,
EuiIcon,
EuiIconTip,
- // @ts-ignore
EuiInMemoryTable,
EuiModal,
EuiModalBody,
@@ -16,18 +15,16 @@ import {
EuiModalHeader,
EuiModalHeaderTitle,
EuiOverlayMask,
- // @ts-ignore
- EuiToolTip,
IconType,
} from '@elastic/eui';
import { FormattedMessage, InjectedIntl } from '@kbn/i18n/react';
import React, { Component, Fragment } from 'react';
-import { Space } from '../../../../../../../../../spaces/common/model/space';
-import { SpaceAvatar } from '../../../../../../../../../spaces/public/space_avatar';
-import { Feature } from '../../../../../../../../../../../plugins/features/public';
-import { FeaturesPrivileges, Role } from '../../../../../../../../common/model';
-import { CalculatedPrivilege } from '../../../../../../../lib/kibana_privilege_calculator';
-import { isGlobalPrivilegeDefinition } from '../../../../../../../lib/privilege_utils';
+import { SpaceAvatar } from '../../../../../../../../../legacy/plugins/spaces/public/space_avatar';
+import { Space } from '../../../../../../../../spaces/common/model/space';
+import { Feature } from '../../../../../../../../features/public';
+import { FeaturesPrivileges, Role } from '../../../../../../../common/model';
+import { CalculatedPrivilege } from '../kibana_privilege_calculator';
+import { isGlobalPrivilegeDefinition } from '../../../privilege_utils';
import { SpacesPopoverList } from '../../../spaces_popover_list';
import { PrivilegeDisplay } from './privilege_display';
@@ -258,11 +255,9 @@ export class PrivilegeMatrix extends Component {
];
return (
- // @ts-ignore missing rowProps from typedef
{
return {
className: item.feature.isBase ? 'secPrivilegeMatrix__row--isBasePrivilege' : '',
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx
similarity index 95%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx
index 2b7d87f663d729..675f02a81f9e1d 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.test.tsx
@@ -9,8 +9,8 @@ import { merge } from 'lodash';
// @ts-ignore
import { findTestSubject } from '@elastic/eui/lib/test';
import { shallowWithIntl, mountWithIntl } from 'test_utils/enzyme_helpers';
-import { KibanaPrivileges } from '../../../../../../../../common/model';
-import { KibanaPrivilegeCalculatorFactory } from '../../../../../../../lib/kibana_privilege_calculator';
+import { KibanaPrivileges } from '../../../../../../../common/model';
+import { KibanaPrivilegeCalculatorFactory } from '../kibana_privilege_calculator';
import { PrivilegeSpaceForm } from './privilege_space_form';
import { rawKibanaPrivileges } from './__fixtures__';
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx
similarity index 96%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx
index 5abb87d23bb6e6..6d1f5117c52e98 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_form.tsx
@@ -24,17 +24,16 @@ 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 { Feature } from '../../../../../../../../../../../plugins/features/public';
-import { KibanaPrivileges, Role } from '../../../../../../../../common/model';
+import { Space } from '../../../../../../../../spaces/common/model/space';
+import { Feature } from '../../../../../../../../features/public';
+import { KibanaPrivileges, Role, copyRole } from '../../../../../../../common/model';
import {
AllowedPrivilege,
KibanaPrivilegeCalculatorFactory,
PrivilegeExplanation,
-} from '../../../../../../../lib/kibana_privilege_calculator';
-import { hasAssignedFeaturePrivileges } from '../../../../../../../lib/privilege_utils';
-import { copyRole } from '../../../../../../../lib/role_utils';
-import { CUSTOM_PRIVILEGE_VALUE } from '../../../../lib/constants';
+} from '../kibana_privilege_calculator';
+import { hasAssignedFeaturePrivileges } from '../../../privilege_utils';
+import { CUSTOM_PRIVILEGE_VALUE } from '../constants';
import { FeatureTable } from '../feature_table';
import { SpaceSelector } from './space_selector';
@@ -285,7 +284,6 @@ export class PrivilegeSpaceForm extends Component {
calculatedPrivileges={calculatedPrivileges}
allowedPrivileges={allowedPrivileges}
rankedFeaturePrivileges={privilegeCalculator.rankedFeaturePrivileges}
- intl={this.props.intl}
onChange={this.onFeaturePrivilegesChange}
onChangeAll={this.onChangeAllFeaturePrivileges}
kibanaPrivileges={this.props.kibanaPrivileges}
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx
similarity index 99%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx
index 37ee43c5473b0d..f0a391c98c9100 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.test.tsx
@@ -10,8 +10,8 @@ import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { ReactWrapper } from 'enzyme';
import { PrivilegeSpaceTable } from './privilege_space_table';
import { PrivilegeDisplay } from './privilege_display';
-import { KibanaPrivileges, Role, RoleKibanaPrivilege } from '../../../../../../../../common/model';
-import { KibanaPrivilegeCalculatorFactory } from '../../../../../../../lib/kibana_privilege_calculator';
+import { KibanaPrivileges, Role, RoleKibanaPrivilege } from '../../../../../../../common/model';
+import { KibanaPrivilegeCalculatorFactory } from '../kibana_privilege_calculator';
import { rawKibanaPrivileges } from './__fixtures__';
interface TableRow {
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx
similarity index 94%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx
index 65a3df9fb47a1a..1c27ec84f50dcd 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/privilege_space_table.tsx
@@ -12,22 +12,21 @@ import {
EuiBasicTableColumn,
} from '@elastic/eui';
import { FormattedMessage, InjectedIntl } from '@kbn/i18n/react';
-import _ from 'lodash';
import React, { Component } from 'react';
-import { getSpaceColor } from '../../../../../../../../../spaces/public/space_avatar';
-import { Space } from '../../../../../../../../../spaces/common/model/space';
+import { getSpaceColor } from '../../../../../../../../../legacy/plugins/spaces/public/space_avatar';
+import { Space } from '../../../../../../../../spaces/common/model/space';
import {
FeaturesPrivileges,
Role,
RoleKibanaPrivilege,
-} from '../../../../../../../../common/model';
-import { KibanaPrivilegeCalculatorFactory } from '../../../../../../../lib/kibana_privilege_calculator';
+ copyRole,
+} from '../../../../../../../common/model';
+import { KibanaPrivilegeCalculatorFactory } from '../kibana_privilege_calculator';
import {
isGlobalPrivilegeDefinition,
hasAssignedFeaturePrivileges,
-} from '../../../../../../../lib/privilege_utils';
-import { copyRole } from '../../../../../../../lib/role_utils';
-import { CUSTOM_PRIVILEGE_VALUE, NO_PRIVILEGE_VALUE } from '../../../../lib/constants';
+} from '../../../privilege_utils';
+import { CUSTOM_PRIVILEGE_VALUE, NO_PRIVILEGE_VALUE } from '../constants';
import { SpacesPopoverList } from '../../../spaces_popover_list';
import { PrivilegeDisplay } from './privilege_display';
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.test.tsx
similarity index 95%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.test.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.test.tsx
index 2756b1c4472744..e06d2a4f7dc337 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.test.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.test.tsx
@@ -6,9 +6,9 @@
import React from 'react';
import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
-import { KibanaPrivileges } from '../../../../../../../../common/model';
-import { KibanaPrivilegeCalculatorFactory } from '../../../../../../../lib/kibana_privilege_calculator';
-import { RoleValidator } from '../../../../lib/validate_role';
+import { KibanaPrivileges } from '../../../../../../../common/model';
+import { KibanaPrivilegeCalculatorFactory } from '../kibana_privilege_calculator';
+import { RoleValidator } from '../../../validate_role';
import { PrivilegeMatrix } from './privilege_matrix';
import { PrivilegeSpaceForm } from './privilege_space_form';
import { PrivilegeSpaceTable } from './privilege_space_table';
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.tsx
similarity index 93%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.tsx
index d324cf99c8418a..21cadfafe1790b 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_aware_privilege_section.tsx
@@ -14,13 +14,12 @@ import {
import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
import _ from 'lodash';
import React, { Component, Fragment } from 'react';
-import { UICapabilities } from 'ui/capabilities';
-import { Space } from '../../../../../../../../../spaces/common/model/space';
-import { Feature } from '../../../../../../../../../../../plugins/features/public';
-import { KibanaPrivileges, Role } from '../../../../../../../../common/model';
-import { KibanaPrivilegeCalculatorFactory } from '../../../../../../../lib/kibana_privilege_calculator';
-import { isReservedRole } from '../../../../../../../lib/role_utils';
-import { RoleValidator } from '../../../../lib/validate_role';
+import { Capabilities } from 'src/core/public';
+import { Space } from '../../../../../../../../spaces/common/model/space';
+import { Feature } from '../../../../../../../../features/public';
+import { KibanaPrivileges, Role, isReservedRole } from '../../../../../../../common/model';
+import { KibanaPrivilegeCalculatorFactory } from '../kibana_privilege_calculator';
+import { RoleValidator } from '../../../validate_role';
import { PrivilegeMatrix } from './privilege_matrix';
import { PrivilegeSpaceForm } from './privilege_space_form';
import { PrivilegeSpaceTable } from './privilege_space_table';
@@ -34,7 +33,7 @@ interface Props {
editable: boolean;
validator: RoleValidator;
intl: InjectedIntl;
- uiCapabilities: UICapabilities;
+ uiCapabilities: Capabilities;
features: Feature[];
}
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/space_selector.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_selector.tsx
similarity index 93%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/space_selector.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_selector.tsx
index 0eb9cf0b0ee9d7..cfeb5b9f37d8ce 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/space_aware_privilege_section/space_selector.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/space_aware_privilege_section/space_selector.tsx
@@ -7,8 +7,8 @@
import { EuiComboBox, EuiComboBoxOptionProps, EuiHealth, EuiHighlight } from '@elastic/eui';
import { InjectedIntl } from '@kbn/i18n/react';
import React, { Component } from 'react';
-import { Space } from '../../../../../../../../../spaces/common/model/space';
-import { getSpaceColor } from '../../../../../../../../../spaces/public/space_avatar';
+import { getSpaceColor } from '../../../../../../../../../legacy/plugins/spaces/public/space_avatar';
+import { Space } from '../../../../../../../../spaces/common/model/space';
const spaceToOption = (space?: Space, currentSelection?: 'global' | 'spaces') => {
if (!space) {
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/transform_error_section/index.ts b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/transform_error_section/index.ts
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/transform_error_section/index.ts
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/transform_error_section/index.ts
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/transform_error_section/transform_error_section.tsx b/x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/transform_error_section/transform_error_section.tsx
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/kibana/transform_error_section/transform_error_section.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/privileges/kibana/transform_error_section/transform_error_section.tsx
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/reserved_role_badge.test.tsx b/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.test.tsx
similarity index 96%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/reserved_role_badge.test.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.test.tsx
index 9b483d92cde41b..d29b442420a90c 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/reserved_role_badge.test.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.test.tsx
@@ -7,7 +7,7 @@
import { EuiIcon } from '@elastic/eui';
import { shallow } from 'enzyme';
import React from 'react';
-import { Role } from '../../../../../common/model';
+import { Role } from '../../../../common/model';
import { ReservedRoleBadge } from './reserved_role_badge';
const reservedRole: Role = {
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/reserved_role_badge.tsx b/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.tsx
similarity index 89%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/reserved_role_badge.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.tsx
index 3d817d1e07d212..501ca7589dafde 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/reserved_role_badge.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/reserved_role_badge.tsx
@@ -8,8 +8,7 @@ import React from 'react';
import { EuiIcon, EuiToolTip } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
-import { Role } from '../../../../../common/model';
-import { isReservedRole } from '../../../../lib/role_utils';
+import { Role, isReservedRole } from '../../../../common/model';
interface Props {
role: Role;
diff --git a/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/_index.scss b/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/_index.scss
new file mode 100644
index 00000000000000..b40a32cb8df96b
--- /dev/null
+++ b/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/_index.scss
@@ -0,0 +1 @@
+@import './spaces_popover_list';
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/spaces_popover_list/_spaces_popover_list.scss b/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/_spaces_popover_list.scss
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/spaces_popover_list/_spaces_popover_list.scss
rename to x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/_spaces_popover_list.scss
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/spaces_popover_list/index.ts b/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/index.ts
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/spaces_popover_list/index.ts
rename to x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/index.ts
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/spaces_popover_list/spaces_popover_list.tsx b/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.tsx
similarity index 95%
rename from x-pack/legacy/plugins/security/public/views/management/edit_role/components/spaces_popover_list/spaces_popover_list.tsx
rename to x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.tsx
index a99e389044eaad..bb7a6db97f7c88 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/spaces_popover_list/spaces_popover_list.tsx
+++ b/x-pack/plugins/security/public/management/roles/edit_role/spaces_popover_list/spaces_popover_list.tsx
@@ -14,9 +14,9 @@ import {
} from '@elastic/eui';
import { FormattedMessage, InjectedIntl } from '@kbn/i18n/react';
import React, { Component } from 'react';
-import { SpaceAvatar } from '../../../../../../../spaces/public/space_avatar';
-import { SPACE_SEARCH_COUNT_THRESHOLD } from '../../../../../../../../../plugins/spaces/common/constants';
-import { Space } from '../../../../../../../../../plugins/spaces/common/model/space';
+import { SpaceAvatar } from '../../../../../../../legacy/plugins/spaces/public/space_avatar';
+import { SPACE_SEARCH_COUNT_THRESHOLD } from '../../../../../../spaces/common';
+import { Space } from '../../../../../../spaces/common/model/space';
interface Props {
spaces: Space[];
@@ -146,7 +146,6 @@ export class SpacesPopoverList extends Component {
return (
{
- // @ts-ignore onSearch isn't defined on the type
({
+ getFields: jest.fn(),
+ }),
+};
diff --git a/x-pack/plugins/security/public/management/roles/indices_api_client.ts b/x-pack/plugins/security/public/management/roles/indices_api_client.ts
new file mode 100644
index 00000000000000..65d9a40a776eb0
--- /dev/null
+++ b/x-pack/plugins/security/public/management/roles/indices_api_client.ts
@@ -0,0 +1,18 @@
+/*
+ * 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 { HttpStart } from 'src/core/public';
+
+export class IndicesAPIClient {
+ constructor(private readonly http: HttpStart) {}
+
+ async getFields(query: string) {
+ return (
+ (await this.http.get(`/internal/security/fields/${encodeURIComponent(query)}`)) ||
+ []
+ );
+ }
+}
diff --git a/x-pack/plugins/security/public/management/roles/privileges_api_client.mock.ts b/x-pack/plugins/security/public/management/roles/privileges_api_client.mock.ts
new file mode 100644
index 00000000000000..2564914a1d3d83
--- /dev/null
+++ b/x-pack/plugins/security/public/management/roles/privileges_api_client.mock.ts
@@ -0,0 +1,12 @@
+/*
+ * 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 privilegesAPIClientMock = {
+ create: () => ({
+ getAll: jest.fn(),
+ getBuiltIn: jest.fn(),
+ }),
+};
diff --git a/x-pack/plugins/security/public/management/roles/privileges_api_client.ts b/x-pack/plugins/security/public/management/roles/privileges_api_client.ts
new file mode 100644
index 00000000000000..45bd2fd8fb3a6a
--- /dev/null
+++ b/x-pack/plugins/security/public/management/roles/privileges_api_client.ts
@@ -0,0 +1,22 @@
+/*
+ * 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 { HttpStart } from 'src/core/public';
+import { BuiltinESPrivileges, RawKibanaPrivileges } from '../../../common/model';
+
+export class PrivilegesAPIClient {
+ constructor(private readonly http: HttpStart) {}
+
+ async getAll({ includeActions }: { includeActions: boolean }) {
+ return await this.http.get('/api/security/privileges', {
+ query: { includeActions },
+ });
+ }
+
+ async getBuiltIn() {
+ return await this.http.get('/internal/security/esPrivileges/builtin');
+ }
+}
diff --git a/x-pack/plugins/security/public/management/roles/roles_api_client.mock.ts b/x-pack/plugins/security/public/management/roles/roles_api_client.mock.ts
new file mode 100644
index 00000000000000..c4d3724c0ecb5f
--- /dev/null
+++ b/x-pack/plugins/security/public/management/roles/roles_api_client.mock.ts
@@ -0,0 +1,14 @@
+/*
+ * 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 rolesAPIClientMock = {
+ create: () => ({
+ getRoles: jest.fn(),
+ getRole: jest.fn(),
+ deleteRole: jest.fn(),
+ saveRole: jest.fn(),
+ }),
+};
diff --git a/x-pack/legacy/plugins/security/public/lib/transform_role_for_save.test.ts b/x-pack/plugins/security/public/management/roles/roles_api_client.test.ts
similarity index 82%
rename from x-pack/legacy/plugins/security/public/lib/transform_role_for_save.test.ts
rename to x-pack/plugins/security/public/management/roles/roles_api_client.test.ts
index 1ea19f2637305e..75611613684051 100644
--- a/x-pack/legacy/plugins/security/public/lib/transform_role_for_save.test.ts
+++ b/x-pack/plugins/security/public/management/roles/roles_api_client.test.ts
@@ -4,12 +4,23 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { Role } from '../../common/model';
-import { transformRoleForSave } from './transform_role_for_save';
+import { Role } from '../../../common/model';
+import { RolesAPIClient } from './roles_api_client';
+import { httpServiceMock } from '../../../../../../src/core/public/mocks';
+
+describe('RolesAPIClient', () => {
+ async function saveRole(role: Role, spacesEnabled: boolean) {
+ const httpMock = httpServiceMock.createStartContract();
+ const rolesAPIClient = new RolesAPIClient(httpMock);
+
+ await rolesAPIClient.saveRole({ role, spacesEnabled });
+ expect(httpMock.put).toHaveBeenCalledTimes(1);
+
+ return JSON.parse(httpMock.put.mock.calls[0][1]?.body as any);
+ }
-describe('transformRoleForSave', () => {
describe('spaces disabled', () => {
- it('removes placeholder index privileges', () => {
+ it('removes placeholder index privileges', async () => {
const role: Role = {
name: 'my role',
elasticsearch: {
@@ -20,7 +31,7 @@ describe('transformRoleForSave', () => {
kibana: [],
};
- const result = transformRoleForSave(role, false);
+ const result = await saveRole(role, false);
expect(result).toEqual({
elasticsearch: {
@@ -32,7 +43,7 @@ describe('transformRoleForSave', () => {
});
});
- it('removes placeholder query entries', () => {
+ it('removes placeholder query entries', async () => {
const role: Role = {
name: 'my role',
elasticsearch: {
@@ -43,7 +54,7 @@ describe('transformRoleForSave', () => {
kibana: [],
};
- const result = transformRoleForSave(role, false);
+ const result = await saveRole(role, false);
expect(result).toEqual({
elasticsearch: {
@@ -55,7 +66,7 @@ describe('transformRoleForSave', () => {
});
});
- it('removes transient fields not required for save', () => {
+ it('removes transient fields not required for save', async () => {
const role: Role = {
name: 'my role',
transient_metadata: {
@@ -74,7 +85,7 @@ describe('transformRoleForSave', () => {
kibana: [],
};
- const result = transformRoleForSave(role, false);
+ const result = await saveRole(role, false);
expect(result).toEqual({
metadata: {
@@ -89,7 +100,7 @@ describe('transformRoleForSave', () => {
});
});
- it('does not remove actual query entries', () => {
+ it('does not remove actual query entries', async () => {
const role: Role = {
name: 'my role',
elasticsearch: {
@@ -100,7 +111,7 @@ describe('transformRoleForSave', () => {
kibana: [],
};
- const result = transformRoleForSave(role, false);
+ const result = await saveRole(role, false);
expect(result).toEqual({
elasticsearch: {
@@ -112,7 +123,7 @@ describe('transformRoleForSave', () => {
});
});
- it('should remove feature privileges if a corresponding base privilege is defined', () => {
+ it('should remove feature privileges if a corresponding base privilege is defined', async () => {
const role: Role = {
name: 'my role',
elasticsearch: {
@@ -132,7 +143,7 @@ describe('transformRoleForSave', () => {
],
};
- const result = transformRoleForSave(role, false);
+ const result = await saveRole(role, false);
expect(result).toEqual({
elasticsearch: {
@@ -150,7 +161,7 @@ describe('transformRoleForSave', () => {
});
});
- it('should not remove feature privileges if a corresponding base privilege is not defined', () => {
+ it('should not remove feature privileges if a corresponding base privilege is not defined', async () => {
const role: Role = {
name: 'my role',
elasticsearch: {
@@ -170,7 +181,7 @@ describe('transformRoleForSave', () => {
],
};
- const result = transformRoleForSave(role, false);
+ const result = await saveRole(role, false);
expect(result).toEqual({
elasticsearch: {
@@ -191,7 +202,7 @@ describe('transformRoleForSave', () => {
});
});
- it('should remove space privileges', () => {
+ it('should remove space privileges', async () => {
const role: Role = {
name: 'my role',
elasticsearch: {
@@ -219,7 +230,7 @@ describe('transformRoleForSave', () => {
],
};
- const result = transformRoleForSave(role, false);
+ const result = await saveRole(role, false);
expect(result).toEqual({
elasticsearch: {
@@ -242,7 +253,7 @@ describe('transformRoleForSave', () => {
});
describe('spaces enabled', () => {
- it('removes placeholder index privileges', () => {
+ it('removes placeholder index privileges', async () => {
const role: Role = {
name: 'my role',
elasticsearch: {
@@ -253,7 +264,7 @@ describe('transformRoleForSave', () => {
kibana: [],
};
- const result = transformRoleForSave(role, true);
+ const result = await saveRole(role, true);
expect(result).toEqual({
elasticsearch: {
@@ -265,7 +276,7 @@ describe('transformRoleForSave', () => {
});
});
- it('removes placeholder query entries', () => {
+ it('removes placeholder query entries', async () => {
const role: Role = {
name: 'my role',
elasticsearch: {
@@ -276,7 +287,7 @@ describe('transformRoleForSave', () => {
kibana: [],
};
- const result = transformRoleForSave(role, true);
+ const result = await saveRole(role, true);
expect(result).toEqual({
elasticsearch: {
@@ -288,7 +299,7 @@ describe('transformRoleForSave', () => {
});
});
- it('removes transient fields not required for save', () => {
+ it('removes transient fields not required for save', async () => {
const role: Role = {
name: 'my role',
transient_metadata: {
@@ -307,7 +318,7 @@ describe('transformRoleForSave', () => {
kibana: [],
};
- const result = transformRoleForSave(role, true);
+ const result = await saveRole(role, true);
expect(result).toEqual({
metadata: {
@@ -322,7 +333,7 @@ describe('transformRoleForSave', () => {
});
});
- it('does not remove actual query entries', () => {
+ it('does not remove actual query entries', async () => {
const role: Role = {
name: 'my role',
elasticsearch: {
@@ -333,7 +344,7 @@ describe('transformRoleForSave', () => {
kibana: [],
};
- const result = transformRoleForSave(role, true);
+ const result = await saveRole(role, true);
expect(result).toEqual({
elasticsearch: {
@@ -345,7 +356,7 @@ describe('transformRoleForSave', () => {
});
});
- it('should remove feature privileges if a corresponding base privilege is defined', () => {
+ it('should remove feature privileges if a corresponding base privilege is defined', async () => {
const role: Role = {
name: 'my role',
elasticsearch: {
@@ -365,7 +376,7 @@ describe('transformRoleForSave', () => {
],
};
- const result = transformRoleForSave(role, true);
+ const result = await saveRole(role, true);
expect(result).toEqual({
elasticsearch: {
@@ -383,7 +394,7 @@ describe('transformRoleForSave', () => {
});
});
- it('should not remove feature privileges if a corresponding base privilege is not defined', () => {
+ it('should not remove feature privileges if a corresponding base privilege is not defined', async () => {
const role: Role = {
name: 'my role',
elasticsearch: {
@@ -403,7 +414,7 @@ describe('transformRoleForSave', () => {
],
};
- const result = transformRoleForSave(role, true);
+ const result = await saveRole(role, true);
expect(result).toEqual({
elasticsearch: {
@@ -424,7 +435,7 @@ describe('transformRoleForSave', () => {
});
});
- it('should not remove space privileges', () => {
+ it('should not remove space privileges', async () => {
const role: Role = {
name: 'my role',
elasticsearch: {
@@ -452,7 +463,7 @@ describe('transformRoleForSave', () => {
],
};
- const result = transformRoleForSave(role, true);
+ const result = await saveRole(role, true);
expect(result).toEqual({
elasticsearch: {
diff --git a/x-pack/plugins/security/public/management/roles/roles_api_client.ts b/x-pack/plugins/security/public/management/roles/roles_api_client.ts
new file mode 100644
index 00000000000000..d7e98e03a965b7
--- /dev/null
+++ b/x-pack/plugins/security/public/management/roles/roles_api_client.ts
@@ -0,0 +1,62 @@
+/*
+ * 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 { HttpStart } from 'src/core/public';
+import { Role, RoleIndexPrivilege, copyRole } from '../../../common/model';
+import { isGlobalPrivilegeDefinition } from './edit_role/privilege_utils';
+
+export class RolesAPIClient {
+ constructor(private readonly http: HttpStart) {}
+
+ public async getRoles() {
+ return await this.http.get('/api/security/role');
+ }
+
+ public async getRole(roleName: string) {
+ return await this.http.get(`/api/security/role/${encodeURIComponent(roleName)}`);
+ }
+
+ public async deleteRole(roleName: string) {
+ await this.http.delete(`/api/security/role/${encodeURIComponent(roleName)}`);
+ }
+
+ public async saveRole({ role, spacesEnabled }: { role: Role; spacesEnabled: boolean }) {
+ await this.http.put(`/api/security/role/${encodeURIComponent(role.name)}`, {
+ body: JSON.stringify(this.transformRoleForSave(copyRole(role), spacesEnabled)),
+ });
+ }
+
+ private transformRoleForSave(role: Role, spacesEnabled: boolean) {
+ // Remove any placeholder index privileges
+ const isPlaceholderPrivilege = (indexPrivilege: RoleIndexPrivilege) =>
+ indexPrivilege.names.length === 0;
+ role.elasticsearch.indices = role.elasticsearch.indices.filter(
+ indexPrivilege => !isPlaceholderPrivilege(indexPrivilege)
+ );
+
+ // Remove any placeholder query entries
+ role.elasticsearch.indices.forEach(index => index.query || delete index.query);
+
+ // If spaces are disabled, then do not persist any space privileges
+ if (!spacesEnabled) {
+ role.kibana = role.kibana.filter(isGlobalPrivilegeDefinition);
+ }
+
+ role.kibana.forEach(kibanaPrivilege => {
+ // If a base privilege is defined, then do not persist feature privileges
+ if (kibanaPrivilege.base.length > 0) {
+ kibanaPrivilege.feature = {};
+ }
+ });
+
+ delete role.name;
+ delete role.transient_metadata;
+ delete role._unrecognized_applications;
+ delete role._transform_error;
+
+ return role;
+ }
+}
diff --git a/x-pack/legacy/plugins/security/public/views/management/roles_grid/components/__snapshots__/roles_grid_page.test.tsx.snap b/x-pack/plugins/security/public/management/roles/roles_grid/__snapshots__/roles_grid_page.test.tsx.snap
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/roles_grid/components/__snapshots__/roles_grid_page.test.tsx.snap
rename to x-pack/plugins/security/public/management/roles/roles_grid/__snapshots__/roles_grid_page.test.tsx.snap
diff --git a/x-pack/legacy/plugins/security/public/views/management/roles_grid/components/confirm_delete/confirm_delete.tsx b/x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/confirm_delete.tsx
similarity index 72%
rename from x-pack/legacy/plugins/security/public/views/management/roles_grid/components/confirm_delete/confirm_delete.tsx
rename to x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/confirm_delete.tsx
index 34784b4b2accb6..37eed3357241d5 100644
--- a/x-pack/legacy/plugins/security/public/views/management/roles_grid/components/confirm_delete/confirm_delete.tsx
+++ b/x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/confirm_delete.tsx
@@ -4,6 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import React, { Component, Fragment } from 'react';
import {
EuiButton,
EuiButtonEmpty,
@@ -15,23 +16,24 @@ import {
EuiOverlayMask,
EuiText,
} from '@elastic/eui';
-import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
-import React, { Component, Fragment } from 'react';
-import { toastNotifications } from 'ui/notify';
-import { RolesApi } from '../../../../../lib/roles_api';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { NotificationsStart } from 'src/core/public';
+import { RolesAPIClient } from '../../roles_api_client';
interface Props {
rolesToDelete: string[];
- intl: InjectedIntl;
callback: (rolesToDelete: string[], errors: string[]) => void;
onCancel: () => void;
+ notifications: NotificationsStart;
+ rolesAPIClient: PublicMethodsOf;
}
interface State {
deleteInProgress: boolean;
}
-class ConfirmDeleteUI extends Component {
+export class ConfirmDelete extends Component {
constructor(props: Props) {
super(props);
this.state = {
@@ -40,15 +42,12 @@ class ConfirmDeleteUI extends Component {
}
public render() {
- const { rolesToDelete, intl } = this.props;
+ const { rolesToDelete } = this.props;
const moreThanOne = rolesToDelete.length > 1;
- const title = intl.formatMessage(
- {
- id: 'xpack.security.management.roles.deleteRoleTitle',
- defaultMessage: 'Delete role{value, plural, one {{roleName}} other {s}}',
- },
- { value: rolesToDelete.length, roleName: ` ${rolesToDelete[0]}` }
- );
+ const title = i18n.translate('xpack.security.management.roles.deleteRoleTitle', {
+ defaultMessage: 'Delete role{value, plural, one {{roleName}} other {s}}',
+ values: { value: rolesToDelete.length, roleName: ` ${rolesToDelete[0]}` },
+ });
// This is largely the same as the built-in EuiConfirmModal component, but we needed the ability
// to disable the buttons since this could be a long-running operation
@@ -128,32 +127,24 @@ class ConfirmDeleteUI extends Component {
};
private deleteRoles = async () => {
- const { rolesToDelete, callback } = this.props;
+ const { rolesToDelete, callback, rolesAPIClient, notifications } = this.props;
const errors: string[] = [];
const deleteOperations = rolesToDelete.map(roleName => {
const deleteRoleTask = async () => {
try {
- await RolesApi.deleteRole(roleName);
- toastNotifications.addSuccess(
- this.props.intl.formatMessage(
- {
- id:
- 'xpack.security.management.roles.confirmDelete.roleSuccessfullyDeletedNotificationMessage',
- defaultMessage: 'Deleted role {roleName}',
- },
- { roleName }
+ await rolesAPIClient.deleteRole(roleName);
+ notifications.toasts.addSuccess(
+ i18n.translate(
+ 'xpack.security.management.roles.confirmDelete.roleSuccessfullyDeletedNotificationMessage',
+ { defaultMessage: 'Deleted role {roleName}', values: { roleName } }
)
);
} catch (e) {
errors.push(roleName);
- toastNotifications.addDanger(
- this.props.intl.formatMessage(
- {
- id:
- 'xpack.security.management.roles.confirmDelete.roleDeletingErrorNotificationMessage',
- defaultMessage: 'Error deleting role {roleName}',
- },
- { roleName }
+ notifications.toasts.addDanger(
+ i18n.translate(
+ 'xpack.security.management.roles.confirmDelete.roleDeletingErrorNotificationMessage',
+ { defaultMessage: 'Error deleting role {roleName}', values: { roleName } }
)
);
}
@@ -167,5 +158,3 @@ class ConfirmDeleteUI extends Component {
callback(rolesToDelete, errors);
};
}
-
-export const ConfirmDelete = injectI18n(ConfirmDeleteUI);
diff --git a/x-pack/legacy/plugins/security/public/views/management/roles_grid/components/confirm_delete/index.ts b/x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/index.ts
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/roles_grid/components/confirm_delete/index.ts
rename to x-pack/plugins/security/public/management/roles/roles_grid/confirm_delete/index.ts
diff --git a/x-pack/legacy/plugins/security/public/views/management/roles_grid/components/index.ts b/x-pack/plugins/security/public/management/roles/roles_grid/index.ts
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/roles_grid/components/index.ts
rename to x-pack/plugins/security/public/management/roles/roles_grid/index.ts
diff --git a/x-pack/legacy/plugins/security/public/views/management/roles_grid/components/permission_denied/index.ts b/x-pack/plugins/security/public/management/roles/roles_grid/permission_denied/index.ts
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/roles_grid/components/permission_denied/index.ts
rename to x-pack/plugins/security/public/management/roles/roles_grid/permission_denied/index.ts
diff --git a/x-pack/legacy/plugins/security/public/views/management/roles_grid/components/permission_denied/permission_denied.tsx b/x-pack/plugins/security/public/management/roles/roles_grid/permission_denied/permission_denied.tsx
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/roles_grid/components/permission_denied/permission_denied.tsx
rename to x-pack/plugins/security/public/management/roles/roles_grid/permission_denied/permission_denied.tsx
diff --git a/x-pack/legacy/plugins/security/public/views/management/roles_grid/components/roles_grid_page.test.tsx b/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.test.tsx
similarity index 63%
rename from x-pack/legacy/plugins/security/public/views/management/roles_grid/components/roles_grid_page.test.tsx
rename to x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.test.tsx
index 6da2f2442d488b..63ace53420612d 100644
--- a/x-pack/legacy/plugins/security/public/views/management/roles_grid/components/roles_grid_page.test.tsx
+++ b/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.test.tsx
@@ -4,50 +4,19 @@
* you may not use this file except in compliance with the Elastic License.
*/
-let mockSimulate403 = false;
-const mock403 = () => ({ body: { statusCode: 403 } });
-jest.mock('../../../../lib/roles_api', () => {
- return {
- RolesApi: {
- async getRoles() {
- if (mockSimulate403) {
- throw mock403();
- }
- return [
- {
- name: 'test-role-1',
- elasticsearch: { cluster: [], indices: [], run_as: [] },
- kibana: { global: [], space: {} },
- },
- {
- name: 'reserved-role',
- elasticsearch: { cluster: [], indices: [], run_as: [] },
- kibana: { global: [], space: {} },
- metadata: {
- _reserved: true,
- },
- },
- {
- name: 'disabled-role',
- elasticsearch: { cluster: [], indices: [], run_as: [] },
- kibana: { global: [], space: {} },
- transient_metadata: {
- enabled: false,
- },
- },
- ];
- },
- },
- };
-});
-
import { EuiIcon } from '@elastic/eui';
import { ReactWrapper } from 'enzyme';
import React from 'react';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
+import { RolesAPIClient } from '../roles_api_client';
import { PermissionDenied } from './permission_denied';
import { RolesGridPage } from './roles_grid_page';
+import { coreMock } from '../../../../../../../src/core/public/mocks';
+import { rolesAPIClientMock } from '../index.mock';
+
+const mock403 = () => ({ body: { statusCode: 403 } });
+
const waitForRender = async (
wrapper: ReactWrapper,
condition: (wrapper: ReactWrapper) => boolean
@@ -69,12 +38,37 @@ const waitForRender = async (
};
describe('', () => {
+ let apiClientMock: jest.Mocked>;
beforeEach(() => {
- mockSimulate403 = false;
+ apiClientMock = rolesAPIClientMock.create();
+ apiClientMock.getRoles.mockResolvedValue([
+ {
+ name: 'test-role-1',
+ elasticsearch: { cluster: [], indices: [], run_as: [] },
+ kibana: [{ base: [], spaces: [], feature: {} }],
+ },
+ {
+ name: 'reserved-role',
+ elasticsearch: { cluster: [], indices: [], run_as: [] },
+ kibana: [{ base: [], spaces: [], feature: {} }],
+ metadata: { _reserved: true },
+ },
+ {
+ name: 'disabled-role',
+ elasticsearch: { cluster: [], indices: [], run_as: [] },
+ kibana: [{ base: [], spaces: [], feature: {} }],
+ transient_metadata: { enabled: false },
+ },
+ ]);
});
it(`renders reserved roles as such`, async () => {
- const wrapper = mountWithIntl();
+ const wrapper = mountWithIntl(
+
+ );
const initialIconCount = wrapper.find(EuiIcon).length;
await waitForRender(wrapper, updatedWrapper => {
@@ -87,8 +81,14 @@ describe('', () => {
});
it('renders permission denied if required', async () => {
- mockSimulate403 = true;
- const wrapper = mountWithIntl();
+ apiClientMock.getRoles.mockRejectedValue(mock403());
+
+ const wrapper = mountWithIntl(
+
+ );
await waitForRender(wrapper, updatedWrapper => {
return updatedWrapper.find(PermissionDenied).length > 0;
});
@@ -96,7 +96,12 @@ describe('', () => {
});
it('renders role actions as appropriate', async () => {
- const wrapper = mountWithIntl();
+ const wrapper = mountWithIntl(
+
+ );
const initialIconCount = wrapper.find(EuiIcon).length;
await waitForRender(wrapper, updatedWrapper => {
diff --git a/x-pack/legacy/plugins/security/public/views/management/roles_grid/components/roles_grid_page.tsx b/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.tsx
similarity index 78%
rename from x-pack/legacy/plugins/security/public/views/management/roles_grid/components/roles_grid_page.tsx
rename to x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.tsx
index 2083a93f4b33c9..7c686bef391a79 100644
--- a/x-pack/legacy/plugins/security/public/views/management/roles_grid/components/roles_grid_page.tsx
+++ b/x-pack/plugins/security/public/management/roles/roles_grid/roles_grid_page.tsx
@@ -4,6 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import _ from 'lodash';
+import React, { Component } from 'react';
import {
EuiButton,
EuiIcon,
@@ -18,18 +20,17 @@ import {
EuiButtonIcon,
EuiBasicTableColumn,
} from '@elastic/eui';
-import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react';
-import _ from 'lodash';
-import React, { Component } from 'react';
-import { toastNotifications } from 'ui/notify';
-import { Role } from '../../../../../common/model';
-import { isRoleEnabled, isReadOnlyRole, isReservedRole } from '../../../../lib/role_utils';
-import { RolesApi } from '../../../../lib/roles_api';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { NotificationsStart } from 'src/core/public';
+import { Role, isRoleEnabled, isReadOnlyRole, isReservedRole } from '../../../../common/model';
+import { RolesAPIClient } from '../roles_api_client';
import { ConfirmDelete } from './confirm_delete';
import { PermissionDenied } from './permission_denied';
interface Props {
- intl: InjectedIntl;
+ notifications: NotificationsStart;
+ rolesAPIClient: PublicMethodsOf;
}
interface State {
@@ -44,7 +45,7 @@ const getRoleManagementHref = (action: 'edit' | 'clone', roleName?: string) => {
return `#/management/security/roles/${action}${roleName ? `/${roleName}` : ''}`;
};
-class RolesGridPageUI extends Component {
+export class RolesGridPage extends Component {
constructor(props: Props) {
super(props);
this.state = {
@@ -68,7 +69,6 @@ class RolesGridPageUI extends Component {
private getPageContent = () => {
const { roles } = this.state;
- const { intl } = this.props;
return (
@@ -105,6 +105,8 @@ class RolesGridPageUI extends Component {
onCancel={this.onCancelDelete}
rolesToDelete={this.state.selection.map(role => role.name)}
callback={this.handleDelete}
+ notifications={this.props.notifications}
+ rolesAPIClient={this.props.rolesAPIClient}
/>
) : null}
@@ -112,7 +114,7 @@ class RolesGridPageUI extends Component {
!role.metadata || !role.metadata._reserved,
@@ -155,17 +157,16 @@ class RolesGridPageUI extends Component {
);
};
- private getColumnConfig = (intl: InjectedIntl) => {
- const reservedRoleDesc = intl.formatMessage({
- id: 'xpack.security.management.roles.reservedColumnDescription',
- defaultMessage: 'Reserved roles are built-in and cannot be edited or removed.',
- });
+ private getColumnConfig = () => {
+ const reservedRoleDesc = i18n.translate(
+ 'xpack.security.management.roles.reservedColumnDescription',
+ { defaultMessage: 'Reserved roles are built-in and cannot be edited or removed.' }
+ );
return [
{
field: 'name',
- name: intl.formatMessage({
- id: 'xpack.security.management.roles.nameColumnName',
+ name: i18n.translate('xpack.security.management.roles.nameColumnName', {
defaultMessage: 'Role',
}),
sortable: true,
@@ -188,8 +189,7 @@ class RolesGridPageUI extends Component {
},
{
field: 'metadata',
- name: intl.formatMessage({
- id: 'xpack.security.management.roles.reservedColumnName',
+ name: i18n.translate('xpack.security.management.roles.reservedColumnName', {
defaultMessage: 'Reserved',
}),
sortable: ({ metadata }: Role) => Boolean(metadata && metadata._reserved),
@@ -197,8 +197,7 @@ class RolesGridPageUI extends Component {
align: 'right',
description: reservedRoleDesc,
render: (metadata: Role['metadata']) => {
- const label = intl.formatMessage({
- id: 'xpack.security.management.roles.reservedRoleIconLabel',
+ const label = i18n.translate('xpack.security.management.roles.reservedRoleIconLabel', {
defaultMessage: 'Reserved role',
});
@@ -210,8 +209,7 @@ class RolesGridPageUI extends Component {
},
},
{
- name: intl.formatMessage({
- id: 'xpack.security.management.roles.actionsColumnName',
+ name: i18n.translate('xpack.security.management.roles.actionsColumnName', {
defaultMessage: 'Actions',
}),
width: '150px',
@@ -219,15 +217,10 @@ class RolesGridPageUI extends Component {
{
available: (role: Role) => !isReadOnlyRole(role),
render: (role: Role) => {
- const title = intl.formatMessage(
- {
- id: 'xpack.security.management.roles.editRoleActionName',
- defaultMessage: `Edit {roleName}`,
- },
- {
- roleName: role.name,
- }
- );
+ const title = i18n.translate('xpack.security.management.roles.editRoleActionName', {
+ defaultMessage: `Edit {roleName}`,
+ values: { roleName: role.name },
+ });
return (
{
{
available: (role: Role) => !isReservedRole(role),
render: (role: Role) => {
- const title = intl.formatMessage(
- {
- id: 'xpack.security.management.roles.cloneRoleActionName',
- defaultMessage: `Clone {roleName}`,
- },
- {
- roleName: role.name,
- }
- );
+ const title = i18n.translate('xpack.security.management.roles.cloneRoleActionName', {
+ defaultMessage: `Clone {roleName}`,
+ values: { roleName: role.name },
+ });
return (
{
private async loadRoles() {
try {
- const roles = await RolesApi.getRoles();
+ const roles = await this.props.rolesAPIClient.getRoles();
this.setState({ roles });
} catch (e) {
if (_.get(e, 'body.statusCode') === 403) {
this.setState({ permissionDenied: true });
} else {
- toastNotifications.addDanger(
- this.props.intl.formatMessage(
- {
- id: 'xpack.security.management.roles.fetchingRolesErrorMessage',
- defaultMessage: 'Error fetching roles: {message}',
- },
- { message: _.get(e, 'body.message', '') }
- )
+ this.props.notifications.toasts.addDanger(
+ i18n.translate('xpack.security.management.roles.fetchingRolesErrorMessage', {
+ defaultMessage: 'Error fetching roles: {message}',
+ values: { message: _.get(e, 'body.message', '') },
+ })
);
}
}
@@ -339,5 +324,3 @@ class RolesGridPageUI extends Component {
this.setState({ showDeleteConfirmation: false });
};
}
-
-export const RolesGridPage = injectI18n(RolesGridPageUI);
diff --git a/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx b/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx
new file mode 100644
index 00000000000000..48bc1a6580a93d
--- /dev/null
+++ b/x-pack/plugins/security/public/management/roles/roles_management_app.test.tsx
@@ -0,0 +1,160 @@
+/*
+ * 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 { licenseMock } from '../../../common/licensing/index.mock';
+
+jest.mock('./roles_grid', () => ({
+ RolesGridPage: (props: any) => `Roles Page: ${JSON.stringify(props)}`,
+}));
+
+jest.mock('./edit_role', () => ({
+ EditRolePage: (props: any) => `Role Edit Page: ${JSON.stringify(props)}`,
+}));
+
+import { rolesManagementApp } from './roles_management_app';
+
+import { coreMock } from '../../../../../../src/core/public/mocks';
+
+async function mountApp(basePath: string) {
+ const { fatalErrors } = coreMock.createSetup();
+ const container = document.createElement('div');
+ const setBreadcrumbs = jest.fn();
+
+ const unmount = await rolesManagementApp
+ .create({
+ license: licenseMock.create(),
+ fatalErrors,
+ getStartServices: jest.fn().mockResolvedValue([coreMock.createStart(), { data: {} }]),
+ })
+ .mount({ basePath, element: container, setBreadcrumbs });
+
+ return { unmount, container, setBreadcrumbs };
+}
+
+describe('rolesManagementApp', () => {
+ it('create() returns proper management app descriptor', () => {
+ const { fatalErrors, getStartServices } = coreMock.createSetup();
+
+ expect(
+ rolesManagementApp.create({
+ license: licenseMock.create(),
+ fatalErrors,
+ getStartServices: getStartServices as any,
+ })
+ ).toMatchInlineSnapshot(`
+ Object {
+ "id": "roles",
+ "mount": [Function],
+ "order": 20,
+ "title": "Roles",
+ }
+ `);
+ });
+
+ it('mount() works for the `grid` page', async () => {
+ const basePath = '/some-base-path/roles';
+ window.location.hash = basePath;
+
+ const { setBreadcrumbs, container, unmount } = await mountApp(basePath);
+
+ expect(setBreadcrumbs).toHaveBeenCalledTimes(1);
+ expect(setBreadcrumbs).toHaveBeenCalledWith([{ href: `#${basePath}`, text: 'Roles' }]);
+ expect(container).toMatchInlineSnapshot(`
+
+ Roles Page: {"notifications":{"toasts":{}},"rolesAPIClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}}}
+
+ `);
+
+ unmount();
+
+ expect(container).toMatchInlineSnapshot(``);
+ });
+
+ it('mount() works for the `create role` page', async () => {
+ const basePath = '/some-base-path/roles';
+ window.location.hash = `${basePath}/edit`;
+
+ const { setBreadcrumbs, container, unmount } = await mountApp(basePath);
+
+ expect(setBreadcrumbs).toHaveBeenCalledTimes(1);
+ expect(setBreadcrumbs).toHaveBeenCalledWith([
+ { href: `#${basePath}`, text: 'Roles' },
+ { text: 'Create' },
+ ]);
+ expect(container).toMatchInlineSnapshot(`
+
+ Role Edit Page: {"action":"edit","rolesAPIClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"userAPIClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"indicesAPIClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"privilegesAPIClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"http":{"basePath":{"basePath":""},"anonymousPaths":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{"_isScalar":false}},"docLinks":{"esDocBasePath":"https://www.elastic.co/guide/en/elasticsearch/reference/mocked-test-branch/"},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{}}}
+
+ `);
+
+ unmount();
+
+ expect(container).toMatchInlineSnapshot(``);
+ });
+
+ it('mount() works for the `edit role` page', async () => {
+ const basePath = '/some-base-path/roles';
+ const roleName = 'someRoleName';
+ window.location.hash = `${basePath}/edit/${roleName}`;
+
+ const { setBreadcrumbs, container, unmount } = await mountApp(basePath);
+
+ expect(setBreadcrumbs).toHaveBeenCalledTimes(1);
+ expect(setBreadcrumbs).toHaveBeenCalledWith([
+ { href: `#${basePath}`, text: 'Roles' },
+ { href: `#/some-base-path/roles/edit/${roleName}`, text: roleName },
+ ]);
+ expect(container).toMatchInlineSnapshot(`
+
+ Role Edit Page: {"action":"edit","roleName":"someRoleName","rolesAPIClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"userAPIClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"indicesAPIClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"privilegesAPIClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"http":{"basePath":{"basePath":""},"anonymousPaths":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{"_isScalar":false}},"docLinks":{"esDocBasePath":"https://www.elastic.co/guide/en/elasticsearch/reference/mocked-test-branch/"},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{}}}
+
+ `);
+
+ unmount();
+
+ expect(container).toMatchInlineSnapshot(``);
+ });
+
+ it('mount() works for the `clone role` page', async () => {
+ const basePath = '/some-base-path/roles';
+ const roleName = 'someRoleName';
+ window.location.hash = `${basePath}/clone/${roleName}`;
+
+ const { setBreadcrumbs, container, unmount } = await mountApp(basePath);
+
+ expect(setBreadcrumbs).toHaveBeenCalledTimes(1);
+ expect(setBreadcrumbs).toHaveBeenCalledWith([
+ { href: `#${basePath}`, text: 'Roles' },
+ { text: 'Create' },
+ ]);
+ expect(container).toMatchInlineSnapshot(`
+
+ Role Edit Page: {"action":"clone","roleName":"someRoleName","rolesAPIClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"userAPIClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"indicesAPIClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"privilegesAPIClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"http":{"basePath":{"basePath":""},"anonymousPaths":{}},"notifications":{"toasts":{}},"fatalErrors":{},"license":{"features$":{"_isScalar":false}},"docLinks":{"esDocBasePath":"https://www.elastic.co/guide/en/elasticsearch/reference/mocked-test-branch/"},"uiCapabilities":{"catalogue":{},"management":{},"navLinks":{}}}
+
+ `);
+
+ unmount();
+
+ expect(container).toMatchInlineSnapshot(``);
+ });
+
+ it('mount() properly encodes role name in `edit role` page link in breadcrumbs', async () => {
+ const basePath = '/some-base-path/roles';
+ const roleName = 'some 安全性 role';
+ window.location.hash = `${basePath}/edit/${roleName}`;
+
+ const { setBreadcrumbs } = await mountApp(basePath);
+
+ expect(setBreadcrumbs).toHaveBeenCalledTimes(1);
+ expect(setBreadcrumbs).toHaveBeenCalledWith([
+ { href: `#${basePath}`, text: 'Roles' },
+ {
+ href: '#/some-base-path/roles/edit/some%20%E5%AE%89%E5%85%A8%E6%80%A7%20role',
+ text: roleName,
+ },
+ ]);
+ });
+});
diff --git a/x-pack/plugins/security/public/management/roles/roles_management_app.tsx b/x-pack/plugins/security/public/management/roles/roles_management_app.tsx
new file mode 100644
index 00000000000000..4e8c95b61c2f19
--- /dev/null
+++ b/x-pack/plugins/security/public/management/roles/roles_management_app.tsx
@@ -0,0 +1,116 @@
+/*
+ * 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 { render, unmountComponentAtNode } from 'react-dom';
+import { HashRouter as Router, Route, Switch, useParams } from 'react-router-dom';
+import { i18n } from '@kbn/i18n';
+import { CoreSetup, FatalErrorsSetup } from 'src/core/public';
+import { RegisterManagementAppArgs } from '../../../../../../src/plugins/management/public';
+import { SecurityLicense } from '../../../common/licensing';
+import { PluginStartDependencies } from '../../plugin';
+import { UserAPIClient } from '../users';
+import { RolesAPIClient } from './roles_api_client';
+import { RolesGridPage } from './roles_grid';
+import { EditRolePage } from './edit_role';
+import { DocumentationLinksService } from './documentation_links';
+import { IndicesAPIClient } from './indices_api_client';
+import { PrivilegesAPIClient } from './privileges_api_client';
+
+interface CreateParams {
+ fatalErrors: FatalErrorsSetup;
+ license: SecurityLicense;
+ getStartServices: CoreSetup['getStartServices'];
+}
+
+export const rolesManagementApp = Object.freeze({
+ id: 'roles',
+ create({ license, fatalErrors, getStartServices }: CreateParams) {
+ return {
+ id: this.id,
+ order: 20,
+ title: i18n.translate('xpack.security.management.rolesTitle', { defaultMessage: 'Roles' }),
+ async mount({ basePath, element, setBreadcrumbs }) {
+ const [
+ { application, docLinks, http, i18n: i18nStart, injectedMetadata, notifications },
+ { data },
+ ] = await getStartServices();
+
+ const rolesBreadcrumbs = [
+ {
+ text: i18n.translate('xpack.security.roles.breadcrumb', { defaultMessage: 'Roles' }),
+ href: `#${basePath}`,
+ },
+ ];
+
+ const rolesAPIClient = new RolesAPIClient(http);
+ const RolesGridPageWithBreadcrumbs = () => {
+ setBreadcrumbs(rolesBreadcrumbs);
+ return ;
+ };
+
+ const EditRolePageWithBreadcrumbs = ({ action }: { action: 'edit' | 'clone' }) => {
+ const { roleName } = useParams<{ roleName?: string }>();
+
+ setBreadcrumbs([
+ ...rolesBreadcrumbs,
+ action === 'edit' && roleName
+ ? { text: roleName, href: `#${basePath}/edit/${encodeURIComponent(roleName)}` }
+ : {
+ text: i18n.translate('xpack.security.roles.createBreadcrumb', {
+ defaultMessage: 'Create',
+ }),
+ },
+ ]);
+
+ return (
+
+ );
+ };
+
+ render(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ element
+ );
+
+ return () => {
+ unmountComponentAtNode(element);
+ };
+ },
+ } as RegisterManagementAppArgs;
+ },
+});
diff --git a/x-pack/plugins/security/public/management/users/_index.scss b/x-pack/plugins/security/public/management/users/_index.scss
new file mode 100644
index 00000000000000..35df0c1b965837
--- /dev/null
+++ b/x-pack/plugins/security/public/management/users/_index.scss
@@ -0,0 +1 @@
+@import './edit_user/index';
diff --git a/x-pack/legacy/plugins/security/public/components/management/change_password_form/change_password_form.test.tsx b/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.test.tsx
similarity index 82%
rename from x-pack/legacy/plugins/security/public/components/management/change_password_form/change_password_form.test.tsx
rename to x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.test.tsx
index 221120532318cb..be46612767a593 100644
--- a/x-pack/legacy/plugins/security/public/components/management/change_password_form/change_password_form.test.tsx
+++ b/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.test.tsx
@@ -7,10 +7,12 @@ import { EuiFieldText } from '@elastic/eui';
import { ReactWrapper } from 'enzyme';
import React from 'react';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
-import { User } from '../../../../common/model';
-import { UserAPIClient } from '../../../lib/api';
+import { User } from '../../../../../common/model';
import { ChangePasswordForm } from './change_password_form';
+import { coreMock } from '../../../../../../../../src/core/public/mocks';
+import { userAPIClientMock } from '../../index.mock';
+
function getCurrentPasswordField(wrapper: ReactWrapper) {
return wrapper.find(EuiFieldText).filter('[data-test-subj="currentPassword"]');
}
@@ -23,8 +25,6 @@ function getConfirmPasswordField(wrapper: ReactWrapper) {
return wrapper.find(EuiFieldText).filter('[data-test-subj="confirmNewPassword"]');
}
-jest.mock('ui/kfetch');
-
describe('', () => {
describe('for the current user', () => {
it('shows fields for current and new passwords', () => {
@@ -40,7 +40,8 @@ describe('', () => {
);
@@ -60,15 +61,15 @@ describe('', () => {
const callback = jest.fn();
- const apiClient = new UserAPIClient();
- apiClient.changePassword = jest.fn();
+ const apiClientMock = userAPIClientMock.create();
const wrapper = mountWithIntl(
);
@@ -83,8 +84,8 @@ describe('', () => {
wrapper.find('button[data-test-subj="changePasswordButton"]').simulate('click');
- expect(apiClient.changePassword).toHaveBeenCalledTimes(1);
- expect(apiClient.changePassword).toHaveBeenCalledWith(
+ expect(apiClientMock.changePassword).toHaveBeenCalledTimes(1);
+ expect(apiClientMock.changePassword).toHaveBeenCalledWith(
'user',
'myNewPassword',
'myCurrentPassword'
@@ -106,7 +107,8 @@ describe('', () => {
);
diff --git a/x-pack/legacy/plugins/security/public/components/management/change_password_form/change_password_form.tsx b/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.tsx
similarity index 96%
rename from x-pack/legacy/plugins/security/public/components/management/change_password_form/change_password_form.tsx
rename to x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.tsx
index 61c0b77decd565..6dcf330ec6f9e1 100644
--- a/x-pack/legacy/plugins/security/public/components/management/change_password_form/change_password_form.tsx
+++ b/x-pack/plugins/security/public/management/users/components/change_password_form/change_password_form.tsx
@@ -5,10 +5,7 @@
*/
import {
EuiButton,
- // @ts-ignore
EuiButtonEmpty,
- // @ts-ignore
- EuiDescribedFormGroup,
EuiFieldText,
EuiFlexGroup,
EuiFlexItem,
@@ -18,15 +15,16 @@ import {
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import React, { ChangeEvent, Component } from 'react';
-import { toastNotifications } from 'ui/notify';
-import { User } from '../../../../common/model';
-import { UserAPIClient } from '../../../lib/api';
+import { NotificationsStart } from 'src/core/public';
+import { User } from '../../../../../common/model';
+import { UserAPIClient } from '../..';
interface Props {
user: User;
isUserChangingOwnPassword: boolean;
onChangePassword?: () => void;
- apiClient: UserAPIClient;
+ apiClient: PublicMethodsOf;
+ notifications: NotificationsStart;
}
interface State {
@@ -294,7 +292,7 @@ export class ChangePasswordForm extends Component {
};
private handleChangePasswordSuccess = () => {
- toastNotifications.addSuccess({
+ this.props.notifications.toasts.addSuccess({
title: i18n.translate('xpack.security.account.changePasswordSuccess', {
defaultMessage: 'Your password has been changed.',
}),
@@ -317,7 +315,7 @@ export class ChangePasswordForm extends Component {
if (error.body && error.body.statusCode === 403) {
this.setState({ currentPasswordError: true });
} else {
- toastNotifications.addDanger(
+ this.props.notifications.toasts.addDanger(
i18n.translate('xpack.security.management.users.editUser.settingPasswordErrorMessage', {
defaultMessage: 'Error setting password: {message}',
values: { message: _.get(error, 'body.message') },
diff --git a/x-pack/legacy/plugins/security/public/components/management/change_password_form/index.ts b/x-pack/plugins/security/public/management/users/components/change_password_form/index.ts
similarity index 100%
rename from x-pack/legacy/plugins/security/public/components/management/change_password_form/index.ts
rename to x-pack/plugins/security/public/management/users/components/change_password_form/index.ts
diff --git a/x-pack/legacy/plugins/security/public/components/management/users/confirm_delete.test.tsx b/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.test.tsx
similarity index 58%
rename from x-pack/legacy/plugins/security/public/components/management/users/confirm_delete.test.tsx
rename to x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.test.tsx
index 9f69fc7a7551f0..bcec707b03f936 100644
--- a/x-pack/legacy/plugins/security/public/components/management/users/confirm_delete.test.tsx
+++ b/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.test.tsx
@@ -5,16 +5,21 @@
*/
import { mountWithIntl } from 'test_utils/enzyme_helpers';
-import { ConfirmDeleteUsers } from './confirm_delete';
+import { ConfirmDeleteUsers } from './confirm_delete_users';
import React from 'react';
-import { UserAPIClient } from '../../../lib/api';
-jest.mock('ui/kfetch');
+import { coreMock } from '../../../../../../../../src/core/public/mocks';
+import { userAPIClientMock } from '../../index.mock';
describe('ConfirmDeleteUsers', () => {
it('renders a warning for a single user', () => {
const wrapper = mountWithIntl(
-
+
);
expect(wrapper.find('EuiModalHeaderTitle').text()).toMatchInlineSnapshot(`"Delete user foo"`);
@@ -23,7 +28,8 @@ describe('ConfirmDeleteUsers', () => {
it('renders a warning for a multiple users', () => {
const wrapper = mountWithIntl(
@@ -35,7 +41,12 @@ describe('ConfirmDeleteUsers', () => {
it('fires onCancel when the operation is cancelled', () => {
const onCancel = jest.fn();
const wrapper = mountWithIntl(
-
+
);
expect(onCancel).toBeCalledTimes(0);
@@ -47,50 +58,48 @@ describe('ConfirmDeleteUsers', () => {
it('deletes the requested users when confirmed', () => {
const onCancel = jest.fn();
- const deleteUser = jest.fn();
-
- const apiClient = new UserAPIClient();
- apiClient.deleteUser = deleteUser;
+ const apiClientMock = userAPIClientMock.create();
const wrapper = mountWithIntl(
);
wrapper.find('EuiButton[data-test-subj="confirmModalConfirmButton"]').simulate('click');
- expect(deleteUser).toBeCalledTimes(2);
- expect(deleteUser).toBeCalledWith('foo');
- expect(deleteUser).toBeCalledWith('bar');
+ expect(apiClientMock.deleteUser).toBeCalledTimes(2);
+ expect(apiClientMock.deleteUser).toBeCalledWith('foo');
+ expect(apiClientMock.deleteUser).toBeCalledWith('bar');
});
it('attempts to delete all users even if some fail', () => {
const onCancel = jest.fn();
- const deleteUser = jest.fn().mockImplementation(user => {
+
+ const apiClientMock = userAPIClientMock.create();
+ apiClientMock.deleteUser.mockImplementation(user => {
if (user === 'foo') {
return Promise.reject('something terrible happened');
}
return Promise.resolve();
});
- const apiClient = new UserAPIClient();
- apiClient.deleteUser = deleteUser;
-
const wrapper = mountWithIntl(
);
wrapper.find('EuiButton[data-test-subj="confirmModalConfirmButton"]').simulate('click');
- expect(deleteUser).toBeCalledTimes(2);
- expect(deleteUser).toBeCalledWith('foo');
- expect(deleteUser).toBeCalledWith('bar');
+ expect(apiClientMock.deleteUser).toBeCalledTimes(2);
+ expect(apiClientMock.deleteUser).toBeCalledWith('foo');
+ expect(apiClientMock.deleteUser).toBeCalledWith('bar');
});
});
diff --git a/x-pack/legacy/plugins/security/public/components/management/users/confirm_delete.tsx b/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.tsx
similarity index 50%
rename from x-pack/legacy/plugins/security/public/components/management/users/confirm_delete.tsx
rename to x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.tsx
index 53bb022afb513f..b7269e0168d7d5 100644
--- a/x-pack/legacy/plugins/security/public/components/management/users/confirm_delete.tsx
+++ b/x-pack/plugins/security/public/management/users/components/confirm_delete_users/confirm_delete_users.tsx
@@ -6,51 +6,46 @@
import React, { Component, Fragment } from 'react';
import { EuiOverlayMask, EuiConfirmModal } from '@elastic/eui';
-import { toastNotifications } from 'ui/notify';
-import { FormattedMessage, injectI18n, InjectedIntl } from '@kbn/i18n/react';
-import { UserAPIClient } from '../../../lib/api';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { NotificationsStart } from 'src/core/public';
+import { UserAPIClient } from '../..';
interface Props {
- intl: InjectedIntl;
usersToDelete: string[];
- apiClient: UserAPIClient;
+ apiClient: PublicMethodsOf;
+ notifications: NotificationsStart;
onCancel: () => void;
callback?: (usersToDelete: string[], errors: string[]) => void;
}
-class ConfirmDeleteUI extends Component {
+export class ConfirmDeleteUsers extends Component {
public render() {
- const { usersToDelete, onCancel, intl } = this.props;
+ const { usersToDelete, onCancel } = this.props;
const moreThanOne = usersToDelete.length > 1;
const title = moreThanOne
- ? intl.formatMessage(
- {
- id: 'xpack.security.management.users.confirmDelete.deleteMultipleUsersTitle',
- defaultMessage: 'Delete {userLength} users',
- },
- { userLength: usersToDelete.length }
- )
- : intl.formatMessage(
- {
- id: 'xpack.security.management.users.confirmDelete.deleteOneUserTitle',
- defaultMessage: 'Delete user {userLength}',
- },
- { userLength: usersToDelete[0] }
- );
+ ? i18n.translate('xpack.security.management.users.confirmDelete.deleteMultipleUsersTitle', {
+ defaultMessage: 'Delete {userLength} users',
+ values: { userLength: usersToDelete.length },
+ })
+ : i18n.translate('xpack.security.management.users.confirmDelete.deleteOneUserTitle', {
+ defaultMessage: 'Delete user {userLength}',
+ values: { userLength: usersToDelete[0] },
+ });
return (
@@ -82,31 +77,23 @@ class ConfirmDeleteUI extends Component
{
}
private deleteUsers = () => {
- const { usersToDelete, callback, apiClient } = this.props;
+ const { usersToDelete, callback, apiClient, notifications } = this.props;
const errors: string[] = [];
usersToDelete.forEach(async username => {
try {
await apiClient.deleteUser(username);
- toastNotifications.addSuccess(
- this.props.intl.formatMessage(
- {
- id:
- 'xpack.security.management.users.confirmDelete.userSuccessfullyDeletedNotificationMessage',
- defaultMessage: 'Deleted user {username}',
- },
- { username }
+ notifications.toasts.addSuccess(
+ i18n.translate(
+ 'xpack.security.management.users.confirmDelete.userSuccessfullyDeletedNotificationMessage',
+ { defaultMessage: 'Deleted user {username}', values: { username } }
)
);
} catch (e) {
errors.push(username);
- toastNotifications.addDanger(
- this.props.intl.formatMessage(
- {
- id:
- 'xpack.security.management.users.confirmDelete.userDeletingErrorNotificationMessage',
- defaultMessage: 'Error deleting user {username}',
- },
- { username }
+ notifications.toasts.addDanger(
+ i18n.translate(
+ 'xpack.security.management.users.confirmDelete.userDeletingErrorNotificationMessage',
+ { defaultMessage: 'Error deleting user {username}', values: { username } }
)
);
}
@@ -116,5 +103,3 @@ class ConfirmDeleteUI extends Component {
});
};
}
-
-export const ConfirmDeleteUsers = injectI18n(ConfirmDeleteUI);
diff --git a/x-pack/legacy/plugins/security/public/views/management/index.js b/x-pack/plugins/security/public/management/users/components/confirm_delete_users/index.ts
similarity index 79%
rename from x-pack/legacy/plugins/security/public/views/management/index.js
rename to x-pack/plugins/security/public/management/users/components/confirm_delete_users/index.ts
index 0ed6fe09ef80a4..fde35ab0f0d02e 100644
--- a/x-pack/legacy/plugins/security/public/views/management/index.js
+++ b/x-pack/plugins/security/public/management/users/components/confirm_delete_users/index.ts
@@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import './management';
+export { ConfirmDeleteUsers } from './confirm_delete_users';
diff --git a/x-pack/plugins/security/public/management/users/components/index.ts b/x-pack/plugins/security/public/management/users/components/index.ts
new file mode 100644
index 00000000000000..54011a6a24cbd2
--- /dev/null
+++ b/x-pack/plugins/security/public/management/users/components/index.ts
@@ -0,0 +1,8 @@
+/*
+ * 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 { ChangePasswordForm } from './change_password_form';
+export { ConfirmDeleteUsers } from './confirm_delete_users';
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_user/_users.scss b/x-pack/plugins/security/public/management/users/edit_user/_edit_user_page.scss
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_user/_users.scss
rename to x-pack/plugins/security/public/management/users/edit_user/_edit_user_page.scss
diff --git a/x-pack/plugins/security/public/management/users/edit_user/_index.scss b/x-pack/plugins/security/public/management/users/edit_user/_index.scss
new file mode 100644
index 00000000000000..734ba7882ba72c
--- /dev/null
+++ b/x-pack/plugins/security/public/management/users/edit_user/_index.scss
@@ -0,0 +1 @@
+@import './edit_user_page';
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.test.tsx b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.test.tsx
similarity index 70%
rename from x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.test.tsx
rename to x-pack/plugins/security/public/management/users/edit_user/edit_user_page.test.tsx
index 639646ce48e224..543d20bb92afe8 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.test.tsx
+++ b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.test.tsx
@@ -8,13 +8,14 @@ import { act } from '@testing-library/react';
import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers';
import { EditUserPage } from './edit_user_page';
import React from 'react';
-import { securityMock } from '../../../../../../../../plugins/security/public/mocks';
-import { UserAPIClient } from '../../../../lib/api';
-import { User, Role } from '../../../../../common/model';
+import { User, Role } from '../../../../common/model';
import { ReactWrapper } from 'enzyme';
-import { mockAuthenticatedUser } from '../../../../../../../../plugins/security/common/model/authenticated_user.mock';
-jest.mock('ui/kfetch');
+import { coreMock } from '../../../../../../../src/core/public/mocks';
+import { mockAuthenticatedUser } from '../../../../common/model/authenticated_user.mock';
+import { securityMock } from '../../../mocks';
+import { rolesAPIClientMock } from '../../roles/index.mock';
+import { userAPIClientMock } from '../index.mock';
const createUser = (username: string) => {
const user: User = {
@@ -34,14 +35,12 @@ const createUser = (username: string) => {
return user;
};
-const buildClient = () => {
- const apiClient = new UserAPIClient();
+const buildClients = () => {
+ const apiClient = userAPIClientMock.create();
+ apiClient.getUser.mockImplementation(async (username: string) => createUser(username));
- apiClient.getUser = jest
- .fn()
- .mockImplementation(async (username: string) => createUser(username));
-
- apiClient.getRoles = jest.fn().mockImplementation(() => {
+ const rolesAPIClient = rolesAPIClientMock.create();
+ rolesAPIClient.getRoles.mockImplementation(() => {
return Promise.resolve([
{
name: 'role 1',
@@ -64,7 +63,7 @@ const buildClient = () => {
] as Role[]);
});
- return apiClient;
+ return { apiClient, rolesAPIClient };
};
function buildSecuritySetup() {
@@ -85,15 +84,15 @@ function expectMissingSaveButton(wrapper: ReactWrapper) {
describe('EditUserPage', () => {
it('allows reserved users to be viewed', async () => {
- const apiClient = buildClient();
+ const { apiClient, rolesAPIClient } = buildClients();
const securitySetup = buildSecuritySetup();
const wrapper = mountWithIntl(
- path}
- intl={null as any}
+ rolesAPIClient={rolesAPIClient}
+ authc={securitySetup.authc}
+ notifications={coreMock.createStart().notifications}
/>
);
@@ -106,15 +105,15 @@ describe('EditUserPage', () => {
});
it('allows new users to be created', async () => {
- const apiClient = buildClient();
+ const { apiClient, rolesAPIClient } = buildClients();
const securitySetup = buildSecuritySetup();
const wrapper = mountWithIntl(
- path}
- intl={null as any}
+ rolesAPIClient={rolesAPIClient}
+ authc={securitySetup.authc}
+ notifications={coreMock.createStart().notifications}
/>
);
@@ -127,15 +126,15 @@ describe('EditUserPage', () => {
});
it('allows existing users to be edited', async () => {
- const apiClient = buildClient();
+ const { apiClient, rolesAPIClient } = buildClients();
const securitySetup = buildSecuritySetup();
const wrapper = mountWithIntl(
- path}
- intl={null as any}
+ rolesAPIClient={rolesAPIClient}
+ authc={securitySetup.authc}
+ notifications={coreMock.createStart().notifications}
/>
);
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.tsx b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx
similarity index 77%
rename from x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.tsx
rename to x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx
index bbffe07485f8dc..576f3ff9e6008c 100644
--- a/x-pack/legacy/plugins/security/public/views/management/edit_user/components/edit_user_page.tsx
+++ b/x-pack/plugins/security/public/management/users/edit_user/edit_user_page.tsx
@@ -26,22 +26,23 @@ import {
EuiHorizontalRule,
EuiSpacer,
} from '@elastic/eui';
-import { toastNotifications } from 'ui/notify';
-import { FormattedMessage, injectI18n, InjectedIntl } from '@kbn/i18n/react';
-import { SecurityPluginSetup } from '../../../../../../../../plugins/security/public';
-import { UserValidator, UserValidationResult } from '../../../../lib/validate_user';
-import { User, EditUser, Role } from '../../../../../common/model';
-import { USERS_PATH } from '../../../../views/management/management_urls';
-import { ConfirmDeleteUsers } from '../../../../components/management/users';
-import { UserAPIClient } from '../../../../lib/api';
-import { ChangePasswordForm } from '../../../../components/management/change_password_form';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { NotificationsStart } from 'src/core/public';
+import { User, EditUser, Role } from '../../../../common/model';
+import { AuthenticationServiceSetup } from '../../../authentication';
+import { USERS_PATH } from '../../management_urls';
+import { RolesAPIClient } from '../../roles';
+import { ConfirmDeleteUsers, ChangePasswordForm } from '../components';
+import { UserValidator, UserValidationResult } from './validate_user';
+import { UserAPIClient } from '..';
interface Props {
- username: string;
- intl: InjectedIntl;
- changeUrl: (path: string) => void;
- apiClient: UserAPIClient;
- securitySetup: SecurityPluginSetup;
+ username?: string;
+ apiClient: PublicMethodsOf;
+ rolesAPIClient: PublicMethodsOf;
+ authc: AuthenticationServiceSetup;
+ notifications: NotificationsStart;
}
interface State {
@@ -56,7 +57,11 @@ interface State {
formError: UserValidationResult | null;
}
-class EditUserPageUI extends Component {
+function backToUserList() {
+ window.location.hash = USERS_PATH;
+}
+
+export class EditUserPage extends Component {
private validator: UserValidator;
constructor(props: Props) {
@@ -84,7 +89,17 @@ class EditUserPageUI extends Component {
}
public async componentDidMount() {
- const { username, apiClient, securitySetup } = this.props;
+ await this.setCurrentUser();
+ }
+
+ public async componentDidUpdate(prevProps: Props) {
+ if (prevProps.username !== this.props.username) {
+ await this.setCurrentUser();
+ }
+ }
+
+ private async setCurrentUser() {
+ const { username, apiClient, rolesAPIClient, notifications, authc } = this.props;
let { user, currentUser } = this.state;
if (username) {
try {
@@ -93,26 +108,24 @@ class EditUserPageUI extends Component {
password: '',
confirmPassword: '',
};
- currentUser = await securitySetup.authc.getCurrentUser();
+ currentUser = await authc.getCurrentUser();
} catch (err) {
- toastNotifications.addDanger({
- title: this.props.intl.formatMessage({
- id: 'xpack.security.management.users.editUser.errorLoadingUserTitle',
+ notifications.toasts.addDanger({
+ title: i18n.translate('xpack.security.management.users.editUser.errorLoadingUserTitle', {
defaultMessage: 'Error loading user',
}),
text: get(err, 'body.message') || err.message,
});
- return;
+ return backToUserList();
}
}
let roles: Role[] = [];
try {
- roles = await apiClient.getRoles();
+ roles = await rolesAPIClient.getRoles();
} catch (err) {
- toastNotifications.addDanger({
- title: this.props.intl.formatMessage({
- id: 'xpack.security.management.users.editUser.errorLoadingRolesTitle',
+ notifications.toasts.addDanger({
+ title: i18n.translate('xpack.security.management.users.editUser.errorLoadingRolesTitle', {
defaultMessage: 'Error loading roles',
}),
text: get(err, 'body.message') || err.message,
@@ -131,8 +144,7 @@ class EditUserPageUI extends Component {
private handleDelete = (usernames: string[], errors: string[]) => {
if (errors.length === 0) {
- const { changeUrl } = this.props;
- changeUrl(USERS_PATH);
+ backToUserList();
}
};
@@ -148,7 +160,7 @@ class EditUserPageUI extends Component {
this.setState({
formError: null,
});
- const { changeUrl, apiClient } = this.props;
+ const { apiClient } = this.props;
const { user, isNewUser, selectedRoles } = this.state;
const userToSave: EditUser = { ...user };
if (!isNewUser) {
@@ -160,26 +172,23 @@ class EditUserPageUI extends Component {
});
try {
await apiClient.saveUser(userToSave);
- toastNotifications.addSuccess(
- this.props.intl.formatMessage(
+ this.props.notifications.toasts.addSuccess(
+ i18n.translate(
+ 'xpack.security.management.users.editUser.userSuccessfullySavedNotificationMessage',
{
- id:
- 'xpack.security.management.users.editUser.userSuccessfullySavedNotificationMessage',
defaultMessage: 'Saved user {message}',
- },
- { message: user.username }
+ values: { message: user.username },
+ }
)
);
- changeUrl(USERS_PATH);
+
+ backToUserList();
} catch (e) {
- toastNotifications.addDanger(
- this.props.intl.formatMessage(
- {
- id: 'xpack.security.management.users.editUser.savingUserErrorMessage',
- defaultMessage: 'Error saving user: {message}',
- },
- { message: get(e, 'body.message', 'Unknown error') }
- )
+ this.props.notifications.toasts.addDanger(
+ i18n.translate('xpack.security.management.users.editUser.savingUserErrorMessage', {
+ defaultMessage: 'Error saving user: {message}',
+ values: { message: get(e, 'body.message', 'Unknown error') },
+ })
);
}
}
@@ -189,8 +198,7 @@ class EditUserPageUI extends Component {
return (
{
/>
{
{user.username === 'kibana' ? (
@@ -260,6 +268,7 @@ class EditUserPageUI extends Component {
isUserChangingOwnPassword={userIsLoggedInUser}
onChangePassword={this.toggleChangePasswordForm}
apiClient={this.props.apiClient}
+ notifications={this.props.notifications}
/>
);
@@ -352,7 +361,6 @@ class EditUserPageUI extends Component {
};
public render() {
- const { changeUrl, intl } = this.props;
const {
user,
roles,
@@ -417,6 +425,7 @@ class EditUserPageUI extends Component {
usersToDelete={[user.username]}
callback={this.handleDelete}
apiClient={this.props.apiClient}
+ notifications={this.props.notifications}
/>
) : null}
@@ -425,17 +434,16 @@ class EditUserPageUI extends Component {
{...this.validator.validateUsername(this.state.user)}
helpText={
!isNewUser && !reserved
- ? intl.formatMessage({
- id:
- 'xpack.security.management.users.editUser.changingUserNameAfterCreationDescription',
- defaultMessage: `Usernames can't be changed after creation.`,
- })
+ ? i18n.translate(
+ 'xpack.security.management.users.editUser.changingUserNameAfterCreationDescription',
+ { defaultMessage: `Usernames can't be changed after creation.` }
+ )
: null
}
- label={intl.formatMessage({
- id: 'xpack.security.management.users.editUser.usernameFormRowLabel',
- defaultMessage: 'Username',
- })}
+ label={i18n.translate(
+ 'xpack.security.management.users.editUser.usernameFormRowLabel',
+ { defaultMessage: 'Username' }
+ )}
>
{
{reserved ? null : (
{
{
)}
{
@@ -513,7 +521,7 @@ class EditUserPageUI extends Component {
{reserved && (
- changeUrl(USERS_PATH)}>
+
{
- changeUrl(USERS_PATH)}
- >
+
{
);
}
}
-
-export const EditUserPage = injectI18n(EditUserPageUI);
diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_user/components/index.ts b/x-pack/plugins/security/public/management/users/edit_user/index.ts
similarity index 100%
rename from x-pack/legacy/plugins/security/public/views/management/edit_user/components/index.ts
rename to x-pack/plugins/security/public/management/users/edit_user/index.ts
diff --git a/x-pack/legacy/plugins/security/public/lib/validate_user.test.ts b/x-pack/plugins/security/public/management/users/edit_user/validate_user.test.ts
similarity index 98%
rename from x-pack/legacy/plugins/security/public/lib/validate_user.test.ts
rename to x-pack/plugins/security/public/management/users/edit_user/validate_user.test.ts
index 0535248fede88d..6050e1868a759a 100644
--- a/x-pack/legacy/plugins/security/public/lib/validate_user.test.ts
+++ b/x-pack/plugins/security/public/management/users/edit_user/validate_user.test.ts
@@ -5,7 +5,7 @@
*/
import { UserValidator, UserValidationResult } from './validate_user';
-import { User, EditUser } from '../../common/model';
+import { User, EditUser } from '../../../../common/model';
function expectValid(result: UserValidationResult) {
expect(result.isInvalid).toBe(false);
diff --git a/x-pack/legacy/plugins/security/public/lib/validate_user.ts b/x-pack/plugins/security/public/management/users/edit_user/validate_user.ts
similarity index 98%
rename from x-pack/legacy/plugins/security/public/lib/validate_user.ts
rename to x-pack/plugins/security/public/management/users/edit_user/validate_user.ts
index 113aaacdcbf966..5edd96c68bf0dc 100644
--- a/x-pack/legacy/plugins/security/public/lib/validate_user.ts
+++ b/x-pack/plugins/security/public/management/users/edit_user/validate_user.ts
@@ -5,7 +5,7 @@
*/
import { i18n } from '@kbn/i18n';
-import { User, EditUser } from '../../common/model';
+import { User, EditUser } from '../../../../common/model';
interface UserValidatorOptions {
shouldValidate?: boolean;
diff --git a/x-pack/legacy/plugins/security/public/views/management/api_keys_grid/components/index.ts b/x-pack/plugins/security/public/management/users/index.mock.ts
similarity index 80%
rename from x-pack/legacy/plugins/security/public/views/management/api_keys_grid/components/index.ts
rename to x-pack/plugins/security/public/management/users/index.mock.ts
index 9f4d4239d6b4cc..f090f88da500de 100644
--- a/x-pack/legacy/plugins/security/public/views/management/api_keys_grid/components/index.ts
+++ b/x-pack/plugins/security/public/management/users/index.mock.ts
@@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { ApiKeysGridPage } from './api_keys_grid_page';
+export { userAPIClientMock } from './user_api_client.mock';
diff --git a/x-pack/legacy/plugins/security/public/objects/index.ts b/x-pack/plugins/security/public/management/users/index.ts
similarity index 68%
rename from x-pack/legacy/plugins/security/public/objects/index.ts
rename to x-pack/plugins/security/public/management/users/index.ts
index a6238ca879901c..c8b4d41973da6a 100644
--- a/x-pack/legacy/plugins/security/public/objects/index.ts
+++ b/x-pack/plugins/security/public/management/users/index.ts
@@ -4,6 +4,5 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { saveRole, deleteRole } from './lib/roles';
-
-export { getFields } from './lib/get_fields';
+export { UserAPIClient } from './user_api_client';
+export { usersManagementApp } from './users_management_app';
diff --git a/x-pack/plugins/security/public/management/users/user_api_client.mock.ts b/x-pack/plugins/security/public/management/users/user_api_client.mock.ts
new file mode 100644
index 00000000000000..7223f78d57fdc0
--- /dev/null
+++ b/x-pack/plugins/security/public/management/users/user_api_client.mock.ts
@@ -0,0 +1,15 @@
+/*
+ * 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 userAPIClientMock = {
+ create: () => ({
+ getUsers: jest.fn(),
+ getUser: jest.fn(),
+ deleteUser: jest.fn(),
+ saveUser: jest.fn(),
+ changePassword: jest.fn(),
+ }),
+};
diff --git a/x-pack/plugins/security/public/management/users/user_api_client.ts b/x-pack/plugins/security/public/management/users/user_api_client.ts
new file mode 100644
index 00000000000000..61dd09d2c5e3de
--- /dev/null
+++ b/x-pack/plugins/security/public/management/users/user_api_client.ts
@@ -0,0 +1,45 @@
+/*
+ * 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 { HttpStart } from 'src/core/public';
+import { User, EditUser } from '../../../common/model';
+
+const usersUrl = '/internal/security/users';
+
+export class UserAPIClient {
+ constructor(private readonly http: HttpStart) {}
+
+ public async getUsers() {
+ return await this.http.get(usersUrl);
+ }
+
+ public async getUser(username: string) {
+ return await this.http.get(`${usersUrl}/${encodeURIComponent(username)}`);
+ }
+
+ public async deleteUser(username: string) {
+ await this.http.delete(`${usersUrl}/${encodeURIComponent(username)}`);
+ }
+
+ public async saveUser(user: EditUser) {
+ await this.http.post(`${usersUrl}/${encodeURIComponent(user.username)}`, {
+ body: JSON.stringify(user),
+ });
+ }
+
+ public async changePassword(username: string, password: string, currentPassword: string) {
+ const data: Record = {
+ newPassword: password,
+ };
+ if (currentPassword) {
+ data.password = currentPassword;
+ }
+
+ await this.http.post(`${usersUrl}/${encodeURIComponent(username)}/password`, {
+ body: JSON.stringify(data),
+ });
+ }
+}
diff --git a/x-pack/legacy/plugins/security/public/views/management/users_grid/components/index.ts b/x-pack/plugins/security/public/management/users/users_grid/index.ts
similarity index 82%
rename from x-pack/legacy/plugins/security/public/views/management/users_grid/components/index.ts
rename to x-pack/plugins/security/public/management/users/users_grid/index.ts
index 03721f5ce93b1f..90e16248e19c36 100644
--- a/x-pack/legacy/plugins/security/public/views/management/users_grid/components/index.ts
+++ b/x-pack/plugins/security/public/management/users/users_grid/index.ts
@@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-export { UsersListPage } from './users_list_page';
+export { UsersGridPage } from './users_grid_page';
diff --git a/x-pack/legacy/plugins/security/public/views/management/users_grid/components/users_list_page.test.tsx b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.test.tsx
similarity index 63%
rename from x-pack/legacy/plugins/security/public/views/management/users_grid/components/users_list_page.test.tsx
rename to x-pack/plugins/security/public/management/users/users_grid/users_grid_page.test.tsx
index bdc0df9bae67c3..def0649953437d 100644
--- a/x-pack/legacy/plugins/security/public/views/management/users_grid/components/users_list_page.test.tsx
+++ b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.test.tsx
@@ -4,19 +4,18 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { UserAPIClient } from '../../../../lib/api';
-import { User } from '../../../../../common/model';
+import { User } from '../../../../common/model';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
-import { UsersListPage } from './users_list_page';
+import { UsersGridPage } from './users_grid_page';
import React from 'react';
import { ReactWrapper } from 'enzyme';
+import { userAPIClientMock } from '../index.mock';
+import { coreMock } from '../../../../../../../src/core/public/mocks';
-jest.mock('ui/kfetch');
-
-describe('UsersListPage', () => {
+describe('UsersGridPage', () => {
it('renders the list of users', async () => {
- const apiClient = new UserAPIClient();
- apiClient.getUsers = jest.fn().mockImplementation(() => {
+ const apiClientMock = userAPIClientMock.create();
+ apiClientMock.getUsers.mockImplementation(() => {
return Promise.resolve([
{
username: 'foo',
@@ -38,22 +37,27 @@ describe('UsersListPage', () => {
]);
});
- const wrapper = mountWithIntl();
+ const wrapper = mountWithIntl(
+
+ );
await waitForRender(wrapper);
- expect(apiClient.getUsers).toBeCalledTimes(1);
+ expect(apiClientMock.getUsers).toBeCalledTimes(1);
expect(wrapper.find('EuiInMemoryTable')).toHaveLength(1);
expect(wrapper.find('EuiTableRow')).toHaveLength(2);
});
it('renders a forbidden message if user is not authorized', async () => {
- const apiClient = new UserAPIClient();
- apiClient.getUsers = jest.fn().mockImplementation(() => {
- return Promise.reject({ body: { statusCode: 403 } });
- });
+ const apiClient = userAPIClientMock.create();
+ apiClient.getUsers.mockRejectedValue({ body: { statusCode: 403 } });
- const wrapper = mountWithIntl();
+ const wrapper = mountWithIntl(
+
+ );
await waitForRender(wrapper);
diff --git a/x-pack/legacy/plugins/security/public/views/management/users_grid/components/users_list_page.tsx b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx
similarity index 85%
rename from x-pack/legacy/plugins/security/public/views/management/users_grid/components/users_list_page.tsx
rename to x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx
index df8522e5f32f91..fa15c3388fcc99 100644
--- a/x-pack/legacy/plugins/security/public/views/management/users_grid/components/users_list_page.tsx
+++ b/x-pack/plugins/security/public/management/users/users_grid/users_grid_page.tsx
@@ -19,15 +19,16 @@ import {
EuiEmptyPrompt,
EuiBasicTableColumn,
} from '@elastic/eui';
-import { toastNotifications } from 'ui/notify';
-import { injectI18n, FormattedMessage, InjectedIntl } from '@kbn/i18n/react';
-import { ConfirmDeleteUsers } from '../../../../components/management/users';
-import { User } from '../../../../../common/model';
-import { UserAPIClient } from '../../../../lib/api';
+import { i18n } from '@kbn/i18n';
+import { FormattedMessage } from '@kbn/i18n/react';
+import { NotificationsStart } from 'src/core/public';
+import { User } from '../../../../common/model';
+import { ConfirmDeleteUsers } from '../components';
+import { UserAPIClient } from '..';
interface Props {
- intl: InjectedIntl;
- apiClient: UserAPIClient;
+ apiClient: PublicMethodsOf;
+ notifications: NotificationsStart;
}
interface State {
@@ -38,7 +39,7 @@ interface State {
filter: string;
}
-class UsersListPageUI extends Component {
+export class UsersGridPage extends Component {
constructor(props: Props) {
super(props);
this.state = {
@@ -56,7 +57,6 @@ class UsersListPageUI extends Component {
public render() {
const { users, filter, permissionDenied, showDeleteConfirmation, selection } = this.state;
- const { intl } = this.props;
if (permissionDenied) {
return (
@@ -88,8 +88,7 @@ class UsersListPageUI extends Component {
const columns: Array> = [
{
field: 'full_name',
- name: intl.formatMessage({
- id: 'xpack.security.management.users.fullNameColumnName',
+ name: i18n.translate('xpack.security.management.users.fullNameColumnName', {
defaultMessage: 'Full Name',
}),
sortable: true,
@@ -100,8 +99,7 @@ class UsersListPageUI extends Component {
},
{
field: 'username',
- name: intl.formatMessage({
- id: 'xpack.security.management.users.userNameColumnName',
+ name: i18n.translate('xpack.security.management.users.userNameColumnName', {
defaultMessage: 'User Name',
}),
sortable: true,
@@ -114,8 +112,7 @@ class UsersListPageUI extends Component {
},
{
field: 'email',
- name: intl.formatMessage({
- id: 'xpack.security.management.users.emailAddressColumnName',
+ name: i18n.translate('xpack.security.management.users.emailAddressColumnName', {
defaultMessage: 'Email Address',
}),
sortable: true,
@@ -126,8 +123,7 @@ class UsersListPageUI extends Component {
},
{
field: 'roles',
- name: intl.formatMessage({
- id: 'xpack.security.management.users.rolesColumnName',
+ name: i18n.translate('xpack.security.management.users.rolesColumnName', {
defaultMessage: 'Roles',
}),
render: (rolenames: string[]) => {
@@ -144,15 +140,13 @@ class UsersListPageUI extends Component {
},
{
field: 'metadata',
- name: intl.formatMessage({
- id: 'xpack.security.management.users.reservedColumnName',
+ name: i18n.translate('xpack.security.management.users.reservedColumnName', {
defaultMessage: 'Reserved',
}),
sortable: ({ metadata }: User) => Boolean(metadata && metadata._reserved),
width: '100px',
align: 'right',
- description: intl.formatMessage({
- id: 'xpack.security.management.users.reservedColumnDescription',
+ description: i18n.translate('xpack.security.management.users.reservedColumnDescription', {
defaultMessage:
'Reserved users are built-in and cannot be removed. Only the password can be changed.',
}),
@@ -233,6 +227,7 @@ class UsersListPageUI extends Component {
usersToDelete={selection.map(user => user.username)}
callback={this.handleDelete}
apiClient={this.props.apiClient}
+ notifications={this.props.notifications}
/>
) : null}
@@ -275,14 +270,11 @@ class UsersListPageUI extends Component {
if (e.body.statusCode === 403) {
this.setState({ permissionDenied: true });
} else {
- toastNotifications.addDanger(
- this.props.intl.formatMessage(
- {
- id: 'xpack.security.management.users.fetchingUsersErrorMessage',
- defaultMessage: 'Error fetching users: {message}',
- },
- { message: e.body.message }
- )
+ this.props.notifications.toasts.addDanger(
+ i18n.translate('xpack.security.management.users.fetchingUsersErrorMessage', {
+ defaultMessage: 'Error fetching users: {message}',
+ values: { message: e.body.message },
+ })
);
}
}
@@ -315,5 +307,3 @@ class UsersListPageUI extends Component {
this.setState({ showDeleteConfirmation: false });
};
}
-
-export const UsersListPage = injectI18n(UsersListPageUI);
diff --git a/x-pack/plugins/security/public/management/users/users_management_app.test.tsx b/x-pack/plugins/security/public/management/users/users_management_app.test.tsx
new file mode 100644
index 00000000000000..48ffcfc550a849
--- /dev/null
+++ b/x-pack/plugins/security/public/management/users/users_management_app.test.tsx
@@ -0,0 +1,131 @@
+/*
+ * 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('./users_grid', () => ({
+ UsersGridPage: (props: any) => `Users Page: ${JSON.stringify(props)}`,
+}));
+
+jest.mock('./edit_user', () => ({
+ EditUserPage: (props: any) => `User Edit Page: ${JSON.stringify(props)}`,
+}));
+
+import { usersManagementApp } from './users_management_app';
+
+import { coreMock } from '../../../../../../src/core/public/mocks';
+import { securityMock } from '../../mocks';
+
+async function mountApp(basePath: string) {
+ const container = document.createElement('div');
+ const setBreadcrumbs = jest.fn();
+
+ const unmount = await usersManagementApp
+ .create({
+ authc: securityMock.createSetup().authc,
+ getStartServices: coreMock.createSetup().getStartServices as any,
+ })
+ .mount({ basePath, element: container, setBreadcrumbs });
+
+ return { unmount, container, setBreadcrumbs };
+}
+
+describe('usersManagementApp', () => {
+ it('create() returns proper management app descriptor', () => {
+ expect(
+ usersManagementApp.create({
+ authc: securityMock.createSetup().authc,
+ getStartServices: coreMock.createSetup().getStartServices as any,
+ })
+ ).toMatchInlineSnapshot(`
+ Object {
+ "id": "users",
+ "mount": [Function],
+ "order": 10,
+ "title": "Users",
+ }
+ `);
+ });
+
+ it('mount() works for the `grid` page', async () => {
+ const basePath = '/some-base-path/users';
+ window.location.hash = basePath;
+
+ const { setBreadcrumbs, container, unmount } = await mountApp(basePath);
+
+ expect(setBreadcrumbs).toHaveBeenCalledTimes(1);
+ expect(setBreadcrumbs).toHaveBeenCalledWith([{ href: `#${basePath}`, text: 'Users' }]);
+ expect(container).toMatchInlineSnapshot(`
+
+ Users Page: {"notifications":{"toasts":{}},"apiClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}}}
+
+ `);
+
+ unmount();
+
+ expect(container).toMatchInlineSnapshot(``);
+ });
+
+ it('mount() works for the `create user` page', async () => {
+ const basePath = '/some-base-path/users';
+ window.location.hash = `${basePath}/edit`;
+
+ const { setBreadcrumbs, container, unmount } = await mountApp(basePath);
+
+ expect(setBreadcrumbs).toHaveBeenCalledTimes(1);
+ expect(setBreadcrumbs).toHaveBeenCalledWith([
+ { href: `#${basePath}`, text: 'Users' },
+ { text: 'Create' },
+ ]);
+ expect(container).toMatchInlineSnapshot(`
+
+ User Edit Page: {"authc":{},"apiClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"rolesAPIClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"notifications":{"toasts":{}}}
+
+ `);
+
+ unmount();
+
+ expect(container).toMatchInlineSnapshot(``);
+ });
+
+ it('mount() works for the `edit user` page', async () => {
+ const basePath = '/some-base-path/users';
+ const userName = 'someUserName';
+ window.location.hash = `${basePath}/edit/${userName}`;
+
+ const { setBreadcrumbs, container, unmount } = await mountApp(basePath);
+
+ expect(setBreadcrumbs).toHaveBeenCalledTimes(1);
+ expect(setBreadcrumbs).toHaveBeenCalledWith([
+ { href: `#${basePath}`, text: 'Users' },
+ { href: `#/some-base-path/users/edit/${userName}`, text: userName },
+ ]);
+ expect(container).toMatchInlineSnapshot(`
+
+ User Edit Page: {"authc":{},"apiClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"rolesAPIClient":{"http":{"basePath":{"basePath":""},"anonymousPaths":{}}},"notifications":{"toasts":{}},"username":"someUserName"}
+
+ `);
+
+ unmount();
+
+ expect(container).toMatchInlineSnapshot(``);
+ });
+
+ it('mount() properly encodes user name in `edit user` page link in breadcrumbs', async () => {
+ const basePath = '/some-base-path/users';
+ const username = 'some 安全性 user';
+ window.location.hash = `${basePath}/edit/${username}`;
+
+ const { setBreadcrumbs } = await mountApp(basePath);
+
+ expect(setBreadcrumbs).toHaveBeenCalledTimes(1);
+ expect(setBreadcrumbs).toHaveBeenCalledWith([
+ { href: `#${basePath}`, text: 'Users' },
+ {
+ href: '#/some-base-path/users/edit/some%20%E5%AE%89%E5%85%A8%E6%80%A7%20user',
+ text: username,
+ },
+ ]);
+ });
+});
diff --git a/x-pack/plugins/security/public/management/users/users_management_app.tsx b/x-pack/plugins/security/public/management/users/users_management_app.tsx
new file mode 100644
index 00000000000000..9aebb396ce9a92
--- /dev/null
+++ b/x-pack/plugins/security/public/management/users/users_management_app.tsx
@@ -0,0 +1,94 @@
+/*
+ * 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 { render, unmountComponentAtNode } from 'react-dom';
+import { HashRouter as Router, Route, Switch, useParams } from 'react-router-dom';
+import { i18n } from '@kbn/i18n';
+import { CoreSetup } from 'src/core/public';
+import { RegisterManagementAppArgs } from '../../../../../../src/plugins/management/public';
+import { AuthenticationServiceSetup } from '../../authentication';
+import { PluginStartDependencies } from '../../plugin';
+import { RolesAPIClient } from '../roles';
+import { UserAPIClient } from './user_api_client';
+import { UsersGridPage } from './users_grid';
+import { EditUserPage } from './edit_user';
+
+interface CreateParams {
+ authc: AuthenticationServiceSetup;
+ getStartServices: CoreSetup['getStartServices'];
+}
+
+export const usersManagementApp = Object.freeze({
+ id: 'users',
+ create({ authc, getStartServices }: CreateParams) {
+ return {
+ id: this.id,
+ order: 10,
+ title: i18n.translate('xpack.security.management.usersTitle', { defaultMessage: 'Users' }),
+ async mount({ basePath, element, setBreadcrumbs }) {
+ const [{ http, notifications, i18n: i18nStart }] = await getStartServices();
+ const usersBreadcrumbs = [
+ {
+ text: i18n.translate('xpack.security.users.breadcrumb', { defaultMessage: 'Users' }),
+ href: `#${basePath}`,
+ },
+ ];
+
+ const userAPIClient = new UserAPIClient(http);
+ const UsersGridPageWithBreadcrumbs = () => {
+ setBreadcrumbs(usersBreadcrumbs);
+ return ;
+ };
+
+ const EditUserPageWithBreadcrumbs = () => {
+ const { username } = useParams<{ username?: string }>();
+
+ setBreadcrumbs([
+ ...usersBreadcrumbs,
+ username
+ ? { text: username, href: `#${basePath}/edit/${encodeURIComponent(username)}` }
+ : {
+ text: i18n.translate('xpack.security.users.createBreadcrumb', {
+ defaultMessage: 'Create',
+ }),
+ },
+ ]);
+
+ return (
+
+ );
+ };
+
+ render(
+
+
+
+
+
+
+
+
+
+
+
+ ,
+ element
+ );
+
+ return () => {
+ unmountComponentAtNode(element);
+ };
+ },
+ } as RegisterManagementAppArgs;
+ },
+});
diff --git a/x-pack/plugins/security/public/plugin.ts b/x-pack/plugins/security/public/plugin.ts
deleted file mode 100644
index 50e0b838c750fc..00000000000000
--- a/x-pack/plugins/security/public/plugin.ts
+++ /dev/null
@@ -1,74 +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 { Plugin, CoreSetup, CoreStart } from 'src/core/public';
-import { LicensingPluginSetup } from '../../licensing/public';
-import {
- SessionExpired,
- SessionTimeout,
- ISessionTimeout,
- SessionTimeoutHttpInterceptor,
- UnauthorizedResponseHttpInterceptor,
-} from './session';
-import { SecurityLicenseService } from '../common/licensing';
-import { SecurityNavControlService } from './nav_control';
-import { AuthenticationService } from './authentication';
-
-export interface PluginSetupDependencies {
- licensing: LicensingPluginSetup;
-}
-
-export class SecurityPlugin implements Plugin {
- private sessionTimeout!: ISessionTimeout;
-
- private navControlService!: SecurityNavControlService;
-
- private securityLicenseService!: SecurityLicenseService;
-
- public setup(core: CoreSetup, { licensing }: PluginSetupDependencies) {
- const { http, notifications, injectedMetadata } = core;
- const { basePath, anonymousPaths } = http;
- anonymousPaths.register('/login');
- anonymousPaths.register('/logout');
- anonymousPaths.register('/logged_out');
-
- const tenant = `${injectedMetadata.getInjectedVar('session.tenant', '')}`;
- const sessionExpired = new SessionExpired(basePath, tenant);
- http.intercept(new UnauthorizedResponseHttpInterceptor(sessionExpired, anonymousPaths));
- this.sessionTimeout = new SessionTimeout(notifications, sessionExpired, http, tenant);
- http.intercept(new SessionTimeoutHttpInterceptor(this.sessionTimeout, anonymousPaths));
-
- this.navControlService = new SecurityNavControlService();
- this.securityLicenseService = new SecurityLicenseService();
- const { license } = this.securityLicenseService.setup({ license$: licensing.license$ });
-
- const authc = new AuthenticationService().setup({ http: core.http });
-
- this.navControlService.setup({
- securityLicense: license,
- authc,
- });
-
- return {
- authc,
- sessionTimeout: this.sessionTimeout,
- };
- }
-
- public start(core: CoreStart) {
- this.sessionTimeout.start();
- this.navControlService.start({ core });
- }
-
- public stop() {
- this.sessionTimeout.stop();
- this.navControlService.stop();
- this.securityLicenseService.stop();
- }
-}
-
-export type SecurityPluginSetup = ReturnType;
-export type SecurityPluginStart = ReturnType;
diff --git a/x-pack/plugins/security/public/plugin.tsx b/x-pack/plugins/security/public/plugin.tsx
new file mode 100644
index 00000000000000..394e23cbbf646c
--- /dev/null
+++ b/x-pack/plugins/security/public/plugin.tsx
@@ -0,0 +1,147 @@
+/*
+ * 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 { Plugin, CoreSetup, CoreStart } from 'src/core/public';
+import { i18n } from '@kbn/i18n';
+import React from 'react';
+import { DataPublicPluginStart } from '../../../../src/plugins/data/public';
+import {
+ FeatureCatalogueCategory,
+ HomePublicPluginSetup,
+} from '../../../../src/plugins/home/public';
+import { LicensingPluginSetup } from '../../licensing/public';
+import { ManagementSetup, ManagementStart } from '../../../../src/plugins/management/public';
+import {
+ SessionExpired,
+ SessionTimeout,
+ ISessionTimeout,
+ SessionTimeoutHttpInterceptor,
+ UnauthorizedResponseHttpInterceptor,
+} from './session';
+import { SecurityLicenseService } from '../common/licensing';
+import { SecurityNavControlService } from './nav_control';
+import { AccountManagementPage } from './account_management';
+import { AuthenticationService, AuthenticationServiceSetup } from './authentication';
+import { ManagementService, UserAPIClient } from './management';
+
+export interface PluginSetupDependencies {
+ licensing: LicensingPluginSetup;
+ home?: HomePublicPluginSetup;
+ management?: ManagementSetup;
+}
+
+export interface PluginStartDependencies {
+ data: DataPublicPluginStart;
+ management?: ManagementStart;
+}
+
+export class SecurityPlugin
+ implements
+ Plugin<
+ SecurityPluginSetup,
+ SecurityPluginStart,
+ PluginSetupDependencies,
+ PluginStartDependencies
+ > {
+ private sessionTimeout!: ISessionTimeout;
+ private readonly navControlService = new SecurityNavControlService();
+ private readonly securityLicenseService = new SecurityLicenseService();
+ private readonly managementService = new ManagementService();
+ private authc!: AuthenticationServiceSetup;
+
+ public setup(
+ core: CoreSetup,
+ { home, licensing, management }: PluginSetupDependencies
+ ) {
+ const { http, notifications, injectedMetadata } = core;
+ const { basePath, anonymousPaths } = http;
+ anonymousPaths.register('/login');
+ anonymousPaths.register('/logout');
+ anonymousPaths.register('/logged_out');
+
+ const tenant = `${injectedMetadata.getInjectedVar('session.tenant', '')}`;
+ const sessionExpired = new SessionExpired(basePath, tenant);
+ http.intercept(new UnauthorizedResponseHttpInterceptor(sessionExpired, anonymousPaths));
+ this.sessionTimeout = new SessionTimeout(notifications, sessionExpired, http, tenant);
+ http.intercept(new SessionTimeoutHttpInterceptor(this.sessionTimeout, anonymousPaths));
+
+ const { license } = this.securityLicenseService.setup({ license$: licensing.license$ });
+
+ this.authc = new AuthenticationService().setup({ http: core.http });
+
+ this.navControlService.setup({
+ securityLicense: license,
+ authc: this.authc,
+ });
+
+ if (management) {
+ this.managementService.setup({
+ license,
+ management,
+ authc: this.authc,
+ fatalErrors: core.fatalErrors,
+ getStartServices: core.getStartServices,
+ });
+ }
+
+ if (management && home) {
+ home.featureCatalogue.register({
+ id: 'security',
+ title: i18n.translate('xpack.security.registerFeature.securitySettingsTitle', {
+ defaultMessage: 'Security Settings',
+ }),
+ description: i18n.translate('xpack.security.registerFeature.securitySettingsDescription', {
+ defaultMessage:
+ 'Protect your data and easily manage who has access to what with users and roles.',
+ }),
+ icon: 'securityApp',
+ path: '/app/kibana#/management/security/users',
+ showOnHomePage: true,
+ category: FeatureCatalogueCategory.ADMIN,
+ });
+ }
+
+ return {
+ authc: this.authc,
+ sessionTimeout: this.sessionTimeout,
+ };
+ }
+
+ public start(core: CoreStart, { data, management }: PluginStartDependencies) {
+ this.sessionTimeout.start();
+ this.navControlService.start({ core });
+
+ if (management) {
+ this.managementService.start({ management });
+ }
+
+ return {
+ __legacyCompat: {
+ account_management: {
+ AccountManagementPage: () => (
+
+
+
+ ),
+ },
+ },
+ };
+ }
+
+ public stop() {
+ this.sessionTimeout.stop();
+ this.navControlService.stop();
+ this.securityLicenseService.stop();
+ this.managementService.stop();
+ }
+}
+
+export type SecurityPluginSetup = ReturnType;
+export type SecurityPluginStart = ReturnType;
diff --git a/x-pack/plugins/security/server/plugin.test.ts b/x-pack/plugins/security/server/plugin.test.ts
index 5e32a0e90198a6..56aad4ece3e958 100644
--- a/x-pack/plugins/security/server/plugin.test.ts
+++ b/x-pack/plugins/security/server/plugin.test.ts
@@ -6,7 +6,7 @@
import { of } from 'rxjs';
import { ByteSizeValue } from '@kbn/config-schema';
-import { ICustomClusterClient, CoreSetup } from '../../../../src/core/server';
+import { ICustomClusterClient } from '../../../../src/core/server';
import { elasticsearchClientPlugin } from './elasticsearch_client_plugin';
import { Plugin, PluginSetupDependencies } from './plugin';
@@ -14,7 +14,7 @@ import { coreMock, elasticsearchServiceMock } from '../../../../src/core/server/
describe('Security Plugin', () => {
let plugin: Plugin;
- let mockCoreSetup: MockedKeys;
+ let mockCoreSetup: ReturnType;
let mockClusterClient: jest.Mocked;
let mockDependencies: PluginSetupDependencies;
beforeEach(() => {
diff --git a/x-pack/plugins/security/server/routes/role_mapping/get.ts b/x-pack/plugins/security/server/routes/role_mapping/get.ts
index 9cd5cf83092e18..def6fabc0e3222 100644
--- a/x-pack/plugins/security/server/routes/role_mapping/get.ts
+++ b/x-pack/plugins/security/server/routes/role_mapping/get.ts
@@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { schema } from '@kbn/config-schema';
-import { RoleMapping } from '../../../../../legacy/plugins/security/common/model';
+import { RoleMapping } from '../../../common/model';
import { createLicensedRouteHandler } from '../licensed_route_handler';
import { wrapError } from '../../errors';
import { RouteDefinitionParams } from '..';
diff --git a/x-pack/plugins/spaces/common/index.ts b/x-pack/plugins/spaces/common/index.ts
index 65baa1bd991022..c1f0f8bd3ece41 100644
--- a/x-pack/plugins/spaces/common/index.ts
+++ b/x-pack/plugins/spaces/common/index.ts
@@ -5,5 +5,5 @@
*/
export { isReservedSpace } from './is_reserved_space';
-export { MAX_SPACE_INITIALS } from './constants';
+export { MAX_SPACE_INITIALS, SPACE_SEARCH_COUNT_THRESHOLD } from './constants';
export { addSpaceIdToPath, getSpaceIdFromPath } from './lib/spaces_url_parser';
diff --git a/x-pack/plugins/task_manager/server/task_manager.ts b/x-pack/plugins/task_manager/server/task_manager.ts
index 93e98f33a30b04..da9640fa3e0718 100644
--- a/x-pack/plugins/task_manager/server/task_manager.ts
+++ b/x-pack/plugins/task_manager/server/task_manager.ts
@@ -401,7 +401,7 @@ export async function claimAvailableTasks(
} else {
performance.mark('claimAvailableTasks.noAvailableWorkers');
logger.info(
- `[Task Ownership]: Task Manager has skipped Claiming Ownership of available tasks at it has ran out Available Workers. If this happens often, consider adjusting the "xpack.task_manager.max_workers" configuration.`
+ `[Task Ownership]: Task Manager has skipped Claiming Ownership of available tasks at it has ran out Available Workers.`
);
}
return [];
diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json
index ce3edbbb598280..c3e46a9c04e1cc 100644
--- a/x-pack/plugins/translations/translations/ja-JP.json
+++ b/x-pack/plugins/translations/translations/ja-JP.json
@@ -10595,17 +10595,6 @@
"xpack.security.management.apiKeys.table.userFilterLabel": "ユーザー",
"xpack.security.management.apiKeys.table.userNameColumnName": "ユーザー",
"xpack.security.management.apiKeysTitle": "API キー",
- "xpack.security.management.changePasswordForm.cancelButtonLabel": "キャンセル",
- "xpack.security.management.changePasswordForm.changePasswordLinkLabel": "パスワードを変更",
- "xpack.security.management.changePasswordForm.confirmPasswordLabel": "パスワードの確認",
- "xpack.security.management.changePasswordForm.currentPasswordLabel": "現在のパスワード",
- "xpack.security.management.changePasswordForm.incorrectPasswordDescription": "入力された現在のパスワードが正しくありません。",
- "xpack.security.management.changePasswordForm.newPasswordLabel": "新しいパスワード",
- "xpack.security.management.changePasswordForm.passwordDontMatchDescription": "パスワードが一致しません",
- "xpack.security.management.changePasswordForm.passwordLabel": "パスワード",
- "xpack.security.management.changePasswordForm.passwordLengthDescription": "パスワードは最低 6 文字必要です",
- "xpack.security.management.changePasswordForm.saveChangesButtonLabel": "変更を保存",
- "xpack.security.management.changePasswordForm.updateAndRestartKibanaDescription": "Kibana ユーザーのパスワードを変更後、kibana.yml ファイルを更新し Kibana を再起動する必要があります。",
"xpack.security.management.editRole.cancelButtonLabel": "キャンセル",
"xpack.security.management.editRole.changeAllPrivilegesLink": "(すべて変更)",
"xpack.security.management.editRole.collapsiblePanel.hideLinkText": "非表示",
@@ -10730,10 +10719,6 @@
"xpack.security.management.editRolespacePrivilegeForm.createPrivilegeButton": "スペース権限を作成",
"xpack.security.management.editRolespacePrivilegeForm.updateGlobalPrivilegeButton": "グローバル特権を更新",
"xpack.security.management.editRolespacePrivilegeForm.updatePrivilegeButton": "スペース権限を更新",
- "xpack.security.management.passwordForm.confirmPasswordLabel": "パスワードの確認",
- "xpack.security.management.passwordForm.passwordDontMatchDescription": "パスワードが一致しません",
- "xpack.security.management.passwordForm.passwordLabel": "パスワード",
- "xpack.security.management.passwordForm.passwordLengthDescription": "パスワードは最低 6 文字必要です",
"xpack.security.management.roles.actionsColumnName": "アクション",
"xpack.security.management.roles.cloneRoleActionName": "{roleName} を複製",
"xpack.security.management.roles.confirmDelete.cancelButtonLabel": "キャンセル",
diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json
index dc72e83ebe3c30..c40b8c8d0393c8 100644
--- a/x-pack/plugins/translations/translations/zh-CN.json
+++ b/x-pack/plugins/translations/translations/zh-CN.json
@@ -10594,17 +10594,6 @@
"xpack.security.management.apiKeys.table.userFilterLabel": "用户",
"xpack.security.management.apiKeys.table.userNameColumnName": "用户",
"xpack.security.management.apiKeysTitle": "API 密钥",
- "xpack.security.management.changePasswordForm.cancelButtonLabel": "取消",
- "xpack.security.management.changePasswordForm.changePasswordLinkLabel": "更改密码",
- "xpack.security.management.changePasswordForm.confirmPasswordLabel": "确认密码",
- "xpack.security.management.changePasswordForm.currentPasswordLabel": "当前密码",
- "xpack.security.management.changePasswordForm.incorrectPasswordDescription": "您输入的当前密码不正确。",
- "xpack.security.management.changePasswordForm.newPasswordLabel": "新密码",
- "xpack.security.management.changePasswordForm.passwordDontMatchDescription": "密码不匹配",
- "xpack.security.management.changePasswordForm.passwordLabel": "密码",
- "xpack.security.management.changePasswordForm.passwordLengthDescription": "密码长度必须至少为 6 个字符",
- "xpack.security.management.changePasswordForm.saveChangesButtonLabel": "保存更改",
- "xpack.security.management.changePasswordForm.updateAndRestartKibanaDescription": "更改 Kibana 用户的密码后,必须更新 kibana.yml 文件并重新启动 Kibana",
"xpack.security.management.editRole.cancelButtonLabel": "取消",
"xpack.security.management.editRole.changeAllPrivilegesLink": "(全部更改)",
"xpack.security.management.editRole.collapsiblePanel.hideLinkText": "隐藏",
@@ -10729,10 +10718,6 @@
"xpack.security.management.editRolespacePrivilegeForm.createPrivilegeButton": "创建工作区权限",
"xpack.security.management.editRolespacePrivilegeForm.updateGlobalPrivilegeButton": "更新全局权限",
"xpack.security.management.editRolespacePrivilegeForm.updatePrivilegeButton": "更新工作区权限",
- "xpack.security.management.passwordForm.confirmPasswordLabel": "确认密码",
- "xpack.security.management.passwordForm.passwordDontMatchDescription": "密码不匹配",
- "xpack.security.management.passwordForm.passwordLabel": "密码",
- "xpack.security.management.passwordForm.passwordLengthDescription": "密码长度必须至少为 6 个字符",
"xpack.security.management.roles.actionsColumnName": "鎿嶄綔",
"xpack.security.management.roles.cloneRoleActionName": "克隆 {roleName}",
"xpack.security.management.roles.confirmDelete.cancelButtonLabel": "取消",
diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/advanced_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/advanced_job.ts
index 386914b735554c..acb92b270c4a12 100644
--- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/advanced_job.ts
+++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/advanced_job.ts
@@ -194,8 +194,8 @@ export default function({ getService }: FtrProviderContext) {
},
modelSizeStats: {
result_type: 'model_size_stats',
- model_bytes_exceeded: '0',
- model_bytes_memory_limit: '10485760',
+ model_bytes_exceeded: '0.0 B',
+ model_bytes_memory_limit: '10.0 MB',
total_by_field_count: '37',
total_over_field_count: '92',
total_partition_field_count: '8',
@@ -261,8 +261,8 @@ export default function({ getService }: FtrProviderContext) {
},
modelSizeStats: {
result_type: 'model_size_stats',
- model_bytes_exceeded: '0',
- model_bytes_memory_limit: '104857600',
+ model_bytes_exceeded: '0.0 B',
+ model_bytes_memory_limit: '100.0 MB',
total_by_field_count: '994',
total_over_field_count: '0',
total_partition_field_count: '2',
diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/multi_metric_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/multi_metric_job.ts
index d41d96e40e2bee..6a12a28e8ac490 100644
--- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/multi_metric_job.ts
+++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/multi_metric_job.ts
@@ -60,8 +60,8 @@ export default function({ getService }: FtrProviderContext) {
return {
job_id: expectedJobId,
result_type: 'model_size_stats',
- model_bytes_exceeded: '0',
- model_bytes_memory_limit: '20971520',
+ model_bytes_exceeded: '0.0 B',
+ model_bytes_memory_limit: '20.0 MB',
total_by_field_count: '59',
total_over_field_count: '0',
total_partition_field_count: '58',
diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/population_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/population_job.ts
index 296af3179ce3ee..6593dd10928b4b 100644
--- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/population_job.ts
+++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/population_job.ts
@@ -74,8 +74,8 @@ export default function({ getService }: FtrProviderContext) {
return {
job_id: expectedJobId,
result_type: 'model_size_stats',
- model_bytes_exceeded: '0',
- model_bytes_memory_limit: '8388608',
+ model_bytes_exceeded: '0.0 B',
+ model_bytes_memory_limit: '8.0 MB',
total_by_field_count: '25',
total_over_field_count: '92',
total_partition_field_count: '3',
diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/saved_search_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/saved_search_job.ts
index 7d989bc6244b81..348910a2a8f84a 100644
--- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/saved_search_job.ts
+++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/saved_search_job.ts
@@ -53,8 +53,8 @@ export default function({ getService }: FtrProviderContext) {
},
modelSizeStats: {
result_type: 'model_size_stats',
- model_bytes_exceeded: '0',
- model_bytes_memory_limit: '20971520',
+ model_bytes_exceeded: '0.0 B',
+ model_bytes_memory_limit: '20.0 MB',
total_by_field_count: '3',
total_over_field_count: '0',
total_partition_field_count: '2',
@@ -104,8 +104,8 @@ export default function({ getService }: FtrProviderContext) {
},
modelSizeStats: {
result_type: 'model_size_stats',
- model_bytes_exceeded: '0',
- model_bytes_memory_limit: '20971520',
+ model_bytes_exceeded: '0.0 B',
+ model_bytes_memory_limit: '20.0 MB',
total_by_field_count: '7',
total_over_field_count: '0',
total_partition_field_count: '6',
@@ -155,8 +155,8 @@ export default function({ getService }: FtrProviderContext) {
},
modelSizeStats: {
result_type: 'model_size_stats',
- model_bytes_exceeded: '0',
- model_bytes_memory_limit: '20971520',
+ model_bytes_exceeded: '0.0 B',
+ model_bytes_memory_limit: '20.0 MB',
total_by_field_count: '7',
total_over_field_count: '0',
total_partition_field_count: '6',
@@ -207,8 +207,8 @@ export default function({ getService }: FtrProviderContext) {
},
modelSizeStats: {
result_type: 'model_size_stats',
- model_bytes_exceeded: '0',
- model_bytes_memory_limit: '20971520',
+ model_bytes_exceeded: '0.0 B',
+ model_bytes_memory_limit: '20.0 MB',
total_by_field_count: '3',
total_over_field_count: '0',
total_partition_field_count: '2',
@@ -258,8 +258,8 @@ export default function({ getService }: FtrProviderContext) {
},
modelSizeStats: {
result_type: 'model_size_stats',
- model_bytes_exceeded: '0',
- model_bytes_memory_limit: '20971520',
+ model_bytes_exceeded: '0.0 B',
+ model_bytes_memory_limit: '20.0 MB',
total_by_field_count: '3',
total_over_field_count: '0',
total_partition_field_count: '2',
diff --git a/x-pack/test/functional/apps/machine_learning/anomaly_detection/single_metric_job.ts b/x-pack/test/functional/apps/machine_learning/anomaly_detection/single_metric_job.ts
index f6cd7b40bc7b1d..13cac36d99a1ba 100644
--- a/x-pack/test/functional/apps/machine_learning/anomaly_detection/single_metric_job.ts
+++ b/x-pack/test/functional/apps/machine_learning/anomaly_detection/single_metric_job.ts
@@ -59,8 +59,8 @@ export default function({ getService }: FtrProviderContext) {
return {
job_id: expectedJobId,
result_type: 'model_size_stats',
- model_bytes_exceeded: '0',
- model_bytes_memory_limit: '15728640',
+ model_bytes_exceeded: '0.0 B',
+ model_bytes_memory_limit: '15.0 MB',
total_by_field_count: '3',
total_over_field_count: '0',
total_partition_field_count: '2',
diff --git a/x-pack/test/functional/apps/security/management.js b/x-pack/test/functional/apps/security/management.js
index 45a35029ffba2e..8ab84126b2b30a 100644
--- a/x-pack/test/functional/apps/security/management.js
+++ b/x-pack/test/functional/apps/security/management.js
@@ -11,7 +11,7 @@ import {
ROLES_PATH,
EDIT_ROLES_PATH,
CLONE_ROLES_PATH,
-} from '../../../../legacy/plugins/security/public/views/management/management_urls';
+} from '../../../../plugins/security/public/management/management_urls';
export default function({ getService, getPageObjects }) {
const kibanaServer = getService('kibanaServer');
diff --git a/x-pack/test/functional/apps/security/role_mappings.ts b/x-pack/test/functional/apps/security/role_mappings.ts
index 5fed56ee79e3dd..a1517e1934a286 100644
--- a/x-pack/test/functional/apps/security/role_mappings.ts
+++ b/x-pack/test/functional/apps/security/role_mappings.ts
@@ -93,7 +93,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
const url = parse(await browser.getCurrentUrl());
- expect(url.hash).to.eql('#/management/security/role_mappings?_g=()');
+ expect(url.hash).to.eql('#/management/security/role_mappings');
});
describe('with role mappings', () => {
diff --git a/x-pack/test/functional/apps/uptime/overview.ts b/x-pack/test/functional/apps/uptime/overview.ts
index ba701da6e517dd..2ef6a381a6a30e 100644
--- a/x-pack/test/functional/apps/uptime/overview.ts
+++ b/x-pack/test/functional/apps/uptime/overview.ts
@@ -50,13 +50,11 @@ export default ({ getPageObjects }: FtrProviderContext) => {
]);
});
- // flakey see https://github.com/elastic/kibana/issues/54527
- it.skip('pagination is cleared when filter criteria changes', async () => {
+ it('pagination is cleared when filter criteria changes', async () => {
await pageObjects.uptime.goToUptimePageAndSetDateRange(DEFAULT_DATE_START, DEFAULT_DATE_END);
await pageObjects.uptime.changePage('next');
// there should now be pagination data in the URL
- const contains = await pageObjects.uptime.pageUrlContains('pagination');
- expect(contains).to.be(true);
+ await pageObjects.uptime.pageUrlContains('pagination');
await pageObjects.uptime.pageHasExpectedIds([
'0010-down',
'0011-up',
@@ -71,8 +69,7 @@ export default ({ getPageObjects }: FtrProviderContext) => {
]);
await pageObjects.uptime.setStatusFilter('up');
// ensure that pagination is removed from the URL
- const doesNotContain = await pageObjects.uptime.pageUrlContains('pagination');
- expect(doesNotContain).to.be(false);
+ await pageObjects.uptime.pageUrlContains('pagination', false);
await pageObjects.uptime.pageHasExpectedIds([
'0000-intermittent',
'0001-up',
diff --git a/x-pack/test/functional/page_objects/uptime_page.ts b/x-pack/test/functional/page_objects/uptime_page.ts
index f04f96148583fa..2ae0ea38c957bb 100644
--- a/x-pack/test/functional/page_objects/uptime_page.ts
+++ b/x-pack/test/functional/page_objects/uptime_page.ts
@@ -4,11 +4,13 @@
* you may not use this file except in compliance with the Elastic License.
*/
+import expect from '@kbn/expect';
import { FtrProviderContext } from '../ftr_provider_context';
export function UptimePageProvider({ getPageObjects, getService }: FtrProviderContext) {
const pageObjects = getPageObjects(['common', 'timePicker']);
const uptimeService = getService('uptime');
+ const retry = getService('retry');
return new (class UptimePage {
public async goToUptimePageAndSetDateRange(
@@ -51,8 +53,10 @@ export function UptimePageProvider({ getPageObjects, getService }: FtrProviderCo
await Promise.all(monitorIdsToCheck.map(id => uptimeService.monitorPageLinkExists(id)));
}
- public async pageUrlContains(value: string) {
- return await uptimeService.urlContains(value);
+ public async pageUrlContains(value: string, expected: boolean = true) {
+ retry.try(async () => {
+ expect(await uptimeService.urlContains(value)).to.eql(expected);
+ });
}
public async changePage(direction: 'next' | 'prev') {
diff --git a/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts b/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts
index bd35f21d8f428b..0346da334d2f2d 100644
--- a/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts
+++ b/x-pack/test/kerberos_api_integration/apis/security/kerberos_login.ts
@@ -344,8 +344,7 @@ export default function({ getService }: FtrProviderContext) {
});
});
- // FAILING: https://github.com/elastic/kibana/issues/52969
- describe.skip('API access with missing access token document or expired refresh token.', () => {
+ describe('API access with missing access token document or expired refresh token.', () => {
let sessionCookie: Cookie;
beforeEach(async () => {