DashboardGrid.tsx 5.2 KB

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