Skip to content

Commit

Permalink
Use embeddable registry in add panel (elastic#31400)
Browse files Browse the repository at this point in the history
* Prepare control flow to use embeddable factories in add panel

* Rewrite saved object finder and add tests

* Fix usages of new saved object finder

* fix test failures

* fix some functional tests and re-introduce makeUrl

* fix tests

* remove direct hrefs in saved_object_lists

* PR review fixes

* update snapshot

* overwrite width of viz dialog

* Update src/legacy/core_plugins/kibana/public/dashboard/top_nav/add_panel.js

Co-Authored-By: flash1293 <email@johannes-reuter.de>

* Update src/legacy/core_plugins/kibana/public/discover/embeddable/search_embeddable_factory.ts

Co-Authored-By: flash1293 <email@johannes-reuter.de>

* Update src/legacy/core_plugins/kibana/public/discover/top_nav/open_search_panel.js

Co-Authored-By: flash1293 <email@johannes-reuter.de>

* Update src/legacy/core_plugins/kibana/public/visualize/wizard/search_selection/search_selection.tsx

Co-Authored-By: flash1293 <email@johannes-reuter.de>

* Update src/legacy/core_plugins/kibana/public/visualize/wizard/search_selection/search_selection.tsx

Co-Authored-By: flash1293 <email@johannes-reuter.de>

* Update src/legacy/core_plugins/kibana/public/visualize/wizard/search_selection/search_selection.tsx

Co-Authored-By: flash1293 <email@johannes-reuter.de>

* fix tests

* review fixes #1

* review fixes #2

* dont use classname in functional test

* remove call to action button prop

* align buttons correctly

* fix tests

* remove debugging statement

* Update src/legacy/core_plugins/kibana/public/dashboard/top_nav/add_panel.js

Co-Authored-By: flash1293 <email@johannes-reuter.de>

* Update src/legacy/core_plugins/kibana/public/discover/top_nav/open_search_panel.js

Co-Authored-By: flash1293 <email@johannes-reuter.de>

* review fixes #3

* improve filter behavior and enable it for search wizard

* adjust functional tests for new filter behavior

* Change translation id due to string change

* Update Jest snapshot
  • Loading branch information
flash1293 authored and timroes committed Mar 11, 2019
1 parent 1ebe64f commit f935c14
Show file tree
Hide file tree
Showing 28 changed files with 1,165 additions and 554 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ app.directive('dashboardApp', function ($injector) {
showNewVisModal(visTypes, { editorParams: [DashboardConstants.ADD_VISUALIZATION_TO_DASHBOARD_MODE_PARAM] });
};

showAddPanel(dashboardStateManager.addNewPanel, addNewVis, visTypes);
showAddPanel(dashboardStateManager.addNewPanel, addNewVis, embeddableFactories);
};
navActions[TopNavIds.OPTIONS] = (menuItem, navController, anchorElement) => {
showOptionsPopover({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,68 +10,60 @@ exports[`render 1`] = `
ownFocus={true}
size="m"
>
<EuiFlyoutBody>
<EuiFlyoutHeader
hasBorder={true}
>
<EuiTitle
size="s"
size="m"
textTransform="none"
>
<h1>
<h2>
<FormattedMessage
defaultMessage="Add Panels"
defaultMessage="Add panels"
id="kbn.dashboard.topNav.addPanelsTitle"
values={Object {}}
/>
</h1>
</h2>
</EuiTitle>
<EuiTabs
expand={false}
size="m"
</EuiFlyoutHeader>
<EuiFlyoutBody>
<SavedObjectFinder
noItemsMessage="No matching objects found."
onChoose={[Function]}
savedObjectMetaData={Array []}
showFilter={true}
/>
</EuiFlyoutBody>
<EuiFlyoutFooter>
<EuiFlexGroup
alignItems="stretch"
component="div"
direction="row"
gutterSize="l"
justifyContent="flexEnd"
responsive={true}
wrap={false}
>
<EuiTab
data-test-subj="addVisualizationTab"
disabled={false}
isSelected={true}
key="vis"
onClick={[Function]}
>
Visualization
</EuiTab>
<EuiTab
data-test-subj="addSavedSearchTab"
disabled={false}
isSelected={false}
key="search"
onClick={[Function]}
<EuiFlexItem
component="div"
grow={false}
>
Saved Search
</EuiTab>
</EuiTabs>
<EuiSpacer
size="s"
/>
<SavedObjectFinder
callToActionButton={
<EuiButton
color="primary"
data-test-subj="addNewSavedObjectLink"
fill={false}
fill={true}
iconSide="left"
onClick={[Function]}
type="button"
>
<FormattedMessage
defaultMessage="Add new Visualization"
id="kbn.dashboard.topNav.addPanel.addNewVisualizationButtonLabel"
defaultMessage="Create new visualization"
id="kbn.dashboard.topNav.addPanel.createNewVisualizationButtonLabel"
values={Object {}}
/>
</EuiButton>
}
key="visSavedObjectFinder"
noItemsMessage="No matching visualizations found."
onChoose={[Function]}
savedObjectType="visualization"
visTypes={Object {}}
/>
</EuiFlyoutBody>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlyoutFooter>
</EuiFlyout>
`;
178 changes: 53 additions & 125 deletions src/legacy/core_plugins/kibana/public/dashboard/top_nav/add_panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,109 +19,24 @@

import React from 'react';
import PropTypes from 'prop-types';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { toastNotifications } from 'ui/notify';
import { SavedObjectFinder } from 'ui/saved_objects/components/saved_object_finder';

import {
EuiFlexGroup,
EuiFlexItem,
EuiFlyout,
EuiFlyoutHeader,
EuiFlyoutFooter,
EuiFlyoutBody,
EuiButton,
EuiTabs,
EuiTab,
EuiSpacer,
EuiTitle,
} from '@elastic/eui';

const VIS_TAB_ID = 'vis';
const SAVED_SEARCH_TAB_ID = 'search';

class DashboardAddPanelUi extends React.Component {
constructor(props) {
super(props);

const addNewVisBtn = (
<EuiButton
onClick={this.props.addNewVis}
data-test-subj="addNewSavedObjectLink"
>
<FormattedMessage
id="kbn.dashboard.topNav.addPanel.addNewVisualizationButtonLabel"
defaultMessage="Add new Visualization"
/>
</EuiButton>
);

const tabs = [{
id: VIS_TAB_ID,
name: props.intl.formatMessage({
id: 'kbn.dashboard.topNav.addPanel.visualizationTabName',
defaultMessage: 'Visualization',
}),
dataTestSubj: 'addVisualizationTab',
toastDataTestSubj: 'addVisualizationToDashboardSuccess',
savedObjectFinder: (
<SavedObjectFinder
key="visSavedObjectFinder"
callToActionButton={addNewVisBtn}
onChoose={this.onAddPanel}
visTypes={this.props.visTypes}
noItemsMessage={props.intl.formatMessage({
id: 'kbn.dashboard.topNav.addPanel.visSavedObjectFinder.noMatchingVisualizationsMessage',
defaultMessage: 'No matching visualizations found.',
})}
savedObjectType="visualization"
/>
)
}, {
id: SAVED_SEARCH_TAB_ID,
name: props.intl.formatMessage({
id: 'kbn.dashboard.topNav.addPanel.savedSearchTabName',
defaultMessage: 'Saved Search',
}),
dataTestSubj: 'addSavedSearchTab',
toastDataTestSubj: 'addSavedSearchToDashboardSuccess',
savedObjectFinder: (
<SavedObjectFinder
key="searchSavedObjectFinder"
onChoose={this.onAddPanel}
noItemsMessage={props.intl.formatMessage({
id: 'kbn.dashboard.topNav.addPanel.searchSavedObjectFinder.noMatchingVisualizationsMessage',
defaultMessage: 'No matching saved searches found.',
})}
savedObjectType="search"
/>
)
}];

this.state = {
tabs: tabs,
selectedTab: tabs[0],
};
}

onSelectedTabChanged = tab => {
this.setState({
selectedTab: tab,
});
}

renderTabs() {
return this.state.tabs.map((tab) => {
return (
<EuiTab
onClick={() => this.onSelectedTabChanged(tab)}
isSelected={tab.id === this.state.selectedTab.id}
key={tab.id}
data-test-subj={tab.dataTestSubj}
>
{tab.name}
</EuiTab>
);
});
}

onAddPanel = (id, type) => {
export class DashboardAddPanel extends React.Component {
onAddPanel = (id, type, name) => {
this.props.addNewPanel(id, type);

// To avoid the clutter of having toast messages cover flyout
Expand All @@ -131,53 +46,66 @@ class DashboardAddPanelUi extends React.Component {
}

this.lastToast = toastNotifications.addSuccess({
title: this.props.intl.formatMessage({
id: 'kbn.dashboard.topNav.addPanel.selectedTabAddedToDashboardSuccessMessageTitle',
defaultMessage: '{selectedTabName} was added to your dashboard',
}, {
selectedTabName: this.state.selectedTab.name,
}),
'data-test-subj': this.state.selectedTab.toastDataTestSubj,
title: i18n.translate(
'kbn.dashboard.topNav.addPanel.savedObjectAddedToDashboardSuccessMessageTitle',
{
defaultMessage: '{savedObjectName} was added to your dashboard',
values: {
savedObjectName: name,
},
}
),
'data-test-subj': 'addObjectToDashboardSuccess',
});
}
};

render() {
return (
<EuiFlyout
ownFocus
onClose={this.props.onClose}
data-test-subj="dashboardAddPanel"
>
<EuiFlyoutBody>

<EuiTitle size="s">
<h1>
<EuiFlyout ownFocus onClose={this.props.onClose} data-test-subj="dashboardAddPanel">
<EuiFlyoutHeader hasBorder>
<EuiTitle size="m">
<h2>
<FormattedMessage
id="kbn.dashboard.topNav.addPanelsTitle"
defaultMessage="Add Panels"
defaultMessage="Add panels"
/>
</h1>
</h2>
</EuiTitle>

<EuiTabs>
{this.renderTabs()}
</EuiTabs>

<EuiSpacer size="s" />

{this.state.selectedTab.savedObjectFinder}

</EuiFlyoutHeader>
<EuiFlyoutBody>
<SavedObjectFinder
onChoose={this.onAddPanel}
savedObjectMetaData={this.props.embeddableFactories
.filter(embeddableFactory => Boolean(embeddableFactory.savedObjectMetaData))
.map(({ savedObjectMetaData }) => savedObjectMetaData)}
showFilter={true}
noItemsMessage={i18n.translate(
'kbn.dashboard.topNav.addPanel.noMatchingObjectsMessage',
{
defaultMessage: 'No matching objects found.',
}
)}
/>
</EuiFlyoutBody>
<EuiFlyoutFooter>
<EuiFlexGroup justifyContent="flexEnd">
<EuiFlexItem grow={false}>
<EuiButton fill onClick={this.props.addNewVis} data-test-subj="addNewSavedObjectLink">
<FormattedMessage
id="kbn.dashboard.topNav.addPanel.createNewVisualizationButtonLabel"
defaultMessage="Create new visualization"
/>
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlyoutFooter>
</EuiFlyout>
);
}
}

DashboardAddPanelUi.propTypes = {
DashboardAddPanel.propTypes = {
onClose: PropTypes.func.isRequired,
visTypes: PropTypes.object.isRequired,
addNewPanel: PropTypes.func.isRequired,
addNewVis: PropTypes.func.isRequired,
};

export const DashboardAddPanel = injectI18n(DashboardAddPanelUi);
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import React from 'react';
import sinon from 'sinon';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { shallow } from 'enzyme';

import {
DashboardAddPanel,
Expand All @@ -38,11 +38,12 @@ beforeEach(() => {
});

test('render', () => {
const component = shallowWithIntl(<DashboardAddPanel.WrappedComponent
const component = shallow(<DashboardAddPanel
onClose={onClose}
visTypes={{}}
addNewPanel={() => {}}
addNewVis={() => {}}
embeddableFactories={[]}
/>);
expect(component).toMatchSnapshot();
});
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import ReactDOM from 'react-dom';

let isOpen = false;

export function showAddPanel(addNewPanel, addNewVis, visTypes) {
export function showAddPanel(addNewPanel, addNewVis, embeddableFactories) {
if (isOpen) {
return;
}
Expand All @@ -47,9 +47,9 @@ export function showAddPanel(addNewPanel, addNewVis, visTypes) {
<I18nContext>
<DashboardAddPanel
onClose={onClose}
visTypes={visTypes}
addNewPanel={addNewPanel}
addNewVis={addNewVisWithCleanup}
embeddableFactories={embeddableFactories}
/>
</I18nContext>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import 'ui/doc_table';

import { i18n } from '@kbn/i18n';
import { EmbeddableFactory } from 'ui/embeddable';
import {
EmbeddableInstanceConfiguration,
Expand All @@ -33,7 +34,16 @@ export class SearchEmbeddableFactory extends EmbeddableFactory {
private $rootScope: ng.IRootScopeService,
private searchLoader: SavedSearchLoader
) {
super({ name: 'search' });
super({
name: 'search',
savedObjectMetaData: {
name: i18n.translate('kbn.discover.savedSearch.savedObjectName', {
defaultMessage: 'Saved search',
}),
type: 'search',
getIconForSavedObject: () => 'search',
},
});
}

public getEditPath(panelId: string) {
Expand Down

0 comments on commit f935c14

Please sign in to comment.