diff --git a/packages/kbn-plugin-generator/sao_template/template/index.js b/packages/kbn-plugin-generator/sao_template/template/index.js index 11655cbff1aca56..dd1384815931d6c 100755 --- a/packages/kbn-plugin-generator/sao_template/template/index.js +++ b/packages/kbn-plugin-generator/sao_template/template/index.js @@ -12,9 +12,6 @@ export default function (kibana) { title: '<%= startCase(name) %>', description: '<%= description %>', main: 'plugins/<%= snakeCase(name) %>/app', - <%_ if (generateScss) { -%> - styleSheetPath: require('path').resolve(__dirname, 'public/app.scss'), - <%_ } -%> }, <%_ } -%> <%_ if (generateHack) { -%> @@ -22,6 +19,9 @@ export default function (kibana) { 'plugins/<%= snakeCase(name) %>/hack' ] <%_ } -%> + <%_ if (generateScss) { -%> + styleSheetPath: require('path').resolve(__dirname, 'public/app.scss'), + <%_ } -%> }, config(Joi) { diff --git a/src/core_plugins/kibana/index.js b/src/core_plugins/kibana/index.js index e32a174fcb3e8ba..60441eecb51724c 100644 --- a/src/core_plugins/kibana/index.js +++ b/src/core_plugins/kibana/index.js @@ -66,9 +66,8 @@ export default function (kibana) { listed: false, description: 'the kibana you know and love', main: 'plugins/kibana/kibana', - styleSheetPath: `${__dirname}/public/index.scss`, }, - + styleSheetPath: `${__dirname}/public/index.scss`, links: [ { id: 'kibana:discover', diff --git a/src/core_plugins/status_page/index.js b/src/core_plugins/status_page/index.js index 1bf964d3b1400f2..56d726d4eb8be84 100644 --- a/src/core_plugins/status_page/index.js +++ b/src/core_plugins/status_page/index.js @@ -20,12 +20,12 @@ export default function (kibana) { return new kibana.Plugin({ uiExports: { + styleSheetPath: `${__dirname}/public/index.scss`, app: { title: 'Server Status', main: 'plugins/status_page/status_page', hidden: true, url: '/status', - styleSheetPath: `${__dirname}/public/index.scss` } } }); diff --git a/src/server/sass/build_all.js b/src/server/sass/build_all.js index 7c616ceeb92485c..540c2440c4843b7 100644 --- a/src/server/sass/build_all.js +++ b/src/server/sass/build_all.js @@ -18,16 +18,15 @@ */ import { Build } from './build'; -import { collectUiExports } from '../../ui/ui_exports'; -export async function buildAll(enabledPluginSpecs) { - const { uiAppSpecs = [] } = collectUiExports(enabledPluginSpecs); - const bundles = await Promise.all(uiAppSpecs.map(async uiAppSpec => { - if (!uiAppSpec.styleSheetPath) { +export async function buildAll(styleSheets = []) { + const bundles = await Promise.all(styleSheets.map(async styleSheet => { + + if (!styleSheet.localPath.endsWith('.scss')) { return; } - const bundle = new Build(uiAppSpec.styleSheetPath); + const bundle = new Build(styleSheet.localPath); await bundle.build(); return bundle; diff --git a/src/server/sass/index.js b/src/server/sass/index.js index 5463052e1236aaa..f7c23a4719e0ee9 100644 --- a/src/server/sass/index.js +++ b/src/server/sass/index.js @@ -24,7 +24,6 @@ export async function sassMixin(kbnServer, server, config) { return; } - /** * Build assets * @@ -40,7 +39,7 @@ export async function sassMixin(kbnServer, server, config) { let trackedFiles = new Set(); try { - scssBundles = await buildAll(kbnServer.pluginSpecs); + scssBundles = await buildAll(kbnServer.uiExports.styleSheetPaths); scssBundles.forEach(bundle => { bundle.includedFiles.forEach(file => trackedFiles.add(file)); diff --git a/src/ui/ui_apps/__tests__/ui_app.js b/src/ui/ui_apps/__tests__/ui_app.js index 87b57a556ca4fce..af2a73a23df9bd2 100644 --- a/src/ui/ui_apps/__tests__/ui_app.js +++ b/src/ui/ui_apps/__tests__/ui_app.js @@ -90,10 +90,6 @@ describe('ui apps / UiApp', () => { expect(app.getMainModuleId()).to.be(undefined); }); - it('has no styleSheetPath', () => { - expect(app.getStyleSheetUrlPath()).to.be(undefined); - }); - it('has a mostly empty JSON representation', () => { expect(JSON.parse(JSON.stringify(app))).to.eql({ id: spec.id, @@ -312,15 +308,4 @@ describe('ui apps / UiApp', () => { expect(app.getMainModuleId()).to.be('bar'); }); }); - - describe('#getStyleSheetUrlPath', () => { - it('returns public path to styleSheetPath', () => { - const app = createUiApp( - createStubUiAppSpec({ pluginId: 'foo', id: 'foo', styleSheetPath: '/bar/public/baz/style.scss' }), - createStubKbnServer({ plugins: [{ id: 'foo', publicDir: '/bar/public' }] }) - ); - - expect(app.getStyleSheetUrlPath()).to.eql('plugins/foo/baz/style.css'); - }); - }); }); diff --git a/src/ui/ui_apps/ui_app.js b/src/ui/ui_apps/ui_app.js index a4c1f4a15a27e6a..7aea264ae0e5f2a 100644 --- a/src/ui/ui_apps/ui_app.js +++ b/src/ui/ui_apps/ui_app.js @@ -17,7 +17,6 @@ * under the License. */ -import path from 'path'; import { UiNavLink } from '../ui_nav_links'; export class UiApp { @@ -34,7 +33,6 @@ export class UiApp { linkToLastSubUrl, listed, url = `/app/${id}`, - styleSheetPath, } = spec; if (!id) { @@ -53,7 +51,6 @@ export class UiApp { this._url = url; this._pluginId = pluginId; this._kbnServer = kbnServer; - this._styleSheetPath = styleSheetPath; if (this._pluginId && !this._getPlugin()) { throw new Error(`Unknown plugin id "${this._pluginId}"`); @@ -105,25 +102,6 @@ export class UiApp { return this._main; } - getStyleSheetUrlPath() { - if (!this._styleSheetPath) { - return; - } - - const plugin = this._getPlugin(); - - // get the path of the stylesheet relative to the public dir for the plugin - let relativePath = path.relative(plugin.publicDir, this._styleSheetPath); - - // replace back slashes on windows - relativePath = relativePath.split('\\').join('/'); - - // replace the extension of relativePath to be .css - relativePath = relativePath.slice(0, -path.extname(relativePath).length) + '.css'; - - return `plugins/${plugin.id}/${relativePath}`; - } - _getPlugin() { const pluginId = this._pluginId; const { plugins } = this._kbnServer; @@ -142,7 +120,6 @@ export class UiApp { main: this._main, navLink: this._navLink, linkToLastSubUrl: this._linkToLastSubUrl, - styleSheetPath: this._styleSheetPath, }; } } diff --git a/src/ui/ui_exports/ui_export_defaults.js b/src/ui/ui_exports/ui_export_defaults.js index aa4ef4f5850f7fd..5f401949aaa5154 100644 --- a/src/ui/ui_exports/ui_export_defaults.js +++ b/src/ui/ui_exports/ui_export_defaults.js @@ -37,6 +37,8 @@ export const UI_EXPORT_DEFAULTS = { translationPaths: [], + styleSheetPaths: [], + appExtensions: { fieldFormatEditors: [ 'ui/field_editor/components/field_format_editor/register' diff --git a/src/ui/ui_exports/ui_export_types/index.js b/src/ui/ui_exports/ui_export_types/index.js index d6ebaa649adf8ff..e51d86c00073e42 100644 --- a/src/ui/ui_exports/ui_export_types/index.js +++ b/src/ui/ui_exports/ui_export_types/index.js @@ -66,6 +66,10 @@ export { links, } from './ui_nav_links'; +export { + styleSheetPath +} from './style_sheet_path'; + export { uiSettingDefaults, } from './ui_settings'; diff --git a/src/ui/ui_exports/ui_export_types/style_sheet_path.js b/src/ui/ui_exports/ui_export_types/style_sheet_path.js new file mode 100644 index 000000000000000..f67f7cbeda697f0 --- /dev/null +++ b/src/ui/ui_exports/ui_export_types/style_sheet_path.js @@ -0,0 +1,61 @@ +/* + * 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 path from 'path'; +import { flatConcatAtType } from './reduce'; +import { alias, mapSpec, wrap } from './modify_reduce'; + +const OK_EXTNAMES = ['.css', '.scss']; + +function normalize(localPath, type, pluginSpec) { + const pluginId = pluginSpec.getId(); + + if (!path.isAbsolute(localPath)) { + throw new Error( + `[plugin:${pluginId}] uiExports.styleSheetPath must be an absolute path, got "${localPath}"` + ); + } + + const extname = path.extname(localPath); + + if (!OK_EXTNAMES.includes(extname)) { + throw new Error( + `[plugin:${pluginId}] uiExports.styleSheetPath supported extensions [${OK_EXTNAMES.join(', ')}], got "${extname}"` + ); + } + + // get the path of the stylesheet relative to the public dir for the plugin + let relativePath = path.relative(pluginSpec.getPublicDir(), localPath); + + // replace back slashes on windows + relativePath = relativePath.split('\\').join('/'); + + // replace the extension of relativePath to be .css + // publicPath will always point to the css file + relativePath = relativePath.slice(0, -extname.length) + '.css'; + + const publicPath = `plugins/${pluginSpec.getId()}/${relativePath}`; + + return { + localPath, + publicPath + }; +} + +export const styleSheetPath = wrap(alias('styleSheetPaths'), mapSpec(normalize), flatConcatAtType); \ No newline at end of file diff --git a/src/ui/ui_exports/ui_export_types/ui_apps.js b/src/ui/ui_exports/ui_export_types/ui_apps.js index 3ee874fd5f6299b..56f7a4f5f723771 100644 --- a/src/ui/ui_exports/ui_export_types/ui_apps.js +++ b/src/ui/ui_exports/ui_export_types/ui_apps.js @@ -17,7 +17,6 @@ * under the License. */ -import { isAbsolute, normalize } from 'path'; import { flatConcatAtType } from './reduce'; import { alias, mapSpec, wrap } from './modify_reduce'; @@ -48,14 +47,6 @@ function applySpecDefaults(spec, type, pluginSpec) { ); } - const styleSheetPath = spec.styleSheetPath ? normalize(spec.styleSheetPath) : undefined; - - if (styleSheetPath && (!isAbsolute(styleSheetPath) || !styleSheetPath.startsWith(pluginSpec.getPublicDir()))) { - throw new Error( - `[plugin:${pluginId}] uiExports.app.styleSheetPath must be an absolute path within the public directory` - ); - } - return { pluginId, id, @@ -68,7 +59,6 @@ function applySpecDefaults(spec, type, pluginSpec) { linkToLastSubUrl, listed, url, - styleSheetPath, }; } diff --git a/src/ui/ui_render/bootstrap/template.js.hbs b/src/ui/ui_render/bootstrap/template.js.hbs index ca4501a23eff100..093843eb7488dc4 100644 --- a/src/ui/ui_render/bootstrap/template.js.hbs +++ b/src/ui/ui_render/bootstrap/template.js.hbs @@ -15,9 +15,9 @@ window.onload = function () { createAnchor('{{bundlePath}}/{{appId}}.bundle.js') ]; - if ('{{styleSheetPath}}' !== '') { - files.push(createAnchor('{{styleSheetPath}}')); - } + {{#each styleSheetPaths}} + files.push(createAnchor('{{this}}')); + {{/each}} (function next() { var file = files.shift(); diff --git a/src/ui/ui_render/ui_render_mixin.js b/src/ui/ui_render/ui_render_mixin.js index 5929f5bc0e73c99..42f66e3bcb3352e 100644 --- a/src/ui/ui_render/ui_render_mixin.js +++ b/src/ui/ui_render/ui_render_mixin.js @@ -67,7 +67,7 @@ export function uiRenderMixin(kbnServer, server, config) { templateData: { appId: app.getId(), bundlePath: `${basePath}/bundles`, - styleSheetPath: app.getStyleSheetUrlPath() ? `${basePath}/${app.getStyleSheetUrlPath()}` : null, + styleSheetPaths: kbnServer.uiExports.styleSheetPaths.map(path => `${basePath}/${path.publicPath}`), }, translations: await server.getUiTranslations() }); diff --git a/x-pack/plugins/dashboard_mode/index.js b/x-pack/plugins/dashboard_mode/index.js index 91290401550323b..892b45f7be18b6e 100644 --- a/x-pack/plugins/dashboard_mode/index.js +++ b/x-pack/plugins/dashboard_mode/index.js @@ -25,6 +25,7 @@ export function dashboardMode(kibana) { publicDir: resolve(__dirname, 'public'), require: ['kibana', 'elasticsearch', 'xpack_main'], uiExports: { + styleSheetPath: `${__dirname}/public/index.scss`, uiSettingDefaults: { [CONFIG_DASHBOARD_ONLY_MODE_ROLES]: { name: 'Dashboards only roles', @@ -40,7 +41,6 @@ export function dashboardMode(kibana) { hidden: true, description: 'view dashboards', main: 'plugins/dashboard_mode/dashboard_viewer', - styleSheetPath: `${__dirname}/public/index.scss`, links: [ { id: 'kibana:dashboard', diff --git a/x-pack/plugins/monitoring/ui_exports.js b/x-pack/plugins/monitoring/ui_exports.js index 2d9a4d0d30c72df..2ba9babaae22399 100644 --- a/x-pack/plugins/monitoring/ui_exports.js +++ b/x-pack/plugins/monitoring/ui_exports.js @@ -18,7 +18,6 @@ export const uiExports = { icon: 'plugins/monitoring/icons/monitoring.svg', linkToLastSubUrl: false, main: 'plugins/monitoring/monitoring', - styleSheetPath: `${__dirname}/public/index.scss`, }, injectDefaultVars(server) { const config = server.config(); @@ -27,5 +26,6 @@ export const uiExports = { }; }, hacks: [ 'plugins/monitoring/hacks/toggle_app_link_in_nav' ], - home: [ 'plugins/monitoring/register_feature' ] + home: [ 'plugins/monitoring/register_feature' ], + styleSheetPath: `${__dirname}/public/index.scss`, };