Browse Source

Fix url encoding, expand template vars, fix TS hacks

* moved datasource related functions to panel sub-class
* expand panel template vars for url
* added keybindings for x -> Explore
* url encoding for explore state
David Kaltschmidt 7 years ago
parent
commit
8a53ec610b

+ 2 - 1
public/app/containers/Explore/Explore.tsx

@@ -10,6 +10,7 @@ import Graph from './Graph';
 import Table from './Table';
 import { DatasourceSrv } from 'app/features/plugins/datasource_srv';
 import { buildQueryOptions, ensureQueries, generateQueryKey, hasQuery } from './utils/query';
+import { decodePathComponent } from 'app/core/utils/location_util';
 
 function makeTimeSeriesList(dataList, options) {
   return dataList.map((seriesData, index) => {
@@ -43,7 +44,7 @@ function parseInitialQueries(initial) {
     return [];
   }
   try {
-    const parsed = JSON.parse(initial);
+    const parsed = JSON.parse(decodePathComponent(initial));
     return parsed.queries.map(q => q.query);
   } catch (e) {
     console.error(e);

+ 13 - 1
public/app/core/services/keybindingSrv.ts

@@ -3,6 +3,7 @@ import _ from 'lodash';
 
 import coreModule from 'app/core/core_module';
 import appEvents from 'app/core/app_events';
+import { encodePathComponent } from 'app/core/utils/location_util';
 
 import Mousetrap from 'mousetrap';
 import 'mousetrap-global-bind';
@@ -13,7 +14,7 @@ export class KeybindingSrv {
   timepickerOpen = false;
 
   /** @ngInject */
-  constructor(private $rootScope, private $location) {
+  constructor(private $rootScope, private $location, private datasourceSrv) {
     // clear out all shortcuts on route change
     $rootScope.$on('$routeChangeSuccess', () => {
       Mousetrap.reset();
@@ -176,6 +177,17 @@ export class KeybindingSrv {
       }
     });
 
+    this.bind('x', async () => {
+      if (dashboard.meta.focusPanelId) {
+        const panel = dashboard.getPanelById(dashboard.meta.focusPanelId);
+        const datasource = await this.datasourceSrv.get(panel.datasource);
+        if (datasource && datasource.supportsExplore) {
+          const exploreState = encodePathComponent(JSON.stringify(datasource.getExploreState(panel)));
+          this.$location.url(`/explore/${exploreState}`);
+        }
+      }
+    });
+
     // delete panel
     this.bind('p r', () => {
       if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) {

+ 7 - 4
public/app/core/utils/location_util.ts

@@ -1,6 +1,11 @@
 import config from 'app/core/config';
 
-const _stripBaseFromUrl = url => {
+// Slash encoding for angular location provider, see https://github.com/angular/angular.js/issues/10479
+const SLASH = '<SLASH>';
+export const decodePathComponent = (pc: string) => decodeURIComponent(pc).replace(new RegExp(SLASH, 'g'), '/');
+export const encodePathComponent = (pc: string) => encodeURIComponent(pc.replace(/\//g, SLASH));
+
+export const stripBaseFromUrl = url => {
   const appSubUrl = config.appSubUrl;
   const stripExtraChars = appSubUrl.endsWith('/') ? 1 : 0;
   const urlWithoutBase =
@@ -9,6 +14,4 @@ const _stripBaseFromUrl = url => {
   return urlWithoutBase;
 };
 
-export default {
-  stripBaseFromUrl: _stripBaseFromUrl,
-};
+export default { stripBaseFromUrl };

+ 19 - 0
public/app/features/panel/metrics_panel_ctrl.ts

@@ -6,6 +6,7 @@ import { PanelCtrl } from 'app/features/panel/panel_ctrl';
 
 import * as rangeUtil from 'app/core/utils/rangeutil';
 import * as dateMath from 'app/core/utils/datemath';
+import { encodePathComponent } from 'app/core/utils/location_util';
 
 import { metricsTabDirective } from './metrics_tab';
 
@@ -309,6 +310,24 @@ class MetricsPanelCtrl extends PanelCtrl {
     this.refresh();
   }
 
+  getAdditionalMenuItems() {
+    const items = [];
+    if (this.datasource.supportsExplore) {
+      items.push({
+        text: 'Explore',
+        click: 'ctrl.explore();',
+        icon: 'fa fa-fw fa-rocket',
+        shortcut: 'x',
+      });
+    }
+    return items;
+  }
+
+  explore() {
+    const exploreState = encodePathComponent(JSON.stringify(this.datasource.getExploreState(this.panel)));
+    this.$location.url(`/explore/${exploreState}`);
+  }
+
   addQuery(target) {
     target.refId = this.dashboard.getNextQueryLetter(this.panel);
 

+ 8 - 16
public/app/features/panel/panel_ctrl.ts

@@ -99,12 +99,6 @@ export class PanelCtrl {
     this.changeView(false, false);
   }
 
-  explore() {
-    // TS hack :<
-    const initialState = JSON.stringify(this['datasource'].getExploreState(this.panel));
-    this.$location.url(`/explore/${initialState}`);
-  }
-
   initEditMode() {
     this.editorTabs = [];
     this.addEditorTab('General', 'public/app/partials/panelgeneral.html');
@@ -162,16 +156,6 @@ export class PanelCtrl {
       });
     }
 
-    // TS hack :<
-    if ('datasource' in this && this['datasource'].supportsExplore) {
-      menu.push({
-        text: 'Explore',
-        click: 'ctrl.explore();',
-        icon: 'fa fa-fw fa-rocket',
-        shortcut: 'x',
-      });
-    }
-
     menu.push({
       text: 'Share',
       click: 'ctrl.sharePanel();',
@@ -179,6 +163,9 @@ export class PanelCtrl {
       shortcut: 'p s',
     });
 
+    // Additional items from sub-class
+    menu.push(...this.getAdditionalMenuItems());
+
     let extendedMenu = this.getExtendedMenu();
     menu.push({
       text: 'More ...',
@@ -227,6 +214,11 @@ export class PanelCtrl {
     return menu;
   }
 
+  // Override in sub-class to add items before extended menu
+  getAdditionalMenuItems() {
+    return [];
+  }
+
   otherPanelInFullscreenMode() {
     return this.dashboard.meta.fullscreen && !this.fullscreen;
   }

+ 11 - 4
public/app/plugins/datasource/prometheus/datasource.ts

@@ -326,11 +326,18 @@ export class PrometheusDatasource {
   }
 
   getExploreState(panel) {
-    if (!panel.targets) {
-      return {};
+    let state = {};
+    if (panel.targets) {
+      const queries = panel.targets.map(t => ({
+        query: this.templateSrv.replace(t.expr, {}, this.interpolateQueryExpr),
+        format: t.format,
+      }));
+      state = {
+        ...state,
+        queries,
+      };
     }
-    const queries = panel.targets.map(t => ({ query: t.expr, format: t.format }));
-    return { queries };
+    return state;
   }
 
   getPrometheusTime(date, roundUp) {