AddPanelPanel.tsx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. import React from 'react';
  2. import _ from 'lodash';
  3. import classNames from 'classnames';
  4. import config from 'app/core/config';
  5. import { PanelModel } from '../panel_model';
  6. import { PanelContainer } from './PanelContainer';
  7. import ScrollBar from 'app/core/components/ScrollBar/ScrollBar';
  8. import store from 'app/core/store';
  9. import { LS_PANEL_COPY_KEY } from 'app/core/constants';
  10. import Highlighter from 'react-highlight-words';
  11. export interface AddPanelPanelProps {
  12. panel: PanelModel;
  13. getPanelContainer: () => PanelContainer;
  14. }
  15. export interface AddPanelPanelState {
  16. filter: string;
  17. panelPlugins: any[];
  18. copiedPanelPlugins: any[];
  19. tab: string;
  20. }
  21. export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelPanelState> {
  22. constructor(props) {
  23. super(props);
  24. this.handleCloseAddPanel = this.handleCloseAddPanel.bind(this);
  25. this.renderPanelItem = this.renderPanelItem.bind(this);
  26. this.state = {
  27. panelPlugins: this.getPanelPlugins(''),
  28. copiedPanelPlugins: this.getCopiedPanelPlugins(''),
  29. filter: '',
  30. tab: 'Add',
  31. };
  32. }
  33. getPanelPlugins(filter) {
  34. let panels = _.chain(config.panels)
  35. .filter({ hideFromList: false })
  36. .map(item => item)
  37. .value();
  38. // add special row type
  39. panels.push({ id: 'row', name: 'Row', sort: 8, info: { logos: { small: 'public/img/icn-row.svg' } } });
  40. panels = this.filterPanels(panels, filter);
  41. // add sort by sort property
  42. return _.sortBy(panels, 'sort');
  43. }
  44. getCopiedPanelPlugins(filter) {
  45. let panels = _.chain(config.panels)
  46. .filter({ hideFromList: false })
  47. .map(item => item)
  48. .value();
  49. let copiedPanels = [];
  50. let copiedPanelJson = store.get(LS_PANEL_COPY_KEY);
  51. if (copiedPanelJson) {
  52. let copiedPanel = JSON.parse(copiedPanelJson);
  53. let pluginInfo = _.find(panels, { id: copiedPanel.type });
  54. if (pluginInfo) {
  55. let pluginCopy = _.cloneDeep(pluginInfo);
  56. pluginCopy.name = copiedPanel.title;
  57. pluginCopy.sort = -1;
  58. pluginCopy.defaults = copiedPanel;
  59. copiedPanels.push(pluginCopy);
  60. }
  61. }
  62. copiedPanels = this.filterPanels(copiedPanels, filter);
  63. return _.sortBy(copiedPanels, 'sort');
  64. }
  65. onAddPanel = panelPluginInfo => {
  66. const panelContainer = this.props.getPanelContainer();
  67. const dashboard = panelContainer.getDashboard();
  68. const { gridPos } = this.props.panel;
  69. var newPanel: any = {
  70. type: panelPluginInfo.id,
  71. title: 'Panel Title',
  72. gridPos: { x: gridPos.x, y: gridPos.y, w: gridPos.w, h: gridPos.h },
  73. };
  74. if (panelPluginInfo.id === 'row') {
  75. newPanel.title = 'Row title';
  76. newPanel.gridPos = { x: 0, y: 0 };
  77. }
  78. // apply panel template / defaults
  79. if (panelPluginInfo.defaults) {
  80. _.defaults(newPanel, panelPluginInfo.defaults);
  81. newPanel.gridPos.w = panelPluginInfo.defaults.gridPos.w;
  82. newPanel.gridPos.h = panelPluginInfo.defaults.gridPos.h;
  83. newPanel.title = panelPluginInfo.defaults.title;
  84. store.delete(LS_PANEL_COPY_KEY);
  85. }
  86. dashboard.addPanel(newPanel);
  87. dashboard.removePanel(this.props.panel);
  88. };
  89. handleCloseAddPanel(evt) {
  90. evt.preventDefault();
  91. const panelContainer = this.props.getPanelContainer();
  92. const dashboard = panelContainer.getDashboard();
  93. dashboard.removePanel(dashboard.panels[0]);
  94. }
  95. renderText(text: string) {
  96. let searchWords = this.state.filter.split('');
  97. return <Highlighter highlightClassName="highlight-search-match" textToHighlight={text} searchWords={searchWords} />;
  98. }
  99. renderPanelItem(panel, index) {
  100. return (
  101. <div key={index} className="add-panel__item" onClick={() => this.onAddPanel(panel)} title={panel.name}>
  102. <img className="add-panel__item-img" src={panel.info.logos.small} />
  103. <div className="add-panel__item-name">{this.renderText(panel.name)}</div>
  104. </div>
  105. );
  106. }
  107. noCopiedPanelPlugins() {
  108. return <div className="add-panel__no-panels">No copied panels yet.</div>;
  109. }
  110. filterChange(evt) {
  111. this.setState({
  112. filter: evt.target.value,
  113. panelPlugins: this.getPanelPlugins(evt.target.value),
  114. copiedPanelPlugins: this.getCopiedPanelPlugins(evt.target.value),
  115. });
  116. }
  117. filterPanels(panels, filter) {
  118. let regex = new RegExp(filter, 'i');
  119. return panels.filter(panel => {
  120. return regex.test(panel.name);
  121. });
  122. }
  123. openCopy() {
  124. this.setState({
  125. tab: 'Copy',
  126. filter: '',
  127. panelPlugins: this.getPanelPlugins(''),
  128. copiedPanelPlugins: this.getCopiedPanelPlugins(''),
  129. });
  130. }
  131. openAdd() {
  132. this.setState({
  133. tab: 'Add',
  134. filter: '',
  135. panelPlugins: this.getPanelPlugins(''),
  136. copiedPanelPlugins: this.getCopiedPanelPlugins(''),
  137. });
  138. }
  139. render() {
  140. let addClass = classNames({
  141. 'active active--panel': this.state.tab === 'Add',
  142. '': this.state.tab === 'Copy',
  143. });
  144. let copyClass = classNames({
  145. '': this.state.tab === 'Add',
  146. 'active active--panel': this.state.tab === 'Copy',
  147. });
  148. let panelTab;
  149. if (this.state.tab === 'Add') {
  150. panelTab = this.state.panelPlugins.map(this.renderPanelItem);
  151. } else if (this.state.tab === 'Copy') {
  152. if (this.state.copiedPanelPlugins.length > 0) {
  153. panelTab = this.state.copiedPanelPlugins.map(this.renderPanelItem);
  154. } else {
  155. panelTab = this.noCopiedPanelPlugins();
  156. }
  157. }
  158. return (
  159. <div className="panel-container">
  160. <div className="add-panel">
  161. <div className="add-panel__header">
  162. <i className="gicon gicon-add-panel" />
  163. <span className="add-panel__title">New Panel</span>
  164. <ul className="gf-tabs">
  165. <li className="gf-tabs-item">
  166. <div className={'gf-tabs-link pointer ' + addClass} onClick={this.openAdd.bind(this)}>
  167. Add
  168. </div>
  169. </li>
  170. <li className="gf-tabs-item">
  171. <div className={'gf-tabs-link pointer ' + copyClass} onClick={this.openCopy.bind(this)}>
  172. Paste
  173. </div>
  174. </li>
  175. </ul>
  176. <button className="add-panel__close" onClick={this.handleCloseAddPanel}>
  177. <i className="fa fa-close" />
  178. </button>
  179. </div>
  180. <ScrollBar className="add-panel__items">
  181. <div className="add-panel__searchbar">
  182. <label className="gf-form gf-form--grow gf-form--has-input-icon">
  183. <input
  184. type="text"
  185. className="gf-form-input max-width-20"
  186. placeholder="Panel Search Filter"
  187. value={this.state.filter}
  188. onChange={this.filterChange.bind(this)}
  189. />
  190. <i className="gf-form-input-icon fa fa-search" />
  191. </label>
  192. </div>
  193. {panelTab}
  194. </ScrollBar>
  195. </div>
  196. </div>
  197. );
  198. }
  199. }