diff --git a/public/app/containers/Explore/Explore.tsx b/public/app/containers/Explore/Explore.tsx index eae3f4d0a1f..ba1cb6807a6 100644 --- a/public/app/containers/Explore/Explore.tsx +++ b/public/app/containers/Explore/Explore.tsx @@ -38,6 +38,19 @@ function makeTimeSeriesList(dataList, options) { }); } +function parseInitialQueries(initial) { + if (!initial) { + return []; + } + try { + const parsed = JSON.parse(initial); + return parsed.queries.map(q => q.query); + } catch (e) { + console.error(e); + return []; + } +} + interface IExploreState { datasource: any; datasourceError: any; @@ -58,6 +71,7 @@ export class Explore extends React.Component { constructor(props) { super(props); + const initialQueries = parseInitialQueries(props.routeParams.initial); this.state = { datasource: null, datasourceError: null, @@ -65,7 +79,7 @@ export class Explore extends React.Component { graphResult: null, latency: 0, loading: false, - queries: ensureQueries(), + queries: ensureQueries(initialQueries), requestOptions: null, showingGraph: true, showingTable: true, @@ -77,7 +91,7 @@ export class Explore extends React.Component { const datasource = await this.props.datasourceSrv.get(); const testResult = await datasource.testDatasource(); if (testResult.status === 'success') { - this.setState({ datasource, datasourceError: null, datasourceLoading: false }); + this.setState({ datasource, datasourceError: null, datasourceLoading: false }, () => this.handleSubmit()); } else { this.setState({ datasource: null, datasourceError: testResult.message, datasourceLoading: false }); } diff --git a/public/app/containers/Explore/QueryRows.tsx b/public/app/containers/Explore/QueryRows.tsx index a0a9981368d..3940d16b2f6 100644 --- a/public/app/containers/Explore/QueryRows.tsx +++ b/public/app/containers/Explore/QueryRows.tsx @@ -6,13 +6,16 @@ class QueryRow extends PureComponent { constructor(props) { super(props); this.state = { - query: '', + edited: false, + query: props.query || '', }; } handleChangeQuery = value => { const { index, onChangeQuery } = this.props; - this.setState({ query: value }); + const { query } = this.state; + const edited = query !== value; + this.setState({ edited, query: value }); if (onChangeQuery) { onChangeQuery(value, index); } @@ -41,6 +44,7 @@ class QueryRow extends PureComponent { render() { const { request } = this.props; + const { edited, query } = this.state; return (
@@ -52,7 +56,12 @@ class QueryRow extends PureComponent {
- +
); @@ -63,7 +72,9 @@ export default class QueryRows extends PureComponent { render() { const { className = '', queries, ...handlers } = this.props; return ( -
{queries.map((q, index) => )}
+
+ {queries.map((q, index) => )} +
); } } diff --git a/public/app/features/panel/panel_ctrl.ts b/public/app/features/panel/panel_ctrl.ts index da8adc4f908..cdd2bc2be60 100644 --- a/public/app/features/panel/panel_ctrl.ts +++ b/public/app/features/panel/panel_ctrl.ts @@ -22,6 +22,7 @@ export class PanelCtrl { editorTabs: any; $scope: any; $injector: any; + $location: any; $timeout: any; fullscreen: boolean; inspector: any; @@ -35,6 +36,7 @@ export class PanelCtrl { constructor($scope, $injector) { this.$injector = $injector; + this.$location = $injector.get('$location'); this.$scope = $scope; this.$timeout = $injector.get('$timeout'); this.editorTabIndex = 0; @@ -97,6 +99,12 @@ 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'); @@ -154,6 +162,16 @@ 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();', diff --git a/public/app/plugins/datasource/prometheus/datasource.ts b/public/app/plugins/datasource/prometheus/datasource.ts index 2a8b3069a53..221bffbda67 100644 --- a/public/app/plugins/datasource/prometheus/datasource.ts +++ b/public/app/plugins/datasource/prometheus/datasource.ts @@ -19,6 +19,7 @@ export class PrometheusDatasource { type: string; editorSrc: string; name: string; + supportsExplore: boolean; supportMetrics: boolean; url: string; directUrl: string; @@ -34,6 +35,7 @@ export class PrometheusDatasource { this.type = 'prometheus'; this.editorSrc = 'app/features/prometheus/partials/query.editor.html'; this.name = instanceSettings.name; + this.supportsExplore = true; this.supportMetrics = true; this.url = instanceSettings.url; this.directUrl = instanceSettings.directUrl; @@ -323,6 +325,14 @@ export class PrometheusDatasource { }); } + getExploreState(panel) { + if (!panel.targets) { + return {}; + } + const queries = panel.targets.map(t => ({ query: t.expr, format: t.format })); + return { queries }; + } + getPrometheusTime(date, roundUp) { if (_.isString(date)) { date = dateMath.parse(date, roundUp); diff --git a/public/app/plugins/panel/pluginlist/module.ts b/public/app/plugins/panel/pluginlist/module.ts index e97b1a8fbf9..acfa69b171c 100644 --- a/public/app/plugins/panel/pluginlist/module.ts +++ b/public/app/plugins/panel/pluginlist/module.ts @@ -12,7 +12,7 @@ class PluginListCtrl extends PanelCtrl { panelDefaults = {}; /** @ngInject */ - constructor($scope, $injector, private backendSrv, private $location) { + constructor($scope, $injector, private backendSrv) { super($scope, $injector); _.defaults(this.panel, this.panelDefaults); diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts index c7f523a9591..28d3f308d68 100644 --- a/public/app/plugins/panel/singlestat/module.ts +++ b/public/app/plugins/panel/singlestat/module.ts @@ -77,7 +77,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { }; /** @ngInject */ - constructor($scope, $injector, private $location, private linkSrv) { + constructor($scope, $injector, private linkSrv) { super($scope, $injector); _.defaults(this.panel, this.panelDefaults); diff --git a/public/app/routes/ReactContainer.tsx b/public/app/routes/ReactContainer.tsx index d6d34372090..db6938cc878 100644 --- a/public/app/routes/ReactContainer.tsx +++ b/public/app/routes/ReactContainer.tsx @@ -29,6 +29,7 @@ export function reactContainer($route, $location, backendSrv: BackendSrv, dataso const props = { backendSrv: backendSrv, datasourceSrv: datasourceSrv, + routeParams: $route.current.params, }; ReactDOM.render(WrapInProvider(store, component, props), elem[0]); diff --git a/public/app/routes/routes.ts b/public/app/routes/routes.ts index 49690561728..6a61315f956 100644 --- a/public/app/routes/routes.ts +++ b/public/app/routes/routes.ts @@ -111,7 +111,7 @@ export function setupAngularRoutes($routeProvider, $locationProvider) { controller: 'FolderDashboardsCtrl', controllerAs: 'ctrl', }) - .when('/explore', { + .when('/explore/:initial?', { template: '', resolve: { component: () => import(/* webpackChunkName: "explore" */ 'app/containers/Explore/Explore'),