getPanelMenu.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. import { PanelMenuItem } from '@grafana/data';
  2. import { AngularComponent, getDataSourceSrv, locationService } from '@grafana/runtime';
  3. import { PanelCtrl } from 'app/angular/panel/panel_ctrl';
  4. import config from 'app/core/config';
  5. import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
  6. import { PanelModel } from 'app/features/dashboard/state/PanelModel';
  7. import {
  8. addLibraryPanel,
  9. copyPanel,
  10. duplicatePanel,
  11. removePanel,
  12. sharePanel,
  13. unlinkLibraryPanel,
  14. } from 'app/features/dashboard/utils/panel';
  15. import { isPanelModelLibraryPanel } from 'app/features/library-panels/guard';
  16. import { store } from 'app/store/store';
  17. import { contextSrv } from '../../../core/services/context_srv';
  18. import { getExploreUrl } from '../../../core/utils/explore';
  19. import { navigateToExplore } from '../../explore/state/main';
  20. import { getTimeSrv } from '../services/TimeSrv';
  21. export function getPanelMenu(
  22. dashboard: DashboardModel,
  23. panel: PanelModel,
  24. angularComponent?: AngularComponent | null
  25. ): PanelMenuItem[] {
  26. const onViewPanel = (event: React.MouseEvent<any>) => {
  27. event.preventDefault();
  28. locationService.partial({
  29. viewPanel: panel.id,
  30. });
  31. };
  32. const onEditPanel = (event: React.MouseEvent<any>) => {
  33. event.preventDefault();
  34. locationService.partial({
  35. editPanel: panel.id,
  36. });
  37. };
  38. const onSharePanel = (event: React.MouseEvent<any>) => {
  39. event.preventDefault();
  40. sharePanel(dashboard, panel);
  41. };
  42. const onAddLibraryPanel = (event: React.MouseEvent<any>) => {
  43. event.preventDefault();
  44. addLibraryPanel(dashboard, panel);
  45. };
  46. const onUnlinkLibraryPanel = (event: React.MouseEvent<any>) => {
  47. event.preventDefault();
  48. unlinkLibraryPanel(panel);
  49. };
  50. const onInspectPanel = (tab?: string) => {
  51. locationService.partial({
  52. inspect: panel.id,
  53. inspectTab: tab,
  54. });
  55. };
  56. const onMore = (event: React.MouseEvent<any>) => {
  57. event.preventDefault();
  58. };
  59. const onDuplicatePanel = (event: React.MouseEvent<any>) => {
  60. event.preventDefault();
  61. duplicatePanel(dashboard, panel);
  62. };
  63. const onCopyPanel = (event: React.MouseEvent<any>) => {
  64. event.preventDefault();
  65. copyPanel(panel);
  66. };
  67. const onRemovePanel = (event: React.MouseEvent<any>) => {
  68. event.preventDefault();
  69. removePanel(dashboard, panel, true);
  70. };
  71. const onNavigateToExplore = (event: React.MouseEvent<any>) => {
  72. event.preventDefault();
  73. const openInNewWindow =
  74. event.ctrlKey || event.metaKey ? (url: string) => window.open(`${config.appSubUrl}${url}`) : undefined;
  75. store.dispatch(navigateToExplore(panel, { getDataSourceSrv, getTimeSrv, getExploreUrl, openInNewWindow }) as any);
  76. };
  77. const menu: PanelMenuItem[] = [];
  78. if (!panel.isEditing) {
  79. menu.push({
  80. text: 'View',
  81. iconClassName: 'eye',
  82. onClick: onViewPanel,
  83. shortcut: 'v',
  84. });
  85. }
  86. if (dashboard.canEditPanel(panel) && !panel.isEditing) {
  87. menu.push({
  88. text: 'Edit',
  89. iconClassName: 'edit',
  90. onClick: onEditPanel,
  91. shortcut: 'e',
  92. });
  93. }
  94. menu.push({
  95. text: 'Share',
  96. iconClassName: 'share-alt',
  97. onClick: onSharePanel,
  98. shortcut: 'p s',
  99. });
  100. if (contextSrv.hasAccessToExplore() && !(panel.plugin && panel.plugin.meta.skipDataQuery)) {
  101. menu.push({
  102. text: 'Explore',
  103. iconClassName: 'compass',
  104. shortcut: 'x',
  105. onClick: onNavigateToExplore,
  106. });
  107. }
  108. const inspectMenu: PanelMenuItem[] = [];
  109. // Only show these inspect actions for data plugins
  110. if (panel.plugin && !panel.plugin.meta.skipDataQuery) {
  111. inspectMenu.push({
  112. text: 'Data',
  113. onClick: (e: React.MouseEvent<any>) => onInspectPanel('data'),
  114. });
  115. if (dashboard.meta.canEdit) {
  116. inspectMenu.push({
  117. text: 'Query',
  118. onClick: (e: React.MouseEvent<any>) => onInspectPanel('query'),
  119. });
  120. }
  121. }
  122. inspectMenu.push({
  123. text: 'Panel JSON',
  124. onClick: (e: React.MouseEvent<any>) => onInspectPanel('json'),
  125. });
  126. menu.push({
  127. type: 'submenu',
  128. text: 'Inspect',
  129. iconClassName: 'info-circle',
  130. onClick: (e: React.MouseEvent<any>) => onInspectPanel(),
  131. shortcut: 'i',
  132. subMenu: inspectMenu,
  133. });
  134. const subMenu: PanelMenuItem[] = [];
  135. if (dashboard.canEditPanel(panel) && !(panel.isViewing || panel.isEditing)) {
  136. subMenu.push({
  137. text: 'Duplicate',
  138. onClick: onDuplicatePanel,
  139. shortcut: 'p d',
  140. });
  141. subMenu.push({
  142. text: 'Copy',
  143. onClick: onCopyPanel,
  144. });
  145. if (isPanelModelLibraryPanel(panel)) {
  146. subMenu.push({
  147. text: 'Unlink library panel',
  148. onClick: onUnlinkLibraryPanel,
  149. });
  150. } else {
  151. subMenu.push({
  152. text: 'Create library panel',
  153. onClick: onAddLibraryPanel,
  154. });
  155. }
  156. }
  157. // add old angular panel options
  158. if (angularComponent) {
  159. const scope = angularComponent.getScope();
  160. const panelCtrl: PanelCtrl = scope.$$childHead.ctrl;
  161. const angularMenuItems = panelCtrl.getExtendedMenu();
  162. for (const item of angularMenuItems) {
  163. const reactItem: PanelMenuItem = {
  164. text: item.text,
  165. href: item.href,
  166. shortcut: item.shortcut,
  167. };
  168. if (item.click) {
  169. reactItem.onClick = () => {
  170. scope.$eval(item.click, { ctrl: panelCtrl });
  171. };
  172. }
  173. subMenu.push(reactItem);
  174. }
  175. }
  176. if (!panel.isEditing && subMenu.length) {
  177. menu.push({
  178. type: 'submenu',
  179. text: 'More...',
  180. iconClassName: 'cube',
  181. subMenu,
  182. onClick: onMore,
  183. });
  184. }
  185. if (dashboard.canEditPanel(panel) && !panel.isEditing && !panel.isViewing) {
  186. menu.push({ type: 'divider', text: '' });
  187. menu.push({
  188. text: 'Remove',
  189. iconClassName: 'trash-alt',
  190. onClick: onRemovePanel,
  191. shortcut: 'p r',
  192. });
  193. }
  194. return menu;
  195. }