From ffae2a37db0a28159e28525a1f9108e95f388f5e Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Fri, 23 Sep 2016 12:07:40 +0500 Subject: Implement attributes aliases --- web/app/Application.js | 3 + web/app/controller/Root.js | 1 + web/app/model/Attribute.js | 6 ++ web/app/model/AttributeAlias.js | 36 ++++++++++ web/app/store/AllAttributesAliases.js | 30 +++++++++ web/app/store/AttributesAliases.js | 30 +++++++++ web/app/view/AttributeAliasDialog.js | 51 ++++++++++++++ web/app/view/AttributesAliases.js | 62 +++++++++++++++++ web/app/view/AttributesAliasesController.js | 100 ++++++++++++++++++++++++++++ web/app/view/BaseMap.js | 6 +- web/app/view/SettingsMenu.js | 7 +- web/app/view/SettingsMenuController.js | 14 +++- web/app/view/State.js | 26 +++++++- web/app/view/StateController.js | 71 +++++++++++++++++--- web/l10n/en.json | 3 + 15 files changed, 428 insertions(+), 18 deletions(-) create mode 100644 web/app/model/AttributeAlias.js create mode 100644 web/app/store/AllAttributesAliases.js create mode 100644 web/app/store/AttributesAliases.js create mode 100644 web/app/view/AttributeAliasDialog.js create mode 100644 web/app/view/AttributesAliases.js create mode 100644 web/app/view/AttributesAliasesController.js (limited to 'web') diff --git a/web/app/Application.js b/web/app/Application.js index 62db7bc1..73b9e838 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,8 @@ Ext.define('Traccar.Application', { 'Notifications', 'AllNotifications', 'GeofenceTypes', + 'AttributesAliases', + 'AllAttributesAliases', 'ReportRoute', 'ReportEvents', 'ReportTrips', diff --git a/web/app/controller/Root.js b/web/app/controller/Root.js index 9cd6fd6d..5e3c39da 100644 --- a/web/app/controller/Root.js +++ b/web/app/controller/Root.js @@ -84,6 +84,7 @@ Ext.define('Traccar.controller.Root', { this.asyncUpdate(true); } }); + Ext.getStore('AllAttributesAliases').load(); attribution = Ext.get('attribution'); if (attribution) { attribution.remove(); diff --git a/web/app/model/Attribute.js b/web/app/model/Attribute.js index d30ddf85..7bf5beb5 100644 --- a/web/app/model/Attribute.js +++ b/web/app/model/Attribute.js @@ -27,5 +27,11 @@ Ext.define('Traccar.model.Attribute', { }, { name: 'value', type: 'string' + }, { + name: 'attribute', + type: 'string' + }, { + name: 'alias', + 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 . + */ + +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/AllAttributesAliases.js b/web/app/store/AllAttributesAliases.js new file mode 100644 index 00000000..7eb6c0c1 --- /dev/null +++ b/web/app/store/AllAttributesAliases.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 . + */ + +Ext.define('Traccar.store.AllAttributesAliases', { + extend: 'Ext.data.Store', + model: 'Traccar.model.AttributeAlias', + + proxy: { + type: 'rest', + url: 'api/devices/aliases', + writer: { + writeAllFields: true + } + } +}); diff --git a/web/app/store/AttributesAliases.js b/web/app/store/AttributesAliases.js new file mode 100644 index 00000000..1f8d11de --- /dev/null +++ b/web/app/store/AttributesAliases.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 . + */ + +Ext.define('Traccar.store.AttributesAliases', { + extend: 'Ext.data.Store', + model: 'Traccar.model.AttributeAlias', + + proxy: { + type: 'rest', + url: 'api/devices/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 . + */ + +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/AttributesAliases.js b/web/app/view/AttributesAliases.js new file mode 100644 index 00000000..b1390e45 --- /dev/null +++ b/web/app/view/AttributesAliases.js @@ -0,0 +1,62 @@ +/* + * 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 . + */ + +Ext.define('Traccar.view.AttributesAliases', { + extend: 'Ext.grid.Panel', + xtype: 'attributesAliasesView', + + requires: [ + 'Traccar.view.AttributesAliasesController', + 'Traccar.view.EditToolbar' + ], + + controller: 'attributesAliases', + store: 'AttributesAliases', + + selType: 'rowmodel', + + tbar: { + xtype: 'editToolbar', + items: ['-', { + xtype: 'combobox', + reference: 'deviceField', + store: 'Devices', + displayField: 'name', + valueField: 'id', + typeAhead: true, + listeners: { + change: 'onDeviceChange' + } + }] + }, + + listeners: { + selectionchange: 'onSelectionChange', + destroy: 'onClose' + }, + + columns: [{ + text: Strings.sharedAttribute, + dataIndex: 'attribute', + flex: 1 + }, { + text: Strings.sharedAlias, + dataIndex: 'alias', + flex: 1 + }] +}); diff --git a/web/app/view/AttributesAliasesController.js b/web/app/view/AttributesAliasesController.js new file mode 100644 index 00000000..e848c489 --- /dev/null +++ b/web/app/view/AttributesAliasesController.js @@ -0,0 +1,100 @@ +/* + * 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 . + */ + +Ext.define('Traccar.view.AttributesAliasesController', { + extend: 'Ext.app.ViewController', + alias: 'controller.attributesAliases', + + 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().getStore().loadData([], false); + }, + + onAddClick: function () { + var attributeAlias, dialog, deviceId; + attributeAlias = Ext.create('Traccar.model.AttributeAlias'); + attributeAlias.store = this.getView().getStore(); + 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]; + 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 = this.getView().getStore(); + 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) { + this.onSelectionChange(''); + if (newValue !== null) { + this.getView().getStore().getProxy().setExtraParam('deviceId', newValue); + this.getView().getStore().load(); + } else { + this.getView().getStore().loadData([], false); + } + }, + + onClose: function () { + Ext.getStore('AllAttributesAliases').load(); + this.fireEvent('updatealiases'); + } + +}); 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: [ - '© OpenStreetMap ' - + 'contributors, © CARTO' + '© OpenStreetMap ' + + 'contributors, © CARTO' ] }) ] diff --git a/web/app/view/SettingsMenu.js b/web/app/view/SettingsMenu.js index 03b2f927..691bf65b 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 @@ -57,6 +57,11 @@ Ext.define('Traccar.view.SettingsMenu', { text: Strings.sharedNotifications, handler: 'onNotificationsClick', reference: 'settingsNotificationsButton' + }, { + hidden: true, + text: Strings.sharedAttributesAliases, + handler: 'onAttributesAliasesClick', + reference: 'settingsAttributesAliasesButton' }, { text: Strings.loginLogout, handler: 'onLogoutClick' diff --git a/web/app/view/SettingsMenuController.js b/web/app/view/SettingsMenuController.js index 5c5a4517..b01e4f81 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.AttributesAliases', '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('settingsAttributesAliasesButton').setHidden(false); } }, @@ -99,6 +101,16 @@ Ext.define('Traccar.view.SettingsMenuController', { }).show(); }, + onAttributesAliasesClick: function () { + Ext.create('Traccar.view.BaseWindow', { + title: Strings.sharedAttributesAliases, + modal: false, + items: { + xtype: 'attributesAliasesView' + } + }).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..ddb9c0ea 100644 --- a/web/app/view/State.js +++ b/web/app/view/State.js @@ -26,12 +26,34 @@ 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, dataIndex: 'name', - flex: 1 + flex: 1, + renderer: function (value, metaData, record) { + var alias = record.get('alias'); + return alias !== '' ? alias : value; + } }, { text: Strings.stateValue, dataIndex: 'value', diff --git a/web/app/view/StateController.js b/web/app/view/StateController.js index d92201b9..4bd43de6 100644 --- a/web/app/view/StateController.js +++ b/web/app/view/StateController.js @@ -28,8 +28,9 @@ Ext.define('Traccar.view.StateController', { listen: { controller: { '*': { - selectDevice: 'selectDevice', - selectReport: 'selectReport' + selectdevice: 'selectDevice', + selectreport: 'selectReport', + updatealiases: 'updateAliases' } }, store: { @@ -39,6 +40,10 @@ Ext.define('Traccar.view.StateController', { }, '#Positions': { clear: 'clearReport' + }, + '#AllAttributesAliases': { + add: 'updateAliases', + update: 'updateAliases' } } } @@ -66,7 +71,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 +85,41 @@ Ext.define('Traccar.view.StateController', { } }, - updatePosition: function (position) { - var attributes, store, key; + updatePosition: function () { + var attributes, store, key, aliasesStore, attributeAlias, alias; 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'); + aliasesStore = Ext.getStore('AllAttributesAliases'); + aliasesStore.filter('deviceId', this.position.get('deviceId')); + + attributes = this.position.get('attributes'); if (attributes instanceof Object) { for (key in attributes) { if (attributes.hasOwnProperty(key)) { + attributeAlias = aliasesStore.findRecord('attribute', key, 0, false, true, true); + if (attributeAlias !== null) { + alias = attributeAlias.get('alias'); + } else { + alias = ''; + } store.add(Ext.create('Traccar.model.Attribute', { priority: 1024, name: key.replace(/^./, function (match) { return match.toUpperCase(); }), + attribute: key, + alias: alias, value: Traccar.AttributeFormatter.getFormatter(key)(attributes[key]) })); } @@ -115,18 +132,50 @@ 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('attribute') !== ''; + this.lookupReference('aliasEditButton').setDisabled(!enabled); + }, + + onAliasEditClick: function () { + var attribute, aliasesStore, attributeAlias, dialog; + attribute = this.getView().getSelectionModel().getSelection()[0]; + aliasesStore = Ext.getStore('AllAttributesAliases'); + attributeAlias = aliasesStore.findRecord('attribute', attribute.get('attribute'), 0, false, true, true); + if (attributeAlias === null) { + attributeAlias = Ext.create('Traccar.model.AttributeAlias', { + deviceId: this.position.get('deviceId'), + attribute: attribute.get('attribute') + }); + attributeAlias.store = 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..1bf53b39 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", + "sharedAttributesAliases": "Attributes Aliases", + "sharedAlias": "Alias", "errorTitle": "Error", "errorUnknown": "Unknown error", "errorConnection": "Connection error", -- cgit v1.2.3