Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Dashboard] Public CRUD API MVP #193067

Merged
merged 73 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
1e286bf
Unify content management and dashboard api schemas
nickpeihl Sep 16, 2024
91788ce
Merge remote-tracking branch 'upstream/main' into dashboard-cmv3
nickpeihl Sep 16, 2024
e55088d
Remove exclusive suite test
nickpeihl Sep 16, 2024
286b76d
Add fields to searchSource.filter.meta and allow unknowns
nickpeihl Sep 16, 2024
352562d
Decouple Dashboard Content Management from Saved Object
nickpeihl Sep 18, 2024
385d8a7
Revert changes to @kbn/content-management-utils
nickpeihl Sep 19, 2024
c9b9820
Link CM version with Public API version
nickpeihl Sep 20, 2024
f5a08b2
Merge remote-tracking branch 'upstream/main' into dashboard-cmv3
nickpeihl Sep 24, 2024
abaad5e
Fix broken Lens panels.
nickpeihl Sep 24, 2024
98e123f
Fix "Cannot assign to read only property" when re-opening Dashboard w…
nickpeihl Sep 25, 2024
b20ca0d
Update route and better error handling
nickpeihl Sep 25, 2024
5caa214
Stub api integration tests
nickpeihl Sep 26, 2024
8af76d6
Merge remote-tracking branch 'upstream/main' into dashboard-cmv3
nickpeihl Sep 26, 2024
eef5b6f
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Sep 26, 2024
3ae6ad7
API tests for create endpoint
nickpeihl Sep 30, 2024
b3a7960
Mark endpoints as Technical Preview
nickpeihl Oct 2, 2024
557ebca
Better defaults
nickpeihl Oct 2, 2024
f79e565
Add OAS tag for docs
nickpeihl Oct 2, 2024
c8f7710
Additional tests for Create endpoint
nickpeihl Oct 2, 2024
0dbba74
Fix Controls validation and transforms
nickpeihl Oct 3, 2024
499072d
Create default dashboard options
nickpeihl Oct 3, 2024
5506977
Merge remote-tracking branch 'refs/remotes/origin/dashboard-cmv3' int…
nickpeihl Oct 7, 2024
e93515e
More API integration tests
nickpeihl Oct 7, 2024
f24386d
Update function name in tests
nickpeihl Oct 7, 2024
5ab2c6b
Fix partial updates
nickpeihl Oct 7, 2024
c0e3634
Fix list endpoint
nickpeihl Oct 7, 2024
3e8fd92
Remove unbounded recursive sorting function
nickpeihl Oct 7, 2024
c54a7a1
Fix integration test
nickpeihl Oct 7, 2024
f2bb339
Merge remote-tracking branch 'upstream/main' into dashboard-cmv3
nickpeihl Oct 7, 2024
8b6ffeb
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Oct 7, 2024
a4f8b1a
Merge remote-tracking branch 'upstream/main' into dashboard-cmv3
nickpeihl Oct 11, 2024
1fa9787
Rename panels to controls in controlGroupInput
nickpeihl Oct 11, 2024
bc1c804
Rename embeddableConfig to panelConfig
nickpeihl Oct 11, 2024
bf83334
Merge remote-tracking branch 'refs/remotes/origin/dashboard-cmv3' int…
nickpeihl Oct 11, 2024
051f71b
Better default handling on controls
nickpeihl Oct 14, 2024
14d0ee0
Merge branch 'main' into dashboard-cmv3
nickpeihl Oct 14, 2024
17440a4
Fix controls types
nickpeihl Oct 17, 2024
13e8311
Merge remote-tracking branch 'refs/remotes/origin/dashboard-cmv3' int…
nickpeihl Oct 17, 2024
eae4cdc
[CI] Auto-commit changed files from 'node scripts/notice'
kibanamachine Oct 17, 2024
e58fda9
Fix controls renderer
nickpeihl Oct 18, 2024
1b923c2
Merge remote-tracking branch 'refs/remotes/origin/dashboard-cmv3' int…
nickpeihl Oct 18, 2024
111fc28
Update dashboard unit tests
nickpeihl Oct 18, 2024
0ebd0cb
Add unit tests for transform utils
nickpeihl Oct 18, 2024
9c60eb0
Update snapshots for migrations tests
nickpeihl Oct 18, 2024
65f2a27
Merge remote-tracking branch 'upstream/main' into dashboard-cmv3
nickpeihl Oct 18, 2024
7c8888e
Undo circular reference in tsconfig
nickpeihl Oct 18, 2024
00396b2
Fix types
nickpeihl Oct 21, 2024
ec8778c
Fix parsing appState from bookmarked URLs
nickpeihl Oct 23, 2024
b5c6f84
Unify control serialized and runtime state options
nickpeihl Oct 23, 2024
94d20f7
Fix unit tests
nickpeihl Oct 23, 2024
79d392c
Merge branch 'main' into dashboard-cmv3
nickpeihl Oct 23, 2024
a594cee
Fix types and tests
nickpeihl Oct 24, 2024
fa8fa60
Fix type imports
nickpeihl Oct 24, 2024
91a9d3b
Silly rabbit, dashboards don't support ESQL filters yet
nickpeihl Oct 24, 2024
2e88238
Fix incorrect test
nickpeihl Oct 24, 2024
b3f2188
Remove comments
nickpeihl Oct 29, 2024
ddd42ea
Fix types
nickpeihl Oct 29, 2024
c505529
Review feedback
nickpeihl Oct 29, 2024
d2bcb1b
Rename constant as suggested
nickpeihl Oct 29, 2024
62bdadf
Merge branch 'main' into dashboard-cmv3
nickpeihl Oct 29, 2024
f0e1cc1
Put experimental HTTP API routes behind feature flag
nickpeihl Nov 4, 2024
287dd2e
[CI] Auto-commit changed files from 'node scripts/notice'
kibanamachine Nov 4, 2024
14319b2
Undo server-side embeddable registration for links
nickpeihl Nov 4, 2024
59ee48f
Fix types
nickpeihl Nov 4, 2024
91b2fcc
Remove unused test suites
nickpeihl Nov 4, 2024
93f45d4
Merge remote-tracking branch 'refs/remotes/origin/dashboard-cmv3' int…
nickpeihl Nov 4, 2024
e800c7d
Merge branch 'main' into dashboard-cmv3
nickpeihl Nov 4, 2024
3fef67b
Type fixes
nickpeihl Nov 4, 2024
c7b15d8
Fix type
nickpeihl Nov 5, 2024
02b5fcb
Remove comment
nickpeihl Nov 5, 2024
1a512ff
Revert "Put experimental HTTP API routes behind feature flag"
nickpeihl Nov 5, 2024
68f0d50
[CI] Auto-commit changed files from 'node scripts/notice'
kibanamachine Nov 5, 2024
f554dd4
Merge branch 'main' into dashboard-cmv3
nickpeihl Nov 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions src/plugins/controls/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,25 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { ControlGroupChainingSystem } from './control_group';
import { ControlLabelPosition, ControlWidth } from './types';

export const DEFAULT_CONTROL_WIDTH: ControlWidth = 'medium';
export const CONTROL_WIDTH_OPTIONS = { SMALL: 'small', MEDIUM: 'medium', LARGE: 'large' } as const;
export const CONTROL_LABEL_POSITION_OPTIONS = { ONE_LINE: 'oneLine', TWO_LINE: 'twoLine' } as const;
export const CONTROL_CHAINING_OPTIONS = { NONE: 'NONE', HIERARCHICAL: 'HIERARCHICAL' } as const;
export const DEFAULT_CONTROL_WIDTH: ControlWidth = CONTROL_WIDTH_OPTIONS.MEDIUM;
export const DEFAULT_CONTROL_LABEL_POSITION: ControlLabelPosition =
CONTROL_LABEL_POSITION_OPTIONS.ONE_LINE;
export const DEFAULT_CONTROL_GROW: boolean = true;
export const DEFAULT_CONTROL_LABEL_POSITION: ControlLabelPosition = 'oneLine';
export const DEFAULT_CONTROL_CHAINING: ControlGroupChainingSystem =
CONTROL_CHAINING_OPTIONS.HIERARCHICAL;
export const DEFAULT_IGNORE_PARENT_SETTINGS = {
ignoreFilters: false,
ignoreQuery: false,
ignoreTimerange: false,
ignoreValidations: false,
} as const;
export const DEFAULT_AUTO_APPLY_SELECTIONS = true;

export const TIME_SLIDER_CONTROL = 'timeSlider';
export const RANGE_SLIDER_CONTROL = 'rangeSliderControl';
Expand Down
18 changes: 8 additions & 10 deletions src/plugins/controls/common/control_group/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@

import { DataViewField } from '@kbn/data-views-plugin/common';
import { ControlLabelPosition, DefaultControlState, ParentIgnoreSettings } from '../types';
import { CONTROL_CHAINING_OPTIONS } from '../constants';

export const CONTROL_GROUP_TYPE = 'control_group';

export type ControlGroupChainingSystem = 'HIERARCHICAL' | 'NONE';
export type ControlGroupChainingSystem =
nickpeihl marked this conversation as resolved.
Show resolved Hide resolved
(typeof CONTROL_CHAINING_OPTIONS)[keyof typeof CONTROL_CHAINING_OPTIONS];

export type FieldFilterPredicate = (f: DataViewField) => boolean;

Expand Down Expand Up @@ -45,15 +47,11 @@ export interface ControlGroupRuntimeState<State extends DefaultControlState = De
}

export interface ControlGroupSerializedState
extends Pick<ControlGroupRuntimeState, 'chainingSystem' | 'editorConfig'> {
panelsJSON: string; // stringified version of ControlSerializedState
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: 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;
extends Omit<ControlGroupRuntimeState, 'initialChildControlState'> {
// In runtime state, we refer to this property as `initialChildControlState`, but in
// the serialized state we transform the state object into an array of state objects
// to make it easier for API consumers to add new controls without specifying a uuid key.
controls: Array<ControlPanelState & { id?: string }>;
}

/**
Expand Down
6 changes: 6 additions & 0 deletions src/plugins/controls/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,15 @@ export type {
} from './types';

export {
DEFAULT_CONTROL_CHAINING,
DEFAULT_CONTROL_GROW,
DEFAULT_CONTROL_LABEL_POSITION,
DEFAULT_CONTROL_WIDTH,
DEFAULT_IGNORE_PARENT_SETTINGS,
DEFAULT_AUTO_APPLY_SELECTIONS,
CONTROL_WIDTH_OPTIONS,
CONTROL_CHAINING_OPTIONS,
CONTROL_LABEL_POSITION_OPTIONS,
OPTIONS_LIST_CONTROL,
RANGE_SLIDER_CONTROL,
TIME_SLIDER_CONTROL,
Expand Down
10 changes: 7 additions & 3 deletions src/plugins/controls/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

export type ControlWidth = 'small' | 'medium' | 'large';
export type ControlLabelPosition = 'twoLine' | 'oneLine';
import { SerializableRecord } from '@kbn/utility-types';
import { CONTROL_LABEL_POSITION_OPTIONS, CONTROL_WIDTH_OPTIONS } from './constants';

export type ControlWidth = (typeof CONTROL_WIDTH_OPTIONS)[keyof typeof CONTROL_WIDTH_OPTIONS];
nickpeihl marked this conversation as resolved.
Show resolved Hide resolved
export type ControlLabelPosition =
(typeof CONTROL_LABEL_POSITION_OPTIONS)[keyof typeof CONTROL_LABEL_POSITION_OPTIONS];

export type TimeSlice = [number, number];

export interface ParentIgnoreSettings {
export interface ParentIgnoreSettings extends SerializableRecord {
ignoreFilters?: boolean;
ignoreQuery?: boolean;
ignoreTimerange?: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ import { useSearchApi, type ViewMode as ViewModeType } from '@kbn/presentation-p
import type { ControlGroupApi } from '../..';
import {
CONTROL_GROUP_TYPE,
DEFAULT_CONTROL_LABEL_POSITION,
type ControlGroupRuntimeState,
type ControlGroupSerializedState,
DEFAULT_CONTROL_CHAINING,
DEFAULT_AUTO_APPLY_SELECTIONS,
} from '../../../common';
import {
type ControlGroupStateBuilder,
Expand Down Expand Up @@ -136,16 +139,19 @@ export const ControlGroupRenderer = ({
...initialState,
editorConfig,
});
const state = {
...omit(initialState, ['initialChildControlState', 'ignoreParentSettings']),
const state: ControlGroupSerializedState = {
...omit(initialState, ['initialChildControlState']),
editorConfig,
controlStyle: initialState?.labelPosition,
panelsJSON: JSON.stringify(initialState?.initialChildControlState ?? {}),
ignoreParentSettingsJSON: JSON.stringify(initialState?.ignoreParentSettings ?? {}),
autoApplySelections: initialState?.autoApplySelections ?? DEFAULT_AUTO_APPLY_SELECTIONS,
labelPosition: initialState?.labelPosition ?? DEFAULT_CONTROL_LABEL_POSITION,
chainingSystem: initialState?.chainingSystem ?? DEFAULT_CONTROL_CHAINING,
controls: Object.entries(initialState?.initialChildControlState ?? {}).map(
([controlId, value]) => ({ ...value, id: controlId })
),
};

if (!cancelled) {
setSerializedState(state as ControlGroupSerializedState);
setSerializedState(state);
}
})();
return () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ import type {
ControlPanelsState,
ParentIgnoreSettings,
} from '../../common';
import { CONTROL_GROUP_TYPE, DEFAULT_CONTROL_LABEL_POSITION } from '../../common';
import {
CONTROL_GROUP_TYPE,
DEFAULT_CONTROL_CHAINING,
DEFAULT_CONTROL_LABEL_POSITION,
} from '../../common';
import { openDataControlEditor } from '../controls/data_controls/open_data_control_editor';
import { coreServices, dataViewsService } from '../services/kibana_services';
import { ControlGroup } from './components/control_group';
Expand All @@ -45,8 +49,6 @@ import { initSelectionsManager } from './selections_manager';
import type { ControlGroupApi } from './types';
import { deserializeControlGroup } from './utils/serialization_utils';

const DEFAULT_CHAINING_SYSTEM = 'HIERARCHICAL';

export const getControlGroupEmbeddableFactory = () => {
const controlGroupEmbeddableFactory: ReactEmbeddableFactory<
ControlGroupSerializedState,
Expand Down Expand Up @@ -85,7 +87,7 @@ export const getControlGroupEmbeddableFactory = () => {
});
const dataViews = new BehaviorSubject<DataView[] | undefined>(undefined);
const chainingSystem$ = new BehaviorSubject<ControlGroupChainingSystem>(
chainingSystem ?? DEFAULT_CHAINING_SYSTEM
chainingSystem ?? DEFAULT_CONTROL_CHAINING
);
const ignoreParentSettings$ = new BehaviorSubject<ParentIgnoreSettings | undefined>(
ignoreParentSettings
Expand All @@ -108,7 +110,7 @@ export const getControlGroupEmbeddableFactory = () => {
chainingSystem: [
chainingSystem$,
(next: ControlGroupChainingSystem) => chainingSystem$.next(next),
(a, b) => (a ?? DEFAULT_CHAINING_SYSTEM) === (b ?? DEFAULT_CHAINING_SYSTEM),
(a, b) => (a ?? DEFAULT_CONTROL_CHAINING) === (b ?? DEFAULT_CONTROL_CHAINING),
],
ignoreParentSettings: [
ignoreParentSettings$,
Expand Down Expand Up @@ -187,14 +189,14 @@ export const getControlGroupEmbeddableFactory = () => {
});
},
serializeState: () => {
const { panelsJSON, references } = controlsManager.serializeControls();
const { controls, references } = controlsManager.serializeControls();
return {
rawState: {
chainingSystem: chainingSystem$.getValue(),
controlStyle: labelPosition$.getValue(),
showApplySelections: !autoApplySelections$.getValue(),
ignoreParentSettingsJSON: JSON.stringify(ignoreParentSettings$.getValue()),
panelsJSON,
labelPosition: labelPosition$.getValue(),
autoApplySelections: autoApplySelections$.getValue(),
ignoreParentSettings: ignoreParentSettings$.getValue(),
controls,
},
references,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,9 +147,8 @@ export function initControlsManager(
},
serializeControls: () => {
const references: Reference[] = [];
const explicitInputPanels: {
[panelId: string]: ControlPanelState & { explicitInput: object };
} = {};

const controls: Array<ControlPanelState & { controlConfig: object }> = [];

controlsInOrder$.getValue().forEach(({ id }, index) => {
const controlApi = getControlApi(id);
Expand All @@ -166,18 +165,18 @@ export function initControlsManager(
references.push(...controlReferences);
}

explicitInputPanels[id] = {
controls.push({
grow,
order: index,
type: controlApi.type,
width,
/** Re-add the `explicitInput` layer on serialize so control group saved object retains shape */
explicitInput: { id, ...rest },
};
/** Re-add the `controlConfig` layer on serialize so control group saved object retains shape */
controlConfig: { id, ...rest },
});
});

return {
panelsJSON: JSON.stringify(explicitInputPanels),
controls,
references,
};
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { DEFAULT_CONTROL_LABEL_POSITION, type ControlGroupRuntimeState } from '../../../common';
import {
type ControlGroupRuntimeState,
DEFAULT_CONTROL_CHAINING,
DEFAULT_CONTROL_LABEL_POSITION,
DEFAULT_AUTO_APPLY_SELECTIONS,
DEFAULT_IGNORE_PARENT_SETTINGS,
} from '../../../common';

export const getDefaultControlGroupRuntimeState = (): ControlGroupRuntimeState => ({
initialChildControlState: {},
labelPosition: DEFAULT_CONTROL_LABEL_POSITION,
chainingSystem: 'HIERARCHICAL',
autoApplySelections: true,
ignoreParentSettings: {
ignoreFilters: false,
ignoreQuery: false,
ignoreTimerange: false,
ignoreValidations: false,
},
chainingSystem: DEFAULT_CONTROL_CHAINING,
autoApplySelections: DEFAULT_AUTO_APPLY_SELECTIONS,
ignoreParentSettings: DEFAULT_IGNORE_PARENT_SETTINGS,
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,31 @@ import { parseReferenceName } from '../../controls/data_controls/reference_name_
export const deserializeControlGroup = (
state: SerializedPanelState<ControlGroupSerializedState>
): ControlGroupRuntimeState => {
const panels = JSON.parse(state.rawState.panelsJSON);
const ignoreParentSettings = JSON.parse(state.rawState.ignoreParentSettingsJSON);
const { controls } = state.rawState;
const controlsMap = Object.fromEntries(controls.map(({ id, ...rest }) => [id, rest]));

/** Inject data view references into each individual control */
const references = state.references ?? [];
references.forEach((reference) => {
const referenceName = reference.name;
const { controlId } = parseReferenceName(referenceName);
if (panels[controlId]) {
panels[controlId].dataViewId = reference.id;
if (controlsMap[controlId]) {
controlsMap[controlId].dataViewId = reference.id;
}
});

/** Flatten the state of each panel by removing `explicitInput` */
const flattenedPanels = Object.keys(panels).reduce((prev, panelId) => {
const currentPanel = panels[panelId];
const currentPanelExplicitInput = panels[panelId].explicitInput;
/** Flatten the state of each control by removing `controlConfig` */
const flattenedControls = Object.keys(controlsMap).reduce((prev, controlId) => {
const currentControl = controlsMap[controlId];
const currentControlExplicitInput = controlsMap[controlId].controlConfig;
return {
...prev,
[panelId]: { ...omit(currentPanel, 'explicitInput'), ...currentPanelExplicitInput },
[controlId]: { ...omit(currentControl, 'controlConfig'), ...currentControlExplicitInput },
};
}, {});

return {
...omit(state.rawState, ['panelsJSON', 'ignoreParentSettingsJSON']),
initialChildControlState: flattenedPanels,
ignoreParentSettings,
autoApplySelections:
typeof state.rawState.showApplySelections === 'boolean'
? !state.rawState.showApplySelections
: true, // Rename "showApplySelections" to "autoApplySelections"
labelPosition: state.rawState.controlStyle, // Rename "controlStyle" to "labelPosition"
...state.rawState,
initialChildControlState: flattenedControls,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,8 @@ import {
import { OptionsListControlState } from '../../common/options_list';
import { mockDataControlState, mockOptionsListControlState } from '../mocks';
import { removeHideExcludeAndHideExists } from './control_group_migrations';
import {
SerializableControlGroupState,
getDefaultControlGroupState,
} from './control_group_persistence';
import { getDefaultControlGroupState } from './control_group_persistence';
import type { SerializableControlGroupState } from './types';

describe('migrate control group', () => {
const getOptionsListControl = (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
type SerializedControlState,
} from '../../common';
import { OptionsListControlState } from '../../common/options_list';
import { SerializableControlGroupState } from './control_group_persistence';
import { SerializableControlGroupState } from './types';

export const makeControlOrdersZeroBased = (state: SerializableControlGroupState) => {
if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
makeControlOrdersZeroBased,
removeHideExcludeAndHideExists,
} from './control_group_migrations';
import type { SerializableControlGroupState } from './control_group_persistence';
import { SerializableControlGroupState } from './types';

const getPanelStatePrefix = (state: SerializedControlState) => `${state.explicitInput.id}:`;

Expand Down
Loading