1717 * under the License.
1818 */
1919
20- import React from 'react' ;
21- import PropTypes from 'prop-types' ;
2220import { injectI18n } from '@kbn/i18n/react' ;
23- import _ from 'lodash' ;
24- import ReactGridLayout from 'react-grid-layout' ;
2521import classNames from 'classnames' ;
22+ import _ from 'lodash' ;
23+ import React from 'react' ;
24+ import ReactGridLayout , { Layout } from 'react-grid-layout' ;
2625import 'react-grid-layout/css/styles.css' ;
2726import '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 ' ;
3231import { toastNotifications } from 'ui/notify' ;
3332import {
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 } ;
4143let 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 } ;
107117const 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-
275300export const DashboardGrid = injectI18n ( DashboardGridUi ) ;
0 commit comments