Skip to content

Commit 2607602

Browse files
committed
[Controls] Add ESQL control types to options list (elastic#233126)
## Summary Part of elastic#227062 This adds types for ES|QL control properties and API methods to the options list control factory in preparation to unify the factories. It does not actually yet make the control function with ES|QL data sources or variables, but lays the groundwork for adding this functionality in a second PR. - Options list control now optionally accepts all the properties in `ESQLControlState` as a possible input state. The input state must now be either `ESQLControlState` or `DefaultDataControlState`. - The options list control and component APIs now publish `esqlQuery$`, `esqlVariable$`, and `esqlControlType$`. `esqlVariable$` is an `ESQLControlVariable` derived from the ES|QL control's `variableType`/`variableName`, and the other two subjects are simply renamed properties to reduce ambiguity downstream in the control factory. - `esqlVariable$` will publish from the control API and be read by the control group. This is how current ES|QL controls already publish their variables and make them available to the dashboard. In this PR, it will always publish `undefined` and therefore do nothing. - `esqlControlType$` can be used to determine whether to fetch available options list suggestions, or to pull them from the `availableOptions` input state - `esqlQuery$` can be used to fetch available options if the control type is `VALUES_FROM_QUERY` - Options list suggestions data requests to be passed to `fetchAndValidate` now have types for possible ES|QL requests. See [this part of the initial draft unification PR](https://github.com/elastic/kibana/pull/230132/files#diff-338ef52d0d7391e8b3fb6cbd90747d33f3a93b0389a8fa586f4f94e86fbc1916) for an example of what this enables us to do. - An ESQL state manager has been added to the options list factory, even though it's not fully implemented yet. This generates all the needed publishing subjects and allows the component and control APIs to pass the new type checks. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios (cherry picked from commit 493cd58) # Conflicts: # src/platform/plugins/shared/controls/common/options_list/types.ts # src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.tsx # src/platform/plugins/shared/controls/public/controls/data_controls/types.ts # src/platform/plugins/shared/controls/public/controls/esql_control/types.ts
1 parent dc5c4a9 commit 2607602

File tree

12 files changed

+72
-52
lines changed

12 files changed

+72
-52
lines changed

src/platform/packages/shared/kbn-alerts-ui-shared/src/alert_filter_controls/constants.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*/
99

1010
import { ALERT_RULE_NAME, ALERT_STATUS } from '@kbn/rule-data-utils';
11-
import type { OptionsListControlState } from '@kbn/controls-plugin/public';
11+
import type { OptionsListDSLControlState } from '@kbn/controls-plugin/public';
1212
import { i18n } from '@kbn/i18n';
1313
import type { FilterControlConfig } from './types';
1414

@@ -65,7 +65,7 @@ export const TEST_IDS = {
6565
},
6666
};
6767

68-
export const COMMON_OPTIONS_LIST_CONTROL_INPUTS: Partial<OptionsListControlState> = {
68+
export const COMMON_OPTIONS_LIST_CONTROL_INPUTS: Partial<OptionsListDSLControlState> = {
6969
hideExclude: true,
7070
hideSort: true,
7171
placeholder: '',

src/platform/packages/shared/kbn-alerts-ui-shared/src/alert_filter_controls/mocks/data.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import type {
1111
ControlGroupRuntimeState,
12-
OptionsListControlState,
12+
OptionsListDSLControlState,
1313
} from '@kbn/controls-plugin/public';
1414
import type { Filter } from '@kbn/es-query';
1515
import { ALERT_DURATION, ALERT_RULE_NAME, ALERT_START, ALERT_STATUS } from '@kbn/rule-data-utils';
@@ -41,7 +41,7 @@ export const sampleOutputData: ControlGroupOutput = {
4141
],
4242
};
4343

44-
export const initialInputData: ControlGroupRuntimeState<OptionsListControlState> = {
44+
export const initialInputData: ControlGroupRuntimeState<OptionsListDSLControlState> = {
4545
initialChildControlState: {
4646
'0': {
4747
type: 'optionsListControl',

src/platform/packages/shared/kbn-alerts-ui-shared/src/alert_filter_controls/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import type { Filter, Query, TimeRange } from '@kbn/es-query';
1111
import type {
1212
ControlGroupRenderer,
13-
OptionsListControlState,
13+
OptionsListDSLControlState,
1414
ControlGroupRuntimeState,
1515
ControlGroupRendererApi,
1616
} from '@kbn/controls-plugin/public';
@@ -19,7 +19,7 @@ import type { Storage } from '@kbn/kibana-utils-plugin/public';
1919
export type FilterUrlFormat = Record<
2020
string,
2121
Pick<
22-
OptionsListControlState,
22+
OptionsListDSLControlState,
2323
'selectedOptions' | 'title' | 'fieldName' | 'existsSelected' | 'exclude'
2424
>
2525
>;
@@ -29,7 +29,7 @@ export interface FilterContextType {
2929
addControl: (controls: FilterControlConfig) => void;
3030
}
3131

32-
export type FilterControlConfig = Omit<OptionsListControlState, 'dataViewId'> & {
32+
export type FilterControlConfig = Omit<OptionsListDSLControlState, 'dataViewId'> & {
3333
/*
3434
* Determines the presence and order of a control
3535
* */

src/platform/packages/shared/kbn-alerts-ui-shared/src/alert_filter_controls/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import type {
1111
ControlGroupRuntimeState,
12-
OptionsListControlState,
12+
OptionsListDSLControlState,
1313
ControlPanelState,
1414
} from '@kbn/controls-plugin/public';
1515

@@ -25,7 +25,7 @@ export const getFilterItemObjListFromControlState = (controlState: ControlGroupR
2525
const panels = getPanelsInOrderFromControlsState(controlState);
2626
return panels.map((panel) => {
2727
const { fieldName, selectedOptions, title, existsSelected, exclude, hideActionBar } =
28-
panel as ControlPanelState<OptionsListControlState>;
28+
panel as ControlPanelState<OptionsListDSLControlState>;
2929

3030
return {
3131
fieldName: fieldName as string,

src/platform/plugins/shared/controls/common/options_list/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export type { OptionsListSearchTechnique } from './suggestions_searching';
1313
export type { OptionsListSortingType } from './suggestions_sorting';
1414
export type {
1515
OptionsListControlState,
16+
OptionsListESQLControlState,
17+
OptionsListDSLControlState,
1618
OptionsListDisplaySettings,
1719
OptionsListFailureResponse,
1820
OptionsListRequest,

src/platform/plugins/shared/controls/common/options_list/types.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@
1010
import { DataView, FieldSpec, RuntimeFieldSpec } from '@kbn/data-views-plugin/common';
1111
import type { AggregateQuery, BoolQuery, Filter, Query, TimeRange } from '@kbn/es-query';
1212

13-
import { OptionsListSelection } from './options_list_selections';
14-
import { OptionsListSortingType } from './suggestions_sorting';
15-
import { DefaultDataControlState } from '../types';
16-
import { OptionsListSearchTechnique } from './suggestions_searching';
13+
import type { ESQLControlState } from '@kbn/esql-types';
14+
import type { OptionsListSelection } from './options_list_selections';
15+
import type { OptionsListSortingType } from './suggestions_sorting';
16+
import type { DefaultDataControlState } from '../types';
17+
import type { OptionsListSearchTechnique } from './suggestions_searching';
1718

1819
/**
1920
* ----------------------------------------------------------------
@@ -29,17 +30,27 @@ export interface OptionsListDisplaySettings {
2930
hideSort?: boolean;
3031
}
3132

32-
export interface OptionsListControlState
33-
extends DefaultDataControlState,
34-
OptionsListDisplaySettings {
33+
type OptionsListBaseControlState = OptionsListDisplaySettings & {
3534
searchTechnique?: OptionsListSearchTechnique;
3635
sort?: OptionsListSortingType;
3736
selectedOptions?: OptionsListSelection[];
3837
existsSelected?: boolean;
3938
runPastTimeout?: boolean;
4039
singleSelect?: boolean;
4140
exclude?: boolean;
42-
}
41+
};
42+
export type OptionsListDSLControlState = DefaultDataControlState & OptionsListBaseControlState;
43+
export type OptionsListESQLControlState = ESQLControlState & OptionsListBaseControlState;
44+
45+
export type OptionsListControlState = OptionsListDSLControlState | OptionsListESQLControlState;
46+
47+
export const isOptionsListESQLControlState = (
48+
state: OptionsListControlState | undefined
49+
): state is OptionsListESQLControlState =>
50+
typeof state !== 'undefined' &&
51+
Object.hasOwn(state, 'esqlQuery') &&
52+
Object.hasOwn(state, 'controlType') &&
53+
!Object.hasOwn(state, 'fieldName');
4354

4455
/**
4556
* ----------------------------------------------------------------
@@ -92,7 +103,7 @@ export type OptionsListRequest = Omit<
92103
*/
93104
export interface OptionsListRequestBody
94105
extends Pick<
95-
OptionsListControlState,
106+
OptionsListDSLControlState,
96107
'fieldName' | 'searchTechnique' | 'sort' | 'selectedOptions'
97108
> {
98109
runtimeFieldMap?: Record<string, RuntimeFieldSpec>;

src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/components/options_list_editor_options.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ export const OptionsListEditorOptions = ({
8787
);
8888

8989
const compatibleSearchTechniques = useMemo(
90-
() => getCompatibleSearchTechniques(field.type),
91-
[field.type]
90+
() => getCompatibleSearchTechniques(field?.type),
91+
[field?.type]
9292
);
9393

9494
const searchOptions = useMemo(() => {

src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/get_options_list_control_factory.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { PublishingSubject } from '@kbn/presentation-publishing';
2525

2626
import { initializeUnsavedChanges } from '@kbn/presentation-containers';
2727
import { OPTIONS_LIST_CONTROL } from '../../../../common';
28+
import { isOptionsListESQLControlState } from '../../../../common/options_list/types';
2829
import type {
2930
OptionsListControlState,
3031
OptionsListSortingType,
@@ -73,6 +74,10 @@ export const getOptionsListControlFactory = (): DataControlFactory<
7374
},
7475
CustomOptionsComponent: OptionsListEditorOptions,
7576
buildControl: async ({ initialState, finalizeApi, uuid, controlGroupApi }) => {
77+
if (isOptionsListESQLControlState(initialState)) {
78+
throw new Error('ES|QL control state handling not yet implemented');
79+
}
80+
7681
/** Serializable state - i.e. the state that is saved with the control */
7782
const editorStateManager = initializeEditorStateManager(initialState);
7883

@@ -299,6 +304,9 @@ export const getOptionsListControlFactory = (): DataControlFactory<
299304
existsSelected: false,
300305
},
301306
onReset: (lastSaved) => {
307+
if (isOptionsListESQLControlState(lastSaved?.rawState)) {
308+
throw new Error('ES|QL control state handling not yet implemented');
309+
}
302310
dataControlManager.reinitializeState(lastSaved?.rawState);
303311
selectionsManager.reinitializeState(lastSaved?.rawState);
304312
editorStateManager.reinitializeState(lastSaved?.rawState);

src/platform/plugins/shared/controls/public/controls/data_controls/options_list_control/types.ts

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import { Subject } from 'rxjs';
1212
import type { PublishesTitle, PublishingSubject } from '@kbn/presentation-publishing';
1313
import { SubjectsOf, SettersOf } from '@kbn/presentation-publishing/state_manager/types';
1414
import type {
15-
OptionsListControlState,
16-
OptionsListDisplaySettings,
1715
OptionsListSelection,
1816
OptionsListSortingType,
1917
OptionsListSuggestions,
@@ -28,32 +26,33 @@ export type OptionsListControlApi = DataControlApi & {
2826
setSelectedOptions: (options: OptionsListSelection[] | undefined) => void;
2927
};
3028

31-
export interface OptionsListComponentState
32-
extends Omit<OptionsListControlState, keyof OptionsListDisplaySettings> {
33-
searchString: string;
34-
searchStringValid: boolean;
35-
requestSize: number;
36-
}
37-
3829
interface PublishesOptions {
3930
availableOptions$: PublishingSubject<OptionsListSuggestions | undefined>;
4031
invalidSelections$: PublishingSubject<Set<OptionsListSelection>>;
4132
totalCardinality$: PublishingSubject<number>;
4233
}
43-
export type OptionsListState = Pick<DefaultDataControlState, 'fieldName'> &
34+
35+
/**
36+
* A type consisting of only the properties that the options list control puts into state managers
37+
* and then passes to the UI component. Excludes any managed state properties that don't end up being used
38+
* by the component
39+
*/
40+
export type OptionsListComponentState = Pick<DefaultDataControlState, 'fieldName'> &
4441
SelectionsState &
4542
EditorState &
46-
TemporaryState & { sort: OptionsListSortingType | undefined };
43+
TemporaryState & {
44+
sort: OptionsListSortingType | undefined;
45+
};
4746

48-
type PublishesOptionsListState = SubjectsOf<OptionsListState>;
49-
type OptionsListStateSetters = Partial<SettersOf<OptionsListState>> &
50-
SettersOf<Pick<OptionsListState, 'sort' | 'searchString' | 'requestSize' | 'exclude'>>;
47+
type PublishesOptionsListComponentState = SubjectsOf<OptionsListComponentState>;
48+
type OptionsListComponentStateSetters = Partial<SettersOf<OptionsListComponentState>> &
49+
SettersOf<Pick<OptionsListComponentState, 'sort' | 'searchString' | 'requestSize' | 'exclude'>>;
5150

5251
export type OptionsListComponentApi = PublishesField &
5352
PublishesOptions &
54-
PublishesOptionsListState &
53+
PublishesOptionsListComponentState &
5554
Pick<PublishesTitle, 'title$'> &
56-
OptionsListStateSetters & {
55+
OptionsListComponentStateSetters & {
5756
deselectOption: (key: string | undefined) => void;
5857
makeSelection: (key: string | undefined, showOnlySelected: boolean) => void;
5958
loadMoreSubject: Subject<void>;

src/platform/plugins/shared/controls/public/controls/data_controls/types.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ import {
1616
PublishingSubject,
1717
} from '@kbn/presentation-publishing';
1818

19-
import { DefaultDataControlState } from '../../../common';
20-
import { ControlGroupApi } from '../../control_group/types';
21-
import { ControlFactory, DefaultControlApi } from '../types';
22-
import { PublishesAsyncFilters } from './publishes_async_filters';
19+
import type { DefaultControlState } from '../../../common';
20+
import type { ControlGroupApi } from '../../control_group/types';
21+
import type { ControlFactory, DefaultControlApi } from '../types';
22+
import type { PublishesAsyncFilters } from './publishes_async_filters';
2323

2424
export type DataControlFieldFormatter = FieldFormatConvertFunction | ((toFormat: any) => string);
2525

@@ -36,17 +36,17 @@ export type DataControlApi = DefaultControlApi &
3636
PublishesAsyncFilters;
3737

3838
export interface CustomOptionsComponentProps<
39-
State extends DefaultDataControlState = DefaultDataControlState
39+
State extends DefaultControlState = DefaultControlState
4040
> {
4141
initialState: Partial<State>;
42-
field: DataViewField;
42+
field?: DataViewField;
4343
updateState: (newState: Partial<State>) => void;
4444
setControlEditorValid: (valid: boolean) => void;
4545
controlGroupApi: ControlGroupApi;
4646
}
4747

4848
export interface DataControlFactory<
49-
State extends DefaultDataControlState = DefaultDataControlState,
49+
State extends DefaultControlState = DefaultControlState,
5050
Api extends DataControlApi = DataControlApi
5151
> extends ControlFactory<State, Api> {
5252
isFieldCompatible: (field: DataViewField) => boolean;

0 commit comments

Comments
 (0)