mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[Embeddable Rebuild] [Controls] Clean up services + TODOs (#193180)](https://github.com/elastic/kibana/pull/193180) <!--- Backport version: 9.4.3 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Hannah Mudge","email":"Heenawter@users.noreply.github.com"},"sourceCommit":{"committedDate":"2024-09-19T14:02:49Z","message":"[Embeddable Rebuild] [Controls] Clean up services + TODOs (#193180)\n\nPart of https://github.com/elastic/kibana/issues/192005\r\nCloses https://github.com/elastic/kibana/issues/167438\r\n\r\n## Summary\r\n\r\n\r\n## Summary\r\n\r\nThis PR represents the second major cleanup task for the control group\r\nembeddable refactor. The tasks included in this PR can be loosely\r\nsummarized as follows:\r\n1. It removes the old, cumbersome services implementation and replaces\r\nit with a much simpler system (which is the same one used in the `links`\r\n+ `presentation_panel` plugins).\r\n- This it the main reason for the decrease in lines - the old system\r\nrequired a **huge** amount of boilerplate code, which is no longer\r\nnecessary with the new method for storing services.\r\n2. It addresses and/or removes any remaining TODO comments in the\r\n`controls` plugin\r\n- This includes renaming `ControlStyle` and `DEFAULT_CONTROL_STYLE` to\r\n`ControlLabelPosition` and `DEFAULT_CONTROL_LABEL_POSITION`\r\nrespectively, which represents a bulk of the changes.\r\n3. It moves all compatibility checks for all control actions to be async\r\nimported.\r\n4. It removes the ability to register controls from the `controls`\r\nplugin setup contract.\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n\r\n### For maintainers\r\n\r\n- [ ] This was checked for breaking API changes and was [labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"db5557429979b9a0f3420a50a06c7fd69cbdf5b2","branchLabelMapping":{"^v9.0.0$":"main","^v8.16.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["Team:Presentation","release_note:skip","impact:high","v9.0.0","backport:prev-minor"],"title":"[Embeddable Rebuild] [Controls] Clean up services + TODOs","number":193180,"url":"https://github.com/elastic/kibana/pull/193180","mergeCommit":{"message":"[Embeddable Rebuild] [Controls] Clean up services + TODOs (#193180)\n\nPart of https://github.com/elastic/kibana/issues/192005\r\nCloses https://github.com/elastic/kibana/issues/167438\r\n\r\n## Summary\r\n\r\n\r\n## Summary\r\n\r\nThis PR represents the second major cleanup task for the control group\r\nembeddable refactor. The tasks included in this PR can be loosely\r\nsummarized as follows:\r\n1. It removes the old, cumbersome services implementation and replaces\r\nit with a much simpler system (which is the same one used in the `links`\r\n+ `presentation_panel` plugins).\r\n- This it the main reason for the decrease in lines - the old system\r\nrequired a **huge** amount of boilerplate code, which is no longer\r\nnecessary with the new method for storing services.\r\n2. It addresses and/or removes any remaining TODO comments in the\r\n`controls` plugin\r\n- This includes renaming `ControlStyle` and `DEFAULT_CONTROL_STYLE` to\r\n`ControlLabelPosition` and `DEFAULT_CONTROL_LABEL_POSITION`\r\nrespectively, which represents a bulk of the changes.\r\n3. It moves all compatibility checks for all control actions to be async\r\nimported.\r\n4. It removes the ability to register controls from the `controls`\r\nplugin setup contract.\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n\r\n### For maintainers\r\n\r\n- [ ] This was checked for breaking API changes and was [labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"db5557429979b9a0f3420a50a06c7fd69cbdf5b2"}},"sourceBranch":"main","suggestedTargetBranches":[],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/193180","number":193180,"mergeCommit":{"message":"[Embeddable Rebuild] [Controls] Clean up services + TODOs (#193180)\n\nPart of https://github.com/elastic/kibana/issues/192005\r\nCloses https://github.com/elastic/kibana/issues/167438\r\n\r\n## Summary\r\n\r\n\r\n## Summary\r\n\r\nThis PR represents the second major cleanup task for the control group\r\nembeddable refactor. The tasks included in this PR can be loosely\r\nsummarized as follows:\r\n1. It removes the old, cumbersome services implementation and replaces\r\nit with a much simpler system (which is the same one used in the `links`\r\n+ `presentation_panel` plugins).\r\n- This it the main reason for the decrease in lines - the old system\r\nrequired a **huge** amount of boilerplate code, which is no longer\r\nnecessary with the new method for storing services.\r\n2. It addresses and/or removes any remaining TODO comments in the\r\n`controls` plugin\r\n- This includes renaming `ControlStyle` and `DEFAULT_CONTROL_STYLE` to\r\n`ControlLabelPosition` and `DEFAULT_CONTROL_LABEL_POSITION`\r\nrespectively, which represents a bulk of the changes.\r\n3. It moves all compatibility checks for all control actions to be async\r\nimported.\r\n4. It removes the ability to register controls from the `controls`\r\nplugin setup contract.\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere updated or added to match the most common scenarios\r\n\r\n\r\n### For maintainers\r\n\r\n- [ ] This was checked for breaking API changes and was [labeled\r\nappropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\r\n\r\n---------\r\n\r\nCo-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>","sha":"db5557429979b9a0f3420a50a06c7fd69cbdf5b2"}}]}] BACKPORT--> Co-authored-by: Hannah Mudge <Heenawter@users.noreply.github.com>
This commit is contained in:
parent
b0853caa12
commit
b2e6263d94
91 changed files with 399 additions and 1408 deletions
|
@ -7,11 +7,11 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { ControlStyle, ControlWidth } from './types';
|
||||
import { ControlLabelPosition, ControlWidth } from './types';
|
||||
|
||||
export const DEFAULT_CONTROL_WIDTH: ControlWidth = 'medium';
|
||||
export const DEFAULT_CONTROL_GROW: boolean = true;
|
||||
export const DEFAULT_CONTROL_STYLE: ControlStyle = 'oneLine';
|
||||
export const DEFAULT_CONTROL_LABEL_POSITION: ControlLabelPosition = 'oneLine';
|
||||
|
||||
export const TIME_SLIDER_CONTROL = 'timeSlider';
|
||||
export const RANGE_SLIDER_CONTROL = 'rangeSliderControl';
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
import { DataViewField } from '@kbn/data-views-plugin/common';
|
||||
import { ControlStyle, DefaultControlState, ParentIgnoreSettings } from '../types';
|
||||
import { ControlLabelPosition, DefaultControlState, ParentIgnoreSettings } from '../types';
|
||||
|
||||
export const CONTROL_GROUP_TYPE = 'control_group';
|
||||
|
||||
|
@ -31,7 +31,7 @@ export interface ControlGroupEditorConfig {
|
|||
|
||||
export interface ControlGroupRuntimeState<State extends DefaultControlState = DefaultControlState> {
|
||||
chainingSystem: ControlGroupChainingSystem;
|
||||
labelPosition: ControlStyle; // TODO: Rename this type to ControlLabelPosition
|
||||
labelPosition: ControlLabelPosition;
|
||||
autoApplySelections: boolean;
|
||||
ignoreParentSettings?: ParentIgnoreSettings;
|
||||
|
||||
|
@ -50,7 +50,7 @@ export interface ControlGroupSerializedState
|
|||
ignoreParentSettingsJSON: string;
|
||||
// In runtime state, we refer to this property as `labelPosition`;
|
||||
// to avoid migrations, we will continue to refer to this property as `controlStyle` in the serialized state
|
||||
controlStyle: ControlStyle;
|
||||
controlStyle: ControlLabelPosition;
|
||||
// In runtime state, we refer to the inverse of this property as `autoApplySelections`
|
||||
// to avoid migrations, we will continue to refer to this property as `showApplySelections` in the serialized state
|
||||
showApplySelections?: boolean;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
export type {
|
||||
ControlStyle,
|
||||
ControlLabelPosition,
|
||||
ControlWidth,
|
||||
DefaultControlState,
|
||||
DefaultDataControlState,
|
||||
|
@ -18,7 +18,7 @@ export type {
|
|||
|
||||
export {
|
||||
DEFAULT_CONTROL_GROW,
|
||||
DEFAULT_CONTROL_STYLE,
|
||||
DEFAULT_CONTROL_LABEL_POSITION,
|
||||
DEFAULT_CONTROL_WIDTH,
|
||||
OPTIONS_LIST_CONTROL,
|
||||
RANGE_SLIDER_CONTROL,
|
||||
|
|
|
@ -15,8 +15,6 @@ import { OptionsListSortingType } from './suggestions_sorting';
|
|||
import { DefaultDataControlState } from '../types';
|
||||
import { OptionsListSearchTechnique } from './suggestions_searching';
|
||||
|
||||
export const OPTIONS_LIST_CONTROL = 'optionsListControl'; // TODO: Replace with OPTIONS_LIST_CONTROL_TYPE
|
||||
|
||||
/**
|
||||
* ----------------------------------------------------------------
|
||||
* Options list state types
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
export type ControlWidth = 'small' | 'medium' | 'large';
|
||||
export type ControlStyle = 'twoLine' | 'oneLine';
|
||||
export type ControlLabelPosition = 'twoLine' | 'oneLine';
|
||||
|
||||
export type TimeSlice = [number, number];
|
||||
|
||||
|
|
|
@ -8,8 +8,5 @@
|
|||
*/
|
||||
|
||||
// Start the services with stubs
|
||||
import { pluginServices } from './public/services';
|
||||
import { registry } from './public/services/plugin_services.stub';
|
||||
|
||||
registry.start({});
|
||||
pluginServices.setRegistry(registry);
|
||||
import { setStubKibanaServices } from './public/services/mocks';
|
||||
setStubKibanaServices();
|
||||
|
|
|
@ -9,8 +9,6 @@
|
|||
"browser": true,
|
||||
"requiredPlugins": [
|
||||
"presentationUtil",
|
||||
"kibanaReact",
|
||||
"expressions",
|
||||
"embeddable",
|
||||
"dataViews",
|
||||
"data",
|
||||
|
@ -18,6 +16,6 @@
|
|||
"uiActions"
|
||||
],
|
||||
"extraPublicDirs": ["common"],
|
||||
"requiredBundles": ["kibanaUtils"]
|
||||
"requiredBundles": []
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,42 +11,10 @@ import React, { SyntheticEvent } from 'react';
|
|||
|
||||
import { EuiButtonIcon, EuiToolTip } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
apiIsPresentationContainer,
|
||||
type PresentationContainer,
|
||||
} from '@kbn/presentation-containers';
|
||||
import {
|
||||
apiCanAccessViewMode,
|
||||
apiHasParentApi,
|
||||
apiHasType,
|
||||
apiHasUniqueId,
|
||||
apiIsOfType,
|
||||
type EmbeddableApiContext,
|
||||
type HasParentApi,
|
||||
type HasType,
|
||||
type HasUniqueId,
|
||||
} from '@kbn/presentation-publishing';
|
||||
import { type Action, IncompatibleActionError } from '@kbn/ui-actions-plugin/public';
|
||||
import type { EmbeddableApiContext, HasUniqueId } from '@kbn/presentation-publishing';
|
||||
import { IncompatibleActionError, type Action } from '@kbn/ui-actions-plugin/public';
|
||||
|
||||
import { ACTION_CLEAR_CONTROL } from '.';
|
||||
import { CONTROL_GROUP_TYPE } from '..';
|
||||
import { isClearableControl, type CanClearSelections } from '../types';
|
||||
|
||||
export type ClearControlActionApi = HasType &
|
||||
HasUniqueId &
|
||||
CanClearSelections &
|
||||
HasParentApi<PresentationContainer & HasType>;
|
||||
|
||||
const isApiCompatible = (api: unknown | null): api is ClearControlActionApi =>
|
||||
Boolean(
|
||||
apiHasType(api) &&
|
||||
apiHasUniqueId(api) &&
|
||||
isClearableControl(api) &&
|
||||
apiHasParentApi(api) &&
|
||||
apiCanAccessViewMode(api.parentApi) &&
|
||||
apiIsOfType(api.parentApi, CONTROL_GROUP_TYPE) &&
|
||||
apiIsPresentationContainer(api.parentApi)
|
||||
);
|
||||
|
||||
export class ClearControlAction implements Action<EmbeddableApiContext> {
|
||||
public readonly type = ACTION_CLEAR_CONTROL;
|
||||
|
@ -56,12 +24,10 @@ export class ClearControlAction implements Action<EmbeddableApiContext> {
|
|||
constructor() {}
|
||||
|
||||
public readonly MenuItem = ({ context }: { context: EmbeddableApiContext }) => {
|
||||
if (!isApiCompatible(context.embeddable)) throw new IncompatibleActionError();
|
||||
|
||||
return (
|
||||
<EuiToolTip content={this.getDisplayName(context)}>
|
||||
<EuiButtonIcon
|
||||
data-test-subj={`control-action-${context.embeddable.uuid}-erase`}
|
||||
data-test-subj={`control-action-${(context.embeddable as HasUniqueId).uuid}-erase`}
|
||||
aria-label={this.getDisplayName(context)}
|
||||
iconType={this.getIconType(context)}
|
||||
onClick={(event: SyntheticEvent<HTMLButtonElement>) => {
|
||||
|
@ -75,23 +41,24 @@ export class ClearControlAction implements Action<EmbeddableApiContext> {
|
|||
};
|
||||
|
||||
public getDisplayName({ embeddable }: EmbeddableApiContext) {
|
||||
if (!isApiCompatible(embeddable)) throw new IncompatibleActionError();
|
||||
return i18n.translate('controls.controlGroup.floatingActions.clearTitle', {
|
||||
defaultMessage: 'Clear',
|
||||
});
|
||||
}
|
||||
|
||||
public getIconType({ embeddable }: EmbeddableApiContext) {
|
||||
if (!isApiCompatible(embeddable)) throw new IncompatibleActionError();
|
||||
return 'eraser';
|
||||
}
|
||||
|
||||
public async isCompatible({ embeddable }: EmbeddableApiContext) {
|
||||
return isApiCompatible(embeddable);
|
||||
const { isCompatible } = await import('./clear_control_action_compatibility_check');
|
||||
return isCompatible(embeddable);
|
||||
}
|
||||
|
||||
public async execute({ embeddable }: EmbeddableApiContext) {
|
||||
if (!isApiCompatible(embeddable)) throw new IncompatibleActionError();
|
||||
const { compatibilityCheck } = await import('./clear_control_action_compatibility_check');
|
||||
if (!compatibilityCheck(embeddable)) throw new IncompatibleActionError();
|
||||
|
||||
embeddable.clearSelections();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { PresentationContainer, apiIsPresentationContainer } from '@kbn/presentation-containers';
|
||||
import {
|
||||
HasParentApi,
|
||||
HasType,
|
||||
HasUniqueId,
|
||||
apiCanAccessViewMode,
|
||||
apiHasParentApi,
|
||||
apiHasType,
|
||||
apiHasUniqueId,
|
||||
apiIsOfType,
|
||||
} from '@kbn/presentation-publishing';
|
||||
import { CONTROL_GROUP_TYPE } from '../../common';
|
||||
import { isClearableControl, type CanClearSelections } from '../types';
|
||||
|
||||
type ClearControlActionApi = HasType &
|
||||
HasUniqueId &
|
||||
CanClearSelections &
|
||||
HasParentApi<PresentationContainer & HasType>;
|
||||
|
||||
export const compatibilityCheck = (api: unknown | null): api is ClearControlActionApi =>
|
||||
Boolean(
|
||||
apiHasType(api) &&
|
||||
apiHasUniqueId(api) &&
|
||||
isClearableControl(api) &&
|
||||
apiHasParentApi(api) &&
|
||||
apiCanAccessViewMode(api.parentApi) &&
|
||||
apiIsOfType(api.parentApi, CONTROL_GROUP_TYPE) &&
|
||||
apiIsPresentationContainer(api.parentApi)
|
||||
);
|
||||
|
||||
export function isCompatible(api: unknown) {
|
||||
return compatibilityCheck(api);
|
||||
}
|
|
@ -9,22 +9,15 @@
|
|||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
|
||||
import { ViewMode } from '@kbn/presentation-publishing';
|
||||
|
||||
import { getOptionsListControlFactory } from '../react_controls/controls/data_controls/options_list_control/get_options_list_control_factory';
|
||||
import { OptionsListControlApi } from '../react_controls/controls/data_controls/options_list_control/types';
|
||||
import {
|
||||
getMockedBuildApi,
|
||||
getMockedControlGroupApi,
|
||||
} from '../react_controls/controls/mocks/control_mocks';
|
||||
import { pluginServices } from '../services';
|
||||
import { DeleteControlAction } from './delete_control_action';
|
||||
|
||||
const mockDataViews = dataViewPluginMocks.createStartContract();
|
||||
const mockCore = coreMock.createStart();
|
||||
import { coreServices } from '../services/kibana_services';
|
||||
|
||||
const dashboardApi = {
|
||||
viewMode: new BehaviorSubject<ViewMode>('view'),
|
||||
|
@ -38,11 +31,7 @@ const controlGroupApi = getMockedControlGroupApi(dashboardApi, {
|
|||
|
||||
let controlApi: OptionsListControlApi;
|
||||
beforeAll(async () => {
|
||||
const controlFactory = getOptionsListControlFactory({
|
||||
core: mockCore,
|
||||
data: dataPluginMock.createStartContract(),
|
||||
dataViews: mockDataViews,
|
||||
});
|
||||
const controlFactory = getOptionsListControlFactory();
|
||||
|
||||
const uuid = 'testControl';
|
||||
const control = await controlFactory.buildControl(
|
||||
|
@ -72,7 +61,7 @@ test('Execute throws an error when called with an embeddable not in a parent', a
|
|||
describe('Execute should open a confirm modal', () => {
|
||||
test('Canceling modal will keep control', async () => {
|
||||
const spyOn = jest.fn().mockResolvedValue(false);
|
||||
pluginServices.getServices().overlays.openConfirm = spyOn;
|
||||
coreServices.overlays.openConfirm = spyOn;
|
||||
|
||||
const deleteControlAction = new DeleteControlAction();
|
||||
await deleteControlAction.execute({ embeddable: controlApi });
|
||||
|
@ -83,7 +72,7 @@ describe('Execute should open a confirm modal', () => {
|
|||
|
||||
test('Confirming modal will delete control', async () => {
|
||||
const spyOn = jest.fn().mockResolvedValue(true);
|
||||
pluginServices.getServices().overlays.openConfirm = spyOn;
|
||||
coreServices.overlays.openConfirm = spyOn;
|
||||
|
||||
const deleteControlAction = new DeleteControlAction();
|
||||
await deleteControlAction.execute({ embeddable: controlApi });
|
||||
|
|
|
@ -10,65 +10,25 @@
|
|||
import React from 'react';
|
||||
|
||||
import { EuiButtonIcon, EuiToolTip } from '@elastic/eui';
|
||||
import { ViewMode } from '@kbn/embeddable-plugin/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
apiIsPresentationContainer,
|
||||
type PresentationContainer,
|
||||
} from '@kbn/presentation-containers';
|
||||
import {
|
||||
apiCanAccessViewMode,
|
||||
apiHasParentApi,
|
||||
apiHasType,
|
||||
apiHasUniqueId,
|
||||
apiIsOfType,
|
||||
getInheritedViewMode,
|
||||
type EmbeddableApiContext,
|
||||
type HasParentApi,
|
||||
type HasType,
|
||||
type HasUniqueId,
|
||||
type PublishesViewMode,
|
||||
} from '@kbn/presentation-publishing';
|
||||
import type { HasUniqueId, EmbeddableApiContext } from '@kbn/presentation-publishing';
|
||||
import { IncompatibleActionError, type Action } from '@kbn/ui-actions-plugin/public';
|
||||
|
||||
import { ACTION_DELETE_CONTROL } from '.';
|
||||
import { CONTROL_GROUP_TYPE } from '..';
|
||||
import { pluginServices } from '../services';
|
||||
|
||||
export type DeleteControlActionApi = HasType &
|
||||
HasUniqueId &
|
||||
HasParentApi<PresentationContainer & PublishesViewMode & HasType>;
|
||||
|
||||
const isApiCompatible = (api: unknown | null): api is DeleteControlActionApi =>
|
||||
Boolean(
|
||||
apiHasType(api) &&
|
||||
apiHasUniqueId(api) &&
|
||||
apiHasParentApi(api) &&
|
||||
apiCanAccessViewMode(api.parentApi) &&
|
||||
apiIsOfType(api.parentApi, CONTROL_GROUP_TYPE) &&
|
||||
apiIsPresentationContainer(api.parentApi)
|
||||
);
|
||||
import { coreServices } from '../services/kibana_services';
|
||||
|
||||
export class DeleteControlAction implements Action<EmbeddableApiContext> {
|
||||
public readonly type = ACTION_DELETE_CONTROL;
|
||||
public readonly id = ACTION_DELETE_CONTROL;
|
||||
public order = 100; // should always be last
|
||||
|
||||
private openConfirm;
|
||||
|
||||
constructor() {
|
||||
({
|
||||
overlays: { openConfirm: this.openConfirm },
|
||||
} = pluginServices.getServices());
|
||||
}
|
||||
constructor() {}
|
||||
|
||||
public readonly MenuItem = ({ context }: { context: EmbeddableApiContext }) => {
|
||||
if (!isApiCompatible(context.embeddable)) throw new IncompatibleActionError();
|
||||
|
||||
return (
|
||||
<EuiToolTip content={this.getDisplayName(context)}>
|
||||
<EuiButtonIcon
|
||||
data-test-subj={`control-action-${context.embeddable.uuid}-delete`}
|
||||
data-test-subj={`control-action-${(context.embeddable as HasUniqueId).uuid}-delete`}
|
||||
aria-label={this.getDisplayName(context)}
|
||||
iconType={this.getIconType(context)}
|
||||
onClick={() => this.execute(context)}
|
||||
|
@ -79,46 +39,46 @@ export class DeleteControlAction implements Action<EmbeddableApiContext> {
|
|||
};
|
||||
|
||||
public getDisplayName({ embeddable }: EmbeddableApiContext) {
|
||||
if (!isApiCompatible(embeddable)) throw new IncompatibleActionError();
|
||||
return i18n.translate('controls.controlGroup.floatingActions.removeTitle', {
|
||||
defaultMessage: 'Delete',
|
||||
});
|
||||
}
|
||||
|
||||
public getIconType({ embeddable }: EmbeddableApiContext) {
|
||||
if (!isApiCompatible(embeddable)) throw new IncompatibleActionError();
|
||||
return 'trash';
|
||||
}
|
||||
|
||||
public async isCompatible({ embeddable }: EmbeddableApiContext) {
|
||||
return (
|
||||
isApiCompatible(embeddable) && getInheritedViewMode(embeddable.parentApi) === ViewMode.EDIT
|
||||
);
|
||||
const { isCompatible } = await import('./delete_control_action_compatibility_check');
|
||||
return isCompatible(embeddable);
|
||||
}
|
||||
|
||||
public async execute({ embeddable }: EmbeddableApiContext) {
|
||||
if (!isApiCompatible(embeddable)) throw new IncompatibleActionError();
|
||||
const { compatibilityCheck } = await import('./delete_control_action_compatibility_check');
|
||||
if (!compatibilityCheck(embeddable)) throw new IncompatibleActionError();
|
||||
|
||||
this.openConfirm(
|
||||
i18n.translate('controls.controlGroup.management.delete.sub', {
|
||||
defaultMessage: 'Controls are not recoverable once removed.',
|
||||
}),
|
||||
{
|
||||
confirmButtonText: i18n.translate('controls.controlGroup.management.delete.confirm', {
|
||||
defaultMessage: 'Delete',
|
||||
coreServices.overlays
|
||||
.openConfirm(
|
||||
i18n.translate('controls.controlGroup.management.delete.sub', {
|
||||
defaultMessage: 'Controls are not recoverable once removed.',
|
||||
}),
|
||||
cancelButtonText: i18n.translate('controls.controlGroup.management.delete.cancel', {
|
||||
defaultMessage: 'Cancel',
|
||||
}),
|
||||
title: i18n.translate('controls.controlGroup.management.delete.deleteTitle', {
|
||||
defaultMessage: 'Delete control?',
|
||||
}),
|
||||
buttonColor: 'danger',
|
||||
}
|
||||
).then((confirmed) => {
|
||||
if (confirmed) {
|
||||
embeddable.parentApi.removePanel(embeddable.uuid);
|
||||
}
|
||||
});
|
||||
{
|
||||
confirmButtonText: i18n.translate('controls.controlGroup.management.delete.confirm', {
|
||||
defaultMessage: 'Delete',
|
||||
}),
|
||||
cancelButtonText: i18n.translate('controls.controlGroup.management.delete.cancel', {
|
||||
defaultMessage: 'Cancel',
|
||||
}),
|
||||
title: i18n.translate('controls.controlGroup.management.delete.deleteTitle', {
|
||||
defaultMessage: 'Delete control?',
|
||||
}),
|
||||
buttonColor: 'danger',
|
||||
}
|
||||
)
|
||||
.then((confirmed) => {
|
||||
if (confirmed) {
|
||||
embeddable.parentApi.removePanel(embeddable.uuid);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { ViewMode } from '@kbn/embeddable-plugin/public';
|
||||
import { PresentationContainer, apiIsPresentationContainer } from '@kbn/presentation-containers';
|
||||
import {
|
||||
HasParentApi,
|
||||
HasType,
|
||||
HasUniqueId,
|
||||
PublishesViewMode,
|
||||
apiCanAccessViewMode,
|
||||
apiHasParentApi,
|
||||
apiHasType,
|
||||
apiHasUniqueId,
|
||||
apiIsOfType,
|
||||
getInheritedViewMode,
|
||||
} from '@kbn/presentation-publishing';
|
||||
import { CONTROL_GROUP_TYPE } from '../../common';
|
||||
|
||||
type DeleteControlActionApi = HasType &
|
||||
HasUniqueId &
|
||||
HasParentApi<PresentationContainer & PublishesViewMode & HasType>;
|
||||
|
||||
export const compatibilityCheck = (api: unknown | null): api is DeleteControlActionApi =>
|
||||
Boolean(
|
||||
apiHasType(api) &&
|
||||
apiHasUniqueId(api) &&
|
||||
apiHasParentApi(api) &&
|
||||
apiCanAccessViewMode(api.parentApi) &&
|
||||
apiIsOfType(api.parentApi, CONTROL_GROUP_TYPE) &&
|
||||
apiIsPresentationContainer(api.parentApi)
|
||||
);
|
||||
|
||||
export function isCompatible(api: unknown) {
|
||||
return compatibilityCheck(api) && getInheritedViewMode(api.parentApi) === ViewMode.EDIT;
|
||||
}
|
|
@ -9,9 +9,6 @@
|
|||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
|
||||
import dateMath from '@kbn/datemath';
|
||||
import type { TimeRange } from '@kbn/es-query';
|
||||
import type { ViewMode } from '@kbn/presentation-publishing';
|
||||
|
@ -23,12 +20,10 @@ import {
|
|||
getMockedControlGroupApi,
|
||||
} from '../react_controls/controls/mocks/control_mocks';
|
||||
import { getTimesliderControlFactory } from '../react_controls/controls/timeslider_control/get_timeslider_control_factory';
|
||||
import { dataService } from '../services/kibana_services';
|
||||
import { EditControlAction } from './edit_control_action';
|
||||
|
||||
const mockDataViews = dataViewPluginMocks.createStartContract();
|
||||
const mockCore = coreMock.createStart();
|
||||
const dataStartServiceMock = dataPluginMock.createStartContract();
|
||||
dataStartServiceMock.query.timefilter.timefilter.calculateBounds = (timeRange: TimeRange) => {
|
||||
dataService.query.timefilter.timefilter.calculateBounds = (timeRange: TimeRange) => {
|
||||
const now = new Date();
|
||||
return {
|
||||
min: dateMath.parse(timeRange.from, { forceNow: now }),
|
||||
|
@ -48,11 +43,7 @@ const controlGroupApi = getMockedControlGroupApi(dashboardApi, {
|
|||
|
||||
let optionsListApi: OptionsListControlApi;
|
||||
beforeAll(async () => {
|
||||
const controlFactory = getOptionsListControlFactory({
|
||||
core: mockCore,
|
||||
data: dataStartServiceMock,
|
||||
dataViews: mockDataViews,
|
||||
});
|
||||
const controlFactory = getOptionsListControlFactory();
|
||||
|
||||
const optionsListUuid = 'optionsListControl';
|
||||
const optionsListControl = await controlFactory.buildControl(
|
||||
|
@ -73,10 +64,7 @@ beforeAll(async () => {
|
|||
|
||||
describe('Incompatible embeddables', () => {
|
||||
test('Action is incompatible with embeddables that are not editable', async () => {
|
||||
const timeSliderFactory = getTimesliderControlFactory({
|
||||
core: mockCore,
|
||||
data: dataStartServiceMock,
|
||||
});
|
||||
const timeSliderFactory = getTimesliderControlFactory();
|
||||
const timeSliderUuid = 'timeSliderControl';
|
||||
const timeSliderControl = await timeSliderFactory.buildControl(
|
||||
{},
|
||||
|
|
|
@ -21,7 +21,6 @@ export { ACTION_CLEAR_CONTROL, ACTION_DELETE_CONTROL, ACTION_EDIT_CONTROL } from
|
|||
export type {
|
||||
DataControlApi,
|
||||
DataControlFactory,
|
||||
DataControlServices,
|
||||
} from './react_controls/controls/data_controls/types';
|
||||
|
||||
export {
|
||||
|
|
|
@ -10,63 +10,36 @@
|
|||
import type { CoreSetup, CoreStart, Plugin } from '@kbn/core/public';
|
||||
import { PANEL_HOVER_TRIGGER } from '@kbn/embeddable-plugin/public';
|
||||
|
||||
import { ClearControlAction } from './actions/clear_control_action';
|
||||
import { DeleteControlAction } from './actions/delete_control_action';
|
||||
import { EditControlAction } from './actions/edit_control_action';
|
||||
import { registerControlGroupEmbeddable } from './react_controls/control_group/register_control_group_embeddable';
|
||||
import { registerOptionsListControl } from './react_controls/controls/data_controls/options_list_control/register_options_list_control';
|
||||
import { registerRangeSliderControl } from './react_controls/controls/data_controls/range_slider/register_range_slider_control';
|
||||
import { registerTimeSliderControl } from './react_controls/controls/timeslider_control/register_timeslider_control';
|
||||
import { controlsService } from './services/controls/controls_service';
|
||||
import type {
|
||||
ControlsPluginSetup,
|
||||
ControlsPluginSetupDeps,
|
||||
ControlsPluginStart,
|
||||
ControlsPluginStartDeps,
|
||||
} from './types';
|
||||
import { setKibanaServices, untilPluginStartServicesReady } from './services/kibana_services';
|
||||
import type { ControlsPluginSetupDeps, ControlsPluginStartDeps } from './types';
|
||||
|
||||
export class ControlsPlugin
|
||||
implements
|
||||
Plugin<
|
||||
ControlsPluginSetup,
|
||||
ControlsPluginStart,
|
||||
ControlsPluginSetupDeps,
|
||||
ControlsPluginStartDeps
|
||||
>
|
||||
implements Plugin<void, void, ControlsPluginSetupDeps, ControlsPluginStartDeps>
|
||||
{
|
||||
private async startControlsKibanaServices(
|
||||
coreStart: CoreStart,
|
||||
startPlugins: ControlsPluginStartDeps
|
||||
) {
|
||||
const { registry, pluginServices } = await import('./services/plugin_services');
|
||||
pluginServices.setRegistry(registry.start({ coreStart, startPlugins }));
|
||||
}
|
||||
|
||||
public setup(
|
||||
_coreSetup: CoreSetup<ControlsPluginStartDeps, ControlsPluginStart>,
|
||||
_coreSetup: CoreSetup<ControlsPluginStartDeps>,
|
||||
_setupPlugins: ControlsPluginSetupDeps
|
||||
): ControlsPluginSetup {
|
||||
const { registerControlFactory } = controlsService;
|
||||
) {
|
||||
const { embeddable } = _setupPlugins;
|
||||
|
||||
registerControlGroupEmbeddable(_coreSetup, embeddable);
|
||||
registerOptionsListControl(_coreSetup);
|
||||
registerRangeSliderControl(_coreSetup);
|
||||
registerTimeSliderControl(_coreSetup);
|
||||
|
||||
return {
|
||||
registerControlFactory,
|
||||
};
|
||||
registerControlGroupEmbeddable(embeddable);
|
||||
registerOptionsListControl();
|
||||
registerRangeSliderControl();
|
||||
registerTimeSliderControl();
|
||||
}
|
||||
|
||||
public start(coreStart: CoreStart, startPlugins: ControlsPluginStartDeps): ControlsPluginStart {
|
||||
this.startControlsKibanaServices(coreStart, startPlugins).then(async () => {
|
||||
const { uiActions } = startPlugins;
|
||||
|
||||
const [{ DeleteControlAction }, { EditControlAction }, { ClearControlAction }] =
|
||||
await Promise.all([
|
||||
import('./actions/delete_control_action'),
|
||||
import('./actions/edit_control_action'),
|
||||
import('./actions/clear_control_action'),
|
||||
]);
|
||||
public start(coreStart: CoreStart, startPlugins: ControlsPluginStartDeps) {
|
||||
const { uiActions } = startPlugins;
|
||||
setKibanaServices(coreStart, startPlugins);
|
||||
|
||||
untilPluginStartServicesReady().then(() => {
|
||||
const deleteControlAction = new DeleteControlAction();
|
||||
uiActions.registerAction(deleteControlAction);
|
||||
uiActions.attachAction(PANEL_HOVER_TRIGGER, deleteControlAction.id);
|
||||
|
@ -79,12 +52,6 @@ export class ControlsPlugin
|
|||
uiActions.registerAction(clearControlAction);
|
||||
uiActions.attachAction(PANEL_HOVER_TRIGGER, clearControlAction.id);
|
||||
});
|
||||
|
||||
const { getControlFactory, getAllControlTypes } = controlsService;
|
||||
return {
|
||||
getControlFactory,
|
||||
getAllControlTypes,
|
||||
};
|
||||
}
|
||||
|
||||
public stop() {}
|
||||
|
|
|
@ -13,8 +13,6 @@ import { EuiButtonEmpty, EuiPopover } from '@elastic/eui';
|
|||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { Markdown } from '@kbn/shared-ux-markdown';
|
||||
|
||||
/** TODO: This file is duplicated from the controls plugin to avoid exporting it */
|
||||
|
||||
interface ControlErrorProps {
|
||||
error: Error | string;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiPanel, EuiToolTip } from '
|
|||
import { css } from '@emotion/react';
|
||||
import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
|
||||
|
||||
import type { ControlStyle } from '../../../../common';
|
||||
import type { ControlLabelPosition } from '../../../../common';
|
||||
import type { DefaultControlApi } from '../../controls/types';
|
||||
import { ControlGroupStrings } from '../control_group_strings';
|
||||
import { ControlsInOrder } from '../init_controls_manager';
|
||||
|
@ -49,7 +49,7 @@ interface Props {
|
|||
setControlApi: (uuid: string, controlApi: DefaultControlApi) => void;
|
||||
};
|
||||
hasUnappliedSelections: boolean;
|
||||
labelPosition: ControlStyle;
|
||||
labelPosition: ControlLabelPosition;
|
||||
}
|
||||
|
||||
export function ControlGroup({
|
||||
|
|
|
@ -15,8 +15,8 @@ import { render } from '@testing-library/react';
|
|||
import { ControlGroupApi } from '../../..';
|
||||
import {
|
||||
ControlGroupChainingSystem,
|
||||
ControlStyle,
|
||||
DEFAULT_CONTROL_STYLE,
|
||||
ControlLabelPosition,
|
||||
DEFAULT_CONTROL_LABEL_POSITION,
|
||||
ParentIgnoreSettings,
|
||||
} from '../../../../common';
|
||||
import { DefaultControlApi } from '../../controls/types';
|
||||
|
@ -33,7 +33,7 @@ describe('render', () => {
|
|||
onDeleteAll: () => {},
|
||||
stateManager: {
|
||||
chainingSystem: new BehaviorSubject<ControlGroupChainingSystem>('HIERARCHICAL'),
|
||||
labelPosition: new BehaviorSubject<ControlStyle>(DEFAULT_CONTROL_STYLE),
|
||||
labelPosition: new BehaviorSubject<ControlLabelPosition>(DEFAULT_CONTROL_LABEL_POSITION),
|
||||
autoApplySelections: new BehaviorSubject<boolean>(true),
|
||||
ignoreParentSettings: new BehaviorSubject<ParentIgnoreSettings | undefined>(undefined),
|
||||
},
|
||||
|
|
|
@ -27,7 +27,7 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
|
||||
|
||||
import type { ControlStyle, ParentIgnoreSettings } from '../../../../common';
|
||||
import type { ControlLabelPosition, ParentIgnoreSettings } from '../../../../common';
|
||||
import { CONTROL_LAYOUT_OPTIONS } from '../../controls/data_controls/editor_constants';
|
||||
import type { ControlStateManager } from '../../controls/types';
|
||||
import { ControlGroupStrings } from '../control_group_strings';
|
||||
|
@ -86,7 +86,7 @@ export const ControlGroupEditor = ({ onCancel, onSave, onDeleteAll, stateManager
|
|||
idSelected={selectedLabelPosition}
|
||||
legend={ControlGroupStrings.management.labelPosition.getLabelPositionLegend()}
|
||||
onChange={(newPosition: string) => {
|
||||
stateManager.labelPosition.next(newPosition as ControlStyle);
|
||||
stateManager.labelPosition.next(newPosition as ControlLabelPosition);
|
||||
}}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
|
|
@ -14,7 +14,7 @@ import { pluginServices as presentationUtilPluginServices } from '@kbn/presentat
|
|||
import { registry as presentationUtilServicesRegistry } from '@kbn/presentation-util-plugin/public/services/plugin_services.story';
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
|
||||
import type { ControlStyle, ControlWidth } from '../../../../common';
|
||||
import type { ControlLabelPosition, ControlWidth } from '../../../../common';
|
||||
import { ControlPanel } from './control_panel';
|
||||
|
||||
describe('render', () => {
|
||||
|
@ -74,7 +74,7 @@ describe('render', () => {
|
|||
mockApi = {
|
||||
uuid: 'control1',
|
||||
parentApi: {
|
||||
labelPosition: new BehaviorSubject<ControlStyle>('oneLine'),
|
||||
labelPosition: new BehaviorSubject<ControlLabelPosition>('oneLine'),
|
||||
},
|
||||
};
|
||||
const controlPanel = render(<ControlPanel uuid="control1" Component={Component} />);
|
||||
|
@ -92,7 +92,7 @@ describe('render', () => {
|
|||
mockApi = {
|
||||
uuid: 'control1',
|
||||
parentApi: {
|
||||
labelPosition: new BehaviorSubject<ControlStyle>('twoLine'),
|
||||
labelPosition: new BehaviorSubject<ControlLabelPosition>('twoLine'),
|
||||
},
|
||||
};
|
||||
const controlPanel = render(<ControlPanel uuid="control1" Component={Component} />);
|
||||
|
|
|
@ -11,9 +11,7 @@ import fastIsEqual from 'fast-deep-equal';
|
|||
import React, { useEffect } from 'react';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { CoreStart } from '@kbn/core/public';
|
||||
import { DataView } from '@kbn/data-views-plugin/common';
|
||||
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import { ReactEmbeddableFactory } from '@kbn/embeddable-plugin/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import {
|
||||
|
@ -31,11 +29,11 @@ import type {
|
|||
ControlGroupChainingSystem,
|
||||
ControlGroupRuntimeState,
|
||||
ControlGroupSerializedState,
|
||||
ControlLabelPosition,
|
||||
ControlPanelsState,
|
||||
ControlStyle,
|
||||
ParentIgnoreSettings,
|
||||
} from '../../../common';
|
||||
import { CONTROL_GROUP_TYPE, DEFAULT_CONTROL_STYLE } from '../../../common';
|
||||
import { CONTROL_GROUP_TYPE, DEFAULT_CONTROL_LABEL_POSITION } from '../../../common';
|
||||
import { openDataControlEditor } from '../controls/data_controls/open_data_control_editor';
|
||||
import { ControlGroup } from './components/control_group';
|
||||
import { chaining$, controlFetch$, controlGroupFetch$ } from './control_fetch';
|
||||
|
@ -45,13 +43,11 @@ import { openEditControlGroupFlyout } from './open_edit_control_group_flyout';
|
|||
import { initSelectionsManager } from './selections_manager';
|
||||
import type { ControlGroupApi } from './types';
|
||||
import { deserializeControlGroup } from './utils/serialization_utils';
|
||||
import { coreServices, dataViewsService } from '../../services/kibana_services';
|
||||
|
||||
const DEFAULT_CHAINING_SYSTEM = 'HIERARCHICAL';
|
||||
|
||||
export const getControlGroupEmbeddableFactory = (services: {
|
||||
core: CoreStart;
|
||||
dataViews: DataViewsPublicPluginStart;
|
||||
}) => {
|
||||
export const getControlGroupEmbeddableFactory = () => {
|
||||
const controlGroupEmbeddableFactory: ReactEmbeddableFactory<
|
||||
ControlGroupSerializedState,
|
||||
ControlGroupRuntimeState,
|
||||
|
@ -75,7 +71,7 @@ export const getControlGroupEmbeddableFactory = (services: {
|
|||
} = initialRuntimeState;
|
||||
|
||||
const autoApplySelections$ = new BehaviorSubject<boolean>(autoApplySelections);
|
||||
const defaultDataViewId = await services.dataViews.getDefaultId();
|
||||
const defaultDataViewId = await dataViewsService.getDefaultId();
|
||||
const lastSavedControlsState$ = new BehaviorSubject<ControlPanelsState>(
|
||||
lastSavedRuntimeState.initialChildControlState
|
||||
);
|
||||
|
@ -94,15 +90,12 @@ export const getControlGroupEmbeddableFactory = (services: {
|
|||
const ignoreParentSettings$ = new BehaviorSubject<ParentIgnoreSettings | undefined>(
|
||||
ignoreParentSettings
|
||||
);
|
||||
const labelPosition$ = new BehaviorSubject<ControlStyle>( // TODO: Rename `ControlStyle`
|
||||
initialLabelPosition ?? DEFAULT_CONTROL_STYLE // TODO: Rename `DEFAULT_CONTROL_STYLE`
|
||||
const labelPosition$ = new BehaviorSubject<ControlLabelPosition>(
|
||||
initialLabelPosition ?? DEFAULT_CONTROL_LABEL_POSITION
|
||||
);
|
||||
const allowExpensiveQueries$ = new BehaviorSubject<boolean>(true);
|
||||
const disabledActionIds$ = new BehaviorSubject<string[] | undefined>(undefined);
|
||||
|
||||
/** TODO: Handle loading; loading should be true if any child is loading */
|
||||
const dataLoading$ = new BehaviorSubject<boolean | undefined>(false);
|
||||
|
||||
const unsavedChanges = initializeControlGroupUnsavedChanges(
|
||||
selectionsManager.applySelections,
|
||||
controlsManager.api.children$,
|
||||
|
@ -122,7 +115,10 @@ export const getControlGroupEmbeddableFactory = (services: {
|
|||
(next: ParentIgnoreSettings | undefined) => ignoreParentSettings$.next(next),
|
||||
fastIsEqual,
|
||||
],
|
||||
labelPosition: [labelPosition$, (next: ControlStyle) => labelPosition$.next(next)],
|
||||
labelPosition: [
|
||||
labelPosition$,
|
||||
(next: ControlLabelPosition) => labelPosition$.next(next),
|
||||
],
|
||||
},
|
||||
controlsManager.snapshotControlsRuntimeState,
|
||||
controlsManager.resetControlsUnsavedChanges,
|
||||
|
@ -157,18 +153,13 @@ export const getControlGroupEmbeddableFactory = (services: {
|
|||
initialChildControlState: controlsManager.snapshotControlsRuntimeState(),
|
||||
};
|
||||
},
|
||||
dataLoading: dataLoading$,
|
||||
onEdit: async () => {
|
||||
openEditControlGroupFlyout(
|
||||
api,
|
||||
{
|
||||
chainingSystem: chainingSystem$,
|
||||
labelPosition: labelPosition$,
|
||||
autoApplySelections: autoApplySelections$,
|
||||
ignoreParentSettings: ignoreParentSettings$,
|
||||
},
|
||||
{ core: services.core }
|
||||
);
|
||||
openEditControlGroupFlyout(api, {
|
||||
chainingSystem: chainingSystem$,
|
||||
labelPosition: labelPosition$,
|
||||
autoApplySelections: autoApplySelections$,
|
||||
ignoreParentSettings: ignoreParentSettings$,
|
||||
});
|
||||
},
|
||||
isEditingEnabled: () => true,
|
||||
openAddDataControlFlyout: (settings) => {
|
||||
|
@ -193,7 +184,6 @@ export const getControlGroupEmbeddableFactory = (services: {
|
|||
settings?.onSave?.();
|
||||
},
|
||||
controlGroupApi: api,
|
||||
services,
|
||||
});
|
||||
},
|
||||
serializeState: () => {
|
||||
|
@ -201,7 +191,7 @@ export const getControlGroupEmbeddableFactory = (services: {
|
|||
return {
|
||||
rawState: {
|
||||
chainingSystem: chainingSystem$.getValue(),
|
||||
controlStyle: labelPosition$.getValue(), // Rename "labelPosition" to "controlStyle"
|
||||
controlStyle: labelPosition$.getValue(),
|
||||
showApplySelections: !autoApplySelections$.getValue(),
|
||||
ignoreParentSettingsJSON: JSON.stringify(ignoreParentSettings$.getValue()),
|
||||
panelsJSON,
|
||||
|
@ -265,10 +255,9 @@ export const getControlGroupEmbeddableFactory = (services: {
|
|||
/** Fetch the allowExpensiveQuries setting for the children to use if necessary */
|
||||
const fetchAllowExpensiveQueries = async () => {
|
||||
try {
|
||||
const { allowExpensiveQueries } = await services.core.http.get<{
|
||||
const { allowExpensiveQueries } = await coreServices.http.get<{
|
||||
allowExpensiveQueries: boolean;
|
||||
// TODO: Rename this route as part of https://github.com/elastic/kibana/issues/174961
|
||||
}>('/internal/controls/optionsList/getExpensiveQueriesSetting', {
|
||||
}>('/internal/controls/getExpensiveQueriesSetting', {
|
||||
version: '1',
|
||||
});
|
||||
if (!allowExpensiveQueries) {
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
*/
|
||||
|
||||
import { OverlayRef } from '@kbn/core-mount-utils-browser';
|
||||
import { CoreStart } from '@kbn/core/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { tracksOverlays } from '@kbn/presentation-containers';
|
||||
import { apiHasParentApi } from '@kbn/presentation-publishing';
|
||||
|
@ -19,13 +18,11 @@ import { BehaviorSubject } from 'rxjs';
|
|||
import { ControlStateManager } from '../controls/types';
|
||||
import { ControlGroupEditor } from './components/control_group_editor';
|
||||
import { ControlGroupApi, ControlGroupEditorState } from './types';
|
||||
import { coreServices } from '../../services/kibana_services';
|
||||
|
||||
export const openEditControlGroupFlyout = (
|
||||
controlGroupApi: ControlGroupApi,
|
||||
stateManager: ControlStateManager<ControlGroupEditorState>,
|
||||
services: {
|
||||
core: CoreStart;
|
||||
}
|
||||
stateManager: ControlStateManager<ControlGroupEditorState>
|
||||
) => {
|
||||
/**
|
||||
* Duplicate all state into a new manager because we do not want to actually apply the changes
|
||||
|
@ -50,7 +47,7 @@ export const openEditControlGroupFlyout = (
|
|||
};
|
||||
|
||||
const onDeleteAll = (ref: OverlayRef) => {
|
||||
services.core.overlays
|
||||
coreServices.overlays
|
||||
.openConfirm(
|
||||
i18n.translate('controls.controlGroup.management.delete.sub', {
|
||||
defaultMessage: 'Controls are not recoverable once removed.',
|
||||
|
@ -77,7 +74,7 @@ export const openEditControlGroupFlyout = (
|
|||
});
|
||||
};
|
||||
|
||||
const overlay = services.core.overlays.openFlyout(
|
||||
const overlay = coreServices.overlays.openFlyout(
|
||||
toMountPoint(
|
||||
<ControlGroupEditor
|
||||
api={controlGroupApi}
|
||||
|
@ -96,8 +93,8 @@ export const openEditControlGroupFlyout = (
|
|||
onCancel={() => closeOverlay(overlay)}
|
||||
/>,
|
||||
{
|
||||
theme: services.core.theme,
|
||||
i18n: services.core.i18n,
|
||||
theme: coreServices.theme,
|
||||
i18n: coreServices.i18n,
|
||||
}
|
||||
),
|
||||
{
|
||||
|
|
|
@ -7,23 +7,16 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { CoreSetup } from '@kbn/core/public';
|
||||
import type { EmbeddableSetup } from '@kbn/embeddable-plugin/public';
|
||||
import type { ControlsPluginStartDeps } from '../../types';
|
||||
import { CONTROL_GROUP_TYPE } from '../../../common';
|
||||
import { untilPluginStartServicesReady } from '../../services/kibana_services';
|
||||
|
||||
export function registerControlGroupEmbeddable(
|
||||
coreSetup: CoreSetup<ControlsPluginStartDeps>,
|
||||
embeddableSetup: EmbeddableSetup
|
||||
) {
|
||||
export function registerControlGroupEmbeddable(embeddableSetup: EmbeddableSetup) {
|
||||
embeddableSetup.registerReactEmbeddableFactory(CONTROL_GROUP_TYPE, async () => {
|
||||
const [{ getControlGroupEmbeddableFactory }, [coreStart, depsStart]] = await Promise.all([
|
||||
const [{ getControlGroupEmbeddableFactory }] = await Promise.all([
|
||||
import('./get_control_group_factory'),
|
||||
coreSetup.getStartServices(),
|
||||
untilPluginStartServicesReady(),
|
||||
]);
|
||||
return getControlGroupEmbeddableFactory({
|
||||
core: coreStart,
|
||||
dataViews: depsStart.data.dataViews,
|
||||
});
|
||||
return getControlGroupEmbeddableFactory();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import {
|
|||
import {
|
||||
HasEditCapabilities,
|
||||
HasParentApi,
|
||||
PublishesDataLoading,
|
||||
PublishesDisabledActionIds,
|
||||
PublishesFilters,
|
||||
PublishesTimeslice,
|
||||
|
@ -35,8 +34,8 @@ import {
|
|||
ControlGroupEditorConfig,
|
||||
ControlGroupRuntimeState,
|
||||
ControlGroupSerializedState,
|
||||
ControlLabelPosition,
|
||||
ControlPanelState,
|
||||
ControlStyle,
|
||||
DefaultControlState,
|
||||
ParentIgnoreSettings,
|
||||
} from '../../../common';
|
||||
|
@ -54,7 +53,6 @@ export type ControlGroupApi = PresentationContainer &
|
|||
PublishesDataViews &
|
||||
HasSerializedChildState<ControlPanelState> &
|
||||
HasEditCapabilities &
|
||||
PublishesDataLoading &
|
||||
Pick<PublishesUnsavedChanges<ControlGroupRuntimeState>, 'unsavedChanges'> &
|
||||
PublishesTimeslice &
|
||||
PublishesDisabledActionIds &
|
||||
|
@ -62,7 +60,7 @@ export type ControlGroupApi = PresentationContainer &
|
|||
allowExpensiveQueries$: PublishingSubject<boolean>;
|
||||
autoApplySelections$: PublishingSubject<boolean>;
|
||||
ignoreParentSettings$: PublishingSubject<ParentIgnoreSettings | undefined>;
|
||||
labelPosition: PublishingSubject<ControlStyle>;
|
||||
labelPosition: PublishingSubject<ControlLabelPosition>;
|
||||
|
||||
asyncResetUnsavedChanges: () => Promise<void>;
|
||||
controlFetch$: (controlUuid: string) => Observable<ControlFetchContext>;
|
||||
|
|
|
@ -13,11 +13,12 @@ import {
|
|||
OPTIONS_LIST_CONTROL,
|
||||
RANGE_SLIDER_CONTROL,
|
||||
TIME_SLIDER_CONTROL,
|
||||
type ControlGroupRuntimeState,
|
||||
type ControlPanelsState,
|
||||
type DefaultDataControlState,
|
||||
} from '../../../../common';
|
||||
import { type ControlGroupRuntimeState, type ControlPanelsState } from '../../../../common';
|
||||
import type { OptionsListControlState } from '../../../../common/options_list';
|
||||
import { pluginServices } from '../../../services';
|
||||
import { dataViewsService } from '../../../services/kibana_services';
|
||||
import { getDataControlFieldRegistry } from '../../controls/data_controls/data_control_editor_utils';
|
||||
import type { RangesliderControlState } from '../../controls/data_controls/range_slider/types';
|
||||
|
||||
|
@ -82,7 +83,7 @@ export const controlGroupStateBuilder = {
|
|||
};
|
||||
|
||||
async function getCompatibleControlType(dataViewId: string, fieldName: string) {
|
||||
const dataView = await pluginServices.getServices().dataViews.get(dataViewId);
|
||||
const dataView = await dataViewsService.get(dataViewId);
|
||||
const fieldRegistry = await getDataControlFieldRegistry(dataView);
|
||||
const field = fieldRegistry[fieldName];
|
||||
if (field.compatibleControlTypes.length === 0) {
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { type ControlGroupRuntimeState, DEFAULT_CONTROL_STYLE } from '../../../../common';
|
||||
import { DEFAULT_CONTROL_LABEL_POSITION, type ControlGroupRuntimeState } from '../../../../common';
|
||||
|
||||
export const getDefaultControlGroupRuntimeState = (): ControlGroupRuntimeState => ({
|
||||
initialChildControlState: {},
|
||||
labelPosition: DEFAULT_CONTROL_STYLE,
|
||||
labelPosition: DEFAULT_CONTROL_LABEL_POSITION,
|
||||
chainingSystem: 'HIERARCHICAL',
|
||||
autoApplySelections: true,
|
||||
ignoreParentSettings: {
|
||||
|
|
|
@ -12,7 +12,6 @@ import { BehaviorSubject } from 'rxjs';
|
|||
|
||||
import { createStubDataView } from '@kbn/data-views-plugin/common/data_view.stub';
|
||||
import { stubFieldSpecMap } from '@kbn/data-views-plugin/common/field.stub';
|
||||
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
|
||||
import { TimeRange } from '@kbn/es-query';
|
||||
import { I18nProvider } from '@kbn/i18n-react';
|
||||
import { act, fireEvent, render, RenderResult, waitFor } from '@testing-library/react';
|
||||
|
@ -22,6 +21,7 @@ import {
|
|||
DEFAULT_CONTROL_WIDTH,
|
||||
type DefaultDataControlState,
|
||||
} from '../../../../common';
|
||||
import { dataViewsService } from '../../../services/kibana_services';
|
||||
import { getAllControlTypes, getControlFactory } from '../../control_factory_registry';
|
||||
import type { ControlGroupApi } from '../../control_group/types';
|
||||
import type { ControlFactory } from '../types';
|
||||
|
@ -39,7 +39,6 @@ jest.mock('../../control_factory_registry', () => ({
|
|||
getControlFactory: jest.fn(),
|
||||
}));
|
||||
|
||||
const mockDataViews = dataViewPluginMocks.createStartContract();
|
||||
const mockDataView = createStubDataView({
|
||||
spec: {
|
||||
id: 'logstash-*',
|
||||
|
@ -58,7 +57,6 @@ const mockDataView = createStubDataView({
|
|||
timeFieldName: '@timestamp',
|
||||
},
|
||||
});
|
||||
mockDataViews.get = jest.fn().mockResolvedValue(mockDataView);
|
||||
|
||||
const dashboardApi = {
|
||||
timeRange$: new BehaviorSubject<TimeRange | undefined>(undefined),
|
||||
|
@ -82,7 +80,7 @@ describe('Data control editor', () => {
|
|||
controlType?: string;
|
||||
initialDefaultPanelTitle?: string;
|
||||
}) => {
|
||||
mockDataViews.get = jest.fn().mockResolvedValue(mockDataView);
|
||||
dataViewsService.get = jest.fn().mockResolvedValue(mockDataView);
|
||||
|
||||
const controlEditor = render(
|
||||
<I18nProvider>
|
||||
|
@ -97,13 +95,12 @@ describe('Data control editor', () => {
|
|||
controlId={controlId}
|
||||
controlType={controlType}
|
||||
initialDefaultPanelTitle={initialDefaultPanelTitle}
|
||||
services={{ dataViews: mockDataViews }}
|
||||
/>
|
||||
</I18nProvider>
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockDataViews.get).toHaveBeenCalledTimes(1);
|
||||
expect(dataViewsService.get).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
return controlEditor;
|
||||
|
|
|
@ -33,7 +33,6 @@ import {
|
|||
EuiToolTip,
|
||||
} from '@elastic/eui';
|
||||
import { DataViewField } from '@kbn/data-views-plugin/common';
|
||||
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import {
|
||||
LazyDataViewPicker,
|
||||
LazyFieldPicker,
|
||||
|
@ -46,6 +45,7 @@ import {
|
|||
type ControlWidth,
|
||||
type DefaultDataControlState,
|
||||
} from '../../../../common';
|
||||
import { dataViewsService } from '../../../services/kibana_services';
|
||||
import { getAllControlTypes, getControlFactory } from '../../control_factory_registry';
|
||||
import type { ControlGroupApi } from '../../control_group/types';
|
||||
import { DataControlEditorStrings } from './data_control_constants';
|
||||
|
@ -67,9 +67,6 @@ export interface ControlEditorProps<
|
|||
controlGroupApi: ControlGroupApi; // controls must always have a parent API
|
||||
onCancel: (newState: Partial<State>) => void;
|
||||
onSave: (newState: Partial<State>, type: string) => void;
|
||||
services: {
|
||||
dataViews: DataViewsPublicPluginStart;
|
||||
};
|
||||
}
|
||||
|
||||
const FieldPicker = withSuspense(LazyFieldPicker, null);
|
||||
|
@ -151,8 +148,6 @@ export const DataControlEditor = <State extends DefaultDataControlState = Defaul
|
|||
onSave,
|
||||
onCancel,
|
||||
controlGroupApi,
|
||||
/** TODO: These should not be props */
|
||||
services: { dataViews: dataViewService },
|
||||
}: ControlEditorProps<State>) => {
|
||||
const [editorState, setEditorState] = useState<Partial<State>>(initialState);
|
||||
const [defaultPanelTitle, setDefaultPanelTitle] = useState<string>(
|
||||
|
@ -163,16 +158,14 @@ export const DataControlEditor = <State extends DefaultDataControlState = Defaul
|
|||
const [controlOptionsValid, setControlOptionsValid] = useState<boolean>(true);
|
||||
const editorConfig = useMemo(() => controlGroupApi.getEditorConfig(), [controlGroupApi]);
|
||||
|
||||
// TODO: Maybe remove `useAsync` - see https://github.com/elastic/kibana/pull/182842#discussion_r1624909709
|
||||
const {
|
||||
loading: dataViewListLoading,
|
||||
value: dataViewListItems = [],
|
||||
error: dataViewListError,
|
||||
} = useAsync(async () => {
|
||||
return dataViewService.getIdsWithTitle();
|
||||
return dataViewsService.getIdsWithTitle();
|
||||
});
|
||||
|
||||
// TODO: Maybe remove `useAsync` - see https://github.com/elastic/kibana/pull/182842#discussion_r1624909709
|
||||
const {
|
||||
loading: dataViewLoading,
|
||||
value: { selectedDataView, fieldRegistry } = {
|
||||
|
@ -185,7 +178,7 @@ export const DataControlEditor = <State extends DefaultDataControlState = Defaul
|
|||
return;
|
||||
}
|
||||
|
||||
const dataView = await dataViewService.get(editorState.dataViewId);
|
||||
const dataView = await dataViewsService.get(editorState.dataViewId);
|
||||
const registry = await getDataControlFieldRegistry(dataView);
|
||||
return {
|
||||
selectedDataView: dataView,
|
||||
|
|
|
@ -13,7 +13,6 @@ import type { DataView } from '@kbn/data-views-plugin/common';
|
|||
import { getAllControlTypes, getControlFactory } from '../../control_factory_registry';
|
||||
import { isDataControlFactory, type DataControlFieldRegistry } from './types';
|
||||
|
||||
/** TODO: This funciton is duplicated from the controls plugin to avoid exporting it */
|
||||
export const getDataControlFieldRegistry = memoize(
|
||||
async (dataView: DataView) => {
|
||||
return await loadFieldRegistryFromDataView(dataView);
|
||||
|
@ -21,7 +20,6 @@ export const getDataControlFieldRegistry = memoize(
|
|||
(dataView: DataView) => [dataView.id, JSON.stringify(dataView.fields.getAll())].join('|')
|
||||
);
|
||||
|
||||
/** TODO: This function is duplicated from the controls plugin to avoid exporting it */
|
||||
const loadFieldRegistryFromDataView = async (
|
||||
dataView: DataView
|
||||
): Promise<DataControlFieldRegistry> => {
|
||||
|
|
|
@ -7,10 +7,9 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
|
||||
import type { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { first, skip } from 'rxjs';
|
||||
import { dataViewsService } from '../../../services/kibana_services';
|
||||
import { ControlGroupApi } from '../../control_group/types';
|
||||
import { initializeDataControl } from './initialize_data_control';
|
||||
|
||||
|
@ -21,9 +20,8 @@ describe('initializeDataControl', () => {
|
|||
};
|
||||
const editorStateManager = {};
|
||||
const controlGroupApi = {} as unknown as ControlGroupApi;
|
||||
const mockDataViews = dataViewPluginMocks.createStartContract();
|
||||
// @ts-ignore
|
||||
mockDataViews.get = async (id: string): Promise<DataView> => {
|
||||
|
||||
dataViewsService.get = async (id: string): Promise<DataView> => {
|
||||
if (id !== 'myDataViewId') {
|
||||
throw new Error(`Simulated error: no data view found for id ${id}`);
|
||||
}
|
||||
|
@ -40,10 +38,6 @@ describe('initializeDataControl', () => {
|
|||
},
|
||||
} as unknown as DataView;
|
||||
};
|
||||
const services = {
|
||||
core: coreMock.createStart(),
|
||||
dataViews: mockDataViews,
|
||||
};
|
||||
|
||||
describe('dataViewId subscription', () => {
|
||||
describe('no blocking errors', () => {
|
||||
|
@ -55,8 +49,7 @@ describe('initializeDataControl', () => {
|
|||
'referenceNameSuffix',
|
||||
dataControlState,
|
||||
editorStateManager,
|
||||
controlGroupApi,
|
||||
services
|
||||
controlGroupApi
|
||||
);
|
||||
|
||||
dataControl.api.defaultPanelTitle!.pipe(skip(1), first()).subscribe(() => {
|
||||
|
@ -90,8 +83,7 @@ describe('initializeDataControl', () => {
|
|||
dataViewId: 'notGonnaFindMeDataViewId',
|
||||
},
|
||||
editorStateManager,
|
||||
controlGroupApi,
|
||||
services
|
||||
controlGroupApi
|
||||
);
|
||||
|
||||
dataControl.api.dataViews.pipe(skip(1), first()).subscribe(() => {
|
||||
|
@ -129,8 +121,7 @@ describe('initializeDataControl', () => {
|
|||
fieldName: 'notGonnaFindMeFieldName',
|
||||
},
|
||||
editorStateManager,
|
||||
controlGroupApi,
|
||||
services
|
||||
controlGroupApi
|
||||
);
|
||||
|
||||
dataControl.api.defaultPanelTitle!.pipe(skip(1), first()).subscribe(() => {
|
||||
|
|
|
@ -10,19 +10,18 @@
|
|||
import { isEqual } from 'lodash';
|
||||
import { BehaviorSubject, combineLatest, debounceTime, first, skip, switchMap, tap } from 'rxjs';
|
||||
|
||||
import { CoreStart } from '@kbn/core-lifecycle-browser';
|
||||
import {
|
||||
DATA_VIEW_SAVED_OBJECT_TYPE,
|
||||
DataView,
|
||||
DataViewField,
|
||||
} from '@kbn/data-views-plugin/common';
|
||||
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { SerializedPanelState } from '@kbn/presentation-containers';
|
||||
import { StateComparators } from '@kbn/presentation-publishing';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { DefaultControlState, DefaultDataControlState } from '../../../../common';
|
||||
import { dataViewsService } from '../../../services/kibana_services';
|
||||
import type { ControlGroupApi } from '../../control_group/types';
|
||||
import { initializeDefaultControlApi } from '../initialize_default_control_api';
|
||||
import type { ControlApiInitialization, ControlStateManager } from '../types';
|
||||
|
@ -40,11 +39,7 @@ export const initializeDataControl = <EditorState extends object = {}>(
|
|||
* responsible for managing
|
||||
*/
|
||||
editorStateManager: ControlStateManager<EditorState>,
|
||||
controlGroupApi: ControlGroupApi,
|
||||
services: {
|
||||
core: CoreStart;
|
||||
dataViews: DataViewsPublicPluginStart;
|
||||
}
|
||||
controlGroupApi: ControlGroupApi
|
||||
): {
|
||||
api: ControlApiInitialization<DataControlApi>;
|
||||
cleanup: () => void;
|
||||
|
@ -88,7 +83,7 @@ export const initializeDataControl = <EditorState extends object = {}>(
|
|||
switchMap(async (currentDataViewId) => {
|
||||
let dataView: DataView | undefined;
|
||||
try {
|
||||
dataView = await services.dataViews.get(currentDataViewId);
|
||||
dataView = await dataViewsService.get(currentDataViewId);
|
||||
return { dataView };
|
||||
} catch (error) {
|
||||
return { error };
|
||||
|
@ -156,7 +151,6 @@ export const initializeDataControl = <EditorState extends object = {}>(
|
|||
|
||||
// open the editor to get the new state
|
||||
openDataControlEditor<DefaultDataControlState & EditorState>({
|
||||
services,
|
||||
onSave: ({ type: newType, state: newState }) => {
|
||||
if (newType === controlType) {
|
||||
// apply the changes from the new state via the state manager
|
||||
|
|
|
@ -10,14 +10,14 @@
|
|||
import React from 'react';
|
||||
import deepEqual from 'react-fast-compare';
|
||||
|
||||
import { CoreStart, OverlayRef } from '@kbn/core/public';
|
||||
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import { OverlayRef } from '@kbn/core/public';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { tracksOverlays } from '@kbn/presentation-containers';
|
||||
import { apiHasParentApi } from '@kbn/presentation-publishing';
|
||||
import { toMountPoint } from '@kbn/react-kibana-mount';
|
||||
|
||||
import type { DefaultDataControlState } from '../../../../common';
|
||||
import { coreServices } from '../../../services/kibana_services';
|
||||
import type { ControlGroupApi } from '../../control_group/types';
|
||||
import { DataControlEditor } from './data_control_editor';
|
||||
|
||||
|
@ -30,7 +30,6 @@ export const openDataControlEditor = <
|
|||
initialDefaultPanelTitle,
|
||||
onSave,
|
||||
controlGroupApi,
|
||||
services,
|
||||
}: {
|
||||
initialState: Partial<State>;
|
||||
controlType?: string;
|
||||
|
@ -38,10 +37,6 @@ export const openDataControlEditor = <
|
|||
initialDefaultPanelTitle?: string;
|
||||
onSave: ({ type, state }: { type: string; state: Partial<State> }) => void;
|
||||
controlGroupApi: ControlGroupApi;
|
||||
services: {
|
||||
core: CoreStart;
|
||||
dataViews: DataViewsPublicPluginStart;
|
||||
};
|
||||
}): void => {
|
||||
const closeOverlay = (overlayRef: OverlayRef) => {
|
||||
if (apiHasParentApi(controlGroupApi) && tracksOverlays(controlGroupApi.parentApi)) {
|
||||
|
@ -55,7 +50,7 @@ export const openDataControlEditor = <
|
|||
closeOverlay(overlay);
|
||||
return;
|
||||
}
|
||||
services.core.overlays
|
||||
coreServices.overlays
|
||||
.openConfirm(
|
||||
i18n.translate('controls.controlGroup.management.discard.sub', {
|
||||
defaultMessage: `Changes that you've made to this control will be discarded, are you sure you want to continue?`,
|
||||
|
@ -80,7 +75,7 @@ export const openDataControlEditor = <
|
|||
});
|
||||
};
|
||||
|
||||
const overlay = services.core.overlays.openFlyout(
|
||||
const overlay = coreServices.overlays.openFlyout(
|
||||
toMountPoint(
|
||||
<DataControlEditor<State>
|
||||
controlGroupApi={controlGroupApi}
|
||||
|
@ -95,11 +90,10 @@ export const openDataControlEditor = <
|
|||
closeOverlay(overlay);
|
||||
onSave({ type: selectedControlType, state });
|
||||
}}
|
||||
services={{ dataViews: services.dataViews }}
|
||||
/>,
|
||||
{
|
||||
theme: services.core.theme,
|
||||
i18n: services.core.i18n,
|
||||
theme: coreServices.theme,
|
||||
i18n: coreServices.i18n,
|
||||
}
|
||||
),
|
||||
{
|
||||
|
|
|
@ -26,13 +26,11 @@ import { isValidSearch } from '../../../../../common/options_list/is_valid_searc
|
|||
import { OptionsListSelection } from '../../../../../common/options_list/options_list_selections';
|
||||
import { ControlFetchContext } from '../../../control_group/control_fetch';
|
||||
import { ControlStateManager } from '../../types';
|
||||
import { DataControlServices } from '../types';
|
||||
import { OptionsListFetchCache } from './options_list_fetch_cache';
|
||||
import { OptionsListComponentApi, OptionsListComponentState, OptionsListControlApi } from './types';
|
||||
|
||||
export function fetchAndValidate$({
|
||||
api,
|
||||
services,
|
||||
stateManager,
|
||||
}: {
|
||||
api: Pick<OptionsListControlApi, 'dataViews' | 'field$' | 'setBlockingError' | 'parentApi'> &
|
||||
|
@ -41,7 +39,6 @@ export function fetchAndValidate$({
|
|||
loadingSuggestions$: BehaviorSubject<boolean>;
|
||||
debouncedSearchString: Observable<string>;
|
||||
};
|
||||
services: DataControlServices;
|
||||
stateManager: ControlStateManager<
|
||||
Pick<OptionsListComponentState, 'requestSize' | 'runPastTimeout' | 'searchTechnique' | 'sort'>
|
||||
> & {
|
||||
|
@ -126,7 +123,7 @@ export function fetchAndValidate$({
|
|||
const newAbortController = new AbortController();
|
||||
abortController = newAbortController;
|
||||
try {
|
||||
return await requestCache.runFetchRequest(request, newAbortController.signal, services);
|
||||
return await requestCache.runFetchRequest(request, newAbortController.signal);
|
||||
} catch (error) {
|
||||
return { error };
|
||||
}
|
||||
|
|
|
@ -9,26 +9,22 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
import { DataView } from '@kbn/data-views-plugin/common';
|
||||
import { createStubDataView } from '@kbn/data-views-plugin/common/data_view.stub';
|
||||
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
|
||||
import { act, render, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { coreServices, dataViewsService } from '../../../../services/kibana_services';
|
||||
import { getMockedBuildApi, getMockedControlGroupApi } from '../../mocks/control_mocks';
|
||||
import { getOptionsListControlFactory } from './get_options_list_control_factory';
|
||||
|
||||
describe('Options List Control Api', () => {
|
||||
const uuid = 'myControl1';
|
||||
const controlGroupApi = getMockedControlGroupApi();
|
||||
const mockDataViews = dataViewPluginMocks.createStartContract();
|
||||
const mockCore = coreMock.createStart();
|
||||
|
||||
const waitOneTick = () => act(() => new Promise((resolve) => setTimeout(resolve, 0)));
|
||||
|
||||
mockDataViews.get = jest.fn().mockImplementation(async (id: string): Promise<DataView> => {
|
||||
dataViewsService.get = jest.fn().mockImplementation(async (id: string): Promise<DataView> => {
|
||||
if (id !== 'myDataViewId') {
|
||||
throw new Error(`Simulated error: no data view found for id ${id}`);
|
||||
}
|
||||
|
@ -60,11 +56,7 @@ describe('Options List Control Api', () => {
|
|||
return stubDataView;
|
||||
});
|
||||
|
||||
const factory = getOptionsListControlFactory({
|
||||
core: mockCore,
|
||||
data: dataPluginMock.createStartContract(),
|
||||
dataViews: mockDataViews,
|
||||
});
|
||||
const factory = getOptionsListControlFactory();
|
||||
|
||||
describe('filters$', () => {
|
||||
test('should not set filters$ when selectedOptions is not provided', async () => {
|
||||
|
@ -177,7 +169,7 @@ describe('Options List Control Api', () => {
|
|||
|
||||
describe('make selection', () => {
|
||||
beforeAll(() => {
|
||||
mockCore.http.fetch = jest.fn().mockResolvedValue({
|
||||
coreServices.http.fetch = jest.fn().mockResolvedValue({
|
||||
suggestions: [
|
||||
{ value: 'woof', docCount: 10 },
|
||||
{ value: 'bark', docCount: 15 },
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
import fastIsEqual from 'fast-deep-equal';
|
||||
import React, { useEffect } from 'react';
|
||||
import { BehaviorSubject, combineLatest, debounceTime, filter, skip } from 'rxjs';
|
||||
import { BehaviorSubject, combineLatest, debounceTime, filter, map, skip } from 'rxjs';
|
||||
|
||||
import { buildExistsFilter, buildPhraseFilter, buildPhrasesFilter, Filter } from '@kbn/es-query';
|
||||
import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
|
||||
|
@ -25,7 +25,7 @@ import type {
|
|||
} from '../../../../../common/options_list';
|
||||
import { getSelectionAsFieldType, isValidSearch } from '../../../../../common/options_list';
|
||||
import { initializeDataControl } from '../initialize_data_control';
|
||||
import type { DataControlFactory, DataControlServices } from '../types';
|
||||
import type { DataControlFactory } from '../types';
|
||||
import { OptionsListControl } from './components/options_list_control';
|
||||
import { OptionsListEditorOptions } from './components/options_list_editor_options';
|
||||
import {
|
||||
|
@ -39,9 +39,10 @@ import { initializeOptionsListSelections } from './options_list_control_selectio
|
|||
import { OptionsListStrings } from './options_list_strings';
|
||||
import type { OptionsListControlApi } from './types';
|
||||
|
||||
export const getOptionsListControlFactory = (
|
||||
services: DataControlServices
|
||||
): DataControlFactory<OptionsListControlState, OptionsListControlApi> => {
|
||||
export const getOptionsListControlFactory = (): DataControlFactory<
|
||||
OptionsListControlState,
|
||||
OptionsListControlApi
|
||||
> => {
|
||||
return {
|
||||
type: OPTIONS_LIST_CONTROL,
|
||||
order: 3, // should always be first, since this is the most popular control
|
||||
|
@ -78,6 +79,7 @@ export const getOptionsListControlFactory = (
|
|||
const searchStringValid$ = new BehaviorSubject<boolean>(true);
|
||||
const requestSize$ = new BehaviorSubject<number>(MIN_OPTIONS_LIST_REQUEST_SIZE);
|
||||
|
||||
const dataLoading$ = new BehaviorSubject<boolean | undefined>(undefined);
|
||||
const availableOptions$ = new BehaviorSubject<OptionsListSuggestions | undefined>(undefined);
|
||||
const invalidSelections$ = new BehaviorSubject<Set<OptionsListSelection>>(new Set());
|
||||
const totalCardinality$ = new BehaviorSubject<number>(0);
|
||||
|
@ -90,8 +92,7 @@ export const getOptionsListControlFactory = (
|
|||
'optionsListDataView',
|
||||
initialState,
|
||||
{ searchTechnique: searchTechnique$, singleSelect: singleSelect$ },
|
||||
controlGroupApi,
|
||||
services
|
||||
controlGroupApi
|
||||
);
|
||||
|
||||
const selections = initializeOptionsListSelections(
|
||||
|
@ -115,12 +116,16 @@ export const getOptionsListControlFactory = (
|
|||
|
||||
/** Handle loading state; since suggestion fetching and validation are tied, only need one loading subject */
|
||||
const loadingSuggestions$ = new BehaviorSubject<boolean>(false);
|
||||
const dataLoadingSubscription = loadingSuggestions$
|
||||
const dataLoadingSubscription = combineLatest([
|
||||
loadingSuggestions$,
|
||||
dataControl.api.dataLoading,
|
||||
])
|
||||
.pipe(
|
||||
debounceTime(100) // debounce set loading so that it doesn't flash as the user types
|
||||
debounceTime(100), // debounce set loading so that it doesn't flash as the user types
|
||||
map((values) => values.some((value) => value))
|
||||
)
|
||||
.subscribe((isLoading) => {
|
||||
dataControl.api.setDataLoading(isLoading);
|
||||
dataLoading$.next(isLoading);
|
||||
});
|
||||
|
||||
/** Debounce the search string changes to reduce the number of fetch requests */
|
||||
|
@ -161,7 +166,6 @@ export const getOptionsListControlFactory = (
|
|||
/** Fetch the suggestions and perform validation */
|
||||
const loadMoreSubject = new BehaviorSubject<null>(null);
|
||||
const fetchSubscription = fetchAndValidate$({
|
||||
services,
|
||||
api: {
|
||||
...dataControl.api,
|
||||
loadMoreSubject,
|
||||
|
@ -235,6 +239,7 @@ export const getOptionsListControlFactory = (
|
|||
const api = buildApi(
|
||||
{
|
||||
...dataControl.api,
|
||||
dataLoading: dataLoading$,
|
||||
getTypeDisplayName: OptionsListStrings.control.getDisplayName,
|
||||
serializeState: () => {
|
||||
const { rawState: dataControlState, references } = dataControl.serialize();
|
||||
|
|
|
@ -20,7 +20,7 @@ import type {
|
|||
OptionsListResponse,
|
||||
OptionsListSuccessResponse,
|
||||
} from '../../../../../common/options_list/types';
|
||||
import type { DataControlServices } from '../types';
|
||||
import { coreServices, dataService } from '../../../../services/kibana_services';
|
||||
|
||||
const REQUEST_CACHE_SIZE = 50; // only store a max of 50 responses
|
||||
const REQUEST_CACHE_TTL = 1000 * 60; // time to live = 1 minute
|
||||
|
@ -80,8 +80,7 @@ export class OptionsListFetchCache {
|
|||
|
||||
public async runFetchRequest(
|
||||
request: OptionsListRequest,
|
||||
abortSignal: AbortSignal,
|
||||
services: DataControlServices
|
||||
abortSignal: AbortSignal
|
||||
): Promise<OptionsListResponse> {
|
||||
const requestHash = this.getRequestHash(request);
|
||||
|
||||
|
@ -90,11 +89,11 @@ export class OptionsListFetchCache {
|
|||
} else {
|
||||
const index = request.dataView.getIndexPattern();
|
||||
|
||||
const timeService = services.data.query.timefilter.timefilter;
|
||||
const timeService = dataService.query.timefilter.timefilter;
|
||||
const { query, filters, dataView, timeRange, field, ...passThroughProps } = request;
|
||||
const timeFilter = timeRange ? timeService.createFilter(dataView, timeRange) : undefined;
|
||||
const filtersToUse = [...(filters ?? []), ...(timeFilter ? [timeFilter] : [])];
|
||||
const config = getEsQueryConfig(services.core.uiSettings);
|
||||
const config = getEsQueryConfig(coreServices.uiSettings);
|
||||
const esFilters = [buildEsQuery(dataView, query ?? [], filtersToUse ?? [], config)];
|
||||
|
||||
const requestBody = {
|
||||
|
@ -105,7 +104,7 @@ export class OptionsListFetchCache {
|
|||
runtimeFieldMap: dataView.toSpec?.().runtimeFieldMap,
|
||||
};
|
||||
|
||||
const result = await services.core.http.fetch<OptionsListResponse>(
|
||||
const result = await coreServices.http.fetch<OptionsListResponse>(
|
||||
`/internal/controls/optionsList/${index}`,
|
||||
{
|
||||
version: '1',
|
||||
|
|
|
@ -7,21 +7,16 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { CoreSetup } from '@kbn/core/public';
|
||||
import type { ControlsPluginStartDeps } from '../../../../types';
|
||||
import { registerControlFactory } from '../../../control_factory_registry';
|
||||
import { OPTIONS_LIST_CONTROL } from '../../../../../common';
|
||||
import { untilPluginStartServicesReady } from '../../../../services/kibana_services';
|
||||
import { registerControlFactory } from '../../../control_factory_registry';
|
||||
|
||||
export function registerOptionsListControl(coreSetup: CoreSetup<ControlsPluginStartDeps>) {
|
||||
export function registerOptionsListControl() {
|
||||
registerControlFactory(OPTIONS_LIST_CONTROL, async () => {
|
||||
const [{ getOptionsListControlFactory }, [coreStart, depsStart]] = await Promise.all([
|
||||
const [{ getOptionsListControlFactory }] = await Promise.all([
|
||||
import('./get_options_list_control_factory'),
|
||||
coreSetup.getStartServices(),
|
||||
untilPluginStartServicesReady(),
|
||||
]);
|
||||
return getOptionsListControlFactory({
|
||||
core: coreStart,
|
||||
data: depsStart.data,
|
||||
dataViews: depsStart.data.dataViews,
|
||||
});
|
||||
return getOptionsListControlFactory();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,13 +11,11 @@ import React from 'react';
|
|||
import { of } from 'rxjs';
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
import { DataViewField } from '@kbn/data-views-plugin/common';
|
||||
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
|
||||
import { SerializedPanelState } from '@kbn/presentation-containers';
|
||||
import { fireEvent, render, waitFor } from '@testing-library/react';
|
||||
|
||||
import { dataService, dataViewsService } from '../../../../services/kibana_services';
|
||||
import { getMockedBuildApi, getMockedControlGroupApi } from '../../mocks/control_mocks';
|
||||
import { getRangesliderControlFactory } from './get_range_slider_control_factory';
|
||||
import { RangesliderControlState } from './types';
|
||||
|
@ -31,11 +29,10 @@ describe('RangesliderControlApi', () => {
|
|||
|
||||
const controlGroupApi = getMockedControlGroupApi();
|
||||
|
||||
const dataStartServiceMock = dataPluginMock.createStartContract();
|
||||
let totalResults = DEFAULT_TOTAL_RESULTS;
|
||||
let min: estypes.AggregationsSingleMetricAggregateBase['value'] = DEFAULT_MIN;
|
||||
let max: estypes.AggregationsSingleMetricAggregateBase['value'] = DEFAULT_MAX;
|
||||
dataStartServiceMock.search.searchSource.create = jest.fn().mockImplementation(() => {
|
||||
dataService.search.searchSource.create = jest.fn().mockImplementation(() => {
|
||||
let isAggsRequest = false;
|
||||
return {
|
||||
setField: (key: string) => {
|
||||
|
@ -54,9 +51,8 @@ describe('RangesliderControlApi', () => {
|
|||
},
|
||||
};
|
||||
});
|
||||
const mockDataViews = dataViewPluginMocks.createStartContract();
|
||||
|
||||
mockDataViews.get = jest.fn().mockImplementation(async (id: string): Promise<DataView> => {
|
||||
dataViewsService.get = jest.fn().mockImplementation(async (id: string): Promise<DataView> => {
|
||||
if (id !== 'myDataViewId') {
|
||||
throw new Error(`no data view found for id ${id}`);
|
||||
}
|
||||
|
@ -82,11 +78,7 @@ describe('RangesliderControlApi', () => {
|
|||
} as unknown as DataView;
|
||||
});
|
||||
|
||||
const factory = getRangesliderControlFactory({
|
||||
core: coreMock.createStart(),
|
||||
data: dataStartServiceMock,
|
||||
dataViews: mockDataViews,
|
||||
});
|
||||
const factory = getRangesliderControlFactory();
|
||||
|
||||
beforeEach(() => {
|
||||
totalResults = DEFAULT_TOTAL_RESULTS;
|
||||
|
|
|
@ -16,7 +16,7 @@ import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing';
|
|||
|
||||
import { RANGE_SLIDER_CONTROL } from '../../../../../common';
|
||||
import { initializeDataControl } from '../initialize_data_control';
|
||||
import type { DataControlFactory, DataControlServices } from '../types';
|
||||
import type { DataControlFactory } from '../types';
|
||||
import { RangeSliderControl } from './components/range_slider_control';
|
||||
import { hasNoResults$ } from './has_no_results';
|
||||
import { minMax$ } from './min_max';
|
||||
|
@ -24,9 +24,10 @@ import { initializeRangeControlSelections } from './range_control_selections';
|
|||
import { RangeSliderStrings } from './range_slider_strings';
|
||||
import type { RangesliderControlApi, RangesliderControlState } from './types';
|
||||
|
||||
export const getRangesliderControlFactory = (
|
||||
services: DataControlServices
|
||||
): DataControlFactory<RangesliderControlState, RangesliderControlApi> => {
|
||||
export const getRangesliderControlFactory = (): DataControlFactory<
|
||||
RangesliderControlState,
|
||||
RangesliderControlApi
|
||||
> => {
|
||||
return {
|
||||
type: RANGE_SLIDER_CONTROL,
|
||||
getIconType: () => 'controlsHorizontal',
|
||||
|
@ -71,8 +72,7 @@ export const getRangesliderControlFactory = (
|
|||
{
|
||||
step: step$,
|
||||
},
|
||||
controlGroupApi,
|
||||
services
|
||||
controlGroupApi
|
||||
);
|
||||
|
||||
const selections = initializeRangeControlSelections(
|
||||
|
@ -111,13 +111,14 @@ export const getRangesliderControlFactory = (
|
|||
}
|
||||
);
|
||||
|
||||
const dataLoadingSubscription = combineLatest([loadingMinMax$, loadingHasNoResults$])
|
||||
const dataLoadingSubscription = combineLatest([
|
||||
loadingMinMax$,
|
||||
loadingHasNoResults$,
|
||||
dataControl.api.dataLoading,
|
||||
])
|
||||
.pipe(
|
||||
map((values) => {
|
||||
return values.some((value) => {
|
||||
return value;
|
||||
});
|
||||
})
|
||||
debounceTime(100),
|
||||
map((values) => values.some((value) => value))
|
||||
)
|
||||
.subscribe((isLoading) => {
|
||||
dataLoading$.next(isLoading);
|
||||
|
@ -138,7 +139,6 @@ export const getRangesliderControlFactory = (
|
|||
const min$ = new BehaviorSubject<number | undefined>(undefined);
|
||||
const minMaxSubscription = minMax$({
|
||||
controlFetch$,
|
||||
data: services.data,
|
||||
dataViews$: dataControl.api.dataViews,
|
||||
fieldName$: dataControl.stateManager.fieldName,
|
||||
setIsLoading: (isLoading: boolean) => {
|
||||
|
@ -198,7 +198,6 @@ export const getRangesliderControlFactory = (
|
|||
const selectionHasNoResults$ = new BehaviorSubject(false);
|
||||
const hasNotResultsSubscription = hasNoResults$({
|
||||
controlFetch$,
|
||||
data: services.data,
|
||||
dataViews$: dataControl.api.dataViews,
|
||||
rangeFilters$: dataControl.api.filters$,
|
||||
ignoreParentSettings$: controlGroupApi.ignoreParentSettings$,
|
||||
|
|
|
@ -8,25 +8,23 @@
|
|||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import { DataView } from '@kbn/data-views-plugin/public';
|
||||
import { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query';
|
||||
import { PublishesDataViews } from '@kbn/presentation-publishing';
|
||||
import { combineLatest, lastValueFrom, Observable, switchMap, tap } from 'rxjs';
|
||||
import { Observable, combineLatest, lastValueFrom, switchMap, tap } from 'rxjs';
|
||||
import { dataService } from '../../../../services/kibana_services';
|
||||
import { ControlFetchContext } from '../../../control_group/control_fetch';
|
||||
import { ControlGroupApi } from '../../../control_group/types';
|
||||
import { DataControlApi } from '../types';
|
||||
|
||||
export function hasNoResults$({
|
||||
controlFetch$,
|
||||
data,
|
||||
dataViews$,
|
||||
rangeFilters$,
|
||||
ignoreParentSettings$,
|
||||
setIsLoading,
|
||||
}: {
|
||||
controlFetch$: Observable<ControlFetchContext>;
|
||||
data: DataPublicPluginStart;
|
||||
dataViews$?: PublishesDataViews['dataViews'];
|
||||
rangeFilters$: DataControlApi['filters$'];
|
||||
ignoreParentSettings$: ControlGroupApi['ignoreParentSettings$'];
|
||||
|
@ -53,7 +51,6 @@ export function hasNoResults$({
|
|||
prevRequestAbortController = abortController;
|
||||
return await hasNoResults({
|
||||
abortSignal: abortController.signal,
|
||||
data,
|
||||
dataView,
|
||||
rangeFilter,
|
||||
...controlFetchContext,
|
||||
|
@ -71,7 +68,6 @@ export function hasNoResults$({
|
|||
|
||||
async function hasNoResults({
|
||||
abortSignal,
|
||||
data,
|
||||
dataView,
|
||||
filters,
|
||||
query,
|
||||
|
@ -79,14 +75,13 @@ async function hasNoResults({
|
|||
timeRange,
|
||||
}: {
|
||||
abortSignal: AbortSignal;
|
||||
data: DataPublicPluginStart;
|
||||
dataView: DataView;
|
||||
filters?: Filter[];
|
||||
query?: Query | AggregateQuery;
|
||||
rangeFilter: Filter;
|
||||
timeRange?: TimeRange;
|
||||
}): Promise<boolean> {
|
||||
const searchSource = await data.search.searchSource.create();
|
||||
const searchSource = await dataService.search.searchSource.create();
|
||||
searchSource.setField('size', 0);
|
||||
searchSource.setField('index', dataView);
|
||||
// Tracking total hits accurately has a performance cost
|
||||
|
@ -97,7 +92,7 @@ async function hasNoResults({
|
|||
const allFilters = filters ? [...filters] : [];
|
||||
allFilters.push(rangeFilter);
|
||||
if (timeRange) {
|
||||
const timeFilter = data.query.timefilter.timefilter.createFilter(dataView, timeRange);
|
||||
const timeFilter = dataService.query.timefilter.timefilter.createFilter(dataView, timeRange);
|
||||
if (timeFilter) allFilters.push(timeFilter);
|
||||
}
|
||||
if (allFilters.length) {
|
||||
|
|
|
@ -8,26 +8,24 @@
|
|||
*/
|
||||
|
||||
import { estypes } from '@elastic/elasticsearch';
|
||||
import { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import { DataView, DataViewField } from '@kbn/data-views-plugin/public';
|
||||
import { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query';
|
||||
import { PublishesDataViews, PublishingSubject } from '@kbn/presentation-publishing';
|
||||
import { combineLatest, lastValueFrom, Observable, of, startWith, switchMap, tap } from 'rxjs';
|
||||
import { apiPublishesReload } from '@kbn/presentation-publishing/interfaces/fetch/publishes_reload';
|
||||
import { Observable, combineLatest, lastValueFrom, of, startWith, switchMap, tap } from 'rxjs';
|
||||
import { dataService } from '../../../../services/kibana_services';
|
||||
import { ControlFetchContext } from '../../../control_group/control_fetch';
|
||||
import { ControlGroupApi } from '../../../control_group/types';
|
||||
|
||||
export function minMax$({
|
||||
controlFetch$,
|
||||
controlGroupApi,
|
||||
data,
|
||||
dataViews$,
|
||||
fieldName$,
|
||||
setIsLoading,
|
||||
}: {
|
||||
controlFetch$: Observable<ControlFetchContext>;
|
||||
controlGroupApi: ControlGroupApi;
|
||||
data: DataPublicPluginStart;
|
||||
dataViews$: PublishesDataViews['dataViews'];
|
||||
fieldName$: PublishingSubject<string>;
|
||||
setIsLoading: (isLoading: boolean) => void;
|
||||
|
@ -60,7 +58,6 @@ export function minMax$({
|
|||
prevRequestAbortController = abortController;
|
||||
return await getMinMax({
|
||||
abortSignal: abortController.signal,
|
||||
data,
|
||||
dataView,
|
||||
field: dataViewField,
|
||||
...controlFetchContext,
|
||||
|
@ -77,7 +74,6 @@ export function minMax$({
|
|||
|
||||
export async function getMinMax({
|
||||
abortSignal,
|
||||
data,
|
||||
dataView,
|
||||
field,
|
||||
filters,
|
||||
|
@ -85,20 +81,19 @@ export async function getMinMax({
|
|||
timeRange,
|
||||
}: {
|
||||
abortSignal: AbortSignal;
|
||||
data: DataPublicPluginStart;
|
||||
dataView: DataView;
|
||||
field: DataViewField;
|
||||
filters?: Filter[];
|
||||
query?: Query | AggregateQuery;
|
||||
timeRange?: TimeRange;
|
||||
}): Promise<{ min: number | undefined; max: number | undefined }> {
|
||||
const searchSource = await data.search.searchSource.create();
|
||||
const searchSource = await dataService.search.searchSource.create();
|
||||
searchSource.setField('size', 0);
|
||||
searchSource.setField('index', dataView);
|
||||
|
||||
const allFilters = filters ? [...filters] : [];
|
||||
if (timeRange) {
|
||||
const timeFilter = data.query.timefilter.timefilter.createFilter(dataView, timeRange);
|
||||
const timeFilter = dataService.query.timefilter.timefilter.createFilter(dataView, timeRange);
|
||||
if (timeFilter) allFilters.push(timeFilter);
|
||||
}
|
||||
if (allFilters.length) {
|
||||
|
|
|
@ -7,22 +7,17 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { CoreSetup } from '@kbn/core/public';
|
||||
import type { ControlsPluginStartDeps } from '../../../../types';
|
||||
import { registerControlFactory } from '../../../control_factory_registry';
|
||||
import { RANGE_SLIDER_CONTROL } from '../../../../../common';
|
||||
import { untilPluginStartServicesReady } from '../../../../services/kibana_services';
|
||||
import { registerControlFactory } from '../../../control_factory_registry';
|
||||
|
||||
export function registerRangeSliderControl(coreSetup: CoreSetup<ControlsPluginStartDeps>) {
|
||||
export function registerRangeSliderControl() {
|
||||
registerControlFactory(RANGE_SLIDER_CONTROL, async () => {
|
||||
const [{ getRangesliderControlFactory }, [coreStart, depsStart]] = await Promise.all([
|
||||
const [{ getRangesliderControlFactory }] = await Promise.all([
|
||||
import('./get_range_slider_control_factory'),
|
||||
coreSetup.getStartServices(),
|
||||
untilPluginStartServicesReady(),
|
||||
]);
|
||||
|
||||
return getRangesliderControlFactory({
|
||||
core: coreStart,
|
||||
data: depsStart.data,
|
||||
dataViews: depsStart.data.dataViews,
|
||||
});
|
||||
return getRangesliderControlFactory();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,10 +7,7 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { CoreStart } from '@kbn/core/public';
|
||||
import { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import { DataViewField } from '@kbn/data-views-plugin/common';
|
||||
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import { FieldFormatConvertFunction } from '@kbn/field-formats-plugin/common';
|
||||
import {
|
||||
HasEditCapabilities,
|
||||
|
@ -62,12 +59,6 @@ export const isDataControlFactory = (
|
|||
return typeof (factory as DataControlFactory).isFieldCompatible === 'function';
|
||||
};
|
||||
|
||||
export interface DataControlServices {
|
||||
core: CoreStart;
|
||||
data: DataPublicPluginStart;
|
||||
dataViews: DataViewsPublicPluginStart;
|
||||
}
|
||||
|
||||
interface DataControlField {
|
||||
field: DataViewField;
|
||||
compatibleControlTypes: string[];
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
import { EuiRangeTick } from '@elastic/eui';
|
||||
import { TimeRange } from '@kbn/es-query';
|
||||
import { coreServices, dataService } from '../../../services/kibana_services';
|
||||
import {
|
||||
FROM_INDEX,
|
||||
getStepSize,
|
||||
|
@ -17,7 +18,6 @@ import {
|
|||
roundUpToNextStepSizeFactor,
|
||||
TO_INDEX,
|
||||
} from './time_utils';
|
||||
import { Services } from './types';
|
||||
|
||||
export interface TimeRangeMeta {
|
||||
format: string;
|
||||
|
@ -29,12 +29,9 @@ export interface TimeRangeMeta {
|
|||
timeRangeMin: number;
|
||||
}
|
||||
|
||||
export function getTimeRangeMeta(
|
||||
timeRange: TimeRange | undefined,
|
||||
services: Services
|
||||
): TimeRangeMeta {
|
||||
const nextBounds = timeRangeToBounds(timeRange ?? getDefaultTimeRange(services), services);
|
||||
const ticks = getTicks(nextBounds[FROM_INDEX], nextBounds[TO_INDEX], getTimezone(services));
|
||||
export function getTimeRangeMeta(timeRange: TimeRange | undefined): TimeRangeMeta {
|
||||
const nextBounds = timeRangeToBounds(timeRange ?? getDefaultTimeRange());
|
||||
const ticks = getTicks(nextBounds[FROM_INDEX], nextBounds[TO_INDEX], getTimezone());
|
||||
const { format, stepSize } = getStepSize(ticks);
|
||||
return {
|
||||
format,
|
||||
|
@ -47,17 +44,17 @@ export function getTimeRangeMeta(
|
|||
};
|
||||
}
|
||||
|
||||
export function getTimezone(services: Services) {
|
||||
return services.core.uiSettings.get('dateFormat:tz', 'Browser');
|
||||
export function getTimezone() {
|
||||
return coreServices.uiSettings.get('dateFormat:tz', 'Browser');
|
||||
}
|
||||
|
||||
function getDefaultTimeRange(services: Services) {
|
||||
const defaultTimeRange = services.core.uiSettings.get('timepicker:timeDefaults');
|
||||
function getDefaultTimeRange() {
|
||||
const defaultTimeRange = coreServices.uiSettings.get('timepicker:timeDefaults');
|
||||
return defaultTimeRange ? defaultTimeRange : { from: 'now-15m', to: 'now' };
|
||||
}
|
||||
|
||||
function timeRangeToBounds(timeRange: TimeRange, services: Services): [number, number] {
|
||||
const timeRangeBounds = services.data.query.timefilter.timefilter.calculateBounds(timeRange);
|
||||
function timeRangeToBounds(timeRange: TimeRange): [number, number] {
|
||||
const timeRangeBounds = dataService.query.timefilter.timefilter.calculateBounds(timeRange);
|
||||
return timeRangeBounds.min === undefined || timeRangeBounds.max === undefined
|
||||
? [Date.now() - 1000 * 60 * 15, Date.now()]
|
||||
: [timeRangeBounds.min.valueOf(), timeRangeBounds.max.valueOf()];
|
||||
|
|
|
@ -7,14 +7,15 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
import React from 'react';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import dateMath from '@kbn/datemath';
|
||||
import { TimeRange } from '@kbn/es-query';
|
||||
import { StateComparators } from '@kbn/presentation-publishing';
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { dataService } from '../../../services/kibana_services';
|
||||
import { getMockedControlGroupApi } from '../mocks/control_mocks';
|
||||
import { ControlApiRegistration } from '../types';
|
||||
import { getTimesliderControlFactory } from './get_timeslider_control_factory';
|
||||
|
@ -28,18 +29,14 @@ describe('TimesliderControlApi', () => {
|
|||
};
|
||||
const controlGroupApi = getMockedControlGroupApi(dashboardApi);
|
||||
|
||||
const dataStartServiceMock = dataPluginMock.createStartContract();
|
||||
dataStartServiceMock.query.timefilter.timefilter.calculateBounds = (timeRange: TimeRange) => {
|
||||
dataService.query.timefilter.timefilter.calculateBounds = (timeRange: TimeRange) => {
|
||||
const now = new Date();
|
||||
return {
|
||||
min: dateMath.parse(timeRange.from, { forceNow: now }),
|
||||
max: dateMath.parse(timeRange.to, { roundUp: true, forceNow: now }),
|
||||
};
|
||||
};
|
||||
const factory = getTimesliderControlFactory({
|
||||
core: coreMock.createStart(),
|
||||
data: dataStartServiceMock,
|
||||
});
|
||||
const factory = getTimesliderControlFactory();
|
||||
let comparators: StateComparators<TimesliderControlState> | undefined;
|
||||
function buildApiMock(
|
||||
api: ControlApiRegistration<TimesliderControlApi>,
|
||||
|
|
|
@ -36,22 +36,23 @@ import {
|
|||
roundDownToNextStepSizeFactor,
|
||||
roundUpToNextStepSizeFactor,
|
||||
} from './time_utils';
|
||||
import { Services, Timeslice, TimesliderControlApi, TimesliderControlState } from './types';
|
||||
import { Timeslice, TimesliderControlApi, TimesliderControlState } from './types';
|
||||
|
||||
const displayName = i18n.translate('controls.timesliderControl.displayName', {
|
||||
defaultMessage: 'Time slider',
|
||||
});
|
||||
|
||||
export const getTimesliderControlFactory = (
|
||||
services: Services
|
||||
): ControlFactory<TimesliderControlState, TimesliderControlApi> => {
|
||||
export const getTimesliderControlFactory = (): ControlFactory<
|
||||
TimesliderControlState,
|
||||
TimesliderControlApi
|
||||
> => {
|
||||
return {
|
||||
type: TIME_SLIDER_CONTROL,
|
||||
getIconType: () => 'search',
|
||||
getDisplayName: () => displayName,
|
||||
buildControl: async (initialState, buildApi, uuid, controlGroupApi) => {
|
||||
const { timeRangeMeta$, formatDate, cleanupTimeRangeSubscription } =
|
||||
initTimeRangeSubscription(controlGroupApi, services);
|
||||
initTimeRangeSubscription(controlGroupApi);
|
||||
const timeslice$ = new BehaviorSubject<[number, number] | undefined>(undefined);
|
||||
const isAnchored$ = new BehaviorSubject<boolean | undefined>(initialState.isAnchored);
|
||||
const isPopoverOpen$ = new BehaviorSubject(false);
|
||||
|
|
|
@ -14,26 +14,23 @@ import moment from 'moment';
|
|||
import { BehaviorSubject, skip } from 'rxjs';
|
||||
import { getTimeRangeMeta, getTimezone, TimeRangeMeta } from './get_time_range_meta';
|
||||
import { getMomentTimezone } from './time_utils';
|
||||
import { Services } from './types';
|
||||
|
||||
export function initTimeRangeSubscription(controlGroupApi: unknown, services: Services) {
|
||||
export function initTimeRangeSubscription(controlGroupApi: unknown) {
|
||||
const timeRange$ =
|
||||
apiHasParentApi(controlGroupApi) && apiPublishesTimeRange(controlGroupApi.parentApi)
|
||||
? controlGroupApi.parentApi.timeRange$
|
||||
: new BehaviorSubject<TimeRange | undefined>(undefined);
|
||||
const timeRangeMeta$ = new BehaviorSubject<TimeRangeMeta>(
|
||||
getTimeRangeMeta(timeRange$.value, services)
|
||||
);
|
||||
const timeRangeMeta$ = new BehaviorSubject<TimeRangeMeta>(getTimeRangeMeta(timeRange$.value));
|
||||
|
||||
const timeRangeSubscription = timeRange$.pipe(skip(1)).subscribe((timeRange) => {
|
||||
timeRangeMeta$.next(getTimeRangeMeta(timeRange, services));
|
||||
timeRangeMeta$.next(getTimeRangeMeta(timeRange));
|
||||
});
|
||||
|
||||
return {
|
||||
timeRangeMeta$,
|
||||
formatDate: (epoch: number) => {
|
||||
return moment
|
||||
.tz(epoch, getMomentTimezone(getTimezone(services)))
|
||||
.tz(epoch, getMomentTimezone(getTimezone()))
|
||||
.locale(i18n.getLocale())
|
||||
.format(timeRangeMeta$.value.format);
|
||||
},
|
||||
|
|
|
@ -7,20 +7,16 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { CoreSetup } from '@kbn/core/public';
|
||||
import type { ControlsPluginStartDeps } from '../../../types';
|
||||
import { registerControlFactory } from '../../control_factory_registry';
|
||||
import { TIME_SLIDER_CONTROL } from '../../../../common';
|
||||
import { untilPluginStartServicesReady } from '../../../services/kibana_services';
|
||||
import { registerControlFactory } from '../../control_factory_registry';
|
||||
|
||||
export function registerTimeSliderControl(coreSetup: CoreSetup<ControlsPluginStartDeps>) {
|
||||
export function registerTimeSliderControl() {
|
||||
registerControlFactory(TIME_SLIDER_CONTROL, async () => {
|
||||
const [{ getTimesliderControlFactory }, [coreStart, depsStart]] = await Promise.all([
|
||||
const [{ getTimesliderControlFactory }] = await Promise.all([
|
||||
import('./get_timeslider_control_factory'),
|
||||
coreSetup.getStartServices(),
|
||||
untilPluginStartServicesReady(),
|
||||
]);
|
||||
return getTimesliderControlFactory({
|
||||
core: coreStart,
|
||||
data: depsStart.data,
|
||||
});
|
||||
return getTimesliderControlFactory();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { CoreStart } from '@kbn/core/public';
|
||||
import { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import type { PublishesPanelTitle, PublishesTimeslice } from '@kbn/presentation-publishing';
|
||||
import type { DefaultControlState } from '../../../../common';
|
||||
import type { DefaultControlApi } from '../types';
|
||||
|
@ -25,8 +23,3 @@ export interface TimesliderControlState extends DefaultControlState {
|
|||
export type TimesliderControlApi = DefaultControlApi &
|
||||
Pick<PublishesPanelTitle, 'defaultPanelTitle'> &
|
||||
PublishesTimeslice;
|
||||
|
||||
export interface Services {
|
||||
core: CoreStart;
|
||||
data: DataPublicPluginStart;
|
||||
}
|
||||
|
|
|
@ -40,15 +40,15 @@ export type DefaultControlApi = PublishesDataLoading &
|
|||
HasType &
|
||||
HasUniqueId &
|
||||
HasParentApi<ControlGroupApi> & {
|
||||
// Can not use HasSerializableState interface
|
||||
// HasSerializableState types serializeState as function returning 'MaybePromise'
|
||||
// Controls serializeState is sync
|
||||
serializeState: () => SerializedPanelState<DefaultControlState>;
|
||||
/** 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>;
|
||||
|
||||
// Can not use HasSerializableState interface
|
||||
// HasSerializableState types serializeState as function returning 'MaybePromise'
|
||||
// Controls serializeState is sync
|
||||
serializeState: () => SerializedPanelState<DefaultControlState>;
|
||||
};
|
||||
|
||||
export type ControlApiRegistration<ControlApi extends DefaultControlApi = DefaultControlApi> = Omit<
|
||||
|
@ -62,7 +62,6 @@ export type ControlApiInitialization<ControlApi extends DefaultControlApi = Defa
|
|||
'serializeState' | 'getTypeDisplayName' | 'clearSelections'
|
||||
>;
|
||||
|
||||
// TODO: Move this to the Control plugin's setup contract
|
||||
export interface ControlFactory<
|
||||
State extends DefaultControlState = DefaultControlState,
|
||||
ControlApi extends DefaultControlApi = DefaultControlApi
|
||||
|
|
|
@ -9,26 +9,22 @@
|
|||
|
||||
import React from 'react';
|
||||
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
|
||||
import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { PublishesUnifiedSearch, PublishingSubject } from '@kbn/presentation-publishing';
|
||||
import { act, render, waitFor } from '@testing-library/react';
|
||||
|
||||
import { ControlGroupRendererApi } from '.';
|
||||
import { CONTROL_GROUP_TYPE } from '../..';
|
||||
import { getControlGroupEmbeddableFactory } from '../control_group/get_control_group_factory';
|
||||
import { ControlGroupRenderer, ControlGroupRendererProps } from './control_group_renderer';
|
||||
import { CONTROL_GROUP_TYPE } from '../..';
|
||||
|
||||
type ParentApiType = PublishesUnifiedSearch & {
|
||||
unifiedSearchFilters$?: PublishingSubject<Filter[] | undefined>;
|
||||
};
|
||||
|
||||
describe('control group renderer', () => {
|
||||
const core = coreMock.createStart();
|
||||
const dataViews = dataViewPluginMocks.createStartContract();
|
||||
const factory = getControlGroupEmbeddableFactory({ core, dataViews });
|
||||
const factory = getControlGroupEmbeddableFactory();
|
||||
const buildControlGroupSpy = jest.spyOn(factory, 'buildEmbeddable');
|
||||
|
||||
const mountControlGroupRenderer = async (
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlFactory, DefaultControlApi } from '../../react_controls/controls/types';
|
||||
import { ControlsServiceType } from './types';
|
||||
|
||||
export type ControlsServiceFactory = PluginServiceFactory<ControlsServiceType>;
|
||||
export const controlsServiceFactory = () => getStubControlsService();
|
||||
|
||||
export const getStubControlsService = () => {
|
||||
const controlsFactoriesMap: { [key: string]: ControlFactory<any, any> } = {};
|
||||
|
||||
const mockRegisterControlFactory = async <
|
||||
State extends object = object,
|
||||
ApiType extends DefaultControlApi = DefaultControlApi
|
||||
>(
|
||||
controlType: string,
|
||||
getFactory: () => Promise<ControlFactory<State, ApiType>>
|
||||
) => {
|
||||
controlsFactoriesMap[controlType] = (await getFactory()) as ControlFactory<any, any>;
|
||||
};
|
||||
|
||||
const mockGetControlFactory = <
|
||||
State extends object = object,
|
||||
ApiType extends DefaultControlApi = DefaultControlApi
|
||||
>(
|
||||
type: string
|
||||
) => {
|
||||
return controlsFactoriesMap[type] as ControlFactory<State, ApiType>;
|
||||
};
|
||||
|
||||
const getAllControlTypes = () => Object.keys(controlsFactoriesMap);
|
||||
|
||||
return {
|
||||
registerControlFactory: mockRegisterControlFactory,
|
||||
getControlFactory: mockGetControlFactory,
|
||||
getAllControlTypes,
|
||||
};
|
||||
};
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import {
|
||||
getAllControlTypes,
|
||||
getControlFactory,
|
||||
registerControlFactory,
|
||||
} from '../../react_controls/control_factory_registry';
|
||||
import { ControlsServiceType } from './types';
|
||||
|
||||
export const controlsServiceFactory = () => controlsService;
|
||||
|
||||
// export controls service directly for use in plugin setup lifecycle
|
||||
export const controlsService: ControlsServiceType = {
|
||||
registerControlFactory,
|
||||
getControlFactory,
|
||||
getAllControlTypes,
|
||||
};
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import {
|
||||
getAllControlTypes,
|
||||
getControlFactory,
|
||||
registerControlFactory,
|
||||
} from '../../react_controls/control_factory_registry';
|
||||
|
||||
export type ControlsServiceFactory = PluginServiceFactory<ControlsServiceType>;
|
||||
|
||||
export interface ControlsServiceType {
|
||||
registerControlFactory: typeof registerControlFactory;
|
||||
getControlFactory: typeof getControlFactory;
|
||||
getAllControlTypes: typeof getAllControlTypes;
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { analyticsServiceMock, coreMock, themeServiceMock } from '@kbn/core/public/mocks';
|
||||
import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlsCoreService } from './types';
|
||||
|
||||
export type CoreServiceFactory = PluginServiceFactory<ControlsCoreService>;
|
||||
|
||||
export const coreServiceFactory: CoreServiceFactory = () => {
|
||||
const corePluginMock = coreMock.createStart();
|
||||
return {
|
||||
analytics: analyticsServiceMock.createAnalyticsServiceStart(),
|
||||
theme: themeServiceMock.createSetupContract(),
|
||||
i18n: corePluginMock.i18n,
|
||||
notifications: corePluginMock.notifications,
|
||||
};
|
||||
};
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlsCoreService } from './types';
|
||||
import { ControlsPluginStartDeps } from '../../types';
|
||||
|
||||
export type CoreServiceFactory = KibanaPluginServiceFactory<
|
||||
ControlsCoreService,
|
||||
ControlsPluginStartDeps
|
||||
>;
|
||||
|
||||
export const coreServiceFactory: CoreServiceFactory = ({ coreStart }) => {
|
||||
const { analytics, theme, i18n, notifications } = coreStart;
|
||||
|
||||
return {
|
||||
analytics,
|
||||
theme,
|
||||
i18n,
|
||||
notifications,
|
||||
};
|
||||
};
|
|
@ -1,17 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { CoreStart } from '@kbn/core/public';
|
||||
|
||||
export interface ControlsCoreService {
|
||||
analytics: CoreStart['analytics'];
|
||||
i18n: CoreStart['i18n'];
|
||||
theme: CoreStart['theme'];
|
||||
notifications: CoreStart['notifications'];
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { of } from 'rxjs';
|
||||
import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import { ControlsDataService } from './types';
|
||||
|
||||
export type DataServiceFactory = PluginServiceFactory<ControlsDataService>;
|
||||
export const dataServiceFactory: DataServiceFactory = () => ({
|
||||
query: {} as unknown as DataPublicPluginStart['query'],
|
||||
searchSource: {
|
||||
create: () => ({
|
||||
setField: () => {},
|
||||
fetch$: () =>
|
||||
of({
|
||||
rawResponse: { aggregations: { minAgg: { value: 0 }, maxAgg: { value: 1000 } } },
|
||||
}),
|
||||
}),
|
||||
} as unknown as DataPublicPluginStart['search']['searchSource'],
|
||||
timefilter: {
|
||||
createFilter: () => {},
|
||||
} as unknown as DataPublicPluginStart['query']['timefilter']['timefilter'],
|
||||
fetchFieldRange: () => Promise.resolve({ min: 0, max: 100 }),
|
||||
});
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlsPluginStartDeps } from '../../types';
|
||||
import { ControlsDataService } from './types';
|
||||
|
||||
export type DataServiceFactory = KibanaPluginServiceFactory<
|
||||
ControlsDataService,
|
||||
ControlsPluginStartDeps
|
||||
>;
|
||||
|
||||
export const dataServiceFactory: DataServiceFactory = ({ startPlugins }) => {
|
||||
const {
|
||||
data: { query: queryPlugin, search },
|
||||
} = startPlugins;
|
||||
|
||||
return {
|
||||
query: queryPlugin,
|
||||
searchSource: search.searchSource,
|
||||
timefilter: queryPlugin.timefilter.timefilter,
|
||||
};
|
||||
};
|
|
@ -1,15 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
export interface ControlsDataService {
|
||||
query: DataPublicPluginStart['query'];
|
||||
searchSource: DataPublicPluginStart['search']['searchSource'];
|
||||
timefilter: DataPublicPluginStart['query']['timefilter']['timefilter'];
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import { DataView } from '@kbn/data-views-plugin/common';
|
||||
import { ControlsDataViewsService } from './types';
|
||||
|
||||
export type DataViewsServiceFactory = PluginServiceFactory<ControlsDataViewsService>;
|
||||
|
||||
let currentDataView: DataView | undefined;
|
||||
export const injectStorybookDataView = (dataView?: DataView) => (currentDataView = dataView);
|
||||
|
||||
export const dataViewsServiceFactory: DataViewsServiceFactory = () => ({
|
||||
get: ((dataViewId) =>
|
||||
new Promise((resolve, reject) =>
|
||||
setTimeout(() => {
|
||||
if (!currentDataView) {
|
||||
reject(
|
||||
new Error(
|
||||
'mock DataViews service currentDataView is undefined, call injectStorybookDataView to set'
|
||||
)
|
||||
);
|
||||
} else if (currentDataView.id === dataViewId) {
|
||||
resolve(currentDataView);
|
||||
} else {
|
||||
reject(
|
||||
new Error(
|
||||
`mock DataViews service currentDataView.id: ${currentDataView.id} does not match requested dataViewId: ${dataViewId}`
|
||||
)
|
||||
);
|
||||
}
|
||||
}, 100)
|
||||
) as unknown) as DataViewsPublicPluginStart['get'],
|
||||
getIdsWithTitle: (() =>
|
||||
new Promise((resolve) =>
|
||||
setTimeout(() => {
|
||||
const idsWithTitle: Array<{ id: string | undefined; title: string }> = [];
|
||||
if (currentDataView) {
|
||||
idsWithTitle.push({ id: currentDataView.id, title: currentDataView.title });
|
||||
}
|
||||
resolve(idsWithTitle);
|
||||
}, 100)
|
||||
) as unknown) as DataViewsPublicPluginStart['getIdsWithTitle'],
|
||||
getDefaultId: () => Promise.resolve(currentDataView?.id ?? null),
|
||||
});
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlsPluginStartDeps } from '../../types';
|
||||
import { ControlsDataViewsService } from './types';
|
||||
|
||||
export type DataViewsServiceFactory = KibanaPluginServiceFactory<
|
||||
ControlsDataViewsService,
|
||||
ControlsPluginStartDeps
|
||||
>;
|
||||
|
||||
export const dataViewsServiceFactory: DataViewsServiceFactory = ({ startPlugins }) => {
|
||||
const {
|
||||
dataViews: { get, getIdsWithTitle, getDefaultId },
|
||||
} = startPlugins;
|
||||
|
||||
return {
|
||||
get,
|
||||
getDefaultId,
|
||||
getIdsWithTitle,
|
||||
};
|
||||
};
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
|
||||
export interface ControlsDataViewsService {
|
||||
get: DataViewsPublicPluginStart['get'];
|
||||
getDefaultId: DataViewsPublicPluginStart['getDefaultId'];
|
||||
getIdsWithTitle: DataViewsPublicPluginStart['getIdsWithTitle'];
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks';
|
||||
import { ControlsEmbeddableService } from './types';
|
||||
|
||||
export type EmbeddableServiceFactory = PluginServiceFactory<ControlsEmbeddableService>;
|
||||
export const embeddableServiceFactory: EmbeddableServiceFactory = () => {
|
||||
const { doStart } = embeddablePluginMock.createInstance();
|
||||
const start = doStart();
|
||||
return { getEmbeddableFactory: start.getEmbeddableFactory };
|
||||
};
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlsEmbeddableService } from './types';
|
||||
import { ControlsPluginStartDeps } from '../../types';
|
||||
|
||||
export type EmbeddableServiceFactory = KibanaPluginServiceFactory<
|
||||
ControlsEmbeddableService,
|
||||
ControlsPluginStartDeps
|
||||
>;
|
||||
|
||||
export const embeddableServiceFactory: EmbeddableServiceFactory = ({ startPlugins }) => {
|
||||
return {
|
||||
getEmbeddableFactory: startPlugins.embeddable.getEmbeddableFactory,
|
||||
};
|
||||
};
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { EmbeddableStart } from '@kbn/embeddable-plugin/public';
|
||||
|
||||
export interface ControlsEmbeddableService {
|
||||
getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory'];
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { HttpResponse } from '@kbn/core/public';
|
||||
import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlsHTTPService } from './types';
|
||||
|
||||
type HttpServiceFactory = PluginServiceFactory<ControlsHTTPService>;
|
||||
|
||||
export const httpServiceFactory: HttpServiceFactory = () => ({
|
||||
get: async () => ({} as unknown as HttpResponse),
|
||||
fetch: async () => ({} as unknown as HttpResponse),
|
||||
});
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlsHTTPService } from './types';
|
||||
import { ControlsPluginStartDeps } from '../../types';
|
||||
|
||||
export type HttpServiceFactory = KibanaPluginServiceFactory<
|
||||
ControlsHTTPService,
|
||||
ControlsPluginStartDeps
|
||||
>;
|
||||
export const httpServiceFactory: HttpServiceFactory = ({ coreStart }) => {
|
||||
const {
|
||||
http: { get, fetch },
|
||||
} = coreStart;
|
||||
|
||||
return {
|
||||
get,
|
||||
fetch,
|
||||
};
|
||||
};
|
|
@ -1,15 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { CoreSetup } from '@kbn/core/public';
|
||||
|
||||
export interface ControlsHTTPService {
|
||||
get: CoreSetup['http']['get'];
|
||||
fetch: CoreSetup['http']['fetch'];
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
export { pluginServices } from './plugin_services';
|
42
src/plugins/controls/public/services/kibana_services.ts
Normal file
42
src/plugins/controls/public/services/kibana_services.ts
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
import { CoreStart } from '@kbn/core/public';
|
||||
import { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
|
||||
import { ControlsPluginStartDeps } from '../types';
|
||||
|
||||
export let coreServices: CoreStart;
|
||||
export let dataService: DataPublicPluginStart;
|
||||
export let dataViewsService: DataViewsPublicPluginStart;
|
||||
|
||||
const servicesReady$ = new BehaviorSubject(false);
|
||||
|
||||
export const setKibanaServices = (kibanaCore: CoreStart, deps: ControlsPluginStartDeps) => {
|
||||
coreServices = kibanaCore;
|
||||
dataService = deps.data;
|
||||
dataViewsService = deps.dataViews;
|
||||
|
||||
servicesReady$.next(true);
|
||||
};
|
||||
|
||||
export const untilPluginStartServicesReady = () => {
|
||||
if (servicesReady$.value) return Promise.resolve();
|
||||
return new Promise<void>((resolve) => {
|
||||
const subscription = servicesReady$.subscribe((isInitialized) => {
|
||||
if (isInitialized) {
|
||||
subscription.unsubscribe();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
23
src/plugins/controls/public/services/mocks.ts
Normal file
23
src/plugins/controls/public/services/mocks.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import { dataPluginMock } from '@kbn/data-plugin/public/mocks';
|
||||
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
|
||||
import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks';
|
||||
|
||||
import { setKibanaServices } from './kibana_services';
|
||||
|
||||
export const setStubKibanaServices = () => {
|
||||
setKibanaServices(coreMock.createStart(), {
|
||||
data: dataPluginMock.createStartContract(),
|
||||
dataViews: dataViewPluginMocks.createStartContract(),
|
||||
uiActions: uiActionsPluginMock.createStartContract(),
|
||||
});
|
||||
};
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import {
|
||||
MountPoint,
|
||||
OverlayFlyoutOpenOptions,
|
||||
OverlayModalConfirmOptions,
|
||||
OverlayRef,
|
||||
} from '@kbn/core/public';
|
||||
import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlsOverlaysService } from './types';
|
||||
|
||||
type OverlaysServiceFactory = PluginServiceFactory<ControlsOverlaysService>;
|
||||
|
||||
class StubRef implements OverlayRef {
|
||||
public readonly onClose: Promise<void> = Promise.resolve();
|
||||
|
||||
public close(): Promise<void> {
|
||||
return this.onClose;
|
||||
}
|
||||
}
|
||||
|
||||
export const overlaysServiceFactory: OverlaysServiceFactory = () => ({
|
||||
openFlyout: (mount: MountPoint, options?: OverlayFlyoutOpenOptions) => new StubRef(),
|
||||
openConfirm: (message: MountPoint | string, options?: OverlayModalConfirmOptions) =>
|
||||
Promise.resolve(true),
|
||||
});
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlsPluginStartDeps } from '../../types';
|
||||
import { ControlsOverlaysService } from './types';
|
||||
|
||||
export type OverlaysServiceFactory = KibanaPluginServiceFactory<
|
||||
ControlsOverlaysService,
|
||||
ControlsPluginStartDeps
|
||||
>;
|
||||
export const overlaysServiceFactory: OverlaysServiceFactory = ({ coreStart }) => {
|
||||
const {
|
||||
overlays: { openFlyout, openConfirm },
|
||||
} = coreStart;
|
||||
|
||||
return {
|
||||
openFlyout,
|
||||
openConfirm,
|
||||
};
|
||||
};
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import {
|
||||
MountPoint,
|
||||
OverlayFlyoutOpenOptions,
|
||||
OverlayModalConfirmOptions,
|
||||
OverlayRef,
|
||||
} from '@kbn/core/public';
|
||||
|
||||
export interface ControlsOverlaysService {
|
||||
openFlyout(mount: MountPoint, options?: OverlayFlyoutOpenOptions): OverlayRef;
|
||||
openConfirm(message: MountPoint | string, options?: OverlayModalConfirmOptions): Promise<boolean>;
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import {
|
||||
PluginServiceProvider,
|
||||
PluginServiceProviders,
|
||||
PluginServiceRegistry,
|
||||
PluginServices,
|
||||
} from '@kbn/presentation-util-plugin/public';
|
||||
|
||||
import { ControlsPluginStart } from '../types';
|
||||
import { ControlsServices } from './types';
|
||||
|
||||
import { controlsServiceFactory } from './controls/controls.stub';
|
||||
import { coreServiceFactory } from './core/core.stub';
|
||||
import { dataServiceFactory } from './data/data.stub';
|
||||
import { dataViewsServiceFactory } from './data_views/data_views.stub';
|
||||
import { embeddableServiceFactory } from './embeddable/embeddable.stub';
|
||||
import { httpServiceFactory } from './http/http.stub';
|
||||
import { overlaysServiceFactory } from './overlays/overlays.stub';
|
||||
import { settingsServiceFactory } from './settings/settings.stub';
|
||||
import { unifiedSearchServiceFactory } from './unified_search/unified_search.stub';
|
||||
import { storageServiceFactory } from './storage/storage_service.stub';
|
||||
|
||||
export const providers: PluginServiceProviders<ControlsServices> = {
|
||||
embeddable: new PluginServiceProvider(embeddableServiceFactory),
|
||||
controls: new PluginServiceProvider(controlsServiceFactory),
|
||||
data: new PluginServiceProvider(dataServiceFactory),
|
||||
dataViews: new PluginServiceProvider(dataViewsServiceFactory),
|
||||
http: new PluginServiceProvider(httpServiceFactory),
|
||||
overlays: new PluginServiceProvider(overlaysServiceFactory),
|
||||
settings: new PluginServiceProvider(settingsServiceFactory),
|
||||
core: new PluginServiceProvider(coreServiceFactory),
|
||||
storage: new PluginServiceProvider(storageServiceFactory),
|
||||
unifiedSearch: new PluginServiceProvider(unifiedSearchServiceFactory),
|
||||
};
|
||||
|
||||
export const pluginServices = new PluginServices<ControlsServices>();
|
||||
|
||||
export const registry = new PluginServiceRegistry<ControlsServices>(providers);
|
||||
|
||||
export const getStubPluginServices = (): ControlsPluginStart => {
|
||||
pluginServices.setRegistry(registry.start({}));
|
||||
return {
|
||||
getControlFactory: pluginServices.getServices().controls.getControlFactory,
|
||||
getAllControlTypes: pluginServices.getServices().controls.getAllControlTypes,
|
||||
};
|
||||
};
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import {
|
||||
KibanaPluginServiceParams,
|
||||
PluginServiceProvider,
|
||||
PluginServiceProviders,
|
||||
PluginServiceRegistry,
|
||||
PluginServices,
|
||||
} from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlsPluginStartDeps } from '../types';
|
||||
import { ControlsServices } from './types';
|
||||
|
||||
import { controlsServiceFactory } from './controls/controls_service';
|
||||
import { coreServiceFactory } from './core/core_service';
|
||||
import { dataServiceFactory } from './data/data_service';
|
||||
import { dataViewsServiceFactory } from './data_views/data_views_service';
|
||||
import { embeddableServiceFactory } from './embeddable/embeddable_service';
|
||||
import { httpServiceFactory } from './http/http_service';
|
||||
import { overlaysServiceFactory } from './overlays/overlays_service';
|
||||
import { settingsServiceFactory } from './settings/settings_service';
|
||||
import { controlsStorageServiceFactory } from './storage/storage_service';
|
||||
import { unifiedSearchServiceFactory } from './unified_search/unified_search_service';
|
||||
|
||||
export const providers: PluginServiceProviders<
|
||||
ControlsServices,
|
||||
KibanaPluginServiceParams<ControlsPluginStartDeps>
|
||||
> = {
|
||||
controls: new PluginServiceProvider(controlsServiceFactory),
|
||||
data: new PluginServiceProvider(dataServiceFactory),
|
||||
dataViews: new PluginServiceProvider(dataViewsServiceFactory),
|
||||
embeddable: new PluginServiceProvider(embeddableServiceFactory),
|
||||
http: new PluginServiceProvider(httpServiceFactory),
|
||||
overlays: new PluginServiceProvider(overlaysServiceFactory),
|
||||
settings: new PluginServiceProvider(settingsServiceFactory),
|
||||
storage: new PluginServiceProvider(controlsStorageServiceFactory),
|
||||
core: new PluginServiceProvider(coreServiceFactory),
|
||||
unifiedSearch: new PluginServiceProvider(unifiedSearchServiceFactory),
|
||||
};
|
||||
|
||||
export const pluginServices = new PluginServices<ControlsServices>();
|
||||
|
||||
export const registry = new PluginServiceRegistry<
|
||||
ControlsServices,
|
||||
KibanaPluginServiceParams<ControlsPluginStartDeps>
|
||||
>(providers);
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlsSettingsService } from './types';
|
||||
|
||||
export type SettingsServiceFactory = PluginServiceFactory<ControlsSettingsService>;
|
||||
export const settingsServiceFactory: SettingsServiceFactory = () => ({
|
||||
getTimezone: () => 'Browser',
|
||||
getDateFormat: () => 'MMM D, YYYY @ HH:mm:ss.SSS',
|
||||
getDefaultTimeRange: () => ({ from: 'now-15m', to: 'now' }),
|
||||
});
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlsSettingsService } from './types';
|
||||
import { ControlsPluginStartDeps } from '../../types';
|
||||
|
||||
export type SettingsServiceFactory = KibanaPluginServiceFactory<
|
||||
ControlsSettingsService,
|
||||
ControlsPluginStartDeps
|
||||
>;
|
||||
|
||||
export const settingsServiceFactory: SettingsServiceFactory = ({ coreStart }) => {
|
||||
return {
|
||||
getDateFormat: () => {
|
||||
return coreStart.uiSettings.get('dateFormat', 'MMM D, YYYY @ HH:mm:ss.SSS');
|
||||
},
|
||||
getTimezone: () => {
|
||||
return coreStart.uiSettings.get('dateFormat:tz', 'Browser');
|
||||
},
|
||||
getDefaultTimeRange: () => {
|
||||
const defaultTimeRange = coreStart.uiSettings.get('timepicker:timeDefaults');
|
||||
return defaultTimeRange ? defaultTimeRange : { from: 'now-15m', to: 'now' };
|
||||
},
|
||||
};
|
||||
};
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import type { TimeRange } from '@kbn/es-query';
|
||||
|
||||
export interface ControlsSettingsService {
|
||||
getTimezone: () => string;
|
||||
getDateFormat: () => string;
|
||||
getDefaultTimeRange: () => TimeRange;
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlsStorageService } from './types';
|
||||
|
||||
type StorageServiceFactory = PluginServiceFactory<ControlsStorageService>;
|
||||
|
||||
export const storageServiceFactory: StorageServiceFactory = () => {
|
||||
return {
|
||||
getShowInvalidSelectionWarning: () => false,
|
||||
setShowInvalidSelectionWarning: (value: boolean) => null,
|
||||
};
|
||||
};
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { Storage } from '@kbn/kibana-utils-plugin/public';
|
||||
import { ControlsStorageService } from './types';
|
||||
|
||||
const STORAGE_KEY = 'controls:showInvalidSelectionWarning';
|
||||
|
||||
class StorageService implements ControlsStorageService {
|
||||
private storage: Storage;
|
||||
|
||||
constructor() {
|
||||
this.storage = new Storage(localStorage);
|
||||
}
|
||||
|
||||
getShowInvalidSelectionWarning = () => {
|
||||
return this.storage.get(STORAGE_KEY);
|
||||
};
|
||||
|
||||
setShowInvalidSelectionWarning = (value: boolean) => {
|
||||
this.storage.set(STORAGE_KEY, value);
|
||||
};
|
||||
}
|
||||
|
||||
export const controlsStorageServiceFactory = () => new StorageService();
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
export interface ControlsStorageService {
|
||||
getShowInvalidSelectionWarning: () => boolean;
|
||||
setShowInvalidSelectionWarning: (value: boolean) => void;
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { ControlsServiceType } from './controls/types';
|
||||
import { ControlsCoreService } from './core/types';
|
||||
import { ControlsDataService } from './data/types';
|
||||
import { ControlsDataViewsService } from './data_views/types';
|
||||
import { ControlsEmbeddableService } from './embeddable/types';
|
||||
import { ControlsHTTPService } from './http/types';
|
||||
import { ControlsOverlaysService } from './overlays/types';
|
||||
import { ControlsSettingsService } from './settings/types';
|
||||
import { ControlsStorageService } from './storage/types';
|
||||
import { ControlsUnifiedSearchService } from './unified_search/types';
|
||||
|
||||
export interface ControlsServices {
|
||||
// dependency services
|
||||
dataViews: ControlsDataViewsService;
|
||||
overlays: ControlsOverlaysService;
|
||||
embeddable: ControlsEmbeddableService;
|
||||
data: ControlsDataService;
|
||||
unifiedSearch: ControlsUnifiedSearchService;
|
||||
http: ControlsHTTPService;
|
||||
settings: ControlsSettingsService;
|
||||
core: ControlsCoreService;
|
||||
|
||||
// controls plugin's own services
|
||||
controls: ControlsServiceType;
|
||||
storage: ControlsStorageService;
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
|
||||
|
||||
export interface ControlsUnifiedSearchService {
|
||||
autocomplete: UnifiedSearchPublicPluginStart['autocomplete'];
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { DataViewField } from '@kbn/data-views-plugin/common';
|
||||
import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
|
||||
|
||||
import { ControlsUnifiedSearchService } from './types';
|
||||
|
||||
let valueSuggestionMethod = ({ field, query }: { field: DataViewField; query: string }) =>
|
||||
Promise.resolve(['storybook', 'default', 'values']);
|
||||
export const replaceValueSuggestionMethod = (
|
||||
newMethod: ({ field, query }: { field: DataViewField; query: string }) => Promise<string[]>
|
||||
) => (valueSuggestionMethod = newMethod);
|
||||
|
||||
export type UnifiedSearchServiceFactory = PluginServiceFactory<ControlsUnifiedSearchService>;
|
||||
export const unifiedSearchServiceFactory: UnifiedSearchServiceFactory = () => ({
|
||||
autocomplete: {
|
||||
getValueSuggestions: valueSuggestionMethod,
|
||||
} as unknown as UnifiedSearchPublicPluginStart['autocomplete'],
|
||||
});
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public
|
||||
* License v3.0 only", or the "Server Side Public License, v 1".
|
||||
*/
|
||||
|
||||
import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlsPluginStartDeps } from '../../types';
|
||||
import { ControlsUnifiedSearchService } from './types';
|
||||
|
||||
export type UnifiedSearchServiceFactory = KibanaPluginServiceFactory<
|
||||
ControlsUnifiedSearchService,
|
||||
ControlsPluginStartDeps
|
||||
>;
|
||||
|
||||
export const unifiedSearchServiceFactory: UnifiedSearchServiceFactory = ({ startPlugins }) => {
|
||||
const {
|
||||
unifiedSearch: { autocomplete },
|
||||
} = startPlugins;
|
||||
|
||||
return {
|
||||
autocomplete,
|
||||
};
|
||||
};
|
|
@ -9,11 +9,8 @@
|
|||
|
||||
import { DataPublicPluginStart } from '@kbn/data-plugin/public';
|
||||
import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
||||
import { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public';
|
||||
import { EmbeddableSetup } from '@kbn/embeddable-plugin/public';
|
||||
import { UiActionsStart } from '@kbn/ui-actions-plugin/public';
|
||||
import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
|
||||
|
||||
import { ControlsServiceType } from './services/controls/types';
|
||||
|
||||
export interface CanClearSelections {
|
||||
clearSelections: () => void;
|
||||
|
@ -26,22 +23,11 @@ export const isClearableControl = (control: unknown): control is CanClearSelecti
|
|||
/**
|
||||
* Plugin types
|
||||
*/
|
||||
export interface ControlsPluginSetup {
|
||||
registerControlFactory: ControlsServiceType['registerControlFactory'];
|
||||
}
|
||||
|
||||
export interface ControlsPluginStart {
|
||||
getControlFactory: ControlsServiceType['getControlFactory'];
|
||||
getAllControlTypes: ControlsServiceType['getAllControlTypes'];
|
||||
}
|
||||
|
||||
export interface ControlsPluginSetupDeps {
|
||||
embeddable: EmbeddableSetup;
|
||||
}
|
||||
export interface ControlsPluginStartDeps {
|
||||
uiActions: UiActionsStart;
|
||||
embeddable: EmbeddableStart;
|
||||
data: DataPublicPluginStart;
|
||||
dataViews: DataViewsPublicPluginStart;
|
||||
unifiedSearch: UnifiedSearchPublicPluginStart;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
import { SerializableRecord } from '@kbn/utility-types';
|
||||
|
||||
import {
|
||||
DEFAULT_CONTROL_STYLE,
|
||||
DEFAULT_CONTROL_LABEL_POSITION,
|
||||
type ControlGroupRuntimeState,
|
||||
type ControlGroupSerializedState,
|
||||
type ControlPanelState,
|
||||
|
@ -19,7 +19,7 @@ import {
|
|||
|
||||
export const getDefaultControlGroupState = (): SerializableControlGroupState => ({
|
||||
panels: {},
|
||||
labelPosition: DEFAULT_CONTROL_STYLE,
|
||||
labelPosition: DEFAULT_CONTROL_LABEL_POSITION,
|
||||
chainingSystem: 'HIERARCHICAL',
|
||||
autoApplySelections: true,
|
||||
ignoreParentSettings: {
|
||||
|
|
|
@ -15,7 +15,7 @@ export const setupOptionsListClusterSettingsRoute = ({ http }: CoreSetup) => {
|
|||
router.versioned
|
||||
.get({
|
||||
access: 'internal',
|
||||
path: '/internal/controls/optionsList/getExpensiveQueriesSetting',
|
||||
path: '/internal/controls/getExpensiveQueriesSetting',
|
||||
})
|
||||
.addVersion(
|
||||
{
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
"@kbn/presentation-containers",
|
||||
"@kbn/presentation-publishing",
|
||||
"@kbn/content-management-utils",
|
||||
"@kbn/core-lifecycle-browser",
|
||||
"@kbn/field-formats-plugin",
|
||||
"@kbn/presentation-panel-plugin",
|
||||
"@kbn/shared-ux-utility"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue