Skip to content

Commit

Permalink
Merge branch 'master' into ingest/config-to-policy-action
Browse files Browse the repository at this point in the history
  • Loading branch information
elasticmachine committed Sep 23, 2020
2 parents 78c8380 + e0f9323 commit 807c4b9
Show file tree
Hide file tree
Showing 23 changed files with 654 additions and 339 deletions.
537 changes: 362 additions & 175 deletions docs/management/advanced-options.asciidoc

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -17,43 +17,36 @@
* under the License.
*/
import React from 'react';
import { wait } from '@testing-library/dom';
import { cleanup, render } from '@testing-library/react/pure';
import { ErrorEmbeddable } from './error_embeddable';
import { EmbeddableRoot } from './embeddable_root';
import { mount } from 'enzyme';

afterEach(cleanup);

test('ErrorEmbeddable renders an embeddable', async () => {
const embeddable = new ErrorEmbeddable('some error occurred', { id: '123', title: 'Error' });
const component = mount(<EmbeddableRoot embeddable={embeddable} />);
expect(
component.getDOMNode().querySelectorAll('[data-test-subj="embeddableStackError"]').length
).toBe(1);
expect(
component.getDOMNode().querySelectorAll('[data-test-subj="errorMessageMarkdown"]').length
).toBe(1);
expect(
component
.getDOMNode()
.querySelectorAll('[data-test-subj="errorMessageMarkdown"]')[0]
.innerHTML.includes('some error occurred')
).toBe(true);
const { getByTestId, getByText } = render(<EmbeddableRoot embeddable={embeddable} />);

expect(getByTestId('embeddableStackError')).toBeVisible();
await wait(() => getByTestId('errorMessageMarkdown')); // wait for lazy markdown component
expect(getByText(/some error occurred/i)).toBeVisible();
});

test('ErrorEmbeddable renders an embeddable with markdown message', async () => {
const error = '[some link](http://localhost:5601/takeMeThere)';
const embeddable = new ErrorEmbeddable(error, { id: '123', title: 'Error' });
const component = mount(<EmbeddableRoot embeddable={embeddable} />);
expect(
component.getDOMNode().querySelectorAll('[data-test-subj="embeddableStackError"]').length
).toBe(1);
expect(
component.getDOMNode().querySelectorAll('[data-test-subj="errorMessageMarkdown"]').length
).toBe(1);
expect(
component
.getDOMNode()
.querySelectorAll('[data-test-subj="errorMessageMarkdown"]')[0]
.innerHTML.includes(
'<a href="http://localhost:5601/takeMeThere" target="_blank" rel="noopener noreferrer">some link</a>'
)
).toBe(true);
const { getByTestId, getByText } = render(<EmbeddableRoot embeddable={embeddable} />);

expect(getByTestId('embeddableStackError')).toBeVisible();
await wait(() => getByTestId('errorMessageMarkdown')); // wait for lazy markdown component
expect(getByText(/some link/i)).toMatchInlineSnapshot(`
<a
href="http://localhost:5601/takeMeThere"
rel="noopener noreferrer"
target="_blank"
>
some link
</a>
`);
});
4 changes: 4 additions & 0 deletions src/plugins/kibana_react/public/code_editor/code_editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,7 @@ export class CodeEditor extends React.Component<Props, {}> {
}
};
}

// React.lazy requires default export
// eslint-disable-next-line import/no-default-export
export default CodeEditor;
18 changes: 15 additions & 3 deletions src/plugins/kibana_react/public/code_editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,23 @@
* under the License.
*/
import React from 'react';
import { EuiDelayRender, EuiLoadingContent } from '@elastic/eui';
import { useUiSetting } from '../ui_settings';
import { CodeEditor as BaseEditor, Props } from './code_editor';
import type { Props } from './code_editor';

const LazyBaseEditor = React.lazy(() => import('./code_editor'));

const Fallback = () => (
<EuiDelayRender>
<EuiLoadingContent lines={3} />
</EuiDelayRender>
);

export const CodeEditor: React.FunctionComponent<Props> = (props) => {
const darkMode = useUiSetting<boolean>('theme:darkMode');

return <BaseEditor {...props} useDarkTheme={darkMode} />;
return (
<React.Suspense fallback={<Fallback />}>
<LazyBaseEditor {...props} useDarkTheme={darkMode} />
</React.Suspense>
);
};
26 changes: 24 additions & 2 deletions src/plugins/kibana_react/public/markdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,27 @@
* under the License.
*/

export { MarkdownSimple } from './markdown_simple';
export { Markdown } from './markdown';
import React from 'react';
import { EuiLoadingContent, EuiDelayRender } from '@elastic/eui';
import type { MarkdownSimpleProps } from './markdown_simple';
import type { MarkdownProps } from './markdown';

const Fallback = () => (
<EuiDelayRender>
<EuiLoadingContent lines={3} />
</EuiDelayRender>
);

const LazyMarkdownSimple = React.lazy(() => import('./markdown_simple'));
export const MarkdownSimple = (props: MarkdownSimpleProps) => (
<React.Suspense fallback={<Fallback />}>
<LazyMarkdownSimple {...props} />
</React.Suspense>
);

const LazyMarkdown = React.lazy(() => import('./markdown'));
export const Markdown = (props: MarkdownProps) => (
<React.Suspense fallback={<Fallback />}>
<LazyMarkdown {...props} />
</React.Suspense>
);
6 changes: 5 additions & 1 deletion src/plugins/kibana_react/public/markdown/markdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export const markdownFactory = memoize(
}
);

interface MarkdownProps extends React.HTMLAttributes<HTMLDivElement> {
export interface MarkdownProps extends React.HTMLAttributes<HTMLDivElement> {
className?: string;
markdown?: string;
openLinksInNewTab?: boolean;
Expand Down Expand Up @@ -112,3 +112,7 @@ export class Markdown extends PureComponent<MarkdownProps> {
);
}
}

// Needed for React.lazy
// eslint-disable-next-line import/no-default-export
export default Markdown;
6 changes: 5 additions & 1 deletion src/plugins/kibana_react/public/markdown/markdown_simple.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,15 @@ const markdownRenderers = {
root: Fragment,
};

interface MarkdownSimpleProps {
export interface MarkdownSimpleProps {
children: string;
}

// Render markdown string into JSX inside of a Fragment.
export const MarkdownSimple = ({ children }: MarkdownSimpleProps) => (
<ReactMarkdown renderers={markdownRenderers}>{children}</ReactMarkdown>
);

// Needed for React.lazy
// eslint-disable-next-line import/no-default-export
export default MarkdownSimple;
Original file line number Diff line number Diff line change
Expand Up @@ -556,3 +556,6 @@ class TableListView extends React.Component<TableListViewProps, TableListViewSta
}

export { TableListView };

// eslint-disable-next-line import/no-default-export
export default TableListView;
20 changes: 9 additions & 11 deletions src/plugins/kibana_utils/public/history/redirect_when_missing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,19 @@
import React, { Fragment } from 'react';
import { History } from 'history';
import { i18n } from '@kbn/i18n';
import { EuiLoadingSpinner } from '@elastic/eui';
import ReactDOM from 'react-dom';
import ReactMarkdown from 'react-markdown';

import { ApplicationStart, HttpStart, ToastsSetup } from 'kibana/public';
import { SavedObjectNotFound } from '..';

const ReactMarkdown = React.lazy(() => import('react-markdown'));
const ErrorRenderer = (props: { children: string }) => (
<React.Suspense fallback={<EuiLoadingSpinner />}>
<ReactMarkdown renderers={{ root: Fragment }} {...props} />
</React.Suspense>
);

interface Mapping {
[key: string]: string | { app: string; path: string };
}
Expand Down Expand Up @@ -96,16 +103,7 @@ export function redirectWhenMissing({
defaultMessage: 'Saved object is missing',
}),
text: (element: HTMLElement) => {
ReactDOM.render(
<ReactMarkdown
renderers={{
root: Fragment,
}}
>
{error.message}
</ReactMarkdown>,
element
);
ReactDOM.render(<ErrorRenderer>{error.message}</ErrorRenderer>, element);
return () => ReactDOM.unmountComponentAtNode(element);
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@
*/

import React from 'react';
import { render, mount } from 'enzyme';
import { wait } from '@testing-library/dom';
import { render, cleanup } from '@testing-library/react/pure';
import { MarkdownVisWrapper } from './markdown_vis_controller';

afterEach(cleanup);

describe('markdown vis controller', () => {
it('should set html from markdown params', () => {
it('should set html from markdown params', async () => {
const vis = {
params: {
openLinksInNewTab: false,
Expand All @@ -32,13 +35,22 @@ describe('markdown vis controller', () => {
},
};

const wrapper = render(
const { getByTestId, getByText } = render(
<MarkdownVisWrapper visParams={vis.params} renderComplete={jest.fn()} fireEvent={jest.fn()} />
);
expect(wrapper.find('a').text()).toBe('markdown');

await wait(() => getByTestId('markdownBody'));

expect(getByText('markdown')).toMatchInlineSnapshot(`
<a
href="http://daringfireball.net/projects/markdown"
>
markdown
</a>
`);
});

it('should not render the html', () => {
it('should not render the html', async () => {
const vis = {
params: {
openLinksInNewTab: false,
Expand All @@ -47,13 +59,20 @@ describe('markdown vis controller', () => {
},
};

const wrapper = render(
const { getByTestId, getByText } = render(
<MarkdownVisWrapper visParams={vis.params} renderComplete={jest.fn()} fireEvent={jest.fn()} />
);
expect(wrapper.text()).toBe('Testing <a>html</a>\n');

await wait(() => getByTestId('markdownBody'));

expect(getByText(/testing/i)).toMatchInlineSnapshot(`
<p>
Testing &lt;a&gt;html&lt;/a&gt;
</p>
`);
});

it('should update the HTML when render again with changed params', () => {
it('should update the HTML when render again with changed params', async () => {
const vis = {
params: {
openLinksInNewTab: false,
Expand All @@ -62,13 +81,20 @@ describe('markdown vis controller', () => {
},
};

const wrapper = mount(
const { getByTestId, getByText, rerender } = render(
<MarkdownVisWrapper visParams={vis.params} renderComplete={jest.fn()} fireEvent={jest.fn()} />
);
expect(wrapper.text().trim()).toBe('Initial');

await wait(() => getByTestId('markdownBody'));

expect(getByText(/initial/i)).toBeInTheDocument();

vis.params.markdown = 'Updated';
wrapper.setProps({ vis });
expect(wrapper.text().trim()).toBe('Updated');
rerender(
<MarkdownVisWrapper visParams={vis.params} renderComplete={jest.fn()} fireEvent={jest.fn()} />
);

expect(getByText(/Updated/i)).toBeInTheDocument();
});

describe('renderComplete', () => {
Expand All @@ -86,56 +112,71 @@ describe('markdown vis controller', () => {
renderComplete.mockClear();
});

it('should be called on initial rendering', () => {
mount(
it('should be called on initial rendering', async () => {
const { getByTestId } = render(
<MarkdownVisWrapper
visParams={vis.params}
renderComplete={renderComplete}
fireEvent={jest.fn()}
/>
);
expect(renderComplete.mock.calls.length).toBe(1);

await wait(() => getByTestId('markdownBody'));

expect(renderComplete).toHaveBeenCalledTimes(1);
});

it('should be called on successive render when params change', () => {
mount(
it('should be called on successive render when params change', async () => {
const { getByTestId, rerender } = render(
<MarkdownVisWrapper
visParams={vis.params}
renderComplete={renderComplete}
fireEvent={jest.fn()}
/>
);
expect(renderComplete.mock.calls.length).toBe(1);

await wait(() => getByTestId('markdownBody'));

expect(renderComplete).toHaveBeenCalledTimes(1);

renderComplete.mockClear();
vis.params.markdown = 'changed';
mount(

rerender(
<MarkdownVisWrapper
visParams={vis.params}
renderComplete={renderComplete}
fireEvent={jest.fn()}
/>
);
expect(renderComplete.mock.calls.length).toBe(1);

expect(renderComplete).toHaveBeenCalledTimes(1);
});

it('should be called on successive render even without data change', () => {
mount(
it('should be called on successive render even without data change', async () => {
const { getByTestId, rerender } = render(
<MarkdownVisWrapper
visParams={vis.params}
renderComplete={renderComplete}
fireEvent={jest.fn()}
/>
);
expect(renderComplete.mock.calls.length).toBe(1);

await wait(() => getByTestId('markdownBody'));

expect(renderComplete).toHaveBeenCalledTimes(1);

renderComplete.mockClear();
mount(

rerender(
<MarkdownVisWrapper
visParams={vis.params}
renderComplete={renderComplete}
fireEvent={jest.fn()}
/>
);
expect(renderComplete.mock.calls.length).toBe(1);

expect(renderComplete).toHaveBeenCalledTimes(1);
});
});
});
Loading

0 comments on commit 807c4b9

Please sign in to comment.