mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
* 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:
parent
0b39582294
commit
fe2f671d0a
18 changed files with 1218 additions and 18 deletions
|
@ -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(),
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
`;
|
|
@ -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,
|
||||
};
|
|
@ -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();
|
||||
});
|
||||
});
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -5,4 +5,5 @@
|
|||
get-config="getConfig"
|
||||
set-config="setConfig"
|
||||
clear-index-patterns-cache="clearIndexPatternsCache"
|
||||
bulk-create="bulkCreate"
|
||||
/>
|
||||
|
|
|
@ -49,6 +49,7 @@ function getRoute() {
|
|||
const getter = indexPatterns.getIds;
|
||||
getter.clearCache();
|
||||
};
|
||||
$scope.bulkCreate = chrome.getSavedObjectsClient().bulkCreate;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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.',
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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: [
|
||||
|
|
|
@ -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];
|
||||
}
|
|
@ -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
|
@ -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}"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue