From 3556f894f7ec0f6342df698a41d9c2053a2f09a4 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 22 Aug 2018 10:49:07 -0600 Subject: [PATCH 1/3] Pass scoped context to tutorial providers when building tutorials --- .../routes/api/home/register_tutorials.js | 2 +- src/ui/tutorials_mixin.js | 27 ++++-- src/ui/tutorials_mixin.test.js | 86 +++++++++++++++++++ 3 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 src/ui/tutorials_mixin.test.js diff --git a/src/core_plugins/kibana/server/routes/api/home/register_tutorials.js b/src/core_plugins/kibana/server/routes/api/home/register_tutorials.js index c7e0909631eaec..89f1ff6213a14e 100644 --- a/src/core_plugins/kibana/server/routes/api/home/register_tutorials.js +++ b/src/core_plugins/kibana/server/routes/api/home/register_tutorials.js @@ -23,7 +23,7 @@ export function registerTutorials(server) { path: '/api/kibana/home/tutorials', method: ['GET'], handler: async function (req, reply) { - reply(server.getTutorials()); + reply(server.getTutorials(req)); } }); } diff --git a/src/ui/tutorials_mixin.js b/src/ui/tutorials_mixin.js index 7ab14bfc45080d..9a6ff59c13c9aa 100644 --- a/src/ui/tutorials_mixin.js +++ b/src/ui/tutorials_mixin.js @@ -17,24 +17,39 @@ * under the License. */ -import _ from 'lodash'; import Joi from 'joi'; import { tutorialSchema } from '../core_plugins/kibana/common/tutorials/tutorial_schema'; export function tutorialsMixin(kbnServer, server) { - const tutorials = []; + const tutorialProviders = []; + const scopedTutorialContextFactoryies = []; - server.decorate('server', 'getTutorials', () => { - return _.cloneDeep(tutorials); + server.decorate('server', 'getTutorials', (request) => { + return tutorialProviders.map((tutorialProvider) => { + const initialContext = {}; + const scopedContext = scopedTutorialContextFactoryies.reduce((accumulatedContext, contextFactory) => { + return { ...accumulatedContext, ...contextFactory(request) }; + }, initialContext); + return tutorialProvider(server, scopedContext); + }); }); server.decorate('server', 'registerTutorial', (specProvider) => { - const { error, value } = Joi.validate(specProvider(server), tutorialSchema); + const emptyContext = {}; + const { error } = Joi.validate(specProvider(server, emptyContext), tutorialSchema); if (error) { throw new Error(`Unable to register tutorial spec because its invalid. ${error}`); } - tutorials.push(value); + tutorialProviders.push(specProvider); + }); + + server.decorate('server', 'addScopedTutorialContextFactory', (scopedTutorialContextFactory) => { + if (typeof scopedTutorialContextFactory !== 'function') { + throw new Error(`Unable to add scoped(request) context factory because you did not provide a function`); + } + + scopedTutorialContextFactoryies.push(scopedTutorialContextFactory); }); } diff --git a/src/ui/tutorials_mixin.test.js b/src/ui/tutorials_mixin.test.js new file mode 100644 index 00000000000000..b29ff10a4d7981 --- /dev/null +++ b/src/ui/tutorials_mixin.test.js @@ -0,0 +1,86 @@ +/* + * 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 { createServer } from '../test_utils/kbn_server'; + +const validTutorial = { + id: 'spec1', + category: 'other', + name: 'spec1', + shortDescription: 'short description', + longDescription: 'long description', + onPrem: { + instructionSets: [ + { + instructionVariants: [ + { + id: 'instructionVariant1', + instructions: [ + {} + ] + } + ] + } + ] + } +}; + +describe('tutorial mixins', () => { + + let kbnServer; + beforeEach(async () => { + kbnServer = createServer(); + await kbnServer.ready(); + }); + + afterEach(async () => { + await kbnServer.close(); + }); + + describe('scoped context', () => { + + const mockRequest = {}; + const spacesContextFactory = (request) => { + if (request !== mockRequest) { + throw new Error('context factory not called with request object'); + } + return { + spaceId: 'my-space' + }; + }; + const specProvider = (server, context) => { + const tutorial = { ...validTutorial }; + tutorial.shortDescription = `I have been provided with scoped context, spaceId: ${context.spaceId}`; + return tutorial; + }; + beforeEach(async () => { + kbnServer.server.addScopedTutorialContextFactory(spacesContextFactory); + kbnServer.server.registerTutorial(specProvider); + }); + + test('passes scoped context to specProviders', () => { + const tutorials = kbnServer.server.getTutorials(mockRequest); + expect(tutorials.length).toBe(1); + expect(tutorials[0].shortDescription).toBe('I have been provided with scoped context, spaceId: my-space'); + }); + }); + +}); + + From 7a36733b1daa36fce6b8bb477d9a74793910b2ff Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Wed, 22 Aug 2018 11:48:58 -0600 Subject: [PATCH 2/3] only generated scoped context one time --- src/ui/tutorials_mixin.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ui/tutorials_mixin.js b/src/ui/tutorials_mixin.js index 9a6ff59c13c9aa..5f6cabec817f15 100644 --- a/src/ui/tutorials_mixin.js +++ b/src/ui/tutorials_mixin.js @@ -25,11 +25,12 @@ export function tutorialsMixin(kbnServer, server) { const scopedTutorialContextFactoryies = []; server.decorate('server', 'getTutorials', (request) => { + const initialContext = {}; + const scopedContext = scopedTutorialContextFactoryies.reduce((accumulatedContext, contextFactory) => { + return { ...accumulatedContext, ...contextFactory(request) }; + }, initialContext); + return tutorialProviders.map((tutorialProvider) => { - const initialContext = {}; - const scopedContext = scopedTutorialContextFactoryies.reduce((accumulatedContext, contextFactory) => { - return { ...accumulatedContext, ...contextFactory(request) }; - }, initialContext); return tutorialProvider(server, scopedContext); }); }); From c5e75644d988f00fa73d51d22d0d4169ba68662d Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Thu, 23 Aug 2018 07:27:45 -0600 Subject: [PATCH 3/3] spelling --- src/ui/tutorials_mixin.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ui/tutorials_mixin.js b/src/ui/tutorials_mixin.js index 5f6cabec817f15..af3663a83b8121 100644 --- a/src/ui/tutorials_mixin.js +++ b/src/ui/tutorials_mixin.js @@ -22,11 +22,11 @@ import { tutorialSchema } from '../core_plugins/kibana/common/tutorials/tutorial export function tutorialsMixin(kbnServer, server) { const tutorialProviders = []; - const scopedTutorialContextFactoryies = []; + const scopedTutorialContextFactories = []; server.decorate('server', 'getTutorials', (request) => { const initialContext = {}; - const scopedContext = scopedTutorialContextFactoryies.reduce((accumulatedContext, contextFactory) => { + const scopedContext = scopedTutorialContextFactories.reduce((accumulatedContext, contextFactory) => { return { ...accumulatedContext, ...contextFactory(request) }; }, initialContext); @@ -51,6 +51,6 @@ export function tutorialsMixin(kbnServer, server) { throw new Error(`Unable to add scoped(request) context factory because you did not provide a function`); } - scopedTutorialContextFactoryies.push(scopedTutorialContextFactory); + scopedTutorialContextFactories.push(scopedTutorialContextFactory); }); }