AddPanelPanel.tsx 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  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 { DashboardModel } from '../dashboard_model';
  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. dashboard: DashboardModel;
  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. private scrollbar: ScrollBar;
  23. constructor(props) {
  24. super(props);
  25. this.handleCloseAddPanel = this.handleCloseAddPanel.bind(this);
  26. this.renderPanelItem = this.renderPanelItem.bind(this);
  27. this.panelSizeChanged = this.panelSizeChanged.bind(this);
  28. this.state = {
  29. panelPlugins: this.getPanelPlugins(''),
  30. copiedPanelPlugins: this.getCopiedPanelPlugins(''),
  31. filter: '',
  32. tab: 'Add',
  33. };
  34. }
  35. componentDidMount() {
  36. this.props.panel.events.on('panel-size-changed', this.panelSizeChanged);
  37. }
  38. componentWillUnmount() {
  39. this.props.panel.events.off('panel-size-changed', this.panelSizeChanged);
  40. }
  41. panelSizeChanged() {
  42. setTimeout(() => {
  43. this.scrollbar.update();
  44. });
  45. }
  46. getPanelPlugins(filter) {
  47. let panels = _.chain(config.panels)
  48. .filter({ hideFromList: false })
  49. .map(item => item)
  50. .value();
  51. // add special row type
  52. panels.push({ id: 'row', name: 'Row', sort: 8, info: { logos: { small: 'public/img/icn-row.svg' } } });
  53. panels = this.filterPanels(panels, filter);
  54. // add sort by sort property
  55. return _.sortBy(panels, 'sort');
  56. }
  57. getCopiedPanelPlugins(filter) {
  58. const panels = _.chain(config.panels)
  59. .filter({ hideFromList: false })
  60. .map(item => item)
  61. .value();
  62. let copiedPanels = [];
  63. const copiedPanelJson = store.get(LS_PANEL_COPY_KEY);
  64. if (copiedPanelJson) {
  65. const copiedPanel = JSON.parse(copiedPanelJson);
  66. const pluginInfo = _.find(panels, { id: copiedPanel.type });
  67. if (pluginInfo) {
  68. const pluginCopy = _.cloneDeep(pluginInfo);
  69. pluginCopy.name = copiedPanel.title;
  70. pluginCopy.sort = -1;
  71. pluginCopy.defaults = copiedPanel;
  72. copiedPanels.push(pluginCopy);
  73. }
  74. }
  75. copiedPanels = this.filterPanels(copiedPanels, filter);
  76. return _.sortBy(copiedPanels, 'sort');
  77. }
  78. onAddPanel = panelPluginInfo => {
  79. const dashboard = this.props.dashboard;
  80. const { gridPos } = this.props.panel;
  81. const newPanel: any = {
  82. type: panelPluginInfo.id,
  83. title: 'Panel Title',
  84. gridPos: { x: gridPos.x, y: gridPos.y, w: gridPos.w, h: gridPos.h },
  85. };
  86. if (panelPluginInfo.id === 'row') {
  87. newPanel.title = 'Row title';
  88. newPanel.gridPos = { x: 0, y: 0 };
  89. }
  90. // apply panel template / defaults
  91. if (panelPluginInfo.defaults) {
  92. _.defaults(newPanel, panelPluginInfo.defaults);
  93. newPanel.gridPos.w = panelPluginInfo.defaults.gridPos.w;
  94. newPanel.gridPos.h = panelPluginInfo.defaults.gridPos.h;
  95. newPanel.title = panelPluginInfo.defaults.title;
  96. store.delete(LS_PANEL_COPY_KEY);
  97. }
  98. dashboard.addPanel(newPanel);
  99. dashboard.removePanel(this.props.panel);
  100. };
  101. handleCloseAddPanel(evt) {
  102. evt.preventDefault();
  103. this.props.dashboard.removePanel(this.props.dashboard.panels[0]);
  104. }
  105. renderText(text: string) {
  106. const searchWords = this.state.filter.split('');
  107. return <Highlighter highlightClassName="highlight-search-match" textToHighlight={text} searchWords={searchWords} />;
  108. }
  109. renderPanelItem(panel, index) {
  110. return (
  111. <div key={index} className="add-panel__item" onClick={() => this.onAddPanel(panel)} title={panel.name}>
  112. <img className="add-panel__item-img" src={panel.info.logos.small} />
  113. <div className="add-panel__item-name">{this.renderText(panel.name)}</div>
  114. </div>
  115. );
  116. }
  117. noCopiedPanelPlugins() {
  118. return <div className="add-panel__no-panels">No copied panels yet.</div>;
  119. }
  120. filterChange(evt) {
  121. this.setState({
  122. filter: evt.target.value,
  123. panelPlugins: this.getPanelPlugins(evt.target.value),
  124. copiedPanelPlugins: this.getCopiedPanelPlugins(evt.target.value),
  125. });
  126. }
  127. filterKeyPress(evt) {
  128. if (evt.key === 'Enter') {
  129. const panel = _.head(this.state.panelPlugins);
  130. if (panel) {
  131. this.onAddPanel(panel);
  132. }
  133. }
  134. }
  135. filterPanels(panels, filter) {
  136. const regex = new RegExp(filter, 'i');
  137. return panels.filter(panel => {
  138. return regex.test(panel.name);
  139. });
  140. }
  141. openCopy() {
  142. this.setState({
  143. tab: 'Copy',
  144. filter: '',
  145. panelPlugins: this.getPanelPlugins(''),
  146. copiedPanelPlugins: this.getCopiedPanelPlugins(''),
  147. });
  148. }
  149. openAdd() {
  150. this.setState({
  151. tab: 'Add',
  152. filter: '',
  153. panelPlugins: this.getPanelPlugins(''),
  154. copiedPanelPlugins: this.getCopiedPanelPlugins(''),
  155. });
  156. }
  157. render() {
  158. const addClass = classNames({
  159. 'active active--panel': this.state.tab === 'Add',
  160. '': this.state.tab === 'Copy',
  161. });
  162. const copyClass = classNames({
  163. '': this.state.tab === 'Add',
  164. 'active active--panel': this.state.tab === 'Copy',
  165. });
  166. let panelTab;
  167. if (this.state.tab === 'Add') {
  168. panelTab = this.state.panelPlugins.map(this.renderPanelItem);
  169. } else if (this.state.tab === 'Copy') {
  170. if (this.state.copiedPanelPlugins.length > 0) {
  171. panelTab = this.state.copiedPanelPlugins.map(this.renderPanelItem);
  172. } else {
  173. panelTab = this.noCopiedPanelPlugins();
  174. }
  175. }
  176. return (
  177. <div className="panel-container add-panel-container">
  178. <div className="add-panel">
  179. <div className="add-panel__header">
  180. <i className="gicon gicon-add-panel" />
  181. <span className="add-panel__title">New Panel</span>
  182. <ul className="gf-tabs">
  183. <li className="gf-tabs-item">
  184. <div className={'gf-tabs-link pointer ' + addClass} onClick={this.openAdd.bind(this)}>
  185. Add
  186. </div>
  187. </li>
  188. <li className="gf-tabs-item">
  189. <div className={'gf-tabs-link pointer ' + copyClass} onClick={this.openCopy.bind(this)}>
  190. Paste
  191. </div>
  192. </li>
  193. </ul>
  194. <button className="add-panel__close" onClick={this.handleCloseAddPanel}>
  195. <i className="fa fa-close" />
  196. </button>
  197. </div>
  198. <ScrollBar ref={element => (this.scrollbar = element)} className="add-panel__items">
  199. <div className="add-panel__searchbar">
  200. <label className="gf-form gf-form--grow gf-form--has-input-icon">
  201. <input
  202. type="text"
  203. autoFocus
  204. className="gf-form-input gf-form--grow"
  205. placeholder="Panel Search Filter"
  206. value={this.state.filter}
  207. onChange={this.filterChange.bind(this)}
  208. onKeyPress={this.filterKeyPress.bind(this)}
  209. />
  210. <i className="gf-form-input-icon fa fa-search" />
  211. </label>
  212. </div>
  213. {panelTab}
  214. </ScrollBar>
  215. </div>
  216. </div>
  217. );
  218. }
  219. }