Skip to content

Commit

Permalink
Moves styleSheetPath to uiExports (elastic#23007) (elastic#23385)
Browse files Browse the repository at this point in the history
This was previously defined in uiExports.app, which limited plugins which are not an app of providing a stylesheet. This allows any plugin to define a stylesheet which will be available on page load.
  • Loading branch information
tylersmalley authored Sep 21, 2018
1 parent fe1b90f commit b93b868
Show file tree
Hide file tree
Showing 28 changed files with 253 additions and 162 deletions.
6 changes: 3 additions & 3 deletions packages/kbn-plugin-generator/sao_template/template/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ 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) { -%>
hacks: [
'plugins/<%= snakeCase(name) %>/hack'
]
<%_ } -%>
<%_ if (generateScss) { -%>
styleSheetPaths: require('path').resolve(__dirname, 'public/app.scss'),
<%_ } -%>
},

config(Joi) {
Expand Down
3 changes: 1 addition & 2 deletions src/core_plugins/kibana/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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`,
},

styleSheetPaths: `${__dirname}/public/index.scss`,
links: [
{
id: 'kibana:discover',
Expand Down
4 changes: 2 additions & 2 deletions src/core_plugins/status_page/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export default function (kibana) {
main: 'plugins/status_page/status_page',
hidden: true,
url: '/status',
styleSheetPath: `${__dirname}/public/index.scss`
}
},
styleSheetPaths: `${__dirname}/public/index.scss`,
}
});
}
2 changes: 1 addition & 1 deletion src/core_plugins/status_page/public/index.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@import 'ui/public/styles/styling_constants';

// SASSTODO: Remove when K7 applies background color to body
.stsPage {
#status_page-app .stsPage {
min-height: 100vh;
}
4 changes: 3 additions & 1 deletion src/dev/build/tasks/transpile_scss_task.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import { toArray } from 'rxjs/operators';
import { buildAll } from '../../../server/sass/build_all';
import { findPluginSpecs } from '../../../plugin_discovery/find_plugin_specs';
import { collectUiExports } from '../../../ui/ui_exports/collect_ui_exports';

export const TranspileScssTask = {
description: 'Transpiling SCSS to CSS',
Expand All @@ -30,9 +31,10 @@ export const TranspileScssTask = {

const { spec$ } = findPluginSpecs({ plugins: { scanDirs, paths } });
const enabledPlugins = await spec$.pipe(toArray()).toPromise();
const uiExports = collectUiExports(enabledPlugins);

try {
const bundles = await buildAll(enabledPlugins);
const bundles = await buildAll(uiExports.styleSheetPaths);
bundles.forEach(bundle => log.info(`Compiled SCSS: ${bundle.source}`));
} catch (error) {
const { message, line, file } = error;
Expand Down
11 changes: 5 additions & 6 deletions src/server/sass/build_all.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 1 addition & 2 deletions src/server/sass/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export async function sassMixin(kbnServer, server, config) {
return;
}


/**
* Build assets
*
Expand All @@ -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));
Expand Down
3 changes: 3 additions & 0 deletions src/ui/public/chrome/chrome.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ const waitForBootstrap = new Promise(resolve => {
require('uiExports/chromeNavControls');
require('uiExports/hacks');

// sets attribute on body for stylesheet sandboxing
document.body.setAttribute('id', `${internals.app.id}-app`);

chrome.setupAngular();
targetDomElement.setAttribute('id', 'kibana-body');
targetDomElement.setAttribute('kbn-chrome', 'true');
Expand Down
15 changes: 0 additions & 15 deletions src/ui/ui_apps/__tests__/ui_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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');
});
});
});
23 changes: 0 additions & 23 deletions src/ui/ui_apps/ui_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
* under the License.
*/

import path from 'path';
import { UiNavLink } from '../ui_nav_links';

export class UiApp {
Expand All @@ -34,7 +33,6 @@ export class UiApp {
linkToLastSubUrl,
listed,
url = `/app/${id}`,
styleSheetPath,
} = spec;

if (!id) {
Expand All @@ -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}"`);
Expand Down Expand Up @@ -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;
Expand All @@ -142,7 +120,6 @@ export class UiApp {
main: this._main,
navLink: this._navLink,
linkToLastSubUrl: this._linkToLastSubUrl,
styleSheetPath: this._styleSheetPath,
};
}
}
2 changes: 2 additions & 0 deletions src/ui/ui_exports/ui_export_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export const UI_EXPORT_DEFAULTS = {

translationPaths: [],

styleSheetPaths: [],

appExtensions: {
fieldFormatEditors: [
'ui/field_editor/components/field_format_editor/register'
Expand Down
4 changes: 4 additions & 0 deletions src/ui/ui_exports/ui_export_types/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ export {
links,
} from './ui_nav_links';

export {
styleSheetPaths
} from './style_sheet_paths';

export {
uiSettingDefaults,
} from './ui_settings';
Expand Down
67 changes: 67 additions & 0 deletions src/ui/ui_exports/ui_export_types/style_sheet_paths.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* 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 { mapSpec, wrap } from './modify_reduce';

const OK_EXTNAMES = ['.css', '.scss'];

function normalize(localPath, type, pluginSpec) {
const pluginId = pluginSpec.getId();
const publicDir = pluginSpec.getPublicDir();
const extname = path.extname(localPath);

if (!OK_EXTNAMES.includes(extname)) {
throw new Error(
`[plugin:${pluginId}] uiExports.styleSheetPaths supported extensions [${OK_EXTNAMES.join(', ')}], got "${extname}"`
);
}

if (!path.isAbsolute(localPath)) {
throw new Error(
`[plugin:${pluginId}] uiExports.styleSheetPaths must be an absolute path, got "${localPath}"`
);
}

if (!localPath.startsWith(publicDir)) {
throw new Error(
`[plugin:${pluginId}] uiExports.styleSheetPaths must be child of publicDir [${publicDir}]`
);
}

// get the path of the stylesheet relative to the public dir for the plugin
let relativePath = path.relative(publicDir, 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 styleSheetPaths = wrap(mapSpec(normalize), flatConcatAtType);
60 changes: 60 additions & 0 deletions src/ui/ui_exports/ui_export_types/style_sheet_paths.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* 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 { styleSheetPaths } from './style_sheet_paths';

describe('uiExports.styleSheetPaths', () => {
const pluginSpec = {
getId: () => 'test',
getPublicDir: () => '/kibana/public'
};

it('does not support relative paths', () => {
expect(() => styleSheetPaths([], 'public/bar.css', 'styleSheetPaths', pluginSpec))
.toThrowError('[plugin:test] uiExports.styleSheetPaths must be an absolute path, got "public/bar.css"');
});

it('path must be child of public path', () => {
expect(() => styleSheetPaths([], '/another/public/bar.css', 'styleSheetPaths', pluginSpec))
.toThrowError('[plugin:test] uiExports.styleSheetPaths must be child of publicDir [/kibana/public]');
});

it('only supports css or scss extensions', () => {
expect(() => styleSheetPaths([], '/kibana/public/bar.bad', 'styleSheetPaths', pluginSpec))
.toThrowError('[plugin:test] uiExports.styleSheetPaths supported extensions [.css, .scss], got ".bad"');
});

it('provides publicPath for scss extensions', () => {
const localPath = '/kibana/public/bar.scss';
const uiExports = styleSheetPaths([], localPath, 'styleSheetPaths', pluginSpec);

expect(uiExports.styleSheetPaths).toHaveLength(1);
expect(uiExports.styleSheetPaths[0].localPath).toEqual(localPath);
expect(uiExports.styleSheetPaths[0].publicPath).toEqual('plugins/test/bar.css');
});

it('provides publicPath for css extensions', () => {
const localPath = '/kibana/public/bar.css';
const uiExports = styleSheetPaths([], localPath, 'styleSheetPaths', pluginSpec);

expect(uiExports.styleSheetPaths).toHaveLength(1);
expect(uiExports.styleSheetPaths[0].localPath).toEqual(localPath);
expect(uiExports.styleSheetPaths[0].publicPath).toEqual('plugins/test/bar.css');
});
});
10 changes: 0 additions & 10 deletions src/ui/ui_exports/ui_export_types/ui_apps.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
* under the License.
*/

import { isAbsolute, normalize } from 'path';
import { flatConcatAtType } from './reduce';
import { alias, mapSpec, wrap } from './modify_reduce';

Expand Down Expand Up @@ -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,
Expand All @@ -68,7 +59,6 @@ function applySpecDefaults(spec, type, pluginSpec) {
linkToLastSubUrl,
listed,
url,
styleSheetPath,
};
}

Expand Down
Loading

0 comments on commit b93b868

Please sign in to comment.