aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Diller.js15
-rw-r--r--src/DillerDao.js28
-rw-r--r--src/web/DillerWeb.js33
-rw-r--r--web/static/app/DillerRpc.js15
-rw-r--r--web/static/app/app.js41
-rw-r--r--web/static/app/templates/device.html13
-rw-r--r--web/static/app/templates/edit-attribute.modal.html (renamed from web/static/app/templates/device-edit-attribute.modal.html)2
-rw-r--r--web/static/app/templates/front-page.html10
-rw-r--r--web/static/app/templates/property.html38
9 files changed, 156 insertions, 39 deletions
diff --git a/src/Diller.js b/src/Diller.js
index 46dc8e2..dc4c5e7 100644
--- a/src/Diller.js
+++ b/src/Diller.js
@@ -21,13 +21,13 @@ function Diller(config, pg, dao) {
function newName(dao, device, property, timestamp, name) {
log.info('New name for property ', device.key + '/' + property.key + '.name = ' + name);
- return dao.updatePropertyName(property.id, name);
+ return dao.updateProperty(property.id, {name: name});
}
function newDescription(dao, device, property, timestamp, description) {
log.info('New description for property ', device.key + '/' + property.key + '.description = ' + description);
- return dao.updatePropertyDescription(property.id, description);
+ return dao.updateProperty(property.id, {description: description});
}
function updateAggregates(propertyId, timestamp) {
@@ -54,6 +54,14 @@ function Diller(config, pg, dao) {
return dao.updateDevice(deviceId, attributes);
}
+ function updatePropertyAttributes(propertyId, attributes) {
+ var x = _.clone(attributes);
+ x.propertyId = propertyId;
+ log.info('Updating property attributes', x);
+
+ return dao.updateProperty(propertyId, attributes);
+ }
+
//noinspection JSUnusedLocalSymbols
function onMessage(topic, message, payload) {
var timestamp = new Date();
@@ -121,7 +129,8 @@ function Diller(config, pg, dao) {
return {
onMessage: onMessage,
- updateDeviceAttributes: updateDeviceAttributes
+ updateDeviceAttributes: updateDeviceAttributes,
+ updatePropertyAttributes: updatePropertyAttributes
}
}
diff --git a/src/DillerDao.js b/src/DillerDao.js
index e7f6b54..63ad3c1 100644
--- a/src/DillerDao.js
+++ b/src/DillerDao.js
@@ -69,12 +69,27 @@ function DillerDao(tx) {
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]);
- }
+ function updateProperty(id, attributes) {
+ var values = [id];
+ var i = 2;
+ var fields = _(attributes).chain()
+ .map(function (value, attribute) {
+ if (attribute == 'name' || attribute == 'description') {
+ value = (value || '').trim();
+ values.push(value.length > 0 ? value : null);
+ return attribute + ' = $' + i++;
+ }
+ })
+ .collect()
+ .join(', ')
+ .value();
+
+ if (fields.length == 0) {
+ return Promise.resolve({});
+ }
- function updatePropertyDescription(id, description) {
- return tx.none('UPDATE device_property SET description=$1 WHERE id=$2', description, id);
+ var sql = 'UPDATE device_property SET ' + fields + ' WHERE id = $1 RETURNING *';
+ return tx.one(sql, values);
}
// -------------------------------------------------------------------------------------------------------------------
@@ -130,8 +145,7 @@ function DillerDao(tx) {
devicePropertyByDeviceIdAndKey: devicePropertyByDeviceIdAndKey,
devicePropertiesByDeviceId: devicePropertiesByDeviceId,
insertDeviceProperty: insertDeviceProperty,
- updatePropertyName: updatePropertyName,
- updatePropertyDescription: updatePropertyDescription,
+ updateProperty: updateProperty,
valuesByPropertyId: valuesByPropertyId,
insertValue: insertValue,
diff --git a/src/web/DillerWeb.js b/src/web/DillerWeb.js
index 3f1d107..03daca7 100644
--- a/src/web/DillerWeb.js
+++ b/src/web/DillerWeb.js
@@ -98,6 +98,37 @@ function DillerWeb(tx, config) {
});
}
+ function patchProperty(req, res) {
+ tx(function (pg, dao, diller) {
+ var propertyId = req.params.propertyId;
+
+ var body = req.body;
+
+ var p;
+ if (!body.attribute) {
+ res.status(400).json({message: 'Required keys: "attribute" and "value".'});
+ } else if (body.attribute == 'name' || body.attribute == 'description') {
+ var attributes = {};
+ attributes[body.attribute] = body.value;
+
+ p = diller.updatePropertyAttributes(propertyId, attributes);
+ } else {
+ p = Promise.reject('Unsupported attribute: ' + body.attribute);
+ }
+
+ return p.then(function (property) {
+ return pg.batch([
+ dao.deviceById(property.device),
+ dao.devicePropertiesByDeviceId(property.device)]
+ );
+ });
+ }).then(function (data) {
+ var device = data[0];
+ device.properties = data[1];
+ res.json({device: device});
+ }, genericErrorHandler(res));
+ }
+
function getIndex(req, res) {
var baseUrl = (req.headers['trygvis-prefix'] || '').replace(/\/$/, '');
res.render('index', {baseUrl: baseUrl + '/'});
@@ -143,7 +174,9 @@ function DillerWeb(tx, config) {
addApi('getDevices', 'get', '/device', getDevices);
addApi('getDevice', 'get', '/device/:deviceId', getDevice);
addApi('patchDevice', 'patch', '/device/:deviceId', patchDevice);
+
addApi('getValues', 'get', '/property/:propertyId/values', getValues);
+ addApi('patchProperty', 'patch', '/property/:propertyId/values', patchProperty);
var templates = express.Router();
diff --git a/web/static/app/DillerRpc.js b/web/static/app/DillerRpc.js
index b1939f4..f865dc5 100644
--- a/web/static/app/DillerRpc.js
+++ b/web/static/app/DillerRpc.js
@@ -33,11 +33,21 @@ function DillerRpc($http, DillerConfig) {
return $http(req);
}
+ function patchProperty(propertyId, payload) {
+ var req = {};
+ req.method = 'patch';
+ req.url = baseUrl + '/api/property/:propertyId/values';
+ req.url = req.url.replace(/:propertyId/, propertyId);
+ req.data = payload;
+ return $http(req);
+ }
+
return {
getDevices: getDevices,
getDevice: getDevice,
patchDevice: patchDevice,
- getValues: getValues
+ getValues: getValues,
+ patchProperty: patchProperty
};
}
@@ -54,3 +64,6 @@ DillerRpcResolve.patchDevice = function(DillerRpc, $route) {
DillerRpcResolve.getValues = function(DillerRpc, $route) {
return DillerRpc.getValues($route.current.params.propertyId);
};
+DillerRpcResolve.patchProperty = function(DillerRpc, $route) {
+ return DillerRpc.patchProperty($route.current.params.propertyId, $route.current.params.payload);
+};
diff --git a/web/static/app/app.js b/web/static/app/app.js
index fa4c4cc..22c7f83 100644
--- a/web/static/app/app.js
+++ b/web/static/app/app.js
@@ -10,7 +10,7 @@
ctrl.device = device.data.device;
- ctrl.propertyChunks = _.chunk(ctrl.device.properties, 3);
+ ctrl.propertyChunks = _(ctrl.device.properties).sortByAll(['name', 'key']).chunk(3).value();
ctrl.editDeviceAttribute = function (attributeName) {
var outer = ctrl;
@@ -18,7 +18,7 @@
controller: function ($uibModalInstance) {
var ctrl = this;
- ctrl.attributeName = attributeName;
+ ctrl.title = 'Edit device ' + attributeName;
ctrl.label = attributeName.substr(0, 1).toUpperCase() + attributeName.substr(1);
ctrl.value = outer.device[attributeName];
@@ -34,16 +34,19 @@
},
controllerAs: 'ctrl',
bindToController: true,
- templateUrl: 'app/templates/device-edit-attribute.modal.html'
+ templateUrl: 'app/templates/edit-attribute.modal.html'
});
}
}
- function PropertyController($timeout, $route, DillerRpc, device, values) {
+ function PropertyController($timeout, $route, $uibModal, DillerRpc, device, values) {
var ctrl = this;
- ctrl.device = device.data.device;
- ctrl.property = _.find(ctrl.device.properties, {id: $route.current.params.propertyId});
+ function updateData(device) {
+ ctrl.device = device.data.device;
+ ctrl.property = _.find(ctrl.device.properties, {id: $route.current.params.propertyId});
+ }
+ updateData(device);
ctrl.values = values.data.values;
var refreshPromise;
@@ -59,6 +62,32 @@
$timeout.cancel(refreshPromise);
})
};
+
+ ctrl.editPropertyAttribute = function (attributeName) {
+ var outer = ctrl;
+ $uibModal.open({
+ controller: function ($uibModalInstance) {
+ var ctrl = this;
+
+ ctrl.title = 'Edit property ' + attributeName;
+ ctrl.label = attributeName.substr(0, 1).toUpperCase() + attributeName.substr(1);
+ ctrl.value = outer.property[attributeName];
+
+ ctrl.update = function () {
+ DillerRpc.patchProperty(outer.property.id, {attribute: attributeName, value: ctrl.value})
+ .then(function (res) {
+ updateData(res);
+ $uibModalInstance.close({});
+ }, function (res) {
+ ctrl.error = res.data.message;
+ });
+ };
+ },
+ controllerAs: 'ctrl',
+ bindToController: true,
+ templateUrl: 'app/templates/edit-attribute.modal.html'
+ });
+ }
}
function TimestampFilter() {
diff --git a/web/static/app/templates/device.html b/web/static/app/templates/device.html
index e3c988d..09452a8 100644
--- a/web/static/app/templates/device.html
+++ b/web/static/app/templates/device.html
@@ -8,12 +8,15 @@
</a>
</h1>
- <p ng-if="ctrl.device.description">
+ <p>
<a ng-click="ctrl.editDeviceAttribute('description')" class="pull-right">
<i class="fa fa-edit"/>
</a>
-
{{ctrl.device.description}}
+
+ <a href ng-if="!ctrl.device.description" ng-click="ctrl.editDeviceAttribute('description')">
+ Edit description
+ </a>
</p>
<!--
@@ -74,7 +77,7 @@
<dt class="col-sm-3">Created</dt>
<dd class="col-sm-9">
- {{ctrl.device.created_timestamp | date}}
+ {{ctrl.device.created_timestamp | date:'medium'}}
&nbsp;
</dd>
</dl>
@@ -90,9 +93,9 @@
</div>
<div class="row" ng-if="ctrl.device.properties.length > 0"
- ng-repeat="chunk in ctrl.propertyChunks | orderBy:'key' track by $index">
+ ng-repeat="chunk in ctrl.propertyChunks">
- <div class="col-sm-4" ng-repeat="p in chunk | orderBy:'key' track by $index">
+ <div class="col-sm-4" ng-repeat="p in chunk">
<div class="card">
<!--
<div class="card-header">
diff --git a/web/static/app/templates/device-edit-attribute.modal.html b/web/static/app/templates/edit-attribute.modal.html
index 2e57f2d..effa08f 100644
--- a/web/static/app/templates/device-edit-attribute.modal.html
+++ b/web/static/app/templates/edit-attribute.modal.html
@@ -3,7 +3,7 @@
<button type="button" class="close" ng-click="$dismiss()">
<span>&times;</span>
</button>
- <h4 class="modal-title">Edit device {{ctrl.attributeName}}</h4>
+ <h4 class="modal-title">{{ctrl.title}}</h4>
</div>
<div class="modal-body">
<fieldset class="form-group">
diff --git a/web/static/app/templates/front-page.html b/web/static/app/templates/front-page.html
index 68026c3..e2ee38b 100644
--- a/web/static/app/templates/front-page.html
+++ b/web/static/app/templates/front-page.html
@@ -5,17 +5,19 @@
<table class="table">
<thead>
<tr>
+ <th>Name</th>
<th>Registered</th>
- <th>Key</th>
</tr>
</thead>
<tbody>
- <tr ng-repeat="d in ctrl.devices | orderBy:'key'">
+ <tr ng-repeat="d in ctrl.devices | orderBy:['name', 'key']">
<td>
- {{d.created_timestamp | date:'medium'}}
+ <a href="#/device/{{d.id}}">
+ {{(d.name || d.key)}}
+ </a>
</td>
<td>
- <a href="#/device/{{d.id}}">{{d.key}}</a>
+ {{d.created_timestamp | date:'medium'}}
</td>
</tr>
</tbody>
diff --git a/web/static/app/templates/property.html b/web/static/app/templates/property.html
index 8cff1f0..969734b 100644
--- a/web/static/app/templates/property.html
+++ b/web/static/app/templates/property.html
@@ -1,24 +1,38 @@
<div class="container">
<h1>
- <a href="#/device/{{ctrl.device.id}}">
- {{(ctrl.device.name || ctrl.device.key)}}
+ <a href="#/device/{{ctrl.device.id}}">{{(ctrl.device.name || ctrl.device.key)}}</a>:
+ {{(ctrl.property.name || ctrl.property.key)}}
+
+ <a ng-click="ctrl.editPropertyAttribute('name')" class="pull-right" style="font-size: 1rem;">
+ <i class="fa fa-edit"/>
</a>
</h1>
- <h2>
- {{(ctrl.property.name || ctrl.property.key)}}
- </h2>
-
- <p ng-show="ctrl.property.description">
+ <p>
+ <a ng-click="ctrl.editPropertyAttribute('description')" class="pull-right">
+ <i class="fa fa-edit"/>
+ </a>
{{ctrl.property.description}}
+
+ <a href ng-if="!ctrl.property.description" ng-click="ctrl.editPropertyAttribute('description')">
+ Edit description
+ </a>
</p>
- <ul>
- <li>Created: {{ctrl.property.created_timestamp | date}}</li>
- <li>Name: {{ctrl.property.name}}</li>
- <li>Description: {{ctrl.property.description}}</li>
- </ul>
+ <dl>
+ <dt class="col-sm-3">Key</dt>
+ <dd class="col-sm-9">
+ {{ctrl.property.key}}
+ &nbsp;
+ </dd>
+
+ <dt class="col-sm-3">Created</dt>
+ <dd class="col-sm-9">
+ {{ctrl.property.created_timestamp | date:'medium'}}
+ &nbsp;
+ </dd>
+ </dl>
<h3>
Latest Values