{
+ [panel: string]: any;
+ public mounted: boolean;
+ public embeddable!: Embeddable;
+ constructor(props: DashboardPanelUiProps) {
super(props);
this.state = {
- error: props.embeddableFactory ? null : props.intl.formatMessage({
- id: 'kbn.dashboard.panel.noEmbeddableFactoryErrorMessage',
- defaultMessage: 'No factory found for embeddable',
- }),
+ error: props.embeddableFactory
+ ? null
+ : props.intl.formatMessage({
+ id: 'kbn.dashboard.panel.noEmbeddableFactoryErrorMessage',
+ defaultMessage: 'No factory found for embeddable',
+ }),
};
this.mounted = false;
}
- async componentDidMount() {
+ public async componentDidMount() {
this.mounted = true;
const {
initialized,
@@ -58,8 +92,9 @@ class DashboardPanelUi extends React.Component {
if (!initialized) {
embeddableIsInitializing();
- embeddableFactory.create(panel, embeddableStateChanged)
- .then((embeddable) => {
+ embeddableFactory
+ .create(panel, embeddableStateChanged)
+ .then((embeddable: Embeddable) => {
if (this.mounted) {
this.embeddable = embeddable;
embeddableIsInitialized(embeddable.metadata);
@@ -68,7 +103,7 @@ class DashboardPanelUi extends React.Component {
embeddable.destroy();
}
})
- .catch((error) => {
+ .catch((error: { message: EmbeddableErrorAction }) => {
if (this.mounted) {
embeddableError(error.message);
}
@@ -76,7 +111,7 @@ class DashboardPanelUi extends React.Component {
}
}
- componentWillUnmount() {
+ public componentWillUnmount() {
this.props.destroy();
this.mounted = false;
if (this.embeddable) {
@@ -84,21 +119,21 @@ class DashboardPanelUi extends React.Component {
}
}
- onFocus = () => {
+ public onFocus = () => {
const { onPanelFocused, panel } = this.props;
if (onPanelFocused) {
onPanelFocused(panel.panelIndex);
}
};
- onBlur = () => {
+ public onBlur = () => {
const { onPanelBlurred, panel } = this.props;
if (onPanelBlurred) {
onPanelBlurred(panel.panelIndex);
}
};
- renderEmbeddableViewport() {
+ public renderEmbeddableViewport() {
const classes = classNames('panel-content', {
'panel-content-isLoading': !this.props.initialized,
});
@@ -107,16 +142,14 @@ class DashboardPanelUi extends React.Component {
this.panelElement = panelElement}
+ ref={panelElement => (this.panelElement = panelElement)}
>
- {!this.props.initialized && (
-
- )}
+ {!this.props.initialized && }
);
}
- shouldComponentUpdate(nextProps) {
+ public shouldComponentUpdate(nextProps: DashboardPanelUiProps) {
if (this.embeddable && !_.isEqual(nextProps.containerState, this.props.containerState)) {
this.embeddable.onContainerStateChanged(nextProps.containerState);
}
@@ -125,27 +158,26 @@ class DashboardPanelUi extends React.Component {
this.embeddable.reload();
}
- return nextProps.error !== this.props.error ||
- nextProps.initialized !== this.props.initialized;
+ return nextProps.error !== this.props.error || nextProps.initialized !== this.props.initialized;
}
- renderEmbeddedError() {
+ public renderEmbeddedError() {
return ;
}
- renderContent() {
+ public renderContent() {
const { error } = this.props;
if (error) {
- return this.renderEmbeddedError(error);
+ return this.renderEmbeddedError();
} else {
return this.renderEmbeddableViewport();
}
}
- render() {
+ public render() {
const { viewOnlyMode, panel } = this.props;
const classes = classNames('dshPanel', this.props.className, {
- 'dshPanel--editing': !viewOnlyMode
+ 'dshPanel--editing': !viewOnlyMode,
});
return (
-
+
{this.renderContent()}
@@ -166,35 +195,4 @@ class DashboardPanelUi extends React.Component {
}
}
-DashboardPanelUi.propTypes = {
- viewOnlyMode: PropTypes.bool.isRequired,
- onPanelFocused: PropTypes.func,
- onPanelBlurred: PropTypes.func,
- error: PropTypes.oneOfType([
- PropTypes.string,
- PropTypes.object
- ]),
- destroy: PropTypes.func.isRequired,
- containerState: PropTypes.shape({
- timeRange: PropTypes.object,
- refreshConfig: PropTypes.object,
- filters: PropTypes.array,
- query: PropTypes.object,
- embeddableCustomization: PropTypes.object,
- hidePanelTitles: PropTypes.bool.isRequired,
- }),
- embeddableFactory: PropTypes.shape({
- create: PropTypes.func,
- }).isRequired,
- lastReloadRequestTime: PropTypes.number.isRequired,
- embeddableStateChanged: PropTypes.func.isRequired,
- embeddableIsInitialized: PropTypes.func.isRequired,
- embeddableError: PropTypes.func.isRequired,
- embeddableIsInitializing: PropTypes.func.isRequired,
- initialized: PropTypes.bool.isRequired,
- panel: PropTypes.shape({
- panelIndex: PropTypes.string,
- }).isRequired,
-};
-
export const DashboardPanel = injectI18n(DashboardPanelUi);
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.test.js b/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.test.tsx
similarity index 72%
rename from src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.test.js
rename to src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.test.tsx
index cb532f1a48e38..939bf4c04ae0e 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.test.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.test.tsx
@@ -17,21 +17,22 @@
* under the License.
*/
-import React from 'react';
import _ from 'lodash';
+import React from 'react';
+import { Provider } from 'react-redux';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
-import { DashboardPanelContainer } from './dashboard_panel_container';
+import { store } from '../../store';
+// @ts-ignore: implicit for any JS file
+import { getEmbeddableFactoryMock } from '../__tests__/get_embeddable_factories_mock';
+import { setPanels, updateTimeRange, updateViewMode } from '../actions';
import { DashboardViewMode } from '../dashboard_view_mode';
import { PanelError } from '../panel/panel_error';
-import { store } from '../../store';
import {
- updateViewMode,
- setPanels, updateTimeRange,
-} from '../actions';
-import { Provider } from 'react-redux';
-import { getEmbeddableFactoryMock } from '../__tests__/get_embeddable_factories_mock';
+ DashboardPanelContainer,
+ DashboardPanelContainerOwnProps,
+} from './dashboard_panel_container';
-function getProps(props = {}) {
+function getProps(props = {}): DashboardPanelContainerOwnProps {
const defaultTestProps = {
panelId: 'foo1',
embeddableFactory: getEmbeddableFactoryMock(),
@@ -42,17 +43,38 @@ function getProps(props = {}) {
beforeAll(() => {
store.dispatch(updateViewMode(DashboardViewMode.EDIT));
store.dispatch(updateTimeRange({ to: 'now', from: 'now-15m' }));
- store.dispatch(setPanels({ 'foo1': { panelIndex: 'foo1' } }));
+ store.dispatch(
+ setPanels({
+ foo1: {
+ panelIndex: 'foo1',
+ id: 'hi',
+ version: '123',
+ type: 'viz',
+ embeddableConfig: {},
+ gridData: {
+ x: 1,
+ y: 1,
+ w: 1,
+ h: 1,
+ i: 'hi',
+ },
+ },
+ })
+ );
});
-test('renders an error when embeddableFactory.create throws an error', (done) => {
+test('renders an error when embeddableFactory.create throws an error', done => {
const props = getProps();
props.embeddableFactory.create = () => {
return new Promise(() => {
throw new Error('simulated error');
});
};
- const component = mountWithIntl();
+ const component = mountWithIntl(
+
+
+
+ );
setTimeout(() => {
component.update();
const panelError = component.find(PanelError);
@@ -60,4 +82,3 @@ test('renders an error when embeddableFactory.create throws an error', (done) =>
done();
}, 0);
});
-
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.js b/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.ts
similarity index 50%
rename from src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.js
rename to src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.ts
index 4ab33cec8d40c..f21dbe4b13e21 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel_container.ts
@@ -17,26 +17,66 @@
* under the License.
*/
-import { connect } from 'react-redux';
-import PropTypes from 'prop-types';
import { i18n } from '@kbn/i18n';
-
-import { DashboardPanel } from './dashboard_panel';
-import { DashboardViewMode } from '../dashboard_view_mode';
-
+import { connect } from 'react-redux';
+import { Action } from 'redux-actions';
+import { ThunkDispatch } from 'redux-thunk';
+import {
+ ContainerState,
+ EmbeddableFactory,
+ EmbeddableMetadata,
+ EmbeddableState,
+} from 'ui/embeddable';
+import { CoreKibanaState } from '../../selectors';
import {
- deletePanel, embeddableError, embeddableIsInitialized, embeddableIsInitializing, embeddableStateChanged,
+ deletePanel,
+ embeddableError,
+ EmbeddableErrorAction,
+ embeddableIsInitialized,
+ embeddableIsInitializing,
+ embeddableStateChanged,
} from '../actions';
-
+import { DashboardViewMode } from '../dashboard_view_mode';
import {
+ getContainerState,
getEmbeddable,
+ getEmbeddableError,
+ getEmbeddableInitialized,
getFullScreenMode,
+ getPanel,
+ getPanelType,
getViewMode,
- getEmbeddableError,
- getPanelType, getContainerState, getPanel, getEmbeddableInitialized,
+ PanelId,
+ PanelState,
} from '../selectors';
+import { DashboardPanel } from './dashboard_panel';
+
+export interface DashboardPanelContainerOwnProps {
+ panelId: PanelId;
+ embeddableFactory: EmbeddableFactory;
+}
-const mapStateToProps = ({ dashboard }, { embeddableFactory, panelId }) => {
+interface DashboardPanelContainerStateProps {
+ error?: string | object;
+ viewOnlyMode: boolean;
+ containerState: ContainerState;
+ initialized: boolean;
+ panel: PanelState;
+ lastReloadRequestTime?: number;
+}
+
+export interface DashboardPanelContainerDispatchProps {
+ destroy: () => void;
+ embeddableIsInitializing: () => void;
+ embeddableIsInitialized: (metadata: EmbeddableMetadata) => void;
+ embeddableStateChanged: (embeddableState: EmbeddableState) => void;
+ embeddableError: (errorMessage: EmbeddableErrorAction) => void;
+}
+
+const mapStateToProps = (
+ { dashboard }: CoreKibanaState,
+ { embeddableFactory, panelId }: DashboardPanelContainerOwnProps
+) => {
const embeddable = getEmbeddable(dashboard, panelId);
let error = null;
if (!embeddableFactory) {
@@ -60,35 +100,26 @@ const mapStateToProps = ({ dashboard }, { embeddableFactory, panelId }) => {
};
};
-const mapDispatchToProps = (dispatch, { panelId }) => ({
- destroy: () => (
- dispatch(deletePanel(panelId))
- ),
- embeddableIsInitializing: () => (
- dispatch(embeddableIsInitializing(panelId))
- ),
- embeddableIsInitialized: (metadata) => (
- dispatch(embeddableIsInitialized({ panelId, metadata }))
- ),
- embeddableStateChanged: (embeddableState) => (
- dispatch(embeddableStateChanged({ panelId, embeddableState }))
- ),
- embeddableError: (errorMessage) => (
- dispatch(embeddableError({ panelId, error: errorMessage }))
- )
+const mapDispatchToProps = (
+ dispatch: ThunkDispatch>,
+ { panelId }: DashboardPanelContainerOwnProps
+): DashboardPanelContainerDispatchProps => ({
+ destroy: () => dispatch(deletePanel(panelId)),
+ embeddableIsInitializing: () => dispatch(embeddableIsInitializing(panelId)),
+ embeddableIsInitialized: (metadata: EmbeddableMetadata) =>
+ dispatch(embeddableIsInitialized({ panelId, metadata })),
+ embeddableStateChanged: (embeddableState: EmbeddableState) =>
+ dispatch(embeddableStateChanged({ panelId, embeddableState })),
+ embeddableError: (errorMessage: EmbeddableErrorAction) =>
+ dispatch(embeddableError({ panelId, error: errorMessage })),
});
-export const DashboardPanelContainer = connect(
+export const DashboardPanelContainer = connect<
+ DashboardPanelContainerStateProps,
+ DashboardPanelContainerDispatchProps,
+ DashboardPanelContainerOwnProps,
+ CoreKibanaState
+>(
mapStateToProps,
mapDispatchToProps
)(DashboardPanel);
-
-DashboardPanelContainer.propTypes = {
- panelId: PropTypes.string.isRequired,
- /**
- * @type {EmbeddableFactory}
- */
- embeddableFactory: PropTypes.shape({
- create: PropTypes.func.isRequired,
- }).isRequired,
-};
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/panel/index.js b/src/legacy/core_plugins/kibana/public/dashboard/panel/index.ts
similarity index 100%
rename from src/legacy/core_plugins/kibana/public/dashboard/panel/index.js
rename to src/legacy/core_plugins/kibana/public/dashboard/panel/index.ts
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/panel/panel_utils.test.js b/src/legacy/core_plugins/kibana/public/dashboard/panel/panel_utils.test.js
index 73adb5a1f40f6..9f410ffbedcd6 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/panel/panel_utils.test.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/panel/panel_utils.test.js
@@ -17,13 +17,17 @@
* under the License.
*/
-jest.mock('ui/chrome',
+jest.mock(
+ 'ui/chrome',
() => ({
getKibanaVersion: () => '6.3.0',
- }), { virtual: true });
+ }),
+ { virtual: true }
+);
+import { DEFAULT_PANEL_HEIGHT, DEFAULT_PANEL_WIDTH } from '../dashboard_constants';
import { PanelUtils } from './panel_utils';
-import { DEFAULT_PANEL_WIDTH, DEFAULT_PANEL_HEIGHT } from '../dashboard_constants';
+import { createPanelState } from './panel_state';
test('parseVersion', () => {
const { major, minor } = PanelUtils.parseVersion('6.2.0');
@@ -33,8 +37,24 @@ test('parseVersion', () => {
test('convertPanelDataPre_6_1 gives supplies width and height when missing', () => {
const panelData = [
- { col: 3, id: 'foo1', row: 1, type: 'visualization', panelIndex: 1 },
- { col: 3, id: 'foo2', row: 1, size_x: 3, size_y: 2, type: 'visualization', panelIndex: 2 }
+ {
+ col: 3,
+ id: 'foo1',
+ row: 1,
+ type: 'visualization',
+ panelIndex: 1,
+ gridData: createPanelState,
+ },
+ {
+ col: 3,
+ id: 'foo2',
+ row: 1,
+ size_x: 3,
+ size_y: 2,
+ type: 'visualization',
+ panelIndex: 2,
+ gridData: createPanelState,
+ },
];
panelData.forEach(oldPanel => PanelUtils.convertPanelDataPre_6_1(oldPanel));
expect(panelData[0].gridData.w).toBe(DEFAULT_PANEL_WIDTH);
@@ -54,9 +74,9 @@ test('convertPanelDataPre_6_3 scales panel dimensions', () => {
x: 2,
y: 5,
},
- version: '6.2.0'
+ version: '6.2.0',
};
- const updatedPanel = PanelUtils.convertPanelDataPre_6_3(oldPanel);
+ const updatedPanel = PanelUtils.convertPanelDataPre_6_3(oldPanel, false);
expect(updatedPanel.gridData.w).toBe(28);
expect(updatedPanel.gridData.h).toBe(15);
expect(updatedPanel.gridData.x).toBe(8);
@@ -72,7 +92,7 @@ test('convertPanelDataPre_6_3 with margins scales panel dimensions', () => {
x: 2,
y: 5,
},
- version: '6.2.0'
+ version: '6.2.0',
};
const updatedPanel = PanelUtils.convertPanelDataPre_6_3(oldPanel, true);
expect(updatedPanel.gridData.w).toBe(28);
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/panel/panel_utils.js b/src/legacy/core_plugins/kibana/public/dashboard/panel/panel_utils.ts
similarity index 55%
rename from src/legacy/core_plugins/kibana/public/dashboard/panel/panel_utils.js
rename to src/legacy/core_plugins/kibana/public/dashboard/panel/panel_utils.ts
index aec24998f17b7..52485b48ce307 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/panel/panel_utils.js
+++ b/src/legacy/core_plugins/kibana/public/dashboard/panel/panel_utils.ts
@@ -17,25 +17,41 @@
* under the License.
*/
-import _ from 'lodash';
import { i18n } from '@kbn/i18n';
-import { DEFAULT_PANEL_WIDTH, DEFAULT_PANEL_HEIGHT } from '../dashboard_constants';
+import _ from 'lodash';
import chrome from 'ui/chrome';
+import { DEFAULT_PANEL_HEIGHT, DEFAULT_PANEL_WIDTH } from '../dashboard_constants';
+import { GridData, PanelState } from '../selectors';
const PANEL_HEIGHT_SCALE_FACTOR = 5;
const PANEL_HEIGHT_SCALE_FACTOR_WITH_MARGINS = 4;
const PANEL_WIDTH_SCALE_FACTOR = 4;
-export class PanelUtils {
+export interface SemanticVersion {
+ major: number;
+ minor: number;
+}
+export class PanelUtils {
// 6.1 switched from gridster to react grid. React grid uses different variables for tracking layout
- static convertPanelDataPre_6_1(panel) { // eslint-disable-line camelcase
+ public static convertPanelDataPre_6_1(panel: {
+ panelIndex: any; // earlier versions allowed panelIndex to be a number or a string
+ gridData: GridData;
+ col: number;
+ row: number;
+ size_x: number;
+ size_y: number;
+ version: string;
+ }): Partial {
['col', 'row'].forEach(key => {
if (!_.has(panel, key)) {
- throw new Error(i18n.translate('kbn.dashboard.panel.unableToMigratePanelDataForSixOneZeroErrorMessage', {
- defaultMessage: 'Unable to migrate panel data for "6.1.0" backwards compatibility, panel does not contain expected field: {key}',
- values: { key },
- }));
+ throw new Error(
+ i18n.translate('kbn.dashboard.panel.unableToMigratePanelDataForSixOneZeroErrorMessage', {
+ defaultMessage:
+ 'Unable to migrate panel data for "6.1.0" backwards compatibility, panel does not contain expected field: {key}',
+ values: { key },
+ })
+ );
}
});
@@ -44,7 +60,7 @@ export class PanelUtils {
y: panel.row - 1,
w: panel.size_x || DEFAULT_PANEL_WIDTH,
h: panel.size_y || DEFAULT_PANEL_HEIGHT,
- i: panel.panelIndex.toString()
+ i: panel.panelIndex.toString(),
};
panel.version = chrome.getKibanaVersion();
panel.panelIndex = panel.panelIndex.toString();
@@ -60,18 +76,32 @@ export class PanelUtils {
// 1) decrease column height from 100 to 20.
// 2) increase rows from 12 to 48
// Need to scale pre 6.3 panels so they maintain the same layout
- static convertPanelDataPre_6_3(panel, useMargins) { // eslint-disable-line camelcase
+ public static convertPanelDataPre_6_3(
+ panel: {
+ gridData: { w: number; x: number; h: number; y: number };
+ version: string;
+ },
+ useMargins: boolean
+ ) {
['w', 'x', 'h', 'y'].forEach(key => {
if (!_.has(panel.gridData, key)) {
- throw new Error(i18n.translate('kbn.dashboard.panel.unableToMigratePanelDataForSixThreeZeroErrorMessage', {
- defaultMessage: 'Unable to migrate panel data for "6.3.0" backwards compatibility, panel does not contain expected field: {key}',
- values: { key },
- }));
+ throw new Error(
+ i18n.translate(
+ 'kbn.dashboard.panel.unableToMigratePanelDataForSixThreeZeroErrorMessage',
+ {
+ defaultMessage:
+ 'Unable to migrate panel data for "6.3.0" backwards compatibility, panel does not contain expected field: {key}',
+ values: { key },
+ }
+ )
+ );
}
});
// see https://github.com/elastic/kibana/issues/20635 on why the scale factor changes when margins are being used
- const heightScaleFactor = useMargins ? PANEL_HEIGHT_SCALE_FACTOR_WITH_MARGINS : PANEL_HEIGHT_SCALE_FACTOR;
+ const heightScaleFactor = useMargins
+ ? PANEL_HEIGHT_SCALE_FACTOR_WITH_MARGINS
+ : PANEL_HEIGHT_SCALE_FACTOR;
panel.gridData.w = panel.gridData.w * PANEL_WIDTH_SCALE_FACTOR;
panel.gridData.x = panel.gridData.x * PANEL_WIDTH_SCALE_FACTOR;
@@ -82,38 +112,40 @@ export class PanelUtils {
return panel;
}
- static parseVersion(version = '6.0.0') {
+ public static parseVersion(version = '6.0.0'): SemanticVersion {
const versionSplit = version.split('.');
if (versionSplit.length < 3) {
- throw new Error(i18n.translate('kbn.dashboard.panel.invalidVersionErrorMessage', {
- defaultMessage: 'Invalid version, {version}, expected {semver}',
- values: {
- version,
- semver: '..',
- },
- }));
+ throw new Error(
+ i18n.translate('kbn.dashboard.panel.invalidVersionErrorMessage', {
+ defaultMessage: 'Invalid version, {version}, expected {semver}',
+ values: {
+ version,
+ semver: '..',
+ },
+ })
+ );
}
return {
major: parseInt(versionSplit[0], 10),
- minor: parseInt(versionSplit[1], 10)
+ minor: parseInt(versionSplit[1], 10),
};
}
- static initPanelIndexes(panels) {
+ public static initPanelIndexes(panels: PanelState[]): void {
// find the largest panelIndex in all the panels
let maxIndex = this.getMaxPanelIndex(panels);
// ensure that all panels have a panelIndex
- panels.forEach(function (panel) {
+ panels.forEach(panel => {
if (!panel.panelIndex) {
- panel.panelIndex = maxIndex++;
+ panel.panelIndex = (maxIndex++).toString();
}
});
}
- static getMaxPanelIndex(panels) {
- let maxId = panels.reduce(function (id, panel) {
- return Math.max(id, panel.panelIndex || id);
+ public static getMaxPanelIndex(panels: PanelState[]): number {
+ let maxId = panels.reduce((id, panel) => {
+ return Math.max(id, Number(panel.panelIndex || id));
}, 0);
return ++maxId;
}
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/reducers/embeddables.test.ts b/src/legacy/core_plugins/kibana/public/dashboard/reducers/embeddables.test.ts
index e85d197315d68..aa29740fa9d37 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/reducers/embeddables.test.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/reducers/embeddables.test.ts
@@ -43,11 +43,11 @@ describe('embeddableIsInitializing', () => {
test('clears the error', () => {
store.dispatch(embeddableIsInitializing('foo1'));
const initialized = getEmbeddableInitialized(store.getState(), 'foo1');
- expect(initialized).toBe(false);
+ expect(initialized).toEqual(false);
});
test('and clears the error', () => {
const error = getEmbeddableError(store.getState(), 'foo1');
- expect(error).toBe(undefined);
+ expect(error).toEqual(undefined);
});
});
diff --git a/src/legacy/core_plugins/kibana/public/dashboard/selectors/types.ts b/src/legacy/core_plugins/kibana/public/dashboard/selectors/types.ts
index abfdd9ec5bddb..3c9d391c266ce 100644
--- a/src/legacy/core_plugins/kibana/public/dashboard/selectors/types.ts
+++ b/src/legacy/core_plugins/kibana/public/dashboard/selectors/types.ts
@@ -48,7 +48,7 @@ export interface PanelState {
readonly id: SavedObjectId;
readonly version: string;
readonly type: string;
- readonly panelIndex: PanelId;
+ panelIndex: PanelId;
readonly embeddableConfig: any;
readonly gridData: GridData;
readonly title?: string;