Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[License Management] Add URL locator #153792

Merged
merged 10 commits into from
Mar 31, 2023
Merged
3 changes: 2 additions & 1 deletion x-pack/plugins/license_management/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"home",
"licensing",
"management",
"features"
"features",
"share"
],
"optionalPlugins": [
"telemetry"
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/license_management/public/application/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
EuiPageBody,
EuiEmptyPrompt,
} from '@elastic/eui';
import { UPLOAD_LICENSE_ROUTE } from '../locator';

export const App = ({
hasPermission,
Expand Down Expand Up @@ -102,7 +103,7 @@ export const App = ({
return (
<EuiPageBody>
<Switch>
<Route path={`/upload_license`} component={withTelemetry(UploadLicense)} />
<Route path={`/${UPLOAD_LICENSE_ROUTE}`} component={withTelemetry(UploadLicense)} />
<Route path={['/']} component={withTelemetry(LicenseDashboard)} />
</Switch>
</EuiPageBody>
Expand Down
34 changes: 34 additions & 0 deletions x-pack/plugins/license_management/public/locator.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { sharePluginMock } from '@kbn/share-plugin/public/mocks';
import { ManagementAppLocatorDefinition } from '@kbn/management-plugin/common/locator';
import { LicenseManagementLocatorDefinition, LICENSE_MANAGEMENT_LOCATOR_ID } from './locator';
describe('License Management URL locator', () => {
let locator: LicenseManagementLocatorDefinition;
beforeEach(() => {
const managementDefinition = new ManagementAppLocatorDefinition();
locator = new LicenseManagementLocatorDefinition({
managementAppLocator: {
...sharePluginMock.createLocator(),
getLocation: (params) => managementDefinition.getLocation(params),
},
});
});
test('locator has the right ID', () => {
expect(locator.id).toBe(LICENSE_MANAGEMENT_LOCATOR_ID);
});

test('locator returns the correct url for dashboard page', async () => {
const { path } = await locator.getLocation({ page: 'dashboard' });
expect(path).toBe('/stack/license_management');
});
test('locator returns the correct url for upload license page', async () => {
const { path } = await locator.getLocation({ page: 'upload_license' });
expect(path).toBe('/stack/license_management/upload_license');
});
});
51 changes: 51 additions & 0 deletions x-pack/plugins/license_management/public/locator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import type { SerializableRecord } from '@kbn/utility-types';
import { ManagementAppLocator } from '@kbn/management-plugin/common';
import { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/public';
import { PLUGIN } from '../common/constants';

export const LICENSE_MANAGEMENT_LOCATOR_ID = 'LICENSE_MANAGEMENT_LOCATOR';
export const UPLOAD_LICENSE_ROUTE = 'upload_license';

export interface LicenseManagementLocatorParams extends SerializableRecord {
page: 'dashboard' | 'upload_license';
}

export type LicenseManagementLocator = LocatorPublic<LicenseManagementLocatorParams>;

export interface LicenseManagementLocatorDefinitionDependencies {
managementAppLocator: ManagementAppLocator;
}

export class LicenseManagementLocatorDefinition
implements LocatorDefinition<LicenseManagementLocatorParams>
{
constructor(protected readonly deps: LicenseManagementLocatorDefinitionDependencies) {}

public readonly id = LICENSE_MANAGEMENT_LOCATOR_ID;

public readonly getLocation = async (params: LicenseManagementLocatorParams) => {
const location = await this.deps.managementAppLocator.getLocation({
sectionId: 'stack',
appId: PLUGIN.id,
});

switch (params.page) {
case 'upload_license': {
return {
...location,
path: `${location.path}/${UPLOAD_LICENSE_ROUTE}`,
};
}
case 'dashboard': {
return location;
}
}
};
}
15 changes: 14 additions & 1 deletion x-pack/plugins/license_management/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,17 @@ import { CoreSetup, Plugin, PluginInitializerContext } from '@kbn/core/public';
import { TelemetryPluginStart } from '@kbn/telemetry-plugin/public';
import { ManagementSetup } from '@kbn/management-plugin/public';
import { LicensingPluginSetup } from '@kbn/licensing-plugin/public';
import { SharePluginSetup } from '@kbn/share-plugin/public';
import { PLUGIN } from '../common/constants';
import { ClientConfigType } from './types';
import { AppDependencies } from './application';
import { BreadcrumbService } from './application/breadcrumbs';
import { LicenseManagementLocator, LicenseManagementLocatorDefinition } from './locator';

interface PluginsDependenciesSetup {
management: ManagementSetup;
licensing: LicensingPluginSetup;
share: SharePluginSetup;
}

interface PluginsDependenciesStart {
Expand All @@ -27,13 +30,15 @@ interface PluginsDependenciesStart {

export interface LicenseManagementUIPluginSetup {
enabled: boolean;
locator: undefined | LicenseManagementLocator;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in which cases would the locator be undefined?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the case that the License Management plugin is hidden from the UI with ui.enabled: false. The plugin is still enabled, but we don't register it in the Kibana navigation and don't initialize the locator.

}
export type LicenseManagementUIPluginStart = void;

export class LicenseManagementUIPlugin
implements Plugin<LicenseManagementUIPluginSetup, LicenseManagementUIPluginStart, any, any>
{
private breadcrumbService = new BreadcrumbService();
private locator?: LicenseManagementLocator;

constructor(private readonly initializerContext: PluginInitializerContext) {}

Expand All @@ -47,11 +52,18 @@ export class LicenseManagementUIPlugin
// No need to go any further
return {
enabled: false,
locator: this.locator,
};
}

const { getStartServices } = coreSetup;
const { management, licensing } = plugins;
const { management, licensing, share } = plugins;

this.locator = share.url.locators.create(
new LicenseManagementLocatorDefinition({
managementAppLocator: management.locator,
})
);

management.sections.section.stack.registerApp({
id: PLUGIN.id,
Expand Down Expand Up @@ -105,6 +117,7 @@ export class LicenseManagementUIPlugin

return {
enabled: true,
locator: this.locator,
};
}

Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/license_management/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
"@kbn/config-schema",
"@kbn/test-jest-helpers",
"@kbn/shared-ux-router",
"@kbn/utility-types",
"@kbn/share-plugin",
],
"exclude": [
"target/**/*",
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions x-pack/plugins/watcher/__jest__/license_prompt.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import React from 'react';
import { shallow } from 'enzyme';
import { sharePluginMock } from '@kbn/share-plugin/public/mocks';
import {
LicenseManagementLocator,
LicenseManagementLocatorParams,
} from '@kbn/license-management-plugin/public/locator';
import { LicensePrompt } from '../public/application/license_prompt';

describe('License prompt', () => {
test('renders a prompt with a link to License Management', () => {
const locator = {
...sharePluginMock.createLocator(),
useUrl: (params: LicenseManagementLocatorParams) => '/license_management',
} as LicenseManagementLocator;
const component = shallow(
<LicensePrompt message="License error" licenseManagementLocator={locator} />
);

expect(component).toMatchSnapshot();
});

test('renders a prompt without a link to License Management', () => {
const component = shallow(<LicensePrompt message="License error" />);

expect(component).toMatchSnapshot();
});
});
3 changes: 3 additions & 0 deletions x-pack/plugins/watcher/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
"data",
"features"
],
"optionalPlugins": [
"licenseManagement"
],
"requiredBundles": [
"esUiShared",
"kibanaReact",
Expand Down
32 changes: 4 additions & 28 deletions x-pack/plugins/watcher/public/application/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,15 @@ import { Router, Switch, Redirect, withRouter, RouteComponentProps } from 'react

import { Route } from '@kbn/shared-ux-router';

import { EuiPageContent_Deprecated as EuiPageContent, EuiEmptyPrompt, EuiLink } from '@elastic/eui';

import { FormattedMessage } from '@kbn/i18n-react';

import { RegisterManagementAppArgs, ManagementAppMountParams } from '@kbn/management-plugin/public';

import { ChartsPluginSetup } from '@kbn/charts-plugin/public';
import { LicenseManagementLocator } from '@kbn/license-management-plugin/public/locator';
import { LicenseStatus } from '../../common/types/license_status';
import { WatchListPage, WatchEditPage, WatchStatusPage } from './sections';
import { registerRouter } from './lib/navigation';
import { AppContextProvider } from './app_context';
import { LicensePrompt } from './license_prompt';

const ShareRouter = withRouter(({ children, history }: RouteComponentProps & { children: any }) => {
registerRouter({ history });
Expand All @@ -49,6 +47,7 @@ export interface AppDeps {
history: ManagementAppMountParams['history'];
getUrlForApp: ApplicationStart['getUrlForApp'];
executionContext: ExecutionContextStart;
licenseManagementLocator?: LicenseManagementLocator;
}

export const App = (deps: AppDeps) => {
Expand All @@ -61,30 +60,7 @@ export const App = (deps: AppDeps) => {

if (!valid) {
return (
<EuiPageContent verticalPosition="center" horizontalPosition="center" color="danger">
<EuiEmptyPrompt
iconType="warning"
title={
<h1>
<FormattedMessage
id="xpack.watcher.app.licenseErrorTitle"
defaultMessage="License error"
/>
</h1>
}
body={<p>{message}</p>}
actions={[
<EuiLink
href={deps.getUrlForApp('management', { path: 'stack/license_management/home' })}
>
<FormattedMessage
id="xpack.watcher.app.licenseErrorLinkText"
defaultMessage="Manage your license"
/>
</EuiLink>,
]}
/>
</EuiPageContent>
<LicensePrompt licenseManagementLocator={deps.licenseManagementLocator} message={message} />
);
}
return (
Expand Down
Loading