mirror of https://github.com/grafana/grafana
commit
9358d0c6f7
@ -0,0 +1,74 @@ |
||||
import {Emitter} from 'app/core/core'; |
||||
|
||||
export interface GridPos { |
||||
x: number; |
||||
y: number; |
||||
w: number; |
||||
h: number; |
||||
} |
||||
|
||||
const notPersistedProperties: {[str: string]: boolean} = { |
||||
"events": true, |
||||
"fullscreen": true, |
||||
"isEditing": true, |
||||
}; |
||||
|
||||
export class PanelModel { |
||||
id: number; |
||||
gridPos: GridPos; |
||||
type: string; |
||||
title: string; |
||||
alert?: any; |
||||
|
||||
// non persisted
|
||||
fullscreen: boolean; |
||||
isEditing: boolean; |
||||
events: Emitter; |
||||
|
||||
constructor(model) { |
||||
this.events = new Emitter(); |
||||
|
||||
// copy properties from persisted model
|
||||
for (var property in model) { |
||||
this[property] = model[property]; |
||||
} |
||||
} |
||||
|
||||
getSaveModel() { |
||||
const model: any = {}; |
||||
for (var property in this) { |
||||
if (notPersistedProperties[property] || !this.hasOwnProperty(property)) { |
||||
continue; |
||||
} |
||||
|
||||
model[property] = this[property]; |
||||
} |
||||
|
||||
return model; |
||||
} |
||||
|
||||
setViewMode(fullscreen: boolean, isEditing: boolean) { |
||||
this.fullscreen = fullscreen; |
||||
this.isEditing = isEditing; |
||||
this.events.emit('panel-size-changed'); |
||||
} |
||||
|
||||
updateGridPos(newPos: GridPos) { |
||||
let sizeChanged = false; |
||||
|
||||
if (this.gridPos.w !== newPos.w || this.gridPos.h !== newPos.h) { |
||||
sizeChanged = true; |
||||
} |
||||
|
||||
this.gridPos.x = newPos.x; |
||||
this.gridPos.y = newPos.y; |
||||
this.gridPos.w = newPos.w; |
||||
this.gridPos.h = newPos.h; |
||||
|
||||
if (sizeChanged) { |
||||
console.log('PanelModel sizeChanged event and render events fired'); |
||||
this.events.emit('panel-size-changed'); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,131 @@ |
||||
import React from 'react'; |
||||
import coreModule from 'app/core/core_module'; |
||||
import ReactGridLayout from 'react-grid-layout'; |
||||
import {CELL_HEIGHT, CELL_VMARGIN} from '../DashboardModel'; |
||||
import {DashboardPanel} from './DashboardPanel'; |
||||
import {DashboardModel} from '../DashboardModel'; |
||||
import {PanelContainer} from './PanelContainer'; |
||||
import {PanelModel} from '../PanelModel'; |
||||
import classNames from 'classnames'; |
||||
import sizeMe from 'react-sizeme'; |
||||
|
||||
const COLUMN_COUNT = 12; |
||||
|
||||
function GridWrapper({size, layout, onLayoutChange, children, onResize}) { |
||||
if (size.width === 0) { |
||||
console.log('size is zero!'); |
||||
} |
||||
|
||||
const gridWidth = size.width > 0 ? size.width : 1200; |
||||
|
||||
return ( |
||||
<ReactGridLayout |
||||
width={gridWidth} |
||||
className="layout" |
||||
isDraggable={true} |
||||
isResizable={true} |
||||
measureBeforeMount={false} |
||||
containerPadding={[0, 0]} |
||||
useCSSTransforms={true} |
||||
margin={[CELL_VMARGIN, CELL_VMARGIN]} |
||||
cols={COLUMN_COUNT} |
||||
rowHeight={CELL_HEIGHT} |
||||
draggableHandle=".grid-drag-handle" |
||||
layout={layout} |
||||
onResize={onResize} |
||||
onLayoutChange={onLayoutChange}> |
||||
{children} |
||||
</ReactGridLayout> |
||||
); |
||||
} |
||||
|
||||
const SizedReactLayoutGrid = sizeMe({monitorWidth: true})(GridWrapper); |
||||
|
||||
export interface DashboardGridProps { |
||||
getPanelContainer: () => PanelContainer; |
||||
} |
||||
|
||||
export class DashboardGrid extends React.Component<DashboardGridProps, any> { |
||||
gridToPanelMap: any; |
||||
panelContainer: PanelContainer; |
||||
dashboard: DashboardModel; |
||||
panelMap: {[id: string]: PanelModel}; |
||||
|
||||
constructor(props) { |
||||
super(props); |
||||
this.panelContainer = this.props.getPanelContainer(); |
||||
this.onLayoutChange = this.onLayoutChange.bind(this); |
||||
this.onResize = this.onResize.bind(this); |
||||
|
||||
// subscribe to dashboard events
|
||||
this.dashboard = this.panelContainer.getDashboard(); |
||||
this.dashboard.on('panel-added', this.triggerForceUpdate.bind(this)); |
||||
this.dashboard.on('view-mode-changed', this.triggerForceUpdate.bind(this)); |
||||
} |
||||
|
||||
buildLayout() { |
||||
const layout = []; |
||||
this.panelMap = {}; |
||||
|
||||
for (let panel of this.dashboard.panels) { |
||||
let stringId = panel.id.toString(); |
||||
this.panelMap[stringId] = panel; |
||||
|
||||
if (!panel.gridPos) { |
||||
console.log('panel without gridpos'); |
||||
continue; |
||||
} |
||||
|
||||
layout.push({ |
||||
i: stringId, |
||||
x: panel.gridPos.x, |
||||
y: panel.gridPos.y, |
||||
w: panel.gridPos.w, |
||||
h: panel.gridPos.h, |
||||
}); |
||||
} |
||||
|
||||
return layout; |
||||
} |
||||
|
||||
onLayoutChange(newLayout) { |
||||
for (const newPos of newLayout) { |
||||
this.panelMap[newPos.i].updateGridPos(newPos); |
||||
} |
||||
} |
||||
|
||||
triggerForceUpdate() { |
||||
this.forceUpdate(); |
||||
} |
||||
|
||||
onResize(layout, oldItem, newItem) { |
||||
this.panelMap[newItem.i].updateGridPos(newItem); |
||||
} |
||||
|
||||
renderPanels() { |
||||
const panelElements = []; |
||||
|
||||
for (let panel of this.dashboard.panels) { |
||||
const panelClasses = classNames({panel: true, 'panel--fullscreen': panel.fullscreen}); |
||||
panelElements.push( |
||||
<div key={panel.id.toString()} className={panelClasses}> |
||||
<DashboardPanel panel={panel} getPanelContainer={this.props.getPanelContainer} /> |
||||
</div>, |
||||
); |
||||
} |
||||
|
||||
return panelElements; |
||||
} |
||||
|
||||
render() { |
||||
return ( |
||||
<SizedReactLayoutGrid layout={this.buildLayout()} onLayoutChange={this.onLayoutChange} onResize={this.onResize}> |
||||
{this.renderPanels()} |
||||
</SizedReactLayoutGrid> |
||||
); |
||||
} |
||||
} |
||||
|
||||
coreModule.directive('dashboardGrid', function(reactDirective) { |
||||
return reactDirective(DashboardGrid, [['getPanelContainer', {watchDepth: 'reference', wrapApply: false}]]); |
||||
}); |
||||
@ -0,0 +1,40 @@ |
||||
import React from 'react'; |
||||
import {PanelModel} from '../PanelModel'; |
||||
import {PanelContainer} from './PanelContainer'; |
||||
import {AttachedPanel} from './PanelLoader'; |
||||
|
||||
export interface DashboardPanelProps { |
||||
panel: PanelModel; |
||||
getPanelContainer: () => PanelContainer; |
||||
} |
||||
|
||||
export class DashboardPanel extends React.Component<DashboardPanelProps, any> { |
||||
element: any; |
||||
attachedPanel: AttachedPanel; |
||||
|
||||
constructor(props) { |
||||
super(props); |
||||
this.state = {}; |
||||
} |
||||
|
||||
componentDidMount() { |
||||
const panelContainer = this.props.getPanelContainer(); |
||||
const dashboard = panelContainer.getDashboard(); |
||||
const loader = panelContainer.getPanelLoader(); |
||||
|
||||
this.attachedPanel = loader.load(this.element, this.props.panel, dashboard); |
||||
} |
||||
|
||||
componentWillUnmount() { |
||||
if (this.attachedPanel) { |
||||
this.attachedPanel.destroy(); |
||||
} |
||||
} |
||||
|
||||
render() { |
||||
return ( |
||||
<div ref={element => this.element = element} /> |
||||
); |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,34 @@ |
||||
import angular from 'angular'; |
||||
import coreModule from 'app/core/core_module'; |
||||
|
||||
export interface AttachedPanel { |
||||
destroy(); |
||||
} |
||||
|
||||
export class PanelLoader { |
||||
|
||||
/** @ngInject */ |
||||
constructor(private $compile, private $rootScope) { |
||||
} |
||||
|
||||
load(elem, panel, dashboard): AttachedPanel { |
||||
var template = '<plugin-component type="panel"></plugin-component>'; |
||||
var panelScope = this.$rootScope.$new(); |
||||
panelScope.panel = panel; |
||||
panelScope.dashboard = dashboard; |
||||
|
||||
const compiledElem = this.$compile(template)(panelScope); |
||||
const rootNode = angular.element(elem); |
||||
rootNode.append(compiledElem); |
||||
|
||||
return { |
||||
destroy: () => { |
||||
console.log('AttachedPanel:Destroy, id' + panel.id); |
||||
panelScope.$destroy(); |
||||
compiledElem.remove(); |
||||
} |
||||
}; |
||||
} |
||||
} |
||||
|
||||
coreModule.service('panelLoader', PanelLoader); |
||||
@ -1,211 +0,0 @@ |
||||
// ///<reference path="../../../headers/common.d.ts" />
|
||||
//
|
||||
// import coreModule from 'app/core/core_module';
|
||||
// import {CELL_HEIGHT, CELL_VMARGIN} from '../model';
|
||||
//
|
||||
// import 'jquery-ui';
|
||||
// import 'gridstack/dist/jquery.jQueryUI';
|
||||
// import 'gridstack';
|
||||
//
|
||||
// const template = `
|
||||
// <div class="grid-stack">
|
||||
// <dash-grid-item ng-repeat="panel in ctrl.dashboard.panels track by panel.id"
|
||||
// class="grid-stack-item"
|
||||
// grid-ctrl="ctrl"
|
||||
// panel="panel">
|
||||
// <plugin-component type="panel" class="grid-stack-item-content">
|
||||
// </plugin-component>
|
||||
// </dash-grid-item>
|
||||
// </div>
|
||||
// `;
|
||||
//
|
||||
// var rowIndex = 0;
|
||||
//
|
||||
// export class GridCtrl {
|
||||
// options: any;
|
||||
// dashboard: any;
|
||||
// panels: any;
|
||||
// gridstack: any;
|
||||
// gridElem: any;
|
||||
// isInitialized: boolean;
|
||||
// isDestroyed: boolean;
|
||||
// index: number;
|
||||
// changeRenderPromise: any;
|
||||
//
|
||||
// #<{(|* @ngInject |)}>#
|
||||
// constructor(private $scope, private $element, private $timeout) {
|
||||
// console.log(this.dashboard);
|
||||
// this.index = rowIndex;
|
||||
// rowIndex += 1;
|
||||
// }
|
||||
//
|
||||
// init() {
|
||||
// this.gridElem = this.$element.find('.grid-stack');
|
||||
//
|
||||
// this.gridstack = this.gridElem.gridstack({
|
||||
// animate: true,
|
||||
// cellHeight: CELL_HEIGHT,
|
||||
// verticalMargin: CELL_VMARGIN,
|
||||
// acceptWidgets: '.grid-stack-item',
|
||||
// handle: '.grid-drag-handle'
|
||||
// }).data('gridstack');
|
||||
//
|
||||
// this.isInitialized = true;
|
||||
//
|
||||
// this.gridElem.on('added', (e, items) => {
|
||||
// for (let item of items) {
|
||||
// this.onGridStackItemAdded(item);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// this.gridElem.on('removed', (e, items) => {
|
||||
// for (let item of items) {
|
||||
// this.onGridStackItemRemoved(item);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// this.gridElem.on('change', (e, items) => {
|
||||
// this.$timeout(() => this.onGridStackItemsChanged(items), 50);
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// onGridStackItemAdded(item) {
|
||||
// console.log('row: ' + this.index + ' item added', item);
|
||||
// }
|
||||
//
|
||||
// onGridStackItemRemoved(item) {
|
||||
// console.log('row: ' + this.index + ' item removed', item.id, item);
|
||||
// }
|
||||
//
|
||||
// onGridStackItemsChanged(items) {
|
||||
// console.log('onGridStackItemsChanged');
|
||||
//
|
||||
// for (let item of items) {
|
||||
// // find panel
|
||||
// var panel = this.dashboard.getPanelById(parseInt(item.id));
|
||||
//
|
||||
// if (!panel) {
|
||||
// console.log('item change but no panel found for item', item);
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// // update panel model position
|
||||
// panel.x = item.x;
|
||||
// panel.y = item.y;
|
||||
// panel.width = item.width;
|
||||
// panel.height = item.height;
|
||||
//
|
||||
// console.log('updating panel: ' + panel.id + ' x: ' + panel.x + ' y: ' + panel.y);
|
||||
// }
|
||||
//
|
||||
// this.dashboard.panels.sort(function (a, b) {
|
||||
// let aScore = a.x + (a.y * 12);
|
||||
// let bScore = b.x + (b.y * 12);
|
||||
// if (aScore < bScore) { return -1; }
|
||||
// if (aScore > bScore) { return 1; }
|
||||
// return 0;
|
||||
// });
|
||||
//
|
||||
// if (this.changeRenderPromise) {
|
||||
// this.$timeout.cancel(this.changeRenderPromise);
|
||||
// }
|
||||
//
|
||||
// this.changeRenderPromise = this.$timeout(() => {
|
||||
// console.log('broadcasting render');
|
||||
// this.$scope.$broadcast('render');
|
||||
// });
|
||||
// }
|
||||
//
|
||||
// destroy() {
|
||||
// this.gridstack.destroy();
|
||||
// this.gridstack = null;
|
||||
// this.isDestroyed = true;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #<{(|* @ngInject *|)}>#
|
||||
// export function dashGrid($timeout) {
|
||||
// return {
|
||||
// restrict: 'E',
|
||||
// template: template,
|
||||
// controller: GridCtrl,
|
||||
// bindToController: true,
|
||||
// controllerAs: 'ctrl',
|
||||
// scope: {
|
||||
// dashboard: "=",
|
||||
// },
|
||||
// link: function(scope, elem, attrs, ctrl) {
|
||||
// $timeout(function() {
|
||||
// ctrl.init();
|
||||
// });
|
||||
//
|
||||
// scope.$on('$destroy', () => {
|
||||
// ctrl.destroy();
|
||||
// });
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// #<{(|* @ngInject *|)}>#
|
||||
// export function dashGridItem($timeout, $rootScope) {
|
||||
// return {
|
||||
// restrict: "E",
|
||||
// scope: {
|
||||
// panel: '=',
|
||||
// gridCtrl: '='
|
||||
// },
|
||||
// link: function (scope, element, attrs) {
|
||||
// let gridCtrl = scope.gridCtrl;
|
||||
// let panel = scope.panel;
|
||||
// let gridStackNode = null;
|
||||
//
|
||||
// element.attr({
|
||||
// 'data-gs-id': panel.id,
|
||||
// 'data-gs-x': panel.x,
|
||||
// 'data-gs-y': panel.y,
|
||||
// 'data-gs-width': panel.width,
|
||||
// 'data-gs-height': panel.height,
|
||||
// 'data-gs-no-resize': panel.type === 'row',
|
||||
// });
|
||||
//
|
||||
// $rootScope.onAppEvent('panel-fullscreen-exit', (evt, payload) => {
|
||||
// if (panel.id !== payload.panelId) {
|
||||
// return;
|
||||
// }
|
||||
// gridCtrl.gridstack.locked(element, false);
|
||||
// element.removeClass('panel-fullscreen');
|
||||
// }, scope);
|
||||
//
|
||||
// $rootScope.onAppEvent('panel-fullscreen-enter', (evt, payload) => {
|
||||
// if (panel.id !== payload.panelId) {
|
||||
// return;
|
||||
// }
|
||||
// element.addClass('panel-fullscreen');
|
||||
// }, scope);
|
||||
//
|
||||
// scope.$on('$destroy', () => {
|
||||
// console.log('grid-item scope $destroy');
|
||||
// if (gridCtrl.isDestroyed) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (gridStackNode) {
|
||||
// console.log('grid-item scope $destroy removeWidget');
|
||||
// gridStackNode._grid.removeWidget(element);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// if (gridCtrl.isInitialized) {
|
||||
// gridCtrl.gridstack.makeWidget(element);
|
||||
// gridStackNode = element.data('_gridstack_node');
|
||||
// } else {
|
||||
// setTimeout(function() {
|
||||
// gridStackNode = element.data('_gridstack_node');
|
||||
// }, 500);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// coreModule.directive('dashGrid', dashGrid);
|
||||
// coreModule.directive('dashGridItem', dashGridItem);
|
||||
@ -1,232 +0,0 @@ |
||||
Skip to content |
||||
This repository |
||||
Search |
||||
Pull requests |
||||
Issues |
||||
Marketplace |
||||
Gist |
||||
@torkelo |
||||
Sign out |
||||
Unwatch 946 |
||||
Unstar 17,021 |
||||
Fork 2,862 grafana/grafana |
||||
Code Issues 1,079 Pull requests 46 Projects 1 Wiki Settings Insights |
||||
Branch: gridstack Find file Copy pathgrafana/public/app/core/components/dashgrid/dashgrid.ts |
||||
a6bbcb8 on Jun 13 |
||||
@torkelo torkelo ux: gridstack poc |
||||
1 contributor |
||||
RawBlameHistory |
||||
213 lines (181 sloc) 5.45 KB |
||||
///<reference path="../../../headers/common.d.ts" /> |
||||
|
||||
import $ from 'jquery'; |
||||
import coreModule from '../../core_module'; |
||||
|
||||
import 'jquery-ui'; |
||||
import 'gridstack'; |
||||
import 'gridstack.jquery-ui'; |
||||
|
||||
const template = ` |
||||
<div gridstack gridstack-handler="ctrl.gridstack" class="grid-stack" |
||||
options="ctrl.options" |
||||
on-change="ctrl.onChange(event,items)" |
||||
on-drag-start="ctrl.onDragStart(event,ui)" |
||||
on-drag-stop="ctrl.onDragStop(event, ui)" |
||||
on-resize-start="ctrl.onResizeStart(event, ui)" |
||||
on-resize-stop="ctrl.onResizeStop(event, ui)"> |
||||
<div gridstack-item ng-repeat="panel in ctrl.panels" |
||||
class="grid-stack-item" |
||||
gs-item-id="panel.id" |
||||
gs-item-x="panel.x" |
||||
gs-item-y="panel.y" |
||||
gs-item-width="panel.width" |
||||
gs-item-height="panel.height" |
||||
gs-item-autopos="1" |
||||
on-item-added="ctrl.onItemAdded(item)" |
||||
on-item-removed="ctrl.onItemRemoved(item)"> |
||||
<plugin-component type="panel" class="panel-margin grid-stack-item-content"> |
||||
</plugin-component> |
||||
</div> |
||||
</div> |
||||
`; |
||||
|
||||
export class DashGridCtrl { |
||||
options: any; |
||||
|
||||
/** @ngInject */ |
||||
constructor(private $rootScope) { |
||||
this.options = { |
||||
animate: true, |
||||
}; |
||||
} |
||||
|
||||
onResizeStop() { |
||||
this.$rootScope.$broadcast('render'); |
||||
} |
||||
} |
||||
|
||||
export function dashGrid($timeout) { |
||||
return { |
||||
restrict: 'E', |
||||
template: template, |
||||
controller: DashGridCtrl, |
||||
bindToController: true, |
||||
controllerAs: 'ctrl', |
||||
scope: { |
||||
dashboard: "=" |
||||
}, |
||||
link: function(scope, elem, attrs, ctrl) { |
||||
|
||||
ctrl.panels = []; |
||||
ctrl.dashboard.forEachPanel((panel, panelIndex, row, rowIndex) => { |
||||
panel.width = 4; |
||||
panel.height = 4; |
||||
panel.x = panelIndex * 4; |
||||
panel.y = rowIndex * 4; |
||||
ctrl.panels.push(panel); |
||||
}); |
||||
|
||||
} |
||||
}; |
||||
} |
||||
|
||||
/** @ngInject */ |
||||
coreModule.controller('GridstackController', ['$scope', function($scope) { |
||||
|
||||
var gridstack = null; |
||||
|
||||
this.init = function(element, options) { |
||||
gridstack = element.gridstack(options).data('gridstack'); |
||||
return gridstack; |
||||
}; |
||||
|
||||
this.removeItem = function(element) { |
||||
if (gridstack) { |
||||
return gridstack.removeWidget(element, false); |
||||
} |
||||
return null; |
||||
}; |
||||
|
||||
this.addItem = function(element) { |
||||
if (gridstack) { |
||||
gridstack.makeWidget(element); |
||||
return element; |
||||
} |
||||
return null; |
||||
}; |
||||
|
||||
}]); |
||||
|
||||
/** @ngInject */ |
||||
coreModule.directive('gridstack', ['$timeout', function($timeout) { |
||||
return { |
||||
restrict: "A", |
||||
controller: 'GridstackController', |
||||
scope: { |
||||
onChange: '&', |
||||
onDragStart: '&', |
||||
onDragStop: '&', |
||||
onResizeStart: '&', |
||||
onResizeStop: '&', |
||||
gridstackHandler: '=', |
||||
options: '=' |
||||
}, |
||||
link: function (scope, element, attrs, controller, ngModel) { |
||||
|
||||
var gridstack = controller.init(element, scope.options); |
||||
scope.gridstackHandler = gridstack; |
||||
|
||||
element.on('change', function (e, items) { |
||||
$timeout(function() { |
||||
scope.$apply(); |
||||
scope.onChange({event: e, items: items}); |
||||
}); |
||||
}); |
||||
|
||||
element.on('dragstart', function(e, ui) { |
||||
scope.onDragStart({event: e, ui: ui}); |
||||
}); |
||||
|
||||
element.on('dragstop', function(e, ui) { |
||||
$timeout(function() { |
||||
scope.$apply(); |
||||
scope.onDragStop({event: e, ui: ui}); |
||||
}); |
||||
}); |
||||
|
||||
element.on('resizestart', function(e, ui) { |
||||
scope.onResizeStart({event: e, ui: ui}); |
||||
}); |
||||
|
||||
element.on('resizestop', function(e, ui) { |
||||
$timeout(function() { |
||||
scope.$apply(); |
||||
scope.onResizeStop({event: e, ui: ui}); |
||||
}); |
||||
}); |
||||
|
||||
} |
||||
}; |
||||
}]); |
||||
|
||||
/** @ngInject */ |
||||
coreModule.directive('gridstackItem', ['$timeout', function($timeout) { |
||||
|
||||
return { |
||||
restrict: "A", |
||||
controller: 'GridstackController', |
||||
require: '^gridstack', |
||||
scope: { |
||||
gridstackItem: '=', |
||||
onItemAdded: '&', |
||||
onItemRemoved: '&', |
||||
gsItemId: '=', |
||||
gsItemX: '=', |
||||
gsItemY: '=', |
||||
gsItemWidth: '=', |
||||
gsItemHeight: '=', |
||||
gsItemAutopos: '=' |
||||
}, |
||||
link: function (scope, element, attrs, controller) { |
||||
$(element).attr('data-gs-id', scope.gsItemId); |
||||
$(element).attr('data-gs-x', scope.gsItemX); |
||||
$(element).attr('data-gs-y', scope.gsItemY); |
||||
$(element).attr('data-gs-width', scope.gsItemWidth); |
||||
$(element).attr('data-gs-height', scope.gsItemHeight); |
||||
$(element).attr('data-gs-auto-position', scope.gsItemAutopos); |
||||
var widget = controller.addItem(element); |
||||
var item = element.data('_gridstack_node'); |
||||
$timeout(function() { |
||||
scope.onItemAdded({item: item}); |
||||
}); |
||||
scope.$watch(function () { return $(element).attr('data-gs-id'); }, function (val) { |
||||
scope.gsItemId = val; |
||||
}); |
||||
scope.$watch(function(){ return $(element).attr('data-gs-x'); }, function(val) { |
||||
scope.gsItemX = val; |
||||
}); |
||||
|
||||
scope.$watch(function(){ return $(element).attr('data-gs-y'); }, function(val) { |
||||
scope.gsItemY = val; |
||||
}); |
||||
|
||||
scope.$watch(function(){ return $(element).attr('data-gs-width'); }, function(val) { |
||||
scope.gsItemWidth = val; |
||||
}); |
||||
|
||||
scope.$watch(function(){ return $(element).attr('data-gs-height'); }, function(val) { |
||||
scope.gsItemHeight = val; |
||||
}); |
||||
|
||||
element.bind('$destroy', function() { |
||||
var item = element.data('_gridstack_node'); |
||||
scope.onItemRemoved({item: item}); |
||||
controller.removeItem(element); |
||||
}); |
||||
} |
||||
}; |
||||
}]); |
||||
|
||||
coreModule.directive('dashGrid', dashGrid); |
||||
Contact GitHub API Training Shop Blog About |
||||
© 2017 GitHub, Inc. Terms Privacy Security Status Help |
||||
@ -1,95 +0,0 @@ |
||||
define([ |
||||
'angular', |
||||
'lodash', |
||||
'app/core/utils/kbn' |
||||
], |
||||
function (angular, _, kbn) { |
||||
'use strict'; |
||||
|
||||
var module = angular.module('grafana.controllers'); |
||||
|
||||
module.controller('GraphiteImportCtrl', function($scope, datasourceSrv, dashboardSrv, $location) { |
||||
$scope.options = {}; |
||||
|
||||
$scope.init = function() { |
||||
$scope.datasources = []; |
||||
_.each(datasourceSrv.getAll(), function(ds) { |
||||
if (ds.type === 'graphite') { |
||||
$scope.options.sourceName = ds.name; |
||||
$scope.datasources.push(ds.name); |
||||
} |
||||
}); |
||||
}; |
||||
|
||||
$scope.listAll = function() { |
||||
datasourceSrv.get($scope.options.sourceName).then(function(datasource) { |
||||
$scope.datasource = datasource; |
||||
$scope.datasource.listDashboards('').then(function(results) { |
||||
$scope.dashboards = results; |
||||
}, function(err) { |
||||
var message = err.message || err.statusText || 'Error'; |
||||
$scope.appEvent('alert-error', ['Failed to load dashboard list from graphite', message]); |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
$scope.import = function(dashName) { |
||||
$scope.datasource.loadDashboard(dashName).then(function(results) { |
||||
if (!results.data || !results.data.state) { |
||||
throw { message: 'no dashboard state received from graphite' }; |
||||
} |
||||
|
||||
graphiteToGrafanaTranslator(results.data.state, $scope.datasource.name); |
||||
}, function(err) { |
||||
var message = err.message || err.statusText || 'Error'; |
||||
$scope.appEvent('alert-error', ['Failed to load dashboard from graphite', message]); |
||||
}); |
||||
}; |
||||
|
||||
function graphiteToGrafanaTranslator(state, datasource) { |
||||
var graphsPerRow = 2; |
||||
var rowHeight = 300; |
||||
var rowTemplate; |
||||
var currentRow; |
||||
var panel; |
||||
|
||||
rowTemplate = { |
||||
title: '', |
||||
panels: [], |
||||
height: rowHeight |
||||
}; |
||||
|
||||
currentRow = angular.copy(rowTemplate); |
||||
|
||||
var newDashboard = dashboardSrv.create({}); |
||||
newDashboard.rows = []; |
||||
newDashboard.title = state.name; |
||||
newDashboard.rows.push(currentRow); |
||||
|
||||
_.each(state.graphs, function(graph, index) { |
||||
if (currentRow.panels.length === graphsPerRow) { |
||||
currentRow = angular.copy(rowTemplate); |
||||
newDashboard.rows.push(currentRow); |
||||
} |
||||
|
||||
panel = { |
||||
type: 'graph', |
||||
span: 12 / graphsPerRow, |
||||
title: graph[1].title, |
||||
targets: [], |
||||
datasource: datasource, |
||||
id: index + 1 |
||||
}; |
||||
|
||||
_.each(graph[1].target, function(target) { |
||||
panel.targets.push({ target: target }); |
||||
}); |
||||
|
||||
currentRow.panels.push(panel); |
||||
}); |
||||
|
||||
window.grafanaImportDashboard = newDashboard; |
||||
$location.path('/dashboard-import/' + kbn.slugifyForUrl(newDashboard.title)); |
||||
} |
||||
}); |
||||
}); |
||||
@ -0,0 +1,24 @@ |
||||
@import "~react-grid-layout/css/styles.css"; |
||||
@import "~react-resizable/css/styles.css"; |
||||
|
||||
.panel-in-fullscreen { |
||||
|
||||
.react-grid-layout { |
||||
height: 100% !important; |
||||
} |
||||
|
||||
.react-grid-item { |
||||
display: none; |
||||
transition-property: none !important; |
||||
} |
||||
|
||||
.panel--fullscreen { |
||||
display: block !important; |
||||
position: unset !important; |
||||
width: 100% !important; |
||||
height: 100% !important; |
||||
transform: translate(0px, 0px) !important; |
||||
} |
||||
} |
||||
|
||||
|
||||
@ -1,325 +0,0 @@ |
||||
.grid-stack-item > .ui-resizable-handle { |
||||
filter: none; |
||||
} |
||||
|
||||
.grid-stack { |
||||
position: relative; |
||||
min-height: 150px; |
||||
} |
||||
|
||||
.grid-stack.grid-stack-rtl { |
||||
direction: ltr; |
||||
} |
||||
|
||||
.grid-stack.grid-stack-rtl > .grid-stack-item { |
||||
direction: rtl; |
||||
} |
||||
|
||||
.grid-stack .grid-stack-placeholder > .placeholder-content { |
||||
background: $input-label-bg; |
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 5px rgba(82,168,236,10.8); |
||||
margin: 0; |
||||
position: absolute; |
||||
top: 0; |
||||
left: 5px; |
||||
right: 5px; |
||||
bottom: 0; |
||||
width: auto; |
||||
text-align: center; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item { |
||||
min-width: 8.3333333333%; |
||||
position: absolute; |
||||
padding: 0; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item > .grid-stack-item-content { |
||||
margin: 0; |
||||
position: absolute; |
||||
top: 0; |
||||
left: 7px; |
||||
right: 7px; |
||||
bottom: 0; |
||||
width: auto; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item > .ui-resizable-handle { |
||||
position: absolute; |
||||
display: block; |
||||
-ms-touch-action: none; |
||||
touch-action: none; |
||||
font-size: 10px; |
||||
color: $text-color-weak; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item.ui-resizable-disabled > .ui-resizable-handle, |
||||
.grid-stack > .grid-stack-item.ui-resizable-autohide > .ui-resizable-handle { |
||||
display: none; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item.ui-draggable-dragging, .grid-stack > .grid-stack-item.ui-resizable-resizing { |
||||
z-index: 100; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item.ui-draggable-dragging > .grid-stack-item-content, |
||||
.grid-stack > .grid-stack-item.ui-draggable-dragging > .grid-stack-item-content, .grid-stack > .grid-stack-item.ui-resizable-resizing > .grid-stack-item-content, |
||||
.grid-stack > .grid-stack-item.ui-resizable-resizing > .grid-stack-item-content { |
||||
box-shadow: 1px 4px 6px rgba(0, 0, 0, 0.2); |
||||
opacity: 0.8; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item > .ui-resizable-se, |
||||
.grid-stack > .grid-stack-item > .ui-resizable-sw { |
||||
font-family: 'grafana-icons' !important; |
||||
speak: none; |
||||
font-style: normal; |
||||
font-weight: normal; |
||||
font-variant: normal; |
||||
text-transform: none; |
||||
line-height: 1; |
||||
-webkit-font-smoothing: antialiased; |
||||
-moz-osx-font-smoothing: grayscale; |
||||
&::before { |
||||
content: "\e90b"; |
||||
} |
||||
} |
||||
.grid-stack > .grid-stack-item > .ui-resizable-se { |
||||
cursor: se-resize; |
||||
width: 16px; |
||||
height: 16px; |
||||
right: 6px; |
||||
bottom: -2px; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item.ui-draggable-dragging > .ui-resizable-handle { |
||||
display: none !important; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-width='1'] { |
||||
width: 8.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-x='1'] { |
||||
left: 8.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-min-width='1'] { |
||||
min-width: 8.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-max-width='1'] { |
||||
max-width: 8.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-width='2'] { |
||||
width: 16.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-x='2'] { |
||||
left: 16.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-min-width='2'] { |
||||
min-width: 16.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-max-width='2'] { |
||||
max-width: 16.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-width='3'] { |
||||
width: 25%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-x='3'] { |
||||
left: 25%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-min-width='3'] { |
||||
min-width: 25%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-max-width='3'] { |
||||
max-width: 25%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-width='4'] { |
||||
width: 33.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-x='4'] { |
||||
left: 33.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-min-width='4'] { |
||||
min-width: 33.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-max-width='4'] { |
||||
max-width: 33.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-width='5'] { |
||||
width: 41.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-x='5'] { |
||||
left: 41.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-min-width='5'] { |
||||
min-width: 41.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-max-width='5'] { |
||||
max-width: 41.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-width='6'] { |
||||
width: 50%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-x='6'] { |
||||
left: 50%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-min-width='6'] { |
||||
min-width: 50%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-max-width='6'] { |
||||
max-width: 50%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-width='7'] { |
||||
width: 58.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-x='7'] { |
||||
left: 58.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-min-width='7'] { |
||||
min-width: 58.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-max-width='7'] { |
||||
max-width: 58.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-width='8'] { |
||||
width: 66.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-x='8'] { |
||||
left: 66.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-min-width='8'] { |
||||
min-width: 66.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-max-width='8'] { |
||||
max-width: 66.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-width='9'] { |
||||
width: 75%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-x='9'] { |
||||
left: 75%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-min-width='9'] { |
||||
min-width: 75%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-max-width='9'] { |
||||
max-width: 75%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-width='10'] { |
||||
width: 83.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-x='10'] { |
||||
left: 83.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-min-width='10'] { |
||||
min-width: 83.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-max-width='10'] { |
||||
max-width: 83.3333333333%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-width='11'] { |
||||
width: 91.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-x='11'] { |
||||
left: 91.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-min-width='11'] { |
||||
min-width: 91.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-max-width='11'] { |
||||
max-width: 91.6666666667%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-width='12'] { |
||||
width: 100%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-x='12'] { |
||||
left: 100%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-min-width='12'] { |
||||
min-width: 100%; |
||||
} |
||||
|
||||
.grid-stack > .grid-stack-item[data-gs-max-width='12'] { |
||||
max-width: 100%; |
||||
} |
||||
|
||||
.grid-stack.grid-stack-animate, |
||||
.grid-stack.grid-stack-animate .grid-stack-item { |
||||
-webkit-transition: left 0.3s, top 0.3s, height 0.3s, width 0.3s; |
||||
-moz-transition: left 0.3s, top 0.3s, height 0.3s, width 0.3s; |
||||
-ms-transition: left 0.3s, top 0.3s, height 0.3s, width 0.3s; |
||||
-o-transition: left 0.3s, top 0.3s, height 0.3s, width 0.3s; |
||||
transition: left 0.3s, top 0.3s, height 0.3s, width 0.3s; |
||||
} |
||||
|
||||
.grid-stack.grid-stack-animate .grid-stack-item.ui-draggable-dragging, |
||||
.grid-stack.grid-stack-animate .grid-stack-item.ui-resizable-resizing, |
||||
.grid-stack.grid-stack-animate .grid-stack-item.grid-stack-placeholder { |
||||
-webkit-transition: left 0s, top 0s, height 0s, width 0s; |
||||
-moz-transition: left 0s, top 0s, height 0s, width 0s; |
||||
-ms-transition: left 0s, top 0s, height 0s, width 0s; |
||||
-o-transition: left 0s, top 0s, height 0s, width 0s; |
||||
transition: left 0s, top 0s, height 0s, width 0s; |
||||
} |
||||
|
||||
.grid-stack.grid-stack-one-column-mode { |
||||
height: auto !important; |
||||
} |
||||
|
||||
.grid-stack.grid-stack-one-column-mode > .grid-stack-item { |
||||
position: relative !important; |
||||
width: auto !important; |
||||
left: 0 !important; |
||||
top: auto !important; |
||||
margin-bottom: 20px; |
||||
max-width: none !important; |
||||
} |
||||
|
||||
.grid-stack.grid-stack-one-column-mode > .grid-stack-item > .ui-resizable-handle { |
||||
display: none; |
||||
} |
||||
@ -1,4 +0,0 @@ |
||||
declare let helpers: any; |
||||
export default helpers; |
||||
|
||||
|
||||
@ -1,180 +0,0 @@ |
||||
define([ |
||||
'lodash', |
||||
'app/core/config', |
||||
'app/core/utils/datemath', |
||||
], function(_, config, dateMath) { |
||||
'use strict'; |
||||
|
||||
function ControllerTestContext() { |
||||
var self = this; |
||||
|
||||
this.datasource = {}; |
||||
this.$element = {}; |
||||
this.annotationsSrv = {}; |
||||
this.timeSrv = new TimeSrvStub(); |
||||
this.templateSrv = new TemplateSrvStub(); |
||||
this.datasourceSrv = { |
||||
getMetricSources: function() {}, |
||||
get: function() { |
||||
return { |
||||
then: function(callback) { |
||||
callback(self.datasource); |
||||
} |
||||
}; |
||||
} |
||||
}; |
||||
|
||||
this.providePhase = function(mocks) { |
||||
return window.module(function($provide) { |
||||
$provide.value('datasourceSrv', self.datasourceSrv); |
||||
$provide.value('annotationsSrv', self.annotationsSrv); |
||||
$provide.value('timeSrv', self.timeSrv); |
||||
$provide.value('templateSrv', self.templateSrv); |
||||
$provide.value('$element', self.$element); |
||||
_.each(mocks, function(value, key) { |
||||
$provide.value(key, value); |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
this.createPanelController = function(Ctrl) { |
||||
return window.inject(function($controller, $rootScope, $q, $location, $browser) { |
||||
self.scope = $rootScope.$new(); |
||||
self.$location = $location; |
||||
self.$browser = $browser; |
||||
self.$q = $q; |
||||
self.panel = {type: 'test'}; |
||||
self.dashboard = {meta: {}}; |
||||
|
||||
$rootScope.appEvent = sinon.spy(); |
||||
$rootScope.onAppEvent = sinon.spy(); |
||||
$rootScope.colors = []; |
||||
|
||||
for (var i = 0; i < 50; i++) { $rootScope.colors.push('#' + i); } |
||||
|
||||
config.panels['test'] = {info: {}}; |
||||
self.ctrl = $controller(Ctrl, {$scope: self.scope}, { |
||||
panel: self.panel, dashboard: self.dashboard, row: {} |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
this.createControllerPhase = function(controllerName) { |
||||
return window.inject(function($controller, $rootScope, $q, $location, $browser) { |
||||
self.scope = $rootScope.$new(); |
||||
self.$location = $location; |
||||
self.$browser = $browser; |
||||
self.scope.contextSrv = {}; |
||||
self.scope.panel = {}; |
||||
self.scope.row = { panels:[] }; |
||||
self.scope.dashboard = {meta: {}}; |
||||
self.scope.dashboardMeta = {}; |
||||
self.scope.dashboardViewState = new DashboardViewStateStub(); |
||||
self.scope.appEvent = sinon.spy(); |
||||
self.scope.onAppEvent = sinon.spy(); |
||||
|
||||
$rootScope.colors = []; |
||||
for (var i = 0; i < 50; i++) { $rootScope.colors.push('#' + i); } |
||||
|
||||
self.$q = $q; |
||||
self.scope.skipDataOnInit = true; |
||||
self.scope.skipAutoInit = true; |
||||
self.controller = $controller(controllerName, { |
||||
$scope: self.scope |
||||
}); |
||||
}); |
||||
}; |
||||
} |
||||
|
||||
function ServiceTestContext() { |
||||
var self = this; |
||||
self.templateSrv = new TemplateSrvStub(); |
||||
self.timeSrv = new TimeSrvStub(); |
||||
self.datasourceSrv = {}; |
||||
self.backendSrv = {}; |
||||
self.$routeParams = {}; |
||||
|
||||
this.providePhase = function(mocks) { |
||||
return window.module(function($provide) { |
||||
_.each(mocks, function(key) { |
||||
$provide.value(key, self[key]); |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
this.createService = function(name) { |
||||
return window.inject(function($q, $rootScope, $httpBackend, $injector, $location, $timeout) { |
||||
self.$q = $q; |
||||
self.$rootScope = $rootScope; |
||||
self.$httpBackend = $httpBackend; |
||||
self.$location = $location; |
||||
|
||||
self.$rootScope.onAppEvent = function() {}; |
||||
self.$rootScope.appEvent = function() {}; |
||||
self.$timeout = $timeout; |
||||
|
||||
self.service = $injector.get(name); |
||||
}); |
||||
}; |
||||
} |
||||
|
||||
function DashboardViewStateStub() { |
||||
this.registerPanel = function() { |
||||
}; |
||||
} |
||||
|
||||
function TimeSrvStub() { |
||||
this.init = sinon.spy(); |
||||
this.time = { from:'now-1h', to: 'now'}; |
||||
this.timeRange = function(parse) { |
||||
if (parse === false) { |
||||
return this.time; |
||||
} |
||||
return { |
||||
from : dateMath.parse(this.time.from, false), |
||||
to : dateMath.parse(this.time.to, true) |
||||
}; |
||||
}; |
||||
|
||||
this.replace = function(target) { |
||||
return target; |
||||
}; |
||||
|
||||
this.setTime = function(time) { |
||||
this.time = time; |
||||
}; |
||||
} |
||||
|
||||
function ContextSrvStub() { |
||||
this.hasRole = function() { |
||||
return true; |
||||
}; |
||||
} |
||||
|
||||
function TemplateSrvStub() { |
||||
this.variables = []; |
||||
this.templateSettings = { interpolate : /\[\[([\s\S]+?)\]\]/g }; |
||||
this.data = {}; |
||||
this.replace = function(text) { |
||||
return _.template(text, this.templateSettings)(this.data); |
||||
}; |
||||
this.init = function() {}; |
||||
this.getAdhocFilters = function() { return []; }; |
||||
this.fillVariableValuesForUrl = function() {}; |
||||
this.updateTemplateData = function() { }; |
||||
this.variableExists = function() { return false; }; |
||||
this.variableInitialized = function() { }; |
||||
this.highlightVariablesAsHtml = function(str) { return str; }; |
||||
this.setGrafanaVariable = function(name, value) { |
||||
this.data[name] = value; |
||||
}; |
||||
} |
||||
|
||||
return { |
||||
ControllerTestContext: ControllerTestContext, |
||||
TimeSrvStub: TimeSrvStub, |
||||
ContextSrvStub: ContextSrvStub, |
||||
ServiceTestContext: ServiceTestContext |
||||
}; |
||||
|
||||
}); |
||||
@ -0,0 +1,195 @@ |
||||
import _ from 'lodash'; |
||||
import config from 'app/core/config'; |
||||
import * as dateMath from 'app/core/utils/datemath'; |
||||
import {angularMocks, sinon} from '../lib/common'; |
||||
import {PanelModel} from 'app/features/dashboard/PanelModel'; |
||||
|
||||
export function ControllerTestContext() { |
||||
var self = this; |
||||
|
||||
this.datasource = {}; |
||||
this.$element = {}; |
||||
this.annotationsSrv = {}; |
||||
this.timeSrv = new TimeSrvStub(); |
||||
this.templateSrv = new TemplateSrvStub(); |
||||
this.datasourceSrv = { |
||||
getMetricSources: function() {}, |
||||
get: function() { |
||||
return { |
||||
then: function(callback) { |
||||
callback(self.datasource); |
||||
}, |
||||
}; |
||||
}, |
||||
}; |
||||
|
||||
this.providePhase = function(mocks) { |
||||
return angularMocks.module(function($provide) { |
||||
$provide.value('datasourceSrv', self.datasourceSrv); |
||||
$provide.value('annotationsSrv', self.annotationsSrv); |
||||
$provide.value('timeSrv', self.timeSrv); |
||||
$provide.value('templateSrv', self.templateSrv); |
||||
$provide.value('$element', self.$element); |
||||
_.each(mocks, function(value, key) { |
||||
$provide.value(key, value); |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
this.createPanelController = function(Ctrl) { |
||||
return angularMocks.inject(function($controller, $rootScope, $q, $location, $browser) { |
||||
self.scope = $rootScope.$new(); |
||||
self.$location = $location; |
||||
self.$browser = $browser; |
||||
self.$q = $q; |
||||
self.panel = new PanelModel({type: 'test'}); |
||||
self.dashboard = {meta: {}}; |
||||
|
||||
$rootScope.appEvent = sinon.spy(); |
||||
$rootScope.onAppEvent = sinon.spy(); |
||||
$rootScope.colors = []; |
||||
|
||||
for (var i = 0; i < 50; i++) { |
||||
$rootScope.colors.push('#' + i); |
||||
} |
||||
|
||||
config.panels['test'] = {info: {}}; |
||||
self.ctrl = $controller( |
||||
Ctrl, |
||||
{$scope: self.scope}, |
||||
{ |
||||
panel: self.panel, |
||||
dashboard: self.dashboard, |
||||
}, |
||||
); |
||||
}); |
||||
}; |
||||
|
||||
this.createControllerPhase = function(controllerName) { |
||||
return angularMocks.inject(function($controller, $rootScope, $q, $location, $browser) { |
||||
self.scope = $rootScope.$new(); |
||||
self.$location = $location; |
||||
self.$browser = $browser; |
||||
self.scope.contextSrv = {}; |
||||
self.scope.panel = {}; |
||||
self.scope.dashboard = {meta: {}}; |
||||
self.scope.dashboardMeta = {}; |
||||
self.scope.dashboardViewState = new DashboardViewStateStub(); |
||||
self.scope.appEvent = sinon.spy(); |
||||
self.scope.onAppEvent = sinon.spy(); |
||||
|
||||
$rootScope.colors = []; |
||||
for (var i = 0; i < 50; i++) { |
||||
$rootScope.colors.push('#' + i); |
||||
} |
||||
|
||||
self.$q = $q; |
||||
self.scope.skipDataOnInit = true; |
||||
self.scope.skipAutoInit = true; |
||||
self.controller = $controller(controllerName, { |
||||
$scope: self.scope, |
||||
}); |
||||
}); |
||||
}; |
||||
} |
||||
|
||||
export function ServiceTestContext() { |
||||
var self = this; |
||||
self.templateSrv = new TemplateSrvStub(); |
||||
self.timeSrv = new TimeSrvStub(); |
||||
self.datasourceSrv = {}; |
||||
self.backendSrv = {}; |
||||
self.$routeParams = {}; |
||||
|
||||
this.providePhase = function(mocks) { |
||||
return angularMocks.module(function($provide) { |
||||
_.each(mocks, function(key) { |
||||
$provide.value(key, self[key]); |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
this.createService = function(name) { |
||||
return angularMocks.inject(function($q, $rootScope, $httpBackend, $injector, $location, $timeout) { |
||||
self.$q = $q; |
||||
self.$rootScope = $rootScope; |
||||
self.$httpBackend = $httpBackend; |
||||
self.$location = $location; |
||||
|
||||
self.$rootScope.onAppEvent = function() {}; |
||||
self.$rootScope.appEvent = function() {}; |
||||
self.$timeout = $timeout; |
||||
|
||||
self.service = $injector.get(name); |
||||
}); |
||||
}; |
||||
} |
||||
|
||||
export function DashboardViewStateStub() { |
||||
this.registerPanel = function() {}; |
||||
} |
||||
|
||||
export function TimeSrvStub() { |
||||
this.init = sinon.spy(); |
||||
this.time = {from: 'now-1h', to: 'now'}; |
||||
this.timeRange = function(parse) { |
||||
if (parse === false) { |
||||
return this.time; |
||||
} |
||||
return { |
||||
from: dateMath.parse(this.time.from, false), |
||||
to: dateMath.parse(this.time.to, true), |
||||
}; |
||||
}; |
||||
|
||||
this.replace = function(target) { |
||||
return target; |
||||
}; |
||||
|
||||
this.setTime = function(time) { |
||||
this.time = time; |
||||
}; |
||||
} |
||||
|
||||
export function ContextSrvStub() { |
||||
this.hasRole = function() { |
||||
return true; |
||||
}; |
||||
} |
||||
|
||||
export function TemplateSrvStub() { |
||||
this.variables = []; |
||||
this.templateSettings = {interpolate: /\[\[([\s\S]+?)\]\]/g}; |
||||
this.data = {}; |
||||
this.replace = function(text) { |
||||
return _.template(text, this.templateSettings)(this.data); |
||||
}; |
||||
this.init = function() {}; |
||||
this.getAdhocFilters = function() { |
||||
return []; |
||||
}; |
||||
this.fillVariableValuesForUrl = function() {}; |
||||
this.updateTemplateData = function() {}; |
||||
this.variableExists = function() { |
||||
return false; |
||||
}; |
||||
this.variableInitialized = function() {}; |
||||
this.highlightVariablesAsHtml = function(str) { |
||||
return str; |
||||
}; |
||||
this.setGrafanaVariable = function(name, value) { |
||||
this.data[name] = value; |
||||
}; |
||||
} |
||||
|
||||
var allDeps = { |
||||
ContextSrvStub: ContextSrvStub, |
||||
TemplateSrvStub: TemplateSrvStub, |
||||
TimeSrvStub: TimeSrvStub, |
||||
ControllerTestContext: ControllerTestContext, |
||||
ServiceTestContext: ServiceTestContext, |
||||
DashboardViewStateStub: DashboardViewStateStub |
||||
}; |
||||
|
||||
// for legacy
|
||||
export default allDeps; |
||||
@ -1,130 +0,0 @@ |
||||
(function() { |
||||
"use strict"; |
||||
|
||||
// Tun on full stack traces in errors to help debugging
|
||||
Error.stackTraceLimit=Infinity; |
||||
|
||||
window.__karma__.loaded = function() {}; |
||||
|
||||
System.config({ |
||||
baseURL: '/base/', |
||||
defaultJSExtensions: true, |
||||
paths: { |
||||
'mousetrap': 'vendor/npm/mousetrap/mousetrap.js', |
||||
'eventemitter3': 'vendor/npm/eventemitter3/index.js', |
||||
'remarkable': 'vendor/npm/remarkable/dist/remarkable.js', |
||||
'tether': 'vendor/npm/tether/dist/js/tether.js', |
||||
'tether-drop': 'vendor/npm/tether-drop/dist/js/drop.js', |
||||
'moment': 'vendor/moment.js', |
||||
"jquery": "vendor/jquery/dist/jquery.js", |
||||
'lodash-src': 'vendor/lodash/dist/lodash.js', |
||||
"lodash": 'app/core/lodash_extended.js', |
||||
"angular": 'vendor/angular/angular.js', |
||||
'angular-mocks': 'vendor/angular-mocks/angular-mocks.js', |
||||
"bootstrap": "vendor/bootstrap/bootstrap.js", |
||||
'angular-route': 'vendor/angular-route/angular-route.js', |
||||
'angular-sanitize': 'vendor/angular-sanitize/angular-sanitize.js', |
||||
"angular-ui": "vendor/angular-ui/ui-bootstrap-tpls.js", |
||||
"angular-strap": "vendor/angular-other/angular-strap.js", |
||||
"angular-dragdrop": "vendor/angular-native-dragdrop/draganddrop.js", |
||||
"angular-bindonce": "vendor/angular-bindonce/bindonce.js", |
||||
"spectrum": "vendor/spectrum.js", |
||||
"bootstrap-tagsinput": "vendor/tagsinput/bootstrap-tagsinput.js", |
||||
"jquery.flot": "vendor/flot/jquery.flot", |
||||
"jquery.flot.pie": "vendor/flot/jquery.flot.pie", |
||||
"jquery.flot.selection": "vendor/flot/jquery.flot.selection", |
||||
"jquery.flot.stack": "vendor/flot/jquery.flot.stack", |
||||
"jquery.flot.stackpercent": "vendor/flot/jquery.flot.stackpercent", |
||||
"jquery.flot.time": "vendor/flot/jquery.flot.time", |
||||
"jquery.flot.crosshair": "vendor/flot/jquery.flot.crosshair", |
||||
"jquery.flot.fillbelow": "vendor/flot/jquery.flot.fillbelow", |
||||
"jquery.flot.gauge": "vendor/flot/jquery.flot.gauge", |
||||
"d3": "vendor/d3/d3.js", |
||||
"jquery.flot.dashes": "vendor/flot/jquery.flot.dashes", |
||||
"twemoji": "vendor/npm/twemoji/2/twemoji.amd.js", |
||||
"ace": "vendor/npm/ace-builds/src-noconflict/ace", |
||||
}, |
||||
|
||||
packages: { |
||||
app: { |
||||
defaultExtension: 'js', |
||||
}, |
||||
vendor: { |
||||
defaultExtension: 'js', |
||||
}, |
||||
}, |
||||
|
||||
map: { |
||||
}, |
||||
|
||||
meta: { |
||||
'vendor/angular/angular.js': { |
||||
format: 'global', |
||||
deps: ['jquery'], |
||||
exports: 'angular', |
||||
}, |
||||
'vendor/angular-mocks/angular-mocks.js': { |
||||
format: 'global', |
||||
deps: ['angular'], |
||||
}, |
||||
'vendor/npm/eventemitter3/index.js': { |
||||
format: 'cjs', |
||||
exports: 'EventEmitter' |
||||
}, |
||||
'vendor/npm/mousetrap/mousetrap.js': { |
||||
format: 'global', |
||||
exports: 'Mousetrap' |
||||
}, |
||||
'vendor/npm/ace-builds/src-noconflict/ace.js': { |
||||
format: 'global', |
||||
exports: 'ace' |
||||
}, |
||||
} |
||||
}); |
||||
|
||||
function file2moduleName(filePath) { |
||||
return filePath.replace(/\\/g, '/') |
||||
.replace(/^\/base\//, '') |
||||
.replace(/\.\w*$/, ''); |
||||
} |
||||
|
||||
function onlySpecFiles(path) { |
||||
return /specs.*/.test(path); |
||||
} |
||||
|
||||
window.grafanaBootData = {settings: {}}; |
||||
|
||||
var modules = ['angular', 'angular-mocks', 'app/app']; |
||||
var promises = modules.map(function(name) { |
||||
return System.import(name); |
||||
}); |
||||
|
||||
Promise.all(promises).then(function(deps) { |
||||
var angular = deps[0]; |
||||
|
||||
angular.module('grafana', ['ngRoute']); |
||||
angular.module('grafana.services', ['ngRoute', '$strap.directives']); |
||||
angular.module('grafana.panels', []); |
||||
angular.module('grafana.controllers', []); |
||||
angular.module('grafana.directives', []); |
||||
angular.module('grafana.filters', []); |
||||
angular.module('grafana.routes', ['ngRoute']); |
||||
|
||||
// load specs
|
||||
return Promise.all( |
||||
Object.keys(window.__karma__.files) // All files served by Karma.
|
||||
.filter(onlySpecFiles) |
||||
.map(file2moduleName) |
||||
.map(function(path) { |
||||
// console.log(path);
|
||||
return System.import(path); |
||||
})); |
||||
}).then(function() { |
||||
window.__karma__.start(); |
||||
}, function(error) { |
||||
window.__karma__.error(error.stack || error); |
||||
}).catch(function(error) { |
||||
window.__karma__.error(error.stack || error); |
||||
}); |
||||
|
||||
})(); |
||||
Loading…
Reference in new issue