latest bits

This commit is contained in:
Dobie Wollert
2015-08-03 05:00:22 -04:00
parent 3964ec1321
commit b4e727c0e6
19 changed files with 1054 additions and 699 deletions

View File

@ -1,176 +1,211 @@
var mongoose = require('mongoose'),
Client = mongoose.model('Client'),
Workorder = mongoose.model('Workorder'),
Tag = mongoose.model('Tag');
Client = mongoose.model('Client'),
Workorder = mongoose.model('Workorder'),
Device = mongoose.model('Device'),
Tag = mongoose.model('Tag');
var log = require('log4node');
var frequencies = ["Medical Device","Sterilizer - TT","Vaporizer","Ice Maker","Anesthesia","Waste Management System","Imaging","Medical Gas Systems","RAE","ERT","N2O Trace Gas","Sterilizer - F","Quarterly","Semi","Annual","legacy","DLLR", "Isolation Panel", "Battery Backup", "Sterilizer - Cleaning"];
var frequencies = [
"Medical Device","Sterilizer - TT",
"Vaporizer",
"Ice Maker",
"Anesthesia",
"Waste Management System",
"Imaging",
"Medical Gas Systems",
"RAE",
"ERT",
"N2O Trace Gas",
"Sterilizer - F",
"Quarterly",
"Semi",
"Annual",
"legacy",
"DLLR",
"Isolation Panel",
"Battery Backup",
"Sterilizer - Cleaning"
];
exports.index = function(req, res) {
log.info("clients.index");
var query = Client.find({ deleted: false })
.select('name identifier address')
.slice('contacts', 1)
.sort('name')
.exec(function(err, results) {
if (err) {
res.json(500, err);
} else {
res.json(results);
}
});
log.info("clients.index");
var query = Client.find({ deleted: false })
.select('name identifier address')
.slice('contacts', 1)
.sort('name')
.exec(function(err, results) {
if (err) {
res.json(500, err);
} else {
res.json(results);
}
});
}
exports.get = function(req, res, next) {
var id = req.param('client_id');
var id = req.param('client_id');
log.info("clients.get %s", id);
Client.findById(id)
.exec(function(err, client) {
if (err) return next(err);
if (!client) return next(new Error('Failed to load client ' + id));
log.info("clients.get %s", id);
Client.findById(id)
.exec(function(err, client) {
if (err) return next(err);
if (!client) return next(new Error('Failed to load client ' + id));
res.json(client);
});
res.json(client);
});
}
exports.frequencies = function(req, res, next) {
log.info("clients.frequencies");
log.info("clients.frequencies");
var query = Client.find({ deleted: false })
.select('name identifier frequencies')
.slice('contacts', 1)
.sort('name')
.exec(function(err, results) {
if (err) {
res.json(500, err);
} else {
res.json(results);
}
});
var query = Client.find({ deleted: false })
.select('name identifier frequencies')
.slice('contacts', 1)
.sort('name')
.exec(function(err, results) {
if (err) {
res.json(500, err);
} else {
res.json(results);
}
});
};
exports.workorders = function(req, res, next) {
var id = req.param('client_id');
log.info("clients.workorders %s", id);
var id = req.param('client_id');
log.info("clients.workorders %s", id);
Workorder.find({ client: id, deleted: false })
.populate({path: 'techs', select: 'name'})
.sort('-scheduling.start')
.exec(function(err, workorders) {
if (err) return next(err);
if (!workorders) return next(new Error('Failed to load workorders ' + id));
Workorder.find({ client: id, deleted: false })
.populate({path: 'techs', select: 'name'})
.sort('-scheduling.start')
.exec(function(err, workorders) {
if (err) return next(err);
if (!workorders) return next(new Error('Failed to load workorders ' + id));
res.json(workorders);
});
res.json(workorders);
});
};
exports.tags = function(req, res, next) {
var id = req.param('client_id');
log.info("clients.tags %s", id);
var id = req.param('client_id');
log.info("clients.tags %s", id);
Tag.find({ client: id })
.exec(function(err, tags) {
if (err) return next(err);
if (!tags) return next(new Error('Failed to load tags ' + id));
Tag.find({ client: id })
.exec(function(err, tags) {
if (err) return next(err);
if (!tags) return next(new Error('Failed to load tags ' + id));
res.json(tags);
});
res.json(tags);
});
};
exports.devices = function(req, res, next) {
var id = req.param('client_id');
log.info("clients.devices %s", id);
Device.find({client: id, deleted: false })
.populate({path: 'deviceType'})
.exec(function(err, devices) {
if (err) return next(err);
if (!devices) return next(new Error('Failed to load devices ' + id));
res.json(devices);
});
}
exports.create = function(req, res, next) {
log.info("clients.create %j", req.body);
log.info("clients.create %j", req.body);
var client = new Client({
name: req.body.name,
identifier: req.body.identifier.toUpperCase(),
contacts: req.body.contacts,
address: req.body.address,
notes: req.body.notes,
frequencies: {}
});
var client = new Client({
name: req.body.name,
identifier: req.body.identifier.toUpperCase(),
contacts: req.body.contacts,
address: req.body.address,
notes: req.body.notes,
frequencies: {}
});
var freq = {};
var freq = {};
for (key in frequencies) {
client.frequencies[frequencies[key]] = [false, false, false, false, false, false, false, false, false, false, false, false];
}
for (key in frequencies) {
client.frequencies[frequencies[key]] = [false, false, false, false, false, false, false, false, false, false, false, false];
}
return client.save(function(err) {
if (err)
log.error("Error: %s", err);
return client.save(function(err) {
if (err)
log.error("Error: %s", err);
return res.json(client);
})
return res.json(client);
})
};
exports.isUnique = function(req, res, next) {
var field = req.param('field');
var value = req.param('value');
var key = req.param('key');
var field = req.param('field');
var value = req.param('value');
var key = req.param('key');
if (!field || !value) {
return res.json(400, 'missing field or value');
}
if (!field || !value) {
return res.json(400, 'missing field or value');
}
var query = {};
if (field === 'identifier') {
query[field] = value.toUpperCase();
} else {
query[field] = value;
}
var query = {};
if (field === 'identifier') {
query[field] = value.toUpperCase();
} else {
query[field] = value;
}
if (key) {
query['_id'] = { $ne: key };
}
if (key) {
query['_id'] = { $ne: key };
}
Client.find(query)
.exec(function(err, result) {
if (err) return next(err);
res.json({
isUnique: result.length === 0
});
});
Client.find(query)
.exec(function(err, result) {
if (err) return next(err);
res.json({
isUnique: result.length === 0
});
});
};
exports.update = function(req, res, next) {
var id = req.param('client_id');
log.info("clients.update %s %j", id, req.body);
var id = req.param('client_id');
log.info("clients.update %s %j", id, req.body);
return Client.findById(id, function(err, client) {
client.name = req.body.name;
client.identifier = req.body.identifier.toUpperCase();
client.contacts = req.body.contacts;
client.address = req.body.address;
client.frequencies = req.body.frequencies;
client.notes = req.body.notes;
return Client.findById(id, function(err, client) {
client.name = req.body.name;
client.identifier = req.body.identifier.toUpperCase();
client.contacts = req.body.contacts;
client.address = req.body.address;
client.frequencies = req.body.frequencies;
client.notes = req.body.notes;
return client.save(function(err) {
if (err)
log.error("Error: %s", err);
return client.save(function(err) {
if (err)
log.error("Error: %s", err);
return res.json(client);
});
});
return res.json(client);
});
});
};
exports.destroy = function(req, res, next) {
var id = req.param('client_id');
var id = req.param('client_id');
log.info("clients.destroy %s", id);
log.info("clients.destroy %s", id);
return Client.findById(id, function(err, client) {
client.deleted = true;
return Client.findById(id, function(err, client) {
client.deleted = true;
return client.save(function(err) {
if (err)
log.error("Error: %s", err);
return client.save(function(err) {
if (err)
log.error("Error: %s", err);
return res.json(client);
})
});
return res.json(client);
})
});
};

View File

@ -0,0 +1,120 @@
var mongoose = require('mongoose'),
DeviceType = mongoose.model('DeviceType');
var _ = require('lodash');
var md5 = require('MD5');
var log = require('log4node');
exports.index = function(req, res, next) {
log.info('device_types.index');
DeviceType.find({ deleted: false })
.exec(returnResult(res));
};
exports.get = function(req, res, next) {
var id = req.param('device_type_id');
log.info("device_types.get %s", id);
DeviceType.findById(id)
.exec(returnResult(res));
};
exports.categories = function(req, res, next) {
log.info("device_types.categories");
DeviceType.find({ deleted: false })
.select('category')
.exec(mutateResult(res, function(data) {
return _.uniq(_.pluck(data, 'category'));
}));
};
exports.makes = function(req, res, next) {
log.info("device_types.makes");
DeviceType.find({ deleted: false })
.select('make')
.exec(mutateResult(res, function(data) {
return _.uniq(_.pluck(data, 'make'));
}));
};
exports.models = function(req, res, next) {
log.info("device_types.models");
DeviceType.find({ deleted: false })
.select('model')
.exec(mutateResult(res, function(data) {
return _.uniq(_.pluck(data, 'model'));
}));
};
exports.create = function(req, res, next) {
log.info("device_types.create %j", res.body);
var deviceType = new DeviceType(req.body);
deviceType.save(returnResult(res));
};
exports.update = function(req, res, next) {
var id = req.param('device_type_id');
log.info('device_types.update %s %j', id, req.body);
DeviceType.findById(id, function(err, deviceType) {
if (err) {
log.error("Error: %s", err);
res.json(500, err);
} else if (!deviceType) {
res.json(404, 'Unknown DeviceType: %s', id);
} else {
_.assign(deviceType, req.body);
deviceType.save(returnResult(res, deviceType));
}
});
};
exports.upload = function(req, res, next) {
var path = req.files.file.path;
fs.readFile(path, function(err, data) {
var hash = md5(data);
fs.writeFile('/srv/biomed-site/images/devices/' + hash, data, function(err) {
if (err)
log.error("Error: %s", err);
return res.json({
filename: hash
});
});
});
};
function returnResult(res, result) {
return function(err, data) {
if (err) {
log.error("Error: %s", err);
res.json(500, err);
} else {
if (result) {
res.json(result);
} else {
res.json(data);
}
}
}
}
function mutateResult(res, mutator) {
return function(err, results) {
if (err) {
log.error("Error: %s", err);
res.json(500, err);
} else {
res.json(mutator(results));
}
}
}

View File

@ -6,127 +6,93 @@ var md5 = require('MD5');
var log = require('log4node');
exports.index = function(req, res) {
log.info('devices.index');
var query = Device.find({ deleted: false })
.exec(function(err, results) {
if (err) {
res.json(500, err);
} else {
res.json(results);
}
});
exports.index = function(req, res, next) {
log.info('devices.index');
Device.find({ deleted: false })
.exec(returnResult(res));
};
exports.get = function(req, res, next) {
var id = req.param('device_id');
var id = req.param('device_id');
log.info("devices.get %s", id);
Device.findById(id)
.exec(function(err, device) {
if (err) return next(err);
if (!device) return next(new Error('failed to load device ' + id));
log.info("devices.get %s", id);
res.json(device);
});
};
exports.deviceTypes = function(req, res, next) {
log.info("devices.deviceTypes");
var query = Device.find({ deleted: false })
.select('deviceType')
.exec(function(err, results) {
if (err) {
res.json(500, err);
} else {
res.json(_.uniq(_.pluck(results, 'deviceType')));
}
});
};
exports.makes = function(req, res, next) {
log.info("devices.makes");
var query = Device.find({ deleted: false })
.select('make')
.exec(function(err, results) {
if (err) {
res.json(500, err);
} else {
res.json(_.uniq(_.pluck(results, 'make')));
}
});
};
exports.models = function(req, res, next) {
log.info("devices.models");
var query = Device.find({ deleted: false })
.select('model')
.exec(function(err, results) {
if (err) {
res.json(500, err);
} else {
res.json(_.uniq(_.pluck(results, 'model')));
}
});
Device.findById(id)
.exec(returnResult(res));
};
exports.create = function(req, res, next) {
log.info("devices.create %j", res.body);
log.info("devices.create %j", res.body);
var device = new Device({
deviceType: req.body.deviceType,
make: req.body.make,
model: req.body.model,
technicalData: req.body.technicalData,
links: req.body.links,
partsRecommended: req.body.partsRecommended,
images: req.body.images
});
return device.save(function(err) {
if (err)
log.error("Error: %s", err);
return res.json(device);
});
var device = new Device(req.body);
device.save(returnResult(res));
};
exports.update = function(req, res, next) {
var id = req.param('device_id');
log.info('devices.update %s %j', id, req.body);
var id = req.param('device_id');
log.info('devices.update %s %j', id, req.body);
return Device.findById(id, function(err, device) {
device.deviceType = req.body.deviceType;
device.make = req.body.make;
device.model = req.body.model;
device.technicalData = req.body.technicalData;
device.links = req.body.links;
device.partsRecommended = req.body.partsRecommended;
device.images = req.body.images;
return device.save(function(err) {
if (err)
log.error("Error: %s", err);
return res.json(device);
});
});
Device.findById(id, function(err, device) {
if (err) {
log.error("Error: %s", err);
res.json(500, err);
} else if (!device) {
res.json(404, 'Unknown Device: %s', id);
} else {
_.assign(device, req.body);
device.save(returnResult(res, device));
}
});
};
exports.upload = function(req, res, next) {
var path = req.files.file.path;
exports.isUnique = function(req, res, next) {
var field = req.param('field');
var value = req.param('value');
var key = req.param('key');
fs.readFile(path, function(err, data) {
var hash = md5(data);
if (!field || !value) {
return res.json(400, 'missing field or value');
}
fs.writeFile('/srv/biomed-site/images/devices/' + hash, data, function(err) {
if (err)
log.error("Error: %s", err);
var query = {};
query[field] = value;
return res.json({
filename: hash
});
});
});
if (key) {
query['_id'] = { $ne: key };
}
Device.find(query)
.exec(function(err, result) {
if (err) return next(err);
res.json({
isUnique: result.length === 0
});
});
};
function returnResult(res, result) {
return function(err, data) {
if (err) {
log.error("Error: %s", err);
res.json(500, err);
} else {
if (result) {
res.json(result);
} else {
res.json(data);
}
}
}
}
function mutateResult(res, mutator) {
return function(err, results) {
if (err) {
log.error("Error: %s", err);
res.json(500, err);
} else {
res.json(mutator(results));
}
}
}

View File

@ -1,16 +1,17 @@
var mongoose = require('mongoose')
Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var deviceSchema = new Schema({
deviceType: String,
make: String,
model: String,
technicalData: String,
links: String,
partsRecommended: String,
images: [{ type: String }],
deleted: { type: Boolean, default: false }
client: { type: ObjectId, ref: 'Client' },
deviceType: { type: ObjectId, ref: 'DeviceType' },
biomedId: String,
serialNumber: String,
purchaseDate: Date,
warrantyExpiration: Date,
location: String,
deleted: { type: Boolean, default: false }
});
module.exports = mongoose.model('Device', deviceSchema);

16
app/model/deviceType.js Normal file
View File

@ -0,0 +1,16 @@
var mongoose = require('mongoose')
Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var deviceTypeSchema = new Schema({
category: String,
make: String,
model: String,
technicalData: String,
links: String,
partsRecommended: String,
images: [{ type: String }],
deleted: { type: Boolean, default: false }
});
module.exports = mongoose.model('DeviceType', deviceTypeSchema);

View File

@ -60,8 +60,8 @@ html(lang="en", ng-app="biomed", ng-controller="PageCtrl")
a(href='/accounting')
| Accounting
li(data-match-route='/devices.*')
a(href='/devices')
li(data-match-route='/deviceTypes.*')
a(href='/deviceTypes')
| Devices
li(data-match-route='/posts.*', ng-show="accountHasPermission('system.admin')")

View File

@ -19,6 +19,8 @@ module.exports = function(app, auth, piler, calendar, directory, config) {
piler.addJsFile("/js/lib/dropzone.js");
piler.addJsFile("/js/app.js");
piler.addJsFile("/js/controllers.js");
piler.addJsFile("/js/controllers/devices.js");
piler.addJsFile("/js/controllers/deviceTypes.js");
piler.addJsFile("/js/directives.js");
piler.addJsFile("/js/filters.js");
piler.addJsFile("/js/services.js");
@ -47,6 +49,7 @@ module.exports = function(app, auth, piler, calendar, directory, config) {
app.get('/api/clients/:client_id', clients.get);
app.get('/api/clients/:client_id/workorders', clients.workorders);
app.get('/api/clients/:client_id/tags', clients.tags);
app.get('/api/clients/:client_id/devices', clients.devices);
app.post('/api/clients', clients.create);
app.post('/api/clients/:client_id', clients.update);
app.del('/api/clients/:client_id', clients.destroy);
@ -60,14 +63,21 @@ module.exports = function(app, auth, piler, calendar, directory, config) {
var devices = require('../app/controllers/devices');
app.get('/api/devices', devices.index);
app.get('/api/devices/deviceTypes', devices.deviceTypes);
app.get('/api/devices/makes', devices.makes);
app.get('/api/devices/models', devices.models);
app.post('/api/devices/images', devices.upload);
app.get('/api/devices/isUnique', devices.isUnique);
app.get('/api/devices/:device_id', devices.get);
app.post('/api/devices', devices.create);
app.post('/api/devices/:device_id', devices.update);
var deviceTypes = require('../app/controllers/deviceTypes');
app.get('/api/device_types', deviceTypes.index);
app.get('/api/device_types/categories', deviceTypes.categories);
app.get('/api/device_types/makes', deviceTypes.makes);
app.get('/api/device_types/models', deviceTypes.models);
app.post('/api/device_types/images', deviceTypes.upload);
app.get('/api/device_types/:device_type_id', deviceTypes.get);
app.post('/api/device_types', deviceTypes.create);
app.post('/api/device_types/:device_type_id', deviceTypes.update);
var pms = require('../app/controllers/pms');
app.get('/api/pms', pms.index);

View File

@ -61,18 +61,22 @@ angular.module('biomed', ['biomed.filters', 'biomed.services', 'biomed.directive
templateUrl: '/partials/clients/edit.html',
controller: "ClientEditCtrl"
})
.when('/devices', {
templateUrl: '/partials/devices/index.html',
controller: "DeviceIndexCtrl",
.when('/deviceTypes', {
templateUrl: '/partials/deviceTypes/index.html',
controller: "DeviceTypeIndexCtrl",
reloadOnSearch: false
})
.when('/devices/add', {
templateUrl: '/partials/devices/add.html',
controller: "DeviceAddCtrl"
})
.when('/devices/:id', {
templateUrl: '/partials/devices/edit.html',
controller: "DeviceEditCtrl"
.when('/deviceTypes/add', {
templateUrl: '/partials/deviceTypes/add.html',
controller: "DeviceTypeAddCtrl"
})
.when('/deviceTypes/:id', {
templateUrl: '/partials/deviceTypes/edit.html',
controller: "DeviceTypeEditCtrl"
})
.when('/accounting', {
templateUrl: '/partials/accounting/index.html',

View File

@ -588,9 +588,7 @@ angular.module('biomed')
updatePms();
});
$scope.tags = Clients.tags($routeParams, function() {
});
$scope.devices = Clients.devices($routeParams);
$scope.identification = createController();
$scope.address = createController();
@ -705,256 +703,6 @@ angular.module('biomed')
}
})
.controller("DeviceIndexCtrl", function($scope, $filter, $routeParams, Devices, LocationBinder) {
$scope.loading = true;
var allData = Devices.index(function() {
$scope.loading = false;
$scope.filter();
});
var filteredData = [];
var index = 0;
var initialPageSize = 100;
var pageSize = 5;
$scope.canLoad = true;
$scope.$watch('query', function() {
$scope.filter();
});
LocationBinder($scope, ['query']);
$scope.filter = function() {
filteredData = $filter('orderBy')($filter('filter')(allData, $scope.query), $scope.sort.column, $scope.sort.descending);
index = initialPageSize;
$scope.canLoad = true;
$scope.devices = filteredData.slice(0, initialPageSize);
};
$scope.addItems = function() {
$scope.devices = $scope.devices.concat(filteredData.slice(index, index + pageSize));
index += pageSize;
$scope.canLoad = index < filteredData.length;
}
$scope.sort = {
column: 'deviceType',
descending: false
};
$scope.selectedCls = function(column) {
return column == $scope.sort.column && 'sort-' + $scope.sort.descending;
}
$scope.changeSorting = function(column) {
var sort = $scope.sort;
if (sort.column == column) {
sort.descending = !sort.descending;
} else {
sort.column = column;
sort.descending = false;
}
$scope.filter();
};
})
.controller("DeviceAddCtrl", function($scope, Devices, $location, $filter) {
$scope.model = {};
$scope.deviceTypes = Devices.deviceTypes();
$scope.deviceMakes = Devices.makes();
$scope.deviceTypeOpts = {
containerCssClass: 'input-xxlarge',
placeholder: 'Choose a Device Type',
query: function(query) {
var data = $filter('filter')($scope.deviceTypes, query.term);
var results = [];
data.forEach(function(item) {
results.push({id: item, text: item});
});
query.callback({results: results });
},
createSearchChoice: function(term) {
return { id: term, text: term };
}
};
$scope.makeOpts = {
containerCssClass: 'input-xxlarge',
placeholder: 'Choose a Device Make',
query: function(query) {
var data = $filter('filter')($scope.deviceMakes, query.term);
var results = [];
data.forEach(function(item) {
results.push({id: item, text: item});
});
query.callback({results: results });
},
createSearchChoice: function(term) {
return { id: term, text: term };
}
};
var images = {};
$scope.imageOpts = {
options: {
url: '/api/devices/images',
addRemoveLinks: true
},
eventHandlers: {
success: function(file, response) {
file.filename = response.filename;
if (images[file.filename]) {
images[file.filename]++;
this.removeFile(file);
} else {
images[file.filename] = 1;
}
},
removedfile: function(file) {
images[file.filename]--;
if (images[file.filename] <= 0) {
delete images[file.filename];
}
}
}
};
$scope.$watch('deviceTypePicker', function() {
if ($scope.deviceTypePicker) {
$scope.model.deviceType = $scope.deviceTypePicker.id;
} else {
$scope.model.deviceType = null;
}
});
$scope.$watch('makePicker', function() {
if ($scope.makePicker) {
$scope.model.make = $scope.makePicker.id;
} else {
$scope.model.make = null;
}
});
$scope.save = function() {
$scope.model.images = Object.keys(images);
Devices.create($scope.model, function(result) {
// $location.path("/devices/" + result._id);
$location.path("/devices/");
});
};
})
.controller("DeviceEditCtrl", function($scope, Devices, $location, $filter, $routeParams) {
var images = {};
$scope.model = Devices.get($routeParams, function() {
$scope.loading = false;
$scope.existingImages = $scope.model.images;
if ($scope.model.images) {
for (var i = 0; i < $scope.model.images.length; i++) {
images[$scope.model.images[i]] = 1;
}
}
$scope.deviceTypePicker = {id: $scope.model.deviceType, text: $scope.model.deviceType};
$scope.makePicker = {id: $scope.model.make, text: $scope.model.make};
});
$scope.deviceTypes = Devices.deviceTypes();
$scope.deviceMakes = Devices.makes();
$scope.deviceTypeOpts = {
containerCssClass: 'input-xxlarge',
placeholder: 'Choose a Device Type',
query: function(query) {
var data = $filter('filter')($scope.deviceTypes, query.term);
var results = [];
data.forEach(function(item) {
results.push({id: item, text: item});
});
query.callback({results: results });
},
createSearchChoice: function(term) {
return { id: term, text: term };
}
};
$scope.makeOpts = {
containerCssClass: 'input-xxlarge',
placeholder: 'Choose a Device Make',
query: function(query) {
var data = $filter('filter')($scope.deviceMakes, query.term);
var results = [];
data.forEach(function(item) {
results.push({id: item, text: item});
});
query.callback({results: results });
},
createSearchChoice: function(term) {
return { id: term, text: term };
}
};
$scope.imageOpts = {
options: {
url: '/api/devices/images',
addRemoveLinks: true
},
eventHandlers: {
success: function(file, response) {
file.filename = response.filename;
if (images[file.filename]) {
images[file.filename]++;
this.removeFile(file);
} else {
images[file.filename] = 1;
}
},
removedfile: function(file) {
images[file.filename]--;
if (images[file.filename] <= 0) {
delete images[file.filename];
}
}
}
};
$scope.$watch('deviceTypePicker', function() {
if ($scope.deviceTypePicker) {
$scope.model.deviceType = $scope.deviceTypePicker.id;
} else {
$scope.model.deviceType = null;
}
});
$scope.$watch('makePicker', function() {
if ($scope.makePicker) {
$scope.model.make = $scope.makePicker.id;
} else {
$scope.model.make = null;
}
});
$scope.save = function() {
$scope.model.images = Object.keys(images);
Devices.update({id: $scope.model._id}, $scope.model, function(result) {
$location.path("/devices/");
});
};
})
.controller("AccountingIndexCtrl", function($scope, $filter, $routeParams, Workorders, LocationBinder) {
$scope.loading = true;

View File

@ -0,0 +1,251 @@
angular.module('biomed')
.controller("DeviceTypeIndexCtrl", function($scope, $filter, $routeParams, DeviceTypes, LocationBinder) {
$scope.loading = true;
var allData = DeviceTypes.index(function() {
$scope.loading = false;
$scope.filter();
});
var filteredData = [];
var index = 0;
var initialPageSize = 100;
var pageSize = 5;
$scope.canLoad = true;
$scope.$watch('query', function() {
$scope.filter();
});
LocationBinder($scope, ['query']);
$scope.filter = function() {
filteredData = $filter('orderBy')($filter('filter')(allData, $scope.query), $scope.sort.column, $scope.sort.descending);
index = initialPageSize;
$scope.canLoad = true;
$scope.devices = filteredData.slice(0, initialPageSize);
};
$scope.addItems = function() {
$scope.devices = $scope.devices.concat(filteredData.slice(index, index + pageSize));
index += pageSize;
$scope.canLoad = index < filteredData.length;
}
$scope.sort = {
column: 'category',
descending: false
};
$scope.selectedCls = function(column) {
return column == $scope.sort.column && 'sort-' + $scope.sort.descending;
}
$scope.changeSorting = function(column) {
var sort = $scope.sort;
if (sort.column == column) {
sort.descending = !sort.descending;
} else {
sort.column = column;
sort.descending = false;
}
$scope.filter();
};
})
.controller("DeviceTypeAddCtrl", function($scope, DeviceTypes, $location, $filter) {
$scope.model = {};
$scope.categories = DeviceTypes.categories();
$scope.deviceMakes = DeviceTypes.makes();
$scope.categoryOpts = {
containerCssClass: 'input-xxlarge',
placeholder: 'Choose a Device Type',
query: function(query) {
var data = $filter('filter')($scope.categories, query.term);
var results = [];
data.forEach(function(item) {
results.push({id: item, text: item});
});
query.callback({results: results });
},
createSearchChoice: function(term) {
return { id: term, text: term };
}
};
$scope.makeOpts = {
containerCssClass: 'input-xxlarge',
placeholder: 'Choose a Device Make',
query: function(query) {
var data = $filter('filter')($scope.deviceMakes, query.term);
var results = [];
data.forEach(function(item) {
results.push({id: item, text: item});
});
query.callback({results: results });
},
createSearchChoice: function(term) {
return { id: term, text: term };
}
};
var images = {};
$scope.imageOpts = {
options: {
url: '/api/deviceTypes/images',
addRemoveLinks: true
},
eventHandlers: {
success: function(file, response) {
file.filename = response.filename;
if (images[file.filename]) {
images[file.filename]++;
this.removeFile(file);
} else {
images[file.filename] = 1;
}
},
removedfile: function(file) {
images[file.filename]--;
if (images[file.filename] <= 0) {
delete images[file.filename];
}
}
}
};
$scope.$watch('categoryPicker', function() {
if ($scope.categoryPicker) {
$scope.model.category = $scope.categoryPicker.id;
} else {
$scope.model.category = null;
}
});
$scope.$watch('makePicker', function() {
if ($scope.makePicker) {
$scope.model.make = $scope.makePicker.id;
} else {
$scope.model.make = null;
}
});
$scope.save = function() {
$scope.model.images = Object.keys(images);
DeviceTypes.create($scope.model, function(result) {
$location.path("/deviceTypes/");
});
};
})
.controller("DeviceTypeEditCtrl", function($scope, DeviceTypes, $location, $filter, $routeParams) {
var images = {};
$scope.model = DeviceTypes.get($routeParams, function() {
$scope.loading = false;
$scope.existingImages = $scope.model.images;
if ($scope.model.images) {
for (var i = 0; i < $scope.model.images.length; i++) {
images[$scope.model.images[i]] = 1;
}
}
$scope.categoryPicker = {id: $scope.model.category, text: $scope.model.category};
$scope.makePicker = {id: $scope.model.make, text: $scope.model.make};
});
$scope.categories = DeviceTypes.categories();
$scope.deviceMakes = DeviceTypes.makes();
$scope.categoryOpts = {
containerCssClass: 'input-xxlarge',
placeholder: 'Choose a Device Type',
query: function(query) {
var data = $filter('filter')($scope.categories, query.term);
var results = [];
data.forEach(function(item) {
results.push({id: item, text: item});
});
query.callback({results: results });
},
createSearchChoice: function(term) {
return { id: term, text: term };
}
};
$scope.makeOpts = {
containerCssClass: 'input-xxlarge',
placeholder: 'Choose a Device Make',
query: function(query) {
var data = $filter('filter')($scope.deviceMakes, query.term);
var results = [];
data.forEach(function(item) {
results.push({id: item, text: item});
});
query.callback({results: results });
},
createSearchChoice: function(term) {
return { id: term, text: term };
}
};
$scope.imageOpts = {
options: {
url: '/api/deviceTypes/images',
addRemoveLinks: true
},
eventHandlers: {
success: function(file, response) {
file.filename = response.filename;
if (images[file.filename]) {
images[file.filename]++;
this.removeFile(file);
} else {
images[file.filename] = 1;
}
},
removedfile: function(file) {
images[file.filename]--;
if (images[file.filename] <= 0) {
delete images[file.filename];
}
}
}
};
$scope.$watch('categoryPicker', function() {
if ($scope.categoryPicker) {
$scope.model.category = $scope.categoryPicker.id;
} else {
$scope.model.category = null;
}
});
$scope.$watch('makePicker', function() {
if ($scope.makePicker) {
$scope.model.make = $scope.makePicker.id;
} else {
$scope.model.make = null;
}
});
$scope.save = function() {
$scope.model.images = Object.keys(images);
DeviceTypes.update({id: $scope.model._id}, $scope.model, function(result) {
$location.path("/deviceTypes/");
});
};
})

View File

@ -0,0 +1 @@

View File

@ -3,23 +3,24 @@ angular.module('biomed.services', [])
return $resource('/api/clients/:id/:cmd',
{ id: "@id", cmd: "@cmd" },
{
index: { method: 'GET', params: {}, isArray: true },
index: { method: 'GET', params: {}, isArray: true },
frequencies: { method: 'GET', params: { cmd: 'frequencies' }, isArray: true },
get: { method: 'GET', params: { id: 0} },
create: { method: 'POST', params: {} },
update: { method: 'POST', params: { id: 0} },
destroy: { method: 'DELETE', params: { id: 0 } },
get: { method: 'GET', params: { id: 0} },
create: { method: 'POST', params: {} },
update: { method: 'POST', params: { id: 0} },
destroy: { method: 'DELETE', params: { id: 0 } },
workorders: { method: 'GET', params: { id: 0, cmd: 'workorders' }, isArray: true },
devices: { method: 'GET', params: { id: 0, cmd: 'devices' }, isArray: true },
tags: { method: 'GET', params: { id: 0, cmd: 'tags' }, isArray: true },
isUnique: { method: 'GET', params: { cmd: 'isUnique' } },
isUnique: { method: 'GET', params: { cmd: 'isUnique' } },
});
})
.factory("Devices", function($resource) {
return $resource('/api/devices/:id/:cmd',
.factory("DeviceTypes", function($resource) {
return $resource('/api/device_types/:id/:cmd',
{ id: "@id", cmd: "@cmd" },
{
index: { method: 'GET', params: {}, isArray: true },
deviceTypes: { method: 'GET', params: { cmd: 'deviceTypes' }, isArray: true },
categories: { method: 'GET', params: { cmd: 'categories' }, isArray: true },
makes: { method: 'GET', params: { cmd: 'makes' }, isArray: true },
models: { method: 'GET', params: { cmd: 'models' }, isArray: true },
get: { method: 'GET', params: { id: 0} },

View File

@ -8,6 +8,7 @@
<p class="lead">{{master.identifier}}</p>
<a class="btn btn-primary" href="/workorders/add?clientId={{master._id}}" ng-show="accountHasPermission('system.edit')">Work Order</a>
<a class="btn" href="/workorders/add?workorderType=meeting&clientId={{master._id}}" ng-show="accountHasPermission('system.edit')">Meeting</a>
<a class="btn" href="/devices/add?clientId={{master._id}}" ng-show="accountHasPermission('system.edit')">Device</a>
</header>
<div ng-hide="loading" class="tabbable">
<div class="tab-content">
@ -309,17 +310,17 @@
</tr>
</thead>
<tbody>
<tr ng-hide="tags.length"><td colspan="11" class="table-message">There is no information to display.</td></tr>
<tr ng-repeat="tag in tags">
<td><a href="http://n.atlb.co/{{tag._id}}">{{tag.data.clientDeviceId}} - (Tag:{{tag._id}})</a></td>
<td>{{tag.data.device}}</td>
<td>{{tag.data.make}}</td>
<td>{{tag.data.model}}</td>
<td>{{tag.data.serialNumber}}</td>
<td>{{tag.data.purchaseDate}}</td>
<td>{{tag.data.deviceWarrantyExpiration}}</td>
<td>{{tag.data.test}}</td>
<td>{{tag.data.roomNumber}}</td>
<tr ng-hide="devices.length"><td colspan="11" class="table-message">There is no information to display.</td></tr>
<tr ng-repeat="device in devices">
<td><a href="/devices/{{device._id}}">{{device.biomedId}}</a></td>
<td></td>
<td>{{device.deviceType.make}}</td>
<td>{{device.deviceType.model}}</td>
<td>{{device.serialNumber}}</td>
<td>{{device.purchaseDate | date}}</td>
<td>{{device.warrantyExpiration | date}}</td>
<td></td>
<td>{{device.location}}</td>
</tr>
</tbody>
</table>

View File

@ -0,0 +1,80 @@
<ul class="breadcrumb">
<li><a href="/devices"><i class="icon-briefcase"></i> Devices</a><span class="divider"></span><li>
<li class="active">New Device<li>
</ul>
<header>
<h1>New Device</h1>
</header>
<form name="form" class="form">
<div class="form-section">
<div class="section-label">Device Identification</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Device Type</label>
<div class="controls">
<input type="hidden" ng-model="categoryPicker" ui-select2="categoryOpts" />
</div>
</div>
<div class="control-group">
<label class="control-label">Make</label>
<div class="controls">
<input type="hidden" ng-model="makePicker" ui-select2="makeOpts" />
</div>
</div>
<div class="control-group">
<label class="control-label">Model</label>
<div class="controls">
<input ng-model="model.model" type="text" class="input-xlarge">
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">Device Details</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Technical Data</label>
<div class="controls">
<textarea ng-model="model.technicalData" type="text" class="input-xxlarge"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">Links</label>
<div class="controls">
<textarea ng-model="model.links" type="text" class="input-xxlarge"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">Recommended Parts</label>
<div class="controls">
<textarea ng-model="model.partsRecommended" type="text" class="input-xxlarge"></textarea>
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">Images</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Images</label>
<div class="controls">
<div class="dropzone" dropzone="imageOpts"></div>
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">&nbsp;</div>
<div class="section-container">
<button ng-click="save()" ng-disabled="form.$invalid" type="button" class="btn btn-primary">Save</button>
</div>
</div>
</form>

View File

@ -0,0 +1,80 @@
<ul class="breadcrumb">
<li><a href="/devices"><i class="icon-briefcase"></i> Devices</a><span class="divider"></span><li>
<li class="active">Edit Device<li>
</ul>
<header>
<h1>Edit Device</h1>
</header>
<form name="form" class="form">
<div class="form-section">
<div class="section-label">Device Identification</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Device Type</label>
<div class="controls">
<input type="hidden" ng-model="categoryPicker" ui-select2="categoryOpts" />
</div>
</div>
<div class="control-group">
<label class="control-label">Make</label>
<div class="controls">
<input type="hidden" ng-model="makePicker" ui-select2="makeOpts" />
</div>
</div>
<div class="control-group">
<label class="control-label">Model</label>
<div class="controls">
<input ng-model="model.model" type="text" class="input-xlarge">
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">Device Details</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Technical Data</label>
<div class="controls">
<textarea ng-model="model.technicalData" type="text" class="input-xxlarge"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">Links</label>
<div class="controls">
<textarea ng-model="model.links" type="text" class="input-xxlarge"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">Recommended Parts</label>
<div class="controls">
<textarea ng-model="model.partsRecommended" type="text" class="input-xxlarge"></textarea>
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">Images</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Images</label>
<div class="controls">
<div class="dropzone" dropzone="imageOpts" existing="existingImages" prefix="devices/"></div>
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">&nbsp;</div>
<div class="section-container">
<button ng-click="save()" ng-disabled="form.$invalid" type="button" class="btn btn-primary">Save</button>
</div>
</div>
</form>

View File

@ -0,0 +1,41 @@
<ul class="breadcrumb">
<li><a href="/devices"><i class="icon-briefcase"></i> Devices</a><li>
</ul>
<header>
<h1>Devices</h1>
</header>
<div class="row-fluid">
<div class="span12">
<div class="toolbelt">
<a href="/deviceTypes/add" class="btn btn-primary" ng-show="accountHasPermission('system.edit')">Create new Device</a>
<div class="pull-right">
<span class="toolbelt-text">Search:</span>
<div class="input-append">
<input type="text" ng-model="query" class="input-large" placeholder="Search">
<span class="add-on"><i class="icon-search"></i></span>
</div>
</div>
</div>
<table class="biomed-table" infinite-scroll="addItems()" can-load="canLoad" threshold="300">
<thead>
<tr>
<th style="width: 33%" ng-class="selectedCls('category')" ng-click="changeSorting('category')">Device Type</th>
<th style="width: 33%" ng-class="selectedCls('make')" ng-click="changeSorting('make')">Make</th>
<th style="width: 33%" ng-class="selectedCls('model')" ng-click="changeSorting('model')">Model</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-show="loading"><td colspan="4" class="table-loading"><i class="loader"></i></td></tr>
<tr ng-hide="loading || devices.length"><td colspan="4" class="table-message">There is no information to display.</td></tr>
<tr ng-hide="loading" ng-repeat="device in devices">
<td>{{device.category}}</td>
<td>{{device.make}}</td>
<td>{{device.model}}</td>
<td><a href="/deviceTypes/{{device._id}}">Edit</a></td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@ -1,80 +1,80 @@
<ul class="breadcrumb">
<li><a href="/devices"><i class="icon-briefcase"></i> Devices</a><span class="divider"></span><li>
<li class="active">New Device<li>
<li><a href="/devices"><i class="icon-briefcase"></i> Devices</a><span class="divider"></span><li>
<li class="active">New Device<li>
</ul>
<header>
<h1>New Device</h1>
<h1>New Device</h1>
</header>
<form name="form" class="form">
<div class="form-section">
<div class="section-label">Device Identification</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Device Type</label>
<div class="controls">
<input type="hidden" ng-model="deviceTypePicker" ui-select2="deviceTypeOpts" />
</div>
</div>
<div class="control-group">
<label class="control-label">Make</label>
<div class="controls">
<input type="hidden" ng-model="makePicker" ui-select2="makeOpts" />
</div>
</div>
<div class="control-group">
<label class="control-label">Model</label>
<div class="controls">
<input ng-model="model.model" type="text" class="input-xlarge">
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">Device Details</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Technical Data</label>
<div class="controls">
<textarea ng-model="model.technicalData" type="text" class="input-xxlarge"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">Links</label>
<div class="controls">
<textarea ng-model="model.links" type="text" class="input-xxlarge"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">Recommended Parts</label>
<div class="controls">
<textarea ng-model="model.partsRecommended" type="text" class="input-xxlarge"></textarea>
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">Images</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Images</label>
<div class="controls">
<div class="dropzone" dropzone="imageOpts"></div>
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">Device Identifieion</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Device Type</label>
<div class="controls">
<input type="hidden" ng-model="categoryPicker" ui-select2="categoryOpts" />
</div>
</div>
<div class="control-group">
<label class="control-label">Make</label>
<div class="controls">
<input type="hidden" ng-model="makePicker" ui-select2="makeOpts" />
</div>
</div>
<div class="control-group">
<label class="control-label">Model</label>
<div class="controls">
<input type="hidden" ng-model="modelPicker" ui-select2="modelOpts">
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">Device Details</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Technical Data</label>
<div class="controls">
<textarea ng-model="model.technicalData" type="text" class="input-xxlarge"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">Links</label>
<div class="controls">
<textarea ng-model="model.links" type="text" class="input-xxlarge"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">Recommended Parts</label>
<div class="controls">
<textarea ng-model="model.partsRecommended" type="text" class="input-xxlarge"></textarea>
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">Images</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Images</label>
<div class="controls">
<div class="dropzone" dropzone="imageOpts"></div>
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">&nbsp;</div>
<div class="section-container">
<button ng-click="save()" ng-disabled="form.$invalid" type="button" class="btn btn-primary">Save</button>
</div>
</div>
<div class="form-section">
<div class="section-label">&nbsp;</div>
<div class="section-container">
<button ng-click="save()" ng-disabled="form.$invalid" type="button" class="btn btn-primary">Save</button>
</div>
</div>
</form>

View File

@ -1,80 +1,80 @@
<ul class="breadcrumb">
<li><a href="/devices"><i class="icon-briefcase"></i> Devices</a><span class="divider"></span><li>
<li class="active">Edit Device<li>
<li><a href="/devices"><i class="icon-briefcase"></i> Devices</a><span class="divider"></span><li>
<li class="active">Edit Device<li>
</ul>
<header>
<h1>Edit Device</h1>
<h1>Edit Device</h1>
</header>
<form name="form" class="form">
<div class="form-section">
<div class="section-label">Device Identification</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Device Type</label>
<div class="controls">
<input type="hidden" ng-model="deviceTypePicker" ui-select2="deviceTypeOpts" />
</div>
</div>
<div class="control-group">
<label class="control-label">Make</label>
<div class="controls">
<input type="hidden" ng-model="makePicker" ui-select2="makeOpts" />
</div>
</div>
<div class="control-group">
<label class="control-label">Model</label>
<div class="controls">
<input ng-model="model.model" type="text" class="input-xlarge">
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">Device Details</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Technical Data</label>
<div class="controls">
<textarea ng-model="model.technicalData" type="text" class="input-xxlarge"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">Links</label>
<div class="controls">
<textarea ng-model="model.links" type="text" class="input-xxlarge"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">Recommended Parts</label>
<div class="controls">
<textarea ng-model="model.partsRecommended" type="text" class="input-xxlarge"></textarea>
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">Images</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Images</label>
<div class="controls">
<div class="dropzone" dropzone="imageOpts" existing="existingImages" prefix="devices/"></div>
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">Device Identification</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Device Type</label>
<div class="controls">
<input type="hidden" ng-model="categoryPicker" ui-select2="categoryOpts" />
</div>
</div>
<div class="control-group">
<label class="control-label">Make</label>
<div class="controls">
<input type="hidden" ng-model="makePicker" ui-select2="makeOpts" />
</div>
</div>
<div class="control-group">
<label class="control-label">Model</label>
<div class="controls">
<input ng-model="model.model" type="text" class="input-xlarge">
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">Device Details</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Technical Data</label>
<div class="controls">
<textarea ng-model="model.technicalData" type="text" class="input-xxlarge"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">Links</label>
<div class="controls">
<textarea ng-model="model.links" type="text" class="input-xxlarge"></textarea>
</div>
</div>
<div class="control-group">
<label class="control-label">Recommended Parts</label>
<div class="controls">
<textarea ng-model="model.partsRecommended" type="text" class="input-xxlarge"></textarea>
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">Images</div>
<div class="section-container">
<div class="form-editor">
<div class="control-group">
<label class="control-label">Images</label>
<div class="controls">
<div class="dropzone" dropzone="imageOpts" existing="existingImages" prefix="devices/"></div>
</div>
</div>
</div>
</div>
</div>
<div class="form-section">
<div class="section-label">&nbsp;</div>
<div class="section-container">
<button ng-click="save()" ng-disabled="form.$invalid" type="button" class="btn btn-primary">Save</button>
</div>
</div>
<div class="form-section">
<div class="section-label">&nbsp;</div>
<div class="section-container">
<button ng-click="save()" ng-disabled="form.$invalid" type="button" class="btn btn-primary">Save</button>
</div>
</div>
</form>

View File

@ -1,41 +1,41 @@
<ul class="breadcrumb">
<li><a href="/devices"><i class="icon-briefcase"></i> Devices</a><li>
<li><a href="/devices"><i class="icon-briefcase"></i> Devices</a><li>
</ul>
<header>
<h1>Devices</h1>
<h1>Devices</h1>
</header>
<div class="row-fluid">
<div class="span12">
<div class="toolbelt">
<a href="/devices/add" class="btn btn-primary" ng-show="accountHasPermission('system.edit')">Create new Device</a>
<div class="pull-right">
<span class="toolbelt-text">Search:</span>
<div class="input-append">
<input type="text" ng-model="query" class="input-large" placeholder="Search">
<span class="add-on"><i class="icon-search"></i></span>
</div>
</div>
</div>
<table class="biomed-table" infinite-scroll="addItems()" can-load="canLoad" threshold="300">
<thead>
<tr>
<th style="width: 33%" ng-class="selectedCls('deviceType')" ng-click="changeSorting('deviceType')">Device Type</th>
<th style="width: 33%" ng-class="selectedCls('make')" ng-click="changeSorting('make')">Make</th>
<th style="width: 33%" ng-class="selectedCls('model')" ng-click="changeSorting('model')">Model</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-show="loading"><td colspan="4" class="table-loading"><i class="loader"></i></td></tr>
<tr ng-hide="loading || devices.length"><td colspan="4" class="table-message">There is no information to display.</td></tr>
<tr ng-hide="loading" ng-repeat="device in devices">
<td>{{device.deviceType}}</td>
<td>{{device.make}}</td>
<td>{{device.model}}</td>
<td><a href="/devices/{{device._id}}">Edit</a></td>
</tr>
</tbody>
</table>
</div>
<div class="span12">
<div class="toolbelt">
<a href="/devices/add" class="btn btn-primary" ng-show="accountHasPermission('system.edit')">Create new Device</a>
<div class="pull-right">
<span class="toolbelt-text">Search:</span>
<div class="input-append">
<input type="text" ng-model="query" class="input-large" placeholder="Search">
<span class="add-on"><i class="icon-search"></i></span>
</div>
</div>
</div>
<table class="biomed-table" infinite-scroll="addItems()" can-load="canLoad" threshold="300">
<thead>
<tr>
<th style="width: 33%" ng-class="selectedCls('category')" ng-click="changeSorting('category')">Device Type</th>
<th style="width: 33%" ng-class="selectedCls('make')" ng-click="changeSorting('make')">Make</th>
<th style="width: 33%" ng-class="selectedCls('model')" ng-click="changeSorting('model')">Model</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-show="loading"><td colspan="4" class="table-loading"><i class="loader"></i></td></tr>
<tr ng-hide="loading || devices.length"><td colspan="4" class="table-message">There is no information to display.</td></tr>
<tr ng-hide="loading" ng-repeat="device in devices">
<td>{{device.category}}</td>
<td>{{device.make}}</td>
<td>{{device.model}}</td>
<td><a href="/devices/{{device._id}}">Edit</a></td>
</tr>
</tbody>
</table>
</div>
</div>