diff --git a/CHANGELOG.md b/CHANGELOG.md index 4dd0adba4c5..73d7aad8fb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ * **Graph Panel**: Log base scale on right Y-axis had no effect, max value calc was not applied, [#6534](https://github.com/grafana/grafana/issues/6534) * **Graph Panel**: Bar width if bars was only used in series override, [#6528](https://github.com/grafana/grafana/issues/6528) * **UI/Browser**: Fixed issue with page/view header gradient border not showing in Safari, [#6530](https://github.com/grafana/grafana/issues/6530) +* **UX**: Panel Drop zone visible after duplicating panel, and when entering fullscreen/edit view, [#6598](https://github.com/grafana/grafana/issues/6598) + +### Enhancements +* **Singlestat**: Support repeated template variables in prefix/postfix [#6595](https://github.com/grafana/grafana/issues/6595) # 4.0-beta1 (2016-11-09) diff --git a/docs/sources/alerting/notifications.md b/docs/sources/alerting/notifications.md index ce9dcdf1b93..dfe84f142ec 100644 --- a/docs/sources/alerting/notifications.md +++ b/docs/sources/alerting/notifications.md @@ -98,6 +98,6 @@ Amazon S3 for this and Webdav. So to set that up you need to configure the [external image uploader](/installation/configuration/#external-image-storage) in your grafana-server ini config file. -This is not an optional requirement, you can get slack and email notifications without setting this up. +This is an optional requirement, you can get slack and email notifications without setting this up. diff --git a/docs/sources/datasources/plugin_api.md b/docs/sources/datasources/plugin_api.md index cdcaca29460..2e2121ed21a 100644 --- a/docs/sources/datasources/plugin_api.md +++ b/docs/sources/datasources/plugin_api.md @@ -30,11 +30,5 @@ Even though the data source type name is with lowercase `g`, the directive uses that is how angular directives needs to be named in order to match an element with name ``. You also specify the query controller here instead of in the query.editor.html partial like before. -### query.editor.html - -This partial needs to be updated, remove the `np-repeat` this is done in the outer partial now,m the query.editor.html -should only render a single query. Take a look at the Graphite or InfluxDB partials for `query.editor.html` for reference. -You should also add a `tight-form-item` with `{{target.refId}}`, all queries needs to be assigned a letter (`refId`). -These query reference letters are going to be utilized in a later feature. diff --git a/docs/sources/installation/rpm.md b/docs/sources/installation/rpm.md index cf33e69aa12..ca71a2355f9 100644 --- a/docs/sources/installation/rpm.md +++ b/docs/sources/installation/rpm.md @@ -141,6 +141,18 @@ those options. - [OpenTSDB]({{< relref "datasources/opentsdb.md" >}}) - [Prometheus]({{< relref "datasources/prometheus.md" >}}) +### Server side image rendering + +Server side image (png) rendering is a feature that is optional but very useful when sharing visualizations, +for example in alert notifications. + +If the image is missing text make sure you have font packages installed. + +``` +yum install fontconfig +yum install freetype* +yum install urw-fonts +``` ## Installing from binary tar file diff --git a/pkg/api/api.go b/pkg/api/api.go index ed73f2dc76d..4fa28f799b0 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -307,4 +307,5 @@ func Register(r *macaron.Macaron) { InitAppPluginRoutes(r) + r.NotFound(NotFoundHandler) } diff --git a/pkg/api/login_oauth.go b/pkg/api/login_oauth.go index b174f88d649..2e58d9155fc 100644 --- a/pkg/api/login_oauth.go +++ b/pkg/api/login_oauth.go @@ -96,7 +96,7 @@ func OAuthLogin(ctx *middleware.Context) { } sslcli := &http.Client{Transport: tr} - oauthCtx = context.TODO() + oauthCtx = context.Background() oauthCtx = context.WithValue(oauthCtx, oauth2.HTTPClient, sslcli) } @@ -106,6 +106,8 @@ func OAuthLogin(ctx *middleware.Context) { ctx.Handle(500, "login.OAuthLogin(NewTransportWithCode)", err) return } + // token.TokenType was defaulting to "bearer", which is out of spec, so we explicitly set to "Bearer" + token.TokenType = "Bearer" ctx.Logger.Debug("OAuthLogin Got token") diff --git a/pkg/middleware/middleware.go b/pkg/middleware/middleware.go index cb3f4480821..a546d7e76fc 100644 --- a/pkg/middleware/middleware.go +++ b/pkg/middleware/middleware.go @@ -187,6 +187,7 @@ func (ctx *Context) Handle(status int, title string, err error) { } ctx.Data["Title"] = title + ctx.Data["AppSubUrl"] = setting.AppSubUrl ctx.HTML(status, strconv.Itoa(status)) } diff --git a/pkg/middleware/recovery.go b/pkg/middleware/recovery.go index 8843f2e55d3..b63bc623549 100644 --- a/pkg/middleware/recovery.go +++ b/pkg/middleware/recovery.go @@ -19,53 +19,14 @@ import ( "bytes" "fmt" "io/ioutil" - "net/http" "runtime" "gopkg.in/macaron.v1" - "github.com/go-macaron/inject" "github.com/grafana/grafana/pkg/log" "github.com/grafana/grafana/pkg/setting" ) -const ( - panicHtml = ` -PANIC: %s - - - -

PANIC

-
%s
-
%s
- -` -) - var ( dunno = []byte("???") centerDot = []byte("ยท") @@ -151,21 +112,34 @@ func Recovery() macaron.Handler { panicLogger.Error("Request error", "error", err, "stack", string(stack)) - // Lookup the current responsewriter - val := c.GetVal(inject.InterfaceOf((*http.ResponseWriter)(nil))) - res := val.Interface().(http.ResponseWriter) + c.Data["Title"] = "Server Error" + c.Data["AppSubUrl"] = setting.AppSubUrl + + if theErr, ok := err.(error); ok { + c.Data["Title"] = theErr.Error() + } - // respond with panic message while in development mode - var body []byte if setting.Env == setting.DEV { - res.Header().Set("Content-Type", "text/html") - body = []byte(fmt.Sprintf(panicHtml, err, err, stack)) + c.Data["ErrorMsg"] = string(stack) } - res.WriteHeader(http.StatusInternalServerError) - if nil != body { - res.Write(body) - } + c.HTML(500, "500") + + // // Lookup the current responsewriter + // val := c.GetVal(inject.InterfaceOf((*http.ResponseWriter)(nil))) + // res := val.Interface().(http.ResponseWriter) + // + // // respond with panic message while in development mode + // var body []byte + // if setting.Env == setting.DEV { + // res.Header().Set("Content-Type", "text/html") + // body = []byte(fmt.Sprintf(panicHtml, err, err, stack)) + // } + // + // res.WriteHeader(http.StatusInternalServerError) + // if nil != body { + // res.Write(body) + // } } }() diff --git a/public/app/app.ts b/public/app/app.ts index c004bac4177..22431a5110c 100644 --- a/public/app/app.ts +++ b/public/app/app.ts @@ -40,7 +40,6 @@ export class GrafanaApp { init() { var app = angular.module('grafana', []); - app.constant('grafanaVersion', "@grafanaVersion@"); moment.locale(config.bootData.user.locale); diff --git a/public/app/core/components/grafana_app.ts b/public/app/core/components/grafana_app.ts index ed3425f670f..40797e9a47c 100644 --- a/public/app/core/components/grafana_app.ts +++ b/public/app/core/components/grafana_app.ts @@ -122,7 +122,7 @@ export function grafanaAppDirective(playlistSrv, contextSrv) { // handle in active view state class var lastActivity = new Date().getTime(); var activeUser = true; - var inActiveTimeLimit = 60 * 1000; + var inActiveTimeLimit = 10 * 1000; function checkForInActiveUser() { if (!activeUser) { @@ -147,9 +147,14 @@ export function grafanaAppDirective(playlistSrv, contextSrv) { } } + // mouse and keyboard is user activity body.mousemove(userActivityDetected); body.keydown(userActivityDetected); - setInterval(checkForInActiveUser, 1000); + // treat tab change as activity + document.addEventListener('visibilitychange', userActivityDetected); + + // check every 2 seconds + setInterval(checkForInActiveUser, 2000); appEvents.on('toggle-view-mode', () => { lastActivity = 0; diff --git a/public/app/core/core.ts b/public/app/core/core.ts index 8e9f64fd17f..4aa2e7eb64a 100644 --- a/public/app/core/core.ts +++ b/public/app/core/core.ts @@ -6,7 +6,6 @@ import "./directives/dash_class"; import "./directives/confirm_click"; import "./directives/dash_edit_link"; import "./directives/dropdown_typeahead"; -import "./directives/grafana_version_check"; import "./directives/metric_segment"; import "./directives/misc"; import "./directives/ng_model_on_blur"; diff --git a/public/app/core/directives/grafana_version_check.js b/public/app/core/directives/grafana_version_check.js deleted file mode 100644 index bee437b8183..00000000000 --- a/public/app/core/directives/grafana_version_check.js +++ /dev/null @@ -1,31 +0,0 @@ -define([ - '../core_module', -], -function (coreModule) { - 'use strict'; - - coreModule.default.directive('grafanaVersionCheck', function($http, contextSrv) { - return { - restrict: 'A', - link: function(scope, elem) { - if (contextSrv.version === 'master') { - return; - } - - $http({ method: 'GET', url: 'https://grafanarel.s3.amazonaws.com/latest.json' }) - .then(function(response) { - if (!response.data || !response.data.version) { - return; - } - - if (contextSrv.version !== response.data.version) { - elem.append(' ' + - ' ' + - 'New version available: ' + response.data.version + - ''); - } - }); - } - }; - }); -}); diff --git a/public/app/core/utils/kbn.js b/public/app/core/utils/kbn.js index a807a249235..78489dcae58 100644 --- a/public/app/core/utils/kbn.js +++ b/public/app/core/utils/kbn.js @@ -420,11 +420,11 @@ function($, _, moment) { kbn.valueFormats.bps = kbn.formatBuilders.decimalSIPrefix('bps'); kbn.valueFormats.Bps = kbn.formatBuilders.decimalSIPrefix('Bps'); kbn.valueFormats.KBs = kbn.formatBuilders.decimalSIPrefix('Bs', 1); - kbn.valueFormats.Kbits = kbn.formatBuilders.decimalSIPrefix('bits', 1); + kbn.valueFormats.Kbits = kbn.formatBuilders.decimalSIPrefix('bps', 1); kbn.valueFormats.MBs = kbn.formatBuilders.decimalSIPrefix('Bs', 2); - kbn.valueFormats.Mbits = kbn.formatBuilders.decimalSIPrefix('bits', 2); + kbn.valueFormats.Mbits = kbn.formatBuilders.decimalSIPrefix('bps', 2); kbn.valueFormats.GBs = kbn.formatBuilders.decimalSIPrefix('Bs', 3); - kbn.valueFormats.Gbits = kbn.formatBuilders.decimalSIPrefix('bits', 3); + kbn.valueFormats.Gbits = kbn.formatBuilders.decimalSIPrefix('bps', 3); // Throughput kbn.valueFormats.ops = kbn.formatBuilders.simpleCountUnit('ops'); diff --git a/public/app/features/dashboard/dynamic_dashboard_srv.ts b/public/app/features/dashboard/dynamic_dashboard_srv.ts index 9f8fe7f7ab2..e5f1c6a9fa1 100644 --- a/public/app/features/dashboard/dynamic_dashboard_srv.ts +++ b/public/app/features/dashboard/dynamic_dashboard_srv.ts @@ -64,6 +64,8 @@ export class DynamicDashboardSrv { j = j - 1; } } + + row.panelSpanChanged(); } } diff --git a/public/app/features/dashboard/model.ts b/public/app/features/dashboard/model.ts index ad28ce4643c..999c0470fdd 100644 --- a/public/app/features/dashboard/model.ts +++ b/public/app/features/dashboard/model.ts @@ -233,7 +233,6 @@ export class DashboardModel { } duplicatePanel(panel, row) { - var rowIndex = _.indexOf(this.rows, row); var newPanel = angular.copy(panel); newPanel.id = this.getNextPanelId(); @@ -241,9 +240,9 @@ export class DashboardModel { delete newPanel.repeatIteration; delete newPanel.repeatPanelId; delete newPanel.scopedVars; + delete newPanel.alert; - var currentRow = this.rows[rowIndex]; - currentRow.panels.push(newPanel); + row.addPanel(newPanel); return newPanel; } diff --git a/public/app/features/dashboard/partials/globalAlerts.html b/public/app/features/dashboard/partials/globalAlerts.html deleted file mode 100644 index 2c065c714fb..00000000000 --- a/public/app/features/dashboard/partials/globalAlerts.html +++ /dev/null @@ -1,282 +0,0 @@ - - - - -
-
-

Global alerts

- -
-
-
    -
  • Filters:
  • -
  • Alert State
  • -
  • -
  • Dashboards
  • -
  • -
  • - - - -
  • -
-
-
-
-
    -
  • - -
  • -
  • - -
  • -
  • - -
  • -
  • - 2 selected, showing 6 of 6 total -
  • -
-
    -
  • - -
    -
    Alert query configure alerting
    -
    -
      -
    • A
    • -
    • apps
    • -
    • -
    • fakesite
    • -
    • counters
    • -
    • requests
    • -
    • count
    • -
    • scaleToSeconds(1)
    • -
    • aliasByNode(2)
    • -
    -
    -
    -
    -
  • -
  • - -
    -
    Alert query configure alerting
    -
    -
      -
    • A
    • -
    • apps
    • -
    • -
    • fakesite
    • -
    • counters
    • -
    • requests
    • -
    • count
    • -
    • scaleToSeconds(1)
    • -
    • aliasByNode(2)
    • -
    -
    -
    -
    -
  • -
  • - -
    -
    Alert query configure alerting
    -
    -
      -
    • A
    • -
    • apps
    • -
    • -
    • fakesite
    • -
    • counters
    • -
    • requests
    • -
    • count
    • -
    • scaleToSeconds(1)
    • -
    • aliasByNode(2)
    • -
    -
    -
    -
    -
  • -
  • - -
    -
    Alert query configure alerting
    -
    -
      -
    • A
    • -
    • apps
    • -
    • -
    • fakesite
    • -
    • counters
    • -
    • requests
    • -
    • count
    • -
    • scaleToSeconds(1)
    • -
    • aliasByNode(2)
    • -
    -
    -
    -
    -
  • -
  • - -
    -
    Alert query configure alerting
    -
    -
      -
    • A
    • -
    • apps
    • -
    • -
    • fakesite
    • -
    • counters
    • -
    • requests
    • -
    • count
    • -
    • scaleToSeconds(1)
    • -
    • aliasByNode(2)
    • -
    -
    -
    -
    -
  • -
-
-
diff --git a/public/app/features/dashboard/specs/dashboard_srv_specs.ts b/public/app/features/dashboard/specs/dashboard_srv_specs.ts index 520216f18ec..6646851e597 100644 --- a/public/app/features/dashboard/specs/dashboard_srv_specs.ts +++ b/public/app/features/dashboard/specs/dashboard_srv_specs.ts @@ -62,7 +62,9 @@ describe('dashboardSrv', function() { it('duplicate panel should try to add it to same row', function() { var panel = { span: 4, attr: '123', id: 10 }; - dashboard.rows = [{ panels: [panel] }]; + + dashboard.addEmptyRow(); + dashboard.rows[0].addPanel(panel); dashboard.duplicatePanel(panel, dashboard.rows[0]); expect(dashboard.rows[0].panels[0].span).to.be(4); @@ -73,7 +75,9 @@ describe('dashboardSrv', function() { it('duplicate panel should remove repeat data', function() { var panel = { span: 4, attr: '123', id: 10, repeat: 'asd', scopedVars: { test: 'asd' }}; - dashboard.rows = [{ panels: [panel] }]; + + dashboard.addEmptyRow(); + dashboard.rows[0].addPanel(panel); dashboard.duplicatePanel(panel, dashboard.rows[0]); expect(dashboard.rows[0].panels[1].repeat).to.be(undefined); diff --git a/public/app/features/panel/panel_ctrl.ts b/public/app/features/panel/panel_ctrl.ts index 40b7365da23..1d1b7c7f4a2 100644 --- a/public/app/features/panel/panel_ctrl.ts +++ b/public/app/features/panel/panel_ctrl.ts @@ -188,6 +188,9 @@ export class PanelCtrl { duplicate() { this.dashboard.duplicatePanel(this.panel, this.row); + this.$timeout(() => { + this.$scope.$root.$broadcast('render'); + }); } updateColumnSpan(span) { diff --git a/public/app/features/panel/panel_directive.ts b/public/app/features/panel/panel_directive.ts index 3af80d25483..28ef0d2bd63 100644 --- a/public/app/features/panel/panel_directive.ts +++ b/public/app/features/panel/panel_directive.ts @@ -68,8 +68,8 @@ module.directive('grafanaPanel', function($rootScope) { // the reason for handling these classes this way is for performance // limit the watchers on panels etc - var transparentLastState; - var lastHasAlertRule; + var transparentLastState = false; + var lastHasAlertRule = false; var lastAlertState; var hasAlertRule; var lastHeight = 0; @@ -91,6 +91,12 @@ module.directive('grafanaPanel', function($rootScope) { lastHeight = ctrl.containerHeight; } + // set initial transparency + if (ctrl.panel.transparent) { + transparentLastState = true; + panelContainer.addClass('panel-transparent', true); + } + ctrl.events.on('render', () => { if (lastHeight !== ctrl.containerHeight) { panelContainer.css({minHeight: ctrl.containerHeight}); diff --git a/public/app/features/panel/partials/query_editor_row.html b/public/app/features/panel/partials/query_editor_row.html index e8dbe1434e7..55933bbbae8 100644 --- a/public/app/features/panel/partials/query_editor_row.html +++ b/public/app/features/panel/partials/query_editor_row.html @@ -57,59 +57,3 @@ -
- - - - - - -
-
diff --git a/public/app/partials/bootstrap/tab.html b/public/app/partials/bootstrap/tab.html deleted file mode 100644 index d76dd67caf2..00000000000 --- a/public/app/partials/bootstrap/tab.html +++ /dev/null @@ -1,3 +0,0 @@ -
  • - {{heading}} -
  • diff --git a/public/app/partials/bootstrap/tabset.html b/public/app/partials/bootstrap/tabset.html deleted file mode 100644 index a811f83fbb5..00000000000 --- a/public/app/partials/bootstrap/tabset.html +++ /dev/null @@ -1,11 +0,0 @@ -
    - -
    -
    -
    -
    -
    diff --git a/public/app/partials/error.html b/public/app/partials/error.html index d38f71ac5d8..0401d6d98db 100644 --- a/public/app/partials/error.html +++ b/public/app/partials/error.html @@ -1,11 +1,12 @@ + + -
    -
    +
    -
    -

    Page not found (404)

    -
    - -
    +
    diff --git a/public/app/plugins/app/testdata/dashboards/graph_last_1h.json b/public/app/plugins/app/testdata/dashboards/graph_last_1h.json index c64ab84f338..c314feb56ad 100644 --- a/public/app/plugins/app/testdata/dashboards/graph_last_1h.json +++ b/public/app/plugins/app/testdata/dashboards/graph_last_1h.json @@ -1,5 +1,5 @@ { - "revision": 5, + "revision": 6, "title": "TestData - Graph Panel Last 1h", "tags": [ "grafana-test" @@ -7,8 +7,48 @@ "style": "dark", "timezone": "browser", "editable": true, - "hideControls": false, "sharedCrosshair": false, + "hideControls": false, + "time": { + "from": "2016-11-16T16:59:38.294Z", + "to": "2016-11-16T17:09:01.532Z" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "templating": { + "list": [] + }, + "annotations": { + "list": [] + }, + "refresh": false, + "schemaVersion": 13, + "version": 4, + "links": [], + "gnetId": null, "rows": [ { "collapse": false, @@ -238,7 +278,13 @@ ] } ], - "title": "New row" + "title": "New row", + "showTitle": false, + "titleSize": "h6", + "isNew": false, + "repeat": null, + "repeatRowId": null, + "repeatIteration": null }, { "collapse": false, @@ -332,7 +378,13 @@ "type": "text" } ], - "title": "New row" + "title": "New row", + "showTitle": false, + "titleSize": "h6", + "isNew": false, + "repeat": null, + "repeatRowId": null, + "repeatIteration": null }, { "collapse": false, @@ -371,7 +423,7 @@ "yaxis": 2 } ], - "span": 7.99561403508772, + "span": 8, "stack": false, "steppedLine": false, "targets": [ @@ -432,12 +484,18 @@ "isNew": true, "links": [], "mode": "markdown", - "span": 4.00438596491228, + "span": 4, "title": "", "type": "text" } ], - "title": "New row" + "title": "New row", + "showTitle": false, + "titleSize": "h6", + "isNew": false, + "repeat": null, + "repeatRowId": null, + "repeatIteration": null }, { "collapse": false, @@ -545,7 +603,7 @@ "points": false, "renderer": "flot", "seriesOverrides": [], - "span": 3, + "span": 4, "stack": false, "steppedLine": false, "targets": [ @@ -592,6 +650,31 @@ } ] }, + { + "content": "Should be a long line connecting the null region in the `connected` mode, and in zero it should just be a line with zero value at the null points. ", + "editable": true, + "error": false, + "id": 13, + "isNew": true, + "links": [], + "mode": "markdown", + "span": 4, + "title": "", + "type": "text" + } + ], + "title": "New row", + "showTitle": false, + "titleSize": "h6", + "isNew": false, + "repeat": null, + "repeatRowId": null, + "repeatIteration": null + }, + { + "isNew": false, + "title": "Dashboard Row", + "panels": [ { "aliasColors": {}, "bars": false, @@ -624,7 +707,7 @@ "zindex": -3 } ], - "span": 5, + "span": 8, "stack": true, "steppedLine": false, "targets": [ @@ -687,49 +770,149 @@ "show": true } ] + }, + { + "content": "Stacking values on top of nulls, should treat the null values as zero. ", + "editable": true, + "error": false, + "id": 14, + "isNew": true, + "links": [], + "mode": "markdown", + "span": 4, + "title": "", + "type": "text" } ], - "title": "New row" + "showTitle": false, + "titleSize": "h6", + "height": 250, + "repeat": null, + "repeatRowId": null, + "repeatIteration": null, + "collapse": false + }, + { + "isNew": false, + "title": "Dashboard Row", + "panels": [ + { + "aliasColors": {}, + "bars": false, + "datasource": "Grafana TestData", + "editable": true, + "error": false, + "fill": 1, + "id": 12, + "isNew": true, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 2, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [ + { + "alias": "B-series", + "zindex": -3 + } + ], + "span": 8, + "stack": true, + "steppedLine": false, + "targets": [ + { + "hide": false, + "refId": "B", + "scenarioId": "csv_metric_values", + "stringInput": "1,20,40,null,null,null,null,null,null,100,10,10,20,30,40,10", + "target": "", + "alias": "" + }, + { + "alias": "", + "hide": false, + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "1,20,40,null,null,null,null,null,null,100,10,10,20,30,40,10", + "target": "" + }, + { + "alias": "", + "hide": false, + "refId": "C", + "scenarioId": "csv_metric_values", + "stringInput": "1,20,40,null,null,null,null,null,null,100,10,10,20,30,40,10", + "target": "" + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Stacking all series null segment", + "tooltip": { + "msResolution": false, + "shared": true, + "sort": 0, + "value_type": "cumulative" + }, + "type": "graph", + "xaxis": { + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "content": "Stacking when all values are null should leave a gap in the graph", + "editable": true, + "error": false, + "id": 15, + "isNew": true, + "links": [], + "mode": "markdown", + "span": 4, + "title": "", + "type": "text" + } + ], + "showTitle": false, + "titleSize": "h6", + "height": 250, + "repeat": null, + "repeatRowId": null, + "repeatIteration": null, + "collapse": false } - ], - "time": { - "from": "now-1h", - "to": "now" - }, - "timepicker": { - "refresh_intervals": [ - "5s", - "10s", - "30s", - "1m", - "5m", - "15m", - "30m", - "1h", - "2h", - "1d" - ], - "time_options": [ - "5m", - "15m", - "1h", - "6h", - "12h", - "24h", - "2d", - "7d", - "30d" - ] - }, - "templating": { - "list": [] - }, - "annotations": { - "list": [] - }, - "refresh": false, - "schemaVersion": 13, - "version": 13, - "links": [], - "gnetId": null + ] } diff --git a/public/app/plugins/app/testdata/plugin.json b/public/app/plugins/app/testdata/plugin.json index 63f88df8140..f8723f95a5f 100644 --- a/public/app/plugins/app/testdata/plugin.json +++ b/public/app/plugins/app/testdata/plugin.json @@ -9,7 +9,7 @@ "name": "Grafana Project", "url": "http://grafana.org" }, - "version": "1.0.14", + "version": "1.0.15", "updated": "2016-09-26" }, diff --git a/public/app/plugins/datasource/cloudwatch/datasource.js b/public/app/plugins/datasource/cloudwatch/datasource.js index 105b08c2b17..07648779648 100644 --- a/public/app/plugins/datasource/cloudwatch/datasource.js +++ b/public/app/plugins/datasource/cloudwatch/datasource.js @@ -37,7 +37,8 @@ function (angular, _, moment, dateMath, kbn, CloudWatchAnnotationQuery) { query.dimensions = self.convertDimensionFormat(target.dimensions, options.scopedVars); query.statistics = target.statistics; - var period = this._getPeriod(target, query, options, start, end); + var now = Math.round(Date.now() / 1000); + var period = this._getPeriod(target, query, options, start, end, now); target.period = period; query.period = period; @@ -67,11 +68,19 @@ function (angular, _, moment, dateMath, kbn, CloudWatchAnnotationQuery) { }); }; - this._getPeriod = function(target, query, options, start, end) { + this._getPeriod = function(target, query, options, start, end, now) { var period; var range = end - start; - if (!target.period) { + var daySec = 60 * 60 * 24; + var periodUnit = 60; + if (now - start > (daySec * 15)) { // until 63 days ago + periodUnit = period = 60 * 5; + } else if (now - start > (daySec * 63)) { // until 455 days ago + periodUnit = period = 60 * 60; + } else if (now - start > (daySec * 455)) { // over 455 days, should return error, but try to long period + periodUnit = period = 60 * 60; + } else if (!target.period) { period = (query.namespace === 'AWS/EC2') ? 300 : 60; } else if (/^\d+$/.test(target.period)) { period = parseInt(target.period, 10); @@ -82,7 +91,7 @@ function (angular, _, moment, dateMath, kbn, CloudWatchAnnotationQuery) { period = 60; } if (range / period >= 1440) { - period = Math.ceil(range / 1440 / 60) * 60; + period = Math.ceil(range / 1440 / periodUnit) * periodUnit; } return period; diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts index 8247b2cd690..3af89abf1d7 100644 --- a/public/app/plugins/panel/singlestat/module.ts +++ b/public/app/plugins/panel/singlestat/module.ts @@ -208,11 +208,8 @@ class SingleStatCtrl extends MetricsPanelCtrl { } // Add $__name variable for using in prefix or postfix - data.scopedVars = { - __name: { - value: this.series[0].label - } - }; + data.scopedVars = _.extend({}, this.panel.scopedVars); + data.scopedVars["__name"] = {value: this.series[0].label}; } // check value to text mappings if its enabled @@ -526,7 +523,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { elem.toggleClass('pointer', panel.links.length > 0); if (panel.links.length > 0) { - linkInfo = linkSrv.getPanelLinkAnchorInfo(panel.links[0], panel.scopedVars); + linkInfo = linkSrv.getPanelLinkAnchorInfo(panel.links[0], data.scopedVars); } else { linkInfo = null; } diff --git a/public/sass/_grafana.scss b/public/sass/_grafana.scss index dfb8506d295..53a96cf9291 100644 --- a/public/sass/_grafana.scss +++ b/public/sass/_grafana.scss @@ -50,11 +50,9 @@ @import "components/tagsinput"; @import "components/tables_lists"; @import "components/search"; -@import "components/tightform"; @import "components/gf-form"; @import "components/sidemenu"; @import "components/navbar"; -@import "components/gfbox"; @import "components/timepicker"; @import "components/filter-controls"; @import "components/filter-list"; diff --git a/public/sass/components/_gfbox.scss b/public/sass/components/_gfbox.scss deleted file mode 100644 index b4e31a2397d..00000000000 --- a/public/sass/components/_gfbox.scss +++ /dev/null @@ -1,69 +0,0 @@ -.gf-box { - margin: 10px 5px; - background-color: $page-bg; - position: relative; - border: 1px solid $tight-form-func-bg; -} - -.gf-box-no-margin { - margin: 0; -} - -.gf-box-header-close-btn { - float: right; - padding: 0; - margin: 0; - background-color: transparent; - border: none; - padding: 8px; - i { - font-size: 120%; - } - color: $text-color; - &:hover { - color: $white; - } -} - -.gf-box-header-save-btn { - padding: 7px 0; - float: right; - color: $gray-2; - font-style: italic; -} - -.gf-box-body { - padding: 20px; - min-height: 150px; -} - -.gf-box-footer { - overflow: hidden; -} - -.gf-box-header { - border-bottom: 1px solid $tight-form-func-bg; - overflow: hidden; - background-color: $tight-form-bg; - .tabs { - float: left; - } - .nav { - margin: 0; - } -} - -.gf-box-title { - padding-right: 20px; - padding-left: 10px; - float: left; - color: $link-color; - font-size: 18px; - font-weight: normal; - line-height: 38px; - margin: 0; - .fa { - padding: 0 8px 0 5px; - color: $text-color; - } -} diff --git a/public/sass/components/_navs.scss b/public/sass/components/_navs.scss index 4bb02d7b514..abbb4ba5042 100644 --- a/public/sass/components/_navs.scss +++ b/public/sass/components/_navs.scss @@ -87,7 +87,7 @@ } // temp hack -.modal-body, .gf-box { +.modal-body { .nav-tabs { border-bottom: none; } diff --git a/public/sass/components/_query_editor.scss b/public/sass/components/_query_editor.scss index 4c807ed0e6b..f2d29572e37 100644 --- a/public/sass/components/_query_editor.scss +++ b/public/sass/components/_query_editor.scss @@ -67,3 +67,82 @@ } } +.grafana-metric-options { + margin-top: 25px; +} + +.tight-form-func { + background: $tight-form-func-bg; + + &.show-function-controls { + padding-top: 5px; + min-width: 100px; + text-align: center; + } +} + +input[type="text"].tight-form-func-param { + background: transparent; + border: none; + margin: 0; + padding: 0; +} + +.tight-form-func-controls { + display: none; + text-align: center; + + .fa-arrow-left { + float: left; + position: relative; + top: 2px; + } + .fa-arrow-right { + float: right; + position: relative; + top: 2px; + } + .fa-remove { + margin-left: 10px; + } +} + +.grafana-metric-options { + margin-top: 25px; +} + +.tight-form-func { + background: $tight-form-func-bg; + + &.show-function-controls { + padding-top: 5px; + min-width: 100px; + text-align: center; + } +} + +input[type="text"].tight-form-func-param { + background: transparent; + border: none; + margin: 0; + padding: 0; +} + +.tight-form-func-controls { + display: none; + text-align: center; + + .fa-arrow-left { + float: left; + position: relative; + top: 2px; + } + .fa-arrow-right { + float: right; + position: relative; + top: 2px; + } + .fa-remove { + margin-left: 10px; + } +} diff --git a/public/sass/components/_row.scss b/public/sass/components/_row.scss index 25d6b9eb622..840db839607 100644 --- a/public/sass/components/_row.scss +++ b/public/sass/components/_row.scss @@ -74,12 +74,11 @@ .add-panel-panels-scroll { width: 100%; overflow: auto; + -ms-overflow-style: none; &::-webkit-scrollbar { display: none } - - -ms-overflow-style: none; } .add-panel-panels { diff --git a/public/sass/components/_shortcuts.scss b/public/sass/components/_shortcuts.scss index 4e2d56503d9..1dedb062183 100644 --- a/public/sass/components/_shortcuts.scss +++ b/public/sass/components/_shortcuts.scss @@ -6,6 +6,8 @@ } .shortcut-table { + margin-bottom: $spacer; + .shortcut-table-category-header { font-weight: normal; font-size: $font-size-h6; @@ -26,8 +28,6 @@ text-align: right; color: $text-color; } - - margin-bottom: $spacer; } .shortcut-table-key { diff --git a/public/sass/components/_submenu.scss b/public/sass/components/_submenu.scss index 14f0658f7cb..93376e0d106 100644 --- a/public/sass/components/_submenu.scss +++ b/public/sass/components/_submenu.scss @@ -7,11 +7,12 @@ } .annotation-segment { + padding: 8px 7px; + label.cr1 { margin-left: 5px; margin-top: 3px; } - padding: 8px 7px; } .submenu-item { @@ -31,14 +32,14 @@ .variable-value-link { padding-right: 10px; - .label-tag { - margin: 0 5px; - } - padding: 8px 7px; box-sizing: content-box; display: inline-block; color: $text-color; + + .label-tag { + margin: 0 5px; + } } .variable-link-wrapper { diff --git a/public/sass/components/_tabbed_view.scss b/public/sass/components/_tabbed_view.scss index f1b59fa2363..e72252330a1 100644 --- a/public/sass/components/_tabbed_view.scss +++ b/public/sass/components/_tabbed_view.scss @@ -38,10 +38,10 @@ background-color: transparent; border: none; padding: ($tabs-padding-top + $tabs-top-margin) $spacer $tabs-padding-bottom; + color: $text-color; i { font-size: 120%; } - color: $text-color; &:hover { color: $white; } diff --git a/public/sass/components/_tightform.scss b/public/sass/components/_tightform.scss deleted file mode 100644 index 7c43854b06c..00000000000 --- a/public/sass/components/_tightform.scss +++ /dev/null @@ -1,235 +0,0 @@ -.tight-form { - border-top: 1px solid $tight-form-border; - border-left: 1px solid $tight-form-border; - border-right: 1px solid $tight-form-border; - background: $tight-form-bg; - - &.last { - border-bottom: 1px solid $tight-form-border; - } - - &.borderless { - background: transparent; - border: none; - } - - .checkbox-label { - display: inline; - padding-right: 4px; - margin-bottom: 0; - cursor: pointer; - } -} - -.tight-form-container-no-item-borders { - border: 1px solid $tight-form-border; - border-bottom: none; - - .tight-form, .tight-form-item, [type="text"].tight-form-input, [type="text"].tight-form-clear-input { - border: none; - } -} - -.spaced-form { - .tight-form { - margin: 7px 0; - } -} - -.borderless { - .tight-form-item, - .tight-form-input { - border: none; - } -} - -.tight-form-container { - border-bottom: 1px solid $tight-form-border; -} - -.tight-form-btn { - padding: 7px 12px; -} - -.tight-form-list { - list-style: none; - margin: 0; - >li { - float: left; - } -} - -.tight-form-flex-wrapper { - display: flex; - flex-direction: row; - float: none !important; -} - -.grafana-metric-options { - margin-top: 25px; -} - -.tight-form-item { - padding: 8px 7px; - box-sizing: content-box; - display: inline-block; - font-weight: normal; - border-right: 1px solid $tight-form-border; - display: inline-block; - color: $text-color; - - .has-open-function & { - padding-top: 25px; - } - - .tight-form-disabled & { - color: $link-color-disabled; - a { - color: $link-color-disabled; - } - } - - &:hover, &:focus { - text-decoration: none; - } - - &a:hover { - background: $tight-form-func-bg; - } - - &.last { - border-right: none; - } -} - - -.tight-form-item-icon { - i { - width: 15px; - text-align: center; - display: inline-block; - } -} - -.tight-form-func { - background: $tight-form-func-bg; - - &.show-function-controls { - padding-top: 5px; - min-width: 100px; - text-align: center; - } -} - -input[type="text"].tight-form-func-param { - background: transparent; - border: none; - margin: 0; - padding: 0; -} - -input[type="text"].tight-form-clear-input { - padding: 8px 7px; - border: none; - margin: 0px; - background: transparent; - border-radius: 0; - border-right: 1px solid $tight-form-border; -} - -[type="text"], -[type="email"], -[type="number"], -[type="password"] { - &.tight-form-input { - background-color: $input-bg; - border: none; - border-right: 1px solid $tight-form-border; - margin: 0px; - border-radius: 0; - padding: 8px 6px; - height: 100%; - box-sizing: border-box; - &.last { - border-right: none; - } - } -} - -input[type="checkbox"].tight-form-checkbox { - margin: 0; -} - -.tight-form-textarea { - height: 200px; - margin: 0; - box-sizing: border-box; -} - -select.tight-form-input { - border: none; - border-right: 1px solid $tight-form-border; - background-color: $input-bg; - margin: 0px; - border-radius: 0; - height: 36px; - padding: 9px 3px; - &.last { - border-right: none; - } -} - -.tight-form-func-controls { - display: none; - text-align: center; - - .fa-arrow-left { - float: left; - position: relative; - top: 2px; - } - .fa-arrow-right { - float: right; - position: relative; - top: 2px; - } - .fa-remove { - margin-left: 10px; - } -} - -.tight-form-radio { - input[type="radio"] { - margin: 0; - } - label { - display: inline; - } -} - -.tight-form-section { - margin-bottom: 20px; - margin-right: 40px; - vertical-align: top; - display: inline-block; - .tight-form { - margin-left: 20px; - } -} - -.tight-form-align { - padding-left: 66px; -} - -.tight-form-item-large { width: 115px; } -.tight-form-item-xlarge { width: 150px; } -.tight-form-item-xxlarge { width: 200px; } - -.tight-form-input.tight-form-item-xxlarge { - width: 215px; -} - -.tight-form-inner-box { - margin: 20px 0 20px 148px; - display: inline-block; -} diff --git a/public/sass/components/_timepicker.scss b/public/sass/components/_timepicker.scss index 1ecc2c7a166..a5f311cdb46 100644 --- a/public/sass/components/_timepicker.scss +++ b/public/sass/components/_timepicker.scss @@ -65,15 +65,17 @@ } .gf-timepicker-component { - margin-bottom: 10px; + padding: $spacer/2 0 $spacer 0; + td { padding: 1px; } button.btn-sm { @include buttonBackground($btn-inverse-bg, $btn-inverse-bg-hl); + font-size: $font-size-sm; background-image: none; border: none; - padding: 6px 10px; + padding: 5px 11px; color: $text-color; &.active span { color: $blue; diff --git a/public/sass/layout/_page.scss b/public/sass/layout/_page.scss index 6203f4be083..5702a1aa260 100644 --- a/public/sass/layout/_page.scss +++ b/public/sass/layout/_page.scss @@ -62,12 +62,6 @@ .admin-page { max-width: 800px; margin-left: 10px; - .gf-box { - margin-top: 0; - } - .gf-box-body { - min-height: 0; - } h2 { margin-left: 15px; margin-bottom: 0px; diff --git a/public/sass/pages/_alerting.scss b/public/sass/pages/_alerting.scss index b739485f170..70124f0cd85 100644 --- a/public/sass/pages/_alerting.scss +++ b/public/sass/pages/_alerting.scss @@ -61,7 +61,6 @@ } &--ok { - box-shadow: 0 0 5px rgba(0,200,0,10.8); .panel-alert-icon:before { color: $online; content: "\e611"; diff --git a/public/sass/pages/_dashboard.scss b/public/sass/pages/_dashboard.scss index 213220674cd..73b2772abc8 100644 --- a/public/sass/pages/_dashboard.scss +++ b/public/sass/pages/_dashboard.scss @@ -172,6 +172,12 @@ div.flot-text { } } +.panel-in-fullscreen { + .panel-drop-zone { + display: none !important; + } +} + .panel-time-info { font-weight: bold; float: right; diff --git a/public/vendor/angular-ui/ui-bootstrap-tpls.js b/public/vendor/angular-ui/ui-bootstrap-tpls.js index 2e7fd621809..87120b66ce1 100644 --- a/public/vendor/angular-ui/ui-bootstrap-tpls.js +++ b/public/vendor/angular-ui/ui-bootstrap-tpls.js @@ -5,8 +5,8 @@ * Version: 0.13.4 - 2015-09-03 * License: MIT */ -angular.module("ui.bootstrap", ["ui.bootstrap.tpls","ui.bootstrap.position","ui.bootstrap.dateparser","ui.bootstrap.datepicker","ui.bootstrap.tabs"]); -angular.module("ui.bootstrap.tpls", ["template/datepicker/datepicker.html","template/datepicker/day.html","template/datepicker/month.html","template/datepicker/popup.html","template/datepicker/year.html","template/tabs/tab.html","template/tabs/tabset.html"]); +angular.module("ui.bootstrap", ["ui.bootstrap.tpls","ui.bootstrap.position","ui.bootstrap.dateparser","ui.bootstrap.datepicker"]); +angular.module("ui.bootstrap.tpls", ["template/datepicker/datepicker.html","template/datepicker/day.html","template/datepicker/month.html","template/datepicker/popup.html","template/datepicker/year.html"]); angular.module('ui.bootstrap.position', []) /** @@ -1180,302 +1180,6 @@ function($compile, $parse, $document, $rootScope, $position, dateFilter, datePar }); -/** - * @ngdoc overview - * @name ui.bootstrap.tabs - * - * @description - * AngularJS version of the tabs directive. - */ - -angular.module('ui.bootstrap.tabs', []) - -.controller('TabsetController', ['$scope', function TabsetCtrl($scope) { - var ctrl = this, - tabs = ctrl.tabs = $scope.tabs = []; - - ctrl.select = function(selectedTab) { - angular.forEach(tabs, function(tab) { - if (tab.active && tab !== selectedTab) { - tab.active = false; - tab.onDeselect(); - selectedTab.selectCalled = false; - } - }); - selectedTab.active = true; - // only call select if it has not already been called - if (!selectedTab.selectCalled) { - selectedTab.onSelect(); - selectedTab.selectCalled = true; - } - }; - - ctrl.addTab = function addTab(tab) { - tabs.push(tab); - // we can't run the select function on the first tab - // since that would select it twice - if (tabs.length === 1 && tab.active !== false) { - tab.active = true; - } else if (tab.active) { - ctrl.select(tab); - } else { - tab.active = false; - } - }; - - ctrl.removeTab = function removeTab(tab) { - var index = tabs.indexOf(tab); - //Select a new tab if the tab to be removed is selected and not destroyed - if (tab.active && tabs.length > 1 && !destroyed) { - //If this is the last tab, select the previous tab. else, the next tab. - var newActiveIndex = index == tabs.length - 1 ? index - 1 : index + 1; - ctrl.select(tabs[newActiveIndex]); - } - tabs.splice(index, 1); - }; - - var destroyed; - $scope.$on('$destroy', function() { - destroyed = true; - }); -}]) - -/** - * @ngdoc directive - * @name ui.bootstrap.tabs.directive:tabset - * @restrict EA - * - * @description - * Tabset is the outer container for the tabs directive - * - * @param {boolean=} vertical Whether or not to use vertical styling for the tabs. - * @param {boolean=} justified Whether or not to use justified styling for the tabs. - * - * @example - - - - First Content! - Second Content! - -
    - - First Vertical Content! - Second Vertical Content! - - - First Justified Content! - Second Justified Content! - -
    -
    - */ -.directive('tabset', function() { - return { - restrict: 'EA', - transclude: true, - replace: true, - scope: { - type: '@' - }, - controller: 'TabsetController', - templateUrl: 'template/tabs/tabset.html', - link: function(scope, element, attrs) { - scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false; - scope.justified = angular.isDefined(attrs.justified) ? scope.$parent.$eval(attrs.justified) : false; - } - }; -}) - -/** - * @ngdoc directive - * @name ui.bootstrap.tabs.directive:tab - * @restrict EA - * - * @param {string=} heading The visible heading, or title, of the tab. Set HTML headings with {@link ui.bootstrap.tabs.directive:tabHeading tabHeading}. - * @param {string=} select An expression to evaluate when the tab is selected. - * @param {boolean=} active A binding, telling whether or not this tab is selected. - * @param {boolean=} disabled A binding, telling whether or not this tab is disabled. - * - * @description - * Creates a tab with a heading and content. Must be placed within a {@link ui.bootstrap.tabs.directive:tabset tabset}. - * - * @example - - -
    - - -
    - - First Tab - - Alert me! - Second Tab, with alert callback and html heading! - - - {{item.content}} - - -
    -
    - - function TabsDemoCtrl($scope) { - $scope.items = [ - { title:"Dynamic Title 1", content:"Dynamic Item 0" }, - { title:"Dynamic Title 2", content:"Dynamic Item 1", disabled: true } - ]; - - $scope.alertMe = function() { - setTimeout(function() { - alert("You've selected the alert tab!"); - }); - }; - }; - -
    - */ - -/** - * @ngdoc directive - * @name ui.bootstrap.tabs.directive:tabHeading - * @restrict EA - * - * @description - * Creates an HTML heading for a {@link ui.bootstrap.tabs.directive:tab tab}. Must be placed as a child of a tab element. - * - * @example - - - - - HTML in my titles?! - And some content, too! - - - Icon heading?!? - That's right. - - - - - */ -.directive('tab', ['$parse', '$log', function($parse, $log) { - return { - require: '^tabset', - restrict: 'EA', - replace: true, - templateUrl: 'template/tabs/tab.html', - transclude: true, - scope: { - active: '=?', - heading: '@', - onSelect: '&select', //This callback is called in contentHeadingTransclude - //once it inserts the tab's content into the dom - onDeselect: '&deselect' - }, - controller: function() { - //Empty controller so other directives can require being 'under' a tab - }, - link: function(scope, elm, attrs, tabsetCtrl, transclude) { - scope.$watch('active', function(active) { - if (active) { - tabsetCtrl.select(scope); - } - }); - - scope.disabled = false; - if (attrs.disable) { - scope.$parent.$watch($parse(attrs.disable), function(value) { - scope.disabled = !! value; - }); - } - - // Deprecation support of "disabled" parameter - // fix(tab): IE9 disabled attr renders grey text on enabled tab #2677 - // This code is duplicated from the lines above to make it easy to remove once - // the feature has been completely deprecated - if (attrs.disabled) { - $log.warn('Use of "disabled" attribute has been deprecated, please use "disable"'); - scope.$parent.$watch($parse(attrs.disabled), function(value) { - scope.disabled = !! value; - }); - } - - scope.select = function() { - if (!scope.disabled) { - scope.active = true; - } - }; - - tabsetCtrl.addTab(scope); - scope.$on('$destroy', function() { - tabsetCtrl.removeTab(scope); - }); - - //We need to transclude later, once the content container is ready. - //when this link happens, we're inside a tab heading. - scope.$transcludeFn = transclude; - } - }; -}]) - -.directive('tabHeadingTransclude', function() { - return { - restrict: 'A', - require: '^tab', - link: function(scope, elm, attrs, tabCtrl) { - scope.$watch('headingElement', function updateHeadingElement(heading) { - if (heading) { - elm.html(''); - elm.append(heading); - } - }); - } - }; -}) - -.directive('tabContentTransclude', function() { - return { - restrict: 'A', - require: '^tabset', - link: function(scope, elm, attrs) { - var tab = scope.$eval(attrs.tabContentTransclude); - - //Now our tab is ready to be transcluded: both the tab heading area - //and the tab content area are loaded. Transclude 'em both. - tab.$transcludeFn(tab.$parent, function(contents) { - angular.forEach(contents, function(node) { - if (isTabHeading(node)) { - //Let tabHeadingTransclude know. - tab.headingElement = node; - } else { - elm.append(node); - } - }); - }); - } - }; - - function isTabHeading(node) { - return node.tagName && ( - node.hasAttribute('tab-heading') || - node.hasAttribute('data-tab-heading') || - node.hasAttribute('x-tab-heading') || - node.tagName.toLowerCase() === 'tab-heading' || - node.tagName.toLowerCase() === 'data-tab-heading' || - node.tagName.toLowerCase() === 'x-tab-heading' - ); - } -}); - angular.module("template/datepicker/datepicker.html", []).run(["$templateCache", function($templateCache) { $templateCache.put("template/datepicker/datepicker.html", "
    \n" + @@ -1568,25 +1272,3 @@ angular.module("template/datepicker/year.html", []).run(["$templateCache", funct ""); }]); -angular.module("template/tabs/tab.html", []).run(["$templateCache", function($templateCache) { - $templateCache.put("template/tabs/tab.html", - "
  • \n" + - " {{heading}}\n" + - "
  • \n" + - ""); -}]); - -angular.module("template/tabs/tabset.html", []).run(["$templateCache", function($templateCache) { - $templateCache.put("template/tabs/tabset.html", - "
    \n" + - "
      \n" + - "
      \n" + - "
      \n" + - "
      \n" + - "
      \n" + - "
      \n" + - ""); -}]); diff --git a/public/views/500.html b/public/views/500.html index 9565304e7ff..cb2e99595f1 100644 --- a/public/views/500.html +++ b/public/views/500.html @@ -5,28 +5,32 @@ - Grafana + Grafana - Error + + + + - + + -
      -
      - +
      + -
      -

      [[.Title]]

      - [[.ErrorMsg]] -
      +

      [[.Title]]

      + +
      [[.ErrorMsg]]
      +
      - - +