aboutsummaryrefslogtreecommitdiff
path: root/web/app
diff options
context:
space:
mode:
Diffstat (limited to 'web/app')
-rw-r--r--web/app/Application.js3
-rw-r--r--web/app/controller/Root.js3
-rw-r--r--web/app/model/Device.js5
-rw-r--r--web/app/model/Group.js31
-rw-r--r--web/app/model/Position.js9
-rw-r--r--web/app/store/AllGroups.js28
-rw-r--r--web/app/store/Groups.js28
-rw-r--r--web/app/view/DeviceDialog.js9
-rw-r--r--web/app/view/Devices.js47
-rw-r--r--web/app/view/DevicesController.js66
-rw-r--r--web/app/view/GroupDialog.js43
-rw-r--r--web/app/view/Groups.js44
-rw-r--r--web/app/view/GroupsController.js63
-rw-r--r--web/app/view/MapController.js44
-rw-r--r--web/app/view/Register.js2
-rw-r--r--web/app/view/SettingsMenu.js3
-rw-r--r--web/app/view/SettingsMenuController.js11
-rw-r--r--web/app/view/UserDevices.js8
-rw-r--r--web/app/view/UserDevicesController.js4
-rw-r--r--web/app/view/UserDialog.js2
-rw-r--r--web/app/view/UserGroups.js44
-rw-r--r--web/app/view/UserGroupsController.js79
-rw-r--r--web/app/view/Users.js7
-rw-r--r--web/app/view/UsersController.js13
24 files changed, 536 insertions, 60 deletions
diff --git a/web/app/Application.js b/web/app/Application.js
index fc4344a08..69ce8f891 100644
--- a/web/app/Application.js
+++ b/web/app/Application.js
@@ -26,6 +26,7 @@ Ext.define('Traccar.Application', {
models: [
'Server',
'User',
+ 'Group',
'Device',
'Position',
'Attribute',
@@ -33,7 +34,9 @@ Ext.define('Traccar.Application', {
],
stores: [
+ 'Groups',
'Devices',
+ 'AllGroups',
'AllDevices',
'Positions',
'LatestPositions',
diff --git a/web/app/controller/Root.js b/web/app/controller/Root.js
index 23ca94972..5bd567619 100644
--- a/web/app/controller/Root.js
+++ b/web/app/controller/Root.js
@@ -73,6 +73,7 @@ Ext.define('Traccar.controller.Root', {
},
loadApp: function () {
+ Ext.getStore('Groups').load();
Ext.getStore('Devices').load();
Ext.get('attribution').remove();
if (this.isPhone) {
@@ -86,7 +87,7 @@ Ext.define('Traccar.controller.Root', {
asyncUpdate: function (first) {
var protocol, socket, self = this;
protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
- socket = new WebSocket(protocol + window.location.host + '/api/socket');
+ socket = new WebSocket(protocol + '//' + window.location.host + '/api/socket');
socket.onclose = function (event) {
self.asyncUpdate(false);
diff --git a/web/app/model/Device.js b/web/app/model/Device.js
index b8434d6ad..588d53c1f 100644
--- a/web/app/model/Device.js
+++ b/web/app/model/Device.js
@@ -33,6 +33,9 @@ Ext.define('Traccar.model.Device', {
}, {
name: 'lastUpdate',
type: 'date',
- dateWriteFormat: 'c'
+ dateFormat: 'c'
+ }, {
+ name: 'groupId',
+ type: 'int'
}]
});
diff --git a/web/app/model/Group.js b/web/app/model/Group.js
new file mode 100644
index 000000000..a28897feb
--- /dev/null
+++ b/web/app/model/Group.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Ext.define('Traccar.model.Group', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'id',
+ type: 'int'
+ }, {
+ name: 'name',
+ type: 'string'
+ }, {
+ name: 'groupId',
+ type: 'int'
+ }]
+});
diff --git a/web/app/model/Position.js b/web/app/model/Position.js
index 365b06115..e559a7eab 100644
--- a/web/app/model/Position.js
+++ b/web/app/model/Position.js
@@ -29,13 +29,16 @@ Ext.define('Traccar.model.Position', {
type: 'int'
}, {
name: 'serverTime',
- type: 'date'
+ type: 'date',
+ dateFormat: 'c'
}, {
name: 'deviceTime',
- type: 'date'
+ type: 'date',
+ dateFormat: 'c'
}, {
name: 'fixTime',
- type: 'date'
+ type: 'date',
+ dateFormat: 'c'
}, {
name: 'valid',
type: 'boolean'
diff --git a/web/app/store/AllGroups.js b/web/app/store/AllGroups.js
new file mode 100644
index 000000000..880ccc8f5
--- /dev/null
+++ b/web/app/store/AllGroups.js
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Ext.define('Traccar.store.AllGroups', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Group',
+
+ proxy: {
+ type: 'rest',
+ url: '/api/groups',
+ extraParams: {
+ all: true
+ }
+ }
+});
diff --git a/web/app/store/Groups.js b/web/app/store/Groups.js
new file mode 100644
index 000000000..938abed64
--- /dev/null
+++ b/web/app/store/Groups.js
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Ext.define('Traccar.store.Groups', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Group',
+
+ proxy: {
+ type: 'rest',
+ url: '/api/groups',
+ writer: {
+ writeAllFields: true
+ }
+ }
+});
diff --git a/web/app/view/DeviceDialog.js b/web/app/view/DeviceDialog.js
index c42af95d0..4a22ca008 100644
--- a/web/app/view/DeviceDialog.js
+++ b/web/app/view/DeviceDialog.js
@@ -29,13 +29,20 @@ Ext.define('Traccar.view.DeviceDialog', {
items: [{
xtype: 'textfield',
name: 'name',
- fieldLabel: Strings.deviceName,
+ fieldLabel: Strings.sharedName,
allowBlank: false
}, {
xtype: 'textfield',
name: 'uniqueId',
fieldLabel: Strings.deviceIdentifier,
allowBlank: false
+ }, {
+ xtype: 'combobox',
+ name: 'groupId',
+ fieldLabel: Strings.groupParent,
+ store: 'Groups',
+ displayField: 'name',
+ valueField: 'id'
}]
}
});
diff --git a/web/app/view/Devices.js b/web/app/view/Devices.js
index 66c4e813b..ebe3ca195 100644
--- a/web/app/view/Devices.js
+++ b/web/app/view/Devices.js
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
*/
Ext.define('Traccar.view.Devices', {
- extend: 'Ext.grid.Panel',
+ extend: 'Ext.tree.Panel',
xtype: 'devicesView',
requires: [
@@ -25,7 +25,17 @@ Ext.define('Traccar.view.Devices', {
],
controller: 'devices',
- store: 'Devices',
+ rootVisible: false,
+ store: {
+ type: 'tree',
+ parentIdProperty: 'groupId',
+ proxy: {
+ type: 'memory',
+ reader: {
+ type: 'json'
+ }
+ }
+ },
title: Strings.deviceTitle,
selType: 'rowmodel',
@@ -53,11 +63,13 @@ Ext.define('Traccar.view.Devices', {
},
listeners: {
- selectionchange: 'onSelectionChange'
+ selectionchange: 'onSelectionChange',
+ beforeselect: 'onBeforeSelect'
},
columns: [{
- text: Strings.deviceName,
+ xtype: 'treecolumn',
+ text: Strings.sharedName,
dataIndex: 'name',
flex: 1
}, {
@@ -65,19 +77,20 @@ Ext.define('Traccar.view.Devices', {
dataIndex: 'lastUpdate',
flex: 1,
renderer: function (value, metaData, record) {
- var status = record.get('status');
- switch (status) {
- case 'online':
- metaData.tdCls = 'status-color-online';
- break;
- case 'offline':
- metaData.tdCls = 'status-color-offline';
- break;
- default:
- metaData.tdCls = 'status-color-unknown';
- break;
+ if (record.get('leaf')) {
+ switch (record.get('status')) {
+ case 'online':
+ metaData.tdCls = 'status-color-online';
+ break;
+ case 'offline':
+ metaData.tdCls = 'status-color-offline';
+ break;
+ default:
+ metaData.tdCls = 'status-color-unknown';
+ break;
+ }
+ return Ext.Date.format(value, Traccar.Style.dateTimeFormat);
}
- return Ext.Date.format(value, Traccar.Style.dateTimeFormat);
}
}]
diff --git a/web/app/view/DevicesController.js b/web/app/view/DevicesController.js
index 8c6c72725..4d8231d94 100644
--- a/web/app/view/DevicesController.js
+++ b/web/app/view/DevicesController.js
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
+ * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,9 +30,54 @@ Ext.define('Traccar.view.DevicesController', {
selectDevice: 'selectDevice',
selectReport: 'selectReport'
}
+ },
+ store: {
+ '#Groups': {
+ datachanged: 'storeUpdate',
+ update: 'storeUpdate'
+ },
+ '#Devices': {
+ datachanged: 'storeUpdate',
+ update: 'storeUpdate'
+ }
}
}
},
+
+ storeUpdate: function () {
+ var nodes = [];
+ Ext.getStore('Groups').each(function (record) {
+ var groupId, node = {
+ id: 'g' + record.get('id'),
+ original: record,
+ name: record.get('name')
+ };
+ groupId = record.get('groupId');
+ if (groupId !== 0) {
+ node.groupId = 'g' + groupId;
+ }
+ nodes.push(node);
+ }, this);
+ Ext.getStore('Devices').each(function (record) {
+ var groupId, node = {
+ id: 'd' + record.get('id'),
+ original: record,
+ name: record.get('name'),
+ status: record.get('status'),
+ lastUpdate: record.get('lastUpdate'),
+ leaf: true
+ };
+ groupId = record.get('groupId');
+ if (groupId !== 0) {
+ node.groupId = 'g' + groupId;
+ }
+ nodes.push(node);
+ }, this);
+ this.getView().getStore().getProxy().setData(nodes);
+ this.getView().getStore().load();
+ this.getView().expandAll();
+ },
+
init: function () {
var readonly = Traccar.app.getServer().get('readonly') && !Traccar.app.getUser().get('admin');
this.lookupReference('toolbarAddButton').setVisible(!readonly);
@@ -43,7 +88,7 @@ Ext.define('Traccar.view.DevicesController', {
onAddClick: function () {
var device, dialog;
device = Ext.create('Traccar.model.Device');
- device.store = this.getView().getStore();
+ device.store = Ext.getStore('Devices');
dialog = Ext.create('Traccar.view.DeviceDialog');
dialog.down('form').loadRecord(device);
dialog.show();
@@ -51,14 +96,14 @@ Ext.define('Traccar.view.DevicesController', {
onEditClick: function () {
var device, dialog;
- device = this.getView().getSelectionModel().getSelection()[0];
+ device = this.getView().getSelectionModel().getSelection()[0].get('original');
dialog = Ext.create('Traccar.view.DeviceDialog');
dialog.down('form').loadRecord(device);
dialog.show();
},
onRemoveClick: function () {
- var device = this.getView().getSelectionModel().getSelection()[0];
+ var device = this.getView().getSelectionModel().getSelection()[0].get('original');
Ext.Msg.show({
title: Strings.deviceDialog,
message: Strings.sharedRemoveConfirm,
@@ -80,7 +125,7 @@ Ext.define('Traccar.view.DevicesController', {
onCommandClick: function () {
var device, command, dialog;
- device = this.getView().getSelectionModel().getSelection()[0];
+ device = this.getView().getSelectionModel().getSelection()[0].get('original');
command = Ext.create('Traccar.model.Command');
command.set('deviceId', device.get('id'));
dialog = Ext.create('Traccar.view.CommandDialog');
@@ -89,17 +134,22 @@ Ext.define('Traccar.view.DevicesController', {
},
onSelectionChange: function (selected) {
- var empty = selected.getCount() === 0;
+ var empty = selected.getCount() === 0 || !this.getView().getSelectionModel().getSelection()[0].get('leaf');
this.lookupReference('toolbarEditButton').setDisabled(empty);
this.lookupReference('toolbarRemoveButton').setDisabled(empty);
this.lookupReference('deviceCommandButton').setDisabled(empty);
if (!empty) {
- this.fireEvent('selectDevice', selected.getLastSelected(), true);
+ this.fireEvent('selectDevice', selected.getLastSelected().get('original'), true);
}
},
+ onBeforeSelect: function (row, record) {
+ return record.get('leaf');
+ },
+
selectDevice: function (device, center) {
- this.getView().getSelectionModel().select([device], false, true);
+ var node = this.getView().getStore().getNodeById('d' + device.get('id'));
+ this.getView().getSelectionModel().select([node], false, true);
},
selectReport: function (position) {
diff --git a/web/app/view/GroupDialog.js b/web/app/view/GroupDialog.js
new file mode 100644
index 000000000..2cca61ef5
--- /dev/null
+++ b/web/app/view/GroupDialog.js
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Ext.define('Traccar.view.GroupDialog', {
+ extend: 'Traccar.view.BaseEditDialog',
+
+ requires: [
+ 'Traccar.view.BaseEditDialogController'
+ ],
+
+ controller: 'baseEditDialog',
+ title: Strings.groupDialog,
+
+ items: {
+ xtype: 'form',
+ items: [{
+ xtype: 'textfield',
+ name: 'name',
+ fieldLabel: Strings.sharedName,
+ allowBlank: false
+ }, {
+ xtype: 'combobox',
+ name: 'groupId',
+ fieldLabel: Strings.groupParent,
+ store: 'Groups',
+ displayField: 'name',
+ valueField: 'id'
+ }]
+ }
+});
diff --git a/web/app/view/Groups.js b/web/app/view/Groups.js
new file mode 100644
index 000000000..8404c59a9
--- /dev/null
+++ b/web/app/view/Groups.js
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Ext.define('Traccar.view.Groups', {
+ extend: 'Ext.grid.Panel',
+ xtype: 'groupsView',
+
+ requires: [
+ 'Traccar.view.GroupsController',
+ 'Traccar.view.EditToolbar'
+ ],
+
+ controller: 'groups',
+ store: 'Groups',
+
+ selType: 'rowmodel',
+
+ tbar: {
+ xtype: 'editToolbar'
+ },
+
+ listeners: {
+ selectionchange: 'onSelectionChange'
+ },
+
+ columns: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ flex: 1
+ }]
+});
diff --git a/web/app/view/GroupsController.js b/web/app/view/GroupsController.js
new file mode 100644
index 000000000..6cc568ea2
--- /dev/null
+++ b/web/app/view/GroupsController.js
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Ext.define('Traccar.view.GroupsController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.groups',
+
+ onAddClick: function () {
+ var group, dialog;
+ group = Ext.create('Traccar.model.Group');
+ group.store = this.getView().getStore();
+ dialog = Ext.create('Traccar.view.GroupDialog');
+ dialog.down('form').loadRecord(group);
+ dialog.show();
+ },
+
+ onEditClick: function () {
+ var group, dialog;
+ group = this.getView().getSelectionModel().getSelection()[0];
+ dialog = Ext.create('Traccar.view.GroupDialog');
+ dialog.down('form').loadRecord(group);
+ dialog.show();
+ },
+
+ onRemoveClick: function () {
+ var group = this.getView().getSelectionModel().getSelection()[0];
+ Ext.Msg.show({
+ title: Strings.groupDialog,
+ message: Strings.sharedRemoveConfirm,
+ buttons: Ext.Msg.YESNO,
+ buttonText: {
+ yes: Strings.sharedRemove,
+ no: Strings.sharedCancel
+ },
+ fn: function (btn) {
+ var store = Ext.getStore('Groups');
+ if (btn === 'yes') {
+ store.remove(group);
+ store.sync();
+ }
+ }
+ });
+ },
+
+ onSelectionChange: function (selected) {
+ var disabled = selected.length > 0;
+ this.lookupReference('toolbarEditButton').setDisabled(disabled);
+ this.lookupReference('toolbarRemoveButton').setDisabled(disabled);
+ }
+});
diff --git a/web/app/view/MapController.js b/web/app/view/MapController.js
index ce420c2ec..918f81390 100644
--- a/web/app/view/MapController.js
+++ b/web/app/view/MapController.js
@@ -113,29 +113,31 @@ Ext.define('Traccar.view.MapController', {
deviceId = position.get('deviceId');
device = Ext.getStore('Devices').findRecord('id', deviceId, 0, false, false, true);
- geometry = new ol.geom.Point(ol.proj.fromLonLat([
- position.get('longitude'),
- position.get('latitude')
- ]));
-
- if (deviceId in this.latestMarkers) {
- marker = this.latestMarkers[deviceId];
- marker.setGeometry(geometry);
- } else {
- marker = new ol.Feature(geometry);
- marker.set('record', device);
- this.latestMarkers[deviceId] = marker;
- this.getView().getLatestSource().addFeature(marker);
-
- style = this.getLatestMarker(this.getDeviceColor(device));
- style.getText().setText(device.get('name'));
- marker.setStyle(style);
- }
+ if (device) {
+ geometry = new ol.geom.Point(ol.proj.fromLonLat([
+ position.get('longitude'),
+ position.get('latitude')
+ ]));
+
+ if (deviceId in this.latestMarkers) {
+ marker = this.latestMarkers[deviceId];
+ marker.setGeometry(geometry);
+ } else {
+ marker = new ol.Feature(geometry);
+ marker.set('record', device);
+ this.latestMarkers[deviceId] = marker;
+ this.getView().getLatestSource().addFeature(marker);
+
+ style = this.getLatestMarker(this.getDeviceColor(device));
+ style.getText().setText(device.get('name'));
+ marker.setStyle(style);
+ }
- marker.getStyle().getImage().setRotation(position.get('course') * Math.PI / 180);
+ marker.getStyle().getImage().setRotation(position.get('course') * Math.PI / 180);
- if (marker === this.selectedMarker && this.followSelected()) {
- this.getView().getMapView().setCenter(marker.getGeometry().getCoordinates());
+ if (marker === this.selectedMarker && this.followSelected()) {
+ this.getView().getMapView().setCenter(marker.getGeometry().getCoordinates());
+ }
}
}
},
diff --git a/web/app/view/Register.js b/web/app/view/Register.js
index 7c2881d62..198e10b8f 100644
--- a/web/app/view/Register.js
+++ b/web/app/view/Register.js
@@ -33,7 +33,7 @@ Ext.define('Traccar.view.Register', {
items: [{
xtype: 'textfield',
name: 'name',
- fieldLabel: Strings.userName,
+ fieldLabel: Strings.sharedName,
allowBlank: false
}, {
xtype: 'textfield',
diff --git a/web/app/view/SettingsMenu.js b/web/app/view/SettingsMenu.js
index c828b37af..1ada94359 100644
--- a/web/app/view/SettingsMenu.js
+++ b/web/app/view/SettingsMenu.js
@@ -32,6 +32,9 @@ Ext.define('Traccar.view.SettingsMenu', {
text: Strings.settingsUser,
handler: 'onUserClick'
}, {
+ text: Strings.settingsGroups,
+ handler: 'onGroupsClick'
+ }, {
text: Strings.settingsServer,
hidden: true,
handler: 'onServerClick',
diff --git a/web/app/view/SettingsMenuController.js b/web/app/view/SettingsMenuController.js
index c52f0a75e..6d767e3a9 100644
--- a/web/app/view/SettingsMenuController.js
+++ b/web/app/view/SettingsMenuController.js
@@ -23,6 +23,7 @@ Ext.define('Traccar.view.SettingsMenuController', {
'Traccar.view.UserDialog',
'Traccar.view.ServerDialog',
'Traccar.view.Users',
+ 'Traccar.view.Groups',
'Traccar.view.BaseWindow'
],
@@ -39,6 +40,16 @@ Ext.define('Traccar.view.SettingsMenuController', {
dialog.show();
},
+ onGroupsClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.settingsGroups,
+ modal: false,
+ items: {
+ xtype: 'groupsView'
+ }
+ }).show();
+ },
+
onServerClick: function () {
var dialog = Ext.create('Traccar.view.ServerDialog');
dialog.down('form').loadRecord(Traccar.app.getServer());
diff --git a/web/app/view/UserDevices.js b/web/app/view/UserDevices.js
index f9ab48266..fe16dd93a 100644
--- a/web/app/view/UserDevices.js
+++ b/web/app/view/UserDevices.js
@@ -37,10 +37,12 @@ Ext.define('Traccar.view.UserDevices', {
},
columns: [{
- text: Strings.deviceName,
- dataIndex: 'name', flex: 1
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ flex: 1
}, {
text: Strings.deviceIdentifier,
- dataIndex: 'uniqueId', flex: 1
+ dataIndex: 'uniqueId',
+ flex: 1
}]
});
diff --git a/web/app/view/UserDevicesController.js b/web/app/view/UserDevicesController.js
index 4f013fd64..e5dbbdbb8 100644
--- a/web/app/view/UserDevicesController.js
+++ b/web/app/view/UserDevicesController.js
@@ -47,7 +47,7 @@ Ext.define('Traccar.view.UserDevicesController', {
onBeforeSelect: function (object, record, index) {
Ext.Ajax.request({
scope: this,
- url: '/api/permissions',
+ url: '/api/permissions/devices',
jsonData: {
userId: this.userId,
deviceId: record.getData().id
@@ -64,7 +64,7 @@ Ext.define('Traccar.view.UserDevicesController', {
Ext.Ajax.request({
scope: this,
method: 'DELETE',
- url: '/api/permissions',
+ url: '/api/permissions/devices',
jsonData: {
userId: this.userId,
deviceId: record.getData().id
diff --git a/web/app/view/UserDialog.js b/web/app/view/UserDialog.js
index 783ddd159..c1ed2fece 100644
--- a/web/app/view/UserDialog.js
+++ b/web/app/view/UserDialog.js
@@ -30,7 +30,7 @@ Ext.define('Traccar.view.UserDialog', {
items: [{
xtype: 'textfield',
name: 'name',
- fieldLabel: Strings.userName
+ fieldLabel: Strings.sharedName
}, {
xtype: 'textfield',
name: 'email',
diff --git a/web/app/view/UserGroups.js b/web/app/view/UserGroups.js
new file mode 100644
index 000000000..cb0f0bd5d
--- /dev/null
+++ b/web/app/view/UserGroups.js
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Ext.define('Traccar.view.UserGroups', {
+ extend: 'Ext.grid.Panel',
+ xtype: 'userGroupsView',
+
+ requires: [
+ 'Traccar.view.UserGroupsController'
+ ],
+
+ controller: 'userGroups',
+ store: 'AllGroups',
+
+ selModel: {
+ selType: 'checkboxmodel',
+ checkOnly: true,
+ showHeaderCheckbox: false
+ },
+
+ listeners: {
+ beforedeselect: 'onBeforeDeselect',
+ beforeselect: 'onBeforeSelect'
+ },
+
+ columns: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ flex: 1
+ }]
+});
diff --git a/web/app/view/UserGroupsController.js b/web/app/view/UserGroupsController.js
new file mode 100644
index 000000000..662508f0a
--- /dev/null
+++ b/web/app/view/UserGroupsController.js
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Ext.define('Traccar.view.UserGroupsController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.userGroups',
+
+ init: function () {
+ this.userId = this.getView().user.getData().id;
+ this.getView().getStore().load({
+ scope: this,
+ callback: function (records, operation, success) {
+ var userStore = Ext.create('Traccar.store.Groups');
+
+ userStore.load({
+ params: {
+ userId: this.userId
+ },
+ scope: this,
+ callback: function (records, operation, success) {
+ var i, index;
+ if (success) {
+ for (i = 0; i < records.length; i++) {
+ index = this.getView().getStore().find('id', records[i].getData().id);
+ this.getView().getSelectionModel().select(index, true, true);
+ }
+ }
+ }
+ });
+ }
+ });
+ },
+
+ onBeforeSelect: function (object, record, index) {
+ Ext.Ajax.request({
+ scope: this,
+ url: '/api/permissions/groups',
+ jsonData: {
+ userId: this.userId,
+ groupId: record.getData().id
+ },
+ callback: function (options, success, response) {
+ if (!success) {
+ Traccar.app.showError(response);
+ }
+ }
+ });
+ },
+
+ onBeforeDeselect: function (object, record, index) {
+ Ext.Ajax.request({
+ scope: this,
+ method: 'DELETE',
+ url: '/api/permissions/groups',
+ jsonData: {
+ userId: this.userId,
+ groupId: record.getData().id
+ },
+ callback: function (options, success, response) {
+ if (!success) {
+ Traccar.app.showError(response);
+ }
+ }
+ });
+ }
+});
diff --git a/web/app/view/Users.js b/web/app/view/Users.js
index f4ef332b4..408a70885 100644
--- a/web/app/view/Users.js
+++ b/web/app/view/Users.js
@@ -35,6 +35,11 @@ Ext.define('Traccar.view.Users', {
disabled: true,
handler: 'onDevicesClick',
reference: 'userDevicesButton'
+ }, {
+ text: Strings.settingsGroups,
+ disabled: true,
+ handler: 'onGroupsClick',
+ reference: 'userGroupsButton'
}]
},
@@ -43,7 +48,7 @@ Ext.define('Traccar.view.Users', {
},
columns: [{
- text: Strings.userName,
+ text: Strings.sharedName,
dataIndex: 'name',
flex: 1
}, {
diff --git a/web/app/view/UsersController.js b/web/app/view/UsersController.js
index 3d0e813e8..c48f57cf4 100644
--- a/web/app/view/UsersController.js
+++ b/web/app/view/UsersController.js
@@ -21,6 +21,7 @@ Ext.define('Traccar.view.UsersController', {
requires: [
'Traccar.view.UserDialog',
'Traccar.view.UserDevices',
+ 'Traccar.view.UserGroups',
'Traccar.view.BaseWindow'
],
@@ -75,10 +76,22 @@ Ext.define('Traccar.view.UsersController', {
}).show();
},
+ onGroupsClick: function () {
+ var user = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.settingsGroups,
+ items: {
+ xtype: 'userGroupsView',
+ user: user
+ }
+ }).show();
+ },
+
onSelectionChange: function (selected) {
var disabled = selected.length > 0;
this.lookupReference('toolbarEditButton').setDisabled(disabled);
this.lookupReference('toolbarRemoveButton').setDisabled(disabled);
this.lookupReference('userDevicesButton').setDisabled(disabled);
+ this.lookupReference('userGroupsButton').setDisabled(disabled);
}
});