Skip to content

Commit a2e7045

Browse files
committed
Merge remote-tracking branch 'origin/master' into feature/merge-code
2 parents 8946092 + ab8a2b1 commit a2e7045

File tree

17 files changed

+213
-145
lines changed

17 files changed

+213
-145
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
"@kbn/ui-framework": "1.0.0",
113113
"@types/json-stable-stringify": "^1.0.32",
114114
"@types/lodash.clonedeep": "^4.5.4",
115+
"@types/react-grid-layout": "^0.16.7",
115116
"@types/recompose": "^0.30.5",
116117
"JSONStream": "1.1.1",
117118
"abortcontroller-polyfill": "^1.1.9",

src/legacy/core_plugins/kibana/public/dashboard/dashboard_strings.js renamed to src/legacy/core_plugins/kibana/public/dashboard/dashboard_strings.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,13 @@ import { DashboardViewMode } from './dashboard_view_mode';
2727
* end of the title.
2828
* @returns {string} A title to display to the user based on the above parameters.
2929
*/
30-
export function getDashboardTitle(title, viewMode, isDirty) {
30+
export function getDashboardTitle(
31+
title: string,
32+
viewMode: DashboardViewMode,
33+
isDirty: boolean
34+
): string {
3135
const isEditMode = viewMode === DashboardViewMode.EDIT;
32-
let displayTitle;
36+
let displayTitle: string;
3337

3438
if (isEditMode && isDirty) {
3539
displayTitle = i18n.translate('kbn.dashboard.strings.dashboardUnsavedEditTitle', {

src/legacy/core_plugins/kibana/public/dashboard/grid/dashboard_grid.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,6 @@ test('adjusts z-index of focused panel to be higher than siblings', () => {
8888
const panelElements = component.find('Connect(InjectIntl(DashboardPanelUi))');
8989
panelElements.first().prop('onPanelFocused')('1');
9090
const [gridItem1, gridItem2] = component.update().findWhere(el => el.key() === '1' || el.key() === '2');
91-
expect(gridItem1.props.style.zIndex).toEqual('2');
91+
expect(gridItem1.props.style.zIndex).toEqual(2);
9292
expect(gridItem2.props.style.zIndex).toEqual('auto');
9393
});

src/legacy/core_plugins/kibana/public/dashboard/grid/dashboard_grid.js renamed to src/legacy/core_plugins/kibana/public/dashboard/grid/dashboard_grid.tsx

Lines changed: 89 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -17,35 +17,37 @@
1717
* under the License.
1818
*/
1919

20-
import React from 'react';
21-
import PropTypes from 'prop-types';
2220
import { injectI18n } from '@kbn/i18n/react';
23-
import _ from 'lodash';
24-
import ReactGridLayout from 'react-grid-layout';
2521
import classNames from 'classnames';
22+
import _ from 'lodash';
23+
import React from 'react';
24+
import ReactGridLayout, { Layout } from 'react-grid-layout';
2625
import 'react-grid-layout/css/styles.css';
2726
import 'react-resizable/css/styles.css';
2827

29-
import { PanelUtils } from '../panel/panel_utils';
30-
import { DashboardViewMode } from '../dashboard_view_mode';
31-
import { DashboardPanel } from '../panel';
28+
// @ts-ignore
29+
import sizeMe from 'react-sizeme';
30+
import { EmbeddableFactory } from 'ui/embeddable';
3231
import { toastNotifications } from 'ui/notify';
3332
import {
34-
DashboardConstants,
3533
DASHBOARD_GRID_COLUMN_COUNT,
3634
DASHBOARD_GRID_HEIGHT,
35+
DashboardConstants,
3736
} from '../dashboard_constants';
38-
import sizeMe from 'react-sizeme';
37+
import { DashboardViewMode } from '../dashboard_view_mode';
38+
import { DashboardPanel } from '../panel';
39+
import { PanelUtils } from '../panel/panel_utils';
40+
import { PanelState, PanelStateMap, Pre61PanelState } from '../selectors/types';
41+
import { GridData } from '../types';
3942

40-
const config = { monitorWidth: true };
4143
let lastValidGridSize = 0;
4244

4345
/**
4446
* This is a fix for a bug that stopped the browser window from automatically scrolling down when panels were made
4547
* taller than the current grid.
4648
* see https://github.com/elastic/kibana/issues/14710.
4749
*/
48-
function ensureWindowScrollsToBottom(layout, oldResizeItem, l, placeholder, event) {
50+
function ensureWindowScrollsToBottom(event: { clientY: number; pageY: number }) {
4951
// The buffer is to handle the case where the browser is maximized and it's impossible for the mouse to move below
5052
// the screen, out of the window. see https://github.com/elastic/kibana/issues/14737
5153
const WINDOW_BUFFER = 10;
@@ -62,6 +64,14 @@ function ResponsiveGrid({
6264
children,
6365
maximizedPanelId,
6466
useMargins,
67+
}: {
68+
size: { width: number };
69+
isViewMode: boolean;
70+
layout: Layout[];
71+
onLayoutChange: () => void;
72+
children: JSX.Element[];
73+
maximizedPanelId: string;
74+
useMargins: boolean;
6575
}) {
6676
// This is to prevent a bug where view mode changes when the panel is expanded. View mode changes will trigger
6777
// the grid to re-render, but when a panel is expanded, the size will be 0. Minimizing the panel won't cause the
@@ -94,8 +104,7 @@ function ResponsiveGrid({
94104
draggableHandle={isViewMode ? '.doesnt-exist' : '.dshPanel__dragger'}
95105
layout={layout}
96106
onLayoutChange={onLayoutChange}
97-
measureBeforeMount={false}
98-
onResize={ensureWindowScrollsToBottom}
107+
onResize={({}, {}, {}, {}, event) => ensureWindowScrollsToBottom(event)}
99108
>
100109
{children}
101110
</ReactGridLayout>
@@ -104,15 +113,43 @@ function ResponsiveGrid({
104113

105114
// Using sizeMe sets up the grid to be re-rendered automatically not only when the window size changes, but also
106115
// when the container size changes, so it works for Full Screen mode switches.
116+
const config = { monitorWidth: true };
107117
const ResponsiveSizedGrid = sizeMe(config)(ResponsiveGrid);
108118

119+
interface Props extends ReactIntl.InjectedIntlProps {
120+
panels: PanelStateMap;
121+
getEmbeddableFactory: (panelType: string) => EmbeddableFactory;
122+
dashboardViewMode: DashboardViewMode.EDIT | DashboardViewMode.VIEW;
123+
onPanelsUpdated: (updatedPanels: PanelStateMap) => void;
124+
maximizedPanelId?: string;
125+
useMargins: boolean;
126+
}
109127

110-
class DashboardGridUi extends React.Component {
111-
constructor(props) {
128+
interface State {
129+
focusedPanelIndex?: string;
130+
isLayoutInvalid: boolean;
131+
layout?: GridData[];
132+
}
133+
134+
interface PanelLayout extends Layout {
135+
i: string;
136+
}
137+
138+
class DashboardGridUi extends React.Component<Props, State> {
139+
// A mapping of panelIndexes to grid items so we can set the zIndex appropriately on the last focused
140+
// item.
141+
private gridItems = {} as { [key: string]: HTMLDivElement | null };
142+
143+
// A mapping of panel type to embeddable handlers. Because this function reaches out of react and into angular,
144+
// if done in the render method, it appears to be triggering a scope.apply, which appears to be trigging a setState
145+
// call inside TSVB visualizations. Moving the function out of render appears to fix the issue. See
146+
// https://github.com/elastic/kibana/issues/14802 for more info.
147+
// This is probably a better implementation anyway so the handlers are cached.
148+
// @type {Object.<string, EmbeddableFactory>}
149+
private embeddableFactoryMap: { [s: string]: EmbeddableFactory } = {};
150+
151+
constructor(props: Props) {
112152
super(props);
113-
// A mapping of panelIndexes to grid items so we can set the zIndex appropriately on the last focused
114-
// item.
115-
this.gridItems = {};
116153

117154
let isLayoutInvalid = false;
118155
let layout;
@@ -127,88 +164,83 @@ class DashboardGridUi extends React.Component {
127164
}),
128165
text: error.message,
129166
});
130-
window.location = `#${DashboardConstants.LANDING_PAGE_PATH}`;
167+
window.location.hash = DashboardConstants.LANDING_PAGE_PATH;
131168
}
132169
this.state = {
133170
focusedPanelIndex: undefined,
134171
layout,
135172
isLayoutInvalid,
136173
};
137-
138-
// A mapping of panel type to embeddable handlers. Because this function reaches out of react and into angular,
139-
// if done in the render method, it appears to be triggering a scope.apply, which appears to be trigging a setState
140-
// call inside TSVB visualizations. Moving the function out of render appears to fix the issue. See
141-
// https://github.com/elastic/kibana/issues/14802 for more info.
142-
// This is probably a better implementation anyway so the handlers are cached.
143-
// @type {Object.<string, EmbeddableFactory>}
144-
this.embeddableFactoryMap = {};
145174
}
146175

147-
buildLayoutFromPanels() {
176+
public buildLayoutFromPanels(): GridData[] {
148177
return _.map(this.props.panels, panel => {
149178
// panel version numbers added in 6.1. Any panel without version number is assumed to be 6.0.0
150-
const panelVersion = panel.version ? PanelUtils.parseVersion(panel.version) : PanelUtils.parseVersion('6.0.0');
179+
const panelVersion =
180+
'version' in panel
181+
? PanelUtils.parseVersion(panel.version)
182+
: PanelUtils.parseVersion('6.0.0');
151183

152184
if (panelVersion.major < 6 || (panelVersion.major === 6 && panelVersion.minor < 1)) {
153-
PanelUtils.convertPanelDataPre_6_1(panel);
185+
panel = PanelUtils.convertPanelDataPre_6_1(panel as Pre61PanelState);
154186
}
155187

156188
if (panelVersion.major < 6 || (panelVersion.major === 6 && panelVersion.minor < 3)) {
157-
PanelUtils.convertPanelDataPre_6_3(panel, this.props.useMargins);
189+
PanelUtils.convertPanelDataPre_6_3(panel as PanelState, this.props.useMargins);
158190
}
159191

160-
return panel.gridData;
192+
return (panel as PanelState).gridData;
161193
});
162194
}
163195

164-
createEmbeddableFactoriesMap(panels) {
196+
public createEmbeddableFactoriesMap(panels: PanelStateMap) {
165197
Object.values(panels).map(panel => {
166198
if (!this.embeddableFactoryMap[panel.type]) {
167199
this.embeddableFactoryMap[panel.type] = this.props.getEmbeddableFactory(panel.type);
168200
}
169201
});
170202
}
171203

172-
componentWillMount() {
204+
public componentWillMount() {
173205
this.createEmbeddableFactoriesMap(this.props.panels);
174206
}
175207

176-
componentWillReceiveProps(nextProps) {
208+
public componentWillReceiveProps(nextProps: Props) {
177209
this.createEmbeddableFactoriesMap(nextProps.panels);
178210
}
179211

180-
onLayoutChange = (layout) => {
212+
public onLayoutChange = (layout: PanelLayout[]) => {
181213
const { onPanelsUpdated, panels } = this.props;
182-
const updatedPanels = layout.reduce((updatedPanelsAcc, panelLayout) => {
183-
updatedPanelsAcc[panelLayout.i] = {
184-
...panels[panelLayout.i],
185-
panelIndex: panelLayout.i,
186-
gridData: _.pick(panelLayout, ['x', 'y', 'w', 'h', 'i'])
187-
};
188-
return updatedPanelsAcc;
189-
}, []);
214+
const updatedPanels = layout.reduce(
215+
(updatedPanelsAcc, panelLayout) => {
216+
updatedPanelsAcc[panelLayout.i] = {
217+
...panels[panelLayout.i],
218+
panelIndex: panelLayout.i,
219+
gridData: _.pick(panelLayout, ['x', 'y', 'w', 'h', 'i']),
220+
};
221+
return updatedPanelsAcc;
222+
},
223+
{} as PanelStateMap
224+
);
190225
onPanelsUpdated(updatedPanels);
191226
};
192227

193-
onPanelFocused = focusedPanelIndex => {
228+
public onPanelFocused = (focusedPanelIndex: string): void => {
194229
this.setState({ focusedPanelIndex });
195230
};
196231

197-
onPanelBlurred = blurredPanelIndex => {
232+
public onPanelBlurred = (blurredPanelIndex: string): void => {
198233
if (this.state.focusedPanelIndex === blurredPanelIndex) {
199234
this.setState({ focusedPanelIndex: undefined });
200235
}
201236
};
202237

203-
renderDOM() {
204-
const {
205-
panels,
206-
maximizedPanelId
207-
} = this.props;
238+
public renderDOM() {
239+
const { panels, maximizedPanelId } = this.props;
208240
const { focusedPanelIndex } = this.state;
209241

210242
// Part of our unofficial API - need to render in a consistent order for plugins.
211-
const panelsInOrder = Object.keys(panels).map(key => panels[key]);
243+
const panelsInOrder = Object.keys(panels).map((key: string) => panels[key] as PanelState);
212244
panelsInOrder.sort((panelA, panelB) => {
213245
if (panelA.gridData.y === panelB.gridData.y) {
214246
return panelA.gridData.x - panelB.gridData.x;
@@ -226,10 +258,12 @@ class DashboardGridUi extends React.Component {
226258
});
227259
return (
228260
<div
229-
style={{ zIndex: focusedPanelIndex === panel.panelIndex ? '2' : 'auto' }}
261+
style={{ zIndex: focusedPanelIndex === panel.panelIndex ? 2 : 'auto' }}
230262
className={classes}
231263
key={panel.panelIndex}
232-
ref={reactGridItem => { this.gridItems[panel.panelIndex] = reactGridItem; }}
264+
ref={reactGridItem => {
265+
this.gridItems[panel.panelIndex] = reactGridItem;
266+
}}
233267
>
234268
<DashboardPanel
235269
panelId={panel.panelIndex}
@@ -242,7 +276,7 @@ class DashboardGridUi extends React.Component {
242276
});
243277
}
244278

245-
render() {
279+
public render() {
246280
if (this.state.isLayoutInvalid) {
247281
return null;
248282
}
@@ -263,13 +297,4 @@ class DashboardGridUi extends React.Component {
263297
}
264298
}
265299

266-
DashboardGridUi.propTypes = {
267-
panels: PropTypes.object.isRequired,
268-
getEmbeddableFactory: PropTypes.func.isRequired,
269-
dashboardViewMode: PropTypes.oneOf([DashboardViewMode.EDIT, DashboardViewMode.VIEW]).isRequired,
270-
onPanelsUpdated: PropTypes.func.isRequired,
271-
maximizedPanelId: PropTypes.string,
272-
useMargins: PropTypes.bool.isRequired,
273-
};
274-
275300
export const DashboardGrid = injectI18n(DashboardGridUi);

src/legacy/core_plugins/kibana/public/dashboard/grid/dashboard_grid_container.js renamed to src/legacy/core_plugins/kibana/public/dashboard/grid/dashboard_grid_container.ts

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,36 @@
1818
*/
1919

2020
import { connect } from 'react-redux';
21-
import { DashboardGrid } from './dashboard_grid';
21+
import { Dispatch } from 'redux';
2222
import { updatePanels } from '../actions';
23-
import {
24-
getPanels,
25-
getViewMode,
26-
getUseMargins,
27-
} from '../selectors';
23+
import { getPanels, getUseMargins, getViewMode } from '../selectors';
24+
import { DashboardViewMode, PanelStateMap } from '../selectors/types';
25+
import { DashboardGrid } from './dashboard_grid';
26+
27+
interface DashboardGridContainerStateProps {
28+
panels: PanelStateMap;
29+
dashboardViewMode: DashboardViewMode;
30+
useMargins: boolean;
31+
}
2832

29-
const mapStateToProps = ({ dashboard }) => ({
33+
interface DashboardGridContainerDispatchProps {
34+
onPanelsUpdated(updatedPanels: PanelStateMap): void;
35+
}
36+
37+
const mapStateToProps = ({ dashboard }: any): any => ({
3038
panels: getPanels(dashboard),
3139
dashboardViewMode: getViewMode(dashboard),
3240
useMargins: getUseMargins(dashboard),
3341
});
3442

35-
const mapDispatchToProps = (dispatch) => ({
36-
onPanelsUpdated: updatedPanels => dispatch(updatePanels(updatedPanels)),
43+
const mapDispatchToProps = (dispatch: Dispatch) => ({
44+
onPanelsUpdated: (updatedPanels: PanelStateMap) => dispatch(updatePanels(updatedPanels)),
3745
});
3846

39-
export const DashboardGridContainer = connect(
47+
export const DashboardGridContainer = connect<
48+
DashboardGridContainerStateProps,
49+
DashboardGridContainerDispatchProps
50+
>(
4051
mapStateToProps,
4152
mapDispatchToProps
4253
)(DashboardGrid);
43-

src/legacy/core_plugins/kibana/public/dashboard/panel/dashboard_panel.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ import { PanelHeader } from './panel_header';
3636

3737
export interface DashboardPanelProps {
3838
viewOnlyMode: boolean;
39-
onPanelFocused?: (panelIndex: PanelId) => {};
40-
onPanelBlurred?: (panelIndex: PanelId) => {};
39+
onPanelFocused?: (panelIndex: PanelId) => void;
40+
onPanelBlurred?: (panelIndex: PanelId) => void;
4141
error?: string | object;
4242
destroy: () => void;
4343
containerState: ContainerState;

0 commit comments

Comments
 (0)