control group state builder (#190575)

legacy control group embeddable exposes `controlGroupInputBuilder` to
provide utility methods for building controlGroupInput. This PR adds
`controlGroupStateBuilder` that provides similar functionality, to allow
users to build react control group embeddable state. The API is not the
same and this is on purpose. Now that control state no longer has
`explicitInput` and splitting of state between multiple levels, the API
can just take `ControlState` shape directly.
This commit is contained in:
Nathan Reese 2024-08-15 15:23:08 -06:00 committed by GitHub
parent 16bded2f27
commit 14200cb42e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 108 additions and 0 deletions

View file

@ -19,6 +19,7 @@ export type {
DataControlFactory,
DataControlServices,
} from './react_controls/controls/data_controls/types';
export { controlGroupStateBuilder } from './react_controls/control_group/control_group_state_builder';
/**
* TODO: remove all exports below this when control group embeddable is removed

View file

@ -0,0 +1,107 @@
/*
* 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 { v4 as uuidv4 } from 'uuid';
import { OPTIONS_LIST_CONTROL, RANGE_SLIDER_CONTROL, TIME_SLIDER_CONTROL } from '../../../common';
import { ControlGroupRuntimeState, ControlPanelsState } from './types';
import { pluginServices } from '../../services';
import { OptionsListControlState } from '../controls/data_controls/options_list_control/types';
import { RangesliderControlState } from '../controls/data_controls/range_slider/types';
import { DefaultDataControlState } from '../controls/data_controls/types';
import { getDataControlFieldRegistry } from '../controls/data_controls/data_control_editor_utils';
export type ControlGroupStateBuilder = typeof controlGroupStateBuilder;
export const controlGroupStateBuilder = {
addDataControlFromField: async (
controlGroupState: Partial<ControlGroupRuntimeState>,
controlState: DefaultDataControlState,
controlId?: string
) => {
controlGroupState.initialChildControlState = {
...(controlGroupState.initialChildControlState ?? {}),
[controlId ?? uuidv4()]: {
type: await getCompatibleControlType(controlState.dataViewId, controlState.fieldName),
order: getNextControlOrder(controlGroupState.initialChildControlState),
...controlState,
},
};
},
addOptionsListControl: (
controlGroupState: Partial<ControlGroupRuntimeState>,
controlState: OptionsListControlState,
controlId?: string
) => {
controlGroupState.initialChildControlState = {
...(controlGroupState.initialChildControlState ?? {}),
[controlId ?? uuidv4()]: {
type: OPTIONS_LIST_CONTROL,
order: getNextControlOrder(controlGroupState.initialChildControlState),
...controlState,
},
};
},
addRangeSliderControl: (
controlGroupState: Partial<ControlGroupRuntimeState>,
controlState: RangesliderControlState,
controlId?: string
) => {
controlGroupState.initialChildControlState = {
...(controlGroupState.initialChildControlState ?? {}),
[controlId ?? uuidv4()]: {
type: RANGE_SLIDER_CONTROL,
order: getNextControlOrder(controlGroupState.initialChildControlState),
...controlState,
},
};
},
addTimeSliderControl: (
controlGroupState: Partial<ControlGroupRuntimeState>,
controlId?: string
) => {
controlGroupState.initialChildControlState = {
...(controlGroupState.initialChildControlState ?? {}),
[controlId ?? uuidv4()]: {
type: TIME_SLIDER_CONTROL,
order: getNextControlOrder(controlGroupState.initialChildControlState),
width: 'large',
},
};
},
};
async function getCompatibleControlType(dataViewId: string, fieldName: string) {
const dataView = await pluginServices.getServices().dataViews.get(dataViewId);
const fieldRegistry = await getDataControlFieldRegistry(dataView);
const field = fieldRegistry[fieldName];
if (field.compatibleControlTypes.length === 0) {
throw new Error(`No compatible control type found for field: ${fieldName}`);
}
return field.compatibleControlTypes[0];
}
function getNextControlOrder(controlPanelsState?: ControlPanelsState) {
if (!controlPanelsState) {
return 0;
}
const values = Object.values(controlPanelsState);
if (values.length === 0) {
return 0;
}
let highestOrder = 0;
values.forEach((controlPanelState) => {
if (controlPanelState.order > highestOrder) {
highestOrder = controlPanelState.order;
}
});
return highestOrder + 1;
}