diff options
-rw-r--r-- | .bowerrc | 2 | ||||
-rw-r--r-- | .gitignore | 6 | ||||
-rw-r--r-- | diller-web.js | 12 | ||||
-rw-r--r-- | package.json | 1 | ||||
-rw-r--r-- | src/Diller.js | 3 | ||||
-rw-r--r-- | src/DillerConfig.js | 1 | ||||
-rw-r--r-- | src/DillerDao.js | 8 | ||||
-rw-r--r-- | src/web/DillerWeb.js | 83 | ||||
-rw-r--r-- | web/app/templates/device.html | 21 | ||||
-rw-r--r-- | web/index.html | 24 | ||||
-rw-r--r-- | web/static/app/DillerRpc.js (renamed from web/app/DillerRpc.js) | 10 | ||||
-rw-r--r-- | web/static/app/app.css | 3 | ||||
-rw-r--r-- | web/static/app/app.js (renamed from web/app/app.js) | 18 | ||||
-rw-r--r-- | web/static/app/templates/device.html | 34 | ||||
-rw-r--r-- | web/static/app/templates/front-page.html (renamed from web/app/templates/front-page.html) | 11 | ||||
-rw-r--r-- | web/static/app/templates/property.html (renamed from web/app/templates/property.html) | 6 | ||||
-rw-r--r-- | web/templates/index.jade | 52 | ||||
-rw-r--r-- | web/templates/wat.html | 25 |
18 files changed, 222 insertions, 98 deletions
@@ -1,3 +1,3 @@ { - "directory": "web/bower_components" + "directory": "web/static/bower_components" } @@ -1,3 +1,7 @@ .idea +*.iml + node_modules -web/bower_components +bower_components + +*.pg diff --git a/diller-web.js b/diller-web.js index 4cceaa1..f89755f 100644 --- a/diller-web.js +++ b/diller-web.js @@ -1,3 +1,4 @@ +var fs = require('fs'); var di = require('di'); var injector = new di.Injector(); @@ -6,5 +7,14 @@ config.configureLogging('web'); var dillerWeb = injector.get(require('./src/web/DillerWeb')); dillerWeb.init(); -dillerWeb.generateRpc(); + +if (config.updateDillerRpc) { + var DillerRpc = dillerWeb.generateRpc(); + var orig = fs.readFileSync('web/static/app/DillerRpc.js', {encoding: 'utf-8'}); + if (orig != DillerRpc) { + console.log('DillerRpc updated'); + fs.writeFileSync('web/static/app/DillerRpc.js', DillerRpc); + } +} + dillerWeb.listen(); diff --git a/package.json b/package.json index bfc0373..6f822ad 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "db-migrate": "^0.9.23", "di": "^2.0.0-pre-14", "express": "^4.13.3", + "jade": "^1.11.0", "lodash": "^3.10.1", "mqtt": "^1.4.3", "pg": "^4.4.2", diff --git a/src/Diller.js b/src/Diller.js index a057054..fa2e308 100644 --- a/src/Diller.js +++ b/src/Diller.js @@ -81,7 +81,7 @@ function Diller(config, db) { } if (!f) { - log.warn('Unknown message topic:', topic); + log.warn('Unknown topic:', topic); return; } @@ -107,6 +107,7 @@ function Diller(config, db) { }); }) .then(function (data) { + // log.info('data.device', data.device, 'data.property', data.property); return f(dao, data.device, data.property, message.toString()); }); }).then(function (res) { diff --git a/src/DillerConfig.js b/src/DillerConfig.js index 84afe42..652561a 100644 --- a/src/DillerConfig.js +++ b/src/DillerConfig.js @@ -55,6 +55,7 @@ function configureLogging(app) { function DillerConfig() { return { isProd: isProd, + updateDillerRpc: !isProd(), mqttUrl: mqttUrl, postgresqlConfig: postgresqlConfig, configureLogging: configureLogging, diff --git a/src/DillerDao.js b/src/DillerDao.js index c4d0e67..b46e734 100644 --- a/src/DillerDao.js +++ b/src/DillerDao.js @@ -33,7 +33,7 @@ function DillerDao(tx) { } function devicePropertyByDeviceIdAndKey(deviceId, key) { - return tx.oneOrNone('SELECT id FROM device_property WHERE device=$1 AND key=$2', [deviceId, key]); + return tx.oneOrNone('SELECT ' + propertyColumns + ' FROM device_property WHERE device=$1 AND key=$2', [deviceId, key]); } function devicePropertiesByDeviceId(deviceId) { @@ -41,11 +41,11 @@ function DillerDao(tx) { } function insertDeviceProperty(deviceId, key) { - return tx.oneOrNone('INSERT INTO device_property(id, device, key, created_timestamp) VALUES(DEFAULT, $1, $2, CURRENT_TIMESTAMP) RETURNING ' + propertyColumns, [deviceId, key]); + return tx.one('INSERT INTO device_property(id, device, key, created_timestamp) VALUES(DEFAULT, $1, $2, CURRENT_TIMESTAMP) RETURNING ' + propertyColumns, [deviceId, key]); } function updatePropertyName(id, name) { - return tx.none('UPDATE device_property SET name=$1 WHERE id=$2', name, id); + return tx.none('UPDATE device_property SET name=$1 WHERE id=$2', [name, id]); } function updatePropertyDescription(id, description) { @@ -58,7 +58,7 @@ function DillerDao(tx) { function valuesByPropertyId(propertyId, limit) { limit = limit || 10; - return tx.many('SELECT timestamp, value FROM value WHERE property=$1 LIMIT $2', [propertyId, limit]); + return tx.many('SELECT timestamp, value FROM value WHERE property=$1 ORDER BY timestamp DESC LIMIT $2', [propertyId, limit]); } function insertValue(propertyId, value) { diff --git a/src/web/DillerWeb.js b/src/web/DillerWeb.js index 40fbc3d..a5bdf6b 100644 --- a/src/web/DillerWeb.js +++ b/src/web/DillerWeb.js @@ -59,17 +59,22 @@ function DillerWeb(diller, db, config) { }); } + function getIndex(req, res) { + var baseUrl = (req.headers['trygvis-prefix'] || '').replace(/\/$/, ''); + res.render('index', {baseUrl: baseUrl + '/'}); + } + function init() { app = express(); app.use(bodyParser.urlencoded({extended: true})); app.use(bodyParser.json()); - var router = express.Router(); + var api = express.Router(); - function addRoute(name, method, path, callback) { - router[method](path, callback); - var layer = _.last(router.stack); + function addApi(name, method, path, callback) { + api[method](path, callback); + var layer = _.last(api.stack); calls.push({ name: name, @@ -82,12 +87,21 @@ function DillerWeb(diller, db, config) { }); } - addRoute('getDevices', 'get', '/device', getDevices); - addRoute('getDevice', 'get', '/device/:deviceId', getDevice); - addRoute('getValues', 'get', '/property/:propertyId/values', getValues); + addApi('getDevices', 'get', '/device', getDevices); + addApi('getDevice', 'get', '/device/:deviceId', getDevice); + addApi('getValues', 'get', '/property/:propertyId/values', getValues); + + var templates = express.Router(); - app.use('/api', router); - app.use(express.static('web')); + templates.get('/', getIndex); + + app.set('views', 'web/templates'); + app.set('view engine', 'jade'); + app.set('view cache', false); + + app.use('/api', api); + app.use('/', templates); + app.use(express.static('web/static')); } function listen() { @@ -96,54 +110,59 @@ function DillerWeb(diller, db, config) { } function generateRpc() { - console.log('function DillerRpc($http) {'); + var s = + 'function DillerRpc($http, DillerConfig) {\n' + + ' var baseUrl = DillerConfig.baseUrl;\n' + + '\n'; - var s = _.map(calls, function (call) { + s += _.map(calls, function (call) { //console.error(call); - console.error('call.layer', call.layer); + //console.error('call.layer', call.layer); var s = ' function ' + call.name + '(' + call.keys.join(', ') + ') {\n' + ' var req = {};\n' + ' req.method = \'' + call.method + '\';\n' + - ' req.url = \'/api' + call.path + '\';\n'; + ' req.url = baseUrl + \'/api' + call.path + '\';\n'; s += _.map(call.layer.keys, function (key) { return ' req.url = req.url.replace(/:' + key.name + '/, ' + key.name + ');\n' - }).join(''); + }).join('\n'); s += ' return $http(req);\n' + ' }\n'; return s; - }); - _.each(s, function (x) { - console.log(x); - }); - - console.log(' return {'); - console.log(_.map(calls, function (call) { + }).join('\n'); + s += '\n'; + s += ' return {\n'; + s += _.map(calls, function (call) { return ' ' + call.name + ': ' + call.name - }).join(',\n')); - console.log(' };'); - console.log('}'); - console.log(''); - - console.log('DillerRpcResolve = {};'); - _.each(calls, function (call) { + }).join(',\n'); + s += '\n'; + s += ' };\n'; + s += '}\n'; + s += '\n'; + + s += 'DillerRpcResolve = {};\n'; + s += _.map(calls, function (call) { + var s = ''; var args = ['DillerRpc']; if (call.keys.length > 0) { args.push('$route'); } - console.log('DillerRpcResolve.' + call.name + ' = function(' + args.join(', ') + ') {'); + s += 'DillerRpcResolve.' + call.name + ' = function(' + args.join(', ') + ') {\n'; args = _.map(call.keys, function (key) { return '$route.current.params.' + key; }); - console.log(' return DillerRpc.' + call.name + '(' + args.join(', ') + ');'); - console.log('};'); - }); + s += ' return DillerRpc.' + call.name + '(' + args.join(', ') + ');\n'; + s += '};\n'; + + return s; + }).join(''); + return s; } return { diff --git a/web/app/templates/device.html b/web/app/templates/device.html deleted file mode 100644 index ae028b5..0000000 --- a/web/app/templates/device.html +++ /dev/null @@ -1,21 +0,0 @@ -<div class="container"> - - <h1> - {{ctrl.device.key}} - <small class="text-muted">device</small> - </h1> - - <ul> - <li>Created: {{ctrl.device.created_timestamp | date}}</li> - <li>Name: {{ctrl.property.name}}</li> - <li>Description: {{ctrl.property.description}}</li> - </ul> - - <h3>Properties</h3> - - <ul> - <li ng-repeat="p in ctrl.device.properties | orderBy:'key'"> - <a href="#/device/{{ctrl.device.id}}/property/{{p.id}}">{{p.key}}</a> - </li> - </ul> -</div> diff --git a/web/index.html b/web/index.html deleted file mode 100644 index b591e55..0000000 --- a/web/index.html +++ /dev/null @@ -1,24 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <meta http-equiv="x-ua-compatible" content="ie=edge"> - - <script src="bower_components/jquery/dist/jquery.js" type="application/javascript"></script> - - <script src="bower_components/bootstrap/dist/js/bootstrap.js" type="application/javascript"></script> - <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css"/> - - <script src="bower_components/angular/angular.js" type="application/javascript"></script> - <script src="bower_components/angular-route/angular-route.js" type="application/javascript"></script> - <script src="bower_components/lodash/lodash.js" type="application/javascript"></script> - - <script src="app/DillerRpc.js" type="application/javascript"></script> - <script src="app/app.js" type="application/javascript"></script> - <base href="/"> -</head> -<body ng-app="Diller" ng-view> -Loading Diller ... -</body> -</html> diff --git a/web/app/DillerRpc.js b/web/static/app/DillerRpc.js index a0c20fb..de90aee 100644 --- a/web/app/DillerRpc.js +++ b/web/static/app/DillerRpc.js @@ -1,15 +1,17 @@ -function DillerRpc($http) { +function DillerRpc($http, DillerConfig) { + var baseUrl = DillerConfig.baseUrl; + function getDevices() { var req = {}; req.method = 'get'; - req.url = '/api/device'; + req.url = baseUrl + '/api/device'; return $http(req); } function getDevice(deviceId) { var req = {}; req.method = 'get'; - req.url = '/api/device/:deviceId'; + req.url = baseUrl + '/api/device/:deviceId'; req.url = req.url.replace(/:deviceId/, deviceId); return $http(req); } @@ -17,7 +19,7 @@ function DillerRpc($http) { function getValues(propertyId) { var req = {}; req.method = 'get'; - req.url = '/api/property/:propertyId/values'; + req.url = baseUrl + '/api/property/:propertyId/values'; req.url = req.url.replace(/:propertyId/, propertyId); return $http(req); } diff --git a/web/static/app/app.css b/web/static/app/app.css new file mode 100644 index 0000000..090ac5e --- /dev/null +++ b/web/static/app/app.css @@ -0,0 +1,3 @@ +nav.navbar { + margin-bottom: 2rem; +} diff --git a/web/app/app.js b/web/static/app/app.js index cd14ae5..5274362 100644 --- a/web/app/app.js +++ b/web/static/app/app.js @@ -24,7 +24,7 @@ .when('/', { controller: FrontPageController, controllerAs: 'ctrl', - templateUrl: '/app/templates/front-page.html', + templateUrl: 'app/templates/front-page.html', resolve: { devices: DillerRpcResolve.getDevices } @@ -32,7 +32,7 @@ .when('/device/:deviceId', { controller: DeviceController, controllerAs: 'ctrl', - templateUrl: '/app/templates/device.html', + templateUrl: 'app/templates/device.html', resolve: { device: DillerRpcResolve.getDevice } @@ -40,7 +40,7 @@ .when('/device/:deviceId/property/:propertyId', { controller: PropertyController, controllerAs: 'ctrl', - templateUrl: '/app/templates/property.html', + templateUrl: 'app/templates/property.html', resolve: { device: DillerRpcResolve.getDevice, values: DillerRpcResolve.getValues @@ -53,8 +53,20 @@ //$locationProvider.html5Mode(true); } + function DillerConfig() { + var head = document.getElementsByTagName('head')[0]; + var base = head.getElementsByTagName('base')[0]; + console.log('base =', base); + var baseUrl = base.href.replace(/\/$/, ''); + console.log('baseUrl =', baseUrl); + return { + baseUrl: baseUrl + }; + } + angular .module('Diller', ['ngRoute']) .config(config) + .service('DillerConfig', DillerConfig) .service('DillerRpc', DillerRpc); })(); diff --git a/web/static/app/templates/device.html b/web/static/app/templates/device.html new file mode 100644 index 0000000..b466fdc --- /dev/null +++ b/web/static/app/templates/device.html @@ -0,0 +1,34 @@ +<div class="container"> + + <h1> + {{ctrl.device.key}} + <small class="text-muted">device</small> + </h1> + + <ul> + <li>Created: {{ctrl.device.created_timestamp | date}}</li> + <li>Name: {{ctrl.property.name}}</li> + <li>Description: {{ctrl.property.description}}</li> + </ul> + + <h3>Properties</h3> + + <table class="table"> + <thead> + <tr> + <td>Registered</td> + <td>Key</td> + </tr> + </thead> + <tbody> + <tr ng-repeat="p in ctrl.device.properties | orderBy:'key'"> + <td> + {{p.created_timestamp | date:'medium'}} + </td> + <td> + <a href="#/device/{{ctrl.device.id}}/property/{{p.id}}">{{p.key}}</a> + </td> + </tr> + </tbody> + </table> +</div> diff --git a/web/app/templates/front-page.html b/web/static/app/templates/front-page.html index 1846dea..68026c3 100644 --- a/web/app/templates/front-page.html +++ b/web/static/app/templates/front-page.html @@ -1,21 +1,20 @@ <div class="container"> - <h1> - Diller - <small class="text-muted">All your sensor data are belong to us</small> - </h1> - <h2>Devices</h2> - <table> + <table class="table"> <thead> <tr> + <th>Registered</th> <th>Key</th> </tr> </thead> <tbody> <tr ng-repeat="d in ctrl.devices | orderBy:'key'"> <td> + {{d.created_timestamp | date:'medium'}} + </td> + <td> <a href="#/device/{{d.id}}">{{d.key}}</a> </td> </tr> diff --git a/web/app/templates/property.html b/web/static/app/templates/property.html index 65a66e8..5f925e7 100644 --- a/web/app/templates/property.html +++ b/web/static/app/templates/property.html @@ -31,6 +31,12 @@ <td>{{v.value}}</td> </tr> </tbody> + <tbody> + <tr ng-repeat="v in ctrl.values"> + <td>{{v.timestamp | date:'medium'}}</td> + <td>{{v.value}}</td> + </tr> + </tbody> </table> </div> diff --git a/web/templates/index.jade b/web/templates/index.jade new file mode 100644 index 0000000..025354e --- /dev/null +++ b/web/templates/index.jade @@ -0,0 +1,52 @@ +doctype html + +html(lang='en') + head + meta(charset='utf-8') + meta(name="viewport", content="width=device-width, initial-scale=1") + meta(http-equiv="x-ua-compatible", content="ie=edge") + + base(href!=baseUrl) + + script(src="bower_components/jquery/dist/jquery.js", type="application/javascript") + script(src="bower_components/bootstrap/dist/js/bootstrap.js", type="application/javascript") + link(rel="stylesheet", href="bower_components/bootstrap/dist/css/bootstrap.css") + script(src="bower_components/angular/angular.js", type="application/javascript") + script(src="bower_components/angular-route/angular-route.js", type="application/javascript") + script(src="bower_components/lodash/lodash.js", type="application/javascript") + + script(src="app/DillerRpc.js", type="application/javascript") + script(src="app/app.js", type="application/javascript") + link(href="app/app.css", rel="stylesheet") + + body(ng-app="Diller") + .container + nav.navbar.navbar-dark.bg-inverse + a.navbar-brand(href='#/') Diller + ul.nav.navbar-nav + li.nav-item + a.nav-link(href='#/') Devices + + // + <nav class="navbar navbar-light bg-faded"> + <a class="navbar-brand" href="#">Navbar</a> + <ul class="nav navbar-nav"> + <li class="nav-item active"> + <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a> + </li> + <li class="nav-item"> + <a class="nav-link" href="#">Features</a> + </li> + <li class="nav-item"> + <a class="nav-link" href="#">Pricing</a> + </li> + <li class="nav-item"> + <a class="nav-link" href="#">About</a> + </li> + </ul> + <form class="form-inline navbar-form pull-right"> + <input class="form-control" type="text" placeholder="Search"> + <button class="btn btn-success-outline" type="submit">Search</button> + </form> + </nav> + span(ng-view) Loading Diller ... diff --git a/web/templates/wat.html b/web/templates/wat.html new file mode 100644 index 0000000..fd504a7 --- /dev/null +++ b/web/templates/wat.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <meta http-equiv="x-ua-compatible" content="ie=edge"> + <base href="/diller/"> + + <base href="/"> + <script src="./bower_components/jquery/dist/jquery.js" type="application/javascript"></script> + + <script src="./bower_components/bootstrap/dist/js/bootstrap.js" type="application/javascript"></script> + <link rel="stylesheet" href="./bower_components/bootstrap/dist/css/bootstrap.css"/> + + <script src="./bower_components/angular/angular.js" type="application/javascript"></script> + <script src="./bower_components/angular-route/angular-route.js" type="application/javascript"></script> + <script src="./bower_components/lodash/lodash.js" type="application/javascript"></script> + + <script src="../static/app/DillerRpc.js" type="application/javascript"></script> + <script src="../static/app/app.js" type="application/javascript"></script> +</head> +<body ng-app="Diller" ng-view> +Loading Diller ... +</body> +</html> |