mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Control group] Open "add control editor" with last used width and grow settings (#190749)
### test instructions 1. run kibana with `yarn start --run-examples` 2. navigate to the "Controls" developer example 3. Click "Add new data-control" button. Notice how the menu sets "width" to medium and selects "grow". 4. Add new control, setting "width" to small and unselected "grow". Click "Save and close". 5. Click "Add new data-control" button. Notice how the menu sets "width" and "grow" to last used values. --------- Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: Hannah Mudge <Heenawter@users.noreply.github.com>
This commit is contained in:
parent
f512acf9c3
commit
01aae2331d
7 changed files with 78 additions and 51 deletions
|
@ -27,11 +27,8 @@ import { apiPublishesReload } from '@kbn/presentation-publishing/interfaces/fetc
|
|||
import { ControlStyle, ParentIgnoreSettings } from '../..';
|
||||
import {
|
||||
ControlGroupChainingSystem,
|
||||
ControlWidth,
|
||||
CONTROL_GROUP_TYPE,
|
||||
DEFAULT_CONTROL_GROW,
|
||||
DEFAULT_CONTROL_STYLE,
|
||||
DEFAULT_CONTROL_WIDTH,
|
||||
} from '../../../common';
|
||||
import { chaining$, controlFetch$, controlGroupFetch$ } from './control_fetch';
|
||||
import { initControlsManager } from './init_controls_manager';
|
||||
|
@ -64,8 +61,6 @@ export const getControlGroupEmbeddableFactory = (services: {
|
|||
) => {
|
||||
const {
|
||||
initialChildControlState,
|
||||
defaultControlGrow,
|
||||
defaultControlWidth,
|
||||
labelPosition: initialLabelPosition,
|
||||
chainingSystem,
|
||||
autoApplySelections,
|
||||
|
@ -89,12 +84,6 @@ export const getControlGroupEmbeddableFactory = (services: {
|
|||
const ignoreParentSettings$ = new BehaviorSubject<ParentIgnoreSettings | undefined>(
|
||||
ignoreParentSettings
|
||||
);
|
||||
const grow = new BehaviorSubject<boolean | undefined>(
|
||||
defaultControlGrow === undefined ? DEFAULT_CONTROL_GROW : defaultControlGrow
|
||||
);
|
||||
const width = new BehaviorSubject<ControlWidth | undefined>(
|
||||
defaultControlWidth ?? DEFAULT_CONTROL_WIDTH
|
||||
);
|
||||
const labelPosition$ = new BehaviorSubject<ControlStyle>( // TODO: Rename `ControlStyle`
|
||||
initialLabelPosition ?? DEFAULT_CONTROL_STYLE // TODO: Rename `DEFAULT_CONTROL_STYLE`
|
||||
);
|
||||
|
@ -175,13 +164,9 @@ export const getControlGroupEmbeddableFactory = (services: {
|
|||
controlInputTransform: (state) => state,
|
||||
};
|
||||
openDataControlEditor({
|
||||
initialState: {
|
||||
grow: api.grow.getValue(),
|
||||
width: api.width.getValue(),
|
||||
dataViewId: controlsManager.api.lastUsedDataViewId$.value,
|
||||
},
|
||||
initialState: controlsManager.getNewControlState(),
|
||||
onSave: ({ type: controlType, state: initialState }) => {
|
||||
api.addNewPanel({
|
||||
controlsManager.api.addNewPanel({
|
||||
panelType: controlType,
|
||||
initialState: controlInputTransform!(
|
||||
initialState as Partial<ControlGroupSerializedState>,
|
||||
|
@ -206,8 +191,6 @@ export const getControlGroupEmbeddableFactory = (services: {
|
|||
references,
|
||||
};
|
||||
},
|
||||
grow,
|
||||
width,
|
||||
dataViews,
|
||||
labelPosition: labelPosition$,
|
||||
saveNotification$: apiHasSaveNotification(parentApi)
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { DefaultDataControlState } from '../controls/data_controls/types';
|
||||
import { DefaultControlApi } from '../controls/types';
|
||||
import { initControlsManager, getLastUsedDataViewId } from './init_controls_manager';
|
||||
import { ControlPanelState } from './types';
|
||||
|
||||
jest.mock('uuid', () => ({
|
||||
v4: jest.fn().mockReturnValue('delta'),
|
||||
|
@ -187,3 +189,51 @@ describe('getLastUsedDataViewId', () => {
|
|||
expect(dataViewId).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getNewControlState', () => {
|
||||
test('should contain defaults when there are no existing controls', () => {
|
||||
const controlsManager = initControlsManager({}, DEFAULT_DATA_VIEW_ID);
|
||||
expect(controlsManager.getNewControlState()).toEqual({
|
||||
grow: true,
|
||||
width: 'medium',
|
||||
dataViewId: DEFAULT_DATA_VIEW_ID,
|
||||
});
|
||||
});
|
||||
|
||||
test('should start with defaults if there are existing controls', () => {
|
||||
const controlsManager = initControlsManager(
|
||||
{
|
||||
alpha: {
|
||||
type: 'testControl',
|
||||
order: 1,
|
||||
dataViewId: 'myOtherDataViewId',
|
||||
width: 'small',
|
||||
grow: false,
|
||||
} as ControlPanelState & Pick<DefaultDataControlState, 'dataViewId'>,
|
||||
},
|
||||
DEFAULT_DATA_VIEW_ID
|
||||
);
|
||||
expect(controlsManager.getNewControlState()).toEqual({
|
||||
grow: true,
|
||||
width: 'medium',
|
||||
dataViewId: 'myOtherDataViewId',
|
||||
});
|
||||
});
|
||||
|
||||
test('should contain values of last added control', () => {
|
||||
const controlsManager = initControlsManager({}, DEFAULT_DATA_VIEW_ID);
|
||||
controlsManager.api.addNewPanel({
|
||||
panelType: 'testControl',
|
||||
initialState: {
|
||||
grow: false,
|
||||
width: 'small',
|
||||
dataViewId: 'myOtherDataViewId',
|
||||
},
|
||||
});
|
||||
expect(controlsManager.getNewControlState()).toEqual({
|
||||
grow: false,
|
||||
width: 'small',
|
||||
dataViewId: 'myOtherDataViewId',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -22,6 +22,7 @@ import { ControlGroupApi, ControlPanelsState, ControlPanelState } from './types'
|
|||
import { DefaultControlApi, DefaultControlState } from '../controls/types';
|
||||
import { ControlGroupComparatorState } from './control_group_unsaved_changes_api';
|
||||
import { DefaultDataControlState } from '../controls/data_controls/types';
|
||||
import { ControlWidth, DEFAULT_CONTROL_GROW, DEFAULT_CONTROL_WIDTH } from '../../../common';
|
||||
|
||||
export type ControlsInOrder = Array<{ id: string; type: string }>;
|
||||
|
||||
|
@ -54,6 +55,8 @@ export function initControlsManager(
|
|||
defaultDataViewId ??
|
||||
undefined
|
||||
);
|
||||
const lastUsedWidth$ = new BehaviorSubject<ControlWidth>(DEFAULT_CONTROL_WIDTH);
|
||||
const lastUsedGrow$ = new BehaviorSubject<boolean>(DEFAULT_CONTROL_GROW);
|
||||
|
||||
function untilControlLoaded(
|
||||
id: string
|
||||
|
@ -91,6 +94,13 @@ export function initControlsManager(
|
|||
if ((initialState as DefaultDataControlState)?.dataViewId) {
|
||||
lastUsedDataViewId$.next((initialState as DefaultDataControlState).dataViewId);
|
||||
}
|
||||
if (initialState?.width) {
|
||||
lastUsedWidth$.next(initialState.width);
|
||||
}
|
||||
if (typeof initialState?.grow === 'boolean') {
|
||||
lastUsedGrow$.next(initialState.grow);
|
||||
}
|
||||
|
||||
const id = generateId();
|
||||
const nextControlsInOrder = [...controlsInOrder$.value];
|
||||
nextControlsInOrder.splice(index, 0, {
|
||||
|
@ -110,6 +120,13 @@ export function initControlsManager(
|
|||
|
||||
return {
|
||||
controlsInOrder$,
|
||||
getNewControlState: () => {
|
||||
return {
|
||||
grow: lastUsedGrow$.value,
|
||||
width: lastUsedWidth$.value,
|
||||
dataViewId: lastUsedDataViewId$.value,
|
||||
};
|
||||
},
|
||||
getControlApi,
|
||||
setControlApi: (uuid: string, controlApi: DefaultControlApi) => {
|
||||
children$.next({
|
||||
|
@ -168,7 +185,6 @@ export function initControlsManager(
|
|||
return controlsRuntimeState;
|
||||
},
|
||||
api: {
|
||||
lastUsedDataViewId$: lastUsedDataViewId$ as PublishingSubject<string | undefined>,
|
||||
getSerializedStateForChild: (childId: string) => {
|
||||
const controlPanelState = controlsPanelState[childId];
|
||||
return controlPanelState ? { rawState: controlPanelState } : undefined;
|
||||
|
@ -210,7 +226,7 @@ export function initControlsManager(
|
|||
},
|
||||
} as PresentationContainer &
|
||||
HasSerializedChildState<ControlPanelState> &
|
||||
Pick<ControlGroupApi, 'untilInitialized' | 'lastUsedDataViewId$'>,
|
||||
Pick<ControlGroupApi, 'untilInitialized'>,
|
||||
comparators: {
|
||||
controlsInOrder: [
|
||||
controlsInOrder$,
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
import { SerializedPanelState } from '@kbn/presentation-containers';
|
||||
import { omit } from 'lodash';
|
||||
import { DEFAULT_CONTROL_GROW, DEFAULT_CONTROL_WIDTH } from '../../../common';
|
||||
import { ControlGroupRuntimeState, ControlGroupSerializedState } from './types';
|
||||
|
||||
export const deserializeControlGroup = (
|
||||
|
@ -46,7 +45,5 @@ export const deserializeControlGroup = (
|
|||
? !state.rawState.showApplySelections
|
||||
: false, // Rename "showApplySelections" to "autoApplySelections"
|
||||
labelPosition: state.rawState.controlStyle, // Rename "controlStyle" to "labelPosition"
|
||||
defaultControlGrow: DEFAULT_CONTROL_GROW,
|
||||
defaultControlWidth: DEFAULT_CONTROL_WIDTH,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -31,21 +31,17 @@ import { PublishesReload } from '@kbn/presentation-publishing/interfaces/fetch/p
|
|||
import { ParentIgnoreSettings } from '../..';
|
||||
import { ControlInputTransform } from '../../../common';
|
||||
import { ControlGroupChainingSystem } from '../../../common/control_group/types';
|
||||
import { ControlStyle, ControlWidth } from '../../types';
|
||||
import { DefaultControlState, PublishesControlDisplaySettings } from '../controls/types';
|
||||
import { ControlStyle } from '../../types';
|
||||
import { DefaultControlState } from '../controls/types';
|
||||
import { ControlFetchContext } from './control_fetch/control_fetch';
|
||||
|
||||
/** The control display settings published by the control group are the "default" */
|
||||
type PublishesControlGroupDisplaySettings = PublishesControlDisplaySettings & {
|
||||
labelPosition: PublishingSubject<ControlStyle>;
|
||||
};
|
||||
export interface ControlPanelsState<ControlState extends ControlPanelState = ControlPanelState> {
|
||||
[panelId: string]: ControlState;
|
||||
}
|
||||
|
||||
export type ControlGroupUnsavedChanges = Omit<
|
||||
ControlGroupRuntimeState,
|
||||
'initialChildControlState' | 'defaultControlGrow' | 'defaultControlWidth'
|
||||
'initialChildControlState'
|
||||
> & {
|
||||
filters: Filter[] | undefined;
|
||||
};
|
||||
|
@ -60,7 +56,6 @@ export type ControlGroupApi = PresentationContainer &
|
|||
HasEditCapabilities &
|
||||
PublishesDataLoading &
|
||||
Pick<PublishesUnsavedChanges, 'unsavedChanges'> &
|
||||
PublishesControlGroupDisplaySettings &
|
||||
PublishesTimeslice &
|
||||
Partial<HasParentApi<PublishesUnifiedSearch> & HasSaveNotification & PublishesReload> & {
|
||||
asyncResetUnsavedChanges: () => Promise<void>;
|
||||
|
@ -73,13 +68,11 @@ export type ControlGroupApi = PresentationContainer &
|
|||
openAddDataControlFlyout: (settings?: {
|
||||
controlInputTransform?: ControlInputTransform;
|
||||
}) => void;
|
||||
lastUsedDataViewId$: PublishingSubject<string | undefined>;
|
||||
labelPosition: PublishingSubject<ControlStyle>;
|
||||
};
|
||||
|
||||
export interface ControlGroupRuntimeState {
|
||||
chainingSystem: ControlGroupChainingSystem;
|
||||
defaultControlGrow?: boolean;
|
||||
defaultControlWidth?: ControlWidth;
|
||||
labelPosition: ControlStyle; // TODO: Rename this type to ControlLabelPosition
|
||||
autoApplySelections: boolean;
|
||||
ignoreParentSettings?: ParentIgnoreSettings;
|
||||
|
|
|
@ -32,7 +32,6 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { DataViewField } from '@kbn/data-views-plugin/common';
|
||||
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
|
||||
import {
|
||||
LazyDataViewPicker,
|
||||
LazyFieldPicker,
|
||||
|
@ -145,10 +144,6 @@ export const DataControlEditor = <State extends DefaultDataControlState = Defaul
|
|||
/** TODO: These should not be props */
|
||||
services: { dataViews: dataViewService },
|
||||
}: ControlEditorProps<State>) => {
|
||||
const [defaultGrow, defaultWidth] = useBatchedPublishingSubjects(
|
||||
controlGroupApi.grow,
|
||||
controlGroupApi.width
|
||||
);
|
||||
const [editorState, setEditorState] = useState<Partial<State>>(initialState);
|
||||
const [defaultPanelTitle, setDefaultPanelTitle] = useState<string>(
|
||||
initialDefaultPanelTitle ?? initialState.fieldName ?? ''
|
||||
|
@ -368,7 +363,7 @@ export const DataControlEditor = <State extends DefaultDataControlState = Defaul
|
|||
color="primary"
|
||||
legend={DataControlEditorStrings.management.controlWidth.getWidthSwitchLegend()}
|
||||
options={CONTROL_WIDTH_OPTIONS}
|
||||
idSelected={editorState.width ?? defaultWidth ?? DEFAULT_CONTROL_WIDTH}
|
||||
idSelected={editorState.width ?? DEFAULT_CONTROL_WIDTH}
|
||||
onChange={(newWidth: string) =>
|
||||
setEditorState({ ...editorState, width: newWidth as ControlWidth })
|
||||
}
|
||||
|
@ -377,10 +372,7 @@ export const DataControlEditor = <State extends DefaultDataControlState = Defaul
|
|||
<EuiSwitch
|
||||
label={DataControlEditorStrings.manageControl.displaySettings.getGrowSwitchTitle()}
|
||||
color="primary"
|
||||
checked={
|
||||
(editorState.grow === undefined ? defaultGrow : editorState.grow) ??
|
||||
DEFAULT_CONTROL_GROW
|
||||
}
|
||||
checked={editorState.grow ?? DEFAULT_CONTROL_GROW}
|
||||
onChange={() => setEditorState({ ...editorState, grow: !editorState.grow })}
|
||||
data-test-subj="control-editor-grow-switch"
|
||||
/>
|
||||
|
|
|
@ -26,11 +26,6 @@ import { CanClearSelections, ControlWidth } from '../../types';
|
|||
|
||||
import { ControlGroupApi } from '../control_group/types';
|
||||
|
||||
export interface PublishesControlDisplaySettings {
|
||||
grow: PublishingSubject<boolean | undefined>;
|
||||
width: PublishingSubject<ControlWidth | undefined>;
|
||||
}
|
||||
|
||||
export interface HasCustomPrepend {
|
||||
CustomPrependComponent: React.FC<{}>;
|
||||
}
|
||||
|
@ -38,7 +33,6 @@ export interface HasCustomPrepend {
|
|||
export type DefaultControlApi = PublishesDataLoading &
|
||||
PublishesBlockingError &
|
||||
PublishesUnsavedChanges &
|
||||
PublishesControlDisplaySettings &
|
||||
Partial<PublishesPanelTitle & PublishesDisabledActionIds & HasCustomPrepend> &
|
||||
CanClearSelections &
|
||||
HasType &
|
||||
|
@ -51,6 +45,8 @@ export type DefaultControlApi = PublishesDataLoading &
|
|||
/** TODO: Make these non-public as part of https://github.com/elastic/kibana/issues/174961 */
|
||||
setDataLoading: (loading: boolean) => void;
|
||||
setBlockingError: (error: Error | undefined) => void;
|
||||
grow: PublishingSubject<boolean | undefined>;
|
||||
width: PublishingSubject<ControlWidth | undefined>;
|
||||
};
|
||||
|
||||
export interface DefaultControlState {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue