started new web client

This commit is contained in:
didier amyot committed 2020-01-19 15:14:21 -05:00
1 parent 1b3d0ea70b
commit fcff74109a
33 files changed
+232 -2585

No files matched your search

-12
View File
@@ -4,7 +4,6 @@ import (
"log" "log"
"github.com/didiercrunch/doormanserver/logpublisher" "github.com/didiercrunch/doormanserver/logpublisher"
"github.com/didiercrunch/doormanserver/nanomsgpublisher"
"github.com/didiercrunch/doormanserver/nsqpublisher" "github.com/didiercrunch/doormanserver/nsqpublisher"
"github.com/didiercrunch/doormanserver/shared" "github.com/didiercrunch/doormanserver/shared"
"gopkg.in/mgo.v2/bson" "gopkg.in/mgo.v2/bson"
@@ -25,21 +24,10 @@ func initNSQPublisher() {
} }
} }
func initNanoMsgPublisher() {
publisher = new(nanomsgpublisher.NanoMsgPublisher)
if err := publisher.Init(); err != nil {
log.Panic(err)
return
}
}
func initPublisher(params *shared.Params) { func initPublisher(params *shared.Params) {
if params.UseNSQ() { if params.UseNSQ() {
initNSQPublisher() initNSQPublisher()
log.Println("using nsq as message queue") log.Println("using nsq as message queue")
} else if params.UseNanomsg() {
initNanoMsgPublisher()
log.Println("using nanomsg as message queue")
} else { } else {
publisher = &logpublisher.LogPublisher{log.Println} publisher = &logpublisher.LogPublisher{log.Println}
log.Println("using stdout as message queue") log.Println("using stdout as message queue")
-41
View File
@@ -1,41 +0,0 @@
package nanomsgpublisher
import (
"errors"
"log"
"github.com/didiercrunch/doormanserver/shared"
"github.com/go-mangos/mangos"
"github.com/go-mangos/mangos/protocol/pub"
"github.com/go-mangos/mangos/transport/ipc"
"github.com/go-mangos/mangos/transport/tcp"
"gopkg.in/mgo.v2/bson"
)
type NanoMsgPublisher struct {
Url string
sock mangos.Socket
}
func (p *NanoMsgPublisher) Init() error {
var err error
if p.sock, err = pub.NewSocket(); err != nil {
return errors.New("can't listen on pub socket:" + err.Error())
}
p.sock.AddTransport(ipc.NewTransport())
p.sock.AddTransport(tcp.NewTransport())
if err = p.sock.Listen(shared.GetParams().NanoMsg.NanoMsgUrl); err != nil {
return errors.New("can't listen on pub socket: %s" + err.Error())
}
return nil
}
func (p *NanoMsgPublisher) Emit(doormanId bson.ObjectId, doorman shared.AsDoormanUpdatePayloader) error {
log.Println("Emit for ", doormanId.Hex())
if d, err := doorman.AsDoormanUpdatePayload(); err != nil {
return err
} else {
return p.sock.Send(d)
}
}
-3
View File
@@ -1,3 +0,0 @@
{
"directory": "app/bower_components"
}
-7
View File
@@ -1,7 +0,0 @@
logs/*
!.gitkeep
node_modules/
bower_components/
tmp
.DS_Store
.idea
-28
View File
@@ -1,28 +0,0 @@
{
"name": "angular-requirejs-seed",
"description": "AngularJS seed project modified for requireJS support.",
"version": "0.2.0",
"homepage": "https://github.com/tnajdek/angular-requirejs-seed",
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"angular": "~1.2.1",
"angular-route": "~1.2.1",
"angular-scenario": "~1.2.1",
"angular-mocks": "~1.2.1",
"requirejs": "~2.1.9",
"requirejs-text": "~2.0.10",
"html5-boilerplate": "~4.3.0",
"angularAMD": "~0.2.1",
"angular-foundation": "~0.5.1",
"lodash": "~3.9.3",
"font-awesome": "~4.3.0",
"bourbon": "~4.2.3"
}
}
-64
View File
@@ -1,64 +0,0 @@
define [
"angularAMD"
"lodash"
"angular-route"
"foundation"
], (angularAMD, _) ->
app = angular.module("webapp", ["ngRoute", "mm.foundation"])
app.config ($routeProvider) ->
$routeProvider.when("/", angularAMD.route(
templateUrl: "partials/home.html"
controller: "HomeCtrl"
controllerUrl: "controllers/homeCtrl"
)).when("/serverspec", angularAMD.route(
templateUrl: "partials/serverspec.html"
controller: "ServerspecCtrl"
controllerUrl: "controllers/serverspecCtrl"
)).when("/apispec", angularAMD.route(
templateUrl: "partials/apispec.html"
controller: "ApispecCtrl"
controllerUrl: "controllers/apispecCtrl"
)).when("/newdoorman", angularAMD.route(
templateUrl: "partials/newdoorman.html"
controller: "NewDoormanCtrl"
controllerUrl: "controllers/newdoormanCtrl"
)).when("/doormen", angularAMD.route(
templateUrl: "partials/doormen.html"
controller: "DoormenCtrl"
controllerUrl: "controllers/doormenCtrl"
)).when("/doormen/error/:error/:id", angularAMD.route(
templateUrl: "partials/doormanError.html"
controller: "DoormanErrorCtrl"
controllerUrl: "controllers/doormanErrorCtrl"
)).when("/doormen/:id", angularAMD.route(
templateUrl: "partials/doorman.html"
controller: "DoormanCtrl"
controllerUrl: "controllers/doormanCtrl"
)).otherwise({redirectTo: "/"})
document.getElementsByTagName("body")[0].style.visibility = ""
return
app.controller "topbarCtrl", ["$scope", "$rootScope", "$location", ($scope, $rootScope, $location) ->
$scope.init = () ->
$scope.email = localStorage.getItem("email")
$scope.loggedIn = !!$scope.email
if !$scope.loggedIn
$location.path('/').replace()
$scope.logout = () ->
localStorage.setItem("email", "")
$scope.email = ""
$scope.loggedIn = false
$scope.$emit("logout")
$scope.init()
$rootScope.$on('login', $scope.init)
return
]
angularAMD.bootstrap(app)
@@ -1,32 +0,0 @@
define ["app", "angularAMD"], (app, angularAMD) ->
app.controller "ApispecCtrl",['$scope', '$http', ($scope, $http) ->
$http.get("/api/documentation").then (res)->
$scope.endpoints = res.data.endpoints
$scope.methods =
get: "GET"
post: "POST"
]
angularAMD.directive "wabMethod", () ->
directive =
restrict: 'E',
scope:
method: '@'
link: (scope, element) ->
scope.methods =
get: "GET"
put: "PUT"
delete: "DELETE"
post: "POST"
template: '<code style="width:5em; display: block; text-align: center;">{{ methods[method] }}</code>'
return directive
angularAMD.directive "wabApi", () ->
directive =
restrict: 'E',
scope:
endpoint: '@'
template: '<a>/api{{ endpoint }}</a>'
return directive
@@ -1,76 +0,0 @@
define ["app", "lodash", "directives/ratinput"], (app, _, ratinput) ->
app.controller "DoormanCtrl", ["$scope", "$http","$routeParams","$location", "$timeout", ($scope, $http, $routeParams, $location, $timeout) ->
$scope.doorman = {values: []}
$scope.somevalue = "2/6"
$scope.apiurl = "/api/doormen/#{$routeParams.id}"
$scope.user = localStorage.getItem("email")
$scope.doormanChanged = false
$http.get($scope.apiurl).then((res) ->
$scope.doorman = res.data
$scope.isAdmin = _.contains($scope.doorman.emails, $scope.user)
$scope.initEmails()
).catch((res) ->
if res.status == 404
$location.path("/doormen/error/#{res.status}/#{$routeParams.id}")
)
$scope.deleteDoorman = () ->
console.log("not yet implemented")
$scope.initEmails = () ->
[$scope.leftEmailColumns, $scope.rightEmailColumns] = _.chunk($scope.doorman.emails, 2)
$scope.rationalToFloat = (rat) ->
if _.contains(rat, "/")
num = Number(rat.substr(0, rat.indexOf("/")))
denum = Number(rat.substr(rat.indexOf("/") + 1))
return num / denum
Number(rat)
$scope.validate = ()->
ret = 0
for val in $scope.doorman.values
ret += $scope.rationalToFloat(val.probability)
return Math.abs(ret - 1.0) < 0.000001
$scope.addNewAuthorEmail = () ->
if not $scope.canAddNewEmail()
return
$scope.doorman.emails.push($scope.newEmail)
$scope.updateDoorman()
$scope.newEmail = ""
$scope.initEmails()
$scope.removeEmail = (email) ->
$scope.doorman.emails = _.reject($scope.doorman.emails , (email_) -> email_ == email)
$scope.initEmails()
$scope.updateDoorman()
$scope.canAddNewEmail = ()->
if !$scope.newEmail or $scope.newEmail.length < 5
return false
not _.contains($scope.doorman.emails, $scope.newEmail)
$scope.updateDoorman = () ->
if !$scope.validate()
return
params = {params: {user: $scope.user}}
$http.put($scope.apiurl, $scope.doorman, params).then((ret)->
console.log "update"
).then((res) ->
$scope.doormanChanged = true
$timeout(() ->
$scope.doormanChanged = false
, 3000)
).catch((res) ->
$scope.error =
message: res.data
status : res.status
)
]
return
@@ -1,6 +0,0 @@
define ["app"], (app) ->
app.controller "DoormanErrorCtrl", ["$scope","$routeParams", ($scope, $routeParams) ->
$scope.id = $routeParams.id
$scope.error = Number($routeParams.error)
]
return
@@ -1,9 +0,0 @@
define ["app"], (app) ->
app.controller "DoormenCtrl",[ "$scope", "$http", ($scope, $http) ->
$scope.doormen = []
$http.get("/api/doormen").then (res) ->
$scope.doormen = res.data.doormen
return
]
return
-15
View File
@@ -1,15 +0,0 @@
define ["app"], (app) ->
app.controller "HomeCtrl", ['$scope', '$rootScope', ($scope, $rootScope) ->
$scope.init = () ->
$scope.loggedEmail = localStorage.getItem("email")
$scope.login = () ->
if $scope.email
localStorage.setItem("email", $scope.email)
$scope.loggedEmail = $scope.email
$scope.email = ""
$scope.$emit("login")
$scope.init()
$rootScope.$on('logout', $scope.init)
]
@@ -1,82 +0,0 @@
epsilon = 0.0001
define ["app", "lodash", "../filters", "directives/ratinput"], (app, _, filters, ratinput) ->
app.controller "NewDoormanCtrl", ["$scope", "$http", "$location", "rationals", ($scope, $http, $location, rationals) ->
$scope.error = ""
$scope.user = localStorage.getItem("email")
$scope.value = {probability: "1", name: ""}
$scope.payload =
name: ""
values: []
emails: [$scope.user]
$scope.isValidValue = () ->
return $scope.value.name
$scope.addNewValue = () ->
if !$scope.isValidValue()
return
$scope.payload.values.push($scope.value)
$scope.value =
name: ""
probability: $scope.getProbabilityRemaining()
$scope.removeValue = (idx) ->
$scope.payload.values.splice(idx, 1);
$scope.getProbabilityRemaining = () ->
sum = rationals.sum(_.pluck($scope.payload.values, "probability")...)
return rationals.minus("1", sum)
$scope.redirectToDoorman = (doormanLocation) ->
$http.get(doormanLocation).then (res) ->
id = res.data.id
return $location.url("/doormen/#{id}")
$scope.getPayload = () ->
payload = _.cloneDeep($scope.payload)
for value in payload.values
value.probability = value.probability
return payload
$scope.createDoorman = () ->
if not $scope.isDoormanValid()
return
params = {params: {user: $scope.user}}
$http.post("/api/doormen", $scope.getPayload(), params).
then((res, s) ->
$scope.redirectToDoorman(res.headers("location"))
).catch((res) ->
$scope.error = res.data
)
$scope.isDoormanValid = () ->
if not $scope.payload.name
return false
if $scope.payload.values.length < 2
return false
rationals.equal($scope.getProbabilityRemaining(), "0" )
$scope.addEmail = () ->
if not $scope.newEmail
return
$scope.payload.emails.push($scope.newEmail)
$scope.newEmail = ""
$scope.removeEmail = (idx) ->
if $scope.payload.emails[idx] == $scope.user
return
$scope.payload.emails.splice(idx, 1);
$scope.getSum = () ->
probs = _.pluck($scope.payload.values, "probability")
return rationals.pp(rationals.sum(probs...))
return
]
return
@@ -1,7 +0,0 @@
define ["app"], (app) ->
app.controller "ServerspecCtrl",["$scope", "$http", ($scope, $http) ->
$scope.server = {}
$http.get("/api/server").then (res) -> $scope.server = res.data
return
]
return
@@ -1,6 +0,0 @@
define ["app"], (app) ->
app.controller "sideBarCtrl", ($scope) ->
$scope.message = "Message from MyCtrl1"
return
return
-64
View File
@@ -1,64 +0,0 @@
template = """
<div class="row rat-input">
<div class="row" ng-show="!edit" >
<div class="columns large-12" style="text-align: center;">
<span class="fraction-box" ng-click="enableEdit()">
<span ng-bind="nominator"></span> &frasl; <span ng-bind="denominator" ></span>
<i class="fa fa-pencil-square-o" ng-show="!ngDisabled"></i>
</span>
</div>
</div>
<div ng-show="edit" class="edit">
<form ng-submit="edit=false">
<div class="large-12 columns" style="text-align: center;">
<input ng-model="nominator" type="text" ng-change="changeModel()" ng-disabled="ngDisabled">
<span style="text-align: center;">&frasl;<span>
<input ng-model="denominator" type="text" ng-change="changeModel()" ng-disabled="ngDisabled">
<i class="fa fa-check" ng-click="edit=false"></i>
<input type="submit" style="display:none;">
</div>
</form>
</div>
</div>
"""
define ["app", "angularAMD", "lodash", "services/rationals"], (app, angularAMD, _, rationals) ->
angularAMD.directive "ratInput", () ->
directive =
restrict: 'E',
template: template
scope:
ngModel: "="
ngDisabled: "="
controller: [ '$scope', "rationals", ($scope, rationals) ->
$scope.getNominator = ()->
if _.contains($scope.ngModel, "/")
return Number($scope.ngModel.substr(0, $scope.ngModel.indexOf("/")))
Number($scope.ngModel)
$scope.getDenominator = () ->
if _.contains($scope.ngModel, "/")
return Number($scope.ngModel.substr($scope.ngModel.indexOf("/") + 1))
1
$scope.changeModel = ()->
$scope.ngModel = rationals.newRat($scope.nominator, $scope.denominator)
$scope.enableEdit = () ->
if not $scope.ngDisabled
$scope.edit = true
$scope.init = () ->
$scope.nominator = rationals.getNominator($scope.ngModel)
$scope.denominator = $scope.getDenominator()
$scope.$watch 'ngModel', () ->
$scope.init()
$scope.init()
]
return directive
-7
View File
@@ -1,7 +0,0 @@
define ['angularAMD', 'app'], (angular, app) ->
app.filter 'reverse', ->
(items) ->
if !Array.isArray(items)
return false
items.slice().reverse()
return
-21
View File
@@ -1,21 +0,0 @@
require.config
baseUrl: "js"
# alias libraries paths. Must set 'angular'
paths:
"angular" : "/bower_components/angular/angular.min"
"angular-route": "/bower_components/angular-route/angular-route.min"
"angularAMD" : "/bower_components/angularAMD/angularAMD.min"
"foundation" : "/bower_components/angular-foundation/mm-foundation-tpls"
"lodash" : "/bower_components/lodash/lodash.min"
# Add angular modules that does not support AMD out of the box, put it in a shim
shim:
"angularAMD": ["angular"]
"angular-route": ["angular"]
"foundation" : ["angular"]
# kick start application
deps: ["app"]
-80
View File
@@ -1,80 +0,0 @@
define ["app", "angularAMD", "lodash"], (app, angularAMD, _) ->
app.service "rationals", () ->
service =
getNominator: (rat) ->
if _.contains(rat, "/")
return Number(rat.substr(0, rat.indexOf("/")))
Number(rat)
getDenominator: (rat) ->
if _.contains(rat, "/")
return Number(rat.substr(rat.indexOf("/") + 1))
1
getNomDenom: (rat) ->
return [service.getNominator(rat), service.getDenominator(rat)]
gcd: (a, b) ->
if b == 0
return a
return service.gcd(b, a % b)
lcm: (a, b) ->
return a * b / service.gcd(a, b)
changeDenominator: (rat, newDenom) ->
[nom, denom] = service.getNomDenom(rat)
return service.newRat( nom * newDenom / denom, newDenom)
add: (rat1, rat2) ->
[nom, denom] = service.getNomDenom(rat2)
[nNom, nDenom] = service.getNomDenom(rat1)
gcd = service.gcd(nDenom, denom)
rNom = nom*nDenom + nNom * denom
rDenom = denom * nDenom
return service.newRat(rNom/gcd , rDenom/gcd)
minus: (rat1, rat2) ->
return service.add(rat1, service.opposite(rat2))
reduce: (rat) ->
[nom, denom] = service.getNomDenom(rat)
gcd = service.gcd(nom, denom)
return service.newRat(nom/gcd, denom/gcd)
opposite: (rat) ->
[nom, denom] = service.getNomDenom(rat)
return service.newRat(-nom, denom)
sum: (rats...) ->
ret = "0/1"
for rat in rats
ret = service.add(ret, rat)
return service.reduce(ret)
equal: (rat1, rat2) ->
[nom1, denom1] = service.getNomDenom(rat1)
[nom2, denom2] = service.getNomDenom(rat2)
return nom1 * denom2 == nom2 * denom1
pp: (x) ->
[num, denum] = service.getNomDenom(service.reduce(x))
if denum == 1
return num
return "#{num}/#{denum}"
newRat: (nom , denom) ->
if nom * denom >= 0
return "#{Math.abs(nom)}/#{Math.abs(denom)}"
return "#{-Math.abs(nom)}/#{Math.abs(denom)}"
return service
app.filter "ratpp", ["rationals", (rationals) ->
filter = (n) ->
return rationals.pp(n)
]
-51
View File
@@ -1,51 +0,0 @@
var bower = require('gulp-bower');
var gulp = require('gulp');
var coffee = require('gulp-coffee');
var help = require('gulp-task-listing');
var clean = require('gulp-clean');
var sass = require('gulp-sass');
var rjs = require("gulp-rjs");
var gutil = require('gulp-util');
gulp.task('help', help);
gulp.task('bower', function() {
return bower()
.pipe(gulp.dest('bower_components/'))
});
gulp.task('sass', ['bower'], function () {
return gulp.src('./scss/*.scss')
.pipe(sass({includePaths: ['bower_components/foundation/scss', 'bower_components/bourbon/app/assets/stylesheets']}))
.pipe(gulp.dest('./css'));
});
gulp.task('coffee', ['bower'], function() {
return gulp.src('coffee/**/*.coffee')
.pipe(coffee({bare: true}).on('error', gutil.log))
.pipe(gulp.dest('js/'))
});
gulp.task('clean', function(){
return gulp.src(["js/", "bower_components/", "css/"], {read: false})
.pipe(clean())
});
gulp.task('rjs', ['coffee'], function(){
return gulp.src('coffee/**/*.coffee')
.pipe(coffee())
.pipe(gulp.dest('./dist'))
.pipe(rjs({baseUrl:'.'}))
});
gulp.task('default', ['bower', 'sass', 'coffee']);
gulp.task('dev', ['bower', 'sass', 'coffee'], function(){
gulp.watch('coffee/**/*.coffee', ['coffee']);
gulp.watch('./scss/*.scss', ['sass']);
});
View File
Whitespace-only changes.
+17 -42
View File
@@ -1,47 +1,22 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<head> <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
<title>doorman</title> <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/lodash@4.17.15/lodash.min.js"></script>
<link rel="stylesheet" href="css/style.css"> <script src="https://unpkg.com/mithril/mithril.js"></script>
<link rel="stylesheet" href="bower_components/font-awesome/css/font-awesome.min.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.8.0/css/bulma.min.css">
<script data-main="/js/main" src="/bower_components/requirejs/require.js"></script>
</head>
<body style="visibility:hidden;">
<div ng-controller="topbarCtrl">
<top-bar>
<ul class="title-area">
<li class="name">
<h1><a href="#/">Doorman</a></h1>
</li>
<li toggle-top-bar class="menu-icon"><a >Menu</a></li>
</ul>
<top-bar-section>
<ul class="left show-for-large-up">
<li>
<a ng-bind="email" href="#"></a>
</li>
</ul>
<ul class="right">
<li has-dropdown>
<a >Dropdown</a>
<ul top-bar-dropdown ng-show="loggedIn">
<li><a href="#/doormen">doormen</a></li>
<li><a href="#/newdoorman">new doorman</a></li>
<li><a href="#/apispec">api specification</a></li>
<li><a href="#/serverspec">server specification</a></li>
<li ng-click="logout()"><a href="#/">logout</a></li>
</ul>
</li>
</ul>
</top-bar-section>
</top-bar>
</div>
<div class="large-12 small-12 columns" ng-view></div>
</body>
</head>
<body >
<section class="section">
<div class="container">
<div id="mithril"></div>
</div>
</section>
<script src="index.js"></script>
</body>
</html> </html>
+215
View File
@@ -0,0 +1,215 @@
(function(){
const Ratio = (n, d) => ({
type: 'Ratio',
'n': n, // numerator
'd': d // denominator
});
const approxRatio = eps => n => {
const
gcde = (e, x, y) => {
const _gcd = (a, b) => (b < e ? a : _gcd(b, a % b));
return _gcd(Math.abs(x), Math.abs(y));
},
c = gcde(Boolean(eps) ? eps : (1 / 10000), 1, n);
return Ratio(
Math.floor(n / c), // numerator
Math.floor(1 / c) // denominator
);
};
var topBar = {}
function fontawesome(){
const classes = _.map(arguments, x => "." + x).reduce((s, n) => s + n);
return m('i' + classes);
}
var TopBar = {
view: function(){
return m('nav.navbar', [
m('div.navbar-brand',
m('a.navbar-item', {href: "#!/"}, "Doorman ", fontawesome('fas', 'fa-door-open'))),
m('div.navbar-menu', [
m('div.navbar-end', [
m('a.navbar-item', {href: "#!/server"}, "Server"),
m('a.navbar-item', {href: "#!/new-doorman"}, "New Doorman"),
])
])
]);
}
}
var Home = {};
Home.doormen = [];
Home.oninit = function(){
m.request({method: "GET", url: "/api/doormen"}).then(data => Home.doormen = data.doormen);
}
Home.doorman = function(doorman, idx){
const link = "#!/doorman/" + doorman.id
return m('li', m('a', {href: link}, doorman.name));
}
Home.view = function() {
return m("main", [
m(TopBar),
m("h1", {class: "title"}, "Home"),
m('div.content',
m('ul', _.map(Home.doormen, Home.doorman)))
]);
}
var NewDoorman = {}
NewDoorman.oninit = function(){
NewDoorman.clear();
}
NewDoorman.setToPayload = function(field){
return function(e){
_.set(NewDoorman.payload, field, e.target.value);
}
}
NewDoorman.nameField = function(){
const fields = {
type: 'text',
placeholder: 'Background Colour dsds',
onchange: NewDoorman.setToPayload('foo')};
return m('label.label', 'Name',
m('input.input', fields));
}
NewDoorman.ownerField = function(email, idx){
const label = 'Owner ' + (idx + 1);
const fields = {
type: 'text',
value: email,
onchange: NewDoorman.setToPayload(['OwnerEmails', idx])}
return m('label.label', label,
m('input.input', fields));
}
NewDoorman.putEmptyOwnerFields = function(){
NewDoorman.payload.OwnerEmails = _(NewDoorman.payload.OwnerEmails)
.filter(x => !_.isEmpty(x))
.concat('')
.value();
}
NewDoorman.ownerFields = function(){
return m('fieldset', {onchange: NewDoorman.putEmptyOwnerFields()},
m('legend', 'Owners'),
_.map(NewDoorman.payload.OwnerEmails, NewDoorman.ownerField));
}
NewDoorman.valueField = function(value, idx){
const nameField = m('div.field',
m('label', 'name',
m('input.input', {type: 'text', value: value.name, onchange: NewDoorman.setToPayload(['Values', idx, 'name'])})));
const valueField = m('div.field', m('label', 'value', m('input.input', {type: 'number', value: value.value, onchange: NewDoorman.setToPayload(['Values', idx, 'value'])})));
return m('div.columns',
m('div.column', nameField),
m('div.column', valueField));
}
NewDoorman.putEmptyValueFields = function() {
const hasEmptyNames = _(NewDoorman.payload.Values).map('name').filter(_.isEmpty).value().length;
const hasEmptyValues = _(NewDoorman.payload.Values).map('value').filter(_.isEmpty).value().length;
const sum = _(NewDoorman.payload.Values).map('value').map(x => parseInt(x)).sum();
if(sum >= 100 || hasEmptyNames || hasEmptyValues){
return;
}
NewDoorman.payload.Values.push({name: '', value: 100 - sum});
}
NewDoorman.valueFields = function(){
return m('fieldset', {onchange: NewDoorman.putEmptyValueFields}, m('legend', 'Values'),
_.map(NewDoorman.payload.Values, NewDoorman.valueField));
}
NewDoorman.clear = function(){
NewDoorman.payload = {
OwnerEmails: [],
Values: [{}]
};
}
NewDoorman.buttons = function(){
return m('div.buttons', [
m('button.button.is-primary.is-light', 'Create'),
m('button.button.is-danger.is-light', {onclick: NewDoorman.clear}, 'Clear')
])
}
NewDoorman.view = function(){
return m('div',
m(TopBar),
m('form', [
NewDoorman.nameField(),
m('br'),
NewDoorman.ownerFields(),
m('br'),
NewDoorman.valueFields(),
m('br'),
NewDoorman.buttons()
]))
}
var Server = {}
Server.data = {};
Server.oninit= function(){
m.request({method: "GET", url: "/api/server"})
.then(function(data) {
Server.data = data;
});
}
Server.renderRow = function(value, key){
return m('tr', [
m('td', key),
m('td', _.isObject(value) ? JSON.stringify(value) : value)]);
}
Server.renderTable = function(serverData){
const rows = _.map(serverData, Server.renderRow);
return m('table.table.is-bordered.is-striped.is-hoverable', rows);
}
Server.view = function() {
return m("div", [
m(TopBar),
m("h1", {class: "title"}, "Server"),
Server.renderTable(Server.data)
]);
}
var Doorman = {};
Doorman.doorman = {}
Doorman.oninit = function(vnode){
m.request({method: "GET", url: "/api/doormen"})
.then(data => _(data.doormen).filter(x => x.id == vnode.attrs.doormanId).map('url').first())
.then(url => m.request({method: "GET", url: url}))
.then(data => Doorman.doorman = data);
}
Doorman.view = function(vnode){
return m('div', [m(TopBar),'blah' + JSON.stringify(Doorman.doorman)])
}
m.route(document.getElementById('mithril'), "/", {
"/": Home,
"/server": Server,
"/new-doorman": NewDoorman,
"/doorman/:doormanId": Doorman,
});
})();
-15
View File
@@ -1,15 +0,0 @@
{
"dependencies": {
"gulp": "~3.8.9",
"gulp-bower": "0.0.7",
"gulp-clean": "~0.3.1",
"gulp-coffee": "~2.2.0",
"gulp-sass": "^1.2.4",
"gulp-task-listing": "~0.3.0",
"gulp-util": "^3.0.3",
"node-sass": "~1.2.3"
},
"devDependencies": {
"gulp-rjs": "^0.1.0"
}
}
-53
View File
@@ -1,53 +0,0 @@
<div class="row">
<div class="columns large-12">
<h1>Api specification</h1>
</div>
</div>
<div class="row">
<div class="columns large-12">
<h3>End points</h3>
</div>
</div>
<div class="row wab-apispect">
<table class="columns large-12">
<thead>
<tr >
<th >api endpoint</th>
<th>method</th>
<th >description</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="endpoint in endpoints">
<td><wab-api endpoint="{{ endpoint.pattern }}"></wab-api></td>
<td>
<code style="width:5em; display: block; text-align: center;">{{ endpoint.method }}</code>
</td>
<td >{{ endpoint.description }}</td>
</tr>
</tbody>
</table>
</div>
<div class="row">
<div class="columns large-12">
<h3>Authentication</h3>
</div>
</div>
<div class="row">
<div class="columns large-12">
<p>
All calls that change an asset requires authentication.
Authentication is done by adding a <code class="light">
user={user_name}</code> parameter to the endpoint. For example, to
authenticate to <code class="light">/api/doormen/zST8_FWcPDT2-14wDQAAAQ==</code>
with a user called "bob", the url becomes
<code class="light">/api/doormen/zST8_FWcPDT2-14wDQAAAQ==?user=bob</code>
</p>
</div>
</div>
-92
View File
@@ -1,92 +0,0 @@
<div class="row">
<div class="columns large-12">
<h1>{{ doorman.name }} </h1>
</div>
</div>
<div class="row">
<div class="columns large-12">
<span>doorman id: <code>{{ doorman.id }}</code></span>
</div>
</div>
<div class="row" ng-repeat="value in doorman.values">
<div class="columns large-8 small-10">
<div class="row">
<div class="large-2 columns">
<a class="button prefix disabled" ng-bind="$index"> </a>
</div>
<div class="large-10 columns">
<input type="text" placeholder="value name" ng-value="value.name" disabled>
</div>
</div>
</div>
<div class="columns large-4 small-2">
<label >
probability
<rat-input ng-model="value.probability" ng-disabled="!isAdmin"></rat-input>
</div>
</div>
<div class="row">
<div class="large-4 columns">
<ul>
<li ng-repeat="email in leftEmailColumns">
<span ng-bind="email"></span>
<i class="fa fa-times right"
ng-click="removeEmail(email)"
style="cursor: pointer;"
ng-show="doorman.emails.length > 1 && isAdmin && email != user"
></i>
</li>
</ul>
</div>
<div class="large-4 columns">
<ul>
<li ng-repeat="email in rightEmailColumns">
<span ng-bind="email"></span>
<i class="fa fa-times right"></i>
</li>
</ul>
</div>
<div class="large-4 columns">
<div>
<label>
new admin
<div class="row collapse">
<div class="columns large-10 small-10">
<input type="text" ng-model="newEmail"/>
</div>
<div class="columns large-2 small-2">
<a class="button postfix" ng-click="addNewAuthorEmail()" ng-class=" canAddNewEmail() ? '' : 'disabled' " >+</a>
</div>
</div>
</label>
</div>
</div>
</div>
<div class="row" ng-show="error">
<div class="columns large-12">
<code style="width:100%; height:100%; display:block; margin-bottom: 1em;">
<b>{{ error.status }}</b><br>&nbsp; {{ error.message }}
</code>
</div>
</div>
<div class="row" ng-show="isAdmin">
<div class="large-12 small-12 columns">
<ul class="button-group">
<li><a ng-click="updateDoorman()" class="small button" ng-class="{disabled: !validate()}">Update</a></li>
</ul>
<span ng-show="doormanChanged">
doorman changed
</span>
</div>
</div>
-11
View File
@@ -1,11 +0,0 @@
<div class="row">
<div class="columns large-12">
<h1>error page</h1>
</div>
</div>
<div class="row">
<div class="columns large-12">
<span>Error {{ error }} getting doorman {{ id }}</span>
</div>
</div>
-13
View File
@@ -1,13 +0,0 @@
<div class="row">
<div class="columns large-12">
<h1>doormen</h1>
</div>
</div>
<div class="row">
<div class="columns large-12">
<ul>
<li ng-repeat="doorman in doormen"> <a href="#/doormen/{{ doorman.id }}"> {{ doorman.name }} </a></li>
</ul>
</div>
</div>
-31
View File
@@ -1,31 +0,0 @@
<div class="row">
<div class="columns large-12">
<h1>Welcome to the world best a/b testing library</h1>
</div>
</div>
<div class="row">
<form ng-submit="login()" >
<fieldset>
<legend>Login</legend>
<div class="large-12 columns">
<div class="row collapse">
<div class="small-10 columns">
<input type="text" placeholder="email" ng-model="email">
</div>
<div class="small-2 columns">
<button type="submit" class="button postfix" >Login!</input>
</div>
</div>
</div>
</fieldset>
<form>
</div>
<div class="row" ng-show="loggedEmail">
<div class="large-12 columns">
You are currently logged in as <code ng-bind="loggedEmail"></code>
</div>
</div>
-101
View File
@@ -1,101 +0,0 @@
<div class="row">
<div class="columns large-12">
<h1>new doorman</h1>
</div>
</div>
<div class="row">
<div class="columns large-12">
<label >name<input type="text" placeholder="unique doorman name" ng-model="payload.name"></label>
</div>
</div>
<div class="row">
<div class="columns large-12">
<fieldset>
<legend>doorman state</legend>
<div class="row">
<div class="columns large-8">
<label >name<input type="text" placeholder="value name" ng-model="value.name"></label>
</div>
<div class="columns large-3">
<label >probability
<rat-input ng-model="value.probability"></rat-input>
</label>
</div>
<div class="columns large-1">
<br>
<a class="button round tiny" ng-class="{disabled: !isValidValue()}" ng-click="addNewValue()">
<i class="fa fa-plus"></i>
</a>
</div>
</div>
<div class="row" ng-repeat="value in payload.values | reverse">
<div class="columns large-8">
<label >value<input type="text" placeholder="value name" ng-model="value.name"></label>
</div>
<div class="columns large-3">
<label >probability
<rat-input ng-model="value.probability"></rat-input>
</label>
</div>
<div class="columns large-1">
<br>
<a class="button round tiny" ng-click="removeValue( payload.values.length - $index - 1 )">
<i class="fa fa-times"></i>
</a>
</div>
</div>
</fieldset>
</div>
</div>
<div class="row">
<div class="columns large-12">
<fieldset>
<legend>administrator</legend>
<div class="row">
<div class="columns large-11">
<label>admin email <input type="text" placeholder="admin email" ng-model="newEmail"></label>
</div>
<div class="columns large-1">
<br><a class="button round tiny" ng-click="addEmail()" ng-class="{disabled: !newEmail}">
<i class="fa fa-plus"></i>
</a>
</div>
</div>
<div class="row" ng-repeat="email in payload.emails | reverse">
<div class="columns large-11">
<label>admin email <input type="text" ng-disabled="email==user" placeholder="wild cards are allow here" ng-model="email"></label>
</div>
<div class="columns large-1">
<br><a class="button round tiny" ng-click="removeEmail(payload.emails.length - $index -1)" ng-disabled="email==user? 'disabled' : ''">
<i class="fa fa-times"></i>
</a>
</div>
</div>
</fieldset>
</div>
</div>
<div class="row" ng-show="error">
<div class="columns large-12">
<code style="width:100%; height:100%; display:block; margin-bottom: 1em;">{{ error }}</code>
</div>
</div>
<div class="row">
<div class="large-9 columns">
<button ng-click="createDoorman()" ng-class="{disabled: !isDoormanValid()}">create</button>
</div>
<div class="large-3 columns">
<span >propability remaning: {{ getProbabilityRemaining() | ratpp}}</span>
</div>
</div>
-55
View File
@@ -1,55 +0,0 @@
<div class="row">
<div class="columns large-12">
<h1>server specification</h1>
</div>
</div>
<div class="row" ng-show="server.message_queue == 'nanomsg'">
<div class="columns large-12">
<h3>general</h3>
<table style="width:100%;">
<thead>
<tr>
<th >value</th>
<th>key</th>
</tr>
</thead>
<tbody>
<tr>
<td>hostname</td>
<td><code>{{server.hostname}}</code></td>
</tr>
<tr>
<td>port</td>
<td><code>{{server.port}}</code></td>
</tr>
<tr>
<td>go version</td>
<td><code>{{server.go_version}}</code></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="row" ng-show="server.message_queue == 'nanomsg'">
<div class="columns large-12">
<h3>nano msg</h3>
<table style="width:100%;">
<thead>
<tr>
<th >value</th>
<th>key</th>
</tr>
</thead>
<tbody>
<tr>
<td>url</td>
<td><code>{{server.nano_msg.url}}</code></td>
</tr>
</tbody>
</table>
</div>
</div>
-67
View File
@@ -1,67 +0,0 @@
@import "settings";
@import "bourbon";
// @import url(http://fonts.googleapis.com/css?family=Orbitron:400,900,500,700);
@font-face {
font-family: 'Orbitron';
font-style: normal;
font-weight: 400;
src: local('Orbitron-Light'), local('Orbitron-Regular'), url(/scss/font/orbitron/HmnHiRzvcnQr8CjBje6GQvesZW2xOQ-xsNqO47m55DA.woff2) format('woff2'), url(/scss/font/orbitron/94ug0rEgQO_WuI_xKJMFc_esZW2xOQ-xsNqO47m55DA.woff) format('woff');
}
h1, h2{
font-family: 'Orbitron', sans-serif;
}
.wab-sidebar{
background: $ghost;
h1{
text-align: center;
color: $primary-color;
}
}
.wab-apispect{
h2{
text-align: center;
}
}
.rat-input{
.fraction-box{
font-family: monospace;
font-size: 1.3em;
border: 2px;
padding: 0.3em;
box-shadow: 2px 2px 1px #888;
@include border-top-radius(5px);
@include border-bottom-radius(5px);
i{
font-size: 1em;
margin-left: 0.2em;
}
}
.fraction-box:hover{
border: 2px;
padding: 0.3em;
box-shadow: 2px 2px 1px red;
}
.edit{
input{
width: 4em;
height: 2em;
display: inline;
padding: 0px;
padding-left: 0.5em;
}
}
}
.light{
border-style: none;
}
File diff suppressed because it is too large. Load diff
-41
View File
@@ -1,41 +0,0 @@
@import "settings";
@import "foundation";
@import "doorman";
// Or selectively include components
// @import
// "foundation/components/accordion",
// "foundation/components/alert-boxes",
// "foundation/components/block-grid",
// "foundation/components/breadcrumbs",
// "foundation/components/button-groups",
// "foundation/components/buttons",
// "foundation/components/clearing",
// "foundation/components/dropdown",
// "foundation/components/dropdown-buttons",
// "foundation/components/flex-video",
// "foundation/components/forms",
// "foundation/components/grid",
// "foundation/components/inline-lists",
// "foundation/components/joyride",
// "foundation/components/keystrokes",
// "foundation/components/labels",
// "foundation/components/magellan",
// "foundation/components/orbit",
// "foundation/components/pagination",
// "foundation/components/panels",
// "foundation/components/pricing-tables",
// "foundation/components/progress-bars",
// "foundation/components/reveal",
// "foundation/components/side-nav",
// "foundation/components/split-buttons",
// "foundation/components/sub-nav",
// "foundation/components/switch",
// "foundation/components/tables",
// "foundation/components/tabs",
// "foundation/components/thumbs",
// "foundation/components/tooltips",
// "foundation/components/top-bar",
// "foundation/components/type",
// "foundation/components/offcanvas",
// "foundation/components/visibility";