diff --git a/src/legacy/core_plugins/kibana/public/dashboard/panel/__snapshots__/dashboard_panel.test.js.snap b/src/legacy/core_plugins/kibana/public/dashboard/panel/__snapshots__/dashboard_panel.test.tsx.snap similarity index 100% rename from src/legacy/core_plugins/kibana/public/dashboard/panel/__snapshots__/dashboard_panel.test.js.snap rename to src/legacy/core_plugins/kibana/public/dashboard/panel/__snapshots__/dashboard_panel.test.tsx.snap diff --git a/src/legacy/core_plugins/kibana/public/dashboard/panel/__tests__/panel_state.js b/src/legacy/core_plugins/kibana/public/dashboard/panel/__tests__/panel_state.ts similarity index 79% rename from src/legacy/core_plugins/kibana/public/dashboard/panel/__tests__/panel_state.js rename to src/legacy/core_plugins/kibana/public/dashboard/panel/__tests__/panel_state.ts index df04107c45fd7..e6162184145eb 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/panel/__tests__/panel_state.js +++ b/src/legacy/core_plugins/kibana/public/dashboard/panel/__tests__/panel_state.ts @@ -18,19 +18,29 @@ */ import expect from 'expect.js'; - +import { PanelState } from '../../selectors'; import { createPanelState } from '../panel_state'; -function createPanelWithDimensions(x, y, w, h) { +function createPanelWithDimensions(x: number, y: number, w: number, h: number): PanelState { return { + id: 'foo', + version: '6.3.0', + type: 'bar', + panelIndex: 'test', + title: 'test title', gridData: { - x, y, w, h - } + x, + y, + w, + h, + i: 'an id', + }, + embeddableConfig: {}, }; } -describe('Panel state', function () { - it('finds a spot on the right', function () { +describe('Panel state', () => { + it('finds a spot on the right', () => { // Default setup after a single panel, of default size, is on the grid const panels = [createPanelWithDimensions(0, 0, 24, 30)]; @@ -39,7 +49,7 @@ describe('Panel state', function () { expect(panel.gridData.y).to.equal(0); }); - it('finds a spot on the right when the panel is taller than any other panel on the grid', function () { + it('finds a spot on the right when the panel is taller than any other panel on the grid', () => { // Should be a little empty spot on the right. const panels = [ createPanelWithDimensions(0, 0, 24, 45), @@ -51,7 +61,7 @@ describe('Panel state', function () { expect(panel.gridData.y).to.equal(30); }); - it('finds an empty spot in the middle of the grid', function () { + it('finds an empty spot in the middle of the grid', () => { const panels = [ createPanelWithDimensions(0, 0, 48, 5), createPanelWithDimensions(0, 5, 4, 30), diff --git a/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel.test.js b/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel.test.tsx similarity index 64% rename from src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel.test.js rename to src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel.test.tsx index 26fac7180850b..e6e0cf292e655 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel.test.js +++ b/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel.test.tsx @@ -17,38 +17,28 @@ * under the License. */ -import React from 'react'; +// TODO: remove this when EUI supports types for this. +// @ts-ignore: implicit any for JS file +import { takeMountedSnapshot } from '@elastic/eui/lib/test'; import _ from 'lodash'; +import React from 'react'; +import { Provider } from 'react-redux'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; -import { DashboardPanel } from './dashboard_panel'; -import { DashboardViewMode } from '../dashboard_view_mode'; -import { PanelError } from '../panel/panel_error'; import { store } from '../../store'; +// @ts-ignore: implicit any for JS file import { getEmbeddableFactoryMock } from '../__tests__/get_embeddable_factories_mock'; +import { embeddableIsInitialized, setPanels, updateTimeRange, updateViewMode } from '../actions'; +import { DashboardViewMode } from '../dashboard_view_mode'; +import { DashboardPanel, DashboardPanelUiProps } from './dashboard_panel'; -import { - updateViewMode, - setPanels, - updateTimeRange, - embeddableIsInitialized, -} from '../actions'; -import { Provider } from 'react-redux'; - -import { - takeMountedSnapshot, -} from '@elastic/eui/lib/test'; +import { PanelError } from './panel_error'; -function getProps(props = {}) { +function getProps(props = {}): DashboardPanelUiProps { const defaultTestProps = { panel: { panelIndex: 'foo1' }, viewOnlyMode: false, - destroy: () => {}, initialized: true, lastReloadRequestTime: 0, - embeddableIsInitialized: () => {}, - embeddableIsInitializing: () => {}, - embeddableStateChanged: () => {}, - embeddableError: () => {}, embeddableFactory: getEmbeddableFactoryMock(), }; return _.defaultsDeep(props, defaultTestProps); @@ -57,22 +47,47 @@ function getProps(props = {}) { beforeAll(() => { store.dispatch(updateTimeRange({ to: 'now', from: 'now-15m' })); store.dispatch(updateViewMode(DashboardViewMode.EDIT)); - 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', + }, + }, + }) + ); const metadata = { title: 'my embeddable title', editUrl: 'editme' }; store.dispatch(embeddableIsInitialized({ metadata, panelId: 'foo1' })); }); test('DashboardPanel matches snapshot', () => { - const component = mountWithIntl(); + const component = mountWithIntl( + + + + ); expect(takeMountedSnapshot(component)).toMatchSnapshot(); }); test('renders an error when error prop is passed', () => { const props = getProps({ - error: 'Simulated error' + error: 'Simulated error', }); - const component = mountWithIntl(); + const component = mountWithIntl( + + + + ); const panelError = component.find(PanelError); expect(panelError.length).toBe(1); }); diff --git a/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel.js b/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel.tsx similarity index 57% rename from src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel.js rename to src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel.tsx index a36c4ba36995d..9ac8b3c49780a 100644 --- a/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel.js +++ b/src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel.tsx @@ -17,34 +17,68 @@ * under the License. */ -import React from 'react'; -import PropTypes from 'prop-types'; -import { injectI18n } from '@kbn/i18n/react'; +import { EuiLoadingChart, EuiPanel } from '@elastic/eui'; +import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; import classNames from 'classnames'; import _ from 'lodash'; - -import { PanelHeader } from './panel_header'; +import React from 'react'; +import { + ContainerState, + Embeddable, + EmbeddableFactory, + EmbeddableMetadata, + EmbeddableState, +} from 'ui/embeddable'; +import { EmbeddableErrorAction } from '../actions'; +import { PanelId, PanelState } from '../selectors'; import { PanelError } from './panel_error'; +import { PanelHeader } from './panel_header'; -import { - EuiPanel, - EuiLoadingChart, -} from '@elastic/eui'; +export interface DashboardPanelProps { + viewOnlyMode: boolean; + onPanelFocused?: (panelIndex: PanelId) => {}; + onPanelBlurred?: (panelIndex: PanelId) => {}; + error?: string | object; + destroy: () => void; + containerState: ContainerState; + embeddableFactory: EmbeddableFactory; + lastReloadRequestTime?: number; + embeddableStateChanged: (embeddableStateChanges: EmbeddableState) => void; + embeddableIsInitialized: (embeddableIsInitializing: EmbeddableMetadata) => void; + embeddableError: (errorMessage: EmbeddableErrorAction) => void; + embeddableIsInitializing: () => void; + initialized: boolean; + panel: PanelState; + className?: string; +} + +export interface DashboardPanelUiProps extends DashboardPanelProps { + intl: InjectedIntl; +} -class DashboardPanelUi extends React.Component { - constructor(props) { +interface State { + error: string | null; +} + +class DashboardPanelUi extends React.Component { + [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;