[home] display tutorial artifacts (#16000)

* display launch dashboard button at end of add data instructions

* add 'View exported fields' button

* view exported fields open in new tab

* use Writer to avoid modifing global Mustache object
This commit is contained in:
Nathan Reese 2018-01-12 11:18:23 -07:00 committed by GitHub
parent 4b92c7481c
commit 6511fc264f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 95 additions and 6 deletions

View file

@ -15,7 +15,7 @@ const dashboardSchema = Joi.object({
const artifactsSchema = Joi.object({
// Fields present in Elasticsearch documents created by this product.
exportedFields: Joi.object({
documentationUrl: Joi.string()
documentationUrl: Joi.string().required()
}),
// Kibana dashboards created by this product.
dashboards: Joi.array().items(dashboardSchema).required()

View file

@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
import {
KuiBar,
KuiBarSection,
KuiLinkButton,
} from 'ui_framework/components';
import { Instruction } from './instruction';
import { ParameterForm } from './parameter_form';
@ -13,6 +14,10 @@ import {
EuiTab,
EuiSpacer,
EuiSteps,
EuiFlexGroup,
EuiFlexItem,
EuiHorizontalRule,
EuiText,
} from '@elastic/eui';
export class InstructionSet extends React.Component {
@ -143,6 +148,39 @@ export class InstructionSet extends React.Component {
);
}
let launchDashboard;
if (this.props.overviewDashboard) {
launchDashboard = (
<div>
<EuiHorizontalRule />
<EuiFlexGroup justifyContent="spaceBetween" alignItems="flexEnd">
<EuiFlexItem grow={false}>
<EuiText>
<p>
{`Once all steps are completed, you're ready to explore your data`}
</p>
</EuiText>
</EuiFlexItem>
<EuiFlexItem
grow={false}
>
<KuiLinkButton
buttonType="primary"
href={`#/dashboards?title=${this.props.overviewDashboard.title}`}
>
{this.props.overviewDashboard.linkLabel}
</KuiLinkButton>
</EuiFlexItem>
</EuiFlexGroup>
</div>
);
}
return (
<div className="kuiVerticalRhythmLarge">
@ -158,6 +196,8 @@ export class InstructionSet extends React.Component {
{this.renderInstructions()}
{launchDashboard}
</div>
);
}
@ -183,4 +223,8 @@ InstructionSet.propTypes = {
paramValues: PropTypes.object.isRequired,
setParameter: PropTypes.func,
replaceTemplateStrings: PropTypes.func.isRequired,
overviewDashboard: PropTypes.shape({
title: PropTypes.string.isRequired,
linkLabel: PropTypes.string.isRequired,
}),
};

View file

@ -3,11 +3,15 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Content } from './content';
import {
KuiLinkButton,
} from 'ui_framework/components';
import {
EuiImage,
EuiSpacer,
} from '@elastic/eui';
export function Introduction({ description, previewUrl, title }) {
export function Introduction({ description, previewUrl, title, exportedFieldsUrl }) {
let img;
if (previewUrl) {
img = (
@ -21,6 +25,22 @@ export function Introduction({ description, previewUrl, title }) {
/>
);
}
let exportedFields;
if (exportedFieldsUrl) {
exportedFields = (
<div>
<EuiSpacer />
<KuiLinkButton
buttonType="secondary"
href={exportedFieldsUrl}
target="_blank"
rel="noopener noreferrer"
>
View exported fields
</KuiLinkButton>
</div>
);
}
return (
<div className="introduction kuiVerticalRhythm">
<div className="kuiFlexGroup kuiFlexGroup--gutterLarge">
@ -30,6 +50,7 @@ export function Introduction({ description, previewUrl, title }) {
{title}
</h1>
<Content className="kuiVerticalRhythm" text={description}/>
{exportedFields}
</div>
<div className="kuiFlexItem kuiFlexItem--flexGrowZero">
@ -44,5 +65,6 @@ export function Introduction({ description, previewUrl, title }) {
Introduction.propTypes = {
description: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
previewUrl: PropTypes.string
previewUrl: PropTypes.string,
exportedFieldsUrl: PropTypes.string,
};

View file

@ -1,4 +1,4 @@
import Mustache from 'mustache';
import { Writer } from 'mustache';
import chrome from 'ui/chrome';
import { metadata } from 'ui/metadata';
import {
@ -9,6 +9,16 @@ import {
const TEMPLATE_TAGS = ['{', '}'];
// Can not use 'Mustache' since its a global object
const mustacheWriter = new Writer();
// do not html escape output
mustacheWriter.escapedValue = function escapedValue(token, context) {
const value = context.lookup(token[1]);
if (value != null) {
return value;
}
};
export function replaceTemplateStrings(text, params = {}) {
const variables = {
config: {
@ -30,6 +40,6 @@ export function replaceTemplateStrings(text, params = {}) {
},
params: params
};
Mustache.parse(text, TEMPLATE_TAGS);
return Mustache.render(text, variables);
mustacheWriter.parse(text, TEMPLATE_TAGS);
return mustacheWriter.render(text, variables);
}

View file

@ -126,6 +126,12 @@ export class Tutorial extends React.Component {
}
renderInstructionSets = (instructions) => {
let overviewDashboard;
if (_.has(this.state, 'tutorial.artifacts.dashboards')) {
overviewDashboard = this.state.tutorial.artifacts.dashboards.find(dashboard => {
return dashboard.isOverview;
});
}
let offset = 1;
return instructions.instructionSets.map((instructionSet, index) => {
const currentOffset = offset;
@ -139,6 +145,7 @@ export class Tutorial extends React.Component {
paramValues={this.state.paramValues}
setParameter={this.setParameter}
replaceTemplateStrings={this.props.replaceTemplateStrings}
overviewDashboard={overviewDashboard}
key={index}
/>
);
@ -163,6 +170,11 @@ export class Tutorial extends React.Component {
previewUrl = this.props.addBasePath(this.state.tutorial.previewImagePath);
}
let exportedFieldsUrl;
if (_.has(this.state, 'tutorial.artifacts.exportedFields')) {
exportedFieldsUrl = this.props.replaceTemplateStrings(this.state.tutorial.artifacts.exportedFields.documentationUrl);
}
const instructions = this.getInstructions();
content = (
<div>
@ -170,6 +182,7 @@ export class Tutorial extends React.Component {
title={this.state.tutorial.name}
description={this.props.replaceTemplateStrings(this.state.tutorial.longDescription)}
previewUrl={previewUrl}
exportedFieldsUrl={exportedFieldsUrl}
/>
<div className="text-center kuiVerticalRhythm">