aboutsummaryrefslogtreecommitdiff
path: root/web/app
diff options
context:
space:
mode:
authorAbyss777 <abyss@fox5.ru>2017-05-10 12:14:44 +0500
committerAbyss777 <abyss@fox5.ru>2017-05-16 13:23:49 +0500
commita6765559b9388cea4ebc056cc207d7fc05206065 (patch)
tree9e9ef8577593c4ec8f5b31d1bfd496681fdf2dc7 /web/app
parente200c1b9fe2f840d0d28836e19abaebb7c33210e (diff)
downloadtrackermap-web-a6765559b9388cea4ebc056cc207d7fc05206065.tar.gz
trackermap-web-a6765559b9388cea4ebc056cc207d7fc05206065.tar.bz2
trackermap-web-a6765559b9388cea4ebc056cc207d7fc05206065.zip
Implement computed attributes
Diffstat (limited to 'web/app')
-rw-r--r--web/app/Application.js4
-rw-r--r--web/app/controller/Root.js1
-rw-r--r--web/app/model/ComputedAttribute.js39
-rw-r--r--web/app/store/AllComputedAttributes.js30
-rw-r--r--web/app/store/ComputedAttributes.js30
-rw-r--r--web/app/view/SettingsMenu.js6
-rw-r--r--web/app/view/SettingsMenuController.js12
-rw-r--r--web/app/view/dialog/ComputedAttribute.js61
-rw-r--r--web/app/view/edit/ComputedAttributes.js58
-rw-r--r--web/app/view/edit/ComputedAttributesController.js31
-rw-r--r--web/app/view/edit/Devices.js8
-rw-r--r--web/app/view/edit/DevicesController.js17
-rw-r--r--web/app/view/edit/Groups.js8
-rw-r--r--web/app/view/edit/GroupsController.js19
-rw-r--r--web/app/view/edit/Users.js7
-rw-r--r--web/app/view/edit/UsersController.js19
-rw-r--r--web/app/view/permissions/DeviceAttributes.js31
-rw-r--r--web/app/view/permissions/GroupAttributes.js31
-rw-r--r--web/app/view/permissions/UserAttributes.js31
19 files changed, 442 insertions, 1 deletions
diff --git a/web/app/Application.js b/web/app/Application.js
index b9d074e4..2a4149df 100644
--- a/web/app/Application.js
+++ b/web/app/Application.js
@@ -83,7 +83,9 @@ Ext.define('Traccar.Application', {
'GeofenceAttributes',
'GroupAttributes',
'ServerAttributes',
- 'UserAttributes'
+ 'UserAttributes',
+ 'ComputedAttributes',
+ 'AllComputedAttributes'
],
controllers: [
diff --git a/web/app/controller/Root.js b/web/app/controller/Root.js
index 4816875f..b69fb0fa 100644
--- a/web/app/controller/Root.js
+++ b/web/app/controller/Root.js
@@ -84,6 +84,7 @@ Ext.define('Traccar.controller.Root', {
Ext.getStore('Geofences').load();
Ext.getStore('Calendars').load();
Ext.getStore('AttributeAliases').load();
+ Ext.getStore('ComputedAttributes').load();
this.initReportEventTypesStore();
Ext.getStore('Devices').load({
scope: this,
diff --git a/web/app/model/ComputedAttribute.js b/web/app/model/ComputedAttribute.js
new file mode 100644
index 00000000..16a78ef1
--- /dev/null
+++ b/web/app/model/ComputedAttribute.js
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+Ext.define('Traccar.model.ComputedAttribute', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'id',
+ type: 'int'
+ }, {
+ name: 'description',
+ type: 'string'
+ }, {
+ name: 'type',
+ type: 'string'
+ }, {
+ name: 'attribute',
+ type: 'string'
+ }, {
+ name: 'expression',
+ type: 'string'
+ }]
+});
diff --git a/web/app/store/AllComputedAttributes.js b/web/app/store/AllComputedAttributes.js
new file mode 100644
index 00000000..e63feb14
--- /dev/null
+++ b/web/app/store/AllComputedAttributes.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+Ext.define('Traccar.store.AllComputedAttributes', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.ComputedAttribute',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/attributes/computed',
+ extraParams: {
+ all: true
+ }
+ }
+});
diff --git a/web/app/store/ComputedAttributes.js b/web/app/store/ComputedAttributes.js
new file mode 100644
index 00000000..33d78298
--- /dev/null
+++ b/web/app/store/ComputedAttributes.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+Ext.define('Traccar.store.ComputedAttributes', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.ComputedAttribute',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/attributes/computed',
+ writer: {
+ writeAllFields: true
+ }
+ }
+});
diff --git a/web/app/view/SettingsMenu.js b/web/app/view/SettingsMenu.js
index 423dc42b..db426bbe 100644
--- a/web/app/view/SettingsMenu.js
+++ b/web/app/view/SettingsMenu.js
@@ -74,6 +74,12 @@ Ext.define('Traccar.view.SettingsMenu', {
reference: 'settingsAttributeAliasesButton'
}, {
hidden: true,
+ text: Strings.sharedComputedAttributes,
+ glyph: 'xf0ae@FontAwesome',
+ handler: 'onComputedAttributesClick',
+ reference: 'settingsComputedAttributesButton'
+ }, {
+ hidden: true,
text: Strings.sharedDeviceDistance,
glyph: 'xf0e4@FontAwesome',
handler: 'onDeviceDistanceClick',
diff --git a/web/app/view/SettingsMenuController.js b/web/app/view/SettingsMenuController.js
index 5fc499ee..2bd4b981 100644
--- a/web/app/view/SettingsMenuController.js
+++ b/web/app/view/SettingsMenuController.js
@@ -28,6 +28,7 @@ Ext.define('Traccar.view.SettingsMenuController', {
'Traccar.view.edit.Geofences',
'Traccar.view.Notifications',
'Traccar.view.edit.AttributeAliases',
+ 'Traccar.view.edit.ComputedAttributes',
'Traccar.view.Statistics',
'Traccar.view.dialog.DeviceDistance',
'Traccar.view.edit.Calendars',
@@ -57,6 +58,7 @@ Ext.define('Traccar.view.SettingsMenuController', {
}
if (admin || (!deviceReadonly && !readonly)) {
this.lookupReference('settingsAttributeAliasesButton').setHidden(false);
+ this.lookupReference('settingsComputedAttributesButton').setHidden(false);
}
},
@@ -127,6 +129,16 @@ Ext.define('Traccar.view.SettingsMenuController', {
}).show();
},
+ onComputedAttributesClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedComputedAttributes,
+ modal: false,
+ items: {
+ xtype: 'computedAttributesView'
+ }
+ }).show();
+ },
+
onStatisticsClick: function () {
Ext.create('Traccar.view.BaseWindow', {
title: Strings.statisticsTitle,
diff --git a/web/app/view/dialog/ComputedAttribute.js b/web/app/view/dialog/ComputedAttribute.js
new file mode 100644
index 00000000..df074919
--- /dev/null
+++ b/web/app/view/dialog/ComputedAttribute.js
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+Ext.define('Traccar.view.dialog.ComputedAttribute', {
+ extend: 'Traccar.view.dialog.BaseEdit',
+
+ title: Strings.sharedComputedAttribute,
+
+ items: {
+ xtype: 'form',
+ items: [{
+ xtype: 'textfield',
+ name: 'description',
+ fieldLabel: Strings.sharedDescription
+ }, {
+ xtype: 'textfield',
+ name: 'attribute',
+ fieldLabel: Strings.sharedAttribute,
+ allowBlank: false
+ }, {
+ xtype: 'textareafield',
+ name: 'expression',
+ fieldLabel: Strings.sharedExpression,
+ allowBlank: false
+ }, {
+ xtype: 'textfield',
+ name: 'type',
+ fieldLabel: Strings.sharedType,
+ allowBlank: false
+ }]
+ },
+
+ buttons: [{
+ glyph: 'xf00c@FontAwesome',
+ tooltip: Strings.sharedSave,
+ tooltipType: 'title',
+ minWidth: 0,
+ handler: 'onSaveClick'
+ }, {
+ glyph: 'xf00d@FontAwesome',
+ tooltip: Strings.sharedCancel,
+ tooltipType: 'title',
+ minWidth: 0,
+ handler: 'closeView'
+ }]
+});
diff --git a/web/app/view/edit/ComputedAttributes.js b/web/app/view/edit/ComputedAttributes.js
new file mode 100644
index 00000000..87d3b8da
--- /dev/null
+++ b/web/app/view/edit/ComputedAttributes.js
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+Ext.define('Traccar.view.edit.ComputedAttributes', {
+ extend: 'Ext.grid.Panel',
+ xtype: 'computedAttributesView',
+
+ requires: [
+ 'Traccar.view.edit.ComputedAttributesController',
+ 'Traccar.view.edit.Toolbar'
+ ],
+
+ controller: 'computedAttributes',
+ store: 'ComputedAttributes',
+
+ tbar: {
+ xtype: 'editToolbar'
+ },
+
+ listeners: {
+ selectionchange: 'onSelectionChange'
+ },
+
+ columns: {
+ defaults: {
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ },
+ items: [{
+ text: Strings.sharedDescription,
+ dataIndex: 'description'
+ }, {
+ text: Strings.sharedAttribute,
+ dataIndex: 'attribute'
+ }, {
+ text: Strings.sharedExpression,
+ dataIndex: 'expression'
+ }, {
+ text: Strings.sharedType,
+ dataIndex: 'type'
+ }]
+ }
+});
diff --git a/web/app/view/edit/ComputedAttributesController.js b/web/app/view/edit/ComputedAttributesController.js
new file mode 100644
index 00000000..6ae14102
--- /dev/null
+++ b/web/app/view/edit/ComputedAttributesController.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+Ext.define('Traccar.view.edit.ComputedAttributesController', {
+ extend: 'Traccar.view.edit.ToolbarController',
+ alias: 'controller.computedAttributes',
+
+ requires: [
+ 'Traccar.view.dialog.ComputedAttribute',
+ 'Traccar.model.ComputedAttribute'
+ ],
+
+ objectModel: 'Traccar.model.ComputedAttribute',
+ objectDialog: 'Traccar.view.dialog.ComputedAttribute',
+ removeTitle: Strings.sharedComputedAttribute
+});
diff --git a/web/app/view/edit/Devices.js b/web/app/view/edit/Devices.js
index b5b6badd..fe3de42c 100644
--- a/web/app/view/edit/Devices.js
+++ b/web/app/view/edit/Devices.js
@@ -75,6 +75,14 @@ Ext.define('Traccar.view.edit.Devices', {
tooltip: Strings.sharedGeofences,
tooltipType: 'title'
}, {
+ xtype: 'button',
+ disabled: true,
+ handler: 'onAttributesClick',
+ reference: 'toolbarAttributesButton',
+ glyph: 'xf0ae@FontAwesome',
+ tooltip: Strings.sharedComputedAttributes,
+ tooltipType: 'title'
+ }, {
disabled: true,
handler: 'onCommandClick',
reference: 'deviceCommandButton',
diff --git a/web/app/view/edit/DevicesController.js b/web/app/view/edit/DevicesController.js
index 0d18c186..2457d5cb 100644
--- a/web/app/view/edit/DevicesController.js
+++ b/web/app/view/edit/DevicesController.js
@@ -23,6 +23,7 @@ Ext.define('Traccar.view.edit.DevicesController', {
'Traccar.view.dialog.Command',
'Traccar.view.dialog.Device',
'Traccar.view.permissions.DeviceGeofences',
+ 'Traccar.view.permissions.DeviceAttributes',
'Traccar.view.BaseWindow',
'Traccar.model.Device',
'Traccar.model.Command'
@@ -77,6 +78,21 @@ Ext.define('Traccar.view.edit.DevicesController', {
}).show();
},
+ onAttributesClick: function () {
+ var device = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedComputedAttributes,
+ items: {
+ xtype: 'deviceAttributesView',
+ baseObjectName: 'deviceId',
+ linkObjectName: 'attributeId',
+ storeName: 'ComputedAttributes',
+ urlApi: 'api/devices/attributes',
+ baseObject: device.getId()
+ }
+ }).show();
+ },
+
onCommandClick: function () {
var device, deviceId, command, dialog, typesStore, online;
device = this.getView().getSelectionModel().getSelection()[0];
@@ -105,6 +121,7 @@ Ext.define('Traccar.view.edit.DevicesController', {
this.lookupReference('toolbarEditButton').setDisabled(empty || readonly || deviceReadonly);
this.lookupReference('toolbarRemoveButton').setDisabled(empty || readonly || deviceReadonly);
this.lookupReference('toolbarGeofencesButton').setDisabled(empty || readonly);
+ this.lookupReference('toolbarAttributesButton').setDisabled(empty || readonly);
this.lookupReference('deviceCommandButton').setDisabled(empty || readonly);
},
diff --git a/web/app/view/edit/Groups.js b/web/app/view/edit/Groups.js
index 43ae8774..88bbd7ba 100644
--- a/web/app/view/edit/Groups.js
+++ b/web/app/view/edit/Groups.js
@@ -37,6 +37,14 @@ Ext.define('Traccar.view.edit.Groups', {
glyph: 'xf21d@FontAwesome',
tooltip: Strings.sharedGeofences,
tooltipType: 'title'
+ }, {
+ xtype: 'button',
+ disabled: true,
+ handler: 'onAttributesClick',
+ reference: 'toolbarAttributesButton',
+ glyph: 'xf0ae@FontAwesome',
+ tooltip: Strings.sharedComputedAttributes,
+ tooltipType: 'title'
}]
},
diff --git a/web/app/view/edit/GroupsController.js b/web/app/view/edit/GroupsController.js
index 36154b4e..602bb095 100644
--- a/web/app/view/edit/GroupsController.js
+++ b/web/app/view/edit/GroupsController.js
@@ -22,6 +22,7 @@ Ext.define('Traccar.view.edit.GroupsController', {
requires: [
'Traccar.view.dialog.Group',
'Traccar.view.permissions.GroupGeofences',
+ 'Traccar.view.permissions.GroupAttributes',
'Traccar.view.BaseWindow',
'Traccar.model.Group'
],
@@ -47,9 +48,27 @@ Ext.define('Traccar.view.edit.GroupsController', {
}).show();
},
+ onAttributesClick: function () {
+ var admin, group;
+ admin = Traccar.app.getUser().get('admin');
+ group = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedComputedAttributes,
+ items: {
+ xtype: 'groupAttributesView',
+ baseObjectName: 'groupId',
+ linkObjectName: 'attributeId',
+ storeName: admin ? 'AllComputedAttributes' : 'ComputedAttributes',
+ urlApi: 'api/groups/attributes',
+ baseObject: group.getId()
+ }
+ }).show();
+ },
+
onSelectionChange: function (selected) {
var disabled = selected.length > 0;
this.lookupReference('toolbarGeofencesButton').setDisabled(disabled);
+ this.lookupReference('toolbarAttributesButton').setDisabled(disabled);
this.callParent(arguments);
}
});
diff --git a/web/app/view/edit/Users.js b/web/app/view/edit/Users.js
index 312ebe24..4356b166 100644
--- a/web/app/view/edit/Users.js
+++ b/web/app/view/edit/Users.js
@@ -75,6 +75,13 @@ Ext.define('Traccar.view.edit.Users', {
glyph: 'xf073@FontAwesome',
tooltip: Strings.sharedCalendars,
tooltipType: 'title'
+ }, {
+ disabled: true,
+ handler: 'onAttributesClick',
+ reference: 'userAttributesButton',
+ glyph: 'xf0ae@FontAwesome',
+ tooltip: Strings.sharedComputedAttributes,
+ tooltipType: 'title'
}]
},
diff --git a/web/app/view/edit/UsersController.js b/web/app/view/edit/UsersController.js
index 88f39fbf..f4ef4012 100644
--- a/web/app/view/edit/UsersController.js
+++ b/web/app/view/edit/UsersController.js
@@ -27,6 +27,7 @@ Ext.define('Traccar.view.edit.UsersController', {
'Traccar.view.permissions.UserGeofences',
'Traccar.view.permissions.UserCalendars',
'Traccar.view.permissions.UserUsers',
+ 'Traccar.view.permissions.UserAttributes',
'Traccar.view.Notifications',
'Traccar.view.BaseWindow',
'Traccar.model.User'
@@ -155,6 +156,23 @@ Ext.define('Traccar.view.edit.UsersController', {
}).show();
},
+ onAttributesClick: function () {
+ var user = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedCalendars,
+ items: {
+ xtype: 'userAttributesView',
+ baseObjectName: 'userId',
+ linkObjectName: 'attributeId',
+ storeName: 'AllComputedAttributes',
+ linkStoreName: 'ComputedAttributes',
+ urlApi: 'api/permissions/attributes',
+ baseObject: user.getId()
+ }
+ }).show();
+ },
+
+
onSelectionChange: function (selection, selected) {
var disabled = selected.length === 0;
this.lookupReference('userDevicesButton').setDisabled(disabled);
@@ -162,6 +180,7 @@ Ext.define('Traccar.view.edit.UsersController', {
this.lookupReference('userGeofencesButton').setDisabled(disabled);
this.lookupReference('userNotificationsButton').setDisabled(disabled);
this.lookupReference('userCalendarsButton').setDisabled(disabled);
+ this.lookupReference('userAttributesButton').setDisabled(disabled);
this.lookupReference('userUsersButton').setDisabled(disabled || selected[0].get('userLimit') === 0);
this.callParent(arguments);
}
diff --git a/web/app/view/permissions/DeviceAttributes.js b/web/app/view/permissions/DeviceAttributes.js
new file mode 100644
index 00000000..43b3d253
--- /dev/null
+++ b/web/app/view/permissions/DeviceAttributes.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+Ext.define('Traccar.view.permissions.DeviceAttributes', {
+ extend: 'Traccar.view.permissions.Base',
+ xtype: 'deviceAttributesView',
+
+ columns: {
+ items: [{
+ text: Strings.sharedDescription,
+ dataIndex: 'description',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ }]
+ }
+});
diff --git a/web/app/view/permissions/GroupAttributes.js b/web/app/view/permissions/GroupAttributes.js
new file mode 100644
index 00000000..10e894d3
--- /dev/null
+++ b/web/app/view/permissions/GroupAttributes.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+Ext.define('Traccar.view.permissions.GroupAttributes', {
+ extend: 'Traccar.view.permissions.Base',
+ xtype: 'groupAttributesView',
+
+ columns: {
+ items: [{
+ text: Strings.sharedDescription,
+ dataIndex: 'description',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ }]
+ }
+});
diff --git a/web/app/view/permissions/UserAttributes.js b/web/app/view/permissions/UserAttributes.js
new file mode 100644
index 00000000..3129ad65
--- /dev/null
+++ b/web/app/view/permissions/UserAttributes.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2017 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+Ext.define('Traccar.view.permissions.UserAttributes', {
+ extend: 'Traccar.view.permissions.Base',
+ xtype: 'userAttributesView',
+
+ columns: {
+ items: [{
+ text: Strings.sharedDescription,
+ dataIndex: 'description',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ }]
+ }
+});