Commit 837beda1 by Torkel Ödegaard

Merge branch 'react-poc'

parents 9500eb8a fed35909
......@@ -10,6 +10,8 @@
"url": "http://github.com/grafana/grafana.git"
},
"devDependencies": {
"@types/react": "^16.0.5",
"@types/react-dom": "^15.5.4",
"autoprefixer": "^6.4.0",
"es6-promise": "^3.0.2",
"es6-shim": "^0.35.1",
......@@ -48,7 +50,7 @@
"mocha": "3.2.0",
"phantomjs-prebuilt": "^2.1.14",
"reflect-metadata": "0.1.8",
"rxjs": "^5.0.0-rc.5",
"rxjs": "^5.4.3",
"sass-lint": "^1.10.2",
"systemjs": "0.19.41",
"zone.js": "^0.7.2"
......@@ -60,6 +62,7 @@
},
"license": "Apache-2.0",
"dependencies": {
"@types/enzyme": "^2.8.8",
"ace-builds": "^1.2.8",
"eventemitter3": "^2.0.2",
"gaze": "^1.1.2",
......@@ -70,13 +73,17 @@
"karma-sinon": "^1.0.5",
"lodash": "^4.17.4",
"mousetrap": "^1.6.0",
"ngreact": "^0.4.1",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-test-renderer": "^15.6.1",
"remarkable": "^1.7.1",
"sinon": "1.17.6",
"systemjs-builder": "^0.15.34",
"tether": "^1.4.0",
"tether-drop": "https://github.com/torkelo/drop",
"tslint": "^5.1.0",
"typescript": "^2.2.2",
"tslint": "^5.7.0",
"typescript": "^2.5.2",
"virtual-scroll": "^1.1.1"
}
}
......@@ -9,6 +9,7 @@ import 'angular-sanitize';
import 'angular-dragdrop';
import 'angular-bindonce';
import 'angular-ui';
import 'ngreact';
import $ from 'jquery';
import angular from 'angular';
......@@ -84,6 +85,7 @@ export class GrafanaApp {
'pasvaz.bindonce',
'ui.bootstrap',
'ui.bootstrap.tpls',
'react'
];
var module_types = ['controllers', 'directives', 'factories', 'services', 'filters', 'routes'];
......
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import coreModule from '../core_module';
export interface ICoolButtonProps {
count: number;
}
export interface ICoolButtonState {
count: number;
}
export class CoolButton extends React.Component<ICoolButtonProps, ICoolButtonState> {
constructor(props) {
super(props);
this.state = {count: 1};
}
onClick() {
this.setState(prevState => ({
count: prevState.count + 1
}));
console.log(this.state.count);
}
render() {
return (
<div>
<h2 onClick={this.onClick.bind(this)}>Hello</h2>
<div>{this.state.count}</div>
<a href="/alerting">Go to alerting</a>
</div>
);
}
}
export interface Props {
fname: string;
onClick: () => void;
}
function SecondButton({fname, onClick}: Props) {
return (
<div className="hello">
<div className="greeting">
Hello {fname}
</div>
<div>
<button onClick={onClick}>button</button>
</div>
</div>
);
}
coreModule.directive('coolButton', function(reactDirective) {
return reactDirective(CoolButton);
});
coreModule.directive('secondButton', function(reactDirective) {
return reactDirective(SecondButton, [
['fname', {watchDepth: 'value'}]
]);
});
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import coreModule from '../core_module';
export interface IProps {
password: string;
}
export class PasswordStrength extends React.Component<IProps, any> {
constructor(props) {
super(props);
}
render() {
let strengthText = "strength: strong like a bull.";
let strengthClass = "password-strength-good";
if (this.props.password.length < 4) {
strengthText = "strength: weak sauce.";
strengthClass = "password-strength-bad";
}
if (this.props.password.length <= 8) {
strengthText = "strength: you can do better.";
strengthClass = "password-strength-ok";
}
return (
<div className={`password-strength small ${strengthClass}`}>
<em>{strengthText}</em>
</div>
);
}
}
coreModule.directive('passwordStrength', function(reactDirective) {
return reactDirective(PasswordStrength, ['password']);
});
///<reference path="../../headers/common.d.ts" />
import coreModule from 'app/core/core_module';
const template = `
<div class="collapse-box">
<div class="collapse-box__header">
<a class="collapse-box__header-title pointer" ng-click="ctrl.toggle()">
<span class="fa fa-fw fa-caret-right" ng-hide="ctrl.isOpen"></span>
<span class="fa fa-fw fa-caret-down" ng-hide="!ctrl.isOpen"></span>
{{ctrl.title}}
</a>
<div class="collapse-box__header-actions" ng-transclude="actions" ng-if="ctrl.isOpen"></div>
</div>
<div class="collapse-box__body" ng-transclude="body" ng-if="ctrl.isOpen">
</div>
</div>
`;
export class CollapseBoxCtrl {
isOpen: boolean;
stateChanged: () => void;
/** @ngInject **/
constructor(private $timeout) {
this.isOpen = false;
}
toggle() {
this.isOpen = !this.isOpen;
this.$timeout(() => {
this.stateChanged();
});
}
}
export function collapseBox() {
return {
restrict: 'E',
template: template,
controller: CollapseBoxCtrl,
bindToController: true,
controllerAs: 'ctrl',
scope: {
"title": "@",
"isOpen": "=?",
"stateChanged": "&"
},
transclude: {
'actions': '?collapseBoxActions',
'body': 'collapseBoxBody',
},
link: function(scope, elem, attrs) {
}
};
}
coreModule.directive('collapseBox', collapseBox);
// ///<reference path="../../headers/common.d.ts" />
//
// import _ from 'lodash';
//
// var objectAssign = require('object-assign');
// var Emitter = require('tiny-emitter');
// var Lethargy = require('lethargy').Lethargy;
// var support = require('./support');
// var clone = require('./clone');
// var bindAll = require('bindall-standalone');
// var EVT_ID = 'virtualscroll';
//
// var keyCodes = {
// LEFT: 37,
// UP: 38,
// RIGHT: 39,
// DOWN: 40
// };
//
// function VirtualScroll(this: any, options) {
// _.bindAll(this, '_onWheel', '_onMouseWheel', '_onTouchStart', '_onTouchMove', '_onKeyDown');
//
// this.el = window;
// if (options && options.el) {
// this.el = options.el;
// delete options.el;
// }
//
// this.options = _.assign({
// mouseMultiplier: 1,
// touchMultiplier: 2,
// firefoxMultiplier: 15,
// keyStep: 120,
// preventTouch: false,
// unpreventTouchClass: 'vs-touchmove-allowed',
// limitInertia: false
// }, options);
//
// if (this.options.limitInertia) this._lethargy = new Lethargy();
//
// this._emitter = new Emitter();
// this._event = {
// y: 0,
// x: 0,
// deltaX: 0,
// deltaY: 0
// };
//
// this.touchStartX = null;
// this.touchStartY = null;
// this.bodyTouchAction = null;
// }
//
// VirtualScroll.prototype._notify = function(e) {
// var evt = this._event;
// evt.x += evt.deltaX;
// evt.y += evt.deltaY;
//
// this._emitter.emit(EVT_ID, {
// x: evt.x,
// y: evt.y,
// deltaX: evt.deltaX,
// deltaY: evt.deltaY,
// originalEvent: e
// });
// };
//
// VirtualScroll.prototype._onWheel = function(e) {
// var options = this.options;
// if (this._lethargy && this._lethargy.check(e) === false) return;
//
// var evt = this._event;
//
// // In Chrome and in Firefox (at least the new one)
// evt.deltaX = e.wheelDeltaX || e.deltaX * -1;
// evt.deltaY = e.wheelDeltaY || e.deltaY * -1;
//
// // for our purpose deltamode = 1 means user is on a wheel mouse, not touch pad
// // real meaning: https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent#Delta_modes
// if(support.isFirefox && e.deltaMode == 1) {
// evt.deltaX *= options.firefoxMultiplier;
// evt.deltaY *= options.firefoxMultiplier;
// }
//
// evt.deltaX *= options.mouseMultiplier;
// evt.deltaY *= options.mouseMultiplier;
//
// this._notify(e);
// };
//
// VirtualScroll.prototype._onMouseWheel = function(e) {
// if (this.options.limitInertia && this._lethargy.check(e) === false) return;
//
// var evt = this._event;
//
// // In Safari, IE and in Chrome if 'wheel' isn't defined
// evt.deltaX = (e.wheelDeltaX) ? e.wheelDeltaX : 0;
// evt.deltaY = (e.wheelDeltaY) ? e.wheelDeltaY : e.wheelDelta;
//
// this._notify(e);
// };
//
// VirtualScroll.prototype._onTouchStart = function(e) {
// var t = (e.targetTouches) ? e.targetTouches[0] : e;
// this.touchStartX = t.pageX;
// this.touchStartY = t.pageY;
// };
//
// VirtualScroll.prototype._onTouchMove = function(e) {
// var options = this.options;
// if(options.preventTouch
// && !e.target.classList.contains(options.unpreventTouchClass)) {
// e.preventDefault();
// }
//
// var evt = this._event;
//
// var t = (e.targetTouches) ? e.targetTouches[0] : e;
//
// evt.deltaX = (t.pageX - this.touchStartX) * options.touchMultiplier;
// evt.deltaY = (t.pageY - this.touchStartY) * options.touchMultiplier;
//
// this.touchStartX = t.pageX;
// this.touchStartY = t.pageY;
//
// this._notify(e);
// };
//
// VirtualScroll.prototype._onKeyDown = function(e) {
// var evt = this._event;
// evt.deltaX = evt.deltaY = 0;
//
// switch(e.keyCode) {
// case keyCodes.LEFT:
// case keyCodes.UP:
// evt.deltaY = this.options.keyStep;
// break;
//
// case keyCodes.RIGHT:
// case keyCodes.DOWN:
// evt.deltaY = - this.options.keyStep;
// break;
//
// default:
// return;
// }
//
// this._notify(e);
// };
//
// VirtualScroll.prototype._bind = function() {
// if(support.hasWheelEvent) this.el.addEventListener('wheel', this._onWheel);
// if(support.hasMouseWheelEvent) this.el.addEventListener('mousewheel', this._onMouseWheel);
//
// if(support.hasTouch) {
// this.el.addEventListener('touchstart', this._onTouchStart);
// this.el.addEventListener('touchmove', this._onTouchMove);
// }
//
// if(support.hasPointer && support.hasTouchWin) {
// this.bodyTouchAction = document.body.style.msTouchAction;
// document.body.style.msTouchAction = 'none';
// this.el.addEventListener('MSPointerDown', this._onTouchStart, true);
// this.el.addEventListener('MSPointerMove', this._onTouchMove, true);
// }
//
// if(support.hasKeyDown) document.addEventListener('keydown', this._onKeyDown);
// };
//
// VirtualScroll.prototype._unbind = function() {
// if(support.hasWheelEvent) this.el.removeEventListener('wheel', this._onWheel);
// if(support.hasMouseWheelEvent) this.el.removeEventListener('mousewheel', this._onMouseWheel);
//
// if(support.hasTouch) {
// this.el.removeEventListener('touchstart', this._onTouchStart);
// this.el.removeEventListener('touchmove', this._onTouchMove);
// }
//
// if(support.hasPointer && support.hasTouchWin) {
// document.body.style.msTouchAction = this.bodyTouchAction;
// this.el.removeEventListener('MSPointerDown', this._onTouchStart, true);
// this.el.removeEventListener('MSPointerMove', this._onTouchMove, true);
// }
//
// if(support.hasKeyDown) document.removeEventListener('keydown', this._onKeyDown);
// };
//
// VirtualScroll.prototype.on = function(cb, ctx) {
// this._emitter.on(EVT_ID, cb, ctx);
//
// var events = this._emitter.e;
// if (events && events[EVT_ID] && events[EVT_ID].length === 1) this._bind();
// };
//
// VirtualScroll.prototype.off = function(cb, ctx) {
// this._emitter.off(EVT_ID, cb, ctx);
//
// var events = this._emitter.e;
// if (!events[EVT_ID] || events[EVT_ID].length <= 0) this._unbind();
// };
//
// VirtualScroll.prototype.reset = function() {
// var evt = this._event;
// evt.x = 0;
// evt.y = 0;
// };
//
// VirtualScroll.prototype.destroy = function() {
// this._emitter.off();
// this._unbind();
// };
<div class="modal-body">
<div class="modal-header">
<h2 class="modal-header-title">
<i class="fa fa-cog fa-spin"></i>
<span class="p-l-1">{{model.name}}</span>
</h2>
<a class="modal-header-close" ng-click="dismiss();">
<i class="fa fa-remove"></i>
</a>
</div>
<div class="modal-content">
<div ng-if="activeStep">
</div>
<!-- <table class="filter&#45;table"> -->
<!-- <tbody> -->
<!-- <tr ng&#45;repeat="step in model.steps"> -->
<!-- <td>{{step.name}}</td> -->
<!-- <td>{{step.status}}</td> -->
<!-- <td width="1%"> -->
<!-- <i class="fa fa&#45;check" style="color: #39A039"></i> -->
<!-- </td> -->
<!-- </tr> -->
<!-- </tbody> -->
<!-- </table> -->
</div>
</div>
///<reference path="../../../headers/common.d.ts" />
import config from 'app/core/config';
import _ from 'lodash';
import $ from 'jquery';
import coreModule from 'app/core/core_module';
import appEvents from 'app/core/app_events';
export class WizardSrv {
/** @ngInject */
constructor() {
}
}
export interface WizardStep {
name: string;
type: string;
process: any;
}
export class SelectOptionStep {
type: string;
name: string;
fulfill: any;
constructor() {
this.type = 'select';
}
process() {
return new Promise((fulfill, reject) => {
});
}
}
export class WizardFlow {
name: string;
steps: WizardStep[];
constructor(name) {
this.name = name;
this.steps = [];
}
addStep(step) {
this.steps.push(step);
}
next(index) {
var step = this.steps[0];
return step.process().then(() => {
if (this.steps.length === index+1) {
return;
}
return this.next(index+1);
});
}
start() {
appEvents.emit('show-modal', {
src: 'public/app/core/components/wizard/wizard.html',
model: this
});
return this.next(0);
}
}
coreModule.service('wizardSrv', WizardSrv);
......@@ -35,7 +35,6 @@ import {layoutSelector} from './components/layout_selector/layout_selector';
import {switchDirective} from './components/switch';
import {dashboardSelector} from './components/dashboard_selector';
import {queryPartEditorDirective} from './components/query_part/query_part_editor';
import {WizardFlow} from './components/wizard/wizard';
import {formDropdownDirective} from './components/form_dropdown/form_dropdown';
import 'app/core/controllers/all';
import 'app/core/services/all';
......@@ -48,11 +47,10 @@ import {assignModelProperties} from './utils/model_utils';
import {contextSrv} from './services/context_srv';
import {KeybindingSrv} from './services/keybindingSrv';
import {helpModal} from './components/help/help';
import {collapseBox} from './components/collapse_box';
import {PasswordStrength} from './components/PasswordStrength';
import {JsonExplorer} from './components/json_explorer/json_explorer';
import {NavModelSrv, NavModel} from './nav_model_srv';
export {
arrayJoin,
coreModule,
......@@ -69,15 +67,14 @@ export {
appEvents,
dashboardSelector,
queryPartEditorDirective,
WizardFlow,
colors,
formDropdownDirective,
assignModelProperties,
contextSrv,
KeybindingSrv,
helpModal,
collapseBox,
JsonExplorer,
NavModelSrv,
NavModel,
PasswordStrength,
};
......@@ -4,7 +4,7 @@ define([
function (coreModule) {
'use strict';
coreModule.default.directive('passwordStrength', function() {
coreModule.default.directive('passwordStrength2', function() {
var template = '<div class="password-strength small" ng-if="!loginMode" ng-class="strengthClass">' +
'<em>{{strengthText}}</em>' +
'</div>';
......
// import React from 'react';
// import {describe, beforeEach, it, sinon, expect} from 'test/lib/common';
// import {shallow} from 'enzyme';
//
// import {PasswordStrength} from '../components/PasswordStrength';
//
// describe('PasswordStrength', () => {
//
// it.skip('should have class bad if length below 4', () => {
// const wrapper = shallow(<PasswordStrength password="asd" />);
// expect(wrapper.find(".password-strength-bad")).to.have.length(3);
// });
// });
//
/// <reference path="./es6-shim/es6-shim.d.ts" />
declare var System: any;
......@@ -53,11 +52,6 @@ declare module 'eventemitter3' {
export default config;
}
declare module 'virtual-scroll' {
var config: any;
export default config;
}
declare module 'mousetrap' {
var config: any;
export default config;
......
......@@ -55,7 +55,7 @@
<input type="password" class="gf-form-input max-width-14" required ng-model="formModel.password" id="inputPassword" placeholder="password" autocomplete="off">
</div>
<div style="margin-left: 7.5rem; width: 254px;">
<div style="margin-left: 9rem; width: 194px;">
<password-strength password="formModel.password"></password-strength>
</div>
......
......@@ -2,7 +2,9 @@ System.config({
defaultJSExtenions: true,
baseURL: 'public',
paths: {
'virtual-scroll': 'vendor/npm/virtual-scroll/src/index.js',
'react': 'vendor/npm/react/dist/react.js',
'react-dom': 'vendor/npm/react-dom/dist/react-dom.js',
'ngreact': 'vendor/npm/ngreact/ngReact.js',
'mousetrap': 'vendor/npm/mousetrap/mousetrap.js',
'remarkable': 'vendor/npm/remarkable/dist/remarkable.js',
'tether': 'vendor/npm/tether/dist/js/tether.js',
......
......@@ -76,7 +76,6 @@
@import "components/edit_sidemenu.scss";
@import "components/row.scss";
@import "components/json_explorer.scss";
@import "components/collapse_box.scss";
@import "components/code_editor.scss";
// PAGES
......
.collapse-box {
margin-bottom: $spacer;
&--error {
.collapse-box__header {
border-color: $collapse-box-body-error-border;
}
.collapse-box__body {
border-color: $collapse-box-body-error-border;
}
}
}
.collapse-box__header {
display: flex;
flex-direction: row;
padding: $input-padding-y $input-padding-x;
margin-right: $gf-form-margin;
background-color: $input-label-bg;
font-size: $font-size-sm;
margin-right: $gf-form-margin;
border: $input-btn-border-width solid $collapse-box-body-border;
@include border-radius($label-border-radius-sm);
}
.collapse-box__header-title {
flex-grow: 1;
}
.collapse-box__body {
padding: $input-padding-y*2 $input-padding-x;
display: block;
margin-right: $gf-form-margin;
border: $input-btn-border-width solid $collapse-box-body-border;
border-top: none;
@include border-radius($label-border-radius-sm);
}
.collapse-box__header-actions {
display: flex;
flex-direction: row;
a {
margin-left: $spacer;
}
}
......@@ -10,6 +10,9 @@
baseURL: '/base/',
defaultJSExtensions: true,
paths: {
'react': 'vendor/npm/react/dist/react.js',
'react-dom': 'vendor/npm/react-dom/dist/react-dom.js',
'ngreact': 'vendor/npm/ngreact/ngReact.js',
'mousetrap': 'vendor/npm/mousetrap/mousetrap.js',
'eventemitter3': 'vendor/npm/eventemitter3/index.js',
'remarkable': 'vendor/npm/remarkable/dist/remarkable.js',
......@@ -83,7 +86,7 @@
function file2moduleName(filePath) {
return filePath.replace(/\\/g, '/')
.replace(/^\/base\//, '')
.replace(/^\/base\//, '')
.replace(/\.\w*$/, '');
}
......@@ -112,12 +115,12 @@
// 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);
}));
.filter(onlySpecFiles)
.map(file2moduleName)
.map(function(path) {
// console.log(path);
return System.import(path);
}));
}).then(function() {
window.__karma__.start();
}, function(error) {
......
......@@ -38,6 +38,9 @@ module.exports = function(config) {
'remarkable/dist/*',
'virtual-scroll/**/*',
'mousetrap/**/*',
'react/dist/*.js',
'react-dom/dist/*.js',
'ngreact/ngReact.js',
],
dest: '<%= srcDir %>/vendor/npm'
}
......
......@@ -5,19 +5,22 @@
"outDir": "public_gen",
"noImplicitAny": false,
"target": "es5",
"lib": ["es6", "dom"],
"rootDir": "public/",
"module": "system",
"jsx": "react",
"noEmitOnError": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noImplicitReturns":false,
"noImplicitThis":false,
"noImplicitThis": false,
"noImplicitUseStrict":false,
"noUnusedLocals":false,
"moduleResolution": "classic"
},
"include": [
"public/app/**/*.ts",
"public/app/**/*.tsx",
"public/test/**/*.ts"
],
"exclude": [
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment