diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | web/app/Application.js | 2 | ||||
-rw-r--r-- | web/app/controller/Root.js | 1 | ||||
-rw-r--r-- | web/app/model/Attribute.js | 3 | ||||
-rw-r--r-- | web/app/model/AttributeAlias.js | 36 | ||||
-rw-r--r-- | web/app/store/AttributeAliases.js | 30 | ||||
-rw-r--r-- | web/app/view/AttributeAliasDialog.js | 51 | ||||
-rw-r--r-- | web/app/view/AttributeAliases.js | 60 | ||||
-rw-r--r-- | web/app/view/AttributeAliasesController.js | 105 | ||||
-rw-r--r-- | web/app/view/BaseMap.js | 6 | ||||
-rw-r--r-- | web/app/view/SettingsMenu.js | 7 | ||||
-rw-r--r-- | web/app/view/SettingsMenuController.js | 14 | ||||
-rw-r--r-- | web/app/view/State.js | 22 | ||||
-rw-r--r-- | web/app/view/StateController.js | 89 | ||||
-rw-r--r-- | web/l10n/en.json | 3 |
15 files changed, 410 insertions, 22 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..52bea8bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.project +.settings + diff --git a/web/app/Application.js b/web/app/Application.js index 62db7bc1..aab9bc8a 100644 --- a/web/app/Application.js +++ b/web/app/Application.js @@ -35,6 +35,7 @@ Ext.define('Traccar.Application', { 'Event', 'Geofence', 'Notification', + 'AttributeAlias', 'ReportSummary', 'ReportTrip' ], @@ -60,6 +61,7 @@ Ext.define('Traccar.Application', { 'Notifications', 'AllNotifications', 'GeofenceTypes', + 'AttributeAliases', 'ReportRoute', 'ReportEvents', 'ReportTrips', diff --git a/web/app/controller/Root.js b/web/app/controller/Root.js index 9cd6fd6d..2807cab9 100644 --- a/web/app/controller/Root.js +++ b/web/app/controller/Root.js @@ -78,6 +78,7 @@ Ext.define('Traccar.controller.Root', { var attribution; Ext.getStore('Groups').load(); Ext.getStore('Geofences').load(); + Ext.getStore('AttributeAliases').load(); Ext.getStore('Devices').load({ scope: this, callback: function () { diff --git a/web/app/model/Attribute.js b/web/app/model/Attribute.js index d30ddf85..b82fecfb 100644 --- a/web/app/model/Attribute.js +++ b/web/app/model/Attribute.js @@ -27,5 +27,8 @@ Ext.define('Traccar.model.Attribute', { }, { name: 'value', type: 'string' + }, { + name: 'attribute', + type: 'string' }] }); diff --git a/web/app/model/AttributeAlias.js b/web/app/model/AttributeAlias.js new file mode 100644 index 00000000..5c7ad68b --- /dev/null +++ b/web/app/model/AttributeAlias.js @@ -0,0 +1,36 @@ +/* + * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com) + * Copyright 2016 Andrey Kunitsyn (abyss@fox5.ru) + * + * 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.AttributeAlias', { + extend: 'Ext.data.Model', + identifier: 'negative', + + fields: [{ + name: 'id', + type: 'int' + }, { + name: 'deviceId', + type: 'int' + }, { + name: 'attribute', + type: 'string' + }, { + name: 'alias', + type: 'string' + }] +}); diff --git a/web/app/store/AttributeAliases.js b/web/app/store/AttributeAliases.js new file mode 100644 index 00000000..ebec8c87 --- /dev/null +++ b/web/app/store/AttributeAliases.js @@ -0,0 +1,30 @@ +/* + * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com) + * Copyright 2016 Andrey Kunitsyn (abyss@fox5.ru) + * + * 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.AttributeAliases', { + extend: 'Ext.data.Store', + model: 'Traccar.model.AttributeAlias', + + proxy: { + type: 'rest', + url: 'api/attributes/aliases', + writer: { + writeAllFields: true + } + } +}); diff --git a/web/app/view/AttributeAliasDialog.js b/web/app/view/AttributeAliasDialog.js new file mode 100644 index 00000000..d86e92d5 --- /dev/null +++ b/web/app/view/AttributeAliasDialog.js @@ -0,0 +1,51 @@ +/* + * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com) + * Copyright 2016 Andrey Kunitsyn (abyss@fox5.ru) + * + * 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.AttributeAliasDialog', { + extend: 'Traccar.view.BaseDialog', + + requires: [ + 'Traccar.view.AttributeController' + ], + + controller: 'attributeDialog', + title: Strings.sharedAttributeAlias, + + items: { + xtype: 'form', + items: [{ + xtype: 'textfield', + name: 'attribute', + fieldLabel: Strings.sharedAttribute, + allowBlank: false + }, { + xtype: 'textfield', + name: 'alias', + fieldLabel: Strings.sharedAlias, + allowBlank: false + }] + }, + + buttons: [{ + text: Strings.sharedSave, + handler: 'onSaveClick' + }, { + text: Strings.sharedCancel, + handler: 'closeView' + }] +}); diff --git a/web/app/view/AttributeAliases.js b/web/app/view/AttributeAliases.js new file mode 100644 index 00000000..182a9cdd --- /dev/null +++ b/web/app/view/AttributeAliases.js @@ -0,0 +1,60 @@ +/* + * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com) + * Copyright 2016 Andrey Kunitsyn (abyss@fox5.ru) + * + * 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.AttributeAliases', { + extend: 'Ext.grid.Panel', + xtype: 'attributeAliasesView', + + requires: [ + 'Traccar.view.AttributeAliasesController', + 'Traccar.view.EditToolbar' + ], + + controller: 'attributeAliases', + + selType: 'rowmodel', + + tbar: { + xtype: 'editToolbar', + items: ['-', { + xtype: 'combobox', + reference: 'deviceField', + store: 'Devices', + displayField: 'name', + valueField: 'id', + typeAhead: true, + listeners: { + change: 'onDeviceChange' + } + }] + }, + + listeners: { + selectionchange: 'onSelectionChange' + }, + + columns: [{ + text: Strings.sharedAttribute, + dataIndex: 'attribute', + flex: 1 + }, { + text: Strings.sharedAlias, + dataIndex: 'alias', + flex: 1 + }] +}); diff --git a/web/app/view/AttributeAliasesController.js b/web/app/view/AttributeAliasesController.js new file mode 100644 index 00000000..6135994e --- /dev/null +++ b/web/app/view/AttributeAliasesController.js @@ -0,0 +1,105 @@ +/* + * Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com) + * Copyright 2016 Andrey Kunitsyn (abyss@fox5.ru) + * + * 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.AttributeAliasesController', { + extend: 'Ext.app.ViewController', + alias: 'controller.attributeAliases', + + requires: [ + 'Traccar.view.AttributeAliasDialog', + 'Traccar.model.AttributeAlias' + ], + + init: function () { + var admin = Traccar.app.getUser().get('admin'); + this.lookupReference('deviceField').setStore(admin ? 'AllDevices' : 'Devices'); + this.lookupReference('toolbarAddButton').setDisabled(true); + this.lookupReference('toolbarEditButton').setDisabled(true); + this.lookupReference('toolbarRemoveButton').setDisabled(true); + this.getView().setStore(Ext.create('Ext.data.ChainedStore', { + storeId: 'EditorAttributeAliases', + source: 'AttributeAliases' + })); + this.getView().getStore().filter('deviceId', 0); + }, + + onAddClick: function () { + var attributeAlias, dialog, deviceId; + attributeAlias = Ext.create('Traccar.model.AttributeAlias'); + attributeAlias.store = Ext.getStore('AttributeAliases'); + deviceId = this.lookupReference('deviceField').getValue(); + attributeAlias.set('deviceId', deviceId); + dialog = Ext.create('Traccar.view.AttributeAliasDialog'); + dialog.down('form').loadRecord(attributeAlias); + dialog.show(); + }, + + onEditClick: function () { + var attributeAlias, dialog; + attributeAlias = this.getView().getSelectionModel().getSelection()[0]; + attributeAlias.store = Ext.getStore('AttributeAliases'); + dialog = Ext.create('Traccar.view.AttributeAliasDialog'); + dialog.down('form').loadRecord(attributeAlias); + dialog.show(); + }, + + onRemoveClick: function () { + var attributeAlias = this.getView().getSelectionModel().getSelection()[0]; + Ext.Msg.show({ + title: Strings.sharedAttributeAlias, + message: Strings.sharedRemoveConfirm, + buttons: Ext.Msg.YESNO, + buttonText: { + yes: Strings.sharedRemove, + no: Strings.sharedCancel + }, + scope: this, + fn: function (btn) { + var store = Ext.getStore('AttributeAliases'); + if (btn === 'yes') { + store.remove(attributeAlias); + store.sync(); + } + } + }); + }, + + onSelectionChange: function (selected) { + var disabled = !this.lookupReference('deviceField').getValue(); + this.lookupReference('toolbarAddButton').setDisabled(disabled); + disabled = selected.length === 0 || !this.lookupReference('deviceField').getValue(); + this.lookupReference('toolbarEditButton').setDisabled(disabled); + this.lookupReference('toolbarRemoveButton').setDisabled(disabled); + }, + + onDeviceChange: function (combobox, newValue, oldValue) { + var admin = Traccar.app.getUser().get('admin'); + this.onSelectionChange(''); + if (newValue !== null) { + this.getView().getStore().filter('deviceId', newValue); + if (admin && this.getView().getStore().getCount() === 0) { + Ext.getStore('AttributeAliases').getProxy().setExtraParam('deviceId', newValue); + Ext.getStore('AttributeAliases').load({ + addRecords: true + }); + } + } else { + this.getView().getStore().filter('deviceId', 0); + } + } +}); diff --git a/web/app/view/BaseMap.js b/web/app/view/BaseMap.js index a3524208..3a0f4420 100644 --- a/web/app/view/BaseMap.js +++ b/web/app/view/BaseMap.js @@ -63,7 +63,7 @@ Ext.define('Traccar.view.BaseMap', { imagerySet: 'Aerial' }) }); - } else if (type === 'osm'){ + } else if (type === 'osm') { layer = new ol.layer.Tile({ source: new ol.source.OSM({}) }); @@ -79,8 +79,8 @@ Ext.define('Traccar.view.BaseMap', { attributions: [ new ol.Attribution({ html: [ - '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> ' - + 'contributors, © <a href="https://carto.com/attributions">CARTO</a>' + '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> ' + + 'contributors, © <a href="https://carto.com/attributions">CARTO</a>' ] }) ] diff --git a/web/app/view/SettingsMenu.js b/web/app/view/SettingsMenu.js index 03b2f927..391db56f 100644 --- a/web/app/view/SettingsMenu.js +++ b/web/app/view/SettingsMenu.js @@ -1,5 +1,5 @@ /* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com) * * 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 @@ -58,6 +58,11 @@ Ext.define('Traccar.view.SettingsMenu', { handler: 'onNotificationsClick', reference: 'settingsNotificationsButton' }, { + hidden: true, + text: Strings.sharedAttributeAliases, + handler: 'onAttributeAliasesClick', + reference: 'settingsAttributeAliasesButton' + }, { text: Strings.loginLogout, handler: 'onLogoutClick' }] diff --git a/web/app/view/SettingsMenuController.js b/web/app/view/SettingsMenuController.js index 5c5a4517..ceef8aba 100644 --- a/web/app/view/SettingsMenuController.js +++ b/web/app/view/SettingsMenuController.js @@ -1,5 +1,5 @@ /* - * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) + * Copyright 2015 - 2016 Anton Tananaev (anton.tananaev@gmail.com) * * 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 @@ -27,6 +27,7 @@ Ext.define('Traccar.view.SettingsMenuController', { 'Traccar.view.Groups', 'Traccar.view.Geofences', 'Traccar.view.Notifications', + 'Traccar.view.AttributeAliases', 'Traccar.view.BaseWindow' ], @@ -42,6 +43,7 @@ Ext.define('Traccar.view.SettingsMenuController', { this.lookupReference('settingsGroupsButton').setHidden(false); this.lookupReference('settingsGeofencesButton').setHidden(false); this.lookupReference('settingsNotificationsButton').setHidden(false); + this.lookupReference('settingsAttributeAliasesButton').setHidden(false); } }, @@ -99,6 +101,16 @@ Ext.define('Traccar.view.SettingsMenuController', { }).show(); }, + onAttributeAliasesClick: function () { + Ext.create('Traccar.view.BaseWindow', { + title: Strings.sharedAttributeAliases, + modal: false, + items: { + xtype: 'attributeAliasesView' + } + }).show(); + }, + onLogoutClick: function () { Ext.create('Traccar.view.LoginController').logout(); } diff --git a/web/app/view/State.js b/web/app/view/State.js index 2974367e..7e9e235c 100644 --- a/web/app/view/State.js +++ b/web/app/view/State.js @@ -26,7 +26,25 @@ Ext.define('Traccar.view.State', { controller: 'state', store: 'Attributes', - title: Strings.stateTitle, + header: { + xtype: 'header', + title: Strings.stateTitle, + items: [{ + xtype: 'tbfill' + }, { + xtype: 'button', + disabled: true, + handler: 'onAliasEditClick', + reference: 'aliasEditButton', + glyph: 'xf040@FontAwesome', + tooltip: Strings.sharedEdit, + tooltipType: 'title' + }] + }, + + listeners: { + selectionchange: 'onSelectionChange' + }, columns: [{ text: Strings.stateName, @@ -37,7 +55,7 @@ Ext.define('Traccar.view.State', { dataIndex: 'value', flex: 1, renderer: function (value, metaData, record) { - if (record.get('name') === 'Alarm') { + if (record.get('attribute') === 'alarm') { metaData.tdCls = 'view-color-red'; } return value; diff --git a/web/app/view/StateController.js b/web/app/view/StateController.js index d92201b9..8a194940 100644 --- a/web/app/view/StateController.js +++ b/web/app/view/StateController.js @@ -21,15 +21,19 @@ Ext.define('Traccar.view.StateController', { requires: [ 'Traccar.AttributeFormatter', - 'Traccar.model.Attribute' + 'Traccar.model.Attribute', + 'Traccar.model.AttributeAlias', + 'Traccar.view.AttributeAliasDialog' + ], config: { listen: { controller: { '*': { - selectDevice: 'selectDevice', - selectReport: 'selectReport' + selectdevice: 'selectDevice', + selectreport: 'selectReport', + updatealiases: 'updateAliases' } }, store: { @@ -39,11 +43,19 @@ Ext.define('Traccar.view.StateController', { }, '#Positions': { clear: 'clearReport' + }, + '#AttributeAliases': { + add: 'updateAliases', + update: 'updateAliases' } } } }, + init: function () { + this.aliasesStore = Ext.getStore('AttributeAliases'); + }, + keys: (function () { var i, list, result; result = {}; @@ -66,7 +78,8 @@ Ext.define('Traccar.view.StateController', { } for (i = 0; i < data.length; i++) { if (this.deviceId === data[i].get('deviceId')) { - this.updatePosition(data[i]); + this.position = data[i]; + this.updatePosition(); } } }, @@ -79,30 +92,42 @@ Ext.define('Traccar.view.StateController', { } }, - updatePosition: function (position) { - var attributes, store, key; + findAttribute: function (record) { + return record.get('deviceId') === this.position.get('deviceId') && record.get('attribute') === this.lookupAttribute; + }, + + updatePosition: function () { + var attributes, store, key, aliasIndex, name; store = Ext.getStore('Attributes'); store.removeAll(); - for (key in position.data) { - if (position.data.hasOwnProperty(key) && this.keys[key] !== undefined) { + for (key in this.position.data) { + if (this.position.data.hasOwnProperty(key) && this.keys[key] !== undefined) { store.add(Ext.create('Traccar.model.Attribute', { priority: this.keys[key].priority, name: this.keys[key].name, - value: Traccar.AttributeFormatter.getFormatter(key)(position.get(key)) + value: Traccar.AttributeFormatter.getFormatter(key)(this.position.get(key)) })); } } - attributes = position.get('attributes'); + attributes = this.position.get('attributes'); if (attributes instanceof Object) { for (key in attributes) { if (attributes.hasOwnProperty(key)) { + this.lookupAttribute = key; + aliasIndex = this.aliasesStore.findBy(this.findAttribute, this); + if (aliasIndex !== -1) { + name = this.aliasesStore.getAt(aliasIndex).get('alias'); + } else { + name = key.replace(/^./, function (match) { + return match.toUpperCase(); + }); + } store.add(Ext.create('Traccar.model.Attribute', { priority: 1024, - name: key.replace(/^./, function (match) { - return match.toUpperCase(); - }), + name: name, + attribute: key, value: Traccar.AttributeFormatter.getFormatter(key)(attributes[key]) })); } @@ -115,18 +140,52 @@ Ext.define('Traccar.view.StateController', { this.deviceId = device.get('id'); position = Ext.getStore('LatestPositions').findRecord('deviceId', this.deviceId, 0, false, false, true); if (position) { - this.updatePosition(position); + this.position = position; + this.updatePosition(); } else { + this.position = null; Ext.getStore('Attributes').removeAll(); } }, selectReport: function (position) { this.deviceId = null; - this.updatePosition(position); + this.position = position; + this.updatePosition(); }, clearReport: function (store) { + this.position = null; Ext.getStore('Attributes').removeAll(); + }, + + onSelectionChange: function (selected, records) { + var enabled = selected.getCount() > 0 && records[0].get('priority') === 1024; + this.lookupReference('aliasEditButton').setDisabled(!enabled); + }, + + onAliasEditClick: function () { + var attribute, aliasIndex, attributeAlias, dialog; + attribute = this.getView().getSelectionModel().getSelection()[0]; + this.lookupAttribute = attribute.get('attribute'); + aliasIndex = this.aliasesStore.findBy(this.findAttribute, this); + if (aliasIndex !== -1) { + attributeAlias = this.aliasesStore.getAt(aliasIndex); + } else { + attributeAlias = Ext.create('Traccar.model.AttributeAlias', { + deviceId: this.position.get('deviceId'), + attribute: attribute.get('attribute') + }); + attributeAlias.store = this.aliasesStore; + } + dialog = Ext.create('Traccar.view.AttributeAliasDialog'); + dialog.down('form').loadRecord(attributeAlias); + dialog.show(); + }, + + updateAliases: function () { + if (this.position !== null) { + this.updatePosition(); + } } }); diff --git a/web/l10n/en.json b/web/l10n/en.json index e34c8d1c..11b2e835 100644 --- a/web/l10n/en.json +++ b/web/l10n/en.json @@ -29,6 +29,9 @@ "sharedHourAbbreviation": "h", "sharedMinuteAbbreviation": "m", "sharedGetMapState": "Get Map State", + "sharedAttributeAlias": "Attribute Alias", + "sharedAttributeAliases": "Attribute Aliases", + "sharedAlias": "Alias", "errorTitle": "Error", "errorUnknown": "Unknown error", "errorConnection": "Connection error", |