keybindingSrv.ts 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. import $ from 'jquery';
  2. import _ from 'lodash';
  3. import coreModule from 'app/core/core_module';
  4. import appEvents from 'app/core/app_events';
  5. import { encodePathComponent } from 'app/core/utils/location_util';
  6. import Mousetrap from 'mousetrap';
  7. import 'mousetrap-global-bind';
  8. export class KeybindingSrv {
  9. helpModal: boolean;
  10. modalOpen = false;
  11. timepickerOpen = false;
  12. /** @ngInject */
  13. constructor(private $rootScope, private $location, private datasourceSrv) {
  14. // clear out all shortcuts on route change
  15. $rootScope.$on('$routeChangeSuccess', () => {
  16. Mousetrap.reset();
  17. // rebind global shortcuts
  18. this.setupGlobal();
  19. });
  20. this.setupGlobal();
  21. appEvents.on('show-modal', () => (this.modalOpen = true));
  22. $rootScope.onAppEvent('timepickerOpen', () => (this.timepickerOpen = true));
  23. $rootScope.onAppEvent('timepickerClosed', () => (this.timepickerOpen = false));
  24. }
  25. setupGlobal() {
  26. this.bind(['?', 'h'], this.showHelpModal);
  27. this.bind('g h', this.goToHome);
  28. this.bind('g a', this.openAlerting);
  29. this.bind('g p', this.goToProfile);
  30. this.bind('s s', this.openSearchStarred);
  31. this.bind('s o', this.openSearch);
  32. this.bind('s t', this.openSearchTags);
  33. this.bind('f', this.openSearch);
  34. this.bindGlobal('esc', this.exit);
  35. }
  36. openSearchStarred() {
  37. appEvents.emit('show-dash-search', { starred: true });
  38. }
  39. openSearchTags() {
  40. appEvents.emit('show-dash-search', { tagsMode: true });
  41. }
  42. openSearch() {
  43. appEvents.emit('show-dash-search');
  44. }
  45. openAlerting() {
  46. this.$location.url('/alerting');
  47. }
  48. goToHome() {
  49. this.$location.url('/');
  50. }
  51. goToProfile() {
  52. this.$location.url('/profile');
  53. }
  54. showHelpModal() {
  55. appEvents.emit('show-modal', { templateHtml: '<help-modal></help-modal>' });
  56. }
  57. exit() {
  58. var popups = $('.popover.in');
  59. if (popups.length > 0) {
  60. return;
  61. }
  62. appEvents.emit('hide-modal');
  63. if (!this.modalOpen) {
  64. if (this.timepickerOpen) {
  65. this.$rootScope.appEvent('closeTimepicker');
  66. this.timepickerOpen = false;
  67. } else {
  68. this.$rootScope.appEvent('panel-change-view', { fullscreen: false, edit: false });
  69. }
  70. } else {
  71. this.modalOpen = false;
  72. }
  73. // close settings view
  74. var search = this.$location.search();
  75. if (search.editview) {
  76. delete search.editview;
  77. this.$location.search(search);
  78. }
  79. }
  80. bind(keyArg, fn) {
  81. Mousetrap.bind(
  82. keyArg,
  83. evt => {
  84. evt.preventDefault();
  85. evt.stopPropagation();
  86. evt.returnValue = false;
  87. return this.$rootScope.$apply(fn.bind(this));
  88. },
  89. 'keydown'
  90. );
  91. }
  92. bindGlobal(keyArg, fn) {
  93. Mousetrap.bindGlobal(
  94. keyArg,
  95. evt => {
  96. evt.preventDefault();
  97. evt.stopPropagation();
  98. evt.returnValue = false;
  99. return this.$rootScope.$apply(fn.bind(this));
  100. },
  101. 'keydown'
  102. );
  103. }
  104. showDashEditView() {
  105. var search = _.extend(this.$location.search(), { editview: 'settings' });
  106. this.$location.search(search);
  107. }
  108. setupDashboardBindings(scope, dashboard) {
  109. this.bind('mod+o', () => {
  110. dashboard.graphTooltip = (dashboard.graphTooltip + 1) % 3;
  111. appEvents.emit('graph-hover-clear');
  112. this.$rootScope.$broadcast('refresh');
  113. });
  114. this.bind('mod+s', e => {
  115. scope.appEvent('save-dashboard');
  116. });
  117. this.bind('t z', () => {
  118. scope.appEvent('zoom-out', 2);
  119. });
  120. this.bind('ctrl+z', () => {
  121. scope.appEvent('zoom-out', 2);
  122. });
  123. this.bind('t left', () => {
  124. scope.appEvent('shift-time-backward');
  125. });
  126. this.bind('t right', () => {
  127. scope.appEvent('shift-time-forward');
  128. });
  129. // edit panel
  130. this.bind('e', () => {
  131. if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) {
  132. this.$rootScope.appEvent('panel-change-view', {
  133. fullscreen: true,
  134. edit: true,
  135. panelId: dashboard.meta.focusPanelId,
  136. toggle: true,
  137. });
  138. }
  139. });
  140. // view panel
  141. this.bind('v', () => {
  142. if (dashboard.meta.focusPanelId) {
  143. this.$rootScope.appEvent('panel-change-view', {
  144. fullscreen: true,
  145. edit: null,
  146. panelId: dashboard.meta.focusPanelId,
  147. toggle: true,
  148. });
  149. }
  150. });
  151. this.bind('x', async () => {
  152. if (dashboard.meta.focusPanelId) {
  153. const panel = dashboard.getPanelById(dashboard.meta.focusPanelId);
  154. const datasource = await this.datasourceSrv.get(panel.datasource);
  155. if (datasource && datasource.supportsExplore) {
  156. const exploreState = encodePathComponent(JSON.stringify(datasource.getExploreState(panel)));
  157. this.$location.url(`/explore/${exploreState}`);
  158. }
  159. }
  160. });
  161. // delete panel
  162. this.bind('p r', () => {
  163. if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) {
  164. this.$rootScope.appEvent('panel-remove', {
  165. panelId: dashboard.meta.focusPanelId,
  166. });
  167. dashboard.meta.focusPanelId = 0;
  168. }
  169. });
  170. // duplicate panel
  171. this.bind('p d', () => {
  172. if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) {
  173. let panelIndex = dashboard.getPanelInfoById(dashboard.meta.focusPanelId).index;
  174. dashboard.duplicatePanel(dashboard.panels[panelIndex]);
  175. }
  176. });
  177. // share panel
  178. this.bind('p s', () => {
  179. if (dashboard.meta.focusPanelId) {
  180. var shareScope = scope.$new();
  181. var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId);
  182. shareScope.panel = panelInfo.panel;
  183. shareScope.dashboard = dashboard;
  184. appEvents.emit('show-modal', {
  185. src: 'public/app/features/dashboard/partials/shareModal.html',
  186. scope: shareScope,
  187. });
  188. }
  189. });
  190. // collapse all rows
  191. this.bind('d shift+c', () => {
  192. dashboard.collapseRows();
  193. });
  194. // expand all rows
  195. this.bind('d shift+e', () => {
  196. dashboard.expandRows();
  197. });
  198. this.bind('d n', e => {
  199. this.$location.url('/dashboard/new');
  200. });
  201. this.bind('d r', () => {
  202. this.$rootScope.$broadcast('refresh');
  203. });
  204. this.bind('d s', () => {
  205. this.showDashEditView();
  206. });
  207. this.bind('d k', () => {
  208. appEvents.emit('toggle-kiosk-mode');
  209. });
  210. this.bind('d v', () => {
  211. appEvents.emit('toggle-view-mode');
  212. });
  213. }
  214. }
  215. coreModule.service('keybindingSrv', KeybindingSrv);