DashboardGrid.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import React from 'react';
  2. import ReactGridLayout from 'react-grid-layout';
  3. import {GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT} from 'app/core/constants';
  4. import {DashboardPanel} from './DashboardPanel';
  5. import {DashboardModel} from '../dashboard_model';
  6. import {PanelContainer} from './PanelContainer';
  7. import {PanelModel} from '../panel_model';
  8. import classNames from 'classnames';
  9. import sizeMe from 'react-sizeme';
  10. let lastGridWidth = 1200;
  11. function GridWrapper({size, layout, onLayoutChange, children, onDragStop, onResize, onResizeStop, onWidthChange, className}) {
  12. if (size.width === 0) {
  13. console.log('size is zero!');
  14. }
  15. const width = size.width > 0 ? size.width : lastGridWidth;
  16. if (width !== lastGridWidth) {
  17. onWidthChange();
  18. lastGridWidth = width;
  19. }
  20. return (
  21. <ReactGridLayout
  22. width={lastGridWidth}
  23. className={className}
  24. isDraggable={true}
  25. isResizable={true}
  26. measureBeforeMount={false}
  27. containerPadding={[0, 0]}
  28. useCSSTransforms={true}
  29. margin={[GRID_CELL_VMARGIN, GRID_CELL_VMARGIN]}
  30. cols={GRID_COLUMN_COUNT}
  31. rowHeight={GRID_CELL_HEIGHT}
  32. draggableHandle=".grid-drag-handle"
  33. layout={layout}
  34. onResize={onResize}
  35. onResizeStop={onResizeStop}
  36. onDragStop={onDragStop}
  37. onLayoutChange={onLayoutChange}>
  38. {children}
  39. </ReactGridLayout>
  40. );
  41. }
  42. const SizedReactLayoutGrid = sizeMe({monitorWidth: true})(GridWrapper);
  43. export interface DashboardGridProps {
  44. getPanelContainer: () => PanelContainer;
  45. }
  46. export class DashboardGrid extends React.Component<DashboardGridProps, any> {
  47. gridToPanelMap: any;
  48. panelContainer: PanelContainer;
  49. dashboard: DashboardModel;
  50. panelMap: {[id: string]: PanelModel};
  51. constructor(props) {
  52. super(props);
  53. this.panelContainer = this.props.getPanelContainer();
  54. this.onLayoutChange = this.onLayoutChange.bind(this);
  55. this.onResize = this.onResize.bind(this);
  56. this.onResizeStop = this.onResizeStop.bind(this);
  57. this.onDragStop = this.onDragStop.bind(this);
  58. this.onWidthChange = this.onWidthChange.bind(this);
  59. this.state = {animated: false};
  60. // subscribe to dashboard events
  61. this.dashboard = this.panelContainer.getDashboard();
  62. this.dashboard.on('panel-added', this.triggerForceUpdate.bind(this));
  63. this.dashboard.on('panel-removed', this.triggerForceUpdate.bind(this));
  64. this.dashboard.on('repeats-processed', this.triggerForceUpdate.bind(this));
  65. this.dashboard.on('view-mode-changed', this.triggerForceUpdate.bind(this));
  66. this.dashboard.on('row-collapsed', this.triggerForceUpdate.bind(this));
  67. this.dashboard.on('row-expanded', this.triggerForceUpdate.bind(this));
  68. }
  69. buildLayout() {
  70. const layout = [];
  71. this.panelMap = {};
  72. for (let panel of this.dashboard.panels) {
  73. let stringId = panel.id.toString();
  74. this.panelMap[stringId] = panel;
  75. if (!panel.gridPos) {
  76. console.log('panel without gridpos');
  77. continue;
  78. }
  79. let panelPos: any = {
  80. i: stringId,
  81. x: panel.gridPos.x,
  82. y: panel.gridPos.y,
  83. w: panel.gridPos.w,
  84. h: panel.gridPos.h,
  85. };
  86. if (panel.type === 'row') {
  87. panelPos.w = GRID_COLUMN_COUNT;
  88. panelPos.h = 1;
  89. panelPos.isResizable = false;
  90. panelPos.isDraggable = panel.collapsed;
  91. }
  92. layout.push(panelPos);
  93. }
  94. return layout;
  95. }
  96. onLayoutChange(newLayout) {
  97. for (const newPos of newLayout) {
  98. this.panelMap[newPos.i].updateGridPos(newPos);
  99. }
  100. this.dashboard.sortPanelsByGridPos();
  101. }
  102. triggerForceUpdate() {
  103. this.forceUpdate();
  104. }
  105. onWidthChange() {
  106. for (const panel of this.dashboard.panels) {
  107. panel.resizeDone();
  108. }
  109. }
  110. updateGridPos(item, layout) {
  111. this.panelMap[item.i].updateGridPos(item);
  112. // react-grid-layout has a bug (#670), and onLayoutChange() is only called when the component is mounted.
  113. // So it's required to call it explicitly when panel resized or moved to save layout changes.
  114. this.onLayoutChange(layout);
  115. }
  116. onResize(layout, oldItem, newItem) {
  117. this.panelMap[newItem.i].updateGridPos(newItem);
  118. }
  119. onResizeStop(layout, oldItem, newItem) {
  120. this.updateGridPos(newItem, layout);
  121. this.panelMap[newItem.i].resizeDone();
  122. }
  123. onDragStop(layout, oldItem, newItem) {
  124. this.updateGridPos(newItem, layout);
  125. }
  126. componentDidMount() {
  127. setTimeout(() => {
  128. this.setState(() => {
  129. return {animated: true};
  130. });
  131. });
  132. }
  133. renderPanels() {
  134. const panelElements = [];
  135. for (let panel of this.dashboard.panels) {
  136. const panelClasses = classNames({panel: true, 'panel--fullscreen': panel.fullscreen});
  137. panelElements.push(
  138. <div key={panel.id.toString()} className={panelClasses}>
  139. <DashboardPanel panel={panel} getPanelContainer={this.props.getPanelContainer} />
  140. </div>,
  141. );
  142. }
  143. return panelElements;
  144. }
  145. render() {
  146. return (
  147. <SizedReactLayoutGrid
  148. className={classNames({'layout': true, 'animated': this.state.animated})}
  149. layout={this.buildLayout()}
  150. onLayoutChange={this.onLayoutChange}
  151. onWidthChange={this.onWidthChange}
  152. onDragStop={this.onDragStop}
  153. onResize={this.onResize}
  154. onResizeStop={this.onResizeStop}>
  155. {this.renderPanels()}
  156. </SizedReactLayoutGrid>
  157. );
  158. }
  159. }