diff --git a/docs/sources/http_api/annotations.md b/docs/sources/http_api/annotations.md index 19c2a5c386c..038ff085674 100644 --- a/docs/sources/http_api/annotations.md +++ b/docs/sources/http_api/annotations.md @@ -180,14 +180,14 @@ Content-Type: application/json ## Delete Annotation By Id -`DELETE /api/annotation/:id` +`DELETE /api/annotations/:id` Deletes the annotation that matches the specified id. **Example Request**: ```http -DELETE /api/annotation/1 HTTP/1.1 +DELETE /api/annotations/1 HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk @@ -204,14 +204,14 @@ Content-Type: application/json ## Delete Annotation By RegionId -`DELETE /api/annotation/region/:id` +`DELETE /api/annotations/region/:id` Deletes the annotation that matches the specified region id. A region is an annotation that covers a timerange and has a start and end time. In the Grafana database, this is a stored as two annotations connected by a region id. **Example Request**: ```http -DELETE /api/annotation/region/1 HTTP/1.1 +DELETE /api/annotations/region/1 HTTP/1.1 Accept: application/json Content-Type: application/json Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk diff --git a/docs/sources/installation/debian.md b/docs/sources/installation/debian.md index 27c0e41ac15..8b51a75a826 100644 --- a/docs/sources/installation/debian.md +++ b/docs/sources/installation/debian.md @@ -34,7 +34,7 @@ sudo dpkg -i grafana_5.0.4_amd64.deb Add the following line to your `/etc/apt/sources.list` file. ```bash -deb https://packagecloud.io/grafana/stable/debian/ jessie main +deb https://packagecloud.io/grafana/stable/debian/ stretch main ``` Use the above line even if you are on Ubuntu or another Debian version. @@ -42,7 +42,7 @@ There is also a testing repository if you want beta or release candidates. ```bash -deb https://packagecloud.io/grafana/testing/debian/ jessie main +deb https://packagecloud.io/grafana/testing/debian/ stretch main ``` Then add the [Package Cloud](https://packagecloud.io/grafana) key. This diff --git a/public/app/core/directives/dash_class.js b/public/app/core/directives/dash_class.js deleted file mode 100644 index 4a139272632..00000000000 --- a/public/app/core/directives/dash_class.js +++ /dev/null @@ -1,36 +0,0 @@ -define([ - 'lodash', - 'jquery', - '../core_module', -], -function (_, $, coreModule) { - 'use strict'; - - coreModule.default.directive('dashClass', function() { - return { - link: function($scope, elem) { - - $scope.onAppEvent('panel-fullscreen-enter', function() { - elem.toggleClass('panel-in-fullscreen', true); - }); - - $scope.onAppEvent('panel-fullscreen-exit', function() { - elem.toggleClass('panel-in-fullscreen', false); - }); - - $scope.$watch('ctrl.dashboardViewState.state.editview', function(newValue) { - if (newValue) { - elem.toggleClass('dashboard-page--settings-opening', _.isString(newValue)); - setTimeout(function() { - elem.toggleClass('dashboard-page--settings-open', _.isString(newValue)); - }, 10); - } else { - elem.removeClass('dashboard-page--settings-opening'); - elem.removeClass('dashboard-page--settings-open'); - } - }); - } - }; - }); - -}); diff --git a/public/app/core/directives/dash_class.ts b/public/app/core/directives/dash_class.ts new file mode 100644 index 00000000000..031338d3c5b --- /dev/null +++ b/public/app/core/directives/dash_class.ts @@ -0,0 +1,31 @@ +import _ from 'lodash'; +import coreModule from '../core_module'; + +/** @ngInject */ +export function dashClass() { + return { + link: function($scope, elem) { + $scope.onAppEvent('panel-fullscreen-enter', function() { + elem.toggleClass('panel-in-fullscreen', true); + }); + + $scope.onAppEvent('panel-fullscreen-exit', function() { + elem.toggleClass('panel-in-fullscreen', false); + }); + + $scope.$watch('ctrl.dashboardViewState.state.editview', function(newValue) { + if (newValue) { + elem.toggleClass('dashboard-page--settings-opening', _.isString(newValue)); + setTimeout(function() { + elem.toggleClass('dashboard-page--settings-open', _.isString(newValue)); + }, 10); + } else { + elem.removeClass('dashboard-page--settings-opening'); + elem.removeClass('dashboard-page--settings-open'); + } + }); + }, + }; +} + +coreModule.directive('dashClass', dashClass); diff --git a/public/app/core/directives/metric_segment.js b/public/app/core/directives/metric_segment.js deleted file mode 100644 index 7ba4a5a5259..00000000000 --- a/public/app/core/directives/metric_segment.js +++ /dev/null @@ -1,246 +0,0 @@ -define([ - 'lodash', - 'jquery', - '../core_module', -], -function (_, $, coreModule) { - 'use strict'; - - coreModule.default.directive('metricSegment', function($compile, $sce) { - var inputTemplate = ''; - - var linkTemplate = ''; - - var selectTemplate = ''; - - return { - scope: { - segment: "=", - getOptions: "&", - onChange: "&", - debounce: "@", - }, - link: function($scope, elem) { - var $input = $(inputTemplate); - var segment = $scope.segment; - var $button = $(segment.selectMode ? selectTemplate : linkTemplate); - var options = null; - var cancelBlur = null; - var linkMode = true; - var debounceLookup = $scope.debounce; - - $input.appendTo(elem); - $button.appendTo(elem); - - $scope.updateVariableValue = function(value) { - if (value === '' || segment.value === value) { - return; - } - - value = _.unescape(value); - - $scope.$apply(function() { - var selected = _.find($scope.altSegments, {value: value}); - if (selected) { - segment.value = selected.value; - segment.html = selected.html || selected.value; - segment.fake = false; - segment.expandable = selected.expandable; - - if (selected.type) { - segment.type = selected.type; - } - } - else if (segment.custom !== 'false') { - segment.value = value; - segment.html = $sce.trustAsHtml(value); - segment.expandable = true; - segment.fake = false; - } - - $scope.onChange(); - }); - }; - - $scope.switchToLink = function(fromClick) { - if (linkMode && !fromClick) { return; } - - clearTimeout(cancelBlur); - cancelBlur = null; - linkMode = true; - $input.hide(); - $button.show(); - $scope.updateVariableValue($input.val()); - }; - - $scope.inputBlur = function() { - // happens long before the click event on the typeahead options - // need to have long delay because the blur - cancelBlur = setTimeout($scope.switchToLink, 200); - }; - - $scope.source = function(query, callback) { - $scope.$apply(function() { - $scope.getOptions({ $query: query }).then(function(altSegments) { - $scope.altSegments = altSegments; - options = _.map($scope.altSegments, function(alt) { - return _.escape(alt.value); - }); - - // add custom values - if (segment.custom !== 'false') { - if (!segment.fake && _.indexOf(options, segment.value) === -1) { - options.unshift(segment.value); - } - } - - callback(options); - }); - }); - }; - - $scope.updater = function(value) { - if (value === segment.value) { - clearTimeout(cancelBlur); - $input.focus(); - return value; - } - - $input.val(value); - $scope.switchToLink(true); - - return value; - }; - - $scope.matcher = function(item) { - var str = this.query; - if (str[0] === '/') { str = str.substring(1); } - if (str[str.length - 1] === '/') { str = str.substring(0, str.length-1); } - try { - return item.toLowerCase().match(str.toLowerCase()); - } catch(e) { - return false; - } - }; - - $input.attr('data-provide', 'typeahead'); - $input.typeahead({ source: $scope.source, minLength: 0, items: 10000, updater: $scope.updater, matcher: $scope.matcher }); - - var typeahead = $input.data('typeahead'); - typeahead.lookup = function () { - this.query = this.$element.val() || ''; - var items = this.source(this.query, $.proxy(this.process, this)); - return items ? this.process(items) : items; - }; - - if (debounceLookup) { - typeahead.lookup = _.debounce(typeahead.lookup, 500, {leading: true}); - } - - $button.keydown(function(evt) { - // trigger typeahead on down arrow or enter key - if (evt.keyCode === 40 || evt.keyCode === 13) { - $button.click(); - } - }); - - $button.click(function() { - options = null; - $input.css('width', (Math.max($button.width(), 80) + 16) + 'px'); - - $button.hide(); - $input.show(); - $input.focus(); - - linkMode = false; - - var typeahead = $input.data('typeahead'); - if (typeahead) { - $input.val(''); - typeahead.lookup(); - } - }); - - $input.blur($scope.inputBlur); - - $compile(elem.contents())($scope); - } - }; - }); - - coreModule.default.directive('metricSegmentModel', function(uiSegmentSrv, $q) { - return { - template: '', - restrict: 'E', - scope: { - property: "=", - options: "=", - getOptions: "&", - onChange: "&", - }, - link: { - pre: function postLink($scope, elem, attrs) { - var cachedOptions; - - $scope.valueToSegment = function(value) { - var option = _.find($scope.options, {value: value}); - var segment = { - cssClass: attrs.cssClass, - custom: attrs.custom, - value: option ? option.text : value, - selectMode: attrs.selectMode, - }; - - return uiSegmentSrv.newSegment(segment); - }; - - $scope.getOptionsInternal = function() { - if ($scope.options) { - cachedOptions = $scope.options; - return $q.when(_.map($scope.options, function(option) { - return {value: option.text}; - })); - } else { - return $scope.getOptions().then(function(options) { - cachedOptions = options; - return _.map(options, function(option) { - if (option.html) { - return option; - } - return {value: option.text}; - }); - }); - } - }; - - $scope.onSegmentChange = function() { - if (cachedOptions) { - var option = _.find(cachedOptions, {text: $scope.segment.value}); - if (option && option.value !== $scope.property) { - $scope.property = option.value; - } else if (attrs.custom !== 'false') { - $scope.property = $scope.segment.value; - } - } else { - $scope.property = $scope.segment.value; - } - - // needs to call this after digest so - // property is synced with outerscope - $scope.$$postDigest(function() { - $scope.$apply(function() { - $scope.onChange(); - }); - }); - }; - - $scope.segment = $scope.valueToSegment($scope.property); - } - } - }; - }); -}); diff --git a/public/app/core/directives/metric_segment.ts b/public/app/core/directives/metric_segment.ts new file mode 100644 index 00000000000..3718d7fbd4a --- /dev/null +++ b/public/app/core/directives/metric_segment.ts @@ -0,0 +1,263 @@ +import _ from 'lodash'; +import $ from 'jquery'; +import coreModule from '../core_module'; + +/** @ngInject */ +export function metricSegment($compile, $sce) { + let inputTemplate = + ''; + + let linkTemplate = + ''; + + let selectTemplate = + ''; + + return { + scope: { + segment: '=', + getOptions: '&', + onChange: '&', + debounce: '@', + }, + link: function($scope, elem) { + let $input = $(inputTemplate); + let segment = $scope.segment; + let $button = $(segment.selectMode ? selectTemplate : linkTemplate); + let options = null; + let cancelBlur = null; + let linkMode = true; + let debounceLookup = $scope.debounce; + + $input.appendTo(elem); + $button.appendTo(elem); + + $scope.updateVariableValue = function(value) { + if (value === '' || segment.value === value) { + return; + } + + value = _.unescape(value); + + $scope.$apply(function() { + let selected = _.find($scope.altSegments, { value: value }); + if (selected) { + segment.value = selected.value; + segment.html = selected.html || selected.value; + segment.fake = false; + segment.expandable = selected.expandable; + + if (selected.type) { + segment.type = selected.type; + } + } else if (segment.custom !== 'false') { + segment.value = value; + segment.html = $sce.trustAsHtml(value); + segment.expandable = true; + segment.fake = false; + } + + $scope.onChange(); + }); + }; + + $scope.switchToLink = function(fromClick) { + if (linkMode && !fromClick) { + return; + } + + clearTimeout(cancelBlur); + cancelBlur = null; + linkMode = true; + $input.hide(); + $button.show(); + $scope.updateVariableValue($input.val()); + }; + + $scope.inputBlur = function() { + // happens long before the click event on the typeahead options + // need to have long delay because the blur + cancelBlur = setTimeout($scope.switchToLink, 200); + }; + + $scope.source = function(query, callback) { + $scope.$apply(function() { + $scope.getOptions({ $query: query }).then(function(altSegments) { + $scope.altSegments = altSegments; + options = _.map($scope.altSegments, function(alt) { + return _.escape(alt.value); + }); + + // add custom values + if (segment.custom !== 'false') { + if (!segment.fake && _.indexOf(options, segment.value) === -1) { + options.unshift(segment.value); + } + } + + callback(options); + }); + }); + }; + + $scope.updater = function(value) { + if (value === segment.value) { + clearTimeout(cancelBlur); + $input.focus(); + return value; + } + + $input.val(value); + $scope.switchToLink(true); + + return value; + }; + + $scope.matcher = function(item) { + let str = this.query; + if (str[0] === '/') { + str = str.substring(1); + } + if (str[str.length - 1] === '/') { + str = str.substring(0, str.length - 1); + } + try { + return item.toLowerCase().match(str.toLowerCase()); + } catch (e) { + return false; + } + }; + + $input.attr('data-provide', 'typeahead'); + $input.typeahead({ + source: $scope.source, + minLength: 0, + items: 10000, + updater: $scope.updater, + matcher: $scope.matcher, + }); + + let typeahead = $input.data('typeahead'); + typeahead.lookup = function() { + this.query = this.$element.val() || ''; + let items = this.source(this.query, $.proxy(this.process, this)); + return items ? this.process(items) : items; + }; + + if (debounceLookup) { + typeahead.lookup = _.debounce(typeahead.lookup, 500, { leading: true }); + } + + $button.keydown(function(evt) { + // trigger typeahead on down arrow or enter key + if (evt.keyCode === 40 || evt.keyCode === 13) { + $button.click(); + } + }); + + $button.click(function() { + options = null; + $input.css('width', Math.max($button.width(), 80) + 16 + 'px'); + + $button.hide(); + $input.show(); + $input.focus(); + + linkMode = false; + + let typeahead = $input.data('typeahead'); + if (typeahead) { + $input.val(''); + typeahead.lookup(); + } + }); + + $input.blur($scope.inputBlur); + + $compile(elem.contents())($scope); + }, + }; +} + +/** @ngInject */ +export function metricSegmentModel(uiSegmentSrv, $q) { + return { + template: + '', + restrict: 'E', + scope: { + property: '=', + options: '=', + getOptions: '&', + onChange: '&', + }, + link: { + pre: function postLink($scope, elem, attrs) { + let cachedOptions; + + $scope.valueToSegment = function(value) { + let option = _.find($scope.options, { value: value }); + let segment = { + cssClass: attrs.cssClass, + custom: attrs.custom, + value: option ? option.text : value, + selectMode: attrs.selectMode, + }; + + return uiSegmentSrv.newSegment(segment); + }; + + $scope.getOptionsInternal = function() { + if ($scope.options) { + cachedOptions = $scope.options; + return $q.when( + _.map($scope.options, function(option) { + return { value: option.text }; + }) + ); + } else { + return $scope.getOptions().then(function(options) { + cachedOptions = options; + return _.map(options, function(option) { + if (option.html) { + return option; + } + return { value: option.text }; + }); + }); + } + }; + + $scope.onSegmentChange = function() { + if (cachedOptions) { + let option = _.find(cachedOptions, { text: $scope.segment.value }); + if (option && option.value !== $scope.property) { + $scope.property = option.value; + } else if (attrs.custom !== 'false') { + $scope.property = $scope.segment.value; + } + } else { + $scope.property = $scope.segment.value; + } + + // needs to call this after digest so + // property is synced with outerscope + $scope.$$postDigest(function() { + $scope.$apply(function() { + $scope.onChange(); + }); + }); + }; + + $scope.segment = $scope.valueToSegment($scope.property); + }, + }, + }; +} + +coreModule.directive('metricSegment', metricSegment); +coreModule.directive('metricSegmentModel', metricSegmentModel); diff --git a/public/app/features/playlist/playlist_routes.ts b/public/app/features/playlist/playlist_routes.ts index c94446c2c1b..b898820e371 100644 --- a/public/app/features/playlist/playlist_routes.ts +++ b/public/app/features/playlist/playlist_routes.ts @@ -1,5 +1,6 @@ import angular from 'angular'; +/** @ngInject */ function grafanaRoutes($routeProvider) { $routeProvider .when('/playlists', { diff --git a/public/app/features/plugins/partials/ds_http_settings.html b/public/app/features/plugins/partials/ds_http_settings.html index 03df677ba13..b9f5683129c 100644 --- a/public/app/features/plugins/partials/ds_http_settings.html +++ b/public/app/features/plugins/partials/ds_http_settings.html @@ -1,5 +1,3 @@ - -

HTTP

@@ -13,12 +11,12 @@

Specify a complete HTTP URL (for example http://your_server:8080)

- Your access method is Direct, this means the URL + Your access method is Browser, this means the URL needs to be accessible from the browser. - Your access method is currently Proxy, this means the URL - needs to be accessible from the grafana backend. + Your access method is Server, this means the URL + needs to be accessible from the grafana backend/server.
@@ -27,14 +25,38 @@
Access -
- - - Direct = URL is used directly from browser
- Proxy = Grafana backend will proxy the request -
+
+
+
+ +
+
+ +
+
+

+ Access mode controls how requests to the data source will be handled. + Server should be the preferred way if nothing else stated. +

+
Server access mode (Default):
+

+ All requests will be made from the browser to Grafana backend/server which in turn will forward the requests to the data source + and by that circumvent possible Cross-Origin Resource Sharing (CORS) requirements. + The URL needs to be accessible from the grafana backend/server if you select this access mode. +

+
Browser access mode:
+

+ All requests will be made from the browser directly to the data source and may be subject to + Cross-Origin Resource Sharing (CORS) requirements. The URL needs to be accessible from the browser if you select this + access mode. +

+
@@ -135,4 +157,3 @@
- diff --git a/public/app/plugins/datasource/prometheus/partials/query.editor.html b/public/app/plugins/datasource/prometheus/partials/query.editor.html index 8d6e89c3406..68791d96c19 100644 --- a/public/app/plugins/datasource/prometheus/partials/query.editor.html +++ b/public/app/plugins/datasource/prometheus/partials/query.editor.html @@ -14,7 +14,7 @@ data-min-length=0 data-items=1000 ng-model-onblur ng-change="ctrl.refreshMetricData()"> - Controls the name of the time series, using name or pattern. For example {{hostname}} will be replaced with label value for + Controls the name of the time series, using name or pattern. For example {{hostname}} will be replaced with label value for the label hostname. diff --git a/public/sass/base/_icons.scss b/public/sass/base/_icons.scss index 31e5ee62d6f..c701cc1249e 100644 --- a/public/sass/base/_icons.scss +++ b/public/sass/base/_icons.scss @@ -1,10 +1,8 @@ .gicon { line-height: 1; display: inline-block; - //width: 1.1057142857em; - //height: 1.1057142857em; - height: 22px; - width: 22px; + width: 1.1057142857em; + height: 1.1057142857em; text-align: center; background-repeat: no-repeat; background-position: center; diff --git a/public/sass/components/_sidemenu.scss b/public/sass/components/_sidemenu.scss index e48ab0597a2..d1372484074 100644 --- a/public/sass/components/_sidemenu.scss +++ b/public/sass/components/_sidemenu.scss @@ -123,6 +123,8 @@ position: relative; opacity: 0.7; font-size: 130%; + height: 22px; + width: 22px; } .fa { diff --git a/public/sass/pages/_dashboard.scss b/public/sass/pages/_dashboard.scss index c957b6af790..871db4dfc2d 100644 --- a/public/sass/pages/_dashboard.scss +++ b/public/sass/pages/_dashboard.scss @@ -33,7 +33,7 @@ div.flot-text { border: $panel-border; position: relative; border-radius: 3px; - //height: 100%; + height: 100%; &.panel-transparent { background-color: transparent;