Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

export { setupGetFieldSuggestions } from './field';
export { setupGetValueSuggestions } from './value';
export { setupGetOperatorSuggestions } from './operator';
export { setupGetConjunctionSuggestions } from './conjunction';
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,12 @@
* Side Public License, v 1.
*/

import { CoreSetup } from '@kbn/core/public';
import { $Keys } from 'utility-types';
import type { CoreSetup } from '@kbn/core/public';
import type { $Keys } from 'utility-types';
import { flatten, uniqBy } from 'lodash';
import { setupGetFieldSuggestions } from './field';
import { setupGetValueSuggestions } from './value';
import { setupGetOperatorSuggestions } from './operator';
import { setupGetConjunctionSuggestions } from './conjunction';
import { UnifiedSearchPublicPluginStart } from '../../../types';
import {
import type { UnifiedSearchPublicPluginStart } from '../../../types';

import type {
QuerySuggestion,
QuerySuggestionGetFnArgs,
QuerySuggestionGetFn,
Expand All @@ -30,40 +27,59 @@ export const KUERY_LANGUAGE_NAME = 'kuery';
export const setupKqlQuerySuggestionProvider = (
core: CoreSetup<object, UnifiedSearchPublicPluginStart>
): QuerySuggestionGetFn => {
const providers = {
field: setupGetFieldSuggestions(core),
value: setupGetValueSuggestions(core),
operator: setupGetOperatorSuggestions(core),
conjunction: setupGetConjunctionSuggestions(core),
};
let getSuggestionsByType:
| ((
cursoredQuery: string,
querySuggestionsArgs: QuerySuggestionGetFnArgs
) => Promise<Array<Promise<QuerySuggestion[]>> | []>)
| undefined;

const getSuggestionsByType = async (
cursoredQuery: string,
querySuggestionsArgs: QuerySuggestionGetFnArgs
): Promise<Array<Promise<QuerySuggestion[]>> | []> => {
try {
const { fromKueryExpression } = await import('@kbn/es-query');
const cursorNode = fromKueryExpression(cursoredQuery, {
cursorSymbol,
parseCursor: true,
});

return cursorNode.suggestionTypes.map((type: $Keys<typeof providers>) =>
providers[type](querySuggestionsArgs, cursorNode)
);
} catch (e) {
return [];
const asyncGetSuggestionsByTypeFn = async () => {
if (getSuggestionsByType) {
return getSuggestionsByType;
}
const {
setupGetFieldSuggestions,
setupGetValueSuggestions,
setupGetOperatorSuggestions,
setupGetConjunctionSuggestions,
} = await import('./async_loads');
const { fromKueryExpression } = await import('@kbn/es-query');

const providers = {
field: setupGetFieldSuggestions(core),
value: setupGetValueSuggestions(core),
operator: setupGetOperatorSuggestions(core),
conjunction: setupGetConjunctionSuggestions(core),
};

return (getSuggestionsByType = async (
cursoredQuery: string,
querySuggestionsArgs: QuerySuggestionGetFnArgs
): Promise<Array<Promise<QuerySuggestion[]>> | []> => {
try {
const cursorNode = fromKueryExpression(cursoredQuery, {
cursorSymbol,
parseCursor: true,
});

return cursorNode.suggestionTypes.map((type: $Keys<typeof providers>) =>
providers[type](querySuggestionsArgs, cursorNode)
);
} catch (e) {
return [];
}
});
};

return async (querySuggestionsArgs): Promise<QuerySuggestion[]> => {
const { query, selectionStart, selectionEnd } = querySuggestionsArgs;
const cursoredQuery = `${query.substr(0, selectionStart)}${cursorSymbol}${query.substr(
selectionEnd
)}`;

return Promise.all(await getSuggestionsByType(cursoredQuery, querySuggestionsArgs)).then(
(suggestionsByType) => dedup(flatten(suggestionsByType))
const fn = await asyncGetSuggestionsByTypeFn();
return Promise.all(await fn(cursoredQuery, querySuggestionsArgs)).then((suggestionsByType) =>
dedup(flatten(suggestionsByType))
);
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { memoize } from 'lodash';
import { UI_SETTINGS, ValueSuggestionsMethod } from '@kbn/data-plugin/common';
import type { DataView, DataViewField } from '@kbn/data-views-plugin/common';
import type { TimefilterSetup } from '@kbn/data-plugin/public';
import { AutocompleteUsageCollector } from '../collectors';
import type { AutocompleteUsageCollector } from '../collectors';

export type ValueSuggestionsGetFn = (args: ValueSuggestionsGetFnArgs) => Promise<any[]>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
import { indexPatternEditorPluginMock as dataViewEditorPluginMock } from '@kbn/data-view-editor-plugin/public/mocks';
import { ChangeDataView } from './change_dataview';
import { DataViewPickerPropsExtended, TextBasedLanguages } from '.';
import { DataViewPickerPropsExtended, TextBasedLanguages } from './data_view_picker';

describe('DataView component', () => {
const createMockWebStorage = () => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import {
} from '@elastic/eui';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import type { IUnifiedSearchPluginServices } from '../types';
import type { DataViewPickerPropsExtended } from '.';
import type { DataViewPickerPropsExtended } from './data_view_picker';
import type { DataViewListItemEnhanced } from './dataview_list';
import type { TextBasedLanguagesListProps } from './text_languages_list';
import type { TextBasedLanguagesTransitionModalProps } from './text_languages_transition_modal';
Expand Down
147 changes: 147 additions & 0 deletions src/plugins/unified_search/public/dataview_picker/data_view_picker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import React from 'react';
import type { EuiButtonProps, EuiSelectableProps } from '@elastic/eui';
import type { DataView, DataViewListItem } from '@kbn/data-views-plugin/public';
import type { AggregateQuery, Query } from '@kbn/es-query';
import { ChangeDataView } from './change_dataview';

export type ChangeDataViewTriggerProps = EuiButtonProps & {
label: string;
title?: string;
};

export enum TextBasedLanguages {
SQL = 'SQL',
ESQL = 'ESQL',
}

export interface OnSaveTextLanguageQueryProps {
onSave: () => void;
onCancel: () => void;
}

/** @public */
export interface DataViewPickerProps {
/**
* The properties of the button that triggers the dataview picker.
*/
trigger: ChangeDataViewTriggerProps;
/**
* Flag that should be enabled when the current dataview is missing.
*/
isMissingCurrent?: boolean;
/**
* Callback that is called when the user changes the currently selected dataview.
*/
onChangeDataView: (newId: string) => void;
/**
* Callback that is called when the user edits the current data view via flyout.
* The first parameter is the updated data view stub without fetched fields
*/
onEditDataView?: (updatedDataViewStub: DataView) => void;
/**
* The id of the selected dataview.
*/
currentDataViewId?: string;
/**
* The adHocDataviews.
*/
adHocDataViews?: DataView[];
/**
* Saved data views
*/
savedDataViews?: DataViewListItem[];
/**
* EuiSelectable properties.
*/
selectableProps?: EuiSelectableProps;
/**
* Callback that is called when the user clicks the add runtime field option.
* Also works as a flag to show the add runtime field button.
*/
onAddField?: () => void;
/**
* Callback that is called when the user clicks the create dataview option.
* Also works as a flag to show the create dataview button.
*/
onDataViewCreated?: () => void;

onCreateDefaultAdHocDataView?: (pattern: string) => void;
/**
* List of the supported text based languages (SQL, ESQL) etc.
* Defined per application, if not provided, no text based languages
* will be available.
*/
textBasedLanguages?: TextBasedLanguages[];
/**
* Callback that is called when the user clicks the Save and switch transition modal button
*/
onSaveTextLanguageQuery?: ({ onSave, onCancel }: OnSaveTextLanguageQueryProps) => void;

/**
* Makes the picker disabled by disabling the popover trigger
*/
isDisabled?: boolean;
}

export interface DataViewPickerPropsExtended extends DataViewPickerProps {
/**
* Callback that is called when the user clicks the submit button
*/
onTextLangQuerySubmit?: (query?: Query | AggregateQuery) => void;
/**
* Text based language that is currently selected; depends on the query
*/
textBasedLanguage?: string;
}

export const DataViewPicker = ({
isMissingCurrent,
currentDataViewId,
adHocDataViews,
savedDataViews,
onChangeDataView,
onEditDataView,
onAddField,
onDataViewCreated,
trigger,
selectableProps,
textBasedLanguages,
onSaveTextLanguageQuery,
onTextLangQuerySubmit,
textBasedLanguage,
onCreateDefaultAdHocDataView,
isDisabled,
}: DataViewPickerPropsExtended) => {
return (
<ChangeDataView
isMissingCurrent={isMissingCurrent}
currentDataViewId={currentDataViewId}
onChangeDataView={onChangeDataView}
onEditDataView={onEditDataView}
onAddField={onAddField}
onDataViewCreated={onDataViewCreated}
onCreateDefaultAdHocDataView={onCreateDefaultAdHocDataView}
trigger={trigger}
adHocDataViews={adHocDataViews}
savedDataViews={savedDataViews}
selectableProps={selectableProps}
textBasedLanguages={textBasedLanguages}
onSaveTextLanguageQuery={onSaveTextLanguageQuery}
onTextLangQuerySubmit={onTextLangQuerySubmit}
textBasedLanguage={textBasedLanguage}
isDisabled={isDisabled}
/>
);
};

// React.lazy support
// eslint-disable-next-line import/no-default-export
export default DataViewPicker;
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { DataViewsList } from './dataview_list';
import { IUnifiedSearchPluginServices } from '../types';
import { ExploreMatchingButton } from './explore_matching_button';

interface DataViewSelectorProps {
export interface DataViewSelectorProps {
currentDataViewId?: string;
searchListInputId?: string;
dataViewsList: DataViewListItem[];
Expand Down Expand Up @@ -95,3 +95,7 @@ export const DataViewSelector = ({
</Fragment>
);
};

// React.lazy support
// eslint-disable-next-line import/no-default-export
export default DataViewSelector;
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,7 @@ export function DataViewsList({
</EuiSelectable>
);
}

// React.lazy support
// eslint-disable-next-line import/no-default-export
export default DataViewsList;
Loading