Merge branch 'master' into 10630_folder_api

This commit is contained in:
Marcus Efraimsson
2018-02-19 13:32:45 +01:00
165 changed files with 5010 additions and 2128 deletions

View File

@@ -147,8 +147,7 @@ export class AlertRuleItem extends React.Component<AlertRuleItemProps, any> {
<div className="alert-rule-item__body">
<div className="alert-rule-item__header">
<div className="alert-rule-item__name">
{rule.canEdit && <a href={ruleUrl}>{this.renderText(rule.name)}</a>}
{!rule.canEdit && <span>{this.renderText(rule.name)}</span>}
<a href={ruleUrl}>{this.renderText(rule.name)}</a>
</div>
<div className="alert-rule-item__text">
<span className={`${rule.stateClass}`}>{this.renderText(rule.stateText)}</span>
@@ -163,24 +162,12 @@ export class AlertRuleItem extends React.Component<AlertRuleItemProps, any> {
className="btn btn-small btn-inverse alert-list__btn width-2"
title="Pausing an alert rule prevents it from executing"
onClick={this.toggleState}
disabled={!rule.canEdit}
>
<i className={stateClass} />
</button>
{rule.canEdit && (
<a className="btn btn-small btn-inverse alert-list__btn width-2" href={ruleUrl} title="Edit alert rule">
<i className="icon-gf icon-gf-settings" />
</a>
)}
{!rule.canEdit && (
<button
className="btn btn-small btn-inverse alert-list__btn width-2"
title="Edit alert rule"
disabled={true}
>
<i className="icon-gf icon-gf-settings" />
</button>
)}
<a className="btn btn-small btn-inverse alert-list__btn width-2" href={ruleUrl} title="Edit alert rule">
<i className="icon-gf icon-gf-settings" />
</a>
</div>
</li>
);

View File

@@ -82,7 +82,6 @@ exports[`AlertRuleList should render 1 rule 1`] = `
>
<button
className="btn btn-small btn-inverse alert-list__btn width-2"
disabled={false}
onClick={[Function]}
title="Pausing an alert rule prevents it from executing"
>

View File

@@ -87,6 +87,11 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
elem.toggleClass('playlist-active', newValue === true);
});
// check if we are in server side render
if (document.cookie.indexOf('renderKey') !== -1) {
body.addClass('body--phantomjs');
}
// tooltip removal fix
// manage page classes
var pageClass;

View File

@@ -1,5 +1,5 @@
<div class="dashboard-list">
<div class="page-action-bar page-action-bar--narrow" ng-hide="!ctrl.hasFilters && ctrl.sections.length === 0">
<div class="page-action-bar page-action-bar--narrow" ng-hide="ctrl.folderId && !ctrl.hasFilters && ctrl.sections.length === 0">
<label class="gf-form gf-form--grow gf-form--has-input-icon">
<input type="text" class="gf-form-input max-width-30" placeholder="Find Dashboard by name" tabindex="1" give-focus="true" ng-model="ctrl.query.query" ng-model-options="{ debounce: 500 }" spellcheck='false' ng-change="ctrl.onQueryChange()" />
<i class="gf-form-input-icon fa fa-search"></i>
@@ -52,6 +52,12 @@
</em>
</div>
<div class="search-results" ng-show="!ctrl.folderId && !ctrl.hasFilters && ctrl.sections.length === 0">
<em class="muted">
No dashboards found.
</em>
</div>
<div class="search-results" ng-show="ctrl.sections.length > 0">
<div class="search-results-filter-row">
<gf-form-switch
@@ -103,6 +109,7 @@
/>
</div>
</div>
</div>
<div ng-if="ctrl.canSave && ctrl.folderId && !ctrl.hasFilters && ctrl.sections.length === 0">

View File

@@ -37,7 +37,7 @@ export class ManageDashboardsCtrl {
folderUid?: string;
// if user can add new folders and/or add new dashboards
canSave: boolean;
canSave = false;
// if user has editor role or higher
isEditor: boolean;

View File

@@ -43,7 +43,7 @@
</tag-filter>
</div>
<div class="search-filter-box">
<div class="search-filter-box" ng-if="ctrl.isEditor">
<a href="dashboard/new" class="search-filter-box-link">
<i class="gicon gicon-dashboard-new"></i> New dashboard
</a>

View File

@@ -1,6 +1,7 @@
import _ from 'lodash';
import coreModule from '../../core_module';
import { SearchSrv } from 'app/core/services/search_srv';
import { contextSrv } from 'app/core/services/context_srv';
import appEvents from 'app/core/app_events';
export class SearchCtrl {
@@ -15,6 +16,7 @@ export class SearchCtrl {
ignoreClose: any;
isLoading: boolean;
initialFolderFilterTitle: string;
isEditor: string;
/** @ngInject */
constructor($scope, private $location, private $timeout, private searchSrv: SearchSrv) {
@@ -24,6 +26,7 @@ export class SearchCtrl {
this.initialFolderFilterTitle = 'All';
this.getTags = this.getTags.bind(this);
this.onTagSelect = this.onTagSelect.bind(this);
this.isEditor = contextSrv.isEditor;
}
closeSearch() {

View File

@@ -21,8 +21,9 @@ export class SignUpCtrl {
$scope.navModel = {
main: {
icon: 'gicon gicon-branding',
text: 'Sign Up',
subTitle: 'Register your Grafana account',
breadcrumbs: [{ title: 'Login', url: 'login' }, { title: 'Sign Up' }],
breadcrumbs: [{ title: 'Login', url: 'login' }],
},
};

View File

@@ -7,7 +7,7 @@ export class AlertSrv {
list: any[];
/** @ngInject */
constructor(private $timeout, private $rootScope, private $modal) {
constructor(private $timeout, private $rootScope) {
this.list = [];
}
@@ -39,7 +39,6 @@ export class AlertSrv {
appEvents.on('alert-warning', options => this.set(options[0], options[1], 'warning', 5000));
appEvents.on('alert-success', options => this.set(options[0], options[1], 'success', 3000));
appEvents.on('alert-error', options => this.set(options[0], options[1], 'error', 7000));
appEvents.on('confirm-modal', this.showConfirmModal.bind(this));
}
getIconForSeverity(severity) {
@@ -96,45 +95,6 @@ export class AlertSrv {
clearAll() {
this.list = [];
}
showConfirmModal(payload) {
var scope = this.$rootScope.$new();
scope.onConfirm = function() {
payload.onConfirm();
scope.dismiss();
};
scope.updateConfirmText = function(value) {
scope.confirmTextValid = payload.confirmText.toLowerCase() === value.toLowerCase();
};
scope.title = payload.title;
scope.text = payload.text;
scope.text2 = payload.text2;
scope.confirmText = payload.confirmText;
scope.onConfirm = payload.onConfirm;
scope.onAltAction = payload.onAltAction;
scope.altActionText = payload.altActionText;
scope.icon = payload.icon || 'fa-check';
scope.yesText = payload.yesText || 'Yes';
scope.noText = payload.noText || 'Cancel';
scope.confirmTextValid = scope.confirmText ? false : true;
var confirmModal = this.$modal({
template: 'public/app/partials/confirm_modal.html',
persist: false,
modalClass: 'confirm-modal',
show: false,
scope: scope,
keyboard: false,
});
confirmModal.then(function(modalEl) {
modalEl.modal('show');
});
}
}
coreModule.service('alertSrv', AlertSrv);

View File

@@ -5,9 +5,11 @@ import coreModule from 'app/core/core_module';
import appEvents from 'app/core/app_events';
import Mousetrap from 'mousetrap';
import 'mousetrap-global-bind';
export class KeybindingSrv {
helpModal: boolean;
modalOpen = false;
/** @ngInject */
constructor(private $rootScope, private $location) {
@@ -19,6 +21,7 @@ export class KeybindingSrv {
});
this.setupGlobal();
appEvents.on('show-modal', () => (this.modalOpen = true));
}
setupGlobal() {
@@ -30,6 +33,7 @@ export class KeybindingSrv {
this.bind('s o', this.openSearch);
this.bind('s t', this.openSearchTags);
this.bind('f', this.openSearch);
this.bindGlobal('esc', this.exit);
}
openSearchStarred() {
@@ -60,6 +64,28 @@ export class KeybindingSrv {
appEvents.emit('show-modal', { templateHtml: '<help-modal></help-modal>' });
}
exit() {
var popups = $('.popover.in');
if (popups.length > 0) {
return;
}
appEvents.emit('hide-modal');
if (!this.modalOpen) {
this.$rootScope.appEvent('panel-change-view', { fullscreen: false, edit: false });
} else {
this.modalOpen = false;
}
// close settings view
var search = this.$location.search();
if (search.editview) {
delete search.editview;
this.$location.search(search);
}
}
bind(keyArg, fn) {
Mousetrap.bind(
keyArg,
@@ -73,6 +99,19 @@ export class KeybindingSrv {
);
}
bindGlobal(keyArg, fn) {
Mousetrap.bindGlobal(
keyArg,
evt => {
evt.preventDefault();
evt.stopPropagation();
evt.returnValue = false;
return this.$rootScope.$apply(fn.bind(this));
},
'keydown'
);
}
showDashEditView() {
var search = _.extend(this.$location.search(), { editview: 'settings' });
this.$location.search(search);
@@ -204,23 +243,6 @@ export class KeybindingSrv {
this.bind('d v', () => {
appEvents.emit('toggle-view-mode');
});
this.bind('esc', () => {
var popups = $('.popover.in');
if (popups.length > 0) {
return;
}
scope.appEvent('hide-modal');
scope.appEvent('panel-change-view', { fullscreen: false, edit: false });
// close settings view
var search = this.$location.search();
if (search.editview) {
delete search.editview;
this.$location.search(search);
}
});
}
}

View File

@@ -10,6 +10,7 @@ export class UtilSrv {
init() {
appEvents.on('show-modal', this.showModal.bind(this), this.$rootScope);
appEvents.on('hide-modal', this.hideModal.bind(this), this.$rootScope);
appEvents.on('confirm-modal', this.showConfirmModal.bind(this), this.$rootScope);
}
hideModal() {
@@ -47,6 +48,38 @@ export class UtilSrv {
modalEl.modal('show');
});
}
showConfirmModal(payload) {
var scope = this.$rootScope.$new();
scope.onConfirm = function() {
payload.onConfirm();
scope.dismiss();
};
scope.updateConfirmText = function(value) {
scope.confirmTextValid = payload.confirmText.toLowerCase() === value.toLowerCase();
};
scope.title = payload.title;
scope.text = payload.text;
scope.text2 = payload.text2;
scope.confirmText = payload.confirmText;
scope.onConfirm = payload.onConfirm;
scope.onAltAction = payload.onAltAction;
scope.altActionText = payload.altActionText;
scope.icon = payload.icon || 'fa-check';
scope.yesText = payload.yesText || 'Yes';
scope.noText = payload.noText || 'Cancel';
scope.confirmTextValid = scope.confirmText ? false : true;
appEvents.emit('show-modal', {
src: 'public/app/partials/confirm_modal.html',
scope: scope,
modalClass: 'confirm-modal',
});
}
}
coreModule.service('utilSrv', UtilSrv);

View File

@@ -348,3 +348,10 @@ describe('duration', function() {
expect(str).toBe('1 year, 2 months, 0 weeks, 3 days, 4 hours, 5 minutes, 6 seconds, 7 milliseconds');
});
});
describe('volume', function() {
it('1000m3', function() {
var str = kbn.valueFormats['m3'](1000, 1, null);
expect(str).toBe('1000.0 m3');
});
});

View File

@@ -1,6 +1,12 @@
import { SearchCtrl } from '../components/search/search';
import { SearchSrv } from '../services/search_srv';
jest.mock('app/core/services/context_srv', () => ({
contextSrv: {
user: { orgId: 1 },
},
}));
describe('SearchCtrl', () => {
const searchSrvStub = {
search: (options: any) => {},

View File

@@ -547,8 +547,8 @@ kbn.valueFormats.accG = kbn.formatBuilders.fixedUnit('g');
// Volume
kbn.valueFormats.litre = kbn.formatBuilders.decimalSIPrefix('L');
kbn.valueFormats.mlitre = kbn.formatBuilders.decimalSIPrefix('L', -1);
kbn.valueFormats.m3 = kbn.formatBuilders.decimalSIPrefix('m3');
kbn.valueFormats.dm3 = kbn.formatBuilders.decimalSIPrefix('dm3');
kbn.valueFormats.m3 = kbn.formatBuilders.fixedUnit('m3');
kbn.valueFormats.dm3 = kbn.formatBuilders.fixedUnit('dm3');
kbn.valueFormats.gallons = kbn.formatBuilders.fixedUnit('gal');
// Flow

View File

@@ -58,15 +58,29 @@ export class AlertNotificationEditCtrl {
}
if (this.model.id) {
this.backendSrv.put(`/api/alert-notifications/${this.model.id}`, this.model).then(res => {
this.model = res;
appEvents.emit('alert-success', ['Notification updated', '']);
});
this.backendSrv
.put(`/api/alert-notifications/${this.model.id}`, this.model)
.then(res => {
this.model = res;
appEvents.emit('alert-success', ['Notification updated', '']);
})
.catch(err => {
if (err.data && err.data.error) {
appEvents.emit('alert-error', [err.data.error]);
}
});
} else {
this.backendSrv.post(`/api/alert-notifications`, this.model).then(res => {
appEvents.emit('alert-success', ['Notification created', '']);
this.$location.path('alerting/notifications');
});
this.backendSrv
.post(`/api/alert-notifications`, this.model)
.then(res => {
appEvents.emit('alert-success', ['Notification created', '']);
this.$location.path('alerting/notifications');
})
.catch(err => {
if (err.data && err.data.error) {
appEvents.emit('alert-error', [err.data.error]);
}
});
}
}

View File

@@ -18,7 +18,7 @@ export class DashboardMigrator {
}
updateSchema(old) {
var i, j, k;
var i, j, k, n;
var oldVersion = this.dashboard.schemaVersion;
var panelUpgrades = [];
this.dashboard.schemaVersion = 16;
@@ -372,6 +372,11 @@ export class DashboardMigrator {
for (j = 0; j < this.dashboard.panels.length; j++) {
for (k = 0; k < panelUpgrades.length; k++) {
panelUpgrades[k].call(this, this.dashboard.panels[j]);
if (this.dashboard.panels[j].panels) {
for (n = 0; n < this.dashboard.panels[j].panels.length; n++) {
panelUpgrades[k].call(this, this.dashboard.panels[j].panels[n]);
}
}
}
}
}
@@ -429,6 +434,9 @@ export class DashboardMigrator {
for (let panel of row.panels) {
panel.span = panel.span || DEFAULT_PANEL_SPAN;
if (panel.minSpan) {
panel.minSpan = Math.min(GRID_COLUMN_COUNT, GRID_COLUMN_COUNT / 12 * panel.minSpan);
}
const panelWidth = Math.floor(panel.span) * widthFactor;
const panelHeight = panel.height ? getGridHeight(panel.height) : rowGridHeight;

View File

@@ -500,11 +500,12 @@ export class DashboardModel {
if (!rowPanel.panels || rowPanel.panels.length === 0) {
return 0;
}
const rowYPos = rowPanel.gridPos.y;
const positions = _.map(rowPanel.panels, 'gridPos');
const maxPos = _.maxBy(positions, pos => {
return pos.y + pos.h;
});
return maxPos.h + 1;
return maxPos.y + maxPos.h - rowYPos;
}
removePanel(panel: PanelModel) {

View File

@@ -77,8 +77,11 @@ export class DashboardSrv {
postSave(clone, data) {
this.dash.version = data.version;
if (data.url !== this.$location.path()) {
this.$location.url(locationUtil.stripBaseFromUrl(data.url)).replace();
const newUrl = locationUtil.stripBaseFromUrl(data.url);
const currentPath = this.$location.path();
if (newUrl !== currentPath) {
this.$location.url(newUrl).replace();
}
this.$rootScope.appEvent('dashboard-saved', this.dash);

View File

@@ -30,7 +30,13 @@ export class FolderPickerCtrl {
}
getOptions(query) {
return this.backendSrv.get('api/dashboards/folders', { query: query }).then(result => {
const params = {
query: query,
type: 'dash-folder',
permission: 'Edit',
};
return this.backendSrv.get('api/search', params).then(result => {
if (
query === '' ||
query.toLowerCase() === 'g' ||

View File

@@ -363,6 +363,22 @@ describe('DashboardModel', function() {
expect(dashboard.panels[0].repeat).toBe('server');
expect(dashboard.panels.length).toBe(2);
});
it('minSpan should be twice', function() {
model.rows = [createRow({ height: 8 }, [[6]])];
model.rows[0].panels[0] = { minSpan: 12 };
let dashboard = new DashboardModel(model);
expect(dashboard.panels[0].minSpan).toBe(24);
});
it('should assign id', function() {
model.rows = [createRow({ collapse: true, height: 8 }, [[6], [6]])];
model.rows[0].panels[0] = {};
let dashboard = new DashboardModel(model);
expect(dashboard.panels[0].id).toBe(1);
});
});
});

View File

@@ -500,6 +500,22 @@ describe('given dashboard with row repeat', function() {
);
expect(panel_ids.length).toEqual(_.uniq(panel_ids).length);
});
it('should place new panels in proper order', function() {
dashboardJSON.panels = [
{ id: 1, type: 'row', gridPos: { x: 0, y: 0, h: 1, w: 24 }, repeat: 'apps' },
{ id: 2, type: 'graph', gridPos: { x: 0, y: 1, h: 3, w: 12 } },
{ id: 3, type: 'graph', gridPos: { x: 6, y: 1, h: 4, w: 12 } },
{ id: 4, type: 'graph', gridPos: { x: 0, y: 5, h: 2, w: 12 } },
];
dashboard = new DashboardModel(dashboardJSON);
dashboard.processRepeats();
const panel_types = _.map(dashboard.panels, 'type');
expect(panel_types).toEqual(['row', 'graph', 'graph', 'graph', 'row', 'graph', 'graph', 'graph']);
const panel_y_positions = _.map(dashboard.panels, p => p.gridPos.y);
expect(panel_y_positions).toEqual([0, 1, 1, 5, 7, 8, 8, 12]);
});
});
describe('given dashboard with row and panel repeat', () => {

View File

@@ -20,7 +20,7 @@
</div>
<div class="gf-form" ng-show="ctrl.panel.repeat">
<span class="gf-form-label width-9">Min width</span>
<select class="gf-form-input" ng-model="ctrl.panel.minSpan" ng-options="f for f in [1,2,3,4,5,6,7,8,9,10,11,12]">
<select class="gf-form-input" ng-model="ctrl.panel.minSpan" ng-options="f for f in [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]">
<option value=""></option>
</select>
</div>

View File

@@ -18,7 +18,7 @@
</div>
</form>
<div ng-if="mode === 'email-sent'">
<div ng-show="mode === 'email-sent'">
An email with a reset link as been sent to the email address. <br>
You should receive it shortly.
<div class="p-t-1">
@@ -27,5 +27,23 @@
</a>
</div>
</div>
<form name="resetForm" class="login-form gf-form-group" ng-show="mode === 'reset'">
<div class="gf-form">
<span class="gf-form-label width-9">New Password</span>
<input type="password" name="NewPassword" class="gf-form-input max-width-14" required ng-minlength="4" ng-model='formModel.newPassword' placeholder="password" watch-change="formModel.newPassword = inputValue;">
</div>
<div class="gf-form">
<span class="gf-form-label width-9">Confirm Password</span>
<input type="password" name="ConfirmPassword" class="gf-form-input max-width-14" required ng-minlength="4" ng-model='formModel.confirmPassword' placeholder="confirm password">
</div>
<div class="signup__password-strength">
<password-strength password="formModel.newPassword"></password-strength>
</div>
<div class="gf-form-button-row">
<button type="submit" class="btn btn-success" ng-click="submitReset();" ng-disabled="!resetForm.$valid">
Reset Password
</button>
</div>
</form>
</div>
</div>

View File

@@ -1,7 +1,7 @@
# CloudWatch Datasource - Native Plugin
# CloudWatch Data Source - Native Plugin
Grafana ships with **built in** support for CloudWatch. You just have to add it as a data source and you will be ready to build dashboards for you CloudWatch metrics.
Read more about it here:
[http://docs.grafana.org/datasources/cloudwatch/](http://docs.grafana.org/datasources/cloudwatch/)
[http://docs.grafana.org/datasources/cloudwatch/](http://docs.grafana.org/datasources/cloudwatch/)

View File

@@ -8,6 +8,7 @@
"annotations": true,
"info": {
"description": "Cloudwatch Data Source for Grafana",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
@@ -15,6 +16,7 @@
"logos": {
"small": "img/amazon-web-services.png",
"large": "img/amazon-web-services.png"
}
},
"version": "5.0.0"
}
}

View File

@@ -1,4 +1,4 @@
# Elasticsearch Datasource - Native Plugin
# Elasticsearch Data Source - Native Plugin
Grafana ships with **advanced support** for Elasticsearch. You can do many types of simple or complex elasticsearch queries to visualize logs or metrics stored in Elasticsearch. You can also annotate your graphs with log events stored in Elasticsearch.

View File

@@ -166,7 +166,7 @@ export class ElasticDatasource {
for (var i = 0; i < hits.length; i++) {
var source = hits[i]._source;
var time = source[timeField];
var time = getFieldFromSource(source, timeField);
if (typeof hits[i].fields !== 'undefined') {
var fields = hits[i].fields;
if (_.isString(fields[timeField]) || _.isNumber(fields[timeField])) {

View File

@@ -17,7 +17,7 @@
"links": [
{"name": "elastic.co", "url": "https://www.elastic.co/products/elasticsearch"}
],
"version": "3.0.0"
"version": "5.0.0"
},
"annotations": true,

View File

@@ -6,4 +6,8 @@ Grafana has an advanced Graphite query editor that lets you quickly navigate the
Read more about it here:
[http://docs.grafana.org/datasources/graphite/](http://docs.grafana.org/datasources/graphite/)
[http://docs.grafana.org/datasources/graphite/](http://docs.grafana.org/datasources/graphite/)
Graphite 1.1 Release:
[https://grafana.com/blog/2018/01/11/graphite-1.1-teaching-an-old-dog-new-tricks/](https://grafana.com/blog/2018/01/11/graphite-1.1-teaching-an-old-dog-new-tricks/)

View File

@@ -17,6 +17,7 @@
},
"info": {
"description": "Graphite Data Source for Grafana",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
@@ -24,6 +25,11 @@
"logos": {
"small": "img/graphite_logo.png",
"large": "img/graphite_logo.png"
}
},
"links": [
{"name": "Graphite", "url": "https://graphiteapp.org/"},
{"name": "Graphite 1.1 Release", "url": "https://grafana.com/blog/2018/01/11/graphite-1.1-teaching-an-old-dog-new-tricks/"}
],
"version": "5.0.0"
}
}

View File

@@ -1,10 +1,8 @@
# InfluxDB Datasource - Native Plugin
Grafana ships with **built in** support for InfluxDB 0.9.
Grafana ships with **built in** support for InfluxDB (> 0.9.x).
There are currently two separate datasources for InfluxDB in Grafana: InfluxDB 0.8.x and InfluxDB 0.9.x. The API and capabilities of InfluxDB 0.9.x are completely different from InfluxDB 0.8.x which is why Grafana handles them as different data sources.
This is the plugin for InfluxDB 0.9. It is rapidly evolving and we continue to track its API.
There are currently two separate datasources for InfluxDB in Grafana: InfluxDB 0.8.x and the latest InfluxDB release. The API and capabilities of latest (> 0.9.x) InfluxDB are completely different from InfluxDB 0.8.x which is why Grafana handles them as different data sources.
InfluxDB 0.8 is no longer maintained by InfluxDB Inc, but we provide support as a convenience to existing users. You can find it [here](https://grafana.com/plugins/grafana-influxdb-08-datasource).

View File

@@ -13,6 +13,7 @@
},
"info": {
"description": "InfluxDB Data Source for Grafana",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
@@ -20,6 +21,7 @@
"logos": {
"small": "img/influxdb_logo.svg",
"large": "img/influxdb_logo.svg"
}
},
"version": "5.0.0"
}
}

View File

@@ -1,3 +1,14 @@
# Grafana Fake Data Datasource - Native Plugin
# MySQL Data Source - Native Plugin
This is the built in Fake Data Datasource that is used before any datasources are set up in your Grafana installation. It means you can create a graph without any data and still get an idea of what it would look like.
Grafana ships with a built-in MySQL data source plugin that allow you to query any visualize data from a MySQL compatible database.
## Adding the data source
1. Open the side menu by clicking the Grafana icon in the top header.
2. In the side menu under the Dashboards link you should find a link named Data Sources.
3. Click the + Add data source button in the top header.
4. Select MySQL from the Type dropdown.
Read more about it here:
[http://docs.grafana.org/features/datasources/mysql/](http://docs.grafana.org/features/datasources/mysql/)

View File

@@ -4,6 +4,7 @@
"id": "mysql",
"info": {
"description": "MySQL Data Source for Grafana",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
@@ -11,7 +12,8 @@
"logos": {
"small": "img/mysql_logo.svg",
"large": "img/mysql_logo.svg"
}
},
"version": "5.0.0"
},
"alerting": true,

View File

@@ -1,7 +1,7 @@
# OpenTSDB Datasource - Native Plugin
# OpenTSDB Data Source - Native Plugin
Grafana ships with **built in** support for OpenTSDB, a scalable, distributed time series database.
Read more about it here:
[http://docs.grafana.org/datasources/opentsdb/](http://docs.grafana.org/datasources/opentsdb/)
[http://docs.grafana.org/datasources/opentsdb/](http://docs.grafana.org/datasources/opentsdb/)

View File

@@ -9,6 +9,7 @@
"alerting": true,
"info": {
"description": "OpenTSDB Data Source for Grafana",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
@@ -16,6 +17,7 @@
"logos": {
"small": "img/opentsdb_logo.png",
"large": "img/opentsdb_logo.png"
}
},
"version": "5.0.0"
}
}

View File

@@ -1,3 +1,12 @@
# Grafana PostgreSQL Datasource - Native Plugin
# Grafana PostgreSQL Data Source - Native Plugin
This is the built in PostgreSQL Datasource that is used to connect to PostgreSQL databases.
Grafana ships with a built-in PostgreSQL data source plugin that allows you to query and visualize data from a PostgreSQL compatible database.
## Adding the data source
1. Open the side menu by clicking the Grafana icon in the top header.
2. In the side menu under the Dashboards link you should find a link named Data Sources.
3. Click the + Add data source button in the top header.
4. Select PostgreSQL from the Type dropdown.
[http://docs.grafana.org/features/datasources/postgres/](http://docs.grafana.org/features/datasources/postgres/)

View File

@@ -4,6 +4,7 @@
"id": "postgres",
"info": {
"description": "PostgreSQL Data Source for Grafana",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
@@ -11,7 +12,8 @@
"logos": {
"small": "img/postgresql_logo.svg",
"large": "img/postgresql_logo.svg"
}
},
"version": "5.0.0"
},
"alerting": true,

View File

@@ -1,4 +1,4 @@
# Prometheus Datasource - Native Plugin
# Prometheus Data Source - Native Plugin
Grafana ships with **built in** support for Prometheus, the open-source service monitoring system and time series database.

View File

@@ -18,6 +18,7 @@
},
"info": {
"description": "Prometheus Data Source for Grafana",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
@@ -25,6 +26,10 @@
"logos": {
"small": "img/prometheus_logo.svg",
"large": "img/prometheus_logo.svg"
}
},
"links": [
{"name": "Prometheus", "url": "https://prometheus.io/"}
],
"version": "5.0.0"
}
}

View File

@@ -1 +1,9 @@
# Alert List Panel - Native plugin
This Alert List panel is **included** with Grafana.
The Alert List panel allows you to display alerts on a dashboard. The list can be configured to show either the current state of your alerts or recent alert state changes. You can read more about alerts [here](http://docs.grafana.org/alerting/rules).
Read more about it here:
[http://docs.grafana.org/features/panels/alertlist/](http://docs.grafana.org/features/panels/alertlist/)

View File

@@ -4,13 +4,15 @@
"id": "alertlist",
"info": {
"description": "Shows list of alerts and their current status",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
},
},
"logos": {
"small": "img/icn-singlestat-panel.svg",
"large": "img/icn-singlestat-panel.svg"
}
},
"version": "5.0.0"
}
}

View File

@@ -4,6 +4,7 @@
"id": "dashlist",
"info": {
"description": "List of dynamic links to other dashboards",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
@@ -11,6 +12,7 @@
"logos": {
"small": "img/icn-dashlist-panel.svg",
"large": "img/icn-dashlist-panel.svg"
}
},
"version": "5.0.0"
}
}

View File

@@ -4,6 +4,7 @@
"id": "graph",
"info": {
"description": "Graph Panel for Grafana",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
@@ -11,7 +12,8 @@
"logos": {
"small": "img/icn-graph-panel.svg",
"large": "img/icn-graph-panel.svg"
}
},
"version": "5.0.0"
}
}

View File

@@ -0,0 +1,7 @@
# Heatmap Panel - Native Plugin
The Heatmap panel allows you to view histograms over time and is **included** with Grafana.
Read more about it here:
[http://docs.grafana.org/features/panels/heatmap/](http://docs.grafana.org/features/panels/heatmap/)

View File

@@ -4,6 +4,7 @@
"id": "heatmap",
"info": {
"description": "Heatmap Panel for Grafana",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
@@ -11,6 +12,11 @@
"logos": {
"small": "img/icn-heatmap-panel.svg",
"large": "img/icn-heatmap-panel.svg"
}
},
"links": [
{"name": "Brendan Gregg - Heatmaps", "url": "http://www.brendangregg.com/heatmaps.html"},
{"name": "Brendan Gregg - Latency Heatmaps", "url": " http://www.brendangregg.com/HeatMaps/latency.html"}
],
"version": "5.0.0"
}
}

View File

@@ -1,2 +1,3 @@
# Plugin List Panel - Native Plugin
The Plugin List plans shows the installed plugins for your Grafana instance and is **included** with Grafana. It is used on the default Home dashboard.

View File

@@ -4,6 +4,7 @@
"id": "pluginlist",
"info": {
"description": "Plugin List for Grafana",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
@@ -11,6 +12,7 @@
"logos": {
"small": "img/icn-dashlist-panel.svg",
"large": "img/icn-dashlist-panel.svg"
}
},
"version": "5.0.0"
}
}

View File

@@ -4,6 +4,7 @@
"id": "singlestat",
"info": {
"description": "Singlestat Panel for Grafana",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
@@ -11,7 +12,8 @@
"logos": {
"small": "img/icn-singlestat-panel.svg",
"large": "img/icn-singlestat-panel.svg"
}
},
"version": "5.0.0"
}
}

View File

@@ -6,4 +6,4 @@ The table panel is very flexible, supporting both multiple modes for time series
Check out the [Table Panel Showcase in the Grafana Playground](http://play.grafana.org/dashboard/db/table-panel-showcase) or read more about it here:
[http://docs.grafana.org/reference/table_panel/](http://docs.grafana.org/reference/table_panel/)
[http://docs.grafana.org/reference/table_panel/](http://docs.grafana.org/reference/table_panel/)

View File

@@ -4,6 +4,7 @@
"id": "table",
"info": {
"description": "Table Panel for Grafana",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
@@ -11,7 +12,8 @@
"logos": {
"small": "img/icn-table-panel.svg",
"large": "img/icn-table-panel.svg"
}
},
"version": "5.0.0"
}
}

View File

@@ -11,7 +11,8 @@
"logos": {
"small": "img/icn-text-panel.svg",
"large": "img/icn-text-panel.svg"
}
},
"version": "5.0.0"
}
}

View File

@@ -14,7 +14,6 @@ export const AlertRule = types
stateAge: types.string,
info: types.optional(types.string, ''),
url: types.string,
canEdit: types.boolean,
})
.views(self => ({
get isPaused() {

View File

@@ -1,9 +1,8 @@
import { types } from 'mobx-state-tree';
import { types } from 'mobx-state-tree';
export const PermissionsStoreItem = types
.model('PermissionsStoreItem', {
dashboardId: types.optional(types.number, -1),
id: types.maybe(types.number),
permission: types.number,
permissionName: types.maybe(types.string),
role: types.maybe(types.string),

View File

@@ -72,7 +72,7 @@ $textShadow: none;
// gradients
$brand-gradient: linear-gradient(to right, rgba(255, 213, 0, 1) 0%, rgba(255, 68, 0, 1) 99%, rgba(255, 68, 0, 1) 100%);
$page-gradient: linear-gradient(-60deg, transparent 70%, $gray-7 98%);
$page-gradient: linear-gradient(-60deg, $gray-7, #f5f6f9 70%, $gray-7 98%);
// Links
// -------------------------

View File

@@ -1,290 +1,254 @@
@import "base/font_awesome";
@import "base/grafana_icons";
@import 'font_awesome';
@import 'grafana_icons';
/* cyrillic-ext */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local("Roboto"), local("Roboto-Regular"),
url(../fonts/roboto/ek4gzZ-GeXAPcSbHtCeQI_esZW2xOQ-xsNqO47m55DA.woff2)
format("woff2");
src: local('Roboto'), local('Roboto-Regular'),
url(../fonts/roboto/ek4gzZ-GeXAPcSbHtCeQI_esZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0460-052f, U+20b4, U+2de0-2dff, U+A640-A69F;
}
/* cyrillic */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local("Roboto"), local("Roboto-Regular"),
url(../fonts/roboto/mErvLBYg_cXG3rLvUsKT_fesZW2xOQ-xsNqO47m55DA.woff2)
format("woff2");
src: local('Roboto'), local('Roboto-Regular'),
url(../fonts/roboto/mErvLBYg_cXG3rLvUsKT_fesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0400-045f, U+0490-0491, U+04b0-04b1, U+2116;
}
/* greek-ext */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local("Roboto"), local("Roboto-Regular"),
url(../fonts/roboto/-2n2p-_Y08sg57CNWQfKNvesZW2xOQ-xsNqO47m55DA.woff2)
format("woff2");
src: local('Roboto'), local('Roboto-Regular'),
url(../fonts/roboto/-2n2p-_Y08sg57CNWQfKNvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+1f00-1fff;
}
/* greek */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local("Roboto"), local("Roboto-Regular"),
url(../fonts/roboto/u0TOpm082MNkS5K0Q4rhqvesZW2xOQ-xsNqO47m55DA.woff2)
format("woff2");
src: local('Roboto'), local('Roboto-Regular'),
url(../fonts/roboto/u0TOpm082MNkS5K0Q4rhqvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0370-03ff;
}
/* vietnamese */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local("Roboto"), local("Roboto-Regular"),
url(../fonts/roboto/NdF9MtnOpLzo-noMoG0miPesZW2xOQ-xsNqO47m55DA.woff2)
format("woff2");
src: local('Roboto'), local('Roboto-Regular'),
url(../fonts/roboto/NdF9MtnOpLzo-noMoG0miPesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0102-0103, U+1ea0-1ef9, U+20ab;
}
/* latin-ext */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local("Roboto"), local("Roboto-Regular"),
url(../fonts/roboto/Fcx7Wwv8OzT71A3E1XOAjvesZW2xOQ-xsNqO47m55DA.woff2)
format("woff2");
unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f,
U+A720-A7FF;
src: local('Roboto'), local('Roboto-Regular'),
url(../fonts/roboto/Fcx7Wwv8OzT71A3E1XOAjvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local("Roboto"), local("Roboto-Regular"),
url(../fonts/roboto/CWB0XYA8bzo0kSThX0UTuA.woff2) format("woff2");
unicode-range: U+0000-00ff, U+0131, U+0152-0153, U+02c6, U+02da, U+02dc,
U+2000-206f, U+2074, U+20ac, U+2212, U+2215;
src: local('Roboto'), local('Roboto-Regular'), url(../fonts/roboto/CWB0XYA8bzo0kSThX0UTuA.woff2) format('woff2');
unicode-range: U+0000-00ff, U+0131, U+0152-0153, U+02c6, U+02da, U+02dc, U+2000-206f, U+2074, U+20ac, U+2212, U+2215;
}
/* cyrillic-ext */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local("Roboto Medium"), local("Roboto-Medium"),
url(../fonts/roboto/ZLqKeelYbATG60EpZBSDyxJtnKITppOI_IvcXXDNrsc.woff2)
format("woff2");
src: local('Roboto Medium'), local('Roboto-Medium'),
url(../fonts/roboto/ZLqKeelYbATG60EpZBSDyxJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0460-052f, U+20b4, U+2de0-2dff, U+A640-A69F;
}
/* cyrillic */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local("Roboto Medium"), local("Roboto-Medium"),
url(../fonts/roboto/oHi30kwQWvpCWqAhzHcCSBJtnKITppOI_IvcXXDNrsc.woff2)
format("woff2");
src: local('Roboto Medium'), local('Roboto-Medium'),
url(../fonts/roboto/oHi30kwQWvpCWqAhzHcCSBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0400-045f, U+0490-0491, U+04b0-04b1, U+2116;
}
/* greek-ext */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local("Roboto Medium"), local("Roboto-Medium"),
url(../fonts/roboto/rGvHdJnr2l75qb0YND9NyBJtnKITppOI_IvcXXDNrsc.woff2)
format("woff2");
src: local('Roboto Medium'), local('Roboto-Medium'),
url(../fonts/roboto/rGvHdJnr2l75qb0YND9NyBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+1f00-1fff;
}
/* greek */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local("Roboto Medium"), local("Roboto-Medium"),
url(../fonts/roboto/mx9Uck6uB63VIKFYnEMXrRJtnKITppOI_IvcXXDNrsc.woff2)
format("woff2");
src: local('Roboto Medium'), local('Roboto-Medium'),
url(../fonts/roboto/mx9Uck6uB63VIKFYnEMXrRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0370-03ff;
}
/* vietnamese */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local("Roboto Medium"), local("Roboto-Medium"),
url(../fonts/roboto/mbmhprMH69Zi6eEPBYVFhRJtnKITppOI_IvcXXDNrsc.woff2)
format("woff2");
src: local('Roboto Medium'), local('Roboto-Medium'),
url(../fonts/roboto/mbmhprMH69Zi6eEPBYVFhRJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0102-0103, U+1ea0-1ef9, U+20ab;
}
/* latin-ext */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local("Roboto Medium"), local("Roboto-Medium"),
url(../fonts/roboto/oOeFwZNlrTefzLYmlVV1UBJtnKITppOI_IvcXXDNrsc.woff2)
format("woff2");
unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f,
U+A720-A7FF;
src: local('Roboto Medium'), local('Roboto-Medium'),
url(../fonts/roboto/oOeFwZNlrTefzLYmlVV1UBJtnKITppOI_IvcXXDNrsc.woff2) format('woff2');
unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local("Roboto Medium"), local("Roboto-Medium"),
url(../fonts/roboto/RxZJdnzeo3R5zSexge8UUVtXRa8TVwTICgirnJhmVJw.woff2)
format("woff2");
unicode-range: U+0000-00ff, U+0131, U+0152-0153, U+02c6, U+02da, U+02dc,
U+2000-206f, U+2074, U+20ac, U+2212, U+2215;
src: local('Roboto Medium'), local('Roboto-Medium'),
url(../fonts/roboto/RxZJdnzeo3R5zSexge8UUVtXRa8TVwTICgirnJhmVJw.woff2) format('woff2');
unicode-range: U+0000-00ff, U+0131, U+0152-0153, U+02c6, U+02da, U+02dc, U+2000-206f, U+2074, U+20ac, U+2212, U+2215;
}
/* cyrillic-ext */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: local("Roboto Italic"), local("Roboto-Italic"),
url(../fonts/roboto/WxrXJa0C3KdtC7lMafG4dRTbgVql8nDJpwnrE27mub0.woff2)
format("woff2");
src: local('Roboto Italic'), local('Roboto-Italic'),
url(../fonts/roboto/WxrXJa0C3KdtC7lMafG4dRTbgVql8nDJpwnrE27mub0.woff2) format('woff2');
unicode-range: U+0460-052f, U+20b4, U+2de0-2dff, U+A640-A69F;
}
/* cyrillic */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: local("Roboto Italic"), local("Roboto-Italic"),
url(../fonts/roboto/OpXUqTo0UgQQhGj_SFdLWBTbgVql8nDJpwnrE27mub0.woff2)
format("woff2");
src: local('Roboto Italic'), local('Roboto-Italic'),
url(../fonts/roboto/OpXUqTo0UgQQhGj_SFdLWBTbgVql8nDJpwnrE27mub0.woff2) format('woff2');
unicode-range: U+0400-045f, U+0490-0491, U+04b0-04b1, U+2116;
}
/* greek-ext */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: local("Roboto Italic"), local("Roboto-Italic"),
url(../fonts/roboto/1hZf02POANh32k2VkgEoUBTbgVql8nDJpwnrE27mub0.woff2)
format("woff2");
src: local('Roboto Italic'), local('Roboto-Italic'),
url(../fonts/roboto/1hZf02POANh32k2VkgEoUBTbgVql8nDJpwnrE27mub0.woff2) format('woff2');
unicode-range: U+1f00-1fff;
}
/* greek */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: local("Roboto Italic"), local("Roboto-Italic"),
url(../fonts/roboto/cDKhRaXnQTOVbaoxwdOr9xTbgVql8nDJpwnrE27mub0.woff2)
format("woff2");
src: local('Roboto Italic'), local('Roboto-Italic'),
url(../fonts/roboto/cDKhRaXnQTOVbaoxwdOr9xTbgVql8nDJpwnrE27mub0.woff2) format('woff2');
unicode-range: U+0370-03ff;
}
/* vietnamese */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: local("Roboto Italic"), local("Roboto-Italic"),
url(../fonts/roboto/K23cxWVTrIFD6DJsEVi07RTbgVql8nDJpwnrE27mub0.woff2)
format("woff2");
src: local('Roboto Italic'), local('Roboto-Italic'),
url(../fonts/roboto/K23cxWVTrIFD6DJsEVi07RTbgVql8nDJpwnrE27mub0.woff2) format('woff2');
unicode-range: U+0102-0103, U+1ea0-1ef9, U+20ab;
}
/* latin-ext */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: local("Roboto Italic"), local("Roboto-Italic"),
url(../fonts/roboto/vSzulfKSK0LLjjfeaxcREhTbgVql8nDJpwnrE27mub0.woff2)
format("woff2");
unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f,
U+A720-A7FF;
src: local('Roboto Italic'), local('Roboto-Italic'),
url(../fonts/roboto/vSzulfKSK0LLjjfeaxcREhTbgVql8nDJpwnrE27mub0.woff2) format('woff2');
unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: local("Roboto Italic"), local("Roboto-Italic"),
url(../fonts/roboto/vPcynSL0qHq_6dX7lKVByfesZW2xOQ-xsNqO47m55DA.woff2)
format("woff2");
unicode-range: U+0000-00ff, U+0131, U+0152-0153, U+02c6, U+02da, U+02dc,
U+2000-206f, U+2074, U+20ac, U+2212, U+2215;
src: local('Roboto Italic'), local('Roboto-Italic'),
url(../fonts/roboto/vPcynSL0qHq_6dX7lKVByfesZW2xOQ-xsNqO47m55DA.woff2) format('woff2');
unicode-range: U+0000-00ff, U+0131, U+0152-0153, U+02c6, U+02da, U+02dc, U+2000-206f, U+2074, U+20ac, U+2212, U+2215;
}
/* cyrillic-ext */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: italic;
font-weight: 500;
src: local("Roboto Medium Italic"), local("Roboto-MediumItalic"),
url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0TTOQ_MqJVwkKsUn0wKzc2I.woff2)
format("woff2");
src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'),
url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0TTOQ_MqJVwkKsUn0wKzc2I.woff2) format('woff2');
unicode-range: U+0460-052f, U+20b4, U+2de0-2dff, U+A640-A69F;
}
/* cyrillic */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: italic;
font-weight: 500;
src: local("Roboto Medium Italic"), local("Roboto-MediumItalic"),
url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0TUj_cnvWIuuBMVgbX098Mw.woff2)
format("woff2");
src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'),
url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0TUj_cnvWIuuBMVgbX098Mw.woff2) format('woff2');
unicode-range: U+0400-045f, U+0490-0491, U+04b0-04b1, U+2116;
}
/* greek-ext */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: italic;
font-weight: 500;
src: local("Roboto Medium Italic"), local("Roboto-MediumItalic"),
url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0UbcKLIaa1LC45dFaAfauRA.woff2)
format("woff2");
src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'),
url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0UbcKLIaa1LC45dFaAfauRA.woff2) format('woff2');
unicode-range: U+1f00-1fff;
}
/* greek */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: italic;
font-weight: 500;
src: local("Roboto Medium Italic"), local("Roboto-MediumItalic"),
url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0Wo_sUJ8uO4YLWRInS22T3Y.woff2)
format("woff2");
src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'),
url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0Wo_sUJ8uO4YLWRInS22T3Y.woff2) format('woff2');
unicode-range: U+0370-03ff;
}
/* vietnamese */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: italic;
font-weight: 500;
src: local("Roboto Medium Italic"), local("Roboto-MediumItalic"),
url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0b6up8jxqWt8HVA3mDhkV_0.woff2)
format("woff2");
src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'),
url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0b6up8jxqWt8HVA3mDhkV_0.woff2) format('woff2');
unicode-range: U+0102-0103, U+1ea0-1ef9, U+20ab;
}
/* latin-ext */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: italic;
font-weight: 500;
src: local("Roboto Medium Italic"), local("Roboto-MediumItalic"),
url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0SYE0-AqJ3nfInTTiDXDjU4.woff2)
format("woff2");
unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f,
U+A720-A7FF;
src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'),
url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0SYE0-AqJ3nfInTTiDXDjU4.woff2) format('woff2');
unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: "Roboto";
font-family: 'Roboto';
font-style: italic;
font-weight: 500;
src: local("Roboto Medium Italic"), local("Roboto-MediumItalic"),
url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0Y4P5ICox8Kq3LLUNMylGO4.woff2)
format("woff2");
unicode-range: U+0000-00ff, U+0131, U+0152-0153, U+02c6, U+02da, U+02dc,
U+2000-206f, U+2074, U+20ac, U+2212, U+2215;
src: local('Roboto Medium Italic'), local('Roboto-MediumItalic'),
url(../fonts/roboto/OLffGBTaF0XFOW1gnuHF0Y4P5ICox8Kq3LLUNMylGO4.woff2) format('woff2');
unicode-range: U+0000-00ff, U+0131, U+0152-0153, U+02c6, U+02da, U+02dc, U+2000-206f, U+2074, U+20ac, U+2212, U+2215;
}

View File

@@ -41,8 +41,8 @@
.theme-dark {
.react-grid-item > .react-resizable-handle::after {
border-right: 2px solid $gray-4;
border-bottom: 2px solid $gray-4;
border-right: 2px solid $gray-1;
border-bottom: 2px solid $gray-1;
}
}

View File

@@ -16,6 +16,10 @@
padding-left: 0px;
}
.graph-legend-table {
width: auto;
}
.graph-legend-table .graph-legend-series {
display: table-row;
}
@@ -45,7 +49,7 @@
.graph-legend {
flex: 0 1 auto;
max-height: 30%;
margin: 0 $spacer;
margin: 0;
text-align: center;
padding-top: 6px;
position: relative;
@@ -70,19 +74,19 @@
font-size: 85%;
text-align: left;
&.current::before {
content: "Current: ";
content: 'Current: ';
}
&.max::before {
content: "Max: ";
content: 'Max: ';
}
&.min::before {
content: "Min: ";
content: 'Min: ';
}
&.total::before {
content: "Total: ";
content: 'Total: ';
}
&.avg::before {
content: "Avg: ";
content: 'Avg: ';
}
}
@@ -106,6 +110,15 @@
padding-left: 6px;
}
// fix for phantomjs
.body--phantomjs {
.graph-panel--legend-right {
.graph-legend-table {
display: table;
}
}
}
.graph-legend-table {
tbody {
display: block;
@@ -114,6 +127,7 @@
height: 100%;
padding-bottom: 1px;
padding-right: 5px;
padding-left: 5px;
}
.graph-legend-series {
@@ -124,7 +138,7 @@
float: none;
.graph-legend-alias::after {
content: "(right-y)";
content: '(right-y)';
padding: 0 5px;
color: $text-color-weak;
}
@@ -175,7 +189,7 @@
&.total,
&.avg {
&::before {
content: "";
content: '';
}
}
}