AddPanelPanel.tsx 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  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. 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 panelContainer = this.props.getPanelContainer();
  80. const dashboard = panelContainer.getDashboard();
  81. const { gridPos } = this.props.panel;
  82. const newPanel: any = {
  83. type: panelPluginInfo.id,
  84. title: 'Panel Title',
  85. gridPos: { x: gridPos.x, y: gridPos.y, w: gridPos.w, h: gridPos.h },
  86. };
  87. if (panelPluginInfo.id === 'row') {
  88. newPanel.title = 'Row title';
  89. newPanel.gridPos = { x: 0, y: 0 };
  90. }
  91. // apply panel template / defaults
  92. if (panelPluginInfo.defaults) {
  93. _.defaults(newPanel, panelPluginInfo.defaults);
  94. newPanel.gridPos.w = panelPluginInfo.defaults.gridPos.w;
  95. newPanel.gridPos.h = panelPluginInfo.defaults.gridPos.h;
  96. newPanel.title = panelPluginInfo.defaults.title;
  97. store.delete(LS_PANEL_COPY_KEY);
  98. }
  99. dashboard.addPanel(newPanel);
  100. dashboard.removePanel(this.props.panel);
  101. };
  102. handleCloseAddPanel(evt) {
  103. evt.preventDefault();
  104. const panelContainer = this.props.getPanelContainer();
  105. const dashboard = panelContainer.getDashboard();
  106. dashboard.removePanel(dashboard.panels[0]);
  107. }
  108. renderText(text: string) {
  109. const searchWords = this.state.filter.split('');
  110. return <Highlighter highlightClassName="highlight-search-match" textToHighlight={text} searchWords={searchWords} />;
  111. }
  112. renderPanelItem(panel, index) {
  113. return (
  114. <div key={index} className="add-panel__item" onClick={() => this.onAddPanel(panel)} title={panel.name}>
  115. <img className="add-panel__item-img" src={panel.info.logos.small} />
  116. <div className="add-panel__item-name">{this.renderText(panel.name)}</div>
  117. </div>
  118. );
  119. }
  120. noCopiedPanelPlugins() {
  121. return <div className="add-panel__no-panels">No copied panels yet.</div>;
  122. }
  123. filterChange(evt) {
  124. this.setState({
  125. filter: evt.target.value,
  126. panelPlugins: this.getPanelPlugins(evt.target.value),
  127. copiedPanelPlugins: this.getCopiedPanelPlugins(evt.target.value),
  128. });
  129. }
  130. filterKeyPress(evt) {
  131. if (evt.key === 'Enter') {
  132. const panel = _.head(this.state.panelPlugins);
  133. if (panel) {
  134. this.onAddPanel(panel);
  135. }
  136. }
  137. }
  138. filterPanels(panels, filter) {
  139. const regex = new RegExp(filter, 'i');
  140. return panels.filter(panel => {
  141. return regex.test(panel.name);
  142. });
  143. }
  144. openCopy() {
  145. this.setState({
  146. tab: 'Copy',
  147. filter: '',
  148. panelPlugins: this.getPanelPlugins(''),
  149. copiedPanelPlugins: this.getCopiedPanelPlugins(''),
  150. });
  151. }
  152. openAdd() {
  153. this.setState({
  154. tab: 'Add',
  155. filter: '',
  156. panelPlugins: this.getPanelPlugins(''),
  157. copiedPanelPlugins: this.getCopiedPanelPlugins(''),
  158. });
  159. }
  160. render() {
  161. const addClass = classNames({
  162. 'active active--panel': this.state.tab === 'Add',
  163. '': this.state.tab === 'Copy',
  164. });
  165. const copyClass = classNames({
  166. '': this.state.tab === 'Add',
  167. 'active active--panel': this.state.tab === 'Copy',
  168. });
  169. let panelTab;
  170. if (this.state.tab === 'Add') {
  171. panelTab = this.state.panelPlugins.map(this.renderPanelItem);
  172. } else if (this.state.tab === 'Copy') {
  173. if (this.state.copiedPanelPlugins.length > 0) {
  174. panelTab = this.state.copiedPanelPlugins.map(this.renderPanelItem);
  175. } else {
  176. panelTab = this.noCopiedPanelPlugins();
  177. }
  178. }
  179. return (
  180. <div className="panel-container add-panel-container">
  181. <div className="add-panel">
  182. <div className="add-panel__header">
  183. <i className="gicon gicon-add-panel" />
  184. <span className="add-panel__title">New Panel</span>
  185. <ul className="gf-tabs">
  186. <li className="gf-tabs-item">
  187. <div className={'gf-tabs-link pointer ' + addClass} onClick={this.openAdd.bind(this)}>
  188. Add
  189. </div>
  190. </li>
  191. <li className="gf-tabs-item">
  192. <div className={'gf-tabs-link pointer ' + copyClass} onClick={this.openCopy.bind(this)}>
  193. Paste
  194. </div>
  195. </li>
  196. </ul>
  197. <button className="add-panel__close" onClick={this.handleCloseAddPanel}>
  198. <i className="fa fa-close" />
  199. </button>
  200. </div>
  201. <ScrollBar ref={element => (this.scrollbar = element)} className="add-panel__items">
  202. <div className="add-panel__searchbar">
  203. <label className="gf-form gf-form--grow gf-form--has-input-icon">
  204. <input
  205. type="text"
  206. autoFocus
  207. className="gf-form-input gf-form--grow"
  208. placeholder="Panel Search Filter"
  209. value={this.state.filter}
  210. onChange={this.filterChange.bind(this)}
  211. onKeyPress={this.filterKeyPress.bind(this)}
  212. />
  213. <i className="gf-form-input-icon fa fa-search" />
  214. </label>
  215. </div>
  216. {panelTab}
  217. </ScrollBar>
  218. </div>
  219. </div>
  220. );
  221. }
  222. }