Using named badges

This commit is contained in:
kobelb 2019-04-04 15:57:54 -07:00
parent 97802c8978
commit c0e341bee1
18 changed files with 87 additions and 184 deletions

View file

@ -36,6 +36,7 @@ const createSetupContractMock = () => {
addApplicationClass: jest.fn(),
removeApplicationClass: jest.fn(),
getApplicationClasses$: jest.fn(),
addNamedBadge: jest.fn(),
getBadge$: jest.fn(),
setBadge: jest.fn(),
getBreadcrumbs$: jest.fn(),

View file

@ -81,7 +81,8 @@ export class ChromeService {
const applicationClasses$ = new Rx.BehaviorSubject<Set<string>>(new Set());
const helpExtension$ = new Rx.BehaviorSubject<ChromeHelpExtension | undefined>(undefined);
const breadcrumbs$ = new Rx.BehaviorSubject<ChromeBreadcrumb[]>([]);
const badge$ = new Rx.BehaviorSubject<ChromeBadge | undefined>(undefined);
const badge$ = new Rx.BehaviorSubject<ChromeBadge | undefined | string>(undefined);
const namedBadges = new Map<string, ChromeBadge>();
if (!this.browserSupportsCsp && injectedMetadata.getCspConfig().warnLegacyBrowsers) {
notifications.toasts.addWarning(
@ -182,15 +183,26 @@ export class ChromeService {
takeUntil(this.stop$)
),
/**
* Sets a named badge which can be used by setBadge
*/
addNamedBadge: (name: string, badge: ChromeBadge) => {
namedBadges.set(name, badge);
},
/**
* Get an observable of the current badge
*/
getBadge$: () => badge$.pipe(takeUntil(this.stop$)),
getBadge$: (): Rx.Observable<ChromeBadge | undefined> =>
badge$.pipe(
map(badge => (typeof badge === 'string' ? namedBadges.get(badge) : badge)),
takeUntil(this.stop$)
),
/**
* Override the current badge
*/
setBadge: (badge: ChromeBadge | undefined) => {
setBadge: (badge: ChromeBadge | undefined | string) => {
badge$.next(badge);
},

View file

@ -58,19 +58,10 @@ uiRoutes
.defaults(/dashboard/, {
requireDefaultIndex: true,
requireUICapability: 'dashboard.show',
badge: (i18n, uiCapabilities) => {
if (uiCapabilities.dashboard.showWriteControls) {
return undefined;
badge: (uiCapabilities) => {
if (!uiCapabilities.dashboard.showWriteControls) {
return 'readOnly';
}
return {
text: i18n('kbn.dashboard.badge.readOnly.text', {
defaultMessage: 'Read Only',
}),
tooltip: i18n('kbn.dashboard.badge.readOnly.tooltip', {
defaultMessage: 'You lack the authority',
}),
};
}
})
.when(DashboardConstants.LANDING_PAGE_PATH, {

View file

@ -34,19 +34,10 @@ uiRoutes
});
uiRoutes.defaults(/^\/dev_tools(\/|$)/, {
badge: (i18n, uiCapabilities) => {
if (uiCapabilities.dev_tools.save) {
return undefined;
badge: (uiCapabilities) => {
if (!uiCapabilities.dev_tools.save) {
return 'readOnly';
}
return {
text: i18n('kbn.devTools.badge.readOnly.text', {
defaultMessage: 'Read Only',
}),
tooltip: i18n('kbn.devTools.badge.readOnly.tooltip', {
defaultMessage: 'You lack the authority',
}),
};
},
k7Breadcrumbs: (i18n) => [
{

View file

@ -90,19 +90,10 @@ uiRoutes
? getSavedSearchBreadcrumbs
: getRootBreadcrumbs
),
badge: (i18n, uiCapabilities) => {
if (uiCapabilities.discover.save) {
return undefined;
badge: (uiCapabilities) => {
if (!uiCapabilities.discover.save) {
return 'readOnly';
}
return {
text: i18n('kbn.discover.badge.readOnly.text', {
defaultMessage: 'Read Only',
}),
tooltip: i18n('kbn.discover.badge.readOnly.tooltip', {
defaultMessage: 'You lack the authority',
}),
};
}
})
.when('/discover/:id?', {

View file

@ -86,19 +86,10 @@ uiRoutes
.defaults(/management\/kibana\/(index_patterns|index_pattern)/, {
resolve: indexPatternsResolutions,
requireUICapability: 'management.kibana.index_patterns',
badge: (i18n, uiCapabilities) => {
if (uiCapabilities.indexPatterns.save) {
return undefined;
badge: (uiCapabilities) => {
if (!uiCapabilities.indexPatterns.save) {
return 'readOnly';
}
return {
text: i18n('kbn.management.indexPatterns.badge.readOnly.text', {
defaultMessage: 'Read Only',
}),
tooltip: i18n('kbn.management.indexPatterns.badge.readOnly.tooltip', {
defaultMessage: 'You lack the authority',
}),
};
}
});

View file

@ -63,19 +63,10 @@ uiRoutes
template: indexTemplate,
k7Breadcrumbs: getBreadcrumbs,
requireUICapability: 'management.kibana.settings',
badge: (i18n, uiCapabilities) => {
if (uiCapabilities.advancedSettings.save) {
return undefined;
badge: (uiCapabilities) => {
if (!uiCapabilities.advancedSettings.save) {
return 'readOnly';
}
return {
text: i18n('kbn.management.advancedSettings.badge.readOnly.text', {
defaultMessage: 'Read Only',
}),
tooltip: i18n('kbn.management.advancedSettings.badge.readOnly.tooltip', {
defaultMessage: 'You lack the authority',
}),
};
}
});

View file

@ -33,19 +33,10 @@ uiRoutes
.defaults(/visualize/, {
requireDefaultIndex: true,
requireUICapability: 'visualize.show',
badge: (i18n, uiCapabilities) => {
if (uiCapabilities.visualize.save) {
return undefined;
badge: (uiCapabilities) => {
if (!uiCapabilities.visualize.save) {
return 'readOnly';
}
return {
text: i18n('kbn.visualize.badge.readOnly.text', {
defaultMessage: 'Read Only',
}),
tooltip: i18n('kbn.visualize.badge.readOnly.tooltip', {
defaultMessage: 'You lack the authority',
}),
};
}
})
.when(VisualizeConstants.LANDING_PAGE_PATH, {

View file

@ -72,19 +72,10 @@ require('ui/routes')
? getSavedSheetBreadcrumbs
: getCreateBreadcrumbs
),
badge: (i18n, uiCapabilities) => {
if (uiCapabilities.timelion.save) {
return undefined;
badge: (uiCapabilities) => {
if (!uiCapabilities.timelion.save) {
return 'readOnly';
}
return {
text: i18n('kbn.timelion.badge.readOnly.text', {
defaultMessage: 'Read Only',
}),
tooltip: i18n('kbn.timelion.badge.readOnly.tooltip', {
defaultMessage: 'You lack the authority',
}),
};
},
resolve: {
savedSheet: function (redirectWhenMissing, savedSheets, $route) {

View file

@ -62,6 +62,10 @@ function createBadgeApi(chrome: { [key: string]: any }) {
set(newBadge: Badge | undefined) {
newPlatformChrome.setBadge(newBadge);
},
addNamedBadge(name: string, badge: Badge) {
newPlatformChrome.addNamedBadge(name, badge);
},
},
/**

View file

@ -4,33 +4,18 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
import React from 'react';
import { injectUICapabilities, UICapabilities } from 'ui/capabilities/react';
import chrome from 'ui/chrome';
interface Props {
uiCapabilities: UICapabilities;
intl: InjectedIntl;
}
class UpdateBadgeComponent extends React.Component<Props> {
public componentDidMount() {
const { uiCapabilities, intl } = this.props;
chrome.badge.set(
!uiCapabilities.apm.save
? {
text: intl.formatMessage({
defaultMessage: 'Read Only',
id: 'xpack.apm.header.badge.readOnly.text'
}),
tooltip: intl.formatMessage({
defaultMessage: 'You lack the authority',
id: 'xpack.aapm.header.badge.readOnly.tooltip'
})
}
: undefined
);
const { uiCapabilities } = this.props;
chrome.badge.set(!uiCapabilities.apm.save ? 'readOnly' : undefined);
}
public render() {
@ -38,6 +23,4 @@ class UpdateBadgeComponent extends React.Component<Props> {
}
}
export const UpdateBadge = injectUICapabilities(
injectI18n(UpdateBadgeComponent)
);
export const UpdateBadge = injectUICapabilities(UpdateBadgeComponent);

View file

@ -9,7 +9,6 @@ import './angular/config';
import './angular/services';
import React from 'react';
import ReactDOM from 'react-dom';
import { i18n } from '@kbn/i18n';
import chrome from 'ui/chrome';
import { uiCapabilities } from 'ui/capabilities';
import { CanvasRootController } from './angular/controllers';
@ -39,15 +38,4 @@ chrome.helpExtension.set(domNode => {
});
// set the read-only badge when appropriate
chrome.badge.set(
uiCapabilities.canvas.save
? undefined
: {
text: i18n.translate('xpack.canvas.badge.readOnly.text', {
defaultMessage: 'Read Only',
}),
tooltip: i18n.translate('xpack.canvas.badge.readOnly.tooltip', {
defaultMessage: 'You lack the authority',
}),
}
);
chrome.badge.set(!uiCapabilities.canvas.save ? 'readOnly' : undefined);

View file

@ -6,16 +6,7 @@
export function getReadonlyBadge(i18n, uiCapabilities) {
if (uiCapabilities.graph.save) {
return null;
if (!uiCapabilities.graph.save) {
return 'readOnly';
}
return {
text: i18n('xpack.graph.badge.readOnly.text', {
defaultMessage: 'Read Only',
}),
tooltip: i18n('xpack.graph.badge.readOnly.tooltip', {
defaultMessage: 'You lack the authority',
}),
};
}

View file

@ -6,7 +6,6 @@
import React from 'react';
import { InjectedIntl, injectI18n } from '@kbn/i18n/react';
import { Breadcrumb } from 'ui/chrome/api/breadcrumbs';
import { WithKibanaChrome } from '../../containers/with_kibana_chrome';
import { ExternalHeader } from './external_header';
@ -14,33 +13,17 @@ import { ExternalHeader } from './external_header';
interface HeaderProps {
breadcrumbs?: Breadcrumb[];
readOnlyBadge?: boolean;
intl: InjectedIntl;
}
export const Header = injectI18n(
({ breadcrumbs = [], readOnlyBadge = false, intl }: HeaderProps) => (
<WithKibanaChrome>
{({ setBreadcrumbs, setBadge }) => (
<ExternalHeader
breadcrumbs={breadcrumbs}
setBreadcrumbs={setBreadcrumbs}
badge={
readOnlyBadge
? {
text: intl.formatMessage({
defaultMessage: 'Read Only',
id: 'xpack.infra.header.badge.readOnly.text',
}),
tooltip: intl.formatMessage({
defaultMessage: 'You lack the authority',
id: 'xpack.infra.header.badge.readOnly.tooltip',
}),
}
: undefined
}
setBadge={setBadge}
/>
)}
</WithKibanaChrome>
)
export const Header = ({ breadcrumbs = [], readOnlyBadge = false }: HeaderProps) => (
<WithKibanaChrome>
{({ setBreadcrumbs, setBadge }) => (
<ExternalHeader
breadcrumbs={breadcrumbs}
setBreadcrumbs={setBreadcrumbs}
badge={readOnlyBadge ? 'readOnly' : undefined}
setBadge={setBadge}
/>
)}
</WithKibanaChrome>
);

View file

@ -39,6 +39,12 @@ import { recentlyAccessed } from 'ui/persisted_log';
const app = uiModules.get('app/maps', ['ngRoute', 'react']);
const badge = (uiCapabilities) => {
if (!uiCapabilities.maps.save) {
return 'readOnly';
}
};
app.directive('mapListing', function (reactDirective) {
return reactDirective(MapListing);
});
@ -46,24 +52,9 @@ app.directive('mapListing', function (reactDirective) {
routes.enable();
routes
.defaults(/.*/, {
badge: (i18n, uiCapabilities) => {
if (uiCapabilities.maps.save) {
return undefined;
}
return {
text: i18n('xpack.maps.badge.readOnly.text', {
defaultMessage: 'Read Only',
}),
tooltip: i18n('xpack.maps.badge.readOnly.tooltip', {
defaultMessage: 'You lack the authority',
}),
};
}
})
.when('/', {
template: listingTemplate,
badge,
controller($scope, gisMapSavedObjectLoader, config) {
$scope.listingLimit = config.get('savedObjects:listingLimit');
$scope.find = (search) => {
@ -90,6 +81,7 @@ routes
.when('/map', {
template: mapTemplate,
controller: 'GisMapController',
badge,
resolve: {
map: function (gisMapSavedObjectLoader, redirectWhenMissing) {
return gisMapSavedObjectLoader.get()
@ -102,6 +94,7 @@ routes
.when('/map/:id', {
template: mapTemplate,
controller: 'GisMapController',
badge,
resolve: {
map: function (gisMapSavedObjectLoader, redirectWhenMissing, $route,
Private) {

View file

@ -91,7 +91,8 @@ export const security = (kibana) => new kibana.Plugin({
}],
hacks: [
'plugins/security/hacks/on_session_timeout',
'plugins/security/hacks/on_unauthorized_response'
'plugins/security/hacks/on_unauthorized_response',
'plugins/security/hacks/badges',
],
home: ['plugins/security/register_feature'],
injectDefaultVars: function (server) {

View file

@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { i18n } from '@kbn/i18n';
import chrome from 'ui/chrome';
chrome.badge.addNamedBadge('readOnly', {
text: i18n.translate('xpack.security.badges.readOnly.text', {
defaultMessage: 'Read Only',
}),
tooltip: i18n.translate('xpack.security.badges.readOnly.tooltip', {
defaultMessage: `You're not authorized to save changes.`,
}),
});

View file

@ -149,14 +149,7 @@ class Application extends React.Component<UptimeAppProps, UptimeAppState> {
public componentWillMount() {
this.setBreadcrumbs([overviewBreadcrumb]);
this.setBadge(
!uiCapabilities.uptime.save
? {
text: 'Read Only',
tooltip: 'You lack the authority',
}
: undefined
);
this.setBadge(!uiCapabilities.uptime.save ? 'readOnly' : undefined);
}
public componentDidMount() {