Remove injected reference from home app (#57836)

This commit is contained in:
Joe Reuter 2020-02-19 12:51:26 +01:00 committed by GitHub
parent e7b63863ab
commit 28034d05a9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 248 additions and 14 deletions

View file

@ -31,6 +31,7 @@ import { TelemetryPluginStart } from '../../../../../plugins/telemetry/public';
import {
Environment,
HomePublicPluginSetup,
TutorialStart,
HomePublicPluginStart,
} from '../../../../../plugins/home/public';
import { KibanaLegacySetup } from '../../../../../plugins/kibana_legacy/public';
@ -38,7 +39,6 @@ import { KibanaLegacySetup } from '../../../../../plugins/kibana_legacy/public';
export interface HomeKibanaServices {
indexPatternService: any;
kibanaVersion: string;
getInjected: (name: string, defaultValue?: any) => unknown;
chrome: ChromeStart;
uiSettings: IUiSettingsClient;
config: KibanaLegacySetup['config'];
@ -54,6 +54,7 @@ export interface HomeKibanaServices {
addBasePath: (url: string) => string;
environment: Environment;
telemetry?: TelemetryPluginStart;
tutorialVariables: TutorialStart['get'];
}
let services: HomeKibanaServices | null = null;

View file

@ -29,7 +29,7 @@ import { FeatureCatalogueCategory } from '../../../../../../../plugins/home/publ
jest.mock('../../kibana_services', () => ({
getServices: () => ({
getBasePath: () => 'path',
getInjected: () => '',
tutorialVariables: () => ({}),
homeConfig: { disableWelcomeScreen: false },
}),
}));

View file

@ -33,7 +33,7 @@ mustacheWriter.escapedValue = function escapedValue(token, context) {
};
export function replaceTemplateStrings(text, params = {}) {
const { getInjected, kibanaVersion, docLinks } = getServices();
const { tutorialVariables, kibanaVersion, docLinks } = getServices();
const variables = {
// '{' and '}' can not be used in template since they are used as template tags.
@ -41,9 +41,7 @@ export function replaceTemplateStrings(text, params = {}) {
curlyOpen: '{',
curlyClose: '}',
config: {
cloud: {
id: getInjected('cloudId'),
},
...tutorialVariables(),
docs: {
base_url: docLinks.ELASTIC_WEBSITE_URL,
beats: {

View file

@ -57,20 +57,22 @@ export class HomePlugin implements Plugin {
constructor(private initializerContext: PluginInitializerContext) {}
setup(core: CoreSetup, { home, kibanaLegacy, usageCollection }: HomePluginSetupDependencies) {
setup(
core: CoreSetup<HomePluginStartDependencies>,
{ home, kibanaLegacy, usageCollection }: HomePluginSetupDependencies
) {
kibanaLegacy.registerLegacyApp({
id: 'home',
title: 'Home',
mount: async (params: AppMountParameters) => {
const trackUiMetric = usageCollection.reportUiStats.bind(usageCollection, 'Kibana_home');
const [coreStart] = await core.getStartServices();
const [coreStart, { home: homeStart }] = await core.getStartServices();
setServices({
trackUiMetric,
kibanaVersion: this.initializerContext.env.packageInfo.version,
http: coreStart.http,
toastNotifications: core.notifications.toasts,
banners: coreStart.overlays.banners,
getInjected: core.injectedMetadata.getInjectedVar,
docLinks: coreStart.docLinks,
savedObjectsClient: this.savedObjectsClient!,
chrome: coreStart.chrome,
@ -82,6 +84,7 @@ export class HomePlugin implements Plugin {
environment: this.environment!,
config: kibanaLegacy.config,
homeConfig: home.config,
tutorialVariables: homeStart.tutorials.get,
featureCatalogue: this.featureCatalogue!,
});
const { renderApp } = await import('./np_ready/application');

View file

@ -22,10 +22,19 @@ import { PluginInitializerContext } from 'kibana/public';
export {
FeatureCatalogueSetup,
FeatureCatalogueStart,
EnvironmentSetup,
EnvironmentStart,
TutorialSetup,
TutorialStart,
HomePublicPluginSetup,
HomePublicPluginStart,
} from './plugin';
export { FeatureCatalogueEntry, FeatureCatalogueCategory, Environment } from './services';
export {
FeatureCatalogueEntry,
FeatureCatalogueCategory,
Environment,
TutorialVariables,
} from './services';
export * from '../common/instruction_variant';
import { HomePublicPlugin } from './plugin';

View file

@ -20,16 +20,19 @@
import { featureCatalogueRegistryMock } from '../services/feature_catalogue/feature_catalogue_registry.mock';
import { environmentServiceMock } from '../services/environment/environment.mock';
import { configSchema } from '../../config';
import { tutorialServiceMock } from '../services/tutorials/tutorial_service.mock';
const createSetupContract = () => ({
featureCatalogue: featureCatalogueRegistryMock.createSetup(),
environment: environmentServiceMock.createSetup(),
tutorials: tutorialServiceMock.createSetup(),
config: configSchema.validate({}),
});
const createStartContract = () => ({
featureCatalogue: featureCatalogueRegistryMock.createStart(),
environment: environmentServiceMock.createStart(),
tutorials: tutorialServiceMock.createStart(),
});
export const homePluginMock = {

View file

@ -19,10 +19,13 @@
import { featureCatalogueRegistryMock } from './services/feature_catalogue/feature_catalogue_registry.mock';
import { environmentServiceMock } from './services/environment/environment.mock';
import { tutorialServiceMock } from './services/tutorials/tutorial_service.mock';
export const registryMock = featureCatalogueRegistryMock.create();
export const environmentMock = environmentServiceMock.create();
export const tutorialMock = tutorialServiceMock.create();
jest.doMock('./services', () => ({
FeatureCatalogueRegistry: jest.fn(() => registryMock),
EnvironmentService: jest.fn(() => environmentMock),
TutorialService: jest.fn(() => tutorialMock),
}));

View file

@ -17,7 +17,7 @@
* under the License.
*/
import { registryMock, environmentMock } from './plugin.test.mocks';
import { registryMock, environmentMock, tutorialMock } from './plugin.test.mocks';
import { HomePublicPlugin } from './plugin';
import { coreMock } from '../../../core/public/mocks';
@ -27,8 +27,10 @@ describe('HomePublicPlugin', () => {
beforeEach(() => {
registryMock.setup.mockClear();
registryMock.start.mockClear();
tutorialMock.setup.mockClear();
environmentMock.setup.mockClear();
environmentMock.start.mockClear();
tutorialMock.start.mockClear();
});
describe('setup', () => {
@ -43,6 +45,12 @@ describe('HomePublicPlugin', () => {
expect(setup).toHaveProperty('environment');
expect(setup.environment).toHaveProperty('update');
});
test('wires up and returns tutorial service', async () => {
const setup = await new HomePublicPlugin(mockInitializerContext).setup();
expect(setup).toHaveProperty('tutorials');
expect(setup.tutorials).toHaveProperty('setVariable');
});
});
describe('start', () => {
@ -66,5 +74,13 @@ describe('HomePublicPlugin', () => {
expect(environmentMock.start).toHaveBeenCalled();
expect(start.environment.get).toBeDefined();
});
test('wires up and returns tutorial service', async () => {
const service = new HomePublicPlugin(mockInitializerContext);
await service.setup();
const start = await service.start(coreMock.createStart());
expect(tutorialMock.start).toHaveBeenCalled();
expect(start.tutorials.get).toBeDefined();
});
});
});

View file

@ -26,12 +26,16 @@ import {
FeatureCatalogueRegistry,
FeatureCatalogueRegistrySetup,
FeatureCatalogueRegistryStart,
TutorialService,
TutorialServiceSetup,
TutorialServiceStart,
} from './services';
import { ConfigSchema } from '../config';
export class HomePublicPlugin implements Plugin<HomePublicPluginSetup, HomePublicPluginStart> {
private readonly featuresCatalogueRegistry = new FeatureCatalogueRegistry();
private readonly environmentService = new EnvironmentService();
private readonly tutorialService = new TutorialService();
constructor(private readonly initializerContext: PluginInitializerContext<ConfigSchema>) {}
@ -39,6 +43,7 @@ export class HomePublicPlugin implements Plugin<HomePublicPluginSetup, HomePubli
return {
featureCatalogue: { ...this.featuresCatalogueRegistry.setup() },
environment: { ...this.environmentService.setup() },
tutorials: { ...this.tutorialService.setup() },
config: this.initializerContext.config.get(),
};
}
@ -50,6 +55,7 @@ export class HomePublicPlugin implements Plugin<HomePublicPluginSetup, HomePubli
capabilities: core.application.capabilities,
}),
},
tutorials: { ...this.tutorialService.start() },
environment: { ...this.environmentService.start() },
};
}
@ -67,8 +73,15 @@ export type EnvironmentSetup = EnvironmentServiceSetup;
/** @public */
export type EnvironmentStart = EnvironmentServiceStart;
/** @public */
export type TutorialSetup = TutorialServiceSetup;
/** @public */
export type TutorialStart = TutorialServiceStart;
/** @public */
export interface HomePublicPluginSetup {
tutorials: TutorialServiceSetup;
featureCatalogue: FeatureCatalogueSetup;
/**
* The environment service is only available for a transition period and will
@ -81,6 +94,7 @@ export interface HomePublicPluginSetup {
/** @public */
export interface HomePublicPluginStart {
tutorials: TutorialServiceStart;
featureCatalogue: FeatureCatalogueStart;
environment: EnvironmentStart;
}

View file

@ -20,15 +20,15 @@
/** @public */
export interface Environment {
/**
* Flag whether the home app should advertize cloud features
* Flag whether the home app should advertise cloud features
*/
readonly cloud: boolean;
/**
* Flag whether the home app should advertize apm features
* Flag whether the home app should advertise apm features
*/
readonly apmUi: boolean;
/**
* Flag whether the home app should advertize ml features
* Flag whether the home app should advertise ml features
*/
readonly ml: boolean;
}

View file

@ -19,3 +19,4 @@
export * from './feature_catalogue';
export * from './environment';
export * from './tutorials';

View file

@ -0,0 +1,25 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
export {
TutorialService,
TutorialVariables,
TutorialServiceSetup,
TutorialServiceStart,
} from './tutorial_service';

View file

@ -0,0 +1,50 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { TutorialService, TutorialServiceSetup, TutorialServiceStart } from './tutorial_service';
const createSetupMock = (): jest.Mocked<TutorialServiceSetup> => {
const setup = {
setVariable: jest.fn(),
};
return setup;
};
const createStartMock = (): jest.Mocked<TutorialServiceStart> => {
const start = {
get: jest.fn(),
};
return start;
};
const createMock = (): jest.Mocked<PublicMethodsOf<TutorialService>> => {
const service = {
setup: jest.fn(),
start: jest.fn(),
};
service.setup.mockImplementation(createSetupMock);
service.start.mockImplementation(createStartMock);
return service;
};
export const tutorialServiceMock = {
createSetup: createSetupMock,
createStart: createStartMock,
create: createMock,
};

View file

@ -0,0 +1,55 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { TutorialService } from './tutorial_service';
describe('TutorialService', () => {
describe('setup', () => {
test('allows multiple set calls', () => {
const setup = new TutorialService().setup();
expect(() => {
setup.setVariable('abc', 123);
setup.setVariable('def', 456);
}).not.toThrow();
});
test('throws when same variable is set twice', () => {
const setup = new TutorialService().setup();
expect(() => {
setup.setVariable('abc', 123);
setup.setVariable('abc', 456);
}).toThrow();
});
});
describe('start', () => {
test('returns empty object', () => {
const service = new TutorialService();
expect(service.start().get()).toEqual({});
});
test('returns last state of update calls', () => {
const service = new TutorialService();
const setup = service.setup();
setup.setVariable('abc', 123);
setup.setVariable('def', { subKey: 456 });
expect(service.start().get()).toEqual({ abc: 123, def: { subKey: 456 } });
});
});
});

View file

@ -0,0 +1,53 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/** @public */
export type TutorialVariables = Partial<Record<string, unknown>>;
export class TutorialService {
private tutorialVariables: TutorialVariables = {};
public setup() {
return {
/**
* Set a variable usable in tutorial templates. Access with `{config.<key>}`.
*/
setVariable: (key: string, value: unknown) => {
if (this.tutorialVariables[key]) {
throw new Error('variable already set');
}
this.tutorialVariables[key] = value;
},
};
}
public start() {
return {
/**
* Retrieve the variables for substitution in tutorials. This API is only intended for internal
* use and is only exposed during a transition period of migrating the home app to the new platform.
* @deprecated
*/
get: (): TutorialVariables => this.tutorialVariables,
};
}
}
export type TutorialServiceSetup = ReturnType<TutorialService['setup']>;
export type TutorialServiceStart = ReturnType<TutorialService['start']>;

View file

@ -31,6 +31,9 @@ export class CloudPlugin implements Plugin<CloudSetup> {
if (home) {
home.environment.update({ cloud: isCloudEnabled });
if (isCloudEnabled) {
home.tutorials.setVariable('cloud', { id });
}
}
return {