mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Dashboard] Move all dashboard extract/inject into persistable state (#96095)
* Move all dashboard inject/extract to be part of embeddable persistable state * Fixes typescript errors * Remove comments * Fixes test * API Doc changes * Fix integration tests * Fix functional testS * Fix unit tests * Update Dashboard plugin API to get dashboard embeddable renderer * Fix Types Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
f544d8d458
commit
b645fec8b8
21 changed files with 966 additions and 347 deletions
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [kibana-plugin-plugins-embeddable-server](./kibana-plugin-plugins-embeddable-server.md) > [EmbeddableStart](./kibana-plugin-plugins-embeddable-server.embeddablestart.md)
|
||||
|
||||
## EmbeddableStart type
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type EmbeddableStart = PersistableStateService<EmbeddableStateWithType>;
|
||||
```
|
|
@ -18,3 +18,9 @@
|
|||
| --- | --- |
|
||||
| [plugin](./kibana-plugin-plugins-embeddable-server.plugin.md) | |
|
||||
|
||||
## Type Aliases
|
||||
|
||||
| Type Alias | Description |
|
||||
| --- | --- |
|
||||
| [EmbeddableStart](./kibana-plugin-plugins-embeddable-server.embeddablestart.md) | |
|
||||
|
||||
|
|
|
@ -55,7 +55,9 @@ const Nav = withRouter(({ history, pages }: NavProps) => {
|
|||
|
||||
interface Props {
|
||||
basename: string;
|
||||
DashboardContainerByValueRenderer: DashboardStart['DashboardContainerByValueRenderer'];
|
||||
DashboardContainerByValueRenderer: ReturnType<
|
||||
DashboardStart['getDashboardContainerByValueRenderer']
|
||||
>;
|
||||
}
|
||||
|
||||
const DashboardEmbeddableExplorerApp = ({ basename, DashboardContainerByValueRenderer }: Props) => {
|
||||
|
|
|
@ -96,7 +96,9 @@ const initialInput: DashboardContainerInput = {
|
|||
export const DashboardEmbeddableByValue = ({
|
||||
DashboardContainerByValueRenderer,
|
||||
}: {
|
||||
DashboardContainerByValueRenderer: DashboardStart['DashboardContainerByValueRenderer'];
|
||||
DashboardContainerByValueRenderer: ReturnType<
|
||||
DashboardStart['getDashboardContainerByValueRenderer']
|
||||
>;
|
||||
}) => {
|
||||
const [input, setInput] = useState(initialInput);
|
||||
|
||||
|
|
|
@ -33,8 +33,7 @@ export class DashboardEmbeddableExamples implements Plugin<void, void, {}, Start
|
|||
return renderApp(
|
||||
{
|
||||
basename: params.appBasePath,
|
||||
DashboardContainerByValueRenderer:
|
||||
depsStart.dashboard.DashboardContainerByValueRenderer,
|
||||
DashboardContainerByValueRenderer: depsStart.dashboard.getDashboardContainerByValueRenderer(),
|
||||
},
|
||||
params.element
|
||||
);
|
||||
|
|
|
@ -78,6 +78,7 @@ export type RawSavedDashboardPanel730ToLatest = Pick<
|
|||
readonly name?: string;
|
||||
|
||||
panelIndex: string;
|
||||
panelRefName?: string;
|
||||
};
|
||||
|
||||
// NOTE!!
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { createExtract, createInject } from './dashboard_container_persistable_state';
|
||||
import { createEmbeddablePersistableStateServiceMock } from '../../../embeddable/common/mocks';
|
||||
import { DashboardContainerStateWithType } from '../types';
|
||||
|
||||
const persistableStateService = createEmbeddablePersistableStateServiceMock();
|
||||
|
||||
const dashboardWithExtractedPanel: DashboardContainerStateWithType = {
|
||||
id: 'id',
|
||||
type: 'dashboard',
|
||||
panels: {
|
||||
panel_1: {
|
||||
type: 'panel_type',
|
||||
gridData: { w: 0, h: 0, x: 0, y: 0, i: '0' },
|
||||
panelRefName: 'panel_panel_1',
|
||||
explicitInput: {
|
||||
id: 'panel_1',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const extractedSavedObjectPanelRef = {
|
||||
name: 'panel_1:panel_panel_1',
|
||||
type: 'panel_type',
|
||||
id: 'object-id',
|
||||
};
|
||||
|
||||
const unextractedDashboardState: DashboardContainerStateWithType = {
|
||||
id: 'id',
|
||||
type: 'dashboard',
|
||||
panels: {
|
||||
panel_1: {
|
||||
type: 'panel_type',
|
||||
gridData: { w: 0, h: 0, x: 0, y: 0, i: '0' },
|
||||
explicitInput: {
|
||||
id: 'panel_1',
|
||||
savedObjectId: 'object-id',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe('inject/extract by reference panel', () => {
|
||||
it('should inject the extracted saved object panel', () => {
|
||||
const inject = createInject(persistableStateService);
|
||||
const references = [extractedSavedObjectPanelRef];
|
||||
|
||||
const injected = inject(
|
||||
dashboardWithExtractedPanel,
|
||||
references
|
||||
) as DashboardContainerStateWithType;
|
||||
|
||||
expect(injected).toEqual(unextractedDashboardState);
|
||||
});
|
||||
|
||||
it('should extract the saved object panel', () => {
|
||||
const extract = createExtract(persistableStateService);
|
||||
const { state: extractedState, references: extractedReferences } = extract(
|
||||
unextractedDashboardState
|
||||
);
|
||||
|
||||
expect(extractedState).toEqual(dashboardWithExtractedPanel);
|
||||
expect(extractedReferences[0]).toEqual(extractedSavedObjectPanelRef);
|
||||
});
|
||||
});
|
||||
|
||||
const dashboardWithExtractedByValuePanel: DashboardContainerStateWithType = {
|
||||
id: 'id',
|
||||
type: 'dashboard',
|
||||
panels: {
|
||||
panel_1: {
|
||||
type: 'panel_type',
|
||||
gridData: { w: 0, h: 0, x: 0, y: 0, i: '0' },
|
||||
explicitInput: {
|
||||
id: 'panel_1',
|
||||
extracted_reference: 'ref',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const extractedByValueRef = {
|
||||
id: 'id',
|
||||
name: 'panel_1:ref',
|
||||
type: 'panel_type',
|
||||
};
|
||||
|
||||
const unextractedDashboardByValueState: DashboardContainerStateWithType = {
|
||||
id: 'id',
|
||||
type: 'dashboard',
|
||||
panels: {
|
||||
panel_1: {
|
||||
type: 'panel_type',
|
||||
gridData: { w: 0, h: 0, x: 0, y: 0, i: '0' },
|
||||
explicitInput: {
|
||||
id: 'panel_1',
|
||||
value: 'id',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe('inject/extract by value panels', () => {
|
||||
it('should inject the extracted references', () => {
|
||||
const inject = createInject(persistableStateService);
|
||||
|
||||
persistableStateService.inject.mockImplementationOnce((state, references) => {
|
||||
const ref = references.find((r) => r.name === 'ref');
|
||||
if (!ref) {
|
||||
return state;
|
||||
}
|
||||
|
||||
if (('extracted_reference' in state) as any) {
|
||||
(state as any).value = ref.id;
|
||||
delete (state as any).extracted_reference;
|
||||
}
|
||||
|
||||
return state;
|
||||
});
|
||||
|
||||
const injectedState = inject(dashboardWithExtractedByValuePanel, [extractedByValueRef]);
|
||||
|
||||
expect(injectedState).toEqual(unextractedDashboardByValueState);
|
||||
});
|
||||
|
||||
it('should extract references using persistable state', () => {
|
||||
const extract = createExtract(persistableStateService);
|
||||
|
||||
persistableStateService.extract.mockImplementationOnce((state) => {
|
||||
if ((state as any).value === 'id') {
|
||||
delete (state as any).value;
|
||||
(state as any).extracted_reference = 'ref';
|
||||
|
||||
return {
|
||||
state,
|
||||
references: [{ id: extractedByValueRef.id, name: 'ref', type: extractedByValueRef.type }],
|
||||
};
|
||||
}
|
||||
|
||||
return { state, references: [] };
|
||||
});
|
||||
|
||||
const { state: extractedState, references: extractedReferences } = extract(
|
||||
unextractedDashboardByValueState
|
||||
);
|
||||
|
||||
expect(extractedState).toEqual(dashboardWithExtractedByValuePanel);
|
||||
expect(extractedReferences).toEqual([extractedByValueRef]);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
EmbeddableInput,
|
||||
EmbeddablePersistableStateService,
|
||||
EmbeddableStateWithType,
|
||||
} from '../../../embeddable/common';
|
||||
import { SavedObjectReference } from '../../../../core/types';
|
||||
import { DashboardContainerStateWithType, DashboardPanelState } from '../types';
|
||||
|
||||
const getPanelStatePrefix = (state: DashboardPanelState) => `${state.explicitInput.id}:`;
|
||||
|
||||
export const createInject = (
|
||||
persistableStateService: EmbeddablePersistableStateService
|
||||
): EmbeddablePersistableStateService['inject'] => {
|
||||
return (state: EmbeddableStateWithType, references: SavedObjectReference[]) => {
|
||||
const workingState = { ...state } as EmbeddableStateWithType | DashboardContainerStateWithType;
|
||||
|
||||
if ('panels' in workingState) {
|
||||
workingState.panels = { ...workingState.panels };
|
||||
|
||||
for (const [key, panel] of Object.entries(workingState.panels)) {
|
||||
workingState.panels[key] = { ...panel };
|
||||
// Find the references for this panel
|
||||
const prefix = getPanelStatePrefix(panel);
|
||||
|
||||
const filteredReferences = references
|
||||
.filter((reference) => reference.name.indexOf(prefix) === 0)
|
||||
.map((reference) => ({ ...reference, name: reference.name.replace(prefix, '') }));
|
||||
|
||||
const panelReferences = filteredReferences.length === 0 ? references : filteredReferences;
|
||||
|
||||
// Inject dashboard references back in
|
||||
if (panel.panelRefName !== undefined) {
|
||||
const matchingReference = panelReferences.find(
|
||||
(reference) => reference.name === panel.panelRefName
|
||||
);
|
||||
|
||||
if (!matchingReference) {
|
||||
throw new Error(`Could not find reference "${panel.panelRefName}"`);
|
||||
}
|
||||
|
||||
if (matchingReference !== undefined) {
|
||||
workingState.panels[key] = {
|
||||
...panel,
|
||||
type: matchingReference.type,
|
||||
explicitInput: {
|
||||
...workingState.panels[key].explicitInput,
|
||||
savedObjectId: matchingReference.id,
|
||||
},
|
||||
};
|
||||
|
||||
delete workingState.panels[key].panelRefName;
|
||||
}
|
||||
}
|
||||
|
||||
const { type, ...injectedState } = persistableStateService.inject(
|
||||
{ ...workingState.panels[key].explicitInput, type: workingState.panels[key].type },
|
||||
panelReferences
|
||||
);
|
||||
|
||||
workingState.panels[key].explicitInput = injectedState as EmbeddableInput;
|
||||
}
|
||||
}
|
||||
|
||||
return workingState as EmbeddableStateWithType;
|
||||
};
|
||||
};
|
||||
|
||||
export const createExtract = (
|
||||
persistableStateService: EmbeddablePersistableStateService
|
||||
): EmbeddablePersistableStateService['extract'] => {
|
||||
return (state: EmbeddableStateWithType) => {
|
||||
const workingState = { ...state } as EmbeddableStateWithType | DashboardContainerStateWithType;
|
||||
|
||||
const references: SavedObjectReference[] = [];
|
||||
|
||||
if ('panels' in workingState) {
|
||||
workingState.panels = { ...workingState.panels };
|
||||
|
||||
// Run every panel through the state service to get the nested references
|
||||
for (const [key, panel] of Object.entries(workingState.panels)) {
|
||||
const prefix = getPanelStatePrefix(panel);
|
||||
|
||||
// If the panel is a saved object, then we will make the reference for that saved object and change the explicit input
|
||||
if (panel.explicitInput.savedObjectId) {
|
||||
panel.panelRefName = `panel_${key}`;
|
||||
|
||||
references.push({
|
||||
name: `${prefix}panel_${key}`,
|
||||
type: panel.type,
|
||||
id: panel.explicitInput.savedObjectId as string,
|
||||
});
|
||||
|
||||
delete panel.explicitInput.savedObjectId;
|
||||
delete panel.explicitInput.type;
|
||||
}
|
||||
|
||||
const { state: panelState, references: panelReferences } = persistableStateService.extract({
|
||||
...panel.explicitInput,
|
||||
type: panel.type,
|
||||
});
|
||||
|
||||
// We're going to prefix the names of the references so that we don't end up with dupes (from visualizations for instance)
|
||||
const prefixedReferences = panelReferences.map((reference) => ({
|
||||
...reference,
|
||||
name: `${prefix}${reference.name}`,
|
||||
}));
|
||||
|
||||
references.push(...prefixedReferences);
|
||||
|
||||
const { type, ...restOfState } = panelState;
|
||||
workingState.panels[key].explicitInput = restOfState as EmbeddableInput;
|
||||
}
|
||||
}
|
||||
|
||||
return { state: workingState as EmbeddableStateWithType, references };
|
||||
};
|
||||
};
|
|
@ -16,6 +16,7 @@ export function convertSavedDashboardPanelToPanelState(
|
|||
return {
|
||||
type: savedDashboardPanel.type,
|
||||
gridData: savedDashboardPanel.gridData,
|
||||
panelRefName: savedDashboardPanel.panelRefName,
|
||||
explicitInput: {
|
||||
id: savedDashboardPanel.panelIndex,
|
||||
...(savedDashboardPanel.id !== undefined && { savedObjectId: savedDashboardPanel.id }),
|
||||
|
@ -38,5 +39,6 @@ export function convertPanelStateToSavedDashboardPanel(
|
|||
embeddableConfig: omit(panelState.explicitInput, ['id', 'savedObjectId', 'title']),
|
||||
...(panelState.explicitInput.title !== undefined && { title: panelState.explicitInput.title }),
|
||||
...(savedObjectId !== undefined && { id: savedObjectId }),
|
||||
...(panelState.panelRefName !== undefined && { panelRefName: panelState.panelRefName }),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ export {
|
|||
DashboardDocPre700,
|
||||
} from './bwc/types';
|
||||
export {
|
||||
DashboardContainerStateWithType,
|
||||
SavedDashboardPanelTo60,
|
||||
SavedDashboardPanel610,
|
||||
SavedDashboardPanel620,
|
||||
|
|
|
@ -12,14 +12,34 @@ import {
|
|||
InjectDeps,
|
||||
ExtractDeps,
|
||||
} from './saved_dashboard_references';
|
||||
|
||||
import { createExtract, createInject } from './embeddable/dashboard_container_persistable_state';
|
||||
import { createEmbeddablePersistableStateServiceMock } from '../../embeddable/common/mocks';
|
||||
|
||||
const embeddablePersistableStateServiceMock = createEmbeddablePersistableStateServiceMock();
|
||||
const dashboardInject = createInject(embeddablePersistableStateServiceMock);
|
||||
const dashboardExtract = createExtract(embeddablePersistableStateServiceMock);
|
||||
|
||||
embeddablePersistableStateServiceMock.extract.mockImplementation((state) => {
|
||||
if (state.type === 'dashboard') {
|
||||
return dashboardExtract(state);
|
||||
}
|
||||
|
||||
return { state, references: [] };
|
||||
});
|
||||
|
||||
embeddablePersistableStateServiceMock.inject.mockImplementation((state, references) => {
|
||||
if (state.type === 'dashboard') {
|
||||
return dashboardInject(state, references);
|
||||
}
|
||||
|
||||
return state;
|
||||
});
|
||||
const deps: InjectDeps & ExtractDeps = {
|
||||
embeddablePersistableStateService: embeddablePersistableStateServiceMock,
|
||||
};
|
||||
|
||||
describe('extractReferences', () => {
|
||||
describe('legacy extract references', () => {
|
||||
test('extracts references from panelsJSON', () => {
|
||||
const doc = {
|
||||
id: '1',
|
||||
|
@ -30,13 +50,13 @@ describe('extractReferences', () => {
|
|||
type: 'visualization',
|
||||
id: '1',
|
||||
title: 'Title 1',
|
||||
version: '7.9.1',
|
||||
version: '7.0.0',
|
||||
},
|
||||
{
|
||||
type: 'visualization',
|
||||
id: '2',
|
||||
title: 'Title 2',
|
||||
version: '7.9.1',
|
||||
version: '7.0.0',
|
||||
},
|
||||
]),
|
||||
},
|
||||
|
@ -48,7 +68,7 @@ describe('extractReferences', () => {
|
|||
Object {
|
||||
"attributes": Object {
|
||||
"foo": true,
|
||||
"panelsJSON": "[{\\"version\\":\\"7.9.1\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 1\\",\\"panelRefName\\":\\"panel_0\\"},{\\"version\\":\\"7.9.1\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 2\\",\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
"panelsJSON": "[{\\"title\\":\\"Title 1\\",\\"version\\":\\"7.0.0\\",\\"panelRefName\\":\\"panel_0\\"},{\\"title\\":\\"Title 2\\",\\"version\\":\\"7.0.0\\",\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"references": Array [
|
||||
Object {
|
||||
|
@ -75,7 +95,7 @@ describe('extractReferences', () => {
|
|||
{
|
||||
id: '1',
|
||||
title: 'Title 1',
|
||||
version: '7.9.1',
|
||||
version: '7.0.0',
|
||||
},
|
||||
]),
|
||||
},
|
||||
|
@ -186,6 +206,102 @@ describe('extractReferences', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('extractReferences', () => {
|
||||
test('extracts references from panelsJSON', () => {
|
||||
const doc = {
|
||||
id: '1',
|
||||
attributes: {
|
||||
foo: true,
|
||||
panelsJSON: JSON.stringify([
|
||||
{
|
||||
panelIndex: 'panel-1',
|
||||
type: 'visualization',
|
||||
id: '1',
|
||||
title: 'Title 1',
|
||||
version: '7.9.1',
|
||||
},
|
||||
{
|
||||
panelIndex: 'panel-2',
|
||||
type: 'visualization',
|
||||
id: '2',
|
||||
title: 'Title 2',
|
||||
version: '7.9.1',
|
||||
},
|
||||
]),
|
||||
},
|
||||
references: [],
|
||||
};
|
||||
const updatedDoc = extractReferences(doc, deps);
|
||||
|
||||
expect(updatedDoc).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"foo": true,
|
||||
"panelsJSON": "[{\\"version\\":\\"7.9.1\\",\\"type\\":\\"visualization\\",\\"panelIndex\\":\\"panel-1\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 1\\",\\"panelRefName\\":\\"panel_panel-1\\"},{\\"version\\":\\"7.9.1\\",\\"type\\":\\"visualization\\",\\"panelIndex\\":\\"panel-2\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 2\\",\\"panelRefName\\":\\"panel_panel-2\\"}]",
|
||||
},
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel-1:panel_panel-1",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel-2:panel_panel-2",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('fails when "type" attribute is missing from a panel', () => {
|
||||
const doc = {
|
||||
id: '1',
|
||||
attributes: {
|
||||
foo: true,
|
||||
panelsJSON: JSON.stringify([
|
||||
{
|
||||
id: '1',
|
||||
title: 'Title 1',
|
||||
version: '7.9.1',
|
||||
},
|
||||
]),
|
||||
},
|
||||
references: [],
|
||||
};
|
||||
expect(() => extractReferences(doc, deps)).toThrowErrorMatchingInlineSnapshot(
|
||||
`"\\"type\\" attribute is missing from panel \\"0\\""`
|
||||
);
|
||||
});
|
||||
|
||||
test('passes when "id" attribute is missing from a panel', () => {
|
||||
const doc = {
|
||||
id: '1',
|
||||
attributes: {
|
||||
foo: true,
|
||||
panelsJSON: JSON.stringify([
|
||||
{
|
||||
type: 'visualization',
|
||||
title: 'Title 1',
|
||||
version: '7.9.1',
|
||||
},
|
||||
]),
|
||||
},
|
||||
references: [],
|
||||
};
|
||||
expect(extractReferences(doc, deps)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"foo": true,
|
||||
"panelsJSON": "[{\\"version\\":\\"7.9.1\\",\\"type\\":\\"visualization\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 1\\"}]",
|
||||
},
|
||||
"references": Array [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('injectReferences', () => {
|
||||
test('returns injected attributes', () => {
|
||||
const attributes = {
|
||||
|
@ -195,10 +311,12 @@ describe('injectReferences', () => {
|
|||
{
|
||||
panelRefName: 'panel_0',
|
||||
title: 'Title 1',
|
||||
version: '7.9.0',
|
||||
},
|
||||
{
|
||||
panelRefName: 'panel_1',
|
||||
title: 'Title 2',
|
||||
version: '7.9.0',
|
||||
},
|
||||
]),
|
||||
};
|
||||
|
@ -219,7 +337,7 @@ describe('injectReferences', () => {
|
|||
expect(newAttributes).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"id": "1",
|
||||
"panelsJSON": "[{\\"type\\":\\"visualization\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 1\\",\\"id\\":\\"1\\"},{\\"type\\":\\"visualization\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 2\\",\\"id\\":\\"2\\"}]",
|
||||
"panelsJSON": "[{\\"version\\":\\"7.9.0\\",\\"type\\":\\"visualization\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 1\\",\\"id\\":\\"1\\"},{\\"version\\":\\"7.9.0\\",\\"type\\":\\"visualization\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 2\\",\\"id\\":\\"2\\"}]",
|
||||
"title": "test",
|
||||
}
|
||||
`);
|
||||
|
@ -280,7 +398,7 @@ describe('injectReferences', () => {
|
|||
expect(newAttributes).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"id": "1",
|
||||
"panelsJSON": "[{\\"type\\":\\"visualization\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 1\\",\\"id\\":\\"1\\"},{\\"embeddableConfig\\":{},\\"title\\":\\"Title 2\\"}]",
|
||||
"panelsJSON": "[{\\"version\\":\\"\\",\\"type\\":\\"visualization\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 1\\",\\"id\\":\\"1\\"},{\\"version\\":\\"\\",\\"embeddableConfig\\":{},\\"title\\":\\"Title 2\\"}]",
|
||||
"title": "test",
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -8,22 +8,71 @@
|
|||
|
||||
import semverSatisfies from 'semver/functions/satisfies';
|
||||
import { SavedObjectAttributes, SavedObjectReference } from '../../../core/types';
|
||||
import {
|
||||
extractPanelsReferences,
|
||||
injectPanelsReferences,
|
||||
} from './embeddable/embeddable_references';
|
||||
import { SavedDashboardPanel730ToLatest } from './types';
|
||||
import { DashboardContainerStateWithType, DashboardPanelState } from './types';
|
||||
import { EmbeddablePersistableStateService } from '../../embeddable/common/types';
|
||||
|
||||
import {
|
||||
convertPanelStateToSavedDashboardPanel,
|
||||
convertSavedDashboardPanelToPanelState,
|
||||
} from './embeddable/embeddable_saved_object_converters';
|
||||
import { SavedDashboardPanel } from './types';
|
||||
export interface ExtractDeps {
|
||||
embeddablePersistableStateService: EmbeddablePersistableStateService;
|
||||
}
|
||||
|
||||
export interface SavedObjectAttributesAndReferences {
|
||||
attributes: SavedObjectAttributes;
|
||||
references: SavedObjectReference[];
|
||||
}
|
||||
|
||||
const isPre730Panel = (panel: Record<string, string>): boolean => {
|
||||
return 'version' in panel ? semverSatisfies(panel.version, '<7.3') : true;
|
||||
};
|
||||
|
||||
function dashboardAttributesToState(
|
||||
attributes: SavedObjectAttributes
|
||||
): {
|
||||
state: DashboardContainerStateWithType;
|
||||
panels: SavedDashboardPanel[];
|
||||
} {
|
||||
let inputPanels = [] as SavedDashboardPanel[];
|
||||
if (typeof attributes.panelsJSON === 'string') {
|
||||
inputPanels = JSON.parse(attributes.panelsJSON) as SavedDashboardPanel[];
|
||||
}
|
||||
|
||||
return {
|
||||
panels: inputPanels,
|
||||
state: {
|
||||
id: attributes.id as string,
|
||||
type: 'dashboard',
|
||||
panels: inputPanels.reduce<Record<string, DashboardPanelState>>((current, panel, index) => {
|
||||
const panelIndex = panel.panelIndex || `${index}`;
|
||||
current[panelIndex] = convertSavedDashboardPanelToPanelState(panel);
|
||||
return current;
|
||||
}, {}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function panelStatesToPanels(
|
||||
panelStates: DashboardContainerStateWithType['panels'],
|
||||
originalPanels: SavedDashboardPanel[]
|
||||
): SavedDashboardPanel[] {
|
||||
return Object.entries(panelStates).map(([id, panelState]) => {
|
||||
// Find matching original panel to get the version
|
||||
let originalPanel = originalPanels.find((p) => p.panelIndex === id);
|
||||
|
||||
if (!originalPanel) {
|
||||
// Maybe original panel doesn't have a panel index and it's just straight up based on it's index
|
||||
const numericId = parseInt(id, 10);
|
||||
originalPanel = isNaN(numericId) ? originalPanel : originalPanels[numericId];
|
||||
}
|
||||
|
||||
return convertPanelStateToSavedDashboardPanel(
|
||||
panelState,
|
||||
originalPanel?.version ? originalPanel.version : ''
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function extractReferences(
|
||||
{ attributes, references = [] }: SavedObjectAttributesAndReferences,
|
||||
deps: ExtractDeps
|
||||
|
@ -31,64 +80,33 @@ export function extractReferences(
|
|||
if (typeof attributes.panelsJSON !== 'string') {
|
||||
return { attributes, references };
|
||||
}
|
||||
const panelReferences: SavedObjectReference[] = [];
|
||||
let panels: Array<Record<string, string>> = JSON.parse(String(attributes.panelsJSON));
|
||||
|
||||
const isPre730Panel = (panel: Record<string, string>): boolean => {
|
||||
return 'version' in panel ? semverSatisfies(panel.version, '<7.3') : true;
|
||||
};
|
||||
const { panels, state } = dashboardAttributesToState(attributes);
|
||||
|
||||
const hasPre730Panel = panels.some(isPre730Panel);
|
||||
|
||||
/**
|
||||
* `extractPanelsReferences` only knows how to reliably handle "latest" panels
|
||||
* It is possible that `extractReferences` is run on older dashboard SO with older panels,
|
||||
* for example, when importing a saved object using saved object UI `extractReferences` is called BEFORE any server side migrations are run.
|
||||
*
|
||||
* In this case we skip running `extractPanelsReferences` on such object.
|
||||
* We also know that there is nothing to extract
|
||||
* (First possible entity to be extracted by this mechanism is a dashboard drilldown since 7.11)
|
||||
*/
|
||||
if (!hasPre730Panel) {
|
||||
const extractedReferencesResult = extractPanelsReferences(
|
||||
// it is ~safe~ to cast to `SavedDashboardPanel730ToLatest` because above we've checked that there are only >=7.3 panels
|
||||
(panels as unknown) as SavedDashboardPanel730ToLatest[],
|
||||
deps
|
||||
);
|
||||
|
||||
panels = (extractedReferencesResult.map((res) => res.panel) as unknown) as Array<
|
||||
Record<string, string>
|
||||
>;
|
||||
extractedReferencesResult.forEach((res) => {
|
||||
panelReferences.push(...res.references);
|
||||
});
|
||||
if (((panels as unknown) as Array<Record<string, string>>).some(isPre730Panel)) {
|
||||
return pre730ExtractReferences({ attributes, references }, deps);
|
||||
}
|
||||
|
||||
// TODO: This extraction should be done by EmbeddablePersistableStateService
|
||||
// https://github.com/elastic/kibana/issues/82830
|
||||
panels.forEach((panel, i) => {
|
||||
if (!panel.type) {
|
||||
throw new Error(`"type" attribute is missing from panel "${i}"`);
|
||||
}
|
||||
if (!panel.id) {
|
||||
// Embeddables are not required to be backed off a saved object.
|
||||
return;
|
||||
}
|
||||
panel.panelRefName = `panel_${i}`;
|
||||
panelReferences.push({
|
||||
name: `panel_${i}`,
|
||||
type: panel.type,
|
||||
id: panel.id,
|
||||
});
|
||||
delete panel.type;
|
||||
delete panel.id;
|
||||
});
|
||||
const missingTypeIndex = panels.findIndex((panel) => panel.type === undefined);
|
||||
if (missingTypeIndex >= 0) {
|
||||
throw new Error(`"type" attribute is missing from panel "${missingTypeIndex}"`);
|
||||
}
|
||||
|
||||
const {
|
||||
state: extractedState,
|
||||
references: extractedReferences,
|
||||
} = deps.embeddablePersistableStateService.extract(state);
|
||||
|
||||
const extractedPanels = panelStatesToPanels(
|
||||
(extractedState as DashboardContainerStateWithType).panels,
|
||||
panels
|
||||
);
|
||||
|
||||
return {
|
||||
references: [...references, ...panelReferences],
|
||||
references: [...references, ...extractedReferences],
|
||||
attributes: {
|
||||
...attributes,
|
||||
panelsJSON: JSON.stringify(panels),
|
||||
panelsJSON: JSON.stringify(extractedPanels),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -107,33 +125,60 @@ export function injectReferences(
|
|||
if (typeof attributes.panelsJSON !== 'string') {
|
||||
return attributes;
|
||||
}
|
||||
let panels = JSON.parse(attributes.panelsJSON);
|
||||
const parsedPanels = JSON.parse(attributes.panelsJSON);
|
||||
// Same here, prevent failing saved object import if ever panels aren't an array.
|
||||
if (!Array.isArray(panels)) {
|
||||
if (!Array.isArray(parsedPanels)) {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
// TODO: This injection should be done by EmbeddablePersistableStateService
|
||||
// https://github.com/elastic/kibana/issues/82830
|
||||
panels.forEach((panel) => {
|
||||
if (!panel.panelRefName) {
|
||||
return;
|
||||
}
|
||||
const reference = references.find((ref) => ref.name === panel.panelRefName);
|
||||
if (!reference) {
|
||||
// Throw an error since "panelRefName" means the reference exists within
|
||||
// "references" and in this scenario we have bad data.
|
||||
throw new Error(`Could not find reference "${panel.panelRefName}"`);
|
||||
}
|
||||
panel.id = reference.id;
|
||||
panel.type = reference.type;
|
||||
delete panel.panelRefName;
|
||||
});
|
||||
const { panels, state } = dashboardAttributesToState(attributes);
|
||||
|
||||
panels = injectPanelsReferences(panels, references, deps);
|
||||
const injectedState = deps.embeddablePersistableStateService.inject(state, references);
|
||||
const injectedPanels = panelStatesToPanels(
|
||||
(injectedState as DashboardContainerStateWithType).panels,
|
||||
panels
|
||||
);
|
||||
|
||||
return {
|
||||
...attributes,
|
||||
panelsJSON: JSON.stringify(panels),
|
||||
panelsJSON: JSON.stringify(injectedPanels),
|
||||
};
|
||||
}
|
||||
|
||||
function pre730ExtractReferences(
|
||||
{ attributes, references = [] }: SavedObjectAttributesAndReferences,
|
||||
deps: ExtractDeps
|
||||
): SavedObjectAttributesAndReferences {
|
||||
if (typeof attributes.panelsJSON !== 'string') {
|
||||
return { attributes, references };
|
||||
}
|
||||
const panelReferences: SavedObjectReference[] = [];
|
||||
const panels: Array<Record<string, string>> = JSON.parse(String(attributes.panelsJSON));
|
||||
|
||||
panels.forEach((panel, i) => {
|
||||
if (!panel.type) {
|
||||
throw new Error(`"type" attribute is missing from panel "${i}"`);
|
||||
}
|
||||
if (!panel.id) {
|
||||
// Embeddables are not required to be backed off a saved object.
|
||||
return;
|
||||
}
|
||||
|
||||
panel.panelRefName = `panel_${i}`;
|
||||
panelReferences.push({
|
||||
name: `panel_${i}`,
|
||||
type: panel.type,
|
||||
id: panel.id,
|
||||
});
|
||||
delete panel.type;
|
||||
delete panel.id;
|
||||
});
|
||||
|
||||
return {
|
||||
references: [...references, ...panelReferences],
|
||||
attributes: {
|
||||
...attributes,
|
||||
panelsJSON: JSON.stringify(panels),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -6,7 +6,11 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EmbeddableInput, PanelState } from '../../../../src/plugins/embeddable/common/types';
|
||||
import {
|
||||
EmbeddableInput,
|
||||
EmbeddableStateWithType,
|
||||
PanelState,
|
||||
} from '../../../../src/plugins/embeddable/common/types';
|
||||
import { SavedObjectEmbeddableInput } from '../../../../src/plugins/embeddable/common/lib/saved_object_embeddable';
|
||||
import {
|
||||
RawSavedDashboardPanelTo60,
|
||||
|
@ -25,6 +29,7 @@ export interface DashboardPanelState<
|
|||
TEmbeddableInput extends EmbeddableInput | SavedObjectEmbeddableInput = SavedObjectEmbeddableInput
|
||||
> extends PanelState<TEmbeddableInput> {
|
||||
readonly gridData: GridData;
|
||||
panelRefName?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -80,3 +85,11 @@ export type SavedDashboardPanel730ToLatest = Pick<
|
|||
readonly id?: string;
|
||||
readonly type: string;
|
||||
};
|
||||
|
||||
// Making this interface because so much of the Container type from embeddable is tied up in public
|
||||
// Once that is all available from common, we should be able to move the dashboard_container type to our common as well
|
||||
export interface DashboardContainerStateWithType extends EmbeddableStateWithType {
|
||||
panels: {
|
||||
[panelId: string]: DashboardPanelState<EmbeddableInput & { [k: string]: unknown }>;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { EmbeddablePersistableStateService } from 'src/plugins/embeddable/common';
|
||||
import {
|
||||
Container,
|
||||
ErrorEmbeddable,
|
||||
|
@ -20,6 +21,10 @@ import {
|
|||
DashboardContainerServices,
|
||||
} from './dashboard_container';
|
||||
import { DASHBOARD_CONTAINER_TYPE } from './dashboard_constants';
|
||||
import {
|
||||
createExtract,
|
||||
createInject,
|
||||
} from '../../../common/embeddable/dashboard_container_persistable_state';
|
||||
|
||||
export type DashboardContainerFactory = EmbeddableFactory<
|
||||
DashboardContainerInput,
|
||||
|
@ -32,7 +37,10 @@ export class DashboardContainerFactoryDefinition
|
|||
public readonly isContainerType = true;
|
||||
public readonly type = DASHBOARD_CONTAINER_TYPE;
|
||||
|
||||
constructor(private readonly getStartServices: () => Promise<DashboardContainerServices>) {}
|
||||
constructor(
|
||||
private readonly getStartServices: () => Promise<DashboardContainerServices>,
|
||||
private readonly persistableStateService: EmbeddablePersistableStateService
|
||||
) {}
|
||||
|
||||
public isEditable = async () => {
|
||||
// Currently unused for dashboards
|
||||
|
@ -62,4 +70,8 @@ export class DashboardContainerFactoryDefinition
|
|||
const services = await this.getStartServices();
|
||||
return new DashboardContainer(initialInput, services, parent);
|
||||
};
|
||||
|
||||
public inject = createInject(this.persistableStateService);
|
||||
|
||||
public extract = createExtract(this.persistableStateService);
|
||||
}
|
||||
|
|
|
@ -121,9 +121,11 @@ export type DashboardSetup = void;
|
|||
|
||||
export interface DashboardStart {
|
||||
getSavedDashboardLoader: () => SavedObjectLoader;
|
||||
getDashboardContainerByValueRenderer: () => ReturnType<
|
||||
typeof createDashboardContainerByValueRenderer
|
||||
>;
|
||||
dashboardUrlGenerator?: DashboardUrlGenerator;
|
||||
dashboardFeatureFlagConfig: DashboardFeatureFlagConfig;
|
||||
DashboardContainerByValueRenderer: ReturnType<typeof createDashboardContainerByValueRenderer>;
|
||||
}
|
||||
|
||||
export class DashboardPlugin
|
||||
|
@ -260,8 +262,16 @@ export class DashboardPlugin
|
|||
},
|
||||
});
|
||||
|
||||
const dashboardContainerFactory = new DashboardContainerFactoryDefinition(getStartServices);
|
||||
embeddable.registerEmbeddableFactory(dashboardContainerFactory.type, dashboardContainerFactory);
|
||||
getStartServices().then((coreStart) => {
|
||||
const dashboardContainerFactory = new DashboardContainerFactoryDefinition(
|
||||
getStartServices,
|
||||
coreStart.embeddable
|
||||
);
|
||||
embeddable.registerEmbeddableFactory(
|
||||
dashboardContainerFactory.type,
|
||||
dashboardContainerFactory
|
||||
);
|
||||
});
|
||||
|
||||
const placeholderFactory = new PlaceholderEmbeddableFactory();
|
||||
embeddable.registerEmbeddableFactory(placeholderFactory.type, placeholderFactory);
|
||||
|
@ -403,17 +413,24 @@ export class DashboardPlugin
|
|||
savedObjects: plugins.savedObjects,
|
||||
embeddableStart: plugins.embeddable,
|
||||
});
|
||||
const dashboardContainerFactory = plugins.embeddable.getEmbeddableFactory(
|
||||
DASHBOARD_CONTAINER_TYPE
|
||||
)! as DashboardContainerFactory;
|
||||
|
||||
return {
|
||||
getSavedDashboardLoader: () => savedDashboardLoader,
|
||||
getDashboardContainerByValueRenderer: () => {
|
||||
const dashboardContainerFactory = plugins.embeddable.getEmbeddableFactory(
|
||||
DASHBOARD_CONTAINER_TYPE
|
||||
);
|
||||
|
||||
if (!dashboardContainerFactory) {
|
||||
throw new Error(`${DASHBOARD_CONTAINER_TYPE} Embeddable Factory not found`);
|
||||
}
|
||||
|
||||
return createDashboardContainerByValueRenderer({
|
||||
factory: dashboardContainerFactory as DashboardContainerFactory,
|
||||
});
|
||||
},
|
||||
dashboardUrlGenerator: this.dashboardUrlGenerator,
|
||||
dashboardFeatureFlagConfig: this.dashboardFeatureFlagConfig!,
|
||||
DashboardContainerByValueRenderer: createDashboardContainerByValueRenderer({
|
||||
factory: dashboardContainerFactory,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EmbeddablePersistableStateService } from 'src/plugins/embeddable/common';
|
||||
import { EmbeddableRegistryDefinition } from '../../../embeddable/server';
|
||||
import {
|
||||
createExtract,
|
||||
createInject,
|
||||
} from '../../common/embeddable/dashboard_container_persistable_state';
|
||||
|
||||
export const dashboardPersistableStateServiceFactory = (
|
||||
persistableStateService: EmbeddablePersistableStateService
|
||||
): EmbeddableRegistryDefinition => {
|
||||
return {
|
||||
id: 'dashboard',
|
||||
extract: createExtract(persistableStateService),
|
||||
inject: createInject(persistableStateService),
|
||||
};
|
||||
};
|
|
@ -18,24 +18,29 @@ import { createDashboardSavedObjectType } from './saved_objects';
|
|||
import { capabilitiesProvider } from './capabilities_provider';
|
||||
|
||||
import { DashboardPluginSetup, DashboardPluginStart } from './types';
|
||||
import { EmbeddableSetup } from '../../embeddable/server';
|
||||
import { EmbeddableSetup, EmbeddableStart } from '../../embeddable/server';
|
||||
import { UsageCollectionSetup } from '../../usage_collection/server';
|
||||
import { registerDashboardUsageCollector } from './usage/register_collector';
|
||||
import { dashboardPersistableStateServiceFactory } from './embeddable/dashboard_container_embeddable_factory';
|
||||
|
||||
interface SetupDeps {
|
||||
embeddable: EmbeddableSetup;
|
||||
usageCollection: UsageCollectionSetup;
|
||||
}
|
||||
|
||||
interface StartDeps {
|
||||
embeddable: EmbeddableStart;
|
||||
}
|
||||
|
||||
export class DashboardPlugin
|
||||
implements Plugin<DashboardPluginSetup, DashboardPluginStart, SetupDeps> {
|
||||
implements Plugin<DashboardPluginSetup, DashboardPluginStart, SetupDeps, StartDeps> {
|
||||
private readonly logger: Logger;
|
||||
|
||||
constructor(initializerContext: PluginInitializerContext) {
|
||||
this.logger = initializerContext.logger.get();
|
||||
}
|
||||
|
||||
public setup(core: CoreSetup, plugins: SetupDeps) {
|
||||
public setup(core: CoreSetup<StartDeps>, plugins: SetupDeps) {
|
||||
this.logger.debug('dashboard: Setup');
|
||||
|
||||
core.savedObjects.registerType(
|
||||
|
@ -48,6 +53,15 @@ export class DashboardPlugin
|
|||
core.capabilities.registerProvider(capabilitiesProvider);
|
||||
|
||||
registerDashboardUsageCollector(plugins.usageCollection, plugins.embeddable);
|
||||
|
||||
(async () => {
|
||||
const [, startPlugins] = await core.getStartServices();
|
||||
|
||||
plugins.embeddable.registerEmbeddableFactory(
|
||||
dashboardPersistableStateServiceFactory(startPlugins.embeddable)
|
||||
);
|
||||
})();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,13 +6,39 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SavedObjectUnsanitizedDoc } from 'kibana/server';
|
||||
import { SavedObjectReference, SavedObjectUnsanitizedDoc } from 'kibana/server';
|
||||
import { savedObjectsServiceMock } from '../../../../core/server/mocks';
|
||||
import { createEmbeddableSetupMock } from '../../../embeddable/server/mocks';
|
||||
import { createDashboardSavedObjectTypeMigrations } from './dashboard_migrations';
|
||||
import { DashboardDoc730ToLatest } from '../../common';
|
||||
import {
|
||||
createExtract,
|
||||
createInject,
|
||||
} from '../../common/embeddable/dashboard_container_persistable_state';
|
||||
import { EmbeddableStateWithType } from 'src/plugins/embeddable/common';
|
||||
|
||||
const embeddableSetupMock = createEmbeddableSetupMock();
|
||||
const extract = createExtract(embeddableSetupMock);
|
||||
const inject = createInject(embeddableSetupMock);
|
||||
const extractImplementation = (state: EmbeddableStateWithType) => {
|
||||
if (state.type === 'dashboard') {
|
||||
return extract(state);
|
||||
}
|
||||
return { state, references: [] };
|
||||
};
|
||||
const injectImplementation = (
|
||||
state: EmbeddableStateWithType,
|
||||
references: SavedObjectReference[]
|
||||
) => {
|
||||
if (state.type === 'dashboard') {
|
||||
return inject(state, references);
|
||||
}
|
||||
|
||||
return state;
|
||||
};
|
||||
embeddableSetupMock.extract.mockImplementation(extractImplementation);
|
||||
embeddableSetupMock.inject.mockImplementation(injectImplementation);
|
||||
|
||||
const migrations = createDashboardSavedObjectTypeMigrations({
|
||||
embeddable: embeddableSetupMock,
|
||||
});
|
||||
|
@ -25,10 +51,10 @@ describe('dashboard', () => {
|
|||
|
||||
test('skips error on empty object', () => {
|
||||
expect(migration({} as SavedObjectUnsanitizedDoc, contextMock)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"references": Array [],
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"references": Array [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('skips errors when searchSourceJSON is null', () => {
|
||||
|
@ -45,29 +71,29 @@ Object {
|
|||
};
|
||||
const migratedDoc = migration(doc, contextMock);
|
||||
expect(migratedDoc).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": null,
|
||||
},
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": null,
|
||||
},
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('skips errors when searchSourceJSON is undefined', () => {
|
||||
|
@ -84,29 +110,29 @@ Object {
|
|||
};
|
||||
const migratedDoc = migration(doc, contextMock);
|
||||
expect(migratedDoc).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": undefined,
|
||||
},
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": undefined,
|
||||
},
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('skips error when searchSourceJSON is not a string', () => {
|
||||
|
@ -122,29 +148,29 @@ Object {
|
|||
},
|
||||
};
|
||||
expect(migration(doc, contextMock)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": 123,
|
||||
},
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": 123,
|
||||
},
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('skips error when searchSourceJSON is invalid json', () => {
|
||||
|
@ -160,29 +186,29 @@ Object {
|
|||
},
|
||||
};
|
||||
expect(migration(doc, contextMock)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": "{abc123}",
|
||||
},
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": "{abc123}",
|
||||
},
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('skips error when "index" and "filter" is missing from searchSourceJSON', () => {
|
||||
|
@ -199,29 +225,29 @@ Object {
|
|||
};
|
||||
const migratedDoc = migration(doc, contextMock);
|
||||
expect(migratedDoc).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": "{\\"bar\\":true}",
|
||||
},
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": "{\\"bar\\":true}",
|
||||
},
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('extracts "index" attribute from doc', () => {
|
||||
|
@ -238,34 +264,34 @@ Object {
|
|||
};
|
||||
const migratedDoc = migration(doc, contextMock);
|
||||
expect(migratedDoc).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": "{\\"bar\\":true,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.index\\"}",
|
||||
},
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "pattern*",
|
||||
"name": "kibanaSavedObjectMeta.searchSourceJSON.index",
|
||||
"type": "index-pattern",
|
||||
},
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": "{\\"bar\\":true,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.index\\"}",
|
||||
},
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "pattern*",
|
||||
"name": "kibanaSavedObjectMeta.searchSourceJSON.index",
|
||||
"type": "index-pattern",
|
||||
},
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('extracts index patterns from filter', () => {
|
||||
|
@ -293,34 +319,34 @@ Object {
|
|||
const migratedDoc = migration(doc, contextMock);
|
||||
|
||||
expect(migratedDoc).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": "{\\"bar\\":true,\\"filter\\":[{\\"meta\\":{\\"foo\\":true,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\\"}}]}",
|
||||
},
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "my-index",
|
||||
"name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index",
|
||||
"type": "index-pattern",
|
||||
},
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": "{\\"bar\\":true,\\"filter\\":[{\\"meta\\":{\\"foo\\":true,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\\"}}]}",
|
||||
},
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "my-index",
|
||||
"name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index",
|
||||
"type": "index-pattern",
|
||||
},
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('skips error when panelsJSON is not a string', () => {
|
||||
|
@ -331,14 +357,14 @@ Object {
|
|||
},
|
||||
} as SavedObjectUnsanitizedDoc;
|
||||
expect(migration(doc, contextMock)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"panelsJSON": 123,
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [],
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"panelsJSON": 123,
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('skips error when panelsJSON is not valid JSON', () => {
|
||||
|
@ -349,14 +375,14 @@ Object {
|
|||
},
|
||||
} as SavedObjectUnsanitizedDoc;
|
||||
expect(migration(doc, contextMock)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"panelsJSON": "{123abc}",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [],
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"panelsJSON": "{123abc}",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('skips panelsJSON when its not an array', () => {
|
||||
|
@ -367,14 +393,14 @@ Object {
|
|||
},
|
||||
} as SavedObjectUnsanitizedDoc;
|
||||
expect(migration(doc, contextMock)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"panelsJSON": "{}",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [],
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"panelsJSON": "{}",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('skips error when a panel is missing "type" attribute', () => {
|
||||
|
@ -385,14 +411,14 @@ Object {
|
|||
},
|
||||
} as SavedObjectUnsanitizedDoc;
|
||||
expect(migration(doc, contextMock)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"panelsJSON": "[{\\"id\\":\\"123\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [],
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"panelsJSON": "[{\\"id\\":\\"123\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('skips error when a panel is missing "id" attribute', () => {
|
||||
|
@ -403,14 +429,14 @@ Object {
|
|||
},
|
||||
} as SavedObjectUnsanitizedDoc;
|
||||
expect(migration(doc, contextMock)).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"panelsJSON": "[{\\"type\\":\\"visualization\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [],
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"panelsJSON": "[{\\"type\\":\\"visualization\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('extract panel references from doc', () => {
|
||||
|
@ -423,25 +449,25 @@ Object {
|
|||
} as SavedObjectUnsanitizedDoc;
|
||||
const migratedDoc = migration(doc, contextMock);
|
||||
expect(migratedDoc).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"panelsJSON": "[{\\"foo\\":true,\\"panelRefName\\":\\"panel_0\\"},{\\"bar\\":true,\\"panelRefName\\":\\"panel_1\\"}]",
|
||||
},
|
||||
"id": "1",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "1",
|
||||
"name": "panel_0",
|
||||
"type": "visualization",
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"name": "panel_1",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -475,19 +501,57 @@ Object {
|
|||
|
||||
test('should migrate 7.3.0 doc without embeddable state to extract', () => {
|
||||
const newDoc = migration(doc, contextMock);
|
||||
expect(newDoc).toEqual(doc);
|
||||
expect(newDoc).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"attributes": Object {
|
||||
"description": "",
|
||||
"kibanaSavedObjectMeta": Object {
|
||||
"searchSourceJSON": "{\\"query\\":{\\"language\\":\\"kuery\\",\\"query\\":\\"\\"},\\"filter\\":[{\\"query\\":{\\"match_phrase\\":{\\"machine.os.keyword\\":\\"osx\\"}},\\"$state\\":{\\"store\\":\\"appState\\"},\\"meta\\":{\\"type\\":\\"phrase\\",\\"key\\":\\"machine.os.keyword\\",\\"params\\":{\\"query\\":\\"osx\\"},\\"disabled\\":false,\\"negate\\":false,\\"alias\\":null,\\"indexRefName\\":\\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\\"}}]}",
|
||||
},
|
||||
"optionsJSON": "{\\"useMargins\\":true,\\"hidePanelTitles\\":false}",
|
||||
"panelsJSON": "[{\\"version\\":\\"7.9.3\\",\\"type\\":\\"visualization\\",\\"gridData\\":{\\"x\\":0,\\"y\\":0,\\"w\\":24,\\"h\\":15,\\"i\\":\\"82fa0882-9f9e-476a-bbb9-03555e5ced91\\"},\\"panelIndex\\":\\"82fa0882-9f9e-476a-bbb9-03555e5ced91\\",\\"embeddableConfig\\":{\\"enhancements\\":{\\"dynamicActions\\":{\\"events\\":[]}}},\\"panelRefName\\":\\"panel_82fa0882-9f9e-476a-bbb9-03555e5ced91\\"}]",
|
||||
"timeRestore": false,
|
||||
"title": "Dashboard A",
|
||||
"version": 1,
|
||||
},
|
||||
"id": "376e6260-1f5e-11eb-91aa-7b6d5f8a61d6",
|
||||
"references": Array [
|
||||
Object {
|
||||
"id": "90943e30-9a47-11e8-b64d-95841ca0b247",
|
||||
"name": "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index",
|
||||
"type": "index-pattern",
|
||||
},
|
||||
Object {
|
||||
"id": "14e2e710-4258-11e8-b3aa-73fdaf54bfc9",
|
||||
"name": "82fa0882-9f9e-476a-bbb9-03555e5ced91:panel_82fa0882-9f9e-476a-bbb9-03555e5ced91",
|
||||
"type": "visualization",
|
||||
},
|
||||
],
|
||||
"type": "dashboard",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test('should migrate 7.3.0 doc and extract embeddable state', () => {
|
||||
embeddableSetupMock.extract.mockImplementationOnce((state) => ({
|
||||
state: { ...state, __extracted: true },
|
||||
references: [{ id: '__new', name: '__newRefName', type: '__newType' }],
|
||||
}));
|
||||
embeddableSetupMock.extract.mockImplementation((state) => {
|
||||
const stateAndReferences = extractImplementation(state);
|
||||
const { references } = stateAndReferences;
|
||||
let { state: newState } = stateAndReferences;
|
||||
|
||||
if (state.enhancements !== undefined && Object.keys(state.enhancements).length !== 0) {
|
||||
newState = { ...state, __extracted: true } as any;
|
||||
references.push({ id: '__new', name: '__newRefName', type: '__newType' });
|
||||
}
|
||||
|
||||
return { state: newState, references };
|
||||
});
|
||||
|
||||
const newDoc = migration(doc, contextMock);
|
||||
expect(newDoc).not.toEqual(doc);
|
||||
expect(newDoc.references).toHaveLength(doc.references.length + 1);
|
||||
expect(JSON.parse(newDoc.attributes.panelsJSON)[0].embeddableConfig.__extracted).toBe(true);
|
||||
|
||||
embeddableSetupMock.extract.mockImplementation(extractImplementation);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EmbeddableServerPlugin, EmbeddableSetup } from './plugin';
|
||||
import { EmbeddableServerPlugin, EmbeddableSetup, EmbeddableStart } from './plugin';
|
||||
|
||||
export { EmbeddableSetup };
|
||||
export { EmbeddableSetup, EmbeddableStart };
|
||||
|
||||
export { EnhancementRegistryDefinition, EmbeddableRegistryDefinition } from './types';
|
||||
|
||||
|
|
|
@ -29,6 +29,11 @@ export interface EmbeddableSetup extends PersistableStateService<EmbeddableState
|
|||
registerEnhancement: (enhancement: EnhancementRegistryDefinition) => void;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "EmbeddableStart" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type EmbeddableStart = PersistableStateService<EmbeddableStateWithType>;
|
||||
|
||||
// Warning: (ae-forgotten-export) The symbol "SerializableState" needs to be exported by the entry point index.d.ts
|
||||
// Warning: (ae-missing-release-tag) "EnhancementRegistryDefinition" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
|
|
|
@ -324,7 +324,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
references: [
|
||||
{
|
||||
id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab',
|
||||
name: 'panel_0',
|
||||
name: '1:panel_1',
|
||||
type: 'visualization',
|
||||
},
|
||||
],
|
||||
|
@ -384,7 +384,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
references: [
|
||||
{
|
||||
id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab',
|
||||
name: 'panel_0',
|
||||
name: '1:panel_1',
|
||||
type: 'visualization',
|
||||
},
|
||||
],
|
||||
|
@ -449,7 +449,7 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
references: [
|
||||
{
|
||||
id: 'dd7caf20-9efd-11e7-acb3-3dab96693fab',
|
||||
name: 'panel_0',
|
||||
name: '1:panel_1',
|
||||
type: 'visualization',
|
||||
},
|
||||
],
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue