Commit 6ad1a396 by Torkel Ödegaard

feat: query troubleshooter

parent 5513d3c9
///<reference path="../../headers/common.d.ts" />
import coreModule from 'app/core/core_module';
const template = `
<div class="collapse-box">
<div class="collapse-box__header">
<a class="collapse-box__header-title pointer" ng-click="ctrl.toggle()">
<span class="fa fa-fw fa-caret-right" ng-hide="ctrl.isOpen"></span>
<span class="fa fa-fw fa-caret-down" ng-hide="!ctrl.isOpen"></span>
{{ctrl.title}}
</a>
<div class="collapse-box__header-actions" ng-transclude="actions"></div>
</div>
<div class="collapse-box__body" ng-transclude="body" ng-if="ctrl.isOpen">
</div>
</div>
`;
export class CollapseBoxCtrl {
isOpen: boolean;
onOpen: () => void;
/** @ngInject **/
constructor() {
this.isOpen = false;
}
toggle() {
this.isOpen = !this.isOpen;
if (this.isOpen) {
this.onOpen();
}
}
}
export function collapseBox() {
return {
restrict: 'E',
template: template,
controller: CollapseBoxCtrl,
bindToController: true,
controllerAs: 'ctrl',
scope: {
"title": "@",
"isOpen": "=?",
"onOpen": "&"
},
transclude: {
'actions': '?collapseBoxActions',
'body': 'collapseBoxBody',
},
link: function(scope, elem, attrs) {
}
};
}
coreModule.directive('collapseBox', collapseBox);
......@@ -45,7 +45,7 @@ const _defaultConfig: JsonExplorerConfig = {
* JsonExplorer allows you to render JSON objects in HTML with a
* **collapsible** navigation.
*/
export default class JsonExplorer {
export class JsonExplorer {
// Hold the open state after the toggler is used
private _isOpen: boolean = null;
......@@ -273,7 +273,7 @@ export default class JsonExplorer {
*
* @returns {HTMLDivElement}
*/
render(): HTMLDivElement {
render(skipRoot = false): HTMLDivElement {
// construct the root element and assign it to this.element
this.element = createElement('div', 'row');
......@@ -371,7 +371,9 @@ export default class JsonExplorer {
}
// append toggler and children elements to root element
this.element.appendChild(togglerLink);
if (!skipRoot) {
this.element.appendChild(togglerLink);
}
this.element.appendChild(children);
// if formatter is set to be open call appendChildren
......
///<reference path="../../headers/common.d.ts" />
import coreModule from 'app/core/core_module';
import JsonExplorer from './json_explorer/json_explorer';
const template = `
<div class="response-viewer">
<div class="response-viewer-json"></div>
</div>
`;
export function responseViewer() {
return {
restrict: 'E',
template: template,
scope: {response: "="},
link: function(scope, elem) {
var jsonElem = elem.find('.response-viewer-json');
scope.$watch("response", newVal => {
if (!newVal) {
elem.empty();
return;
}
if (scope.response.headers) {
delete scope.response.headers;
}
if (scope.response.data) {
scope.response.response = scope.response.data;
delete scope.response.data;
}
if (scope.response.config) {
scope.response.request = scope.response.config;
delete scope.response.config;
delete scope.response.request.transformRequest;
delete scope.response.request.transformResponse;
delete scope.response.request.paramSerializer;
delete scope.response.request.jsonpCallbackParam;
delete scope.response.request.headers;
delete scope.response.request.requestId;
delete scope.response.request.inspect;
delete scope.response.request.retry;
delete scope.response.request.timeout;
}
const formatter = new JsonExplorer(scope.response, 2, {
theme: 'dark',
});
const html = formatter.render();
jsonElem.html(html);
});
}
};
}
coreModule.directive('responseViewer', responseViewer);
......@@ -45,7 +45,8 @@ import {assignModelProperties} from './utils/model_utils';
import {contextSrv} from './services/context_srv';
import {KeybindingSrv} from './services/keybindingSrv';
import {helpModal} from './components/help/help';
import {responseViewer} from './components/response_viewer';
import {collapseBox} from './components/collapse_box';
import {JsonExplorer} from './components/json_explorer/json_explorer';
export {
arrayJoin,
......@@ -69,5 +70,6 @@ export {
contextSrv,
KeybindingSrv,
helpModal,
responseViewer,
collapseBox,
JsonExplorer,
};
......@@ -6,4 +6,5 @@ define([
'./panel_editor_tab',
'./query_editor_row',
'./metrics_ds_selector',
'./query_troubleshooter',
], function () {});
......@@ -8,10 +8,6 @@ var module = angular.module('grafana.directives');
var template = `
<div class="gf-form-group" ng-if="ctrl.showResponse">
<response-viewer response="ctrl.responseData" />
</div>
<div class="gf-form-group">
<div class="gf-form-inline">
<div class="gf-form">
......@@ -40,13 +36,6 @@ var template = `
</div>
</div>
<div class="gf-form gf-form--offset-1">
<button class="btn btn-inverse gf-form-btn" ng-click="ctrl.toggleShowResponse()" ng-show="ctrl.responseData">
<i class="fa fa-binoculars"></i>&nbsp;
Request & Response
</button>
</div>
</div>
</div>
`;
......@@ -81,24 +70,8 @@ export class MetricsDsSelectorCtrl {
this.dsSegment = uiSegmentSrv.newSegment({value: this.current.name, selectMode: true});
this.mixedDsSegment = uiSegmentSrv.newSegment({value: 'Add Query', selectMode: true});
appEvents.on('ds-request-response', this.onRequestResponse.bind(this), $scope);
appEvents.on('ds-request-error', this.onRequestError.bind(this), $scope);
}
onRequestResponse(data) {
this.responseData = data;
}
toggleShowResponse() {
this.showResponse = !this.showResponse;
}
onRequestError(err) {
this.responseData = err;
this.responseData.isError = true;
this.showResponse = true;
}
getOptions(includeBuiltin) {
return Promise.resolve(this.datasources.filter(value => {
......
///<reference path="../../headers/common.d.ts" />
import _ from 'lodash';
import appEvents from 'app/core/app_events';
import {coreModule, JsonExplorer} from 'app/core/core';
const template = `
<collapse-box title="Query Troubleshooter" is-open="ctrl.showResponse" on-open="ctrl.onOpen()">
<collapse-box-actions>
<a class="pointer"><i class="fa fa-clipboard"></i> Copy to clipboard</a>
</collapse-box-actions>
<collapse-box-body>
<div class="query-troubleshooter-json"></div>
</collapse-box-body>
</collapse-box>
`;
export class QueryTroubleshooterCtrl {
responseData: any;
showResponse: boolean;
panelCtrl: any;
renderJsonExplorer: (data) => void;
/** @ngInject **/
constructor($scope, private $timeout) {
appEvents.on('ds-request-response', this.onRequestResponse.bind(this), $scope);
appEvents.on('ds-request-error', this.onRequestError.bind(this), $scope);
}
onRequestResponse(data) {
this.responseData = data;
}
toggleShowResponse() {
this.showResponse = !this.showResponse;
}
onRequestError(err) {
this.responseData = err;
this.responseData.isError = true;
this.showResponse = true;
}
onOpen() {
if (!this.responseData) {
console.log('no data');
return;
}
var data = this.responseData;
if (data.headers) {
delete data.headers;
}
if (data.config) {
data.request = data.config;
delete data.config;
delete data.request.transformRequest;
delete data.request.transformResponse;
delete data.request.paramSerializer;
delete data.request.jsonpCallbackParam;
delete data.request.headers;
delete data.request.requestId;
delete data.request.inspect;
delete data.request.retry;
delete data.request.timeout;
}
if (data.data) {
data.response = data.data;
delete data.data;
delete data.status;
delete data.statusText;
delete data.$$config;
}
this.$timeout(_.partial(this.renderJsonExplorer, data), 10);
}
}
export function queryTroubleshooter() {
return {
restrict: 'E',
template: template,
controller: QueryTroubleshooterCtrl,
bindToController: true,
controllerAs: 'ctrl',
scope: {
panelCtrl: "="
},
link: function(scope, elem, attrs, ctrl) {
ctrl.renderJsonExplorer = function(data) {
var jsonElem = elem.find('.query-troubleshooter-json');
const formatter = new JsonExplorer(data, 2, {
theme: 'dark',
});
const html = formatter.render(true);
jsonElem.html(html);
};
}
};
}
coreModule.directive('queryTroubleshooter', queryTroubleshooter);
<metrics-ds-selector panel-ctrl="ctrl"></metrics-ds-selector>
<div class="query-editor-rows gf-form-group">
<div ng-repeat="target in ctrl.panel.targets" ng-class="{'gf-form-disabled': target.hide}">
<rebuild-on-change property="ctrl.panel.datasource || target.datasource" show-null="true">
......@@ -8,7 +10,7 @@
</div>
</div>
<metrics-ds-selector panel-ctrl="ctrl"></metrics-ds-selector>
<query-troubleshooter panel-ctrl="ctrl"></query-troubleshooter>
<div class="gf-form-group">
<rebuild-on-change property="ctrl.panel.datasource" show-null="true">
......
......@@ -75,8 +75,8 @@
@import "components/jsontree";
@import "components/edit_sidemenu.scss";
@import "components/row.scss";
@import "components/response_viewer.scss";
@import "components/json_explorer.scss";
@import "components/collapse_box.scss";
// PAGES
@import "pages/login";
......
.collapse-box {
margin-bottom: $spacer;
}
.collapse-box__header {
display: flex;
flex-direction: row;
padding: $input-padding-y $input-padding-x;
margin-right: $gf-form-margin;
background-color: $input-bg;
font-size: $font-size-sm;
margin-right: $gf-form-margin;
border: $input-btn-border-width solid transparent;
@include border-radius($label-border-radius-sm);
}
.collapse-box__header-title {
flex-grow: 1;
}
.collapse-box__body {
padding: $input-padding-y*2 $input-padding-x;
background-color: $input-label-bg;
display: block;
margin-right: $gf-form-margin;
border: $input-btn-border-width solid transparent;
@include border-radius($label-border-radius-sm);
}
......@@ -36,7 +36,7 @@
.json-formatter-string {
color: $string-color;
white-space: pre;
white-space: normal;
word-wrap: break-word;
}
.json-formatter-number { color: $number-color; }
......
.response-viewer {
background: $card-background;
box-shadow: $card-shadow;
padding: 1rem;
border-radius: 4px;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment