aboutsummaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
authorAnton Tananaev <anton.tananaev@gmail.com>2016-09-27 23:55:42 +1300
committerGitHub <noreply@github.com>2016-09-27 23:55:42 +1300
commita47bf8f3eb6807c4fc9094f6e1e6b62185354b2c (patch)
tree2030cd9ce92d4bcfede0257d27dd96190b8a7e4a /web
parente236e3b26434aee0016a7a743e6e3bb0233e0e8d (diff)
parentb1715a760cde09ec69a6756d7067a8c077d0fe2b (diff)
downloadtrackermap-web-a47bf8f3eb6807c4fc9094f6e1e6b62185354b2c.tar.gz
trackermap-web-a47bf8f3eb6807c4fc9094f6e1e6b62185354b2c.tar.bz2
trackermap-web-a47bf8f3eb6807c4fc9094f6e1e6b62185354b2c.zip
Merge pull request #287 from Abyss777/attribute_aliases
Implement attributes aliases
Diffstat (limited to 'web')
-rw-r--r--web/app/Application.js2
-rw-r--r--web/app/controller/Root.js1
-rw-r--r--web/app/model/Attribute.js3
-rw-r--r--web/app/model/AttributeAlias.js36
-rw-r--r--web/app/store/AttributeAliases.js30
-rw-r--r--web/app/view/AttributeAliasDialog.js51
-rw-r--r--web/app/view/AttributeAliases.js60
-rw-r--r--web/app/view/AttributeAliasesController.js105
-rw-r--r--web/app/view/BaseMap.js6
-rw-r--r--web/app/view/SettingsMenu.js7
-rw-r--r--web/app/view/SettingsMenuController.js14
-rw-r--r--web/app/view/State.js22
-rw-r--r--web/app/view/StateController.js89
-rw-r--r--web/l10n/en.json3
14 files changed, 407 insertions, 22 deletions
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: [
- '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> '
- + 'contributors, &copy; <a href="https://carto.com/attributions">CARTO</a>'
+ '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> ' +
+ 'contributors, &copy; <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",