Skip to content

Commit

Permalink
[Add panel flyout] Moving create new to the top of SavedObjectFinder (#…
Browse files Browse the repository at this point in the history
…56428) (#57360)

* [Add panel flyout] Moving create new to the top of SavedObjectFinder

* [Add panel flyout] Moving create new to the top of SavedObjectFinder

* Fixing failing unit test

* Readd missing test

* [NP] Move saved object modal into new platform (#56383)

* Move saved object modal into new platform

* Fix TS

* Revert "Fix TS"

This reverts commit f2f9f5e.

* Revert "Move saved object modal into new platform"

This reverts commit d0f0ea6.

# Conflicts:
#	src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js

* Move save_object_save_modal

* Move show_saved_object_save_modal.tsx

* Move save_object_finder.tsx

* Remove unused export

* Pass I18nContext to showSaveModal

* Update i18n ids

* Fix map save

* Refactoring

* Load styles

* Revert importing styles

* Update snapshot

* Update snapshot

* Structural refactoring

* Fix path

Co-authored-by: Elastic Machine <[email protected]>

* Applying PR comments

Removing faulty rebase imports

Fixing unresolved conflict

Removing faulty merge files

Removing faulty import

Readd accidentally added file

* Removing unnecessary eslint-ignore

Co-authored-by: Maryia Lapata <[email protected]>
Co-authored-by: Elastic Machine <[email protected]>

Co-authored-by: Maryia Lapata <[email protected]>
Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
3 people authored Feb 12, 2020
1 parent f97e1ef commit 98b6eb1
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,18 @@ import { ContactCardEmbeddable } from '../../../../test_samples/embeddables/cont
import { ContainerInput } from '../../../../containers';
import { mountWithIntl as mount } from 'test_utils/enzyme_helpers';
import { ReactWrapper } from 'enzyme';

import { coreMock } from '../../../../../../../../core/public/mocks';
// @ts-ignore
import { findTestSubject } from '@elastic/eui/lib/test';

// eslint-disable-next-line
import { coreMock } from '../../../../../../../../core/public/mocks';
function DummySavedObjectFinder(props: { children: React.ReactNode }) {
return (
<div>
<div>Hello World</div>
{props.children}
</div>
) as JSX.Element;
}

test('createNewEmbeddable() add embeddable to container', async () => {
const core = coreMock.createStart();
Expand Down Expand Up @@ -101,14 +107,14 @@ test('selecting embeddable in "Create new ..." list calls createNewEmbeddable()'
};
const container = new HelloWorldContainer(input, { getEmbeddableFactory } as any);
const onClose = jest.fn();
const component = mount<AddPanelFlyout>(
const component = mount(
<AddPanelFlyout
container={container}
onClose={onClose}
getFactory={getEmbeddableFactory}
getAllFactories={() => new Set<any>([contactCardEmbeddableFactory]).values()}
notifications={core.notifications}
SavedObjectFinder={() => null}
SavedObjectFinder={props => <DummySavedObjectFinder {...props} />}
/>
) as ReactWrapper<unknown, unknown, AddPanelFlyout>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,21 @@
*/
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import React from 'react';
import React, { ReactElement } from 'react';
import { CoreSetup } from 'src/core/public';

import {
EuiButton,
EuiContextMenuItem,
EuiContextMenuPanel,
EuiFlyout,
EuiFlyoutBody,
EuiFlyoutFooter,
EuiFlyoutHeader,
EuiPopover,
EuiTitle,
} from '@elastic/eui';

import { IContainer } from '../../../../containers';
import { EmbeddableFactoryNotFoundError } from '../../../../errors';
import { GetEmbeddableFactories, GetEmbeddableFactory } from '../../../../types';
import { SavedObjectFinderCreateNew } from './saved_object_finder_create_new';

interface Props {
onClose: () => void;
Expand Down Expand Up @@ -107,15 +104,7 @@ export class AddPanelFlyout extends React.Component<Props, State> {
this.showToast(name);
};

private toggleCreateMenu = () => {
this.setState(prevState => ({ isCreateMenuOpen: !prevState.isCreateMenuOpen }));
};

private closeCreateMenu = () => {
this.setState({ isCreateMenuOpen: false });
};

private getCreateMenuItems() {
private getCreateMenuItems(): ReactElement[] {
return [...this.props.getAllFactories()]
.filter(factory => factory.isEditable() && !factory.isContainerType && factory.canCreateNew())
.map(factory => (
Expand Down Expand Up @@ -145,7 +134,9 @@ export class AddPanelFlyout extends React.Component<Props, State> {
noItemsMessage={i18n.translate('embeddableApi.addPanel.noMatchingObjectsMessage', {
defaultMessage: 'No matching objects found.',
})}
/>
>
<SavedObjectFinderCreateNew menuItems={this.getCreateMenuItems()} />
</SavedObjectFinder>
);

return (
Expand All @@ -158,30 +149,6 @@ export class AddPanelFlyout extends React.Component<Props, State> {
</EuiTitle>
</EuiFlyoutHeader>
<EuiFlyoutBody>{savedObjectsFinder}</EuiFlyoutBody>
<EuiFlyoutFooter>
<EuiPopover
id="createNew"
button={
<EuiButton
data-test-subj="createNew"
iconType="arrowDown"
iconSide="right"
onClick={this.toggleCreateMenu}
>
<FormattedMessage
id="embeddableApi.addPanel.createNewDefaultOption"
defaultMessage="Create new"
/>
</EuiButton>
}
isOpen={this.state.isCreateMenuOpen}
closePopover={this.closeCreateMenu}
panelPaddingSize="none"
anchorPosition="upLeft"
>
<EuiContextMenuPanel items={this.getCreateMenuItems()} />
</EuiPopover>
</EuiFlyoutFooter>
</EuiFlyout>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* 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, { ReactElement, useState } from 'react';
import { EuiButton } from '@elastic/eui';
import { EuiContextMenuPanel } from '@elastic/eui';
import { EuiPopover } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';

interface Props {
menuItems: ReactElement[];
}

export function SavedObjectFinderCreateNew({ menuItems }: Props) {
const [isCreateMenuOpen, setCreateMenuOpen] = useState(false);
const toggleCreateMenu = () => {
setCreateMenuOpen(!isCreateMenuOpen);
};
const closeCreateMenu = () => {
setCreateMenuOpen(false);
};
return (
<EuiPopover
id="createNew"
button={
<EuiButton
data-test-subj="createNew"
iconType="arrowDown"
iconSide="right"
onClick={toggleCreateMenu}
fill
>
<FormattedMessage
id="embeddableApi.addPanel.createNewDefaultOption"
defaultMessage="Create new"
/>
</EuiButton>
}
isOpen={isCreateMenuOpen}
closePopover={closeCreateMenu}
panelPaddingSize="none"
anchorPosition="downRight"
>
<EuiContextMenuPanel items={menuItems} />
</EuiPopover>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* 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 { SavedObjectFinderCreateNew } from '../saved_object_finder_create_new';
import { shallow } from 'enzyme';
import { EuiButton, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui';
import { mountWithIntl } from 'test_utils/enzyme_helpers';

describe('SavedObjectFinderCreateNew', () => {
test('renders correctly with no items', () => {
const wrapper = shallow(<SavedObjectFinderCreateNew menuItems={[]} />);
expect(wrapper.find(EuiPopover).length).toEqual(1);
const menuPanel = wrapper.find(EuiContextMenuPanel);
expect(menuPanel.length).toEqual(1);
const panelItems = menuPanel.prop('items');
if (panelItems) {
expect(panelItems.length).toEqual(0);
} else {
fail('Expect paneltems to be defined');
}
});

test('renders correctly with items', () => {
const items = [];
const onClick = jest.fn();
for (let i = 0; i < 3; i++) {
items.push(
<EuiContextMenuItem
key={i + 1}
data-test-subj={`item${i + 1}`}
onClick={onClick}
>{`item${i + 1}`}</EuiContextMenuItem>
);
}

const wrapper = shallow(<SavedObjectFinderCreateNew menuItems={items} />);
expect(wrapper.find(EuiPopover).length).toEqual(1);
const menuPanel = wrapper.find(EuiContextMenuPanel);
expect(menuPanel.length).toEqual(1);
const paneltems = menuPanel.prop('items');
if (paneltems) {
expect(paneltems.length).toEqual(3);
expect(paneltems[0].key).toEqual('1');
expect(paneltems[1].key).toEqual('2');
expect(paneltems[2].key).toEqual('3');
} else {
fail('Expect paneltems to be defined');
}
});

test('clicking the button opens/closes the popover', () => {
const items = [];
const onClick = jest.fn();
for (let i = 0; i < 3; i++) {
items.push(
<EuiContextMenuItem
key={i + 1}
data-test-subj={`item${i + 1}`}
onClick={onClick}
>{`item${i + 1}`}</EuiContextMenuItem>
);
}

const component = mountWithIntl(<SavedObjectFinderCreateNew menuItems={items} />);
let popover = component.find(EuiPopover);
expect(popover.prop('isOpen')).toBe(false);
const button = component.find(EuiButton);
button.simulate('click');
popover = component.find(EuiPopover);
expect(popover.prop('isOpen')).toBe(true);
button.simulate('click');
popover = component.find(EuiPopover);
expect(popover.prop('isOpen')).toBe(false);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -695,4 +695,34 @@ describe('SavedObjectsFinder', () => {
expect(wrapper.containsMatchingElement(<EuiLoadingSpinner />)).toBe(false);
});
});

it('should render with children', async () => {
const core = coreMock.createStart();
((core.savedObjects.client.find as any) as jest.SpyInstance).mockImplementation(() =>
Promise.resolve({ savedObjects: [doc, doc2] })
);
core.uiSettings.get.mockImplementation(() => 10);

const wrapper = shallow(
<SavedObjectFinder
savedObjects={core.savedObjects}
uiSettings={core.uiSettings}
savedObjectMetaData={[
{
type: 'search',
name: 'Search',
getIconForSavedObject: () => 'search',
},
{
type: 'vis',
name: 'Vis',
getIconForSavedObject: () => 'visLine',
},
]}
>
<button id="testChildButton">Dummy text</button>
</SavedObjectFinder>
);
expect(wrapper.exists('#testChildButton')).toBe(true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ class SavedObjectFinderUi extends React.Component<
)}
</EuiFilterGroup>
</EuiFlexItem>
{this.props.children ? <EuiFlexItem grow={false}>{this.props.children}</EuiFlexItem> : null}
</EuiFlexGroup>
);
}
Expand Down

0 comments on commit 98b6eb1

Please sign in to comment.