mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
Add <FormCreateDrilldown> component (#58335)
* refactor: 💡 use .story for Storybook and standartize dir struct * feat: 🎸 add <FlyoutFrame> component * feat: 🎸 add <FlyoutCreateDrilldown> component * refactor: 💡 improve FlyoutCreateDrilldownAction * test: 💍 add <FlyoutFrame> tests * docs: ✏️ add @todo for <DrilldownHelloBar> * feat: 🎸 make name editable in <FormCreateDrilldown> * test: 💍 add <FormCreateDrilldown> name field tests * chore: 🤖 change drilldown translation keys
This commit is contained in:
parent
bd40f557a5
commit
120f03dc06
24 changed files with 528 additions and 86 deletions
|
@ -10,11 +10,11 @@ import { CoreStart } from 'src/core/public';
|
|||
import { Action } from '../../../../../../src/plugins/ui_actions/public';
|
||||
import { toMountPoint } from '../../../../../../src/plugins/kibana_react/public';
|
||||
import { IEmbeddable } from '../../../../../../src/plugins/embeddable/public';
|
||||
import { FormCreateDrilldown } from '../../components/form_create_drilldown';
|
||||
import { FlyoutCreateDrilldown } from '../../components/flyout_create_drilldown';
|
||||
|
||||
export const OPEN_FLYOUT_ADD_DRILLDOWN = 'OPEN_FLYOUT_ADD_DRILLDOWN';
|
||||
|
||||
interface ActionContext {
|
||||
export interface FlyoutCreateDrilldownActionContext {
|
||||
embeddable: IEmbeddable;
|
||||
}
|
||||
|
||||
|
@ -22,29 +22,31 @@ export interface OpenFlyoutAddDrilldownParams {
|
|||
overlays: () => Promise<CoreStart['overlays']>;
|
||||
}
|
||||
|
||||
export class OpenFlyoutAddDrilldown implements Action<ActionContext> {
|
||||
export class FlyoutCreateDrilldownAction implements Action<FlyoutCreateDrilldownActionContext> {
|
||||
public readonly type = OPEN_FLYOUT_ADD_DRILLDOWN;
|
||||
public readonly id = OPEN_FLYOUT_ADD_DRILLDOWN;
|
||||
public order = 100;
|
||||
public order = 5;
|
||||
|
||||
constructor(protected readonly params: OpenFlyoutAddDrilldownParams) {}
|
||||
|
||||
public getDisplayName() {
|
||||
return i18n.translate('xpack.drilldowns.panel.openFlyoutAddDrilldown.displayName', {
|
||||
defaultMessage: 'Add drilldown',
|
||||
return i18n.translate('xpack.drilldowns.FlyoutCreateDrilldownAction.displayName', {
|
||||
defaultMessage: 'Create Drilldown',
|
||||
});
|
||||
}
|
||||
|
||||
public getIconType() {
|
||||
return 'empty';
|
||||
return 'plusInCircle';
|
||||
}
|
||||
|
||||
public async isCompatible({ embeddable }: ActionContext) {
|
||||
public async isCompatible({ embeddable }: FlyoutCreateDrilldownActionContext) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public async execute({ embeddable }: ActionContext) {
|
||||
public async execute(context: FlyoutCreateDrilldownActionContext) {
|
||||
const overlays = await this.params.overlays();
|
||||
overlays.openFlyout(toMountPoint(<FormCreateDrilldown />));
|
||||
const handle = overlays.openFlyout(
|
||||
toMountPoint(<FlyoutCreateDrilldown context={context} onClose={() => handle.close()} />)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,4 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export * from './open_flyout_add_drilldown';
|
||||
export * from './flyout_create_drilldown';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import * as React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { DrilldownHelloBar } from '..';
|
||||
import { DrilldownHelloBar } from '.';
|
||||
|
||||
storiesOf('components/DrilldownHelloBar', module).add('default', () => {
|
||||
return <DrilldownHelloBar />;
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export interface DrilldownHelloBarProps {
|
||||
docsLink?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo https://github.com/elastic/kibana/issues/55311
|
||||
*/
|
||||
export const DrilldownHelloBar: React.FC<DrilldownHelloBarProps> = ({ docsLink }) => {
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
Drilldowns provide the ability to define a new behavior when interacting with a panel. You
|
||||
can add multiple options or simply override the default filtering behavior.
|
||||
</p>
|
||||
<a href={docsLink}>View docs</a>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -4,24 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export interface DrilldownHelloBarProps {
|
||||
docsLink?: string;
|
||||
}
|
||||
|
||||
export const DrilldownHelloBar: React.FC<DrilldownHelloBarProps> = ({ docsLink }) => {
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
Drilldowns provide the ability to define a new behavior when interacting with a panel. You
|
||||
can add multiple options or simply override the default filtering behavior.
|
||||
</p>
|
||||
<a href={docsLink}>View docs</a>
|
||||
<img
|
||||
src="https://user-images.githubusercontent.com/9773803/72729009-e5803180-3b8e-11ea-8330-b86089bf5f0a.png"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export * from './drilldown_hello_bar';
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import * as React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { DrilldownPicker } from '..';
|
||||
import { DrilldownPicker } from '.';
|
||||
|
||||
storiesOf('components/DrilldownPicker', module).add('default', () => {
|
||||
return <DrilldownPicker />;
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
// eslint-disable-next-line
|
||||
export interface DrilldownPickerProps {}
|
||||
|
||||
export const DrilldownPicker: React.FC<DrilldownPickerProps> = () => {
|
||||
return (
|
||||
<img
|
||||
src={
|
||||
'https://user-images.githubusercontent.com/9773803/72725665-9e8e3e00-3b86-11ea-9314-8724c521b41f.png'
|
||||
}
|
||||
alt=""
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -4,18 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
// eslint-disable-next-line
|
||||
export interface DrilldownPickerProps {}
|
||||
|
||||
export const DrilldownPicker: React.FC<DrilldownPickerProps> = () => {
|
||||
return (
|
||||
<img
|
||||
src={
|
||||
'https://user-images.githubusercontent.com/9773803/72725665-9e8e3e00-3b86-11ea-9314-8724c521b41f.png'
|
||||
}
|
||||
alt=""
|
||||
/>
|
||||
);
|
||||
};
|
||||
export * from './drilldown_picker';
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import * as React from 'react';
|
||||
import { EuiFlyout } from '@elastic/eui';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { FlyoutCreateDrilldown } from '.';
|
||||
|
||||
storiesOf('components/FlyoutCreateDrilldown', module)
|
||||
.add('default', () => {
|
||||
return <FlyoutCreateDrilldown context={{} as any} />;
|
||||
})
|
||||
.add('open in flyout', () => {
|
||||
return (
|
||||
<EuiFlyout>
|
||||
<FlyoutCreateDrilldown context={{} as any} />
|
||||
</EuiFlyout>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiButton } from '@elastic/eui';
|
||||
import { FormCreateDrilldown } from '../form_create_drilldown';
|
||||
import { FlyoutFrame } from '../flyout_frame';
|
||||
import { txtCreateDrilldown } from './i18n';
|
||||
import { FlyoutCreateDrilldownActionContext } from '../../actions';
|
||||
|
||||
export interface FlyoutCreateDrilldownProps {
|
||||
context: FlyoutCreateDrilldownActionContext;
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
export const FlyoutCreateDrilldown: React.FC<FlyoutCreateDrilldownProps> = ({
|
||||
context,
|
||||
onClose,
|
||||
}) => {
|
||||
const footer = (
|
||||
<EuiButton onClick={() => {}} fill>
|
||||
{txtCreateDrilldown}
|
||||
</EuiButton>
|
||||
);
|
||||
|
||||
return (
|
||||
<FlyoutFrame title={txtCreateDrilldown} footer={footer} onClose={onClose}>
|
||||
<FormCreateDrilldown />
|
||||
</FlyoutFrame>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export const txtCreateDrilldown = i18n.translate(
|
||||
'xpack.drilldowns.components.FlyoutCreateDrilldown.CreateDrilldown',
|
||||
{
|
||||
defaultMessage: 'Create drilldown',
|
||||
}
|
||||
);
|
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export * from './flyout_create_drilldown';
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import * as React from 'react';
|
||||
import { EuiFlyout, EuiButton } from '@elastic/eui';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { FlyoutFrame } from '.';
|
||||
|
||||
storiesOf('components/FlyoutFrame', module)
|
||||
.add('default', () => {
|
||||
return <FlyoutFrame>test</FlyoutFrame>;
|
||||
})
|
||||
.add('with title', () => {
|
||||
return <FlyoutFrame title="Hello world">test</FlyoutFrame>;
|
||||
})
|
||||
.add('with onClose', () => {
|
||||
return <FlyoutFrame onClose={() => console.log('onClose')}>test</FlyoutFrame>;
|
||||
})
|
||||
.add('custom footer', () => {
|
||||
return <FlyoutFrame footer={<button>click me!</button>}>test</FlyoutFrame>;
|
||||
})
|
||||
.add('open in flyout', () => {
|
||||
return (
|
||||
<EuiFlyout>
|
||||
<FlyoutFrame
|
||||
title="Create drilldown"
|
||||
footer={<EuiButton>Save</EuiButton>}
|
||||
onClose={() => console.log('onClose')}
|
||||
>
|
||||
test
|
||||
</FlyoutFrame>
|
||||
</EuiFlyout>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { render as renderTestingLibrary, fireEvent } from '@testing-library/react';
|
||||
import { FlyoutFrame } from '.';
|
||||
|
||||
describe('<FlyoutFrame>', () => {
|
||||
test('renders without crashing', () => {
|
||||
const div = document.createElement('div');
|
||||
render(<FlyoutFrame />, div);
|
||||
});
|
||||
|
||||
describe('[title=]', () => {
|
||||
test('renders title in <h1> tag', () => {
|
||||
const div = document.createElement('div');
|
||||
render(<FlyoutFrame title={'foobar'} />, div);
|
||||
|
||||
const title = div.querySelector('h1');
|
||||
expect(title?.textContent).toBe('foobar');
|
||||
});
|
||||
|
||||
test('title can be any react node', () => {
|
||||
const div = document.createElement('div');
|
||||
render(
|
||||
<FlyoutFrame
|
||||
title={
|
||||
<>
|
||||
foo <strong>bar</strong>
|
||||
</>
|
||||
}
|
||||
/>,
|
||||
div
|
||||
);
|
||||
|
||||
const title = div.querySelector('h1');
|
||||
expect(title?.innerHTML).toBe('foo <strong>bar</strong>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('[footer=]', () => {
|
||||
test('if [footer=] prop not provided, does not render footer', () => {
|
||||
const div = document.createElement('div');
|
||||
render(<FlyoutFrame />, div);
|
||||
|
||||
const footer = div.querySelector('[data-test-subj="flyoutFooter"]');
|
||||
expect(footer).toBe(null);
|
||||
});
|
||||
|
||||
test('can render anything in footer', () => {
|
||||
const div = document.createElement('div');
|
||||
render(
|
||||
<FlyoutFrame
|
||||
footer={
|
||||
<>
|
||||
a <em>b</em>
|
||||
</>
|
||||
}
|
||||
/>,
|
||||
div
|
||||
);
|
||||
|
||||
const footer = div.querySelector('[data-test-subj="flyoutFooter"]');
|
||||
expect(footer?.innerHTML).toBe('a <em>b</em>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('[onClose=]', () => {
|
||||
test('does not render close button if "onClose" prop is missing', () => {
|
||||
const div = document.createElement('div');
|
||||
render(<FlyoutFrame />, div);
|
||||
|
||||
const closeButton = div.querySelector('[data-test-subj="flyoutCloseButton"]');
|
||||
expect(closeButton).toBe(null);
|
||||
});
|
||||
|
||||
test('renders close button if "onClose" prop is provided', () => {
|
||||
const div = document.createElement('div');
|
||||
render(<FlyoutFrame onClose={() => {}} />, div);
|
||||
|
||||
const closeButton = div.querySelector('[data-test-subj="flyoutCloseButton"]');
|
||||
expect(closeButton).not.toBe(null);
|
||||
});
|
||||
|
||||
test('calls onClose prop when close button clicked', async () => {
|
||||
const onClose = jest.fn();
|
||||
const el = renderTestingLibrary(<FlyoutFrame onClose={onClose} />);
|
||||
|
||||
const closeButton = el.queryByText('Close');
|
||||
|
||||
expect(onClose).toHaveBeenCalledTimes(0);
|
||||
|
||||
fireEvent.click(closeButton!);
|
||||
|
||||
expect(onClose).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
EuiFlyoutHeader,
|
||||
EuiTitle,
|
||||
EuiFlyoutBody,
|
||||
EuiFlyoutFooter,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiButtonEmpty,
|
||||
} from '@elastic/eui';
|
||||
import { txtClose } from './i18n';
|
||||
|
||||
export interface FlyoutFrameProps {
|
||||
title?: React.ReactNode;
|
||||
footer?: React.ReactNode;
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo This component can be moved to `kibana_react`.
|
||||
*/
|
||||
export const FlyoutFrame: React.FC<FlyoutFrameProps> = ({
|
||||
title = '',
|
||||
footer,
|
||||
onClose,
|
||||
children,
|
||||
}) => {
|
||||
const headerFragment = title && (
|
||||
<EuiFlyoutHeader hasBorder>
|
||||
<EuiTitle size="s">
|
||||
<h1>{title}</h1>
|
||||
</EuiTitle>
|
||||
</EuiFlyoutHeader>
|
||||
);
|
||||
|
||||
const footerFragment = (onClose || footer) && (
|
||||
<EuiFlyoutFooter>
|
||||
<EuiFlexGroup justifyContent="spaceBetween">
|
||||
<EuiFlexItem grow={false}>
|
||||
{onClose && (
|
||||
<EuiButtonEmpty
|
||||
iconType="cross"
|
||||
onClick={onClose}
|
||||
flush="left"
|
||||
data-test-subj="flyoutCloseButton"
|
||||
>
|
||||
{txtClose}
|
||||
</EuiButtonEmpty>
|
||||
)}
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={false} data-test-subj="flyoutFooter">
|
||||
{footer}
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiFlyoutFooter>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{headerFragment}
|
||||
<EuiFlyoutBody>{children}</EuiFlyoutBody>
|
||||
{footerFragment}
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -4,10 +4,8 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { FormCreateDrilldown } from '..';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
storiesOf('components/FormCreateDrilldown', module).add('default', () => {
|
||||
return <FormCreateDrilldown />;
|
||||
export const txtClose = i18n.translate('xpack.drilldowns.components.FlyoutFrame.Close', {
|
||||
defaultMessage: 'Close',
|
||||
});
|
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export * from './flyout_frame';
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import * as React from 'react';
|
||||
import { EuiFlyout } from '@elastic/eui';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { FormCreateDrilldown } from '.';
|
||||
|
||||
const DemoEditName: React.FC = () => {
|
||||
const [name, setName] = React.useState('');
|
||||
|
||||
return <FormCreateDrilldown name={name} onNameChange={setName} />;
|
||||
};
|
||||
|
||||
storiesOf('components/FormCreateDrilldown', module)
|
||||
.add('default', () => {
|
||||
return <FormCreateDrilldown />;
|
||||
})
|
||||
.add('[name=foobar]', () => {
|
||||
return <FormCreateDrilldown name={'foobar'} />;
|
||||
})
|
||||
.add('can edit name', () => <DemoEditName />)
|
||||
.add('open in flyout', () => {
|
||||
return (
|
||||
<EuiFlyout>
|
||||
<FormCreateDrilldown />
|
||||
</EuiFlyout>
|
||||
);
|
||||
});
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { FormCreateDrilldown } from '.';
|
||||
import { render as renderTestingLibrary, fireEvent } from '@testing-library/react';
|
||||
import { txtNameOfDrilldown } from './i18n';
|
||||
|
||||
describe('<FormCreateDrilldown>', () => {
|
||||
test('renders without crashing', () => {
|
||||
const div = document.createElement('div');
|
||||
render(<FormCreateDrilldown name={''} onNameChange={() => {}} />, div);
|
||||
});
|
||||
|
||||
describe('[name=]', () => {
|
||||
test('if name not provided, uses to empty string', () => {
|
||||
const div = document.createElement('div');
|
||||
|
||||
render(<FormCreateDrilldown />, div);
|
||||
|
||||
const input = div.querySelector(
|
||||
'[data-test-subj="dynamicActionNameInput"]'
|
||||
) as HTMLInputElement;
|
||||
|
||||
expect(input?.value).toBe('');
|
||||
});
|
||||
|
||||
test('can set name input field value', () => {
|
||||
const div = document.createElement('div');
|
||||
|
||||
render(<FormCreateDrilldown name={'foo'} />, div);
|
||||
|
||||
const input = div.querySelector(
|
||||
'[data-test-subj="dynamicActionNameInput"]'
|
||||
) as HTMLInputElement;
|
||||
|
||||
expect(input?.value).toBe('foo');
|
||||
|
||||
render(<FormCreateDrilldown name={'bar'} />, div);
|
||||
|
||||
expect(input?.value).toBe('bar');
|
||||
});
|
||||
|
||||
test('fires onNameChange callback on name change', () => {
|
||||
const onNameChange = jest.fn();
|
||||
const utils = renderTestingLibrary(
|
||||
<FormCreateDrilldown name={''} onNameChange={onNameChange} />
|
||||
);
|
||||
const input = utils.getByLabelText(txtNameOfDrilldown);
|
||||
|
||||
expect(onNameChange).toHaveBeenCalledTimes(0);
|
||||
|
||||
fireEvent.change(input, { target: { value: 'qux' } });
|
||||
|
||||
expect(onNameChange).toHaveBeenCalledTimes(1);
|
||||
expect(onNameChange).toHaveBeenCalledWith('qux');
|
||||
|
||||
fireEvent.change(input, { target: { value: 'quxx' } });
|
||||
|
||||
expect(onNameChange).toHaveBeenCalledTimes(2);
|
||||
expect(onNameChange).toHaveBeenCalledWith('quxx');
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiForm, EuiFormRow, EuiFieldText } from '@elastic/eui';
|
||||
import { DrilldownHelloBar } from '../drilldown_hello_bar';
|
||||
import { txtNameOfDrilldown, txtUntitledDrilldown, txtDrilldownAction } from './i18n';
|
||||
import { DrilldownPicker } from '../drilldown_picker';
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
export interface FormCreateDrilldownProps {
|
||||
name?: string;
|
||||
onNameChange?: (name: string) => void;
|
||||
}
|
||||
|
||||
export const FormCreateDrilldown: React.FC<FormCreateDrilldownProps> = ({
|
||||
name = '',
|
||||
onNameChange = noop,
|
||||
}) => {
|
||||
const nameFragment = (
|
||||
<EuiFormRow label={txtNameOfDrilldown}>
|
||||
<EuiFieldText
|
||||
name="drilldown_name"
|
||||
placeholder={txtUntitledDrilldown}
|
||||
value={name}
|
||||
disabled={onNameChange === noop}
|
||||
onChange={event => onNameChange(event.target.value)}
|
||||
data-test-subj="dynamicActionNameInput"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
|
||||
const triggerPicker = <div>Trigger Picker will be here</div>;
|
||||
const actionPicker = (
|
||||
<EuiFormRow label={txtDrilldownAction}>
|
||||
<DrilldownPicker />
|
||||
</EuiFormRow>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<DrilldownHelloBar />
|
||||
<EuiForm>{nameFragment}</EuiForm>
|
||||
{triggerPicker}
|
||||
{actionPicker}
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -7,21 +7,21 @@
|
|||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export const txtNameOfDrilldown = i18n.translate(
|
||||
'xpack.drilldowns.components.form_create_drilldown.nameOfDrilldown',
|
||||
'xpack.drilldowns.components.FormCreateDrilldown.nameOfDrilldown',
|
||||
{
|
||||
defaultMessage: 'Name of drilldown',
|
||||
}
|
||||
);
|
||||
|
||||
export const txtUntitledDrilldown = i18n.translate(
|
||||
'xpack.drilldowns.components.form_create_drilldown.untitledDrilldown',
|
||||
'xpack.drilldowns.components.FormCreateDrilldown.untitledDrilldown',
|
||||
{
|
||||
defaultMessage: 'Untitled drilldown',
|
||||
}
|
||||
);
|
||||
|
||||
export const txtDrilldownAction = i18n.translate(
|
||||
'xpack.drilldowns.components.form_create_drilldown.drilldownAction',
|
||||
'xpack.drilldowns.components.FormCreateDrilldown.drilldownAction',
|
||||
{
|
||||
defaultMessage: 'Drilldown action',
|
||||
}
|
||||
|
|
|
@ -4,27 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiForm, EuiFormRow, EuiFieldText } from '@elastic/eui';
|
||||
import { DrilldownHelloBar } from '../drilldown_hello_bar';
|
||||
import { txtNameOfDrilldown, txtUntitledDrilldown, txtDrilldownAction } from './i18n';
|
||||
import { DrilldownPicker } from '../drilldown_picker';
|
||||
|
||||
// eslint-disable-next-line
|
||||
export interface FormCreateDrilldownProps {}
|
||||
|
||||
export const FormCreateDrilldown: React.FC<FormCreateDrilldownProps> = () => {
|
||||
return (
|
||||
<div>
|
||||
<DrilldownHelloBar />
|
||||
<EuiForm>
|
||||
<EuiFormRow label={txtNameOfDrilldown}>
|
||||
<EuiFieldText name="drilldown_name" placeholder={txtUntitledDrilldown} />
|
||||
</EuiFormRow>
|
||||
<EuiFormRow label={txtDrilldownAction}>
|
||||
<DrilldownPicker />
|
||||
</EuiFormRow>
|
||||
</EuiForm>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export * from './form_create_drilldown';
|
||||
|
|
|
@ -5,17 +5,17 @@
|
|||
*/
|
||||
|
||||
import { CoreSetup } from 'src/core/public';
|
||||
import { OpenFlyoutAddDrilldown } from '../actions/open_flyout_add_drilldown';
|
||||
import { FlyoutCreateDrilldownAction } from '../actions';
|
||||
import { DrilldownsSetupDependencies } from '../plugin';
|
||||
|
||||
export class DrilldownService {
|
||||
bootstrap(core: CoreSetup, { uiActions }: DrilldownsSetupDependencies) {
|
||||
const actionOpenFlyoutAddDrilldown = new OpenFlyoutAddDrilldown({
|
||||
const actionFlyoutCreateDrilldown = new FlyoutCreateDrilldownAction({
|
||||
overlays: async () => (await core.getStartServices())[0].overlays,
|
||||
});
|
||||
|
||||
uiActions.registerAction(actionOpenFlyoutAddDrilldown);
|
||||
uiActions.attachAction('CONTEXT_MENU_TRIGGER', actionOpenFlyoutAddDrilldown.id);
|
||||
uiActions.registerAction(actionFlyoutCreateDrilldown);
|
||||
uiActions.attachAction('CONTEXT_MENU_TRIGGER', actionFlyoutCreateDrilldown.id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,5 +9,5 @@ import { join } from 'path';
|
|||
// eslint-disable-next-line
|
||||
require('@kbn/storybook').runStorybookCli({
|
||||
name: 'drilldowns',
|
||||
storyGlobs: [join(__dirname, '..', 'public', 'components', '**', '*.examples.tsx')],
|
||||
storyGlobs: [join(__dirname, '..', 'public', 'components', '**', '*.story.tsx')],
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue