mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
* Sample data - allow plugins to register additional view data links * remove comment * remove unused function * review feedback
This commit is contained in:
parent
2804bb1f60
commit
da81772bb8
12 changed files with 356 additions and 20 deletions
|
@ -0,0 +1,69 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should render popover when appLinks is not empty 1`] = `
|
||||
<EuiPopover
|
||||
anchorPosition="downCenter"
|
||||
button={
|
||||
<EuiButton
|
||||
aria-label="View Sample eCommerce orders"
|
||||
color="primary"
|
||||
fill={false}
|
||||
iconSide="right"
|
||||
iconType="arrowDown"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
>
|
||||
View data
|
||||
</EuiButton>
|
||||
}
|
||||
closePopover={[Function]}
|
||||
hasArrow={true}
|
||||
id="sampleDataLinksecommerce"
|
||||
isOpen={false}
|
||||
ownFocus={false}
|
||||
panelPaddingSize="none"
|
||||
>
|
||||
<EuiContextMenu
|
||||
initialPanelId={0}
|
||||
panels={
|
||||
Array [
|
||||
Object {
|
||||
"id": 0,
|
||||
"items": Array [
|
||||
Object {
|
||||
"href": "root/app/kibana#/dashboard/722b74f0-b882-11e8-a6d9-e546fe2bba5f",
|
||||
"icon": <EuiIcon
|
||||
size="m"
|
||||
type="dashboardApp"
|
||||
/>,
|
||||
"name": "Dashboard",
|
||||
},
|
||||
Object {
|
||||
"href": "rootapp/myAppPath",
|
||||
"icon": <EuiIcon
|
||||
size="m"
|
||||
type="logoKibana"
|
||||
/>,
|
||||
"name": "myAppLabel",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</EuiPopover>
|
||||
`;
|
||||
|
||||
exports[`should render simple button when appLinks is empty 1`] = `
|
||||
<EuiButton
|
||||
aria-label="View Sample eCommerce orders"
|
||||
color="primary"
|
||||
data-test-subj="launchSampleDataSetecommerce"
|
||||
fill={false}
|
||||
href="root/app/kibana#/dashboard/722b74f0-b882-11e8-a6d9-e546fe2bba5f"
|
||||
iconSide="left"
|
||||
type="button"
|
||||
>
|
||||
View data
|
||||
</EuiButton>
|
||||
`;
|
|
@ -34,6 +34,8 @@ export const UNINSTALLED_STATUS = 'not_installed';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { SampleDataViewDataButton } from './sample_data_view_data_button';
|
||||
|
||||
export class SampleDataSetCard extends React.Component {
|
||||
|
||||
isInstalled = () => {
|
||||
|
@ -91,21 +93,12 @@ export class SampleDataSetCard extends React.Component {
|
|||
</EuiButtonEmpty>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
href={this.props.launchUrl}
|
||||
data-test-subj={`launchSampleDataSet${this.props.id}`}
|
||||
aria-label={i18n.translate('kbn.home.sampleDataSetCard.viewDataButtonAriaLabel', {
|
||||
defaultMessage: 'View {datasetName}',
|
||||
values: {
|
||||
datasetName: this.props.name,
|
||||
}
|
||||
})}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="kbn.home.sampleDataSetCard.viewDataButtonLabel"
|
||||
defaultMessage="View data"
|
||||
/>
|
||||
</EuiButton>
|
||||
<SampleDataViewDataButton
|
||||
id={this.props.id}
|
||||
name={this.props.name}
|
||||
overviewDashboard={this.props.overviewDashboard}
|
||||
appLinks={this.props.appLinks}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
|
@ -207,7 +200,12 @@ SampleDataSetCard.propTypes = {
|
|||
id: PropTypes.string.isRequired,
|
||||
description: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
launchUrl: PropTypes.string.isRequired,
|
||||
overviewDashboard: PropTypes.string.isRequired,
|
||||
appLinks: PropTypes.arrayOf(PropTypes.shape({
|
||||
path: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
icon: PropTypes.string.isRequired,
|
||||
})).isRequired,
|
||||
status: PropTypes.oneOf([
|
||||
INSTALLED_STATUS,
|
||||
UNINSTALLED_STATUS,
|
||||
|
|
|
@ -199,7 +199,8 @@ export class SampleDataSetCards extends React.Component {
|
|||
id={sampleDataSet.id}
|
||||
description={sampleDataSet.description}
|
||||
name={sampleDataSet.name}
|
||||
launchUrl={this.props.addBasePath(`/app/kibana#/dashboard/${sampleDataSet.overviewDashboard}`)}
|
||||
overviewDashboard={sampleDataSet.overviewDashboard}
|
||||
appLinks={sampleDataSet.appLinks}
|
||||
status={sampleDataSet.status}
|
||||
isProcessing={_.get(this.state.processingStatus, sampleDataSet.id, false)}
|
||||
statusMsg={sampleDataSet.statusMsg}
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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 PropTypes from 'prop-types';
|
||||
import {
|
||||
EuiButton,
|
||||
EuiContextMenu,
|
||||
EuiIcon,
|
||||
EuiPopover,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import chrome from 'ui/chrome';
|
||||
|
||||
export class SampleDataViewDataButton extends React.Component {
|
||||
|
||||
state = {
|
||||
isPopoverOpen: false
|
||||
}
|
||||
|
||||
togglePopoverVisibility = () => {
|
||||
this.setState(prevState => ({
|
||||
isPopoverOpen: !prevState.isPopoverOpen,
|
||||
}));
|
||||
};
|
||||
|
||||
closePopover = () => {
|
||||
this.setState({
|
||||
isPopoverOpen: false,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const viewDataButtonLabel = i18n.translate('kbn.home.sampleDataSetCard.viewDataButtonLabel', {
|
||||
defaultMessage: 'View data' });
|
||||
const viewDataButtonAriaLabel = i18n.translate('kbn.home.sampleDataSetCard.viewDataButtonAriaLabel', {
|
||||
defaultMessage: 'View {datasetName}',
|
||||
values: {
|
||||
datasetName: this.props.name,
|
||||
},
|
||||
});
|
||||
const dashboardPath = chrome.addBasePath(`/app/kibana#/dashboard/${this.props.overviewDashboard}`);
|
||||
|
||||
if (this.props.appLinks.length === 0) {
|
||||
return (
|
||||
<EuiButton
|
||||
href={dashboardPath}
|
||||
data-test-subj={`launchSampleDataSet${this.props.id}`}
|
||||
aria-label={viewDataButtonAriaLabel}
|
||||
>
|
||||
{viewDataButtonLabel}
|
||||
</EuiButton>
|
||||
);
|
||||
}
|
||||
|
||||
const additionalItems = this.props.appLinks.map(({ path, label, icon }) => {
|
||||
return {
|
||||
name: label,
|
||||
icon: (
|
||||
<EuiIcon
|
||||
type={icon}
|
||||
size="m"
|
||||
/>
|
||||
),
|
||||
href: chrome.addBasePath(path)
|
||||
};
|
||||
});
|
||||
const panels = [
|
||||
{
|
||||
id: 0,
|
||||
items: [
|
||||
{
|
||||
name: i18n.translate('kbn.home.sampleDataSetCard.dashboardLinkLabel', {
|
||||
defaultMessage: 'Dashboard' }),
|
||||
icon: (
|
||||
<EuiIcon
|
||||
type="dashboardApp"
|
||||
size="m"
|
||||
/>
|
||||
),
|
||||
href: dashboardPath,
|
||||
},
|
||||
...additionalItems
|
||||
]
|
||||
}
|
||||
];
|
||||
const popoverButton = (
|
||||
<EuiButton
|
||||
aria-label={viewDataButtonAriaLabel}
|
||||
onClick={this.togglePopoverVisibility}
|
||||
iconType="arrowDown"
|
||||
iconSide="right"
|
||||
>
|
||||
{viewDataButtonLabel}
|
||||
</EuiButton>
|
||||
);
|
||||
return (
|
||||
<EuiPopover
|
||||
id={`sampleDataLinks${this.props.id}`}
|
||||
button={popoverButton}
|
||||
isOpen={this.state.isPopoverOpen}
|
||||
closePopover={this.closePopover}
|
||||
panelPaddingSize="none"
|
||||
anchorPosition="downCenter"
|
||||
>
|
||||
<EuiContextMenu
|
||||
initialPanelId={0}
|
||||
panels={panels}
|
||||
/>
|
||||
</EuiPopover>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SampleDataViewDataButton.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
overviewDashboard: PropTypes.string.isRequired,
|
||||
appLinks: PropTypes.arrayOf(PropTypes.shape({
|
||||
path: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
icon: PropTypes.string.isRequired,
|
||||
})).isRequired,
|
||||
};
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
jest.mock('ui/chrome', () => {
|
||||
return {
|
||||
addBasePath: (path) => {
|
||||
return `root${path}`;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { SampleDataViewDataButton } from './sample_data_view_data_button';
|
||||
|
||||
test('should render simple button when appLinks is empty', () => {
|
||||
const component = shallow(<SampleDataViewDataButton
|
||||
id="ecommerce"
|
||||
name="Sample eCommerce orders"
|
||||
overviewDashboard="722b74f0-b882-11e8-a6d9-e546fe2bba5f"
|
||||
appLinks={[]}
|
||||
/>);
|
||||
expect(component).toMatchSnapshot(); // eslint-disable-line
|
||||
});
|
||||
|
||||
test('should render popover when appLinks is not empty', () => {
|
||||
const appLinks = [
|
||||
{
|
||||
path: 'app/myAppPath',
|
||||
label: 'myAppLabel',
|
||||
icon: 'logoKibana'
|
||||
}
|
||||
];
|
||||
|
||||
const component = shallow(<SampleDataViewDataButton
|
||||
id="ecommerce"
|
||||
name="Sample eCommerce orders"
|
||||
overviewDashboard="722b74f0-b882-11e8-a6d9-e546fe2bba5f"
|
||||
appLinks={appLinks}
|
||||
/>);
|
||||
expect(component).toMatchSnapshot(); // eslint-disable-line
|
||||
});
|
|
@ -44,6 +44,12 @@ const dataIndexSchema = Joi.object({
|
|||
preserveDayOfWeekTimeOfDay: Joi.boolean().default(false),
|
||||
});
|
||||
|
||||
const appLinkSchema = Joi.object({
|
||||
path: Joi.string().required(),
|
||||
label: Joi.string().required(),
|
||||
icon: Joi.string().required(),
|
||||
});
|
||||
|
||||
export const sampleDataSchema = {
|
||||
id: Joi.string().regex(/^[a-zA-Z0-9-]+$/).required(),
|
||||
name: Joi.string().required(),
|
||||
|
@ -53,6 +59,7 @@ export const sampleDataSchema = {
|
|||
|
||||
// saved object id of main dashboard for sample data set
|
||||
overviewDashboard: Joi.string().required(),
|
||||
appLinks: Joi.array().items(appLinkSchema).default([]),
|
||||
|
||||
// saved object id of default index-pattern for sample data set
|
||||
defaultIndex: Joi.string().required(),
|
||||
|
|
|
@ -39,6 +39,7 @@ export const createListRoute = () => ({
|
|||
previewImagePath: sampleDataset.previewImagePath,
|
||||
darkPreviewImagePath: sampleDataset.darkPreviewImagePath,
|
||||
overviewDashboard: sampleDataset.overviewDashboard,
|
||||
appLinks: sampleDataset.appLinks,
|
||||
defaultIndex: sampleDataset.defaultIndex,
|
||||
dataIndices: sampleDataset.dataIndices.map(({ id }) => ({ id })),
|
||||
};
|
||||
|
|
|
@ -79,6 +79,18 @@ export function sampleDataMixin(kbnServer, server) {
|
|||
sampleDataset.savedObjects = sampleDataset.savedObjects.concat(savedObjects);
|
||||
});
|
||||
|
||||
server.decorate('server', 'addAppLinksToSampleDataset', (id, appLinks) => {
|
||||
const sampleDataset = sampleDatasets.find(sampleDataset => {
|
||||
return sampleDataset.id === id;
|
||||
});
|
||||
|
||||
if (!sampleDataset) {
|
||||
throw new Error(`Unable to find sample dataset with id: ${id}`);
|
||||
}
|
||||
|
||||
sampleDataset.appLinks = sampleDataset.appLinks.concat(appLinks);
|
||||
});
|
||||
|
||||
server.registerSampleDataset(flightsSpecProvider);
|
||||
server.registerSampleDataset(logsSpecProvider);
|
||||
server.registerSampleDataset(ecommerceSpecProvider);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { ecommerceSavedObjects, flightsSavedObjects, webLogsSavedObjects } from './index';
|
||||
|
||||
export function loadSampleData(server) {
|
||||
|
@ -20,13 +21,33 @@ export function loadSampleData(server) {
|
|||
});
|
||||
}
|
||||
|
||||
const sampleDataLinkLabel = i18n.translate('xpack.canvas.sampleDataLinkLabel', {
|
||||
defaultMessage: 'Canvas',
|
||||
});
|
||||
server.addSavedObjectsToSampleDataset(
|
||||
'ecommerce',
|
||||
updateCanvasWorkpadTimestamps(ecommerceSavedObjects)
|
||||
);
|
||||
server.addAppLinksToSampleDataset('ecommerce', {
|
||||
path: '/app/canvas#/workpad/workpad-e08b9bdb-ec14-4339-94c4-063bddfd610e',
|
||||
label: sampleDataLinkLabel,
|
||||
icon: 'canvasApp',
|
||||
});
|
||||
|
||||
server.addSavedObjectsToSampleDataset(
|
||||
'flights',
|
||||
updateCanvasWorkpadTimestamps(flightsSavedObjects)
|
||||
);
|
||||
server.addAppLinksToSampleDataset('flights', {
|
||||
path: '/app/canvas#/workpad/workpad-a474e74b-aedc-47c3-894a-db77e62c41e0',
|
||||
label: sampleDataLinkLabel,
|
||||
icon: 'canvasApp',
|
||||
});
|
||||
|
||||
server.addSavedObjectsToSampleDataset('logs', updateCanvasWorkpadTimestamps(webLogsSavedObjects));
|
||||
server.addAppLinksToSampleDataset('logs', {
|
||||
path: '/app/canvas#/workpad/workpad-5563cc40-5760-4afe-bf33-9da72fac53b7',
|
||||
label: sampleDataLinkLabel,
|
||||
icon: 'canvasApp',
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
export const GIS_API_PATH = 'api/maps';
|
||||
|
||||
export const MAP_SAVED_OBJECT_TYPE = 'map';
|
||||
export function createMapPath(id) {
|
||||
return `/app/maps#/map/${id}`;
|
||||
}
|
||||
|
||||
export const EMS_FILE = 'EMS_FILE';
|
||||
export const ES_GEO_GRID = 'ES_GEO_GRID';
|
||||
|
|
|
@ -16,7 +16,7 @@ import { watchStatusAndLicenseToInitialize } from
|
|||
'../../server/lib/watch_status_and_license_to_initialize';
|
||||
import { initTelemetryCollection } from './server/maps_telemetry';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { APP_ID, APP_ICON } from './common/constants';
|
||||
import { APP_ID, APP_ICON, createMapPath } from './common/constants';
|
||||
import { getAppTitle } from './common/i18n_getters';
|
||||
|
||||
export function maps(kibana) {
|
||||
|
@ -91,9 +91,33 @@ export function maps(kibana) {
|
|||
.feature(this.id)
|
||||
.registerLicenseCheckResultsGenerator(checkLicense);
|
||||
|
||||
const sampleDataLinkLabel = i18n.translate('xpack.maps.sampleDataLinkLabel', {
|
||||
defaultMessage: 'Map'
|
||||
});
|
||||
server.addSavedObjectsToSampleDataset('ecommerce', getEcommerceSavedObjects());
|
||||
server.addAppLinksToSampleDataset('ecommerce', [
|
||||
{
|
||||
path: createMapPath('2c9c1f60-1909-11e9-919b-ffe5949a18d2'),
|
||||
label: sampleDataLinkLabel,
|
||||
icon: 'gisApp'
|
||||
}
|
||||
]);
|
||||
server.addSavedObjectsToSampleDataset('flights', getFlightsSavedObjects());
|
||||
server.addAppLinksToSampleDataset('flights', [
|
||||
{
|
||||
path: createMapPath('5dd88580-1906-11e9-919b-ffe5949a18d2'),
|
||||
label: sampleDataLinkLabel,
|
||||
icon: 'gisApp'
|
||||
}
|
||||
]);
|
||||
server.addSavedObjectsToSampleDataset('logs', getWebLogsSavedObjects());
|
||||
server.addAppLinksToSampleDataset('logs', [
|
||||
{
|
||||
path: createMapPath('de71f4f0-1902-11e9-919b-ffe5949a18d2'),
|
||||
label: sampleDataLinkLabel,
|
||||
icon: 'gisApp'
|
||||
}
|
||||
]);
|
||||
server.injectUiAppVars('maps', async () => {
|
||||
return await server.getInjectedUiAppVars('kibana');
|
||||
});
|
||||
|
|
|
@ -10,7 +10,7 @@ import { EmbeddableFactory } from 'ui/embeddable';
|
|||
import { MapEmbeddable } from './map_embeddable';
|
||||
import { indexPatternService } from '../kibana_services';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { MAP_SAVED_OBJECT_TYPE } from '../../common/constants';
|
||||
import { createMapPath, MAP_SAVED_OBJECT_TYPE } from '../../common/constants';
|
||||
|
||||
export class MapEmbeddableFactory extends EmbeddableFactory {
|
||||
|
||||
|
@ -49,7 +49,7 @@ export class MapEmbeddableFactory extends EmbeddableFactory {
|
|||
return new MapEmbeddable({
|
||||
onEmbeddableStateChanged,
|
||||
savedMap,
|
||||
editUrl: chrome.addBasePath(`/app/maps#/map/${panelMetadata.id}`),
|
||||
editUrl: chrome.addBasePath(createMapPath(panelMetadata.id)),
|
||||
indexPatterns,
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue