mirror of
https://github.com/grafana/grafana.git
synced 2026-07-29 15:59:50 -05:00
Merge branch 'master' into 10630_folder_api
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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' }],
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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) => {},
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user