Commit 5a81cf6c by Torkel Ödegaard

Merge branch 'master' of github.com:grafana/grafana

parents f772a5cf eeb7524c
# 3.0.0-beta2 (unreleased)
# 3.0.0-beta3 (unreleased)
### Enhancements
* **InfluxDB**: Changed multi query encoding to work with InfluxDB 0.11 & 0.12, closes [#4533](https://github.com/grafana/grafana/issues/4533)
### Bug fixes
* **Postgres**: Fixed page render crash when using postgres, fixes [#4558](https://github.com/grafana/grafana/issues/4558)
* **Table panel**: Fixed table panel bug when trying to show annotations in table panel, fixes [#4563](https://github.com/grafana/grafana/issues/4563)
* **App Config**: Fixed app config issue showing content of other app config, fixes [#4575](https://github.com/grafana/grafana/issues/4575)
* **Graph Panel**: Fixed legend option max not updating, fixes [#4601](https://github.com/grafana/grafana/issues/4601)
* **Graph Panel**: Fixed issue where newly added graph panels shared same axes config, fixes [#4582](https://github.com/grafana/grafana/issues/4582)
* **Graph Panel**: Fixed issue with axis labels overlapping Y-axis, fixes [#4626](https://github.com/grafana/grafana/issues/4626)
* **InfluxDB**: Fixed issue with templating query containing template variable, fixes [#4602](https://github.com/grafana/grafana/issues/4602)
* **Graph Panel**: Fixed issue with hiding series and stacking, fixes [#4557](https://github.com/grafana/grafana/issues/4557)
* **Graph Panel**: Fixed issue with legend height in table mode with few series, affected iframe embedding as well, fixes [#4640](https://github.com/grafana/grafana/issues/4640)
# 3.0.0-beta2 (2016-04-04)
### New Features (introduces since 3.0-beta1)
* **Preferences**: Set home dashboard on user and org level, closes [#1678](https://github.com/grafana/grafana/issues/1678)
......
......@@ -30,6 +30,7 @@ func Register(r *macaron.Macaron) {
// authed views
r.Get("/profile/", reqSignedIn, Index)
r.Get("/profile/password", reqSignedIn, Index)
r.Get("/profile/switch-org/:id", reqSignedIn, ChangeActiveOrgAndRedirectToHome)
r.Get("/org/", reqSignedIn, Index)
r.Get("/org/new", reqSignedIn, Index)
r.Get("/datasources/", reqSignedIn, Index)
......
......@@ -4,6 +4,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
)
......@@ -109,6 +110,23 @@ func UserSetUsingOrg(c *middleware.Context) Response {
return ApiSuccess("Active organization changed")
}
// GET /profile/switch-org/:id
func ChangeActiveOrgAndRedirectToHome(c *middleware.Context) {
orgId := c.ParamsInt64(":id")
if !validateUsingOrg(c.UserId, orgId) {
NotFoundHandler(c)
}
cmd := m.SetUsingOrgCommand{UserId: c.UserId, OrgId: orgId}
if err := bus.Dispatch(&cmd); err != nil {
NotFoundHandler(c)
}
c.Redirect(setting.AppSubUrl + "/")
}
func ChangeUserPassword(c *middleware.Context, cmd m.ChangeUserPasswordCommand) Response {
userQuery := m.GetUserByIdQuery{Id: c.UserId}
......
......@@ -25,7 +25,7 @@ func runCommand(command func(commandLine CommandLine) error) func(context *cli.C
var pluginCommands = []cli.Command{
{
Name: "install",
Usage: "install <plugin name>",
Usage: "install <plugin id>",
Action: runCommand(installCommand),
}, {
Name: "list-remote",
......@@ -33,7 +33,7 @@ var pluginCommands = []cli.Command{
Action: runCommand(listremoteCommand),
}, {
Name: "upgrade",
Usage: "upgrade <plugin name>",
Usage: "upgrade <plugin id>",
Action: runCommand(upgradeCommand),
}, {
Name: "upgrade-all",
......@@ -44,8 +44,12 @@ var pluginCommands = []cli.Command{
Usage: "list all installed plugins",
Action: runCommand(lsCommand),
}, {
Name: "uninstall",
Usage: "uninstall <plugin id>",
Action: runCommand(removeCommand),
}, {
Name: "remove",
Usage: "remove <plugin name>",
Usage: "remove <plugin id>",
Action: runCommand(removeCommand),
},
}
......
......@@ -10,6 +10,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/log"
m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/setting"
)
......@@ -56,6 +57,9 @@ func sendUsageStats() {
metrics["stats.users.count"] = statsQuery.Result.UserCount
metrics["stats.orgs.count"] = statsQuery.Result.OrgCount
metrics["stats.playlist.count"] = statsQuery.Result.PlaylistCount
metrics["stats.plugins.apps.count"] = len(plugins.Apps)
metrics["stats.plugins.panels.count"] = len(plugins.Panels)
metrics["stats.plugins.datasources.count"] = len(plugins.DataSources)
dsStats := m.GetDataSourceStatsQuery{}
if err := bus.Dispatch(&dsStats); err != nil {
......
......@@ -21,10 +21,6 @@
<i class="{{::menuItem.icon}}" ng-show="::menuItem.icon"></i>
{{::menuItem.text}}
</a>
<a ng-click="menuItem.click()" ng-show="::menuItem.click">
<i class="{{::menuItem.icon}}"></i>
{{::menuItem.text}}
</a>
</li>
</ul>
</li>
......
......@@ -72,9 +72,8 @@ export class SideMenuCtrl {
this.orgMenu.push({
text: "Switch to " + org.name,
icon: "fa fa-fw fa-random",
click: () => {
this.switchOrg(org.orgId);
}
url: this.getUrl('/profile/switch-org/' + org.orgId),
target: '_self'
});
});
......@@ -83,12 +82,6 @@ export class SideMenuCtrl {
}
});
}
switchOrg(orgId) {
this.backendSrv.post('/api/user/using/' + orgId).then(() => {
window.location.href = `${config.appSubUrl}/`;
});
};
}
export function sideMenuDirective() {
......
......@@ -21,14 +21,14 @@ export class SwitchCtrl {
id: any;
/** @ngInject */
constructor($scope) {
constructor($scope, private $timeout) {
this.show = true;
this.id = $scope.$id;
}
internalOnChange() {
return new Promise(resolve => {
setTimeout(() => {
this.$timeout(() => {
this.onChange();
resolve();
});
......
......@@ -46,9 +46,12 @@ function popoverSrv($compile, $rootScope) {
drop.on('close', () => {
popoverScope.dismiss({fromDropClose: true});
destroyDrop();
if (options.onClose) {
options.onClose();
}
});
drop.open();
setTimeout(() => { drop.open(); }, 10);
};
}
......
......@@ -38,31 +38,26 @@
<div ng-include src="'shareLinkOptions.html'"></div>
<div class="gf-form-group position-center">
<div class="gf-form width-30" >
<div class="gf-form-group section">
<div class="gf-form width-30">
<textarea rows="5" data-share-panel-url class="gf-form-input width-30" ng-model='iframeHtml'></textarea>
</div>
</div>
<div class="gf-form-group">
<div class="gf-form position-center">
<button class="btn btn-inverse" data-clipboard-text="{{iframeHtml}}" clipboard-button><i class="fa fa-clipboard"></i> Copy</button>
</div>
</div>
</script>
<script type="text/ng-template" id="shareLinkOptions.html">
<div class="gf-form-group position-center">
<div class="gf-form">
<span class="gf-form-label width-5">Include</span>
<editor-checkbox text="Current time range" model="options.forCurrent" change="buildUrl()"></editor-checkbox>
</div>
<div class="gf-form">
<span class="gf-form-label width-5">Include</span>
<editor-checkbox text="Template variables" model="options.includeTemplateVars" change="buildUrl()"></editor-checkbox>
</div>
<div class="gf-form-group section">
<gf-form-switch class="gf-form"
label="Current time range" label-class="width-12" switch-class="max-width-6"
checked="options.forCurrent" on-change="buildUrl()">
</gf-form-switch>
<gf-form-switch class="gf-form"
label="Template variables" label-class="width-12" switch-class="max-width-6"
checked="options.includeTemplateVars" on-change="buildUrl()">
</gf-form-switch>
<div class="gf-form">
<span class="gf-form-label width-5">Theme</span>
<div class="gf-form-select-wrapper max-width-10">
<span class="gf-form-label width-12">Theme</span>
<div class="gf-form-select-wrapper width-6">
<select class="gf-form-input" ng-model="options.theme" ng-options="f as f for f in ['current', 'dark', 'light']" ng-change="buildUrl()"></select>
</div>
</div>
......@@ -75,18 +70,19 @@
</div>
<div ng-include src="'shareLinkOptions.html'"></div>
<div class="gf-form-group position-center">
<div class="gf-form-inline">
<div class="gf-form width-30">
<input type="text" data-share-panel-url class="gf-form-input" ng-model="shareUrl"></input>
</div>
<div class="gf-form pull-right">
<button class="btn btn-inverse pull-right" data-clipboard-text="{{shareUrl}}" clipboard-button><i class="fa fa-clipboard"></i> Copy</button>
<div>
<div class="gf-form-group section">
<div class="gf-form-inline">
<div class="gf-form width-30">
<input type="text" data-share-panel-url class="gf-form-input" ng-model="shareUrl"></input>
</div>
<div class="gf-form pull-right">
<button class="btn btn-inverse pull-right" data-clipboard-text="{{shareUrl}}" clipboard-button><i class="fa fa-clipboard"></i> Copy</button>
</div>
</div>
</div>
</div>
<div class="gf-form position-center" ng-show="modeSharePanel">
<div class="gf-form section" ng-show="modeSharePanel">
<a href="{{imageUrl}}" target="_blank"><i class="fa fa-camera"></i> Direct link rendered image</a>
</div>
</script>
......@@ -117,7 +113,7 @@
</p>
</div>
<div class="gf-form-group share-modal-options position-center">
<div class="gf-form-group share-modal-options">
<div class="gf-form" ng-if="step === 1">
<span class="gf-form-label width-12">Snapshot name</span>
<input type="text" ng-model="snapshot.name" class="gf-form-input max-width-15" >
......
......@@ -184,7 +184,6 @@ class MetricsPanelCtrl extends PanelCtrl {
cacheTimeout: this.panel.cacheTimeout
};
this.setTimeQueryStart();
return datasource.query(metricsQuery);
}
......@@ -252,8 +251,12 @@ class MetricsPanelCtrl extends PanelCtrl {
}
addDataQuery(datasource) {
var target = {
};
var target: any = {};
if (datasource) {
target.datasource = datasource.name;
}
this.panel.targets.push(target);
}
}
......
......@@ -55,7 +55,7 @@ export default class InfluxDatasource {
query = query.replace(/\$interval/g, (target.interval || options.interval));
return query;
}).join("\n");
}).join(";");
// replace grafana variables
allQueries = allQueries.replace(/\$timeFilter/g, timeFilter);
......@@ -107,7 +107,7 @@ export default class InfluxDatasource {
var timeFilter = this.getTimeFilter({rangeRaw: options.rangeRaw});
var query = options.annotation.query.replace('$timeFilter', timeFilter);
query = this.templateSrv.replace(query);
query = this.templateSrv.replace(query, null, 'regex');
return this._seriesQuery(query).then(data => {
if (!data || !data.results || !data.results[0]) {
......@@ -133,6 +133,17 @@ export default class InfluxDatasource {
return this._influxRequest('GET', '/query', {q: query, epoch: 'ms'});
}
serializeParams(params) {
if (!params) { return '';}
return _.reduce(params, (memo, value, key) => {
if (value === null || value === undefined) { return memo; }
memo.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
return memo;
}, []).join("&");
}
testDatasource() {
return this.metricFindQuery('SHOW MEASUREMENTS LIMIT 1').then(() => {
return { status: "success", message: "Data source is working", title: "Success" };
......@@ -166,6 +177,7 @@ export default class InfluxDatasource {
data: data,
precision: "ms",
inspect: { type: 'influxdb' },
paramSerializer: this.serializeParams,
};
options.headers = options.headers || {};
......
......@@ -16,7 +16,7 @@ export class OpenTsConfigCtrl {
tsdbVersions = [
{name: '<=2.1', value: 1},
{name: '2.2', value: 2},
{name: '>=2.2', value: 2},
];
tsdbResolutions = [
......
......@@ -151,8 +151,10 @@ function (angular, $, moment, _, kbn, GraphTooltip) {
}
function processOffsetHook(plot, gridMargin) {
if (panel.yaxis) { gridMargin.left = 20; }
if (panel.rightYAxisLabel) { gridMargin.right = 20; }
var left = panel.yaxes[0];
var right = panel.yaxes[1];
if (left.show && left.label) { gridMargin.left = 20; }
if (right.show && right.label) { gridMargin.right = 20; }
}
// Function for rendering panel
......
......@@ -33,9 +33,8 @@ function ($) {
return j - 1;
};
this.showTooltip = function(absoluteTime, relativeTime, innerHtml, pos) {
var body = '<div class="graph-tooltip small"><div class="graph-tooltip-time">'+ absoluteTime +
' <span class="tone-down">(' + relativeTime + ')</span></div> ';
this.showTooltip = function(absoluteTime, innerHtml, pos) {
var body = '<div class="graph-tooltip small"><div class="graph-tooltip-time">'+ absoluteTime + '</div> ';
body += innerHtml + '</div>';
$tooltip.html(body).place_tt(pos.pageX + 20, pos.pageY);
};
......@@ -109,7 +108,7 @@ function ($) {
var plot = elem.data().plot;
var plotData = plot.getData();
var seriesList = getSeriesFn();
var group, value, absoluteTime, relativeTime, hoverInfo, i, series, seriesHtml, tooltipFormat;
var group, value, absoluteTime, hoverInfo, i, series, seriesHtml, tooltipFormat;
if (panel.tooltip.msResolution) {
tooltipFormat = 'YYYY-MM-DD HH:mm:ss.SSS';
......@@ -132,7 +131,6 @@ function ($) {
seriesHtml = '';
relativeTime = dashboard.getRelativeTime(seriesHoverInfo.time);
absoluteTime = dashboard.formatDate(seriesHoverInfo.time, tooltipFormat);
for (i = 0; i < seriesHoverInfo.length; i++) {
......@@ -142,17 +140,22 @@ function ($) {
continue;
}
var highlightClass = '';
if (item && i === item.seriesIndex) {
highlightClass = 'graph-tooltip-list-item--highlight';
}
series = seriesList[i];
value = series.formatValue(hoverInfo.value);
seriesHtml += '<div class="graph-tooltip-list-item"><div class="graph-tooltip-series-name">';
seriesHtml += '<div class="graph-tooltip-list-item ' + highlightClass + '"><div class="graph-tooltip-series-name">';
seriesHtml += '<i class="fa fa-minus" style="color:' + series.color +';"></i> ' + series.label + ':</div>';
seriesHtml += '<div class="graph-tooltip-value">' + value + '</div></div>';
plot.highlight(i, hoverInfo.hoverIndex);
}
self.showTooltip(absoluteTime, relativeTime, seriesHtml, pos);
self.showTooltip(absoluteTime, seriesHtml, pos);
}
// single series tooltip
else if (item) {
......@@ -169,12 +172,11 @@ function ($) {
value = series.formatValue(value);
relativeTime = dashboard.getRelativeTime(item.datapoint[0]);
absoluteTime = dashboard.formatDate(item.datapoint[0], tooltipFormat);
group += '<div class="graph-tooltip-value">' + value + '</div>';
self.showTooltip(absoluteTime, relativeTime, group, pos);
self.showTooltip(absoluteTime, group, pos);
}
// no hit
else {
......
......@@ -194,9 +194,9 @@ function (angular, _, $) {
}
var topPadding = 6;
$container.css("height", maxHeight - topPadding);
$container.css("max-height", maxHeight - topPadding);
} else {
$container.css("height", "");
$container.css("max-height", "");
}
}
}
......
......@@ -116,6 +116,7 @@ class GraphCtrl extends MetricsPanelCtrl {
this.colors = $scope.$root.colors;
this.events.on('render', this.onRender.bind(this));
this.events.on('data-received', this.onDataReceived.bind(this));
this.events.on('data-error', this.onDataError.bind(this));
this.events.on('data-snapshot-load', this.onDataSnapshotLoad.bind(this));
......@@ -215,8 +216,6 @@ class GraphCtrl extends MetricsPanelCtrl {
this.panel.tooltip.msResolution = this.panel.tooltip.msResolution || series.isMsResolutionNeeded();
}
series.applySeriesOverrides(this.panel.seriesOverrides);
if (seriesData.unit) {
this.panel.yaxes[series.yaxis-1].format = seriesData.unit;
}
......@@ -224,6 +223,14 @@ class GraphCtrl extends MetricsPanelCtrl {
return series;
}
onRender() {
if (!this.seriesList) { return; }
for (let series of this.seriesList) {
series.applySeriesOverrides(this.panel.seriesOverrides);
}
}
changeSeriesColor(series, color) {
series.color = color;
this.panel.aliasColors[series.alias] = series.color;
......@@ -240,7 +247,6 @@ class GraphCtrl extends MetricsPanelCtrl {
} else {
this.toggleSeriesExclusiveMode(serie);
}
this.render();
}
......
......@@ -60,6 +60,9 @@ define([
template: '<gf-color-picker></gf-color-picker>',
model: {
colorSelected: $scope.colorSelected,
},
onClose: function() {
$scope.ctrl.render();
}
});
};
......
......@@ -218,6 +218,7 @@ class TablePanelCtrl extends MetricsPanelCtrl {
if (data) {
renderPanel();
}
ctrl.renderingCompleted();
});
}
}
......
......@@ -39,6 +39,7 @@ $brand-primary: $orange;
$brand-success: $green;
$brand-warning: $brand-primary;
$brand-danger: $red;
$brand-text-highlight: #f7941d;
// Status colors
// -------------------------
......@@ -242,8 +243,8 @@ $infoBackground: $blue-dark;
// Tooltips and popovers
// -------------------------
$tooltipColor: $white;
$tooltipBackground: rgb(58, 57, 57);
$tooltipColor: $text-color;
$tooltipBackground: $dark-4;
$tooltipArrowWidth: 5px;
$tooltipArrowColor: $tooltipBackground;
$tooltipLinkColor: $link-color;
......
......@@ -44,6 +44,7 @@ $brand-primary: $orange;
$brand-success: $green;
$brand-warning: $orange;
$brand-danger: $red;
$brand-text-highlight: #f7941d;
// Status colors
// -------------------------
......
......@@ -127,6 +127,7 @@
.share-modal-options {
margin: 11px 20px 33px 20px;
display: inline-block;
}
.share-modal-big-icon {
......@@ -162,8 +163,3 @@
}
}
.modal-body {
.position-center {
display: inline-block;
}
}
......@@ -237,27 +237,28 @@
.graph-tooltip-time {
text-align: center;
font-weight: $font-weight-semi-bold;
position: relative;
top: -3px;
}
.tone-down {
opacity: 0.7;
padding: 0.2rem;
}
.graph-tooltip-list-item {
display: table-row;
&--highlight {
color: $brand-text-highlight;
}
}
.graph-tooltip-series-name {
display: table-cell;
padding: 0.15rem;
}
.graph-tooltip-value {
display: table-cell;
font-weight: bold;
padding-left: 10px;
padding-left: 15px;
text-align: right;
}
}
......
......@@ -88,13 +88,6 @@
}
}
.grafana-tooltip hr {
padding: 2px;
color: #c8c8c8;
margin: 0px;
border-bottom: 0px solid #c8c8c8;
}
.grafana-tip {
padding-left: 5px;
}
......
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