Skip to content

Commit

Permalink
[Search] Send to background UI (#81793) (#83415)
Browse files Browse the repository at this point in the history
Also adds xpack.data_enhanced.search.sendToBackground.enabled config option
  • Loading branch information
Dosant committed Nov 16, 2020
1 parent 2238f5f commit 769fa71
Show file tree
Hide file tree
Showing 19 changed files with 649 additions and 7 deletions.
1 change: 1 addition & 0 deletions src/dev/storybook/aliases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const storybookAliases = {
canvas: 'x-pack/plugins/canvas/storybook',
codeeditor: 'src/plugins/kibana_react/public/code_editor/.storybook',
dashboard_enhanced: 'x-pack/plugins/dashboard_enhanced/.storybook',
data_enhanced: 'x-pack/plugins/data_enhanced/.storybook',
embeddable: 'src/plugins/embeddable/.storybook',
infra: 'x-pack/plugins/infra/.storybook',
security_solution: 'x-pack/plugins/security_solution/.storybook',
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/data/common/search/session/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* under the License.
*/

import { BehaviorSubject } from 'rxjs';
import { ISessionService } from './types';

export function getSessionServiceMock(): jest.Mocked<ISessionService> {
Expand All @@ -25,6 +26,6 @@ export function getSessionServiceMock(): jest.Mocked<ISessionService> {
start: jest.fn(),
restore: jest.fn(),
getSessionId: jest.fn(),
getSession$: jest.fn(),
getSession$: jest.fn(() => new BehaviorSubject(undefined).asObservable()),
};
}
7 changes: 7 additions & 0 deletions x-pack/plugins/data_enhanced/.storybook/main.js
Original file line number Diff line number Diff line change
@@ -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.
*/

module.exports = require('@kbn/storybook').defaultConfig;
17 changes: 17 additions & 0 deletions x-pack/plugins/data_enhanced/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* 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 { schema, TypeOf } from '@kbn/config-schema';

export const configSchema = schema.object({
search: schema.object({
sendToBackground: schema.object({
enabled: schema.boolean({ defaultValue: false }),
}),
}),
});

export type ConfigSchema = TypeOf<typeof configSchema>;
2 changes: 1 addition & 1 deletion x-pack/plugins/data_enhanced/kibana.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@
"optionalPlugins": ["kibanaUtils", "usageCollection"],
"server": true,
"ui": true,
"requiredBundles": ["kibanaUtils"]
"requiredBundles": ["kibanaUtils", "kibanaReact"]
}
5 changes: 4 additions & 1 deletion x-pack/plugins/data_enhanced/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { PluginInitializerContext } from 'kibana/public';
import { DataEnhancedPlugin, DataEnhancedSetup, DataEnhancedStart } from './plugin';
import { ConfigSchema } from '../config';

export const plugin = () => new DataEnhancedPlugin();
export const plugin = (initializerContext: PluginInitializerContext<ConfigSchema>) =>
new DataEnhancedPlugin(initializerContext);

export { DataEnhancedSetup, DataEnhancedStart };

Expand Down
22 changes: 20 additions & 2 deletions x-pack/plugins/data_enhanced/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { CoreSetup, CoreStart, Plugin } from 'src/core/public';
import React from 'react';
import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'src/core/public';
import { DataPublicPluginSetup, DataPublicPluginStart } from '../../../../src/plugins/data/public';

import { setAutocompleteService } from './services';
import { setupKqlQuerySuggestionProvider, KUERY_LANGUAGE_NAME } from './autocomplete';

import { EnhancedSearchInterceptor } from './search/search_interceptor';
import { toMountPoint } from '../../../../src/plugins/kibana_react/public';
import { createConnectedBackgroundSessionIndicator } from './search';
import { ConfigSchema } from '../config';

export interface DataEnhancedSetupDependencies {
data: DataPublicPluginSetup;
Expand All @@ -25,6 +29,8 @@ export class DataEnhancedPlugin
implements Plugin<void, void, DataEnhancedSetupDependencies, DataEnhancedStartDependencies> {
private enhancedSearchInterceptor!: EnhancedSearchInterceptor;

constructor(private initializerContext: PluginInitializerContext<ConfigSchema>) {}

public setup(
core: CoreSetup<DataEnhancedStartDependencies>,
{ data }: DataEnhancedSetupDependencies
Expand Down Expand Up @@ -52,6 +58,18 @@ export class DataEnhancedPlugin

public start(core: CoreStart, plugins: DataEnhancedStartDependencies) {
setAutocompleteService(plugins.data.autocomplete);

if (this.initializerContext.config.get().search.sendToBackground.enabled) {
core.chrome.setBreadcrumbsAppendExtension({
content: toMountPoint(
React.createElement(
createConnectedBackgroundSessionIndicator({
sessionService: plugins.data.search.session,
})
)
),
});
}
}

public stop() {
Expand Down
7 changes: 7 additions & 0 deletions x-pack/plugins/data_enhanced/public/search/index.ts
Original file line number Diff line number Diff line change
@@ -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 './ui';
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.backgroundSessionIndicator {
padding: 0 $euiSizeXS;
}

@include euiBreakpoint('xs', 's') {
.backgroundSessionIndicator__popoverContainer.euiFlexGroup--responsive .euiFlexItem {
margin-bottom: $euiSizeXS !important;
}
}

.backgroundSessionIndicator__verticalDivider {
@include euiBreakpoint('xs', 's') {
margin-left: $euiSizeXS;
padding-left: $euiSizeXS;
}

@include euiBreakpoint('m', 'l', 'xl') {
border-left: $euiBorderThin;
align-self: stretch;
margin-left: $euiSizeS;
padding-left: $euiSizeS;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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 { storiesOf } from '@storybook/react';
import { BackgroundSessionIndicator } from './background_session_indicator';
import { BackgroundSessionViewState } from '../connected_background_session_indicator';

storiesOf('components/BackgroundSessionIndicator', module).add('default', () => (
<>
<div>
<BackgroundSessionIndicator state={BackgroundSessionViewState.Loading} />
</div>
<div>
<BackgroundSessionIndicator state={BackgroundSessionViewState.Completed} />
</div>
<div>
<BackgroundSessionIndicator state={BackgroundSessionViewState.BackgroundLoading} />
</div>
<div>
<BackgroundSessionIndicator state={BackgroundSessionViewState.BackgroundCompleted} />
</div>
<div>
<BackgroundSessionIndicator state={BackgroundSessionViewState.Restored} />
</div>
</>
));
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* 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, { ReactNode } from 'react';
import { screen, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { BackgroundSessionIndicator } from './background_session_indicator';
import { BackgroundSessionViewState } from '../connected_background_session_indicator';
import { IntlProvider } from 'react-intl';

function Container({ children }: { children?: ReactNode }) {
return <IntlProvider locale="en">{children}</IntlProvider>;
}

test('Loading state', async () => {
const onCancel = jest.fn();
render(
<Container>
<BackgroundSessionIndicator state={BackgroundSessionViewState.Loading} onCancel={onCancel} />
</Container>
);

await userEvent.click(screen.getByLabelText('Loading results'));
await userEvent.click(screen.getByText('Cancel'));

expect(onCancel).toBeCalled();
});

test('Completed state', async () => {
const onSave = jest.fn();
render(
<Container>
<BackgroundSessionIndicator
state={BackgroundSessionViewState.Completed}
onSaveResults={onSave}
/>
</Container>
);

await userEvent.click(screen.getByLabelText('Results loaded'));
await userEvent.click(screen.getByText('Save'));

expect(onSave).toBeCalled();
});

test('Loading in the background state', async () => {
const onCancel = jest.fn();
render(
<Container>
<BackgroundSessionIndicator
state={BackgroundSessionViewState.BackgroundLoading}
onCancel={onCancel}
/>
</Container>
);

await userEvent.click(screen.getByLabelText('Loading results in the background'));
await userEvent.click(screen.getByText('Cancel'));

expect(onCancel).toBeCalled();
});

test('BackgroundCompleted state', async () => {
const onViewSession = jest.fn();
render(
<Container>
<BackgroundSessionIndicator
state={BackgroundSessionViewState.BackgroundCompleted}
onViewBackgroundSessions={onViewSession}
/>
</Container>
);

await userEvent.click(screen.getByLabelText('Results loaded in the background'));
await userEvent.click(screen.getByText('View background sessions'));

expect(onViewSession).toBeCalled();
});

test('Restored state', async () => {
const onRefresh = jest.fn();
render(
<Container>
<BackgroundSessionIndicator
state={BackgroundSessionViewState.Restored}
onRefresh={onRefresh}
/>
</Container>
);

await userEvent.click(screen.getByLabelText('Results no longer current'));
await userEvent.click(screen.getByText('Refresh'));

expect(onRefresh).toBeCalled();
});
Loading

0 comments on commit 769fa71

Please sign in to comment.