Skip to content

Commit

Permalink
[controls] align controlGroupInputBuilder API in ControlGroupContaine…
Browse files Browse the repository at this point in the history
…r API (#146928)

PR does the following
* Mirror controlGroupInputBuilder methods in ControlGroupContainer API:
    * addOptionsListControl
    * addRangeSliderControl
    * addTimeSliderControl 
* Update existing ControlGroupContainer.addDataControlFromField method
have same signature as controlGroupInputBuilder.addDataControlFromField
* Use new ControlGroupContainer APIs when adding controls view React
components

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
nreese and kibanamachine authored Dec 6, 2022
1 parent 0bf250a commit 92ae81d
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 114 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
* Side Public License, v 1.
*/

import { i18n } from '@kbn/i18n';
import uuid from 'uuid';
import { ControlPanelState } from '../../common';
import { ControlPanelState, OptionsListEmbeddableInput } from '../../common';
import {
DEFAULT_CONTROL_GROW,
DEFAULT_CONTROL_WIDTH,
Expand All @@ -33,9 +34,7 @@ export interface AddDataControlProps {
width?: ControlWidth;
}

export type AddOptionsListControlProps = AddDataControlProps & {
selectedOptions?: string[];
};
export type AddOptionsListControlProps = AddDataControlProps & Partial<OptionsListEmbeddableInput>;

export type AddRangeSliderControlProps = AddDataControlProps & {
value?: RangeValue;
Expand All @@ -46,104 +45,113 @@ export const controlGroupInputBuilder = {
initialInput: Partial<ControlGroupInput>,
controlProps: AddDataControlProps
) => {
const { controlId, dataViewId, fieldName, title } = controlProps;
const panelId = controlId ? controlId : uuid.v4();
const panelState = await getDataControlPanelState(initialInput, controlProps);
initialInput.panels = {
...initialInput.panels,
[panelId]: {
order: getNextPanelOrder(initialInput),
type: await getCompatibleControlType({ dataViewId, fieldName }),
grow: getGrow(initialInput, controlProps),
width: getWidth(initialInput, controlProps),
explicitInput: {
id: panelId,
dataViewId,
fieldName,
title: title ?? fieldName,
},
} as ControlPanelState<DataControlInput>,
[panelState.explicitInput.id]: panelState,
};
},
addOptionsListControl: (
initialInput: Partial<ControlGroupInput>,
controlProps: AddOptionsListControlProps
) => {
const { controlId, dataViewId, fieldName, selectedOptions, title } = controlProps;
const panelId = controlId ? controlId : uuid.v4();
const panelState = getOptionsListPanelState(initialInput, controlProps);
initialInput.panels = {
...initialInput.panels,
[panelId]: {
order: getNextPanelOrder(initialInput),
type: OPTIONS_LIST_CONTROL,
grow: getGrow(initialInput, controlProps),
width: getWidth(initialInput, controlProps),
explicitInput: {
id: panelId,
dataViewId,
fieldName,
selectedOptions,
title: title ?? fieldName,
},
} as ControlPanelState<DataControlInput>,
[panelState.explicitInput.id]: panelState,
};
},
addRangeSliderControl: (
initialInput: Partial<ControlGroupInput>,
controlProps: AddRangeSliderControlProps
) => {
const { controlId, dataViewId, fieldName, title, value } = controlProps;
const panelId = controlId ? controlId : uuid.v4();
const panelState = getRangeSliderPanelState(initialInput, controlProps);
initialInput.panels = {
...initialInput.panels,
[panelId]: {
order: getNextPanelOrder(initialInput),
type: RANGE_SLIDER_CONTROL,
grow: getGrow(initialInput, controlProps),
width: getWidth(initialInput, controlProps),
explicitInput: {
id: panelId,
dataViewId,
fieldName,
title: title ?? fieldName,
value: value ? value : ['', ''],
},
} as ControlPanelState<DataControlInput>,
[panelState.explicitInput.id]: panelState,
};
},
addTimeSliderControl: (initialInput: Partial<ControlGroupInput>) => {
const panelId = uuid.v4();
const panelState = getTimeSliderPanelState(initialInput);
initialInput.panels = {
...initialInput.panels,
[panelId]: {
order: getNextPanelOrder(initialInput),
type: TIME_SLIDER_CONTROL,
grow: true,
width: 'large',
explicitInput: {
id: panelId,
title: 'timeslider',
},
} as ControlPanelState<ControlInput>,
[panelState.explicitInput.id]: panelState,
};
},
};

function getGrow(initialInput: Partial<ControlGroupInput>, controlProps: AddDataControlProps) {
if (typeof controlProps.grow === 'boolean') {
return controlProps.grow;
}
export async function getDataControlPanelState(
input: Partial<ControlGroupInput>,
controlProps: AddDataControlProps
) {
const { controlId, dataViewId, fieldName, title } = controlProps;
return {
type: await getCompatibleControlType({ dataViewId, fieldName }),
...getPanelState(input, controlProps),
explicitInput: {
id: controlId ? controlId : uuid.v4(),
dataViewId,
fieldName,
title: title ?? fieldName,
},
} as ControlPanelState<DataControlInput>;
}

return typeof initialInput.defaultControlGrow === 'boolean'
? initialInput.defaultControlGrow
: DEFAULT_CONTROL_GROW;
export function getOptionsListPanelState(
input: Partial<ControlGroupInput>,
controlProps: AddOptionsListControlProps
) {
const { controlId, dataViewId, fieldName, title, ...rest } = controlProps;
return {
type: OPTIONS_LIST_CONTROL,
...getPanelState(input, controlProps),
explicitInput: {
id: controlId ? controlId : uuid.v4(),
dataViewId,
fieldName,
title: title ?? fieldName,
...rest,
},
} as ControlPanelState<DataControlInput>;
}

function getWidth(initialInput: Partial<ControlGroupInput>, controlProps: AddDataControlProps) {
if (controlProps.width) {
return controlProps.width;
}
export function getRangeSliderPanelState(
input: Partial<ControlGroupInput>,
controlProps: AddRangeSliderControlProps
) {
const { controlId, dataViewId, fieldName, title, ...rest } = controlProps;
return {
type: RANGE_SLIDER_CONTROL,
...getPanelState(input, controlProps),
explicitInput: {
id: controlId ? controlId : uuid.v4(),
dataViewId,
fieldName,
title: title ?? fieldName,
...rest,
},
} as ControlPanelState<DataControlInput>;
}

export function getTimeSliderPanelState(input: Partial<ControlGroupInput>) {
return {
type: TIME_SLIDER_CONTROL,
order: getNextPanelOrder(input.panels),
grow: true,
width: 'large',
explicitInput: {
id: uuid.v4(),
title: i18n.translate('controls.controlGroup.timeSlider.title', {
defaultMessage: 'Time slider',
}),
},
} as ControlPanelState<ControlInput>;
}

return initialInput.defaultControlWidth
? initialInput.defaultControlWidth
: DEFAULT_CONTROL_WIDTH;
function getPanelState(input: Partial<ControlGroupInput>, controlProps: AddDataControlProps) {
return {
order: getNextPanelOrder(input.panels),
grow: controlProps.grow ?? input.defaultControlGrow ?? DEFAULT_CONTROL_GROW,
width: controlProps.width ?? input.defaultControlWidth ?? DEFAULT_CONTROL_WIDTH,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,23 @@
import { i18n } from '@kbn/i18n';
import React from 'react';
import { EuiContextMenuItem } from '@elastic/eui';
import type { ControlInput } from '../../types';
import { TIME_SLIDER_CONTROL } from '../../time_slider/types';

interface Props {
addNewEmbeddable: (type: string, input: Omit<ControlInput, 'id'>) => void;
onCreate: () => void;
closePopover?: () => void;
hasTimeSliderControl: boolean;
}

export const CreateTimeSliderControlButton = ({
addNewEmbeddable,
onCreate,
closePopover,
hasTimeSliderControl,
}: Props) => {
return (
<EuiContextMenuItem
icon="plusInCircle"
onClick={() => {
addNewEmbeddable(TIME_SLIDER_CONTROL, {
title: i18n.translate('controls.controlGroup.timeSlider.title', {
defaultMessage: 'Time slider',
}),
});
onCreate();
if (closePopover) {
closePopover();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,22 @@ import { ControlGroupStrings } from '../control_group_strings';
import { EditControlGroup } from '../editor/edit_control_group';
import { ControlGroup } from '../component/control_group_component';
import { controlGroupReducers } from '../state/control_group_reducers';
import { ControlEmbeddable, ControlInput, ControlOutput, DataControlInput } from '../../types';
import { OPTIONS_LIST_CONTROL, RANGE_SLIDER_CONTROL, TIME_SLIDER_CONTROL } from '../..';
import { ControlEmbeddable, ControlInput, ControlOutput } from '../../types';
import { CreateControlButton, CreateControlButtonTypes } from '../editor/create_control';
import { CreateTimeSliderControlButton } from '../editor/create_time_slider_control';
import { TIME_SLIDER_CONTROL } from '../../time_slider';
import { getCompatibleControlType, getNextPanelOrder } from './control_group_helpers';
import { getNextPanelOrder } from './control_group_helpers';
import type {
AddDataControlProps,
AddOptionsListControlProps,
AddRangeSliderControlProps,
} from '../control_group_input_builder';
import {
getDataControlPanelState,
getOptionsListPanelState,
getRangeSliderPanelState,
getTimeSliderPanelState,
} from '../control_group_input_builder';

let flyoutRef: OverlayRef | undefined;
export const setFlyoutRef = (newRef: OverlayRef | undefined) => {
Expand Down Expand Up @@ -96,23 +107,24 @@ export class ControlGroupContainer extends Container<
flyoutRef = undefined;
}

public async addDataControlFromField({
uuid,
dataViewId,
fieldName,
title,
}: {
uuid?: string;
dataViewId: string;
fieldName: string;
title?: string;
}) {
return this.addNewEmbeddable(await getCompatibleControlType({ dataViewId, fieldName }), {
id: uuid,
dataViewId,
fieldName,
title: title ?? fieldName,
} as DataControlInput);
public async addDataControlFromField(controlProps: AddDataControlProps) {
const panelState = await getDataControlPanelState(this.getInput(), controlProps);
return this.createAndSaveEmbeddable(panelState.type, panelState);
}

public addOptionsListControl(controlProps: AddOptionsListControlProps) {
const panelState = getOptionsListPanelState(this.getInput(), controlProps);
return this.createAndSaveEmbeddable(panelState.type, panelState);
}

public addRangeSliderControl(controlProps: AddRangeSliderControlProps) {
const panelState = getRangeSliderPanelState(this.getInput(), controlProps);
return this.createAndSaveEmbeddable(panelState.type, panelState);
}

public addTimeSliderControl() {
const panelState = getTimeSliderPanelState(this.getInput());
return this.createAndSaveEmbeddable(panelState.type, panelState);
}

/**
Expand All @@ -138,7 +150,19 @@ export class ControlGroupContainer extends Container<
updateDefaultGrow={(defaultControlGrow: boolean) =>
this.updateInput({ defaultControlGrow })
}
addNewEmbeddable={(type, input) => this.addNewEmbeddable(type, input)}
addNewEmbeddable={(type, input) => {
if (type === OPTIONS_LIST_CONTROL) {
this.addOptionsListControl(input as AddOptionsListControlProps);
return;
}

if (type === RANGE_SLIDER_CONTROL) {
this.addRangeSliderControl(input as AddRangeSliderControlProps);
return;
}

this.addDataControlFromField(input as AddDataControlProps);
}}
closePopover={closePopover}
getRelevantDataViewId={() => this.getMostRelevantDataViewId()}
setLastUsedDataViewId={(newId) => this.setLastUsedDataViewId(newId)}
Expand All @@ -155,7 +179,9 @@ export class ControlGroupContainer extends Container<
});
return (
<CreateTimeSliderControlButton
addNewEmbeddable={(type, input) => this.addNewEmbeddable(type, input)}
onCreate={() => {
this.addTimeSliderControl();
}}
closePopover={closePopover}
hasTimeSliderControl={hasTimeSliderControl}
/>
Expand Down Expand Up @@ -317,12 +343,10 @@ export class ControlGroupContainer extends Container<
partial: Partial<TEmbeddableInput> = {}
): ControlPanelState<TEmbeddableInput> {
const panelState = super.createNewPanelState(factory, partial);
const nextOrder = getNextPanelOrder(this.getInput());
return {
order: nextOrder,
width:
panelState.type === TIME_SLIDER_CONTROL ? 'large' : this.getInput().defaultControlWidth,
grow: panelState.type === TIME_SLIDER_CONTROL ? true : this.getInput().defaultControlGrow,
order: getNextPanelOrder(this.getInput().panels),
width: this.getInput().defaultControlWidth,
grow: this.getInput().defaultControlGrow,
...panelState,
} as ControlPanelState<TEmbeddableInput>;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
* Side Public License, v 1.
*/

import { ControlGroupInput } from '../types';
import { ControlsPanels } from '../types';
import { pluginServices } from '../../services';
import { getDataControlFieldRegistry } from '../editor/data_control_editor_tools';

export const getNextPanelOrder = (initialInput: Partial<ControlGroupInput>) => {
export const getNextPanelOrder = (panels?: ControlsPanels) => {
let nextOrder = 0;
if (Object.keys(initialInput.panels ?? {}).length > 0) {
if (Object.keys(panels ?? {}).length > 0) {
nextOrder =
Object.values(initialInput.panels ?? {}).reduce((highestSoFar, panel) => {
Object.values(panels ?? {}).reduce((highestSoFar, panel) => {
if (panel.order > highestSoFar) highestSoFar = panel.order;
return highestSoFar;
}, 0) + 1;
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/embeddable/public/lib/containers/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ export abstract class Container<
}
}

private async createAndSaveEmbeddable<
protected async createAndSaveEmbeddable<
TEmbeddableInput extends EmbeddableInput = EmbeddableInput,
TEmbeddable extends IEmbeddable<TEmbeddableInput> = IEmbeddable<TEmbeddableInput>
>(type: string, panelState: PanelState) {
Expand Down

0 comments on commit 92ae81d

Please sign in to comment.