mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* add markdown functional test * update markdown vis to use markdown-it * migrate markdown angular filter to markdown-it * place other uses of marked and remove dependency * update breaking changes documenation and set linkify to true
This commit is contained in:
parent
627161ff48
commit
504af4942e
14 changed files with 134 additions and 27 deletions
|
@ -72,3 +72,10 @@ This is no longer the case. Now, only commas are a valid query separator: e.g. `
|
|||
*Details:* Since 4.3, index patterns could be configured to do a pre-flight field_stats request before a search in order to determine exact indices that could contain matching documents. Elasticsearch now optimizes searches internally in a similar way and has also removed the field_stats API, so this option was removed from Kibana entirely.
|
||||
|
||||
*Impact:* No change is required for existing Kibana index patterns. Those previously configured with this option will gracefully use the new Elasticsearch optimizations instead, as will all new index patterns.
|
||||
|
||||
[float]
|
||||
=== Replace markdown parser `marked` with `markdown-it`
|
||||
*Details:* Starting in 6.0.0, Kibana will use `markdown-it` to parse markdown text. Kibana switched to `markdown-it` because `marked` is no longer actively maintained. Markdown-it supports CommonMark and GFM (GitHub Flavored Markdown) Tables and Strikethrough.
|
||||
|
||||
*Impact:* There may be slight changes in parsed markdown. Review markdown as needed.
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@
|
|||
"less": "2.7.1",
|
||||
"less-loader": "2.2.3",
|
||||
"lodash": "3.10.1",
|
||||
"marked": "0.3.6",
|
||||
"markdown-it": "8.3.2",
|
||||
"minimatch": "2.0.10",
|
||||
"mkdirp": "0.5.1",
|
||||
"moment": "2.13.0",
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
ng-model="conf.unsavedValue"
|
||||
ng-keyup="maybeCancel($event, conf)"
|
||||
elastic-textarea
|
||||
data-test-subj="unsavedValueMarkdownTextArea"
|
||||
></textarea>
|
||||
|
||||
<textarea
|
||||
|
@ -170,6 +171,7 @@
|
|||
ng-hide="isDefaultValue(conf)"
|
||||
aria-label="Clear {{conf.ariaName}}"
|
||||
class="kuiMenuButton kuiMenuButton--danger kuiMenuButton--iconText"
|
||||
data-test-subj="advancedSetting-{{conf.name}}-clearButton"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
<div ng-controller="KbnMarkdownVisController" class="markdown-vis">
|
||||
<div ng-bind-html="html" class="markdown-body" ng-style="{'font-size': vis.params.fontSize + 'pt'}" ></div>
|
||||
<div
|
||||
ng-bind-html="html"
|
||||
class="markdown-body"
|
||||
ng-style="{'font-size': vis.params.fontSize + 'pt'}"
|
||||
data-test-subj="markdownBody"
|
||||
></div>
|
||||
</div>
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
import marked from 'marked';
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import 'angular-sanitize';
|
||||
|
||||
marked.setOptions({
|
||||
gfm: true, // Github-flavored markdown
|
||||
sanitize: true // Sanitize HTML tags
|
||||
const markdownIt = new MarkdownIt({
|
||||
html: false,
|
||||
linkify: true
|
||||
});
|
||||
|
||||
|
||||
const module = uiModules.get('kibana/markdown_vis', ['kibana', 'ngSanitize']);
|
||||
module.controller('KbnMarkdownVisController', function ($scope) {
|
||||
$scope.$watch('vis.params.markdown', function (html) {
|
||||
if (html) {
|
||||
$scope.html = marked(html);
|
||||
$scope.html = markdownIt.render(html);
|
||||
}
|
||||
$scope.renderComplete();
|
||||
});
|
||||
|
|
|
@ -11,5 +11,11 @@
|
|||
<input id="markdownVisFontSize" type="range" ng-model="vis.params.fontSize" class="form-control" min="8" max="36" />
|
||||
</div>
|
||||
</div>
|
||||
<textarea id="markdownVisInput" ng-model="vis.params.markdown" class="form-control" rows="20"></textarea>
|
||||
<textarea
|
||||
id="markdownVisInput"
|
||||
ng-model="vis.params.markdown"
|
||||
class="form-control"
|
||||
rows="20"
|
||||
data-test-subj="markdownTextarea"
|
||||
></textarea>
|
||||
</div>
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import marked from 'marked';
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import { uiModules } from 'ui/modules';
|
||||
import 'angular-sanitize';
|
||||
|
||||
marked.setOptions({
|
||||
gfm: true, // GitHub-flavored markdown
|
||||
sanitize: true // Sanitize HTML tags
|
||||
const markdownIt = new MarkdownIt({
|
||||
html: false,
|
||||
linkify: true
|
||||
});
|
||||
|
||||
uiModules
|
||||
.get('kibana', ['ngSanitize'])
|
||||
.filter('markdown', function ($sanitize) {
|
||||
return md => md ? $sanitize(marked(md)) : '';
|
||||
return md => md ? $sanitize(markdownIt.render(md)) : '';
|
||||
});
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
import { uiModules } from 'ui/modules';
|
||||
import _ from 'lodash';
|
||||
import marked from 'marked';
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import { modifyUrl } from 'ui/url';
|
||||
marked.setOptions({
|
||||
gfm: true, // Github-flavored markdown
|
||||
sanitize: true // Sanitize HTML tags
|
||||
|
||||
const markdownIt = new MarkdownIt({
|
||||
html: false,
|
||||
linkify: true
|
||||
});
|
||||
|
||||
uiModules.get('kibana')
|
||||
.service('serviceSettings', function ($http, $sanitize, mapConfig, tilemapsConfig, kbnVersion) {
|
||||
|
||||
|
||||
const attributionFromConfig = $sanitize(marked(tilemapsConfig.deprecated.config.options.attribution || ''));
|
||||
const attributionFromConfig = $sanitize(markdownIt.render(tilemapsConfig.deprecated.config.options.attribution || ''));
|
||||
const tmsOptionsFromConfig = _.assign({}, tilemapsConfig.deprecated.config.options, { attribution: attributionFromConfig });
|
||||
|
||||
const extendUrl = (url, props) => (
|
||||
|
@ -69,7 +70,7 @@ uiModules.get('kibana')
|
|||
const layers = manifest.data.layers.filter(layer => layer.format === 'geojson');
|
||||
layers.forEach((layer) => {
|
||||
layer.url = this._extendUrlWithParams(layer.url);
|
||||
layer.attribution = $sanitize(marked(layer.attribution));
|
||||
layer.attribution = $sanitize(markdownIt.render(layer.attribution));
|
||||
});
|
||||
return layers;
|
||||
});
|
||||
|
@ -93,7 +94,7 @@ uiModules.get('kibana')
|
|||
}
|
||||
|
||||
|
||||
firstService.attribution = $sanitize(marked(firstService.attribution));
|
||||
firstService.attribution = $sanitize(markdownIt.render(firstService.attribution));
|
||||
firstService.subdomains = firstService.subdomains || [];
|
||||
firstService.url = this._extendUrlWithParams(firstService.url);
|
||||
return firstService;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import d3 from 'd3';
|
||||
import _ from 'lodash';
|
||||
import $ from 'jquery';
|
||||
import marked from 'marked';
|
||||
import MarkdownIt from 'markdown-it';
|
||||
import { NoResults } from 'ui/errors';
|
||||
import { Binder } from 'ui/binder';
|
||||
import { VislibLibLayoutLayoutProvider } from './layout/layout';
|
||||
|
@ -11,6 +11,11 @@ import { VislibLibAxisProvider } from './axis/axis';
|
|||
import { VislibGridProvider } from './chart_grid';
|
||||
import { VislibVisualizationsVisTypesProvider } from '../visualizations/vis_types';
|
||||
|
||||
const markdownIt = new MarkdownIt({
|
||||
html: false,
|
||||
linkify: true
|
||||
});
|
||||
|
||||
export function VisHandlerProvider(Private) {
|
||||
const chartTypes = Private(VislibVisualizationsVisTypesProvider);
|
||||
const Layout = Private(VislibLibLayoutLayoutProvider);
|
||||
|
@ -204,7 +209,7 @@ export function VisHandlerProvider(Private) {
|
|||
|
||||
div.append('div').attr('class', 'item bottom');
|
||||
} else {
|
||||
div.append('h4').text(marked.inlineLexer(message, []));
|
||||
div.append('h4').text(markdownIt.renderInline(message));
|
||||
}
|
||||
|
||||
$(this.el).trigger('renderComplete');
|
||||
|
|
|
@ -23,7 +23,7 @@ export default function ({ getService, getPageObjects }) {
|
|||
|
||||
it('should allow setting advanced settings', async function () {
|
||||
await PageObjects.settings.clickKibanaSettings();
|
||||
await PageObjects.settings.setAdvancedSettings('dateFormat:tz', 'America/Phoenix');
|
||||
await PageObjects.settings.setAdvancedSettingsSelect('dateFormat:tz', 'America/Phoenix');
|
||||
const advancedSetting = await PageObjects.settings.getAdvancedSettings('dateFormat:tz');
|
||||
expect(advancedSetting).to.be('America/Phoenix');
|
||||
});
|
||||
|
@ -80,9 +80,24 @@ export default function ({ getService, getPageObjects }) {
|
|||
});
|
||||
});
|
||||
|
||||
describe('notifications:banner', () => {
|
||||
it('Should convert notification banner markdown into HTML', async function () {
|
||||
await PageObjects.settings.clickKibanaSettings();
|
||||
await PageObjects.settings.setAdvancedSettingsInput('notifications:banner', '# Welcome to Kibana', 'unsavedValueMarkdownTextArea');
|
||||
const bannerValue = await PageObjects.settings.getAdvancedSettings('notifications:banner');
|
||||
expect(bannerValue).to.equal('Welcome to Kibana');
|
||||
});
|
||||
|
||||
after('navigate to settings page and clear notifications:banner', async () => {
|
||||
await PageObjects.settings.navigateTo();
|
||||
await PageObjects.settings.clickKibanaSettings();
|
||||
await PageObjects.settings.clearAdvancedSettings('notifications:banner');
|
||||
});
|
||||
});
|
||||
|
||||
after(async function () {
|
||||
await PageObjects.settings.clickKibanaSettings();
|
||||
await PageObjects.settings.setAdvancedSettings('dateFormat:tz', 'UTC');
|
||||
await PageObjects.settings.setAdvancedSettingsSelect('dateFormat:tz', 'UTC');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
34
test/functional/apps/visualize/_markdown_vis.js
Normal file
34
test/functional/apps/visualize/_markdown_vis.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
import expect from 'expect.js';
|
||||
|
||||
export default function ({ getPageObjects }) {
|
||||
const PageObjects = getPageObjects(['common', 'visualize', 'header']);
|
||||
const markdown = `
|
||||
# Heading 1
|
||||
|
||||
<h3>Inline HTML that should not be rendered as html</h3>
|
||||
`;
|
||||
|
||||
describe('visualize app', async () => {
|
||||
before(async function () {
|
||||
await PageObjects.common.navigateToUrl('visualize', 'new');
|
||||
await PageObjects.visualize.clickMarkdownWidget();
|
||||
await PageObjects.visualize.setMarkdownTxt(markdown);
|
||||
await PageObjects.visualize.clickGo();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
});
|
||||
|
||||
describe('markdown vis', async () => {
|
||||
|
||||
it('should render markdown as html', async function () {
|
||||
const h1Txt = await PageObjects.visualize.getMarkdownBodyDescendentText('h1');
|
||||
expect(h1Txt).to.equal('Heading 1');
|
||||
});
|
||||
|
||||
it('should not render html in markdown as html', async function () {
|
||||
const expected = 'Heading 1\n<h3>Inline HTML that should not be rendered as html</h3>';
|
||||
const actual = await PageObjects.visualize.getMarkdownText();
|
||||
expect(actual).to.equal(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -27,6 +27,7 @@ export default function ({ getService, loadTestFile }) {
|
|||
loadTestFile(require.resolve('./_vertical_bar_chart'));
|
||||
loadTestFile(require.resolve('./_heatmap_chart'));
|
||||
loadTestFile(require.resolve('./_point_series_options'));
|
||||
loadTestFile(require.resolve('./_markdown_vis'));
|
||||
loadTestFile(require.resolve('./_shared_item'));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -33,11 +33,16 @@ export function SettingsPageProvider({ getService, getPageObjects }) {
|
|||
}
|
||||
|
||||
async getAdvancedSettings(propertyName) {
|
||||
log.debug('in setAdvancedSettings');
|
||||
log.debug('in getAdvancedSettings');
|
||||
return await testSubjects.getVisibleText(`advancedSetting-${propertyName}-currentValue`);
|
||||
}
|
||||
|
||||
async setAdvancedSettings(propertyName, propertyValue) {
|
||||
async clearAdvancedSettings(propertyName) {
|
||||
await testSubjects.click(`advancedSetting-${propertyName}-clearButton`);
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
}
|
||||
|
||||
async setAdvancedSettingsSelect(propertyName, propertyValue) {
|
||||
await testSubjects.click(`advancedSetting-${propertyName}-editButton`);
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.common.sleep(1000);
|
||||
|
@ -48,6 +53,16 @@ export function SettingsPageProvider({ getService, getPageObjects }) {
|
|||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
}
|
||||
|
||||
async setAdvancedSettingsInput(propertyName, propertyValue, inputSelector) {
|
||||
await testSubjects.click(`advancedSetting-${propertyName}-editButton`);
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
const input = await testSubjects.find(inputSelector);
|
||||
await input.clearValue();
|
||||
await input.type(propertyValue);
|
||||
await testSubjects.click(`advancedSetting-${propertyName}-saveButton`);
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
}
|
||||
|
||||
async toggleAdvancedSettingCheckbox(propertyName) {
|
||||
await testSubjects.click(`advancedSetting-${propertyName}-editButton`);
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
|
|
|
@ -112,6 +112,23 @@ export function VisualizePageProvider({ getService, getPageObjects }) {
|
|||
defaultFindTimeout * 2);
|
||||
}
|
||||
|
||||
async setMarkdownTxt(markdownTxt) {
|
||||
const input = await testSubjects.find('markdownTextarea');
|
||||
await input.clearValue();
|
||||
await input.type(markdownTxt);
|
||||
}
|
||||
|
||||
async getMarkdownText() {
|
||||
const markdownContainer = await testSubjects.find('markdownBody');
|
||||
return markdownContainer.getVisibleText();
|
||||
}
|
||||
|
||||
async getMarkdownBodyDescendentText(selector) {
|
||||
const markdownContainer = await testSubjects.find('markdownBody');
|
||||
const element = await find.descendantDisplayedByCssSelector(selector, markdownContainer);
|
||||
return element.getVisibleText();
|
||||
}
|
||||
|
||||
async setFromTime(timeString) {
|
||||
const input = await find.byCssSelector('input[ng-model="absolute.from"]', defaultFindTimeout * 2);
|
||||
await input.clearValue();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue