[home] Include ability to publish kibana saved objects from add data tutorial (#19559) (#20939)

* add savedObjects to tutorial schema, add savedObjects to APM, add bulk create endpoint

* SavedObjectInstaller component

* bulkCreate fixes

* fix tutorial jest test

* update from sqren review

* updated copy

* move saved object json into seperate json files

* minor commit clean up

* ensure isMounted before setting state after async call, allow manifest to customize saved object install message

* remove duplicated logic for getting config xpack.apm.indexPattern

* refactor get index pattern title

* add functional test that loads APM saved objects

* remove extra await

* display overwrite message

* use angular free savedObjectClient

* functional test cleanup

* handle bulkRequest exception and add jest tests for SavedObjectsInstaller

* use Promise.reject instead of throw

* update copy
This commit is contained in:
Nathan Reese 2018-07-18 12:17:54 -06:00 committed by GitHub
parent 0b39582294
commit fe2f671d0a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 1218 additions and 18 deletions

View file

@ -109,4 +109,8 @@ export const tutorialSchema = {
// Elastic stack artifacts produced by product when it is setup and run.
artifacts: artifactsSchema,
// saved objects used by data module.
savedObjects: Joi.array().items(),
savedObjectsInstallMsg: Joi.string(),
};

View file

@ -40,6 +40,7 @@ export function HomeApp({
getConfig,
setConfig,
clearIndexPatternsCache,
bulkCreate,
}) {
const isCloudEnabled = chrome.getInjected('isCloudEnabled', false);
@ -66,6 +67,7 @@ export function HomeApp({
getTutorial={getTutorial}
replaceTemplateStrings={replaceTemplateStrings}
tutorialId={props.match.params.id}
bulkCreate={bulkCreate}
/>
);
};
@ -119,4 +121,5 @@ HomeApp.propTypes = {
getConfig: PropTypes.func.isRequired,
setConfig: PropTypes.func.isRequired,
clearIndexPatternsCache: PropTypes.func.isRequired,
bulkCreate: PropTypes.func.isRequired,
};

View file

@ -0,0 +1,531 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`bulkCreate should display error message when bulkCreate request fails 1`] = `
<SavedObjectsInstaller
bulkCreate={[Function]}
savedObjects={
Array [
Object {
"attributes": Object {},
"id": "1",
"type": "index-pattern",
},
]
}
>
<EuiSteps
firstStepNumber={1}
headingElement="p"
steps={
Array [
Object {
"children": <UNDEFINED>
<EuiFlexGroup
alignItems="center"
component="div"
direction="row"
gutterSize="l"
justifyContent="spaceBetween"
responsive={true}
wrap={false}
>
<EuiFlexItem
component="div"
grow={true}
>
<EuiText
grow={true}
>
<p>
Imports index pattern, visualizations and pre-defined dashboards.
</p>
</EuiText>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={false}
>
<EuiButton
color="primary"
data-test-subj="loadSavedObjects"
fill={false}
iconSide="left"
isLoading={false}
onClick={[Function]}
type="button"
>
Load Kibana objects
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer
size="s"
/>
<EuiCallOut
color="warning"
data-test-subj="loadSavedObjects_failed"
size="m"
title="Request failed, Error: simulated bulkRequest error"
/>
</UNDEFINED>,
"key": "installStep",
"status": "incomplete",
"title": "Load Kibana objects",
},
]
}
>
<div
className="euiSteps"
>
<EuiStep
headingElement="p"
key="installStep"
status="incomplete"
step={1}
title="Load Kibana objects"
>
<div
className="euiStep"
>
<EuiScreenReaderOnly>
<span
className="euiScreenReaderOnly"
>
Step
</span>
</EuiScreenReaderOnly>
<div
className="euiStep__circle euiStep__circle--incomplete"
/>
<EuiTitle
className="euiStep__title"
size="s"
>
<p
className="euiTitle euiTitle--small euiStep__title"
>
Load Kibana objects
</p>
</EuiTitle>
<div
className="euiStep__content"
>
<EuiFlexGroup
alignItems="center"
component="div"
direction="row"
gutterSize="l"
justifyContent="spaceBetween"
responsive={true}
wrap={false}
>
<div
className="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--alignItemsCenter euiFlexGroup--justifyContentSpaceBetween euiFlexGroup--directionRow euiFlexGroup--responsive"
>
<EuiFlexItem
component="div"
grow={true}
>
<div
className="euiFlexItem"
>
<EuiText
grow={true}
>
<div
className="euiText"
>
<p>
Imports index pattern, visualizations and pre-defined dashboards.
</p>
</div>
</EuiText>
</div>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={false}
>
<div
className="euiFlexItem euiFlexItem--flexGrowZero"
>
<EuiButton
color="primary"
data-test-subj="loadSavedObjects"
fill={false}
iconSide="left"
isLoading={false}
onClick={[Function]}
type="button"
>
<button
className="euiButton euiButton--primary"
data-test-subj="loadSavedObjects"
onClick={[Function]}
type="button"
>
<span
className="euiButton__content"
>
<span
className="euiButton__text"
>
Load Kibana objects
</span>
</span>
</button>
</EuiButton>
</div>
</EuiFlexItem>
</div>
</EuiFlexGroup>
<EuiSpacer
size="s"
>
<div
className="euiSpacer euiSpacer--s"
/>
</EuiSpacer>
<EuiCallOut
color="warning"
data-test-subj="loadSavedObjects_failed"
size="m"
title="Request failed, Error: simulated bulkRequest error"
>
<div
className="euiCallOut euiCallOut--warning"
data-test-subj="loadSavedObjects_failed"
>
<div
className="euiCallOutHeader"
>
<span
className="euiCallOutHeader__title"
>
Request failed, Error: simulated bulkRequest error
</span>
</div>
</div>
</EuiCallOut>
</div>
</div>
</EuiStep>
</div>
</EuiSteps>
</SavedObjectsInstaller>
`;
exports[`bulkCreate should display success message when bulkCreate is successful 1`] = `
<SavedObjectsInstaller
bulkCreate={[Function]}
savedObjects={
Array [
Object {
"attributes": Object {},
"id": "1",
"type": "index-pattern",
},
]
}
>
<EuiSteps
firstStepNumber={1}
headingElement="p"
steps={
Array [
Object {
"children": <UNDEFINED>
<EuiFlexGroup
alignItems="center"
component="div"
direction="row"
gutterSize="l"
justifyContent="spaceBetween"
responsive={true}
wrap={false}
>
<EuiFlexItem
component="div"
grow={true}
>
<EuiText
grow={true}
>
<p>
Imports index pattern, visualizations and pre-defined dashboards.
</p>
</EuiText>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={false}
>
<EuiButton
color="primary"
data-test-subj="loadSavedObjects"
fill={false}
iconSide="left"
isLoading={false}
onClick={[Function]}
type="button"
>
Load Kibana objects
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer
size="s"
/>
<EuiCallOut
color="success"
data-test-subj="loadSavedObjects_success"
size="m"
title="1 saved objects successfully added"
/>
</UNDEFINED>,
"key": "installStep",
"status": "complete",
"title": "Load Kibana objects",
},
]
}
>
<div
className="euiSteps"
>
<EuiStep
headingElement="p"
key="installStep"
status="complete"
step={1}
title="Load Kibana objects"
>
<div
className="euiStep"
>
<EuiScreenReaderOnly>
<span
className="euiScreenReaderOnly"
>
Step
</span>
</EuiScreenReaderOnly>
<div
className="euiStep__circle euiStep__circle--complete"
>
<EuiIcon
className="euiStep__circleIcon"
color="ghost"
size="m"
type="check"
>
<check
className="euiIcon euiIcon--medium euiIcon--ghost euiStep__circleIcon"
focusable="false"
height="16"
style={null}
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
>
<svg
className="euiIcon euiIcon--medium euiIcon--ghost euiStep__circleIcon"
focusable="false"
height="16"
style={null}
viewBox="0 0 16 16"
width="16"
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
>
<defs>
<path
d="M6.5 12a.502.502 0 0 1-.354-.146l-4-4a.502.502 0 0 1 .708-.708L6.5 10.793l6.646-6.647a.502.502 0 0 1 .708.708l-7 7A.502.502 0 0 1 6.5 12"
id="check-a"
/>
</defs>
<use
xlinkHref="#check-a"
/>
</svg>
</check>
</EuiIcon>
</div>
<EuiTitle
className="euiStep__title"
size="s"
>
<p
className="euiTitle euiTitle--small euiStep__title"
>
Load Kibana objects
</p>
</EuiTitle>
<div
className="euiStep__content"
>
<EuiFlexGroup
alignItems="center"
component="div"
direction="row"
gutterSize="l"
justifyContent="spaceBetween"
responsive={true}
wrap={false}
>
<div
className="euiFlexGroup euiFlexGroup--gutterLarge euiFlexGroup--alignItemsCenter euiFlexGroup--justifyContentSpaceBetween euiFlexGroup--directionRow euiFlexGroup--responsive"
>
<EuiFlexItem
component="div"
grow={true}
>
<div
className="euiFlexItem"
>
<EuiText
grow={true}
>
<div
className="euiText"
>
<p>
Imports index pattern, visualizations and pre-defined dashboards.
</p>
</div>
</EuiText>
</div>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={false}
>
<div
className="euiFlexItem euiFlexItem--flexGrowZero"
>
<EuiButton
color="primary"
data-test-subj="loadSavedObjects"
fill={false}
iconSide="left"
isLoading={false}
onClick={[Function]}
type="button"
>
<button
className="euiButton euiButton--primary"
data-test-subj="loadSavedObjects"
onClick={[Function]}
type="button"
>
<span
className="euiButton__content"
>
<span
className="euiButton__text"
>
Load Kibana objects
</span>
</span>
</button>
</EuiButton>
</div>
</EuiFlexItem>
</div>
</EuiFlexGroup>
<EuiSpacer
size="s"
>
<div
className="euiSpacer euiSpacer--s"
/>
</EuiSpacer>
<EuiCallOut
color="success"
data-test-subj="loadSavedObjects_success"
size="m"
title="1 saved objects successfully added"
>
<div
className="euiCallOut euiCallOut--success"
data-test-subj="loadSavedObjects_success"
>
<div
className="euiCallOutHeader"
>
<span
className="euiCallOutHeader__title"
>
1 saved objects successfully added
</span>
</div>
</div>
</EuiCallOut>
</div>
</div>
</EuiStep>
</div>
</EuiSteps>
</SavedObjectsInstaller>
`;
exports[`renders 1`] = `
<EuiSteps
firstStepNumber={1}
headingElement="p"
steps={
Array [
Object {
"children": <UNDEFINED>
<EuiFlexGroup
alignItems="center"
component="div"
direction="row"
gutterSize="l"
justifyContent="spaceBetween"
responsive={true}
wrap={false}
>
<EuiFlexItem
component="div"
grow={true}
>
<EuiText
grow={true}
>
<p>
Imports index pattern, visualizations and pre-defined dashboards.
</p>
</EuiText>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={false}
>
<EuiButton
color="primary"
data-test-subj="loadSavedObjects"
fill={false}
iconSide="left"
isLoading={false}
onClick={[Function]}
type="button"
>
Load Kibana objects
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer
size="s"
/>
</UNDEFINED>,
"key": "installStep",
"status": "incomplete",
"title": "Load Kibana objects",
},
]
}
/>
`;

View file

@ -0,0 +1,184 @@
/*
* 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 React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import {
EuiSteps,
EuiFlexGroup,
EuiFlexItem,
EuiText,
EuiButton,
EuiSpacer,
EuiCallOut,
} from '@elastic/eui';
const DEFAULT_BUTTON_LABEL = 'Load Kibana objects';
export class SavedObjectsInstaller extends React.Component {
state = {
isInstalling: false,
isInstalled: false,
overwrite: false,
buttonLabel: DEFAULT_BUTTON_LABEL,
};
componentDidMount() {
this._isMounted = true;
}
componentWillUnmount() {
this._isMounted = false;
}
installSavedObjects = async () => {
this.setState({
isInstalling: true,
});
let resp;
try {
resp = await this.props.bulkCreate(this.props.savedObjects, { overwrite: this.state.overwrite });
} catch (error) {
if (!this._isMounted) {
return;
}
this.setState({
isInstalling: false,
installStatusMsg: `Request failed, Error: ${error.message}`,
isInstalled: false,
overwrite: false,
buttonLabel: DEFAULT_BUTTON_LABEL
});
return;
}
if (!this._isMounted) {
return;
}
const errors = resp.savedObjects.filter(savedObject => {
return savedObject.hasOwnProperty('error');
});
const overwriteErrors = errors.filter(savedObject => {
return savedObject.error.statusCode === 409;
});
if (overwriteErrors.length > 0) {
this.setState({
isInstalling: false,
installStatusMsg: `${overwriteErrors.length} of ${this.props.savedObjects.length} objects already exist. ` +
`Click 'Confirm overwrite' to import and overwrite existing objects. ` +
`Any changes to the objects will be lost.`,
isInstalled: false,
overwrite: true,
buttonLabel: 'Confirm overwrite'
});
return;
}
const hasErrors = errors.length > 0;
const statusMsg = hasErrors
? `Unable to add ${errors.length} of ${this.props.savedObjects.length} kibana objects, Error: ${errors[0].error.message}`
: `${this.props.savedObjects.length} saved objects successfully added`;
this.setState({
isInstalling: false,
installStatusMsg: statusMsg,
isInstalled: !hasErrors,
overwrite: false,
buttonLabel: DEFAULT_BUTTON_LABEL,
});
}
renderInstallMessage() {
if (!this.state.installStatusMsg) {
return;
}
return (
<EuiCallOut
title={this.state.installStatusMsg}
color={this.state.isInstalled ? 'success' : 'warning'}
data-test-subj={this.state.isInstalled ? 'loadSavedObjects_success' : 'loadSavedObjects_failed'}
/>
);
}
renderInstallStep = () => {
const installMsg = this.props.installMsg
? this.props.installMsg
: 'Imports index pattern, visualizations and pre-defined dashboards.';
const installStep = (
<Fragment>
<EuiFlexGroup justifyContent="spaceBetween" alignItems="center">
<EuiFlexItem>
<EuiText>
<p>{installMsg}</p>
</EuiText>
</EuiFlexItem>
<EuiFlexItem
grow={false}
>
<EuiButton
onClick={this.installSavedObjects}
isLoading={this.state.isInstalling}
data-test-subj="loadSavedObjects"
>
{this.state.buttonLabel}
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
{this.renderInstallMessage()}
</Fragment>
);
return {
title: 'Load Kibana objects',
status: this.state.isInstalled ? 'complete' : 'incomplete',
children: installStep,
key: 'installStep'
};
}
render() {
return (
<EuiSteps
steps={[this.renderInstallStep()]}
/>
);
}
}
const savedObjectShape = PropTypes.shape({
id: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
attributes: PropTypes.object.isRequired,
});
SavedObjectsInstaller.propTypes = {
bulkCreate: PropTypes.func.isRequired,
savedObjects: PropTypes.arrayOf(savedObjectShape).isRequired,
installMsg: PropTypes.string,
};

View file

@ -0,0 +1,79 @@
/*
* 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 React from 'react';
import { shallow, mount } from 'enzyme';
import { findTestSubject } from '@elastic/eui/lib/test';
import { SavedObjectsInstaller } from './saved_objects_installer';
test('renders', () => {
const component = shallow(<SavedObjectsInstaller
bulkCreate={() => {}}
savedObjects={[]}
/>);
expect(component).toMatchSnapshot();
});
describe('bulkCreate', () => {
const savedObject = {
id: '1',
type: 'index-pattern',
attributes: {}
};
test('should display success message when bulkCreate is successful', async () => {
const bulkCreateMock = () => {
return Promise.resolve({
savedObjects: [savedObject]
});
};
const component = mount(<SavedObjectsInstaller
bulkCreate={bulkCreateMock}
savedObjects={[savedObject]}
/>);
findTestSubject(component, 'loadSavedObjects').simulate('click');
// Ensure all promises resolve
await new Promise(resolve => process.nextTick(resolve));
// Ensure the state changes are reflected
component.update();
expect(component).toMatchSnapshot();
});
test('should display error message when bulkCreate request fails', async () => {
const bulkCreateMock = () => {
return Promise.reject(new Error('simulated bulkRequest error'));
};
const component = mount(<SavedObjectsInstaller
bulkCreate={bulkCreateMock}
savedObjects={[savedObject]}
/>);
findTestSubject(component, 'loadSavedObjects').simulate('click');
// Ensure all promises resolve
await new Promise(resolve => process.nextTick(resolve));
// Ensure the state changes are reflected
component.update();
expect(component).toMatchSnapshot();
});
});

View file

@ -25,6 +25,7 @@ import { Footer } from './footer';
import { Introduction } from './introduction';
import { InstructionSet } from './instruction_set';
import { RadioButtonGroup } from './radio_button_group';
import { SavedObjectsInstaller } from './saved_objects_installer';
import { EuiSpacer, EuiPage, EuiPanel, EuiLink, EuiText, EuiPageBody } from '@elastic/eui';
import * as StatusCheckStates from './status_check_states';
@ -235,6 +236,21 @@ export class Tutorial extends React.Component {
});
};
renderSavedObjectsInstaller = () => {
if (!this.state.tutorial.savedObjects) {
return;
}
return (
<SavedObjectsInstaller
bulkCreate={this.props.bulkCreate}
savedObjects={this.state.tutorial.savedObjects}
installMsg={this.state.tutorial.savedObjectsInstallMsg}
/>
);
}
renderFooter = () => {
let label;
let url;
@ -306,6 +322,7 @@ export class Tutorial extends React.Component {
<EuiSpacer />
<EuiPanel paddingSize="l">
{this.renderInstructionSets(instructions)}
{this.renderSavedObjectsInstaller()}
{this.renderFooter()}
</EuiPanel>
</div>
@ -333,4 +350,5 @@ Tutorial.propTypes = {
getTutorial: PropTypes.func.isRequired,
replaceTemplateStrings: PropTypes.func.isRequired,
tutorialId: PropTypes.string.isRequired,
bulkCreate: PropTypes.func.isRequired,
};

View file

@ -72,6 +72,7 @@ describe('isCloudEnabled is false', () => {
getTutorial={getTutorial}
replaceTemplateStrings={replaceTemplateStrings}
tutorialId={'my_testing_tutorial'}
bulkCreate={() => {}}
/>);
loadTutorialPromise.then(() => {
component.update();
@ -95,6 +96,7 @@ describe('isCloudEnabled is false', () => {
getTutorial={getBasicTutorial}
replaceTemplateStrings={replaceTemplateStrings}
tutorialId={'my_testing_tutorial'}
bulkCreate={() => {}}
/>);
loadBasicTutorialPromise.then(() => {
component.update();
@ -109,6 +111,7 @@ describe('isCloudEnabled is false', () => {
getTutorial={getTutorial}
replaceTemplateStrings={replaceTemplateStrings}
tutorialId={'my_testing_tutorial'}
bulkCreate={() => {}}
/>);
loadTutorialPromise.then(() => {
component.update();
@ -126,6 +129,7 @@ test('should render ELASTIC_CLOUD instructions when isCloudEnabled is true', ()
getTutorial={getTutorial}
replaceTemplateStrings={replaceTemplateStrings}
tutorialId={'my_testing_tutorial'}
bulkCreate={() => {}}
/>);
loadTutorialPromise.then(() => {
component.update();

View file

@ -5,4 +5,5 @@
get-config="getConfig"
set-config="setConfig"
clear-index-patterns-cache="clearIndexPatternsCache"
bulk-create="bulkCreate"
/>

View file

@ -49,6 +49,7 @@ function getRoute() {
const getter = indexPatterns.getIds;
getter.clearCache();
};
$scope.bulkCreate = chrome.getSavedObjectsClient().bulkCreate;
}
};
}

View file

@ -20,19 +20,32 @@
import { TUTORIAL_CATEGORY } from '../../../common/tutorials/tutorial_category';
import { onPremInstructions } from './on_prem';
import { ELASTIC_CLOUD_INSTRUCTIONS } from './elastic_cloud';
import { getSavedObjects } from './saved_objects/get_saved_objects';
const apmIntro = 'Collect in-depth performance metrics and errors from inside your applications.';
function isEnabled(config, key) {
try {
return config.get(key);
} catch (err) {
return false;
const ENABLED_KEY = 'xpack.apm.ui.enabled';
function isEnabled(config) {
if (config.has(ENABLED_KEY)) {
return config.get(ENABLED_KEY);
}
return false;
}
const TITLE_KEY = 'xpack.apm.indexPattern';
const DEFAULT_TITLE = 'apm*';
function getIndexPatternTitle(config) {
if (config.has(TITLE_KEY)) {
return config.get(TITLE_KEY);
}
return DEFAULT_TITLE;
}
export function apmSpecProvider(server) {
const config = server.config();
const apmIndexPattern = getIndexPatternTitle(config);
const artifacts = {
dashboards: [
@ -43,7 +56,7 @@ export function apmSpecProvider(server) {
}
]
};
if (isEnabled(config, 'xpack.apm.ui.enabled')) {
if (isEnabled(config)) {
artifacts.application = {
path: '/app/apm',
label: 'Launch APM'
@ -61,8 +74,11 @@ export function apmSpecProvider(server) {
' [Learn more]({config.docs.base_url}guide/en/apm/get-started/{config.docs.version}/index.html).',
euiIconType: 'apmApp',
artifacts: artifacts,
onPrem: onPremInstructions(server),
onPrem: onPremInstructions(apmIndexPattern),
elasticCloud: ELASTIC_CLOUD_INSTRUCTIONS,
previewImagePath: '/plugins/kibana/home/tutorial_resources/apm/apm.png',
savedObjects: getSavedObjects(apmIndexPattern),
savedObjectsInstallMsg: 'Load index pattern, visualizations, and pre-defined dashboards.' +
' An index pattern is required for some features in the APM UI.',
};
}

View file

@ -38,14 +38,7 @@ import {
JAVA_CLIENT_INSTRUCTIONS,
} from './apm_client_instructions';
export function onPremInstructions(server) {
let apmIndexPattern = 'apm*';
try {
apmIndexPattern = server.config().get('xpack.apm.indexPattern');
} catch (error) {
// ignore error when config does not contain 'xpack.apm.indexPattern'.
// This is expected when APM plugin is not running.
}
export function onPremInstructions(apmIndexPattern) {
return {
instructionSets: [

View file

@ -0,0 +1,30 @@
/*
* 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 indexPattern from './index_pattern.json';
import staticSavedObjects from './saved_objects.json';
function getIndexPattern(apmIndexPattern) {
indexPattern.attributes.title = apmIndexPattern;
return indexPattern;
}
export function getSavedObjects(server) {
return [getIndexPattern(server), ...staticSavedObjects];
}

View file

@ -0,0 +1,32 @@
/*
* 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 expect from 'expect.js';
import { getSavedObjects } from './get_saved_objects';
const indexPatternTitle = 'dynamic index pattern title';
test('should dynamically set index title to "xpack.apm.indexPattern" yaml config value', () => {
const savedObjects = getSavedObjects(indexPatternTitle);
const indexPattern = savedObjects[0];
expect(indexPattern.type).to.be('index-pattern');
// if index pattern id changes, ensure other saved objects point to the new id
expect(indexPattern.id).to.be('12e52550-6354-11e8-9d01-ed6a4badd083');
expect(indexPattern.attributes.title).to.be(indexPatternTitle);
});

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,262 @@
[
{
"id": "1ffc5e20-7827-11e7-8c47-65b845b5cfb3",
"type": "visualization",
"version": 1,
"attributes": {
"title": "Services [APM]",
"visState": "{\"title\":\"Services [APM]\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMeticsAtAllLevels\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"showTotal\":false,\"totalFunc\":\"sum\"},\"aggs\":[{\"id\":\"1\",\"enabled\":true,\"type\":\"avg\",\"schema\":\"metric\",\"params\":{\"field\":\"transaction.duration.us\",\"customLabel\":\"Avg. Resp. Time\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"percentiles\",\"schema\":\"metric\",\"params\":{\"field\":\"transaction.duration.us\",\"percents\":[95],\"customLabel\":\"Resp. Time\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"cardinality\",\"schema\":\"metric\",\"params\":{\"field\":\"transaction.id\",\"customLabel\":\"Total Transactions\"}},{\"id\":\"6\",\"enabled\":true,\"type\":\"cardinality\",\"schema\":\"metric\",\"params\":{\"field\":\"error.id\",\"customLabel\":\"Errors\"}},{\"id\":\"5\",\"enabled\":true,\"type\":\"top_hits\",\"schema\":\"metric\",\"params\":{\"field\":\"view errors\",\"aggregate\":\"concat\",\"size\":1,\"sortField\":\"@timestamp\",\"sortOrder\":\"desc\",\"customLabel\":\"-\"}},{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"context.service.name\",\"size\":1000,\"order\":\"desc\",\"orderBy\":\"1\"}}]}",
"uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"12e52550-6354-11e8-9d01-ed6a4badd083\",\"filter\":[],\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
}
}
},
{
"id": "1bdca740-7828-11e7-8c47-65b845b5cfb3",
"type": "visualization",
"version": 2,
"attributes": {
"title": "Top Services by Response Time [APM]",
"visState": "{\"title\":\"Top Services by Response Time [APM]\",\"type\":\"metrics\",\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(0,156,224,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"avg\",\"field\":\"transaction.duration.us\"}],\"seperate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"us,ms,0\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":1,\"fill\":\"0\",\"stacked\":\"none\",\"terms_field\":\"context.service.name\",\"value_template\":\"{{value}} ms\",\"split_color_mode\":\"gradient\",\"terms_order_by\":\"61ca57f2-469d-11e7-af02-69e470af7417\"}],\"time_field\":\"@timestamp\",\"interval\":\">=1m\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1},\"aggs\":[]}",
"uiStateJSON": "{}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"12e52550-6354-11e8-9d01-ed6a4badd083\",\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
}
}
},
{
"id": "804ffc40-7828-11e7-8c47-65b845b5cfb3",
"type": "visualization",
"version": 1,
"attributes": {
"title": "Top Services by Request Per Minute [APM]",
"visState": "{\"title\":\"Top Apps by Request Per Minute [APM]\",\"type\":\"metrics\",\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(0,156,224,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"},{\"id\":\"3fcaa6c0-7828-11e7-bb25-2ff6dee07a1b\",\"type\":\"cumulative_sum\",\"field\":\"61ca57f2-469d-11e7-af02-69e470af7417\"},{\"unit\":\"1m\",\"id\":\"467f1cd0-7828-11e7-bb25-2ff6dee07a1b\",\"type\":\"derivative\",\"field\":\"3fcaa6c0-7828-11e7-bb25-2ff6dee07a1b\"},{\"unit\":\"\",\"id\":\"4bd1b8f0-7828-11e7-bb25-2ff6dee07a1b\",\"type\":\"positive_only\",\"field\":\"467f1cd0-7828-11e7-bb25-2ff6dee07a1b\"}],\"seperate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":1,\"fill\":\"0\",\"stacked\":\"none\",\"terms_field\":\"context.service.name\",\"terms_order_by\":\"_count\",\"value_template\":\"{{value}} rpm\"}],\"time_field\":\"@timestamp\",\"interval\":\">=1m\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1},\"aggs\":[]}",
"uiStateJSON": "{}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"12e52550-6354-11e8-9d01-ed6a4badd083\",\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
}
}
},
{
"id": "8d3ed660-7828-11e7-8c47-65b845b5cfb3",
"type": "dashboard",
"version": 1,
"attributes": {
"title": "[APM] Services",
"hits": 0,
"description": "",
"panelsJSON": "[{\"col\":1,\"id\":\"1ffc5e20-7827-11e7-8c47-65b845b5cfb3\",\"panelIndex\":1,\"row\":4,\"size_x\":12,\"size_y\":5,\"type\":\"visualization\"},{\"col\":1,\"id\":\"1bdca740-7828-11e7-8c47-65b845b5cfb3\",\"panelIndex\":2,\"row\":1,\"size_x\":6,\"size_y\":3,\"type\":\"visualization\"},{\"col\":7,\"id\":\"804ffc40-7828-11e7-8c47-65b845b5cfb3\",\"panelIndex\":3,\"row\":1,\"size_x\":6,\"size_y\":3,\"type\":\"visualization\"}]",
"optionsJSON": "{\"darkTheme\":false}",
"uiStateJSON": "{\"P-1\":{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}}",
"version": 1,
"timeRestore": false,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[],\"highlightAll\":true,\"version\":true}"
}
}
},
{
"id": "c618e4e0-7c69-11e7-aa55-3b0d52c71c60",
"type": "visualization",
"version": 1,
"attributes": {
"title": "Error Occurrences [APM]",
"visState": "{\"title\":\"Error Occurrences [APM]\",\"type\":\"metrics\",\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(0,156,224,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"}],\"seperate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"bar\",\"line_width\":\"0\",\"point_size\":1,\"fill\":\"1\",\"stacked\":\"none\",\"label\":\"Occurrences\",\"terms_field\":\"error.grouping_key\"}],\"time_field\":\"@timestamp\",\"interval\":\">=1m\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":0,\"show_grid\":1,\"filter\":\"processor.event:error\"},\"aggs\":[]}",
"uiStateJSON": "{}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"12e52550-6354-11e8-9d01-ed6a4badd083\",\"query\":{\"query\":\"\",\"language\":\"lucene\"}}"
}
}
},
{
"id": "ceefd050-7c6a-11e7-aa55-3b0d52c71c60",
"type": "search",
"version": 1,
"attributes": {
"title": "Error Details [APM]",
"description": "",
"hits": 0,
"columns": [
"error.culprit",
"error.exception.type",
"error.exception.message",
"error.log.message",
"error.exception.handled",
"context.service.name"
],
"sort": [
"@timestamp",
"desc"
],
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"12e52550-6354-11e8-9d01-ed6a4badd083\",\"highlightAll\":true,\"version\":true,\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[{\"$state\":{\"store\":\"appState\"},\"meta\":{\"alias\":null,\"disabled\":false,\"index\":\"12e52550-6354-11e8-9d01-ed6a4badd083\",\"key\":\"processor.event\",\"negate\":false,\"params\":{\"query\":\"error\",\"type\":\"phrase\"},\"type\":\"phrase\",\"value\":\"error\"},\"query\":{\"match\":{\"processor.event\":{\"query\":\"error\",\"type\":\"phrase\"}}}}]}"
}
}
},
{
"id": "5f08a870-7c6a-11e7-aa55-3b0d52c71c60",
"type": "dashboard",
"version": 1,
"attributes": {
"title": "[APM] Error Details",
"hits": 0,
"description": "",
"panelsJSON": "[{\"col\":1,\"id\":\"c618e4e0-7c69-11e7-aa55-3b0d52c71c60\",\"panelIndex\":1,\"row\":1,\"size_x\":12,\"size_y\":3,\"type\":\"visualization\"},{\"col\":1,\"columns\":[\"error.culprit\",\"error.exception.type\",\"error.exception.message\",\"error.log.message\",\"error.exception.handled\",\"context.service.name\"],\"id\":\"ceefd050-7c6a-11e7-aa55-3b0d52c71c60\",\"panelIndex\":2,\"row\":4,\"size_x\":12,\"size_y\":21,\"sort\":[\"@timestamp\",\"desc\"],\"type\":\"search\"}]",
"optionsJSON": "{\"darkTheme\":false}",
"uiStateJSON": "{}",
"version": 1,
"timeRestore": false,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[],\"highlightAll\":true,\"version\":true}"
}
}
},
{
"id": "22518e70-7c69-11e7-aa55-3b0d52c71c60",
"type": "visualization",
"version": 1,
"attributes": {
"title": "Top Errors for Time Period [APM]",
"visState": "{\"title\":\"Top Errors for Time Period [APM]\",\"type\":\"table\",\"params\":{\"perPage\":25,\"showMeticsAtAllLevels\":false,\"showPartialRows\":false,\"showTotal\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"totalFunc\":\"sum\"},\"aggs\":[{\"id\":\"2\",\"enabled\":true,\"type\":\"terms\",\"schema\":\"bucket\",\"params\":{\"field\":\"error id icon\",\"size\":100,\"order\":\"desc\",\"orderBy\":\"1\",\"customLabel\":\"-\"}},{\"id\":\"5\",\"enabled\":true,\"type\":\"top_hits\",\"schema\":\"metric\",\"params\":{\"field\":\"error.exception.message\",\"aggregate\":\"concat\",\"size\":1,\"sortField\":\"@timestamp\",\"sortOrder\":\"desc\",\"customLabel\":\"Message\"}},{\"id\":\"1\",\"enabled\":true,\"type\":\"count\",\"schema\":\"metric\",\"params\":{\"customLabel\":\"Number of Errors\"}},{\"id\":\"4\",\"enabled\":true,\"type\":\"top_hits\",\"schema\":\"metric\",\"params\":{\"field\":\"error.exception.type\",\"aggregate\":\"concat\",\"size\":1,\"sortField\":\"@timestamp\",\"sortOrder\":\"desc\",\"customLabel\":\"Type\"}},{\"id\":\"3\",\"enabled\":true,\"type\":\"top_hits\",\"schema\":\"metric\",\"params\":{\"field\":\"error.culprit\",\"aggregate\":\"concat\",\"size\":1,\"sortField\":\"@timestamp\",\"sortOrder\":\"desc\",\"customLabel\":\"Culprit\"}},{\"id\":\"6\",\"enabled\":true,\"type\":\"top_hits\",\"schema\":\"metric\",\"params\":{\"field\":\"context.service.name\",\"aggregate\":\"concat\",\"size\":1,\"sortField\":\"@timestamp\",\"sortOrder\":\"desc\",\"customLabel\":\"App Name\"}},{\"id\":\"7\",\"enabled\":true,\"type\":\"top_hits\",\"schema\":\"metric\",\"params\":{\"field\":\"error.grouping_key\",\"aggregate\":\"concat\",\"size\":1,\"sortField\":\"@timestamp\",\"sortOrder\":\"desc\",\"customLabel\":\"-\"}}]}",
"uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"12e52550-6354-11e8-9d01-ed6a4badd083\",\"filter\":[],\"query\":{\"language\":\"lucene\",\"query\":\"\"}}"
}
}
},
{
"id": "37f6fac0-7c6a-11e7-aa55-3b0d52c71c60",
"type": "dashboard",
"version": 1,
"attributes": {
"title": "[APM] Errors",
"hits": 0,
"description": "",
"panelsJSON": "[{\"col\":1,\"id\":\"22518e70-7c69-11e7-aa55-3b0d52c71c60\",\"panelIndex\":1,\"row\":4,\"size_x\":12,\"size_y\":10,\"type\":\"visualization\"},{\"col\":1,\"id\":\"c618e4e0-7c69-11e7-aa55-3b0d52c71c60\",\"panelIndex\":2,\"row\":1,\"size_x\":12,\"size_y\":3,\"type\":\"visualization\"}]",
"optionsJSON": "{\"darkTheme\":false}",
"uiStateJSON": "{\"P-1\":{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}}",
"version": 1,
"timeRestore": false,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[],\"highlightAll\":true,\"version\":true}"
}
}
},
{
"id": "a2e199b0-7820-11e7-8c47-65b845b5cfb3",
"type": "visualization",
"version": 1,
"attributes": {
"title": "Top Transactions for Time Period [APM]",
"visState": "{\"aggs\":[{\"enabled\":true,\"id\":\"2\",\"params\":{\"customLabel\":\"Transaction\",\"field\":\"transaction.name.keyword\",\"order\":\"desc\",\"orderBy\":\"1\",\"size\":1000},\"schema\":\"bucket\",\"type\":\"terms\"},{\"enabled\":true,\"id\":\"5\",\"params\":{\"aggregate\":\"concat\",\"customLabel\":\"Type\",\"field\":\"transaction.type\",\"size\":1,\"sortField\":\"@timestamp\",\"sortOrder\":\"desc\"},\"schema\":\"metric\",\"type\":\"top_hits\"},{\"enabled\":true,\"id\":\"1\",\"params\":{\"customLabel\":\"Avg. Resp Time (ms)\",\"field\":\"transaction.duration.us\"},\"schema\":\"metric\",\"type\":\"avg\"},{\"enabled\":true,\"id\":\"3\",\"params\":{\"customLabel\":\"Resp Time (ms)\",\"field\":\"transaction.duration.us\",\"percents\":[95]},\"schema\":\"metric\",\"type\":\"percentiles\"},{\"enabled\":true,\"id\":\"4\",\"params\":{\"aggregate\":\"concat\",\"customLabel\":\"View Spans\",\"field\":\"transaction.id\",\"size\":1,\"sortField\":\"@timestamp\",\"sortOrder\":\"desc\"},\"schema\":\"metric\",\"type\":\"top_hits\"}],\"params\":{\"perPage\":25,\"showMeticsAtAllLevels\":false,\"showPartialRows\":false,\"showTotal\":false,\"sort\":{\"columnIndex\":null,\"direction\":null},\"totalFunc\":\"sum\"},\"title\":\"Top Transactions for Time Period [APM]\",\"type\":\"table\"}",
"uiStateJSON": "{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"12e52550-6354-11e8-9d01-ed6a4badd083\",\"filter\":[],\"query\":{\"language\":\"lucene\",\"query\":\"\"}}"
}
}
},
{
"id": "09bcf890-7822-11e7-8c47-65b845b5cfb3",
"type": "visualization",
"version": 2,
"attributes": {
"title": "Response Times [APM]",
"visState": "{\"title\":\"Response Times [APM]\",\"type\":\"metrics\",\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(0,156,224,1)\",\"split_mode\":\"everything\",\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"avg\",\"field\":\"transaction.duration.us\"}],\"seperate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"us,ms,0\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":1,\"fill\":\"0\",\"stacked\":\"none\",\"value_template\":\"{{value}} ms\",\"label\":\"Average\"},{\"id\":\"79921480-7821-11e7-8745-07eaffcb65e5\",\"color\":\"rgba(115,216,255,1)\",\"split_mode\":\"everything\",\"metrics\":[{\"id\":\"79921481-7821-11e7-8745-07eaffcb65e5\",\"type\":\"percentile\",\"field\":\"transaction.duration.us\",\"percentiles\":[{\"value\":\"95\",\"percentile\":\"\",\"shade\":0.2,\"id\":\"858ec670-7821-11e7-8745-07eaffcb65e5\",\"mode\":\"line\"}]}],\"seperate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"us,ms,0\",\"chart_type\":\"line\",\"line_width\":1,\"point_size\":1,\"fill\":0.5,\"stacked\":\"none\",\"value_template\":\"{{value}} ms\",\"label\":\"95th Percentile\"},{\"id\":\"c1e42de0-7821-11e7-8745-07eaffcb65e5\",\"color\":\"rgba(254,146,0,1)\",\"split_mode\":\"everything\",\"metrics\":[{\"id\":\"c1e42de1-7821-11e7-8745-07eaffcb65e5\",\"type\":\"percentile\",\"field\":\"transaction.duration.us\",\"percentiles\":[{\"value\":\"99\",\"percentile\":\"\",\"shade\":0.2,\"id\":\"858ec670-7821-11e7-8745-07eaffcb65e5\",\"mode\":\"line\"}]}],\"seperate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"us,ms,0\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":1,\"fill\":\"0\",\"stacked\":\"none\",\"value_template\":\"{{value}} ms\",\"label\":\"99th Percentile\"}],\"time_field\":\"@timestamp\",\"interval\":\">=1m\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1,\"legend_position\":\"right\"},\"aggs\":[]}",
"uiStateJSON": "{}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"12e52550-6354-11e8-9d01-ed6a4badd083\",\"query\":{\"language\":\"lucene\",\"query\":\"\"}}"
}
}
},
{
"id": "55606a60-7823-11e7-8c47-65b845b5cfb3",
"type": "visualization",
"version": 1,
"attributes": {
"title": "Request Per Minute [APM]",
"visState": "{\"title\":\"Request Per Minute [APM]\",\"type\":\"metrics\",\"params\":{\"id\":\"61ca57f0-469d-11e7-af02-69e470af7417\",\"type\":\"timeseries\",\"series\":[{\"id\":\"61ca57f1-469d-11e7-af02-69e470af7417\",\"color\":\"rgba(115,216,255,1)\",\"split_mode\":\"terms\",\"metrics\":[{\"id\":\"61ca57f2-469d-11e7-af02-69e470af7417\",\"type\":\"count\"},{\"id\":\"3fcaa6c0-7828-11e7-bb25-2ff6dee07a1b\",\"type\":\"cumulative_sum\",\"field\":\"61ca57f2-469d-11e7-af02-69e470af7417\"},{\"unit\":\"1m\",\"id\":\"467f1cd0-7828-11e7-bb25-2ff6dee07a1b\",\"type\":\"derivative\",\"field\":\"3fcaa6c0-7828-11e7-bb25-2ff6dee07a1b\"},{\"unit\":\"\",\"id\":\"4bd1b8f0-7828-11e7-bb25-2ff6dee07a1b\",\"type\":\"positive_only\",\"field\":\"467f1cd0-7828-11e7-bb25-2ff6dee07a1b\"}],\"seperate_axis\":0,\"axis_position\":\"right\",\"formatter\":\"number\",\"chart_type\":\"line\",\"line_width\":\"2\",\"point_size\":\"0\",\"fill\":\"0\",\"stacked\":\"none\",\"label\":\"\",\"value_template\":\"{{value}} rpm\",\"terms_field\":\"transaction.result\"}],\"time_field\":\"@timestamp\",\"interval\":\">=1m\",\"axis_position\":\"left\",\"axis_formatter\":\"number\",\"show_legend\":1,\"show_grid\":1},\"aggs\":[]}",
"uiStateJSON": "{}",
"description": "",
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"12e52550-6354-11e8-9d01-ed6a4badd083\",\"query\":{\"language\":\"lucene\",\"query\":\"\"}}"
}
}
},
{
"id": "41b5d920-7821-11e7-8c47-65b845b5cfb3",
"type": "dashboard",
"version": 1,
"attributes": {
"title": "[APM] Transactions",
"hits": 0,
"description": "",
"panelsJSON": "[{\"col\":1,\"id\":\"a2e199b0-7820-11e7-8c47-65b845b5cfb3\",\"panelIndex\":1,\"row\":4,\"size_x\":12,\"size_y\":10,\"type\":\"visualization\"},{\"col\":1,\"id\":\"09bcf890-7822-11e7-8c47-65b845b5cfb3\",\"panelIndex\":2,\"row\":1,\"size_x\":6,\"size_y\":3,\"type\":\"visualization\"},{\"col\":7,\"id\":\"55606a60-7823-11e7-8c47-65b845b5cfb3\",\"panelIndex\":3,\"row\":1,\"size_x\":6,\"size_y\":3,\"type\":\"visualization\"}]",
"optionsJSON": "{\"darkTheme\":false}",
"uiStateJSON": "{\"P-1\":{\"vis\":{\"params\":{\"sort\":{\"columnIndex\":null,\"direction\":null}}}}}",
"version": 1,
"timeRestore": false,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[],\"highlightAll\":true,\"version\":true}"
}
}
},
{
"id": "d7735b90-7ddf-11e7-b115-df9c90da2df1",
"type": "search",
"version": 1,
"attributes": {
"title": "Spans [APM]",
"description": "",
"hits": 0,
"columns": [
"span.type",
"span.name",
"span.duration.us",
"span.start.us"
],
"sort": [
"span.start.us",
"asc"
],
"version": 1,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"index\":\"12e52550-6354-11e8-9d01-ed6a4badd083\",\"highlightAll\":true,\"version\":true,\"query\":{\"language\":\"lucene\",\"query\":\"\"},\"filter\":[{\"meta\":{\"index\":\"12e52550-6354-11e8-9d01-ed6a4badd083\",\"negate\":false,\"disabled\":false,\"alias\":null,\"type\":\"phrase\",\"key\":\"processor.event\",\"value\":\"span\",\"params\":{\"query\":\"span\",\"type\":\"phrase\"}},\"query\":{\"match\":{\"processor.event\":{\"query\":\"span\",\"type\":\"phrase\"}}},\"$state\":{\"store\":\"appState\"}}]}"
}
}
},
{
"id": "3e3de700-7de0-11e7-b115-df9c90da2df1",
"type": "dashboard",
"version": 2,
"attributes": {
"title": "[APM] Span Details",
"hits": 0,
"description": "",
"panelsJSON": "[{\"size_x\":12,\"size_y\":23,\"panelIndex\":1,\"type\":\"search\",\"id\":\"d7735b90-7ddf-11e7-b115-df9c90da2df1\",\"col\":1,\"row\":1,\"columns\":[\"span.type\",\"span.name\",\"span.duration.us\",\"span.start.us\"],\"sort\":[\"span.start.us\",\"asc\"]}]",
"optionsJSON": "{\"darkTheme\":false}",
"uiStateJSON": "{}",
"version": 1,
"timeRestore": false,
"kibanaSavedObjectMeta": {
"searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"lucene\"},\"filter\":[],\"highlightAll\":true,\"version\":true}"
}
}
}
]

View file

@ -20,12 +20,15 @@
import _ from 'lodash';
export class SavedObject {
constructor(client, { id, type, version, attributes } = {}) {
constructor(client, { id, type, version, attributes, error } = {}) {
this._client = client;
this.id = id;
this.type = type;
this.attributes = attributes || {};
this._version = version;
if (error) {
this.error = error;
}
}
get(key) {

View file

@ -21,7 +21,7 @@ import expect from 'expect.js';
export default function ({ getService, getPageObjects }) {
const retry = getService('retry');
const PageObjects = getPageObjects(['common', 'header', 'home']);
const PageObjects = getPageObjects(['common', 'header', 'home', 'dashboard']);
describe('add data tutorials', function describeIndexTests() {
@ -34,5 +34,25 @@ export default function ({ getService, getPageObjects }) {
});
});
describe('apm', function describeIndexTests() {
it('should install saved objects', async ()=> {
await PageObjects.common.navigateToUrl('home', 'tutorial_directory');
await PageObjects.header.waitUntilLoadingHasFinished();
await retry.try(async () => {
await PageObjects.home.clickSynopsis('apm');
});
await PageObjects.home.loadSavedObjects();
await PageObjects.common.navigateToApp('dashboard');
await PageObjects.dashboard.searchForDashboardWithName('APM');
const countOfDashboards = await PageObjects.dashboard.getCountOfDashboardsInListingTable();
expect(countOfDashboards).to.equal(5);
});
});
});
}

View file

@ -17,9 +17,9 @@
* under the License.
*/
export function HomePageProvider({ getService }) {
const testSubjects = getService('testSubjects');
const retry = getService('retry');
class HomePage {
@ -63,6 +63,16 @@ export function HomePageProvider({ getService }) {
await testSubjects.click(`launchSampleDataSet${id}`);
}
async loadSavedObjects() {
await retry.try(async () => {
await testSubjects.click('loadSavedObjects');
const successMsgExists = await testSubjects.exists('loadSavedObjects_success', 5000);
if (!successMsgExists) {
throw new Error('Failed to load saved objects');
}
});
}
}
return new HomePage();