mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* remove usage of legacy notifier * fix superfluous whitespace changes * fix redirection on role management screen * extract session expiration warning into its own component
This commit is contained in:
parent
f7236a96e8
commit
00f220df0e
9 changed files with 117 additions and 57 deletions
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* 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 { SessionExpirationWarning } from './session_expiration_warning';
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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 { mountWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { SessionExpirationWarning } from './session_expiration_warning';
|
||||
|
||||
describe('SessionExpirationWarning', () => {
|
||||
it('fires its callback when the OK button is clicked', () => {
|
||||
const handler = jest.fn();
|
||||
const wrapper = mountWithIntl(<SessionExpirationWarning onRefreshSession={handler} />);
|
||||
|
||||
expect(handler).toBeCalledTimes(0);
|
||||
wrapper.find('EuiButton[data-test-subj="refreshSessionButton"]').simulate('click');
|
||||
expect(handler).toBeCalledTimes(1);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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 { EuiButton } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
interface Props {
|
||||
onRefreshSession: () => void;
|
||||
}
|
||||
|
||||
export const SessionExpirationWarning = (props: Props) => {
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="xpack.security.components.sessionExpiration.logoutNotification"
|
||||
defaultMessage="You will soon be logged out due to inactivity. Click OK to resume."
|
||||
/>
|
||||
</p>
|
||||
<div className="eui-textRight">
|
||||
<EuiButton
|
||||
size="s"
|
||||
color="warning"
|
||||
onClick={props.onRefreshSession}
|
||||
data-test-subj="refreshSessionButton"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="xpack.security.components.sessionExpiration.okButtonText"
|
||||
defaultMessage="OK"
|
||||
/>
|
||||
</EuiButton>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -4,12 +4,15 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import { isSystemApiRequest } from 'ui/system_api';
|
||||
import { PathProvider } from 'plugins/xpack_main/services/path';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
import 'plugins/security/services/auto_logout';
|
||||
import { SessionExpirationWarning } from '../components/session_expiration_warning';
|
||||
|
||||
/**
|
||||
* Client session timeout is decreased by this number so that Kibana server
|
||||
|
@ -27,35 +30,40 @@ module.config(($httpProvider) => {
|
|||
$q,
|
||||
$injector,
|
||||
sessionTimeout,
|
||||
Notifier,
|
||||
Private,
|
||||
autoLogout
|
||||
) => {
|
||||
|
||||
function refreshSession() {
|
||||
// Make a simple request to keep the session alive
|
||||
$injector.get('es').ping();
|
||||
clearNotifications();
|
||||
}
|
||||
|
||||
const isUnauthenticated = Private(PathProvider).isUnauthenticated();
|
||||
const notifier = new Notifier();
|
||||
const notificationLifetime = 60 * 1000;
|
||||
const notificationOptions = {
|
||||
type: 'warning',
|
||||
content: i18n.translate('xpack.security.hacks.logoutNotification', {
|
||||
defaultMessage: 'You will soon be logged out due to inactivity. Click OK to resume.'
|
||||
}),
|
||||
icon: 'warning',
|
||||
color: 'warning',
|
||||
text: (
|
||||
<SessionExpirationWarning onRefreshSession={refreshSession} />
|
||||
),
|
||||
title: i18n.translate('xpack.security.hacks.warningTitle', {
|
||||
defaultMessage: 'Warning'
|
||||
}),
|
||||
lifetime: Math.min(
|
||||
toastLifeTimeMs: Math.min(
|
||||
(sessionTimeout - SESSION_TIMEOUT_GRACE_PERIOD_MS),
|
||||
notificationLifetime
|
||||
),
|
||||
actions: ['accept']
|
||||
};
|
||||
|
||||
let pendingNotification;
|
||||
let activeNotification;
|
||||
let pendingSessionExpiration;
|
||||
|
||||
function clearNotifications() {
|
||||
if (pendingNotification) $timeout.cancel(pendingNotification);
|
||||
if (activeNotification) activeNotification.clear();
|
||||
if (pendingSessionExpiration) clearTimeout(pendingSessionExpiration);
|
||||
if (activeNotification) toastNotifications.remove(activeNotification);
|
||||
}
|
||||
|
||||
function scheduleNotification() {
|
||||
|
@ -63,14 +71,8 @@ module.config(($httpProvider) => {
|
|||
}
|
||||
|
||||
function showNotification() {
|
||||
activeNotification = notifier.add(notificationOptions, (action) => {
|
||||
if (action === 'accept') {
|
||||
// Make a simple request to keep the session alive
|
||||
$injector.get('es').ping();
|
||||
} else {
|
||||
autoLogout();
|
||||
}
|
||||
});
|
||||
activeNotification = toastNotifications.add(notificationOptions);
|
||||
pendingSessionExpiration = setTimeout(() => autoLogout(), notificationOptions.toastLifeTimeMs);
|
||||
}
|
||||
|
||||
function interceptorFactory(responseHandler) {
|
||||
|
|
|
@ -1,22 +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 { XPackInfoProvider } from 'plugins/xpack_main/services/xpack_info';
|
||||
import { Notifier } from 'ui/notify';
|
||||
|
||||
export function checkLicenseError(kbnUrl, Promise, Private) {
|
||||
const xpackInfo = Private(XPackInfoProvider);
|
||||
const genericNotifier = new Notifier({ location: 'Security' });
|
||||
|
||||
return err => {
|
||||
if (!xpackInfo.get('features.security.showLinks')) {
|
||||
genericNotifier.error(xpackInfo.get('features.security.linksMessage'));
|
||||
kbnUrl.redirect('/management');
|
||||
return Promise.halt();
|
||||
}
|
||||
return Promise.reject(err);
|
||||
};
|
||||
}
|
|
@ -8,7 +8,7 @@ import _ from 'lodash';
|
|||
import routes from 'ui/routes';
|
||||
import { capabilities } from 'ui/capabilities';
|
||||
import { kfetch } from 'ui/kfetch';
|
||||
import { fatalError } from 'ui/notify';
|
||||
import { fatalError, toastNotifications } from 'ui/notify';
|
||||
import template from 'plugins/security/views/management/edit_role/edit_role.html';
|
||||
import 'ui/angular_ui_select';
|
||||
import 'plugins/security/services/application_privilege';
|
||||
|
@ -19,7 +19,6 @@ import 'plugins/security/services/shield_indices';
|
|||
import { IndexPatternsProvider } from 'ui/index_patterns/index_patterns';
|
||||
import { XPackInfoProvider } from 'plugins/xpack_main/services/xpack_info';
|
||||
import { SpacesManager } from '../../../../../spaces/public/lib';
|
||||
import { checkLicenseError } from 'plugins/security/lib/check_license_error';
|
||||
import { EDIT_ROLES_PATH, ROLES_PATH } from '../management_urls';
|
||||
import { getEditRoleBreadcrumbs, getCreateRoleBreadcrumbs } from '../breadcrumbs';
|
||||
|
||||
|
@ -28,6 +27,7 @@ import { EditRolePage } from './components';
|
|||
import React from 'react';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import { I18nContext } from 'ui/i18n';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
routes.when(`${EDIT_ROLES_PATH}/:name?`, {
|
||||
template,
|
||||
|
@ -37,7 +37,7 @@ routes.when(`${EDIT_ROLES_PATH}/:name?`, {
|
|||
: getCreateRoleBreadcrumbs
|
||||
),
|
||||
resolve: {
|
||||
role($route, ShieldRole, kbnUrl, Promise, Notifier) {
|
||||
role($route, ShieldRole, Promise, kbnUrl) {
|
||||
const name = $route.current.params.name;
|
||||
|
||||
let role;
|
||||
|
@ -45,17 +45,19 @@ routes.when(`${EDIT_ROLES_PATH}/:name?`, {
|
|||
if (name != null) {
|
||||
role = ShieldRole.get({ name }).$promise
|
||||
.catch((response) => {
|
||||
|
||||
if (response.status !== 404) {
|
||||
if (response.status === 404) {
|
||||
toastNotifications.addDanger({
|
||||
title: i18n.translate('xpack.security.management.roles.roleNotFound',
|
||||
{
|
||||
defaultMessage: 'No "{roleName}" role found.',
|
||||
values: { roleName: name }
|
||||
}),
|
||||
});
|
||||
kbnUrl.redirect(ROLES_PATH);
|
||||
} else {
|
||||
return fatalError(response);
|
||||
}
|
||||
|
||||
const notifier = new Notifier();
|
||||
notifier.error(`No "${name}" role found.`);
|
||||
kbnUrl.redirect(ROLES_PATH);
|
||||
return Promise.halt();
|
||||
});
|
||||
|
||||
} else {
|
||||
role = Promise.resolve(new ShieldRole({
|
||||
elasticsearch: {
|
||||
|
@ -70,11 +72,10 @@ routes.when(`${EDIT_ROLES_PATH}/:name?`, {
|
|||
|
||||
return role.then(res => res.toJSON());
|
||||
},
|
||||
users(ShieldUser, kbnUrl, Promise, Private) {
|
||||
users(ShieldUser) {
|
||||
// $promise is used here because the result is an ngResource, not a promise itself
|
||||
return ShieldUser.query().$promise
|
||||
.then(users => _.map(users, 'username'))
|
||||
.catch(checkLicenseError(kbnUrl, Promise, Private));
|
||||
.then(users => _.map(users, 'username'));
|
||||
},
|
||||
indexPatterns(Private) {
|
||||
const indexPatterns = Private(IndexPatternsProvider);
|
||||
|
|
|
@ -17,8 +17,22 @@ import { ROLES_PATH, USERS_PATH } from './management_urls';
|
|||
|
||||
import { management } from 'ui/management';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { toastNotifications } from 'ui/notify';
|
||||
|
||||
routes.defaults(/\/management/, {
|
||||
routes.defaults(/^\/management\/security(\/|$)/, {
|
||||
resolve: {
|
||||
showLinks(kbnUrl, Promise, Private) {
|
||||
const xpackInfo = Private(XPackInfoProvider);
|
||||
if (!xpackInfo.get('features.security.showLinks')) {
|
||||
toastNotifications.addDanger({
|
||||
title: xpackInfo.get('features.security.linksMessage')
|
||||
});
|
||||
kbnUrl.redirect('/management');
|
||||
return Promise.halt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}).defaults(/\/management/, {
|
||||
resolve: {
|
||||
securityManagementSection: function (ShieldUser, Private) {
|
||||
const xpackInfo = Private(XPackInfoProvider);
|
||||
|
|
|
@ -8651,7 +8651,7 @@
|
|||
"xpack.security.account.passwordsDoNotMatch": "パスワードが一致していません。",
|
||||
"xpack.security.account.usernameGroupDescription": "この情報は変更できません。",
|
||||
"xpack.security.account.usernameGroupTitle": "ユーザー名とメールアドレス",
|
||||
"xpack.security.hacks.logoutNotification": "操作がないため間もなくログアウトします。再開するには [OK] をクリックしてくださ。",
|
||||
"xpack.security.components.sessionExpiration.logoutNotification": "操作がないため間もなくログアウトします。再開するには [OK] をクリックしてくださ。",
|
||||
"xpack.security.hacks.warningTitle": "警告",
|
||||
"xpack.security.loggedOut.login": "ログイン",
|
||||
"xpack.security.loggedOut.title": "ログアウト完了",
|
||||
|
|
|
@ -8661,7 +8661,7 @@
|
|||
"xpack.security.account.passwordsDoNotMatch": "密码不匹配。",
|
||||
"xpack.security.account.usernameGroupDescription": "不能更改此信息。",
|
||||
"xpack.security.account.usernameGroupTitle": "用户名和电子邮件",
|
||||
"xpack.security.hacks.logoutNotification": "由于处于不活动状态,您即将退出。单击“确定”可以恢复。",
|
||||
"xpack.security.components.sessionExpiration.logoutNotification": "由于处于不活动状态,您即将退出。单击“确定”可以恢复。",
|
||||
"xpack.security.hacks.warningTitle": "警告",
|
||||
"xpack.security.loggedOut.login": "登录",
|
||||
"xpack.security.loggedOut.title": "已成功退出",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue