aboutsummaryrefslogtreecommitdiff
path: root/legacy/web/app
diff options
context:
space:
mode:
Diffstat (limited to 'legacy/web/app')
-rw-r--r--legacy/web/app/Application.js246
-rw-r--r--legacy/web/app/AttributeFormatter.js311
-rw-r--r--legacy/web/app/DeviceImages.js99
-rw-r--r--legacy/web/app/GeofenceConverter.js101
-rw-r--r--legacy/web/app/Style.js95
-rw-r--r--legacy/web/app/controller/Root.js363
-rw-r--r--legacy/web/app/model/Attribute.js33
-rw-r--r--legacy/web/app/model/Calendar.js34
-rw-r--r--legacy/web/app/model/Command.js40
-rw-r--r--legacy/web/app/model/ComputedAttribute.js39
-rw-r--r--legacy/web/app/model/Device.js64
-rw-r--r--legacy/web/app/model/Driver.js35
-rw-r--r--legacy/web/app/model/Event.js81
-rw-r--r--legacy/web/app/model/Geofence.js40
-rw-r--r--legacy/web/app/model/Group.js34
-rw-r--r--legacy/web/app/model/KnownAttribute.js35
-rw-r--r--legacy/web/app/model/KnownCommand.js34
-rw-r--r--legacy/web/app/model/KnownNotification.js32
-rw-r--r--legacy/web/app/model/KnownNotificator.js32
-rw-r--r--legacy/web/app/model/Maintenance.js41
-rw-r--r--legacy/web/app/model/Notification.js40
-rw-r--r--legacy/web/app/model/Position.js72
-rw-r--r--legacy/web/app/model/ReportStop.js58
-rw-r--r--legacy/web/app/model/ReportSummary.js61
-rw-r--r--legacy/web/app/model/ReportTrip.js77
-rw-r--r--legacy/web/app/model/Server.js88
-rw-r--r--legacy/web/app/model/Statistics.js59
-rw-r--r--legacy/web/app/model/User.js101
-rw-r--r--legacy/web/app/store/AlarmTypes.js34
-rw-r--r--legacy/web/app/store/AllCalendars.js30
-rw-r--r--legacy/web/app/store/AllCommandTypes.js32
-rw-r--r--legacy/web/app/store/AllCommands.js30
-rw-r--r--legacy/web/app/store/AllComputedAttributes.js30
-rw-r--r--legacy/web/app/store/AllDevices.js29
-rw-r--r--legacy/web/app/store/AllDrivers.js30
-rw-r--r--legacy/web/app/store/AllGeofences.js29
-rw-r--r--legacy/web/app/store/AllGroups.js29
-rw-r--r--legacy/web/app/store/AllMaintenances.js30
-rw-r--r--legacy/web/app/store/AllNotificationTypes.js32
-rw-r--r--legacy/web/app/store/AllNotifications.js29
-rw-r--r--legacy/web/app/store/AllNotificators.js32
-rw-r--r--legacy/web/app/store/AllTimezones.js798
-rw-r--r--legacy/web/app/store/AttributeValueTypes.js33
-rw-r--r--legacy/web/app/store/Attributes.js25
-rw-r--r--legacy/web/app/store/Calendars.js30
-rw-r--r--legacy/web/app/store/CommandTypes.js32
-rw-r--r--legacy/web/app/store/Commands.js30
-rw-r--r--legacy/web/app/store/CommonDeviceAttributes.js32
-rw-r--r--legacy/web/app/store/CommonUserAttributes.js90
-rw-r--r--legacy/web/app/store/ComputedAttributes.js30
-rw-r--r--legacy/web/app/store/CoordinateFormats.js56
-rw-r--r--legacy/web/app/store/DeviceAttributes.js52
-rw-r--r--legacy/web/app/store/DeviceCommands.js32
-rw-r--r--legacy/web/app/store/DeviceImages.js37
-rw-r--r--legacy/web/app/store/DeviceStatuses.js35
-rw-r--r--legacy/web/app/store/Devices.js29
-rw-r--r--legacy/web/app/store/DistanceUnits.js53
-rw-r--r--legacy/web/app/store/Drivers.js30
-rw-r--r--legacy/web/app/store/EventPositions.js31
-rw-r--r--legacy/web/app/store/Events.js29
-rw-r--r--legacy/web/app/store/GeofenceAttributes.js38
-rw-r--r--legacy/web/app/store/GeofenceTypes.js32
-rw-r--r--legacy/web/app/store/Geofences.js29
-rw-r--r--legacy/web/app/store/GroupAttributes.js32
-rw-r--r--legacy/web/app/store/Groups.js29
-rw-r--r--legacy/web/app/store/HoursUnits.js43
-rw-r--r--legacy/web/app/store/KnownCommands.js241
-rw-r--r--legacy/web/app/store/Languages.js34
-rw-r--r--legacy/web/app/store/LatestPositions.js21
-rw-r--r--legacy/web/app/store/MaintenanceTypes.js22
-rw-r--r--legacy/web/app/store/Maintenances.js30
-rw-r--r--legacy/web/app/store/MapTypes.js56
-rw-r--r--legacy/web/app/store/Notifications.js29
-rw-r--r--legacy/web/app/store/PositionAttributes.js269
-rw-r--r--legacy/web/app/store/Positions.js29
-rw-r--r--legacy/web/app/store/ReportChartTypes.js33
-rw-r--r--legacy/web/app/store/ReportEventTypes.js26
-rw-r--r--legacy/web/app/store/ReportEvents.js35
-rw-r--r--legacy/web/app/store/ReportPeriods.js45
-rw-r--r--legacy/web/app/store/ReportRoute.js35
-rw-r--r--legacy/web/app/store/ReportStops.js36
-rw-r--r--legacy/web/app/store/ReportSummary.js36
-rw-r--r--legacy/web/app/store/ReportTrips.js36
-rw-r--r--legacy/web/app/store/ReportTypes.js44
-rw-r--r--legacy/web/app/store/ServerAttributes.js23
-rw-r--r--legacy/web/app/store/SpeedUnits.js53
-rw-r--r--legacy/web/app/store/Statistics.js26
-rw-r--r--legacy/web/app/store/TimeUnits.js44
-rw-r--r--legacy/web/app/store/UserAttributes.js70
-rw-r--r--legacy/web/app/store/Users.js29
-rw-r--r--legacy/web/app/store/VisibleDevices.js22
-rw-r--r--legacy/web/app/store/VolumeUnits.js57
-rw-r--r--legacy/web/app/view/ArrayListFilter.js50
-rw-r--r--legacy/web/app/view/BaseWindow.js32
-rw-r--r--legacy/web/app/view/ClearableComboBox.js31
-rw-r--r--legacy/web/app/view/ColorPicker.js43
-rw-r--r--legacy/web/app/view/CustomNumberField.js109
-rw-r--r--legacy/web/app/view/CustomTimeField.js30
-rw-r--r--legacy/web/app/view/DeviceMenu.js72
-rw-r--r--legacy/web/app/view/DeviceMenuController.js134
-rw-r--r--legacy/web/app/view/Events.js117
-rw-r--r--legacy/web/app/view/EventsController.js126
-rw-r--r--legacy/web/app/view/GridPanel.js34
-rw-r--r--legacy/web/app/view/Main.js84
-rw-r--r--legacy/web/app/view/MainController.js26
-rw-r--r--legacy/web/app/view/MainMobile.js73
-rw-r--r--legacy/web/app/view/Report.js115
-rw-r--r--legacy/web/app/view/ReportController.js678
-rw-r--r--legacy/web/app/view/SettingsMenu.js111
-rw-r--r--legacy/web/app/view/SettingsMenuController.js176
-rw-r--r--legacy/web/app/view/State.js85
-rw-r--r--legacy/web/app/view/StateController.js216
-rw-r--r--legacy/web/app/view/Statistics.js93
-rw-r--r--legacy/web/app/view/StatisticsController.js29
-rw-r--r--legacy/web/app/view/TouchFix62.js48
-rw-r--r--legacy/web/app/view/UnescapedTextAreaField.js29
-rw-r--r--legacy/web/app/view/UnescapedTextField.js29
-rw-r--r--legacy/web/app/view/dialog/Attribute.js65
-rw-r--r--legacy/web/app/view/dialog/AttributeController.js126
-rw-r--r--legacy/web/app/view/dialog/Base.js32
-rw-r--r--legacy/web/app/view/dialog/BaseEdit.js46
-rw-r--r--legacy/web/app/view/dialog/BaseEditController.js61
-rw-r--r--legacy/web/app/view/dialog/Calendar.js63
-rw-r--r--legacy/web/app/view/dialog/CalendarController.js37
-rw-r--r--legacy/web/app/view/dialog/ComputedAttribute.js84
-rw-r--r--legacy/web/app/view/dialog/ComputedAttributeController.js45
-rw-r--r--legacy/web/app/view/dialog/Device.js99
-rw-r--r--legacy/web/app/view/dialog/DeviceAccumulators.js55
-rw-r--r--legacy/web/app/view/dialog/DeviceAccumulatorsController.js48
-rw-r--r--legacy/web/app/view/dialog/DeviceController.js29
-rw-r--r--legacy/web/app/view/dialog/Driver.js46
-rw-r--r--legacy/web/app/view/dialog/Geofence.js89
-rw-r--r--legacy/web/app/view/dialog/GeofenceController.js58
-rw-r--r--legacy/web/app/view/dialog/Group.js55
-rw-r--r--legacy/web/app/view/dialog/Login.js151
-rw-r--r--legacy/web/app/view/dialog/LoginController.js132
-rw-r--r--legacy/web/app/view/dialog/Maintenance.js75
-rw-r--r--legacy/web/app/view/dialog/MaintenanceController.js65
-rw-r--r--legacy/web/app/view/dialog/MapPickerController.js42
-rw-r--r--legacy/web/app/view/dialog/Notification.js95
-rw-r--r--legacy/web/app/view/dialog/NotificationController.js53
-rw-r--r--legacy/web/app/view/dialog/Register.js67
-rw-r--r--legacy/web/app/view/dialog/RegisterController.js44
-rw-r--r--legacy/web/app/view/dialog/ReportConfig.js136
-rw-r--r--legacy/web/app/view/dialog/ReportConfigController.js99
-rw-r--r--legacy/web/app/view/dialog/SavedCommand.js83
-rw-r--r--legacy/web/app/view/dialog/SavedCommandController.js99
-rw-r--r--legacy/web/app/view/dialog/SelectDevice.js59
-rw-r--r--legacy/web/app/view/dialog/SelectDeviceController.js45
-rw-r--r--legacy/web/app/view/dialog/SendCommand.js98
-rw-r--r--legacy/web/app/view/dialog/SendCommandController.js78
-rw-r--r--legacy/web/app/view/dialog/Server.js159
-rw-r--r--legacy/web/app/view/dialog/User.js211
-rw-r--r--legacy/web/app/view/dialog/UserController.js69
-rw-r--r--legacy/web/app/view/edit/Attributes.js65
-rw-r--r--legacy/web/app/view/edit/AttributesController.js124
-rw-r--r--legacy/web/app/view/edit/Calendars.js50
-rw-r--r--legacy/web/app/view/edit/CalendarsController.js31
-rw-r--r--legacy/web/app/view/edit/ComputedAttributes.js80
-rw-r--r--legacy/web/app/view/edit/ComputedAttributesController.js31
-rw-r--r--legacy/web/app/view/edit/Devices.js161
-rw-r--r--legacy/web/app/view/edit/DevicesController.js139
-rw-r--r--legacy/web/app/view/edit/Drivers.js54
-rw-r--r--legacy/web/app/view/edit/DriversController.js31
-rw-r--r--legacy/web/app/view/edit/Geofences.js63
-rw-r--r--legacy/web/app/view/edit/GeofencesController.js30
-rw-r--r--legacy/web/app/view/edit/Groups.js109
-rw-r--r--legacy/web/app/view/edit/GroupsController.js141
-rw-r--r--legacy/web/app/view/edit/Maintenances.js77
-rw-r--r--legacy/web/app/view/edit/MaintenancesController.js31
-rw-r--r--legacy/web/app/view/edit/Notifications.js111
-rw-r--r--legacy/web/app/view/edit/NotificationsController.js31
-rw-r--r--legacy/web/app/view/edit/SavedCommands.js65
-rw-r--r--legacy/web/app/view/edit/SavedCommandsController.js31
-rw-r--r--legacy/web/app/view/edit/Toolbar.js49
-rw-r--r--legacy/web/app/view/edit/ToolbarController.js70
-rw-r--r--legacy/web/app/view/edit/Users.js156
-rw-r--r--legacy/web/app/view/edit/UsersController.js244
-rw-r--r--legacy/web/app/view/map/BaseMap.js243
-rw-r--r--legacy/web/app/view/map/GeofenceMap.js150
-rw-r--r--legacy/web/app/view/map/GeofenceMapController.js85
-rw-r--r--legacy/web/app/view/map/Map.js158
-rw-r--r--legacy/web/app/view/map/MapController.js101
-rw-r--r--legacy/web/app/view/map/MapMarkerController.js687
-rw-r--r--legacy/web/app/view/permissions/Base.js37
-rw-r--r--legacy/web/app/view/permissions/BaseController.js84
-rw-r--r--legacy/web/app/view/permissions/Calendars.js32
-rw-r--r--legacy/web/app/view/permissions/ComputedAttributes.js45
-rw-r--r--legacy/web/app/view/permissions/Devices.js82
-rw-r--r--legacy/web/app/view/permissions/Drivers.js38
-rw-r--r--legacy/web/app/view/permissions/Geofences.js43
-rw-r--r--legacy/web/app/view/permissions/Groups.js47
-rw-r--r--legacy/web/app/view/permissions/Maintenances.js65
-rw-r--r--legacy/web/app/view/permissions/Notifications.js78
-rw-r--r--legacy/web/app/view/permissions/SavedCommands.js50
-rw-r--r--legacy/web/app/view/permissions/Users.js32
196 files changed, 15308 insertions, 0 deletions
diff --git a/legacy/web/app/Application.js b/legacy/web/app/Application.js
new file mode 100644
index 00000000..dd9210dc
--- /dev/null
+++ b/legacy/web/app/Application.js
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.Application', {
+ extend: 'Ext.app.Application',
+ name: 'Traccar',
+
+ requires: [
+ 'Traccar.Style',
+ 'Traccar.AttributeFormatter',
+ 'Traccar.view.TouchFix62'
+ ],
+
+ models: [
+ 'Server',
+ 'User',
+ 'Group',
+ 'Device',
+ 'Position',
+ 'Attribute',
+ 'Command',
+ 'Event',
+ 'Geofence',
+ 'Notification',
+ 'ReportSummary',
+ 'ReportTrip',
+ 'ReportStop',
+ 'Calendar',
+ 'KnownAttribute',
+ 'Driver',
+ 'KnownCommand',
+ 'KnownNotification',
+ 'Maintenance'
+ ],
+
+ stores: [
+ 'Groups',
+ 'Devices',
+ 'AllGroups',
+ 'AllDevices',
+ 'AlarmTypes',
+ 'Positions',
+ 'LatestPositions',
+ 'EventPositions',
+ 'Users',
+ 'Attributes',
+ 'MapTypes',
+ 'DistanceUnits',
+ 'SpeedUnits',
+ 'CoordinateFormats',
+ 'CommandTypes',
+ 'TimeUnits',
+ 'Languages',
+ 'Events',
+ 'Geofences',
+ 'AllGeofences',
+ 'Notifications',
+ 'AllNotifications',
+ 'GeofenceTypes',
+ 'ReportRoute',
+ 'ReportEvents',
+ 'ReportTrips',
+ 'ReportStops',
+ 'ReportSummary',
+ 'ReportTypes',
+ 'ReportEventTypes',
+ 'ReportChartTypes',
+ 'ReportPeriods',
+ 'Statistics',
+ 'DeviceImages',
+ 'Calendars',
+ 'AllCalendars',
+ 'AllTimezones',
+ 'VisibleDevices',
+ 'DeviceStatuses',
+ 'CommonDeviceAttributes',
+ 'DeviceAttributes',
+ 'GeofenceAttributes',
+ 'GroupAttributes',
+ 'ServerAttributes',
+ 'CommonUserAttributes',
+ 'UserAttributes',
+ 'ComputedAttributes',
+ 'AllComputedAttributes',
+ 'PositionAttributes',
+ 'AttributeValueTypes',
+ 'Drivers',
+ 'AllDrivers',
+ 'KnownCommands',
+ 'VolumeUnits',
+ 'AllCommandTypes',
+ 'Commands',
+ 'AllCommands',
+ 'DeviceCommands',
+ 'AllNotificationTypes',
+ 'Maintenances',
+ 'AllMaintenances',
+ 'MaintenanceTypes',
+ 'HoursUnits',
+ 'AllNotificators'
+ ],
+
+ controllers: [
+ 'Root'
+ ],
+
+ isMobile: function () {
+ return window.matchMedia && window.matchMedia('(max-width: 768px)').matches;
+ },
+
+ getVehicleFeaturesDisabled: function () {
+ return this.getBooleanAttributePreference('ui.disableVehicleFeatures');
+ },
+
+ getEventString: function (eventType) {
+ var key = 'event' + eventType.charAt(0).toUpperCase() + eventType.slice(1);
+ return Strings[key] || key;
+ },
+
+ getNotificatorString: function (eventType) {
+ var key = 'notificator' + eventType.charAt(0).toUpperCase() + eventType.slice(1);
+ return Strings[key] || key;
+ },
+
+ showReports: function (show) {
+ var rootPanel = Ext.getCmp('rootPanel');
+ if (rootPanel) {
+ rootPanel.setActiveItem(show ? 1 : 0);
+ }
+ },
+
+ showEvents: function (show) {
+ var rootPanel = Ext.getCmp('rootPanel');
+ if (rootPanel) {
+ rootPanel.setActiveItem(show ? 2 : 0);
+ }
+ },
+
+ updateNotificationToken: function (token) {
+ var attributes = Ext.clone(this.user.get('attributes'));
+ if (!attributes.notificationTokens || attributes.notificationTokens.indexOf(token) < 0) {
+ if (!attributes.notificationTokens) {
+ attributes.notificationTokens = token;
+ } else {
+ attributes.notificationTokens += ',' + token;
+ }
+ this.user.set('attributes', attributes);
+ this.user.save();
+ }
+ },
+
+ setUser: function (data) {
+ var reader = Ext.create('Ext.data.reader.Json', {
+ model: 'Traccar.model.User'
+ });
+ this.user = reader.readRecords(data).getRecords()[0];
+ },
+
+ getUser: function () {
+ return this.user;
+ },
+
+ setServer: function (data) {
+ var reader = Ext.create('Ext.data.reader.Json', {
+ model: 'Traccar.model.Server'
+ });
+ this.server = reader.readRecords(data).getRecords()[0];
+ },
+
+ getServer: function () {
+ return this.server;
+ },
+
+ getPreference: function (key, defaultValue) {
+ if (this.getServer().get('forceSettings')) {
+ return this.getServer().get(key) || this.getUser().get(key) || defaultValue;
+ } else {
+ return this.getUser().get(key) || this.getServer().get(key) || defaultValue;
+ }
+ },
+
+ getAttributePreference: function (key, defaultValue) {
+ if (this.getServer().get('forceSettings')) {
+ return this.getServer().get('attributes')[key] || this.getUser().get('attributes')[key] || defaultValue;
+ } else {
+ return this.getUser().get('attributes')[key] || this.getServer().get('attributes')[key] || defaultValue;
+ }
+ },
+
+ getBooleanAttributePreference: function (key) {
+ return this.getAttributePreference(key, false).toString() === 'true';
+ },
+
+ getReportColor: function (deviceId) {
+ var index, reportColor, device = Ext.getStore('Devices').getById(deviceId);
+ if (device) {
+ reportColor = device.get('attributes')['web.reportColor'];
+ }
+ if (reportColor) {
+ return reportColor;
+ } else {
+ index = 0;
+ if (deviceId !== undefined) {
+ index = deviceId % Traccar.Style.mapRouteColor.length;
+ }
+ return Traccar.Style.mapRouteColor[index];
+ }
+ },
+
+ showError: function (error) {
+ if (Ext.isString(error)) {
+ Ext.Msg.alert(Strings.errorTitle, error);
+ } else if (error.responseText) {
+ Ext.Msg.alert(Strings.errorTitle, Strings.errorGeneral +
+ '<br><br><textarea readonly rows="5" style="resize: none; width: 100%;">' +
+ error.responseText + '</textarea>');
+ } else if (error.statusText) {
+ Ext.Msg.alert(Strings.errorTitle, error.statusText);
+ } else {
+ Ext.Msg.alert(Strings.errorTitle, Strings.errorConnection);
+ }
+ },
+
+ showToast: function (message, title) {
+ Ext.toast({
+ html: message,
+ title: title,
+ width: Traccar.Style.toastWidth,
+ align: 'br'
+ });
+ }
+});
diff --git a/legacy/web/app/AttributeFormatter.js b/legacy/web/app/AttributeFormatter.js
new file mode 100644
index 00000000..d207ef1e
--- /dev/null
+++ b/legacy/web/app/AttributeFormatter.js
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2015 - 2018 Anton Tananaev (anton@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.AttributeFormatter', {
+ singleton: true,
+
+ numberFormatterFactory: function (precision, suffix) {
+ return function (value) {
+ if (value !== undefined) {
+ return Number(value.toFixed(precision)) + ' ' + suffix;
+ }
+ return null;
+ };
+ },
+
+ coordinateFormatter: function (key, value) {
+ return Ext.getStore('CoordinateFormats').formatValue(key, value, Traccar.app.getPreference('coordinateFormat'));
+ },
+
+ speedFormatter: function (value) {
+ return Ext.getStore('SpeedUnits').formatValue(value, Traccar.app.getAttributePreference('speedUnit'));
+ },
+
+ speedConverter: function (value) {
+ return Ext.getStore('SpeedUnits').convertValue(value, Traccar.app.getAttributePreference('speedUnit'));
+ },
+
+ courseFormatter: function (value) {
+ var courseValues = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'];
+ return courseValues[Math.floor(value / 45)];
+ },
+
+ distanceFormatter: function (value) {
+ return Ext.getStore('DistanceUnits').formatValue(value, Traccar.app.getAttributePreference('distanceUnit'));
+ },
+
+ distanceConverter: function (value) {
+ return Ext.getStore('DistanceUnits').convertValue(value, Traccar.app.getAttributePreference('distanceUnit'));
+ },
+
+ volumeFormatter: function (value) {
+ return Ext.getStore('VolumeUnits').formatValue(value, Traccar.app.getAttributePreference('volumeUnit'));
+ },
+
+ volumeConverter: function (value) {
+ return Ext.getStore('VolumeUnits').convertValue(value, Traccar.app.getAttributePreference('volumeUnit'));
+ },
+
+ hoursFormatter: function (value) {
+ return Ext.getStore('HoursUnits').formatValue(value, 'h');
+ },
+
+ hoursConverter: function (value) {
+ return Ext.getStore('HoursUnits').convertValue(value, 'h');
+ },
+
+ durationFormatter: function (value) {
+ return Ext.getStore('HoursUnits').formatValue(value, 'h', true);
+ },
+
+ deviceIdFormatter: function (value) {
+ var device, store;
+ if (value !== 0) {
+ store = Ext.getStore('AllDevices');
+ if (store.getTotalCount() === 0) {
+ store = Ext.getStore('Devices');
+ }
+ device = store.getById(value);
+ return device ? device.get('name') : '';
+ }
+ return null;
+ },
+
+ groupIdFormatter: function (value) {
+ var group, store;
+ if (value !== 0) {
+ store = Ext.getStore('AllGroups');
+ if (store.getTotalCount() === 0) {
+ store = Ext.getStore('Groups');
+ }
+ group = store.getById(value);
+ return group ? group.get('name') : value;
+ }
+ return null;
+ },
+
+ geofenceIdFormatter: function (value) {
+ var geofence, store;
+ if (value !== 0) {
+ store = Ext.getStore('AllGeofences');
+ if (store.getTotalCount() === 0) {
+ store = Ext.getStore('Geofences');
+ }
+ geofence = store.getById(value);
+ return geofence ? geofence.get('name') : '';
+ }
+ return null;
+ },
+
+ calendarIdFormatter: function (value) {
+ var calendar, store;
+ if (value !== 0) {
+ store = Ext.getStore('AllCalendars');
+ if (store.getTotalCount() === 0) {
+ store = Ext.getStore('Calendars');
+ }
+ calendar = store.getById(value);
+ return calendar ? calendar.get('name') : '';
+ }
+ return null;
+ },
+
+ driverUniqueIdFormatter: function (value) {
+ var driver, store;
+ if (value !== 0) {
+ store = Ext.getStore('AllDrivers');
+ if (store.getTotalCount() === 0) {
+ store = Ext.getStore('Drivers');
+ }
+ driver = store.findRecord('uniqueId', value, 0, false, true, true);
+ return driver ? value + ' (' + driver.get('name') + ')' : value;
+ }
+ return null;
+ },
+
+ maintenanceIdFormatter: function (value) {
+ var maintenance, store;
+ if (value !== 0) {
+ store = Ext.getStore('AllMaintenances');
+ if (store.getTotalCount() === 0) {
+ store = Ext.getStore('Maintenances');
+ }
+ maintenance = store.getById(value);
+ return maintenance ? maintenance.get('name') : '';
+ }
+ return null;
+ },
+
+ lastUpdateFormatter: function (value) {
+ var seconds, interval;
+ if (value) {
+ seconds = Math.floor((new Date() - value) / 1000);
+ if (seconds < 0) {
+ seconds = 0;
+ }
+ interval = Math.floor(seconds / 86400);
+ if (interval > 1) {
+ return interval + ' ' + Strings.sharedDays;
+ }
+ interval = Math.floor(seconds / 3600);
+ if (interval > 1) {
+ return interval + ' ' + Strings.sharedHours;
+ }
+ return Math.floor(seconds / 60) + ' ' + Strings.sharedMinutes;
+ }
+ return null;
+ },
+
+ commandTypeFormatter: function (value) {
+ var name = Strings['command' + value.charAt(0).toUpperCase() + value.slice(1)];
+ return name ? name : value;
+ },
+
+ defaultFormatter: function (value) {
+ if (typeof value === 'number') {
+ return Number(value.toFixed(Traccar.Style.numberPrecision));
+ } else if (typeof value === 'boolean') {
+ return value ? Ext.Msg.buttonText.yes : Ext.Msg.buttonText.no;
+ } else if (value instanceof Date) {
+ if (Traccar.app.getPreference('twelveHourFormat', false)) {
+ return Ext.Date.format(value, Traccar.Style.dateTimeFormat12);
+ } else {
+ return Ext.Date.format(value, Traccar.Style.dateTimeFormat24);
+ }
+ }
+ return value;
+ },
+
+ dateFormatter: function (value) {
+ return Ext.Date.format(value, Traccar.Style.dateFormat);
+ },
+
+ getFormatter: function (key) {
+ var self = this;
+
+ switch (key) {
+ case 'latitude':
+ case 'longitude':
+ return function (value) {
+ return self.coordinateFormatter(key, value);
+ };
+ case 'speed':
+ return this.speedFormatter;
+ case 'course':
+ return this.courseFormatter;
+ case 'distance':
+ case 'accuracy':
+ return this.distanceFormatter;
+ case 'duration':
+ return this.durationFormatter;
+ case 'deviceId':
+ return this.deviceIdFormatter;
+ case 'groupId':
+ return this.groupIdFormatter;
+ case 'geofenceId':
+ return this.geofenceIdFormatter;
+ case 'maintenanceId':
+ return this.maintenanceIdFormatter;
+ case 'calendarId':
+ return this.calendarIdFormatter;
+ case 'lastUpdate':
+ return this.lastUpdateFormatter;
+ case 'spentFuel':
+ return this.volumeFormatter;
+ case 'driverUniqueId':
+ return this.driverUniqueIdFormatter;
+ case 'commandType':
+ return this.commandTypeFormatter;
+ default:
+ return this.defaultFormatter;
+ }
+ },
+
+ getConverter: function (key) {
+ switch (key) {
+ case 'speed':
+ return this.speedConverter;
+ case 'distance':
+ case 'accuracy':
+ return this.distanceConverter;
+ case 'spentFuel':
+ return this.volumeConverter;
+ default:
+ return function (value) {
+ return value;
+ };
+ }
+ },
+
+ getAttributeFormatter: function (key) {
+ var dataType = Ext.getStore('PositionAttributes').getAttributeDataType(key);
+
+ switch (dataType) {
+ case 'distance':
+ return this.distanceFormatter;
+ case 'speed':
+ return this.speedFormatter;
+ case 'driverUniqueId':
+ return this.driverUniqueIdFormatter;
+ case 'voltage':
+ return this.numberFormatterFactory(Traccar.Style.numberPrecision, Strings.sharedVoltAbbreviation);
+ case 'percentage':
+ return this.numberFormatterFactory(Traccar.Style.numberPrecision, '&#37;');
+ case 'temperature':
+ return this.numberFormatterFactory(Traccar.Style.numberPrecision, '&deg;C');
+ case 'volume':
+ return this.volumeFormatter;
+ case 'hours':
+ return this.hoursFormatter;
+ case 'consumption':
+ return this.numberFormatterFactory(Traccar.Style.numberPrecision, Strings.sharedLiterPerHourAbbreviation);
+ default:
+ return this.defaultFormatter;
+ }
+ },
+
+ getAttributeConverter: function (key) {
+ var dataType = Ext.getStore('PositionAttributes').getAttributeDataType(key);
+
+ switch (dataType) {
+ case 'distance':
+ return this.distanceConverter;
+ case 'speed':
+ return this.speedConverter;
+ case 'volume':
+ return this.volumeConverter;
+ case 'hours':
+ return this.hoursConverter;
+ default:
+ return function (value) {
+ return value;
+ };
+ }
+ },
+
+ renderAttribute: function (value, attribute) {
+ if (attribute && attribute.get('dataType') === 'speed') {
+ return Ext.getStore('SpeedUnits').formatValue(value, Traccar.app.getAttributePreference('speedUnit', 'kn'), true);
+ } else if (attribute && attribute.get('dataType') === 'distance') {
+ return Ext.getStore('DistanceUnits').formatValue(value, Traccar.app.getAttributePreference('distanceUnit', 'km'), true);
+ } else if (attribute && attribute.get('dataType') === 'hours') {
+ return Ext.getStore('HoursUnits').formatValue(value, 'h', true);
+ } else {
+ return value;
+ }
+ }
+});
diff --git a/legacy/web/app/DeviceImages.js b/legacy/web/app/DeviceImages.js
new file mode 100644
index 00000000..af45ce90
--- /dev/null
+++ b/legacy/web/app/DeviceImages.js
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 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.DeviceImages', {
+ singleton: true,
+
+ getImageSvg: function (color, zoom, angle, category) {
+ var i, info, svg, width, height, rotateTransform, scaleTransform, fill;
+
+ info = Ext.getStore('DeviceImages').findRecord('key', category || 'default', 0, false, false, true);
+ svg = Ext.clone(info.get('svg'));
+ if (!svg) {
+ svg = this.cloneDocument(info.get('svg'));
+ }
+
+ width = parseFloat(svg.documentElement.getAttribute('width'));
+ height = parseFloat(svg.documentElement.getAttribute('height'));
+
+ fill = info.get('fillId');
+ if (!Ext.isArray(fill)) {
+ fill = [fill];
+ }
+ for (i = 0; i < fill.length; i++) {
+ svg.getElementById(fill[i]).style.fill = color;
+ }
+
+ rotateTransform = 'rotate(' + angle + ' ' + width / 2 + ' ' + height / 2 + ')';
+ svg.getElementById(info.get('rotateId')).setAttribute('transform', rotateTransform);
+
+ if (zoom) {
+ width *= Traccar.Style.mapScaleSelected;
+ height *= Traccar.Style.mapScaleSelected;
+ scaleTransform = 'scale(' + Traccar.Style.mapScaleSelected + ') ';
+ } else {
+ width *= Traccar.Style.mapScaleNormal;
+ height *= Traccar.Style.mapScaleNormal;
+ scaleTransform = 'scale(' + Traccar.Style.mapScaleNormal + ') ';
+ }
+
+ if (info.get('scaleId') !== info.get('rotateId')) {
+ svg.getElementById(info.get('scaleId')).setAttribute('transform', scaleTransform);
+ } else {
+ svg.getElementById(info.get('scaleId')).setAttribute('transform', scaleTransform + ' ' + rotateTransform);
+ }
+
+ svg.documentElement.setAttribute('width', width);
+ svg.documentElement.setAttribute('height', height);
+ svg.documentElement.setAttribute('viewBox', '0 0 ' + width + ' ' + height);
+
+ return svg;
+ },
+
+ formatSrc: function (svg) {
+ return 'data:image/svg+xml;charset=utf-8,' +
+ encodeURIComponent(new XMLSerializer().serializeToString(svg.documentElement));
+ },
+
+ cloneDocument: function (svgDocument) {
+ var newDocument, newNode;
+ newDocument = svgDocument.implementation.createDocument(svgDocument.namespaceURI, null, null);
+ newNode = newDocument.importNode(svgDocument.documentElement, true);
+ newDocument.appendChild(newNode);
+ return newDocument;
+ },
+
+ getImageIcon: function (color, zoom, angle, category) {
+ var image, svg, width, height;
+
+ svg = this.getImageSvg(color, zoom, angle, category);
+ width = parseFloat(svg.documentElement.getAttribute('width'));
+ height = parseFloat(svg.documentElement.getAttribute('height'));
+
+ image = new ol.style.Icon({
+ imgSize: [width, height],
+ src: this.formatSrc(svg)
+ });
+ image.fill = color;
+ image.zoom = zoom;
+ image.angle = angle;
+ image.category = category;
+
+ return image;
+ }
+});
diff --git a/legacy/web/app/GeofenceConverter.js b/legacy/web/app/GeofenceConverter.js
new file mode 100644
index 00000000..688f2233
--- /dev/null
+++ b/legacy/web/app/GeofenceConverter.js
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@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.GeofenceConverter', {
+ singleton: true,
+
+ wktToGeometry: function (mapView, wkt) {
+ var geometry, projection, resolutionAtEquator, pointResolution, resolutionFactor,
+ points = [], center, radius, content, i, lat, lon, coordinates;
+ if (wkt.lastIndexOf('POLYGON', 0) === 0) {
+ content = wkt.match(/\([^()]+\)/);
+ if (content !== null) {
+ coordinates = content[0].match(/-?\d+\.?\d*/g);
+ if (coordinates !== null) {
+ projection = mapView.getProjection();
+ for (i = 0; i < coordinates.length; i += 2) {
+ lat = Number(coordinates[i]);
+ lon = Number(coordinates[i + 1]);
+ points.push(ol.proj.transform([lon, lat], 'EPSG:4326', projection));
+ }
+ geometry = new ol.geom.Polygon([points]);
+ }
+ }
+ } else if (wkt.lastIndexOf('CIRCLE', 0) === 0) {
+ content = wkt.match(/\([^()]+\)/);
+ if (content !== null) {
+ coordinates = content[0].match(/-?\d+\.?\d*/g);
+ if (coordinates !== null) {
+ projection = mapView.getProjection();
+ center = ol.proj.transform([Number(coordinates[1]), Number(coordinates[0])], 'EPSG:4326', projection);
+ resolutionAtEquator = mapView.getResolution();
+ pointResolution = ol.proj.getPointResolution(projection, resolutionAtEquator, center);
+ resolutionFactor = resolutionAtEquator / pointResolution;
+ radius = Number(coordinates[2]) / ol.proj.Units.METERS_PER_UNIT.m * resolutionFactor;
+ geometry = new ol.geom.Circle(center, radius);
+ }
+ }
+ } else if (wkt.lastIndexOf('LINESTRING', 0) === 0) {
+ content = wkt.match(/\([^()]+\)/);
+ if (content !== null) {
+ coordinates = content[0].match(/-?\d+\.?\d*/g);
+ if (coordinates !== null) {
+ projection = mapView.getProjection();
+ for (i = 0; i < coordinates.length; i += 2) {
+ lat = Number(coordinates[i]);
+ lon = Number(coordinates[i + 1]);
+ points.push(ol.proj.transform([lon, lat], 'EPSG:4326', projection));
+ }
+ geometry = new ol.geom.LineString(points);
+ }
+ }
+ }
+ return geometry;
+ },
+
+ geometryToWkt: function (projection, geometry) {
+ var result, i, center, radius, edgeCoordinate, groundRadius, points;
+ if (geometry instanceof ol.geom.Circle) {
+ center = geometry.getCenter();
+ radius = geometry.getRadius();
+ edgeCoordinate = [center[0] + radius, center[1]];
+ center = ol.proj.transform(center, projection, 'EPSG:4326');
+ groundRadius = ol.sphere.getDistance(
+ center, ol.proj.transform(edgeCoordinate, projection, 'EPSG:4326'), 6378137);
+ result = 'CIRCLE (';
+ result += center[1] + ' ' + center[0] + ', ';
+ result += groundRadius.toFixed(1) + ')';
+ } else if (geometry instanceof ol.geom.Polygon) {
+ geometry.transform(projection, 'EPSG:4326');
+ points = geometry.getCoordinates();
+ result = 'POLYGON((';
+ for (i = 0; i < points[0].length; i += 1) {
+ result += points[0][i][1] + ' ' + points[0][i][0] + ', ';
+ }
+ result = result.substring(0, result.length - 2) + '))';
+ } else if (geometry instanceof ol.geom.LineString) {
+ geometry.transform(projection, 'EPSG:4326');
+ points = geometry.getCoordinates();
+ result = 'LINESTRING (';
+ for (i = 0; i < points.length; i += 1) {
+ result += points[i][1] + ' ' + points[i][0] + ', ';
+ }
+ result = result.substring(0, result.length - 2) + ')';
+ }
+ return result;
+ }
+});
diff --git a/legacy/web/app/Style.js b/legacy/web/app/Style.js
new file mode 100644
index 00000000..371e05a1
--- /dev/null
+++ b/legacy/web/app/Style.js
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.Style', {
+ singleton: true,
+
+ refreshPeriod: 60 * 1000,
+ reconnectTimeout: 60 * 1000,
+ reportTimeout: 120 * 1000,
+
+ normalPadding: 10,
+
+ windowWidth: 800,
+ windowHeight: 600,
+
+ formFieldWidth: 275,
+
+ dateTimeFormat24: 'Y-m-d H:i:s',
+ dateTimeFormat12: 'Y-m-d g:i:s a',
+ timeFormat24: 'H:i',
+ timeFormat12: 'g:i a',
+ dateFormat: 'Y-m-d',
+ weekStartDay: 1,
+
+ deviceWidth: 400,
+ toastWidth: 300,
+
+ reportHeight: 250,
+
+ columnWidthNormal: 100,
+
+ mapDefaultLat: 48.8567,
+ mapDefaultLon: 2.3508,
+ mapDefaultZoom: 4,
+
+ mapRouteColor: [
+ '#F06292',
+ '#BA68C8',
+ '#4DD0E1',
+ '#4DB6AC',
+ '#FF8A65',
+ '#A1887F'
+ ],
+ mapRouteWidth: 5,
+
+ mapTextColor: 'rgba(50, 50, 50, 1.0)',
+ mapTextStrokeColor: 'rgba(255, 255, 255, 1.0)',
+ mapTextStrokeWidth: 2,
+ mapTextOffset: 2,
+ mapTextFont: 'bold 12px sans-serif',
+
+ mapColorOnline: 'rgba(77, 250, 144, 1.0)',
+ mapColorUnknown: 'rgba(250, 190, 77, 1.0)',
+ mapColorOffline: 'rgba(255, 162, 173, 1.0)',
+
+ mapScaleNormal: 1,
+ mapScaleSelected: 1.5,
+
+ mapMaxZoom: 18,
+ mapDelay: 500,
+
+ mapAccuracyColor: 'rgba(96, 96, 96, 1.0)',
+
+ mapGeofenceTextColor: 'rgba(14, 88, 141, 1.0)',
+ mapGeofenceColor: 'rgba(21, 127, 204, 1.0)',
+ mapGeofenceOverlayOpacity: 0.2,
+ mapGeofenceWidth: 5,
+ mapGeofenceRadius: 9,
+
+ mapAnimateMarkerDuration: 2000,
+ mapAnimateMarkerTimeout: 40,
+
+ coordinatePrecision: 6,
+ numberPrecision: 2,
+
+ reportGridStyle: 'borderTop: 1px solid lightgray',
+
+ chartPadding: '20 40 10 10',
+ chartMarkerRadius: 3,
+ chartMarkerHighlightScaling: 1.5
+});
diff --git a/legacy/web/app/controller/Root.js b/legacy/web/app/controller/Root.js
new file mode 100644
index 00000000..22869f45
--- /dev/null
+++ b/legacy/web/app/controller/Root.js
@@ -0,0 +1,363 @@
+/*
+ * Copyright 2015 - 2022 Anton Tananaev (anton@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.controller.Root', {
+ extend: 'Ext.app.Controller',
+ alias: 'controller.root',
+
+ requires: [
+ 'Traccar.view.dialog.Login',
+ 'Traccar.view.Main',
+ 'Traccar.view.MainMobile',
+ 'Traccar.model.Position'
+ ],
+
+ init: function () {
+ var i, data, attribute, chartTypesStore, maintenanceTypesStore;
+ chartTypesStore = Ext.getStore('ReportChartTypes');
+ maintenanceTypesStore = Ext.getStore('MaintenanceTypes');
+ Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
+ data = Ext.getStore('PositionAttributes').getData().items;
+ for (i = 0; i < data.length; i++) {
+ attribute = data[i];
+ Traccar.model.Position.addFields([{
+ name: 'attribute.' + attribute.get('key'),
+ attributeKey: attribute.get('key'),
+ calculate: this.calculateAttribute,
+ persist: false
+ }]);
+ if (attribute.get('valueType') === 'number') {
+ chartTypesStore.add({
+ key: 'attribute.' + attribute.get('key'),
+ name: attribute.get('name')
+ });
+ maintenanceTypesStore.add(attribute);
+ }
+ }
+ },
+
+ calculateAttribute: function (data) {
+ var value = data.attributes[this.attributeKey];
+ if (value !== undefined) {
+ return Traccar.AttributeFormatter.getAttributeConverter(this.attributeKey)(value);
+ }
+ return value;
+ },
+
+ onLaunch: function () {
+ Ext.Ajax.request({
+ scope: this,
+ url: 'api/server',
+ callback: this.onServerReturn
+ });
+ },
+
+ showAnnouncement: function (announcement) {
+ var maxWidth = Ext.getBody().getViewSize().width - 2 * Traccar.Style.normalPadding;
+ if (maxWidth > Traccar.Style.windowWidth) {
+ maxWidth = Traccar.Style.windowWidth;
+ }
+ Ext.Msg.show({
+ msg: announcement,
+ buttons: Ext.Msg.OK,
+ closable: false,
+ modal: false,
+ maxWidth: maxWidth
+ }).alignTo(Ext.getBody(), 't-t', [0, Traccar.Style.normalPadding]);
+ },
+
+ onServerReturn: function (options, success, response) {
+ var announcement, token, parameters = {};
+ if (success) {
+ Traccar.app.setServer(Ext.decode(response.responseText));
+ announcement = Traccar.app.getServer().get('announcement');
+ if (announcement) {
+ this.showAnnouncement(announcement);
+ }
+ token = Ext.Object.fromQueryString(window.location.search).token;
+ if (token) {
+ parameters.token = token;
+ }
+ Ext.Ajax.request({
+ scope: this,
+ url: 'api/session',
+ method: 'GET',
+ params: parameters,
+ callback: this.onSessionReturn
+ });
+ } else {
+ Traccar.app.showError(response);
+ }
+ },
+
+ onSessionReturn: function (options, success, response) {
+ var passwordReset, dialog;
+ Ext.get('spinner').setVisible(false);
+ if (success) {
+ Traccar.app.setUser(Ext.decode(response.responseText));
+ this.loadApp();
+ } else {
+ this.login = Ext.create('widget.login', {
+ listeners: {
+ scope: this,
+ login: this.onLogin
+ }
+ });
+ this.login.show();
+
+ passwordReset = Ext.Object.fromQueryString(window.location.search).passwordReset;
+ if (passwordReset) {
+ dialog = Ext.Msg.prompt(Strings.loginReset, Strings.userPassword, function (btn, text) {
+ dialog.textField.inputEl.dom.type = 'text';
+ if (btn === 'ok') {
+ Ext.Ajax.request({
+ scope: this,
+ method: 'POST',
+ url: 'api/password/update',
+ params: {
+ token: passwordReset,
+ password: text
+ },
+ callback: function (options, success, response) {
+ if (success) {
+ Traccar.app.showToast(Strings.loginUpdateSuccess);
+ this.removeUrlParameter('passwordReset');
+ } else {
+ Traccar.app.showError(response.responseText);
+ }
+ }
+ });
+ }
+ }, this);
+ dialog.textField.inputEl.dom.type = 'password';
+ }
+ }
+ },
+
+ onLogin: function () {
+ this.login.close();
+ this.loadApp();
+ },
+
+ loadApp: function () {
+ var updateView, attributionView, eventId;
+
+ if (window.webkit && window.webkit.messageHandlers.appInterface) {
+ window.webkit.messageHandlers.appInterface.postMessage('login');
+ }
+ if (window.appInterface) {
+ window.appInterface.postMessage('login');
+ }
+
+ Ext.getStore('Groups').load();
+ Ext.getStore('Drivers').load();
+ Ext.getStore('Geofences').load();
+ Ext.getStore('Calendars').load();
+ Ext.getStore('Maintenances').load();
+ Ext.getStore('ComputedAttributes').load();
+ Ext.getStore('AllCommandTypes').load();
+ Ext.getStore('Commands').load();
+ Ext.getStore('AllNotificationTypes').load({
+ callback: function (records, operation, success) {
+ var store = Ext.getStore('ReportEventTypes');
+ if (success) {
+ store.add({
+ type: Traccar.store.ReportEventTypes.allEvents,
+ name: Strings.eventAll
+ });
+ store.loadData(records, true);
+ }
+ }
+ });
+ Ext.getStore('AllNotificators').load();
+ Ext.getStore('Notifications').load();
+
+ Ext.getStore('ServerAttributes').loadData(Ext.getStore('CommonDeviceAttributes').getData().items, true);
+ Ext.getStore('ServerAttributes').loadData(Ext.getStore('CommonUserAttributes').getData().items, true);
+ Ext.getStore('UserAttributes').loadData(Ext.getStore('CommonUserAttributes').getData().items, true);
+ Ext.getStore('DeviceAttributes').loadData(Ext.getStore('CommonDeviceAttributes').getData().items, true);
+ Ext.getStore('GroupAttributes').loadData(Ext.getStore('CommonDeviceAttributes').getData().items, true);
+
+ Ext.getStore('Devices').load({
+ scope: this,
+ callback: function () {
+ this.asyncUpdate(true);
+ }
+ });
+ updateView = Ext.get('update');
+ if (updateView) {
+ updateView.remove();
+ }
+ attributionView = Ext.get('attribution');
+ if (attributionView) {
+ attributionView.remove();
+ }
+ if (Traccar.app.isMobile()) {
+ Ext.create('widget.mainMobile');
+ } else {
+ Ext.create('widget.main');
+ }
+ eventId = Ext.Object.fromQueryString(window.location.search).eventId;
+ if (eventId) {
+ this.fireEvent('showsingleevent', eventId);
+ this.removeUrlParameter('eventId');
+ }
+ },
+
+ beep: function () {
+ if (!this.beepSound) {
+ this.beepSound = new Audio('beep.wav');
+ }
+ this.beepSound.play();
+ },
+
+ soundPressed: function () {
+ var soundButton = Ext.getCmp('soundButton');
+ return soundButton && soundButton.pressed;
+ },
+
+ removeUrlParameter: function (param) {
+ var params = Ext.Object.fromQueryString(window.location.search);
+ delete params[param];
+ if (Ext.Object.isEmpty(params)) {
+ window.history.pushState(null, null, window.location.pathname);
+ } else {
+ window.history.pushState(null, null, window.location.pathname + '?' + Ext.Object.toQueryString(params));
+ }
+ },
+
+ asyncUpdate: function (first) {
+ var self = this, protocol, pathname, socket;
+ protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
+ pathname = window.location.pathname.substring(0, window.location.pathname.lastIndexOf('/') + 1);
+ socket = new WebSocket(protocol + '//' + window.location.host + pathname + 'api/socket');
+
+ socket.onclose = function () {
+ Ext.Ajax.request({
+ url: 'api/devices',
+ success: function (response) {
+ self.updateDevices(Ext.decode(response.responseText));
+ },
+ failure: function (response) {
+ if (response.status === 401) {
+ window.location.reload();
+ }
+ }
+ });
+
+ Ext.Ajax.request({
+ url: 'api/positions',
+ headers: {
+ Accept: 'application/json'
+ },
+ success: function (response) {
+ self.updatePositions(Ext.decode(response.responseText));
+ }
+ });
+
+ setTimeout(function () {
+ self.asyncUpdate(false);
+ }, Traccar.Style.reconnectTimeout);
+ };
+
+ socket.onmessage = function (event) {
+ var data = Ext.decode(event.data);
+
+ if (data.devices) {
+ self.updateDevices(data.devices);
+ }
+ if (data.positions) {
+ self.updatePositions(data.positions, first);
+ first = false;
+ }
+ if (data.events) {
+ self.updateEvents(data.events);
+ }
+ };
+ },
+
+ updateDevices: function (array) {
+ var i, store, entity;
+ store = Ext.getStore('Devices');
+ for (i = 0; i < array.length; i++) {
+ entity = store.getById(array[i].id);
+ if (entity) {
+ entity.set({
+ status: array[i].status,
+ lastUpdate: array[i].lastUpdate
+ }, {
+ dirty: false
+ });
+ }
+ }
+ },
+
+ updatePositions: function (array, first) {
+ var i, store, entity, uniqueId, device;
+ store = Ext.getStore('LatestPositions');
+ for (i = 0; i < array.length; i++) {
+ entity = store.findRecord('deviceId', array[i].deviceId, 0, false, false, true);
+ if (entity) {
+ entity.set(array[i]);
+ } else {
+ store.add(Ext.create('Traccar.model.Position', array[i]));
+ }
+ if (Ext.getStore('Events').findRecord('positionId', array[i].id, 0, false, false, true)) {
+ Ext.getStore('EventPositions').add(Ext.create('Traccar.model.Position', array[i]));
+ }
+ }
+ if (first) {
+ uniqueId = Ext.Object.fromQueryString(window.location.search).deviceId;
+ if (uniqueId) {
+ device = Ext.getStore('VisibleDevices').findRecord('uniqueId', uniqueId, 0, false, true, true);
+ if (device) {
+ this.fireEvent('selectdevice', device, true);
+ }
+ }
+ if (!device) {
+ this.zoomToAllDevices();
+ }
+ }
+ },
+
+ updateEvents: function (array) {
+ var i, store, device;
+ store = Ext.getStore('Events');
+ for (i = 0; i < array.length; i++) {
+ store.insert(0, array[i]);
+ device = Ext.getStore('Devices').getById(array[i].deviceId);
+ if (device) {
+ if (this.soundPressed()) {
+ this.beep();
+ }
+ Traccar.app.showToast(array[i].text, device.get('name'));
+ } else {
+ Traccar.app.showToast(array[i].text);
+ }
+ }
+ },
+
+ zoomToAllDevices: function () {
+ var lat, lon, zoom;
+ lat = Traccar.app.getPreference('latitude', 0);
+ lon = Traccar.app.getPreference('longitude', 0);
+ zoom = Traccar.app.getPreference('zoom', 0);
+ if (lat === 0 && lon === 0 && zoom === 0) {
+ this.fireEvent('zoomtoalldevices');
+ }
+ }
+});
diff --git a/legacy/web/app/model/Attribute.js b/legacy/web/app/model/Attribute.js
new file mode 100644
index 00000000..b1586a73
--- /dev/null
+++ b/legacy/web/app/model/Attribute.js
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.Attribute', {
+ extend: 'Ext.data.Model',
+
+ fields: [{
+ name: 'priority',
+ type: 'int'
+ }, {
+ name: 'name',
+ type: 'string'
+ }, {
+ name: 'value'
+ }, {
+ name: 'attribute',
+ type: 'string'
+ }]
+});
diff --git a/legacy/web/app/model/Calendar.js b/legacy/web/app/model/Calendar.js
new file mode 100644
index 00000000..8c44d625
--- /dev/null
+++ b/legacy/web/app/model/Calendar.js
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 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.Calendar', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'id',
+ type: 'int'
+ }, {
+ name: 'name',
+ type: 'string'
+ }, {
+ name: 'data'
+ }, {
+ name: 'attributes'
+ }]
+});
diff --git a/legacy/web/app/model/Command.js b/legacy/web/app/model/Command.js
new file mode 100644
index 00000000..f64d2a4b
--- /dev/null
+++ b/legacy/web/app/model/Command.js
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.Command', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'id',
+ type: 'int'
+ }, {
+ name: 'description',
+ type: 'string'
+ }, {
+ name: 'deviceId',
+ type: 'int'
+ }, {
+ name: 'type',
+ type: 'string'
+ }, {
+ name: 'textChannel',
+ type: 'boolean'
+ }, {
+ name: 'attributes'
+ }]
+});
diff --git a/legacy/web/app/model/ComputedAttribute.js b/legacy/web/app/model/ComputedAttribute.js
new file mode 100644
index 00000000..16a78ef1
--- /dev/null
+++ b/legacy/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/legacy/web/app/model/Device.js b/legacy/web/app/model/Device.js
new file mode 100644
index 00000000..ca1e07a6
--- /dev/null
+++ b/legacy/web/app/model/Device.js
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.Device', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'id',
+ type: 'int'
+ }, {
+ name: 'name',
+ type: 'string'
+ }, {
+ name: 'uniqueId',
+ type: 'string'
+ }, {
+ name: 'phone',
+ type: 'string',
+ allowNull: true
+ }, {
+ name: 'model',
+ type: 'string',
+ allowNull: true
+ }, {
+ name: 'contact',
+ type: 'string',
+ allowNull: true
+ }, {
+ name: 'category',
+ type: 'string',
+ allowNull: true
+ }, {
+ name: 'status',
+ type: 'string',
+ allowNull: true
+ }, {
+ name: 'lastUpdate',
+ type: 'date',
+ dateFormat: 'c'
+ }, {
+ name: 'groupId',
+ type: 'int'
+ }, {
+ name: 'disabled',
+ type: 'boolean'
+ }, {
+ name: 'attributes'
+ }]
+});
diff --git a/legacy/web/app/model/Driver.js b/legacy/web/app/model/Driver.js
new file mode 100644
index 00000000..3c3b30e5
--- /dev/null
+++ b/legacy/web/app/model/Driver.js
@@ -0,0 +1,35 @@
+/*
+ * 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.Driver', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'id',
+ type: 'int'
+ }, {
+ name: 'name',
+ type: 'string'
+ }, {
+ name: 'uniqueId',
+ type: 'string'
+ }, {
+ name: 'attributes'
+ }]
+});
diff --git a/legacy/web/app/model/Event.js b/legacy/web/app/model/Event.js
new file mode 100644
index 00000000..d1297dd7
--- /dev/null
+++ b/legacy/web/app/model/Event.js
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 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.Event', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'id',
+ type: 'int'
+ }, {
+ name: 'type',
+ type: 'string'
+ }, {
+ name: 'eventTime',
+ type: 'date',
+ dateFormat: 'c'
+ }, {
+ name: 'deviceId',
+ type: 'int'
+ }, {
+ name: 'positionId',
+ type: 'int'
+ }, {
+ name: 'geofenceId',
+ type: 'int'
+ }, {
+ name: 'maintenanceId',
+ type: 'int'
+ }, {
+ name: 'text',
+ convert: function (v, rec) {
+ var text, alarmKey, geofence, maintenance;
+ if (rec.get('type') === 'commandResult') {
+ text = Strings.eventCommandResult + ': ' + rec.get('attributes')['result'];
+ } else if (rec.get('type') === 'alarm') {
+ alarmKey = rec.get('attributes')['alarm'];
+ alarmKey = 'alarm' + alarmKey.charAt(0).toUpperCase() + alarmKey.slice(1);
+ text = Strings[alarmKey] || alarmKey;
+ } else if (rec.get('type') === 'textMessage') {
+ text = Strings.eventTextMessage + ': ' + rec.get('attributes')['message'];
+ } else if (rec.get('type') === 'driverChanged') {
+ text = Strings.eventDriverChanged + ': ' +
+ Traccar.AttributeFormatter.driverUniqueIdFormatter(rec.get('attributes')['driverUniqueId']);
+ } else {
+ text = Traccar.app.getEventString(rec.get('type'));
+ }
+ if (rec.get('geofenceId')) {
+ geofence = Ext.getStore('Geofences').getById(rec.get('geofenceId'));
+ if (geofence) {
+ text += ' "' + geofence.get('name') + '"';
+ }
+ }
+ if (rec.get('maintenanceId')) {
+ maintenance = Ext.getStore('Maintenances').getById(rec.get('maintenanceId'));
+ if (maintenance) {
+ text += ' "' + maintenance.get('name') + '"';
+ }
+ }
+ return text;
+ },
+ depends: ['type', 'attributes', 'geofenceId', 'maintenanceId']
+ }, {
+ name: 'attributes'
+ }]
+});
diff --git a/legacy/web/app/model/Geofence.js b/legacy/web/app/model/Geofence.js
new file mode 100644
index 00000000..12a9f878
--- /dev/null
+++ b/legacy/web/app/model/Geofence.js
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@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.Geofence', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'id',
+ type: 'int'
+ }, {
+ name: 'name',
+ type: 'string'
+ }, {
+ name: 'description',
+ type: 'string'
+ }, {
+ name: 'area',
+ type: 'string'
+ }, {
+ name: 'calendarId',
+ type: 'int'
+ }, {
+ name: 'attributes'
+ }]
+});
diff --git a/legacy/web/app/model/Group.js b/legacy/web/app/model/Group.js
new file mode 100644
index 00000000..8230fda1
--- /dev/null
+++ b/legacy/web/app/model/Group.js
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@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.Group', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'id',
+ type: 'int'
+ }, {
+ name: 'name',
+ type: 'string'
+ }, {
+ name: 'groupId',
+ type: 'int'
+ }, {
+ name: 'attributes'
+ }]
+});
diff --git a/legacy/web/app/model/KnownAttribute.js b/legacy/web/app/model/KnownAttribute.js
new file mode 100644
index 00000000..f6f41a73
--- /dev/null
+++ b/legacy/web/app/model/KnownAttribute.js
@@ -0,0 +1,35 @@
+/*
+ * 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.KnownAttribute', {
+ extend: 'Ext.data.Model',
+ idProperty: 'key',
+
+ fields: [{
+ name: 'key',
+ type: 'string'
+ }, {
+ name: 'name',
+ type: 'string'
+ }, {
+ name: 'valueType',
+ type: 'string'
+ }, {
+ name: 'dataType',
+ type: 'string'
+ }]
+});
diff --git a/legacy/web/app/model/KnownCommand.js b/legacy/web/app/model/KnownCommand.js
new file mode 100644
index 00000000..06610e32
--- /dev/null
+++ b/legacy/web/app/model/KnownCommand.js
@@ -0,0 +1,34 @@
+/*
+ * 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.KnownCommand', {
+ extend: 'Ext.data.Model',
+ idProperty: 'type',
+
+ fields: [{
+ name: 'type',
+ type: 'string'
+ }, {
+ name: 'name',
+ convert: function (v, rec) {
+ return Traccar.AttributeFormatter.getFormatter('commandType')(rec.get('type'));
+ },
+ depends: ['type']
+ }, {
+ name: 'parameters'
+ }]
+});
diff --git a/legacy/web/app/model/KnownNotification.js b/legacy/web/app/model/KnownNotification.js
new file mode 100644
index 00000000..f42ef972
--- /dev/null
+++ b/legacy/web/app/model/KnownNotification.js
@@ -0,0 +1,32 @@
+/*
+ * 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.KnownNotification', {
+ extend: 'Ext.data.Model',
+ idProperty: 'type',
+
+ fields: [{
+ name: 'type',
+ type: 'string'
+ }, {
+ name: 'name',
+ convert: function (v, rec) {
+ return Traccar.app.getEventString(rec.get('type'));
+ },
+ depends: ['type']
+ }]
+});
diff --git a/legacy/web/app/model/KnownNotificator.js b/legacy/web/app/model/KnownNotificator.js
new file mode 100644
index 00000000..7855a12b
--- /dev/null
+++ b/legacy/web/app/model/KnownNotificator.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 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.KnownNotificator', {
+ extend: 'Ext.data.Model',
+ idProperty: 'type',
+
+ fields: [{
+ name: 'type',
+ type: 'string'
+ }, {
+ name: 'name',
+ convert: function (v, rec) {
+ return Traccar.app.getNotificatorString(rec.get('type'));
+ },
+ depends: ['type']
+ }]
+});
diff --git a/legacy/web/app/model/Maintenance.js b/legacy/web/app/model/Maintenance.js
new file mode 100644
index 00000000..a0654275
--- /dev/null
+++ b/legacy/web/app/model/Maintenance.js
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 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.Maintenance', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'id',
+ type: 'int'
+ }, {
+ name: 'name',
+ type: 'string'
+ }, {
+ name: 'type',
+ type: 'string'
+ }, {
+ name: 'start',
+ type: 'float'
+ }, {
+ name: 'period',
+ type: 'float'
+ }, {
+ name: 'attributes'
+ }]
+});
diff --git a/legacy/web/app/model/Notification.js b/legacy/web/app/model/Notification.js
new file mode 100644
index 00000000..fc9d84d7
--- /dev/null
+++ b/legacy/web/app/model/Notification.js
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2016 - 2018 Anton Tananaev (anton@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.Notification', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'id',
+ type: 'int'
+ }, {
+ name: 'type',
+ type: 'string'
+ }, {
+ name: 'always',
+ type: 'bool'
+ }, {
+ name: 'attributes'
+ }, {
+ name: 'notificators',
+ type: 'string'
+ }, {
+ name: 'calendarId',
+ type: 'int'
+ }]
+});
diff --git a/legacy/web/app/model/Position.js b/legacy/web/app/model/Position.js
new file mode 100644
index 00000000..6db54653
--- /dev/null
+++ b/legacy/web/app/model/Position.js
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.Position', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'id',
+ type: 'int'
+ }, {
+ name: 'protocol',
+ type: 'string'
+ }, {
+ name: 'deviceId',
+ type: 'int'
+ }, {
+ name: 'serverTime',
+ type: 'date',
+ dateFormat: 'c'
+ }, {
+ name: 'deviceTime',
+ type: 'date',
+ dateFormat: 'c'
+ }, {
+ name: 'fixTime',
+ type: 'date',
+ dateFormat: 'c'
+ }, {
+ name: 'valid',
+ type: 'boolean'
+ }, {
+ name: 'accuracy',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('accuracy')
+ }, {
+ name: 'latitude',
+ type: 'float'
+ }, {
+ name: 'longitude',
+ type: 'float'
+ }, {
+ name: 'altitude',
+ type: 'float'
+ }, {
+ name: 'speed',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('speed')
+ }, {
+ name: 'course',
+ type: 'float'
+ }, {
+ name: 'address',
+ type: 'string'
+ }, {
+ name: 'attributes'
+ }]
+});
diff --git a/legacy/web/app/model/ReportStop.js b/legacy/web/app/model/ReportStop.js
new file mode 100644
index 00000000..9aaa58b0
--- /dev/null
+++ b/legacy/web/app/model/ReportStop.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.model.ReportStop', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'deviceId',
+ type: 'int'
+ }, {
+ name: 'deviceName',
+ type: 'string'
+ }, {
+ name: 'duration',
+ type: 'int'
+ }, {
+ name: 'startTime',
+ type: 'date',
+ dateFormat: 'c'
+ }, {
+ name: 'startOdometer',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('distance')
+ }, {
+ name: 'address',
+ type: 'string'
+ }, {
+ name: 'endTime',
+ type: 'date',
+ dateFormat: 'c'
+ }, {
+ name: 'engineHours',
+ type: 'int'
+ }, {
+ name: 'positionId',
+ type: 'int'
+ }, {
+ name: 'spentFuel',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('spentFuel')
+ }]
+});
diff --git a/legacy/web/app/model/ReportSummary.js b/legacy/web/app/model/ReportSummary.js
new file mode 100644
index 00000000..559ffd41
--- /dev/null
+++ b/legacy/web/app/model/ReportSummary.js
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 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.ReportSummary', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'deviceId',
+ type: 'int'
+ }, {
+ name: 'deviceName',
+ type: 'string'
+ }, {
+ name: 'startTime',
+ type: 'date',
+ dateFormat: 'c'
+ }, {
+ name: 'maxSpeed',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('speed')
+ }, {
+ name: 'averageSpeed',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('speed')
+ }, {
+ name: 'distance',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('distance')
+ }, {
+ name: 'startOdometer',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('distance')
+ }, {
+ name: 'endOdometer',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('distance')
+ }, {
+ name: 'engineHours',
+ type: 'int'
+ }, {
+ name: 'spentFuel',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('spentFuel')
+ }]
+});
diff --git a/legacy/web/app/model/ReportTrip.js b/legacy/web/app/model/ReportTrip.js
new file mode 100644
index 00000000..9d45fc87
--- /dev/null
+++ b/legacy/web/app/model/ReportTrip.js
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 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.ReportTrip', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'deviceId',
+ type: 'int'
+ }, {
+ name: 'deviceName',
+ type: 'string'
+ }, {
+ name: 'maxSpeed',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('speed')
+ }, {
+ name: 'averageSpeed',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('speed')
+ }, {
+ name: 'distance',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('distance')
+ }, {
+ name: 'startOdometer',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('distance')
+ }, {
+ name: 'endOdometer',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('distance')
+ }, {
+ name: 'duration',
+ type: 'int'
+ }, {
+ name: 'startTime',
+ type: 'date',
+ dateFormat: 'c'
+ }, {
+ name: 'startAddress',
+ type: 'string'
+ }, {
+ name: 'endTime',
+ type: 'date',
+ dateFormat: 'c'
+ }, {
+ name: 'endAddress',
+ type: 'string'
+ }, {
+ name: 'spentFuel',
+ type: 'float',
+ convert: Traccar.AttributeFormatter.getConverter('spentFuel')
+ }, {
+ name: 'driverUniqueId',
+ type: 'string'
+ }, {
+ name: 'driverName',
+ type: 'string'
+ }]
+});
diff --git a/legacy/web/app/model/Server.js b/legacy/web/app/model/Server.js
new file mode 100644
index 00000000..177b4fc4
--- /dev/null
+++ b/legacy/web/app/model/Server.js
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2015 - 2018 Anton Tananaev (anton@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.Server', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'id',
+ type: 'int'
+ }, {
+ name: 'registration',
+ type: 'boolean'
+ }, {
+ name: 'readonly',
+ type: 'boolean'
+ }, {
+ name: 'deviceReadonly',
+ type: 'boolean'
+ }, {
+ name: 'limitCommands',
+ type: 'boolean'
+ }, {
+ name: 'disableReports',
+ type: 'boolean'
+ }, {
+ name: 'map',
+ type: 'string'
+ }, {
+ name: 'bingKey',
+ type: 'string'
+ }, {
+ name: 'mapUrl',
+ type: 'string'
+ }, {
+ name: 'latitude',
+ type: 'float'
+ }, {
+ name: 'longitude',
+ type: 'float'
+ }, {
+ name: 'zoom',
+ type: 'int'
+ }, {
+ name: 'twelveHourFormat',
+ type: 'boolean'
+ }, {
+ name: 'forceSettings',
+ type: 'boolean'
+ }, {
+ name: 'coordinateFormat',
+ type: 'string'
+ }, {
+ name: 'poiLayer',
+ type: 'string'
+ }, {
+ name: 'announcement',
+ type: 'string'
+ }, {
+ name: 'attributes'
+ }],
+
+ proxy: {
+ type: 'ajax',
+ url: 'api/server',
+ actionMethods: {
+ update: 'PUT'
+ },
+ writer: {
+ type: 'json',
+ writeAllFields: true
+ }
+ }
+});
diff --git a/legacy/web/app/model/Statistics.js b/legacy/web/app/model/Statistics.js
new file mode 100644
index 00000000..95280ac4
--- /dev/null
+++ b/legacy/web/app/model/Statistics.js
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@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.Statistics', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'id',
+ type: 'int'
+ }, {
+ name: 'captureTime',
+ type: 'date',
+ dateFormat: 'c'
+ }, {
+ name: 'activeUsers',
+ type: 'int'
+ }, {
+ name: 'activeDevices',
+ type: 'int'
+ }, {
+ name: 'requests',
+ type: 'int'
+ }, {
+ name: 'messagesReceived',
+ type: 'int'
+ }, {
+ name: 'messagesStored',
+ type: 'int'
+ }, {
+ name: 'mailSent',
+ type: 'int'
+ }, {
+ name: 'smsSent',
+ type: 'int'
+ }, {
+ name: 'geocoderRequests',
+ type: 'int'
+ }, {
+ name: 'geolocationRequests',
+ type: 'int'
+ }, {
+ name: 'attributes'
+ }]
+});
diff --git a/legacy/web/app/model/User.js b/legacy/web/app/model/User.js
new file mode 100644
index 00000000..455bca64
--- /dev/null
+++ b/legacy/web/app/model/User.js
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2015 - 2018 Anton Tananaev (anton@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.User', {
+ extend: 'Ext.data.Model',
+ identifier: 'negative',
+
+ fields: [{
+ name: 'id',
+ type: 'int'
+ }, {
+ name: 'name',
+ type: 'string'
+ }, {
+ name: 'login',
+ type: 'string'
+ }, {
+ name: 'email',
+ type: 'string'
+ }, {
+ name: 'password',
+ type: 'string'
+ }, {
+ name: 'phone',
+ type: 'string'
+ }, {
+ name: 'readonly',
+ type: 'boolean'
+ }, {
+ name: 'administrator',
+ type: 'boolean'
+ }, {
+ name: 'map',
+ type: 'string'
+ }, {
+ name: 'latitude',
+ type: 'float'
+ }, {
+ name: 'longitude',
+ type: 'float'
+ }, {
+ name: 'zoom',
+ type: 'int'
+ }, {
+ name: 'twelveHourFormat',
+ type: 'boolean'
+ }, {
+ name: 'coordinateFormat',
+ type: 'string'
+ }, {
+ name: 'disabled',
+ type: 'boolean'
+ }, {
+ name: 'expirationTime',
+ type: 'date',
+ dateFormat: 'c'
+ }, {
+ name: 'deviceLimit',
+ type: 'int'
+ }, {
+ name: 'userLimit',
+ type: 'int'
+ }, {
+ name: 'deviceReadonly',
+ type: 'boolean'
+ }, {
+ name: 'limitCommands',
+ type: 'boolean'
+ }, {
+ name: 'disableReports',
+ type: 'boolean'
+ }, {
+ name: 'poiLayer',
+ type: 'string'
+ }, {
+ name: 'attributes'
+ }],
+
+ proxy: {
+ type: 'rest',
+ url: 'api/users',
+ writer: {
+ type: 'json',
+ writeAllFields: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/AlarmTypes.js b/legacy/web/app/store/AlarmTypes.js
new file mode 100644
index 00000000..1ee7ffe8
--- /dev/null
+++ b/legacy/web/app/store/AlarmTypes.js
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 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.AlarmTypes', {
+ extend: 'Ext.data.Store',
+ fields: ['key', 'name'],
+
+ data: (function () {
+ var key, items = [];
+ for (key in Strings) {
+ if (Strings.hasOwnProperty(key) && key.lastIndexOf('alarm', 0) === 0) {
+ items.push({
+ key: key.charAt(5).toLowerCase() + key.slice(6),
+ name: Strings[key]
+ });
+ }
+ }
+ return items;
+ })()
+});
diff --git a/legacy/web/app/store/AllCalendars.js b/legacy/web/app/store/AllCalendars.js
new file mode 100644
index 00000000..26557287
--- /dev/null
+++ b/legacy/web/app/store/AllCalendars.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 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.AllCalendars', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Calendar',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/calendars',
+ extraParams: {
+ all: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/AllCommandTypes.js b/legacy/web/app/store/AllCommandTypes.js
new file mode 100644
index 00000000..c35f50d9
--- /dev/null
+++ b/legacy/web/app/store/AllCommandTypes.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 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.AllCommandTypes', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.KnownCommand',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/commands/types',
+ listeners: {
+ exception: function (proxy, response) {
+ Traccar.app.showError(response);
+ }
+ }
+ }
+});
diff --git a/legacy/web/app/store/AllCommands.js b/legacy/web/app/store/AllCommands.js
new file mode 100644
index 00000000..7f5e1253
--- /dev/null
+++ b/legacy/web/app/store/AllCommands.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.AllCommands', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Command',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/commands',
+ extraParams: {
+ all: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/AllComputedAttributes.js b/legacy/web/app/store/AllComputedAttributes.js
new file mode 100644
index 00000000..e63feb14
--- /dev/null
+++ b/legacy/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/legacy/web/app/store/AllDevices.js b/legacy/web/app/store/AllDevices.js
new file mode 100644
index 00000000..338e6be7
--- /dev/null
+++ b/legacy/web/app/store/AllDevices.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.AllDevices', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Device',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/devices',
+ extraParams: {
+ all: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/AllDrivers.js b/legacy/web/app/store/AllDrivers.js
new file mode 100644
index 00000000..9d723885
--- /dev/null
+++ b/legacy/web/app/store/AllDrivers.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.AllDrivers', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Driver',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/drivers',
+ extraParams: {
+ all: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/AllGeofences.js b/legacy/web/app/store/AllGeofences.js
new file mode 100644
index 00000000..4042732b
--- /dev/null
+++ b/legacy/web/app/store/AllGeofences.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@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.AllGeofences', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Geofence',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/geofences',
+ extraParams: {
+ all: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/AllGroups.js b/legacy/web/app/store/AllGroups.js
new file mode 100644
index 00000000..ba02e715
--- /dev/null
+++ b/legacy/web/app/store/AllGroups.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@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.AllGroups', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Group',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/groups',
+ extraParams: {
+ all: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/AllMaintenances.js b/legacy/web/app/store/AllMaintenances.js
new file mode 100644
index 00000000..8435ad40
--- /dev/null
+++ b/legacy/web/app/store/AllMaintenances.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 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.AllMaintenances', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Maintenance',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/maintenance',
+ extraParams: {
+ all: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/AllNotificationTypes.js b/legacy/web/app/store/AllNotificationTypes.js
new file mode 100644
index 00000000..63fec1bc
--- /dev/null
+++ b/legacy/web/app/store/AllNotificationTypes.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 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.AllNotificationTypes', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.KnownNotification',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/notifications/types',
+ listeners: {
+ exception: function (proxy, response) {
+ Traccar.app.showError(response);
+ }
+ }
+ }
+});
diff --git a/legacy/web/app/store/AllNotifications.js b/legacy/web/app/store/AllNotifications.js
new file mode 100644
index 00000000..a3e59e15
--- /dev/null
+++ b/legacy/web/app/store/AllNotifications.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.AllNotifications', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Notification',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/notifications',
+ extraParams: {
+ all: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/AllNotificators.js b/legacy/web/app/store/AllNotificators.js
new file mode 100644
index 00000000..d81b02fd
--- /dev/null
+++ b/legacy/web/app/store/AllNotificators.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 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.AllNotificators', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.KnownNotificator',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/notifications/notificators',
+ listeners: {
+ exception: function (proxy, response) {
+ Traccar.app.showError(response);
+ }
+ }
+ }
+});
diff --git a/legacy/web/app/store/AllTimezones.js b/legacy/web/app/store/AllTimezones.js
new file mode 100644
index 00000000..2a7fa371
--- /dev/null
+++ b/legacy/web/app/store/AllTimezones.js
@@ -0,0 +1,798 @@
+/*
+ * 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.AllTimezones', {
+ extend: 'Ext.data.Store',
+ fields: ['key'],
+
+ sorters: {
+ property: 'key',
+ direction: 'ASC'
+ },
+
+ data: [{
+ key: 'Africa/Abidjan'
+ }, {
+ key: 'Africa/Accra'
+ }, {
+ key: 'Africa/Bissau'
+ }, {
+ key: 'Africa/Casablanca'
+ }, {
+ key: 'Africa/El_Aaiun'
+ }, {
+ key: 'Africa/Monrovia'
+ }, {
+ key: 'America/Danmarkshavn'
+ }, {
+ key: 'Antarctica/Troll'
+ }, {
+ key: 'Atlantic/Canary'
+ }, {
+ key: 'Atlantic/Faroe'
+ }, {
+ key: 'Atlantic/Madeira'
+ }, {
+ key: 'Atlantic/Reykjavik'
+ }, {
+ key: 'GMT'
+ }, {
+ key: 'Etc/GMT'
+ }, {
+ key: 'Etc/UCT'
+ }, {
+ key: 'Etc/UTC'
+ }, {
+ key: 'Europe/Dublin'
+ }, {
+ key: 'Europe/Lisbon'
+ }, {
+ key: 'Europe/London'
+ }, {
+ key: 'WET'
+ }, {
+ key: 'Africa/Algiers'
+ }, {
+ key: 'Africa/Ceuta'
+ }, {
+ key: 'Africa/Lagos'
+ }, {
+ key: 'Africa/Ndjamena'
+ }, {
+ key: 'Africa/Tunis'
+ }, {
+ key: 'Africa/Windhoek'
+ }, {
+ key: 'CET'
+ }, {
+ key: 'Etc/GMT-1'
+ }, {
+ key: 'Europe/Amsterdam'
+ }, {
+ key: 'Europe/Andorra'
+ }, {
+ key: 'Europe/Belgrade'
+ }, {
+ key: 'Europe/Berlin'
+ }, {
+ key: 'Europe/Brussels'
+ }, {
+ key: 'Europe/Budapest'
+ }, {
+ key: 'Europe/Copenhagen'
+ }, {
+ key: 'Europe/Gibraltar'
+ }, {
+ key: 'Europe/Luxembourg'
+ }, {
+ key: 'Europe/Madrid'
+ }, {
+ key: 'Europe/Malta'
+ }, {
+ key: 'Europe/Monaco'
+ }, {
+ key: 'Europe/Oslo'
+ }, {
+ key: 'Europe/Paris'
+ }, {
+ key: 'Europe/Prague'
+ }, {
+ key: 'Europe/Rome'
+ }, {
+ key: 'Europe/Stockholm'
+ }, {
+ key: 'Europe/Tirane'
+ }, {
+ key: 'Europe/Vienna'
+ }, {
+ key: 'Europe/Warsaw'
+ }, {
+ key: 'Europe/Zurich'
+ }, {
+ key: 'MET'
+ }, {
+ key: 'Africa/Cairo'
+ }, {
+ key: 'Africa/Johannesburg'
+ }, {
+ key: 'Africa/Maputo'
+ }, {
+ key: 'Africa/Tripoli'
+ }, {
+ key: 'Asia/Amman'
+ }, {
+ key: 'Asia/Beirut'
+ }, {
+ key: 'Asia/Damascus'
+ }, {
+ key: 'Asia/Gaza'
+ }, {
+ key: 'Asia/Hebron'
+ }, {
+ key: 'Asia/Jerusalem'
+ }, {
+ key: 'Asia/Nicosia'
+ }, {
+ key: 'EET'
+ }, {
+ key: 'Etc/GMT-2'
+ }, {
+ key: 'Europe/Athens'
+ }, {
+ key: 'Europe/Bucharest'
+ }, {
+ key: 'Europe/Chisinau'
+ }, {
+ key: 'Europe/Helsinki'
+ }, {
+ key: 'Europe/Kaliningrad'
+ }, {
+ key: 'Europe/Kiev'
+ }, {
+ key: 'Europe/Riga'
+ }, {
+ key: 'Europe/Sofia'
+ }, {
+ key: 'Europe/Tallinn'
+ }, {
+ key: 'Europe/Uzhgorod'
+ }, {
+ key: 'Europe/Vilnius'
+ }, {
+ key: 'Europe/Zaporozhye'
+ }, {
+ key: 'Africa/Khartoum'
+ }, {
+ key: 'Africa/Nairobi'
+ }, {
+ key: 'Antarctica/Syowa'
+ }, {
+ key: 'Asia/Baghdad'
+ }, {
+ key: 'Asia/Famagusta'
+ }, {
+ key: 'Asia/Qatar'
+ }, {
+ key: 'Asia/Riyadh'
+ }, {
+ key: 'Etc/GMT-3'
+ }, {
+ key: 'Europe/Istanbul'
+ }, {
+ key: 'Europe/Kirov'
+ }, {
+ key: 'Europe/Minsk'
+ }, {
+ key: 'Europe/Moscow'
+ }, {
+ key: 'Europe/Simferopol'
+ }, {
+ key: 'Europe/Volgograd'
+ }, {
+ key: 'Asia/Tehran'
+ }, {
+ key: 'Asia/Baku'
+ }, {
+ key: 'Asia/Dubai'
+ }, {
+ key: 'Asia/Tbilisi'
+ }, {
+ key: 'Asia/Yerevan'
+ }, {
+ key: 'Etc/GMT-4'
+ }, {
+ key: 'Europe/Astrakhan'
+ }, {
+ key: 'Europe/Samara'
+ }, {
+ key: 'Europe/Saratov'
+ }, {
+ key: 'Europe/Ulyanovsk'
+ }, {
+ key: 'Indian/Mahe'
+ }, {
+ key: 'Indian/Mauritius'
+ }, {
+ key: 'Indian/Reunion'
+ }, {
+ key: 'Asia/Kabul'
+ }, {
+ key: 'Antarctica/Mawson'
+ }, {
+ key: 'Asia/Aqtau'
+ }, {
+ key: 'Asia/Aqtobe'
+ }, {
+ key: 'Asia/Ashgabat'
+ }, {
+ key: 'Asia/Atyrau'
+ }, {
+ key: 'Asia/Dushanbe'
+ }, {
+ key: 'Asia/Karachi'
+ }, {
+ key: 'Asia/Oral'
+ }, {
+ key: 'Asia/Samarkand'
+ }, {
+ key: 'Asia/Tashkent'
+ }, {
+ key: 'Asia/Yekaterinburg'
+ }, {
+ key: 'Etc/GMT-5'
+ }, {
+ key: 'Indian/Kerguelen'
+ }, {
+ key: 'Indian/Maldives'
+ }, {
+ key: 'Asia/Colombo'
+ }, {
+ key: 'Asia/Kolkata'
+ }, {
+ key: 'Asia/Kathmandu'
+ }, {
+ key: 'Antarctica/Vostok'
+ }, {
+ key: 'Asia/Almaty'
+ }, {
+ key: 'Asia/Bishkek'
+ }, {
+ key: 'Asia/Dhaka'
+ }, {
+ key: 'Asia/Omsk'
+ }, {
+ key: 'Asia/Qyzylorda'
+ }, {
+ key: 'Asia/Thimphu'
+ }, {
+ key: 'Asia/Urumqi'
+ }, {
+ key: 'Etc/GMT-6'
+ }, {
+ key: 'Indian/Chagos'
+ }, {
+ key: 'Asia/Yangon'
+ }, {
+ key: 'Indian/Cocos'
+ }, {
+ key: 'Antarctica/Davis'
+ }, {
+ key: 'Asia/Bangkok'
+ }, {
+ key: 'Asia/Barnaul'
+ }, {
+ key: 'Asia/Ho_Chi_Minh'
+ }, {
+ key: 'Asia/Hovd'
+ }, {
+ key: 'Asia/Jakarta'
+ }, {
+ key: 'Asia/Krasnoyarsk'
+ }, {
+ key: 'Asia/Novokuznetsk'
+ }, {
+ key: 'Asia/Novosibirsk'
+ }, {
+ key: 'Asia/Pontianak'
+ }, {
+ key: 'Asia/Tomsk'
+ }, {
+ key: 'Etc/GMT-7'
+ }, {
+ key: 'Indian/Christmas'
+ }, {
+ key: 'Asia/Brunei'
+ }, {
+ key: 'Asia/Choibalsan'
+ }, {
+ key: 'Asia/Hong_Kong'
+ }, {
+ key: 'Asia/Irkutsk'
+ }, {
+ key: 'Asia/Kuala_Lumpur'
+ }, {
+ key: 'Asia/Kuching'
+ }, {
+ key: 'Asia/Macau'
+ }, {
+ key: 'Asia/Makassar'
+ }, {
+ key: 'Asia/Manila'
+ }, {
+ key: 'Asia/Shanghai'
+ }, {
+ key: 'Asia/Singapore'
+ }, {
+ key: 'Asia/Taipei'
+ }, {
+ key: 'Asia/Ulaanbaatar'
+ }, {
+ key: 'Australia/Perth'
+ }, {
+ key: 'Etc/GMT-8'
+ }, {
+ key: 'Asia/Pyongyang'
+ }, {
+ key: 'Australia/Eucla'
+ }, {
+ key: 'Asia/Chita'
+ }, {
+ key: 'Asia/Dili'
+ }, {
+ key: 'Asia/Jayapura'
+ }, {
+ key: 'Asia/Khandyga'
+ }, {
+ key: 'Asia/Seoul'
+ }, {
+ key: 'Asia/Tokyo'
+ }, {
+ key: 'Asia/Yakutsk'
+ }, {
+ key: 'Etc/GMT-9'
+ }, {
+ key: 'Pacific/Palau'
+ }, {
+ key: 'Australia/Adelaide'
+ }, {
+ key: 'Australia/Broken_Hill'
+ }, {
+ key: 'Australia/Darwin'
+ }, {
+ key: 'Antarctica/DumontDUrville'
+ }, {
+ key: 'Asia/Ust-Nera'
+ }, {
+ key: 'Asia/Vladivostok'
+ }, {
+ key: 'Australia/Brisbane'
+ }, {
+ key: 'Australia/Currie'
+ }, {
+ key: 'Australia/Hobart'
+ }, {
+ key: 'Australia/Lindeman'
+ }, {
+ key: 'Australia/Melbourne'
+ }, {
+ key: 'Australia/Sydney'
+ }, {
+ key: 'Etc/GMT-10'
+ }, {
+ key: 'Pacific/Chuuk'
+ }, {
+ key: 'Pacific/Guam'
+ }, {
+ key: 'Pacific/Port_Moresby'
+ }, {
+ key: 'Australia/Lord_Howe'
+ }, {
+ key: 'Antarctica/Casey'
+ }, {
+ key: 'Antarctica/Macquarie'
+ }, {
+ key: 'Asia/Magadan'
+ }, {
+ key: 'Asia/Sakhalin'
+ }, {
+ key: 'Asia/Srednekolymsk'
+ }, {
+ key: 'Etc/GMT-11'
+ }, {
+ key: 'Pacific/Bougainville'
+ }, {
+ key: 'Pacific/Efate'
+ }, {
+ key: 'Pacific/Guadalcanal'
+ }, {
+ key: 'Pacific/Kosrae'
+ }, {
+ key: 'Pacific/Norfolk'
+ }, {
+ key: 'Pacific/Noumea'
+ }, {
+ key: 'Pacific/Pohnpei'
+ }, {
+ key: 'Asia/Anadyr'
+ }, {
+ key: 'Asia/Kamchatka'
+ }, {
+ key: 'Etc/GMT-12'
+ }, {
+ key: 'Pacific/Auckland'
+ }, {
+ key: 'Pacific/Fiji'
+ }, {
+ key: 'Pacific/Funafuti'
+ }, {
+ key: 'Pacific/Kwajalein'
+ }, {
+ key: 'Pacific/Majuro'
+ }, {
+ key: 'Pacific/Nauru'
+ }, {
+ key: 'Pacific/Tarawa'
+ }, {
+ key: 'Pacific/Wake'
+ }, {
+ key: 'Pacific/Wallis'
+ }, {
+ key: 'Pacific/Chatham'
+ }, {
+ key: 'Etc/GMT-13'
+ }, {
+ key: 'Pacific/Apia'
+ }, {
+ key: 'Pacific/Enderbury'
+ }, {
+ key: 'Pacific/Fakaofo'
+ }, {
+ key: 'Pacific/Tongatapu'
+ }, {
+ key: 'Etc/GMT-14'
+ }, {
+ key: 'Pacific/Kiritimati'
+ }, {
+ key: 'America/Scoresbysund'
+ }, {
+ key: 'Atlantic/Azores'
+ }, {
+ key: 'Atlantic/Cape_Verde'
+ }, {
+ key: 'Etc/GMT+1'
+ }, {
+ key: 'America/Noronha'
+ }, {
+ key: 'Atlantic/South_Georgia'
+ }, {
+ key: 'Etc/GMT+2'
+ }, {
+ key: 'America/Araguaina'
+ }, {
+ key: 'America/Argentina/Buenos_Aires'
+ }, {
+ key: 'America/Argentina/Catamarca'
+ }, {
+ key: 'America/Argentina/Cordoba'
+ }, {
+ key: 'America/Argentina/Jujuy'
+ }, {
+ key: 'America/Argentina/La_Rioja'
+ }, {
+ key: 'America/Argentina/Mendoza'
+ }, {
+ key: 'America/Argentina/Rio_Gallegos'
+ }, {
+ key: 'America/Argentina/Salta'
+ }, {
+ key: 'America/Argentina/San_Juan'
+ }, {
+ key: 'America/Argentina/San_Luis'
+ }, {
+ key: 'America/Argentina/Tucuman'
+ }, {
+ key: 'America/Argentina/Ushuaia'
+ }, {
+ key: 'America/Bahia'
+ }, {
+ key: 'America/Belem'
+ }, {
+ key: 'America/Cayenne'
+ }, {
+ key: 'America/Fortaleza'
+ }, {
+ key: 'America/Godthab'
+ }, {
+ key: 'America/Maceio'
+ }, {
+ key: 'America/Miquelon'
+ }, {
+ key: 'America/Montevideo'
+ }, {
+ key: 'America/Paramaribo'
+ }, {
+ key: 'America/Recife'
+ }, {
+ key: 'America/Santarem'
+ }, {
+ key: 'America/Sao_Paulo'
+ }, {
+ key: 'Antarctica/Rothera'
+ }, {
+ key: 'Atlantic/Stanley'
+ }, {
+ key: 'Etc/GMT+3'
+ }, {
+ key: 'America/St_Johns'
+ }, {
+ key: 'America/Asuncion'
+ }, {
+ key: 'America/Barbados'
+ }, {
+ key: 'America/Blanc-Sablon'
+ }, {
+ key: 'America/Boa_Vista'
+ }, {
+ key: 'America/Campo_Grande'
+ }, {
+ key: 'America/Caracas'
+ }, {
+ key: 'America/Cuiaba'
+ }, {
+ key: 'America/Curacao'
+ }, {
+ key: 'America/Glace_Bay'
+ }, {
+ key: 'America/Goose_Bay'
+ }, {
+ key: 'America/Grand_Turk'
+ }, {
+ key: 'America/Guyana'
+ }, {
+ key: 'America/Halifax'
+ }, {
+ key: 'America/La_Paz'
+ }, {
+ key: 'America/Manaus'
+ }, {
+ key: 'America/Martinique'
+ }, {
+ key: 'America/Moncton'
+ }, {
+ key: 'America/Port_of_Spain'
+ }, {
+ key: 'America/Porto_Velho'
+ }, {
+ key: 'America/Puerto_Rico'
+ }, {
+ key: 'America/Santiago'
+ }, {
+ key: 'America/Santo_Domingo'
+ }, {
+ key: 'America/Thule'
+ }, {
+ key: 'Antarctica/Palmer'
+ }, {
+ key: 'Atlantic/Bermuda'
+ }, {
+ key: 'Etc/GMT+4'
+ }, {
+ key: 'America/Atikokan'
+ }, {
+ key: 'America/Bogota'
+ }, {
+ key: 'America/Cancun'
+ }, {
+ key: 'America/Detroit'
+ }, {
+ key: 'America/Eirunepe'
+ }, {
+ key: 'America/Guayaquil'
+ }, {
+ key: 'America/Havana'
+ }, {
+ key: 'America/Indiana/Indianapolis'
+ }, {
+ key: 'America/Indiana/Marengo'
+ }, {
+ key: 'America/Indiana/Petersburg'
+ }, {
+ key: 'America/Indiana/Vevay'
+ }, {
+ key: 'America/Indiana/Vincennes'
+ }, {
+ key: 'America/Indiana/Winamac'
+ }, {
+ key: 'America/Iqaluit'
+ }, {
+ key: 'America/Jamaica'
+ }, {
+ key: 'America/Kentucky/Louisville'
+ }, {
+ key: 'America/Kentucky/Monticello'
+ }, {
+ key: 'America/Lima'
+ }, {
+ key: 'America/Nassau'
+ }, {
+ key: 'America/New_York'
+ }, {
+ key: 'America/Nipigon'
+ }, {
+ key: 'America/Panama'
+ }, {
+ key: 'America/Pangnirtung'
+ }, {
+ key: 'America/Port-au-Prince'
+ }, {
+ key: 'America/Rio_Branco'
+ }, {
+ key: 'America/Thunder_Bay'
+ }, {
+ key: 'America/Toronto'
+ }, {
+ key: 'EST'
+ }, {
+ key: 'EST5EDT'
+ }, {
+ key: 'Etc/GMT+5'
+ }, {
+ key: 'America/Bahia_Banderas'
+ }, {
+ key: 'America/Belize'
+ }, {
+ key: 'America/Chicago'
+ }, {
+ key: 'America/Costa_Rica'
+ }, {
+ key: 'America/El_Salvador'
+ }, {
+ key: 'America/Guatemala'
+ }, {
+ key: 'America/Indiana/Knox'
+ }, {
+ key: 'America/Indiana/Tell_City'
+ }, {
+ key: 'America/Managua'
+ }, {
+ key: 'America/Matamoros'
+ }, {
+ key: 'America/Menominee'
+ }, {
+ key: 'America/Merida'
+ }, {
+ key: 'America/Mexico_City'
+ }, {
+ key: 'America/Monterrey'
+ }, {
+ key: 'America/North_Dakota/Beulah'
+ }, {
+ key: 'America/North_Dakota/Center'
+ }, {
+ key: 'America/North_Dakota/New_Salem'
+ }, {
+ key: 'America/Rainy_River'
+ }, {
+ key: 'America/Rankin_Inlet'
+ }, {
+ key: 'America/Regina'
+ }, {
+ key: 'America/Resolute'
+ }, {
+ key: 'America/Swift_Current'
+ }, {
+ key: 'America/Tegucigalpa'
+ }, {
+ key: 'America/Winnipeg'
+ }, {
+ key: 'CST6CDT'
+ }, {
+ key: 'Etc/GMT+6'
+ }, {
+ key: 'Pacific/Easter'
+ }, {
+ key: 'Pacific/Galapagos'
+ }, {
+ key: 'America/Boise'
+ }, {
+ key: 'America/Cambridge_Bay'
+ }, {
+ key: 'America/Chihuahua'
+ }, {
+ key: 'America/Creston'
+ }, {
+ key: 'America/Dawson_Creek'
+ }, {
+ key: 'America/Denver'
+ }, {
+ key: 'America/Edmonton'
+ }, {
+ key: 'America/Fort_Nelson'
+ }, {
+ key: 'America/Hermosillo'
+ }, {
+ key: 'America/Inuvik'
+ }, {
+ key: 'America/Mazatlan'
+ }, {
+ key: 'America/Ojinaga'
+ }, {
+ key: 'America/Phoenix'
+ }, {
+ key: 'America/Yellowknife'
+ }, {
+ key: 'Etc/GMT+7'
+ }, {
+ key: 'MST'
+ }, {
+ key: 'MST7MDT'
+ }, {
+ key: 'America/Dawson'
+ }, {
+ key: 'America/Los_Angeles'
+ }, {
+ key: 'America/Tijuana'
+ }, {
+ key: 'America/Vancouver'
+ }, {
+ key: 'America/Whitehorse'
+ }, {
+ key: 'Etc/GMT+8'
+ }, {
+ key: 'Pacific/Pitcairn'
+ }, {
+ key: 'PST8PDT'
+ }, {
+ key: 'America/Anchorage'
+ }, {
+ key: 'America/Juneau'
+ }, {
+ key: 'America/Metlakatla'
+ }, {
+ key: 'America/Nome'
+ }, {
+ key: 'America/Sitka'
+ }, {
+ key: 'America/Yakutat'
+ }, {
+ key: 'Etc/GMT+9'
+ }, {
+ key: 'Pacific/Gambier'
+ }, {
+ key: 'Pacific/Marquesas'
+ }, {
+ key: 'America/Adak'
+ }, {
+ key: 'Etc/GMT+10'
+ }, {
+ key: 'HST'
+ }, {
+ key: 'Pacific/Honolulu'
+ }, {
+ key: 'Pacific/Rarotonga'
+ }, {
+ key: 'Pacific/Tahiti'
+ }, {
+ key: 'Etc/GMT+11'
+ }, {
+ key: 'Pacific/Niue'
+ }, {
+ key: 'Pacific/Pago_Pago'
+ }, {
+ key: 'Etc/GMT+12'
+ }]
+});
diff --git a/legacy/web/app/store/AttributeValueTypes.js b/legacy/web/app/store/AttributeValueTypes.js
new file mode 100644
index 00000000..b80eba39
--- /dev/null
+++ b/legacy/web/app/store/AttributeValueTypes.js
@@ -0,0 +1,33 @@
+/*
+ * 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.AttributeValueTypes', {
+ extend: 'Ext.data.Store',
+ fields: ['id', 'name'],
+ proxy: 'memory',
+
+ data: [{
+ id: 'string',
+ name: Strings.sharedTypeString
+ }, {
+ id: 'number',
+ name: Strings.sharedTypeNumber
+ }, {
+ id: 'boolean',
+ name: Strings.sharedTypeBoolean
+ }]
+});
diff --git a/legacy/web/app/store/Attributes.js b/legacy/web/app/store/Attributes.js
new file mode 100644
index 00000000..388fa436
--- /dev/null
+++ b/legacy/web/app/store/Attributes.js
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.Attributes', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Attribute',
+
+ sorters: [{
+ property: 'priority'
+ }]
+});
diff --git a/legacy/web/app/store/Calendars.js b/legacy/web/app/store/Calendars.js
new file mode 100644
index 00000000..fa8e5c66
--- /dev/null
+++ b/legacy/web/app/store/Calendars.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 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.Calendars', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Calendar',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/calendars',
+ writer: {
+ writeAllFields: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/CommandTypes.js b/legacy/web/app/store/CommandTypes.js
new file mode 100644
index 00000000..3b898f2e
--- /dev/null
+++ b/legacy/web/app/store/CommandTypes.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 Gabor Somogyi (gabor.g.somogyi@gmail.com)
+ * 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.CommandTypes', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.KnownCommand',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/commands/types',
+ listeners: {
+ 'exception': function (proxy, response) {
+ Traccar.app.showError(response);
+ }
+ }
+ }
+});
diff --git a/legacy/web/app/store/Commands.js b/legacy/web/app/store/Commands.js
new file mode 100644
index 00000000..3e5b7604
--- /dev/null
+++ b/legacy/web/app/store/Commands.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.Commands', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Command',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/commands',
+ writer: {
+ writeAllFields: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/CommonDeviceAttributes.js b/legacy/web/app/store/CommonDeviceAttributes.js
new file mode 100644
index 00000000..e63daa6b
--- /dev/null
+++ b/legacy/web/app/store/CommonDeviceAttributes.js
@@ -0,0 +1,32 @@
+/*
+ * 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.CommonDeviceAttributes', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.KnownAttribute',
+
+ data: [{
+ key: 'speedLimit',
+ name: Strings.attributeSpeedLimit,
+ valueType: 'number',
+ dataType: 'speed'
+ }, {
+ key: 'report.ignoreOdometer',
+ name: Strings.attributeReportIgnoreOdometer,
+ valueType: 'boolean'
+ }]
+});
diff --git a/legacy/web/app/store/CommonUserAttributes.js b/legacy/web/app/store/CommonUserAttributes.js
new file mode 100644
index 00000000..0619df22
--- /dev/null
+++ b/legacy/web/app/store/CommonUserAttributes.js
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2017 - 2022 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.CommonUserAttributes', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.KnownAttribute',
+
+ data: [{
+ key: 'web.liveRouteLength',
+ name: Strings.attributeWebLiveRouteLength,
+ valueType: 'number',
+ allowDecimals: false
+ }, {
+ key: 'web.selectZoom',
+ name: Strings.attributeWebSelectZoom,
+ valueType: 'number',
+ allowDecimals: false,
+ minValue: Traccar.Style.mapDefaultZoom,
+ maxValue: Traccar.Style.mapMaxZoom
+ }, {
+ key: 'web.maxZoom',
+ name: Strings.attributeWebMaxZoom,
+ valueType: 'number',
+ allowDecimals: false,
+ minValue: Traccar.Style.mapDefaultZoom,
+ maxValue: Traccar.Style.mapMaxZoom
+ }, {
+ key: 'ui.disableEvents',
+ name: Strings.attributeUiDisableEvents,
+ valueType: 'boolean'
+ }, {
+ key: 'ui.disableVehicleFeatures',
+ name: Strings.attributeUiDisableVehicleFeatures,
+ valueType: 'boolean'
+ }, {
+ key: 'ui.disableDrivers',
+ name: Strings.attributeUiDisableDrivers,
+ valueType: 'boolean'
+ }, {
+ key: 'ui.disableComputedAttributes',
+ name: Strings.attributeUiDisableComputedAttributes,
+ valueType: 'boolean'
+ }, {
+ key: 'ui.disableCalendars',
+ name: Strings.attributeUiDisableCalendars,
+ valueType: 'boolean'
+ }, {
+ key: 'ui.disableMaintenance',
+ name: Strings.attributeUiDisableMaintenance,
+ valueType: 'boolean'
+ }, {
+ key: 'ui.hidePositionAttributes',
+ name: Strings.attributeUiHidePositionAttributes,
+ valueType: 'string'
+ }, {
+ key: 'distanceUnit',
+ name: Strings.settingsDistanceUnit,
+ valueType: 'string',
+ dataType: 'distanceUnit'
+ }, {
+ key: 'speedUnit',
+ name: Strings.settingsSpeedUnit,
+ valueType: 'string',
+ dataType: 'speedUnit'
+ }, {
+ key: 'volumeUnit',
+ name: Strings.settingsVolumeUnit,
+ valueType: 'string',
+ dataType: 'volumeUnit'
+ }, {
+ key: 'timezone',
+ name: Strings.sharedTimezone,
+ valueType: 'string',
+ dataType: 'timezone'
+ }]
+});
diff --git a/legacy/web/app/store/ComputedAttributes.js b/legacy/web/app/store/ComputedAttributes.js
new file mode 100644
index 00000000..33d78298
--- /dev/null
+++ b/legacy/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/legacy/web/app/store/CoordinateFormats.js b/legacy/web/app/store/CoordinateFormats.js
new file mode 100644
index 00000000..d5db871a
--- /dev/null
+++ b/legacy/web/app/store/CoordinateFormats.js
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@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.CoordinateFormats', {
+ extend: 'Ext.data.Store',
+ fields: ['key', 'name'],
+
+ data: [{
+ key: 'dd',
+ name: Strings.sharedDecimalDegrees
+ }, {
+ key: 'ddm',
+ name: Strings.sharedDegreesDecimalMinutes
+ }, {
+ key: 'dms',
+ name: Strings.sharedDegreesMinutesSeconds
+ }],
+
+ formatValue: function (key, value, unit) {
+ var hemisphere, degrees, minutes, seconds;
+ if (key === 'latitude') {
+ hemisphere = value >= 0 ? 'N' : 'S';
+ } else {
+ hemisphere = value >= 0 ? 'E' : 'W';
+ }
+ switch (unit) {
+ case 'ddm':
+ value = Math.abs(value);
+ degrees = Math.floor(value);
+ minutes = (value - degrees) * 60;
+ return degrees + '° ' + minutes.toFixed(Traccar.Style.coordinatePrecision) + '\' ' + hemisphere;
+ case 'dms':
+ value = Math.abs(value);
+ degrees = Math.floor(value);
+ minutes = Math.floor((value - degrees) * 60);
+ seconds = Math.round((value - degrees - minutes / 60) * 3600);
+ return degrees + '° ' + minutes + '\' ' + seconds + '" ' + hemisphere;
+ default:
+ return value.toFixed(Traccar.Style.coordinatePrecision) + '°';
+ }
+ }
+});
diff --git a/legacy/web/app/store/DeviceAttributes.js b/legacy/web/app/store/DeviceAttributes.js
new file mode 100644
index 00000000..45ae6e3d
--- /dev/null
+++ b/legacy/web/app/store/DeviceAttributes.js
@@ -0,0 +1,52 @@
+/*
+ * 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.DeviceAttributes', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.KnownAttribute',
+
+ data: [{
+ key: 'web.reportColor',
+ name: Strings.attributeWebReportColor,
+ valueType: 'color'
+ }, {
+ key: 'devicePassword',
+ name: Strings.attributeDevicePassword,
+ valueType: 'string'
+ }, {
+ key: 'processing.copyAttributes',
+ name: Strings.attributeProcessingCopyAttributes,
+ valueType: 'string'
+ }, {
+ key: 'decoder.timezone',
+ name: Strings.sharedTimezone,
+ valueType: 'string',
+ dataType: 'timezone'
+ }, {
+ key: 'deviceInactivityStart',
+ name: Strings.attributeDeviceInactivityStart,
+ valueType: 'number',
+ allowDecimals: false,
+ minValue: 1
+ }, {
+ key: 'deviceInactivityPeriod',
+ name: Strings.attributeDeviceInactivityPeriod,
+ valueType: 'number',
+ allowDecimals: false,
+ minValue: 1
+ }]
+});
diff --git a/legacy/web/app/store/DeviceCommands.js b/legacy/web/app/store/DeviceCommands.js
new file mode 100644
index 00000000..7233b3ba
--- /dev/null
+++ b/legacy/web/app/store/DeviceCommands.js
@@ -0,0 +1,32 @@
+/*
+ * 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.DeviceCommands', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Command',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/commands/send',
+ listeners: {
+ 'exception': function (proxy, response) {
+ Traccar.app.showError(response);
+ }
+ }
+ }
+});
diff --git a/legacy/web/app/store/DeviceImages.js b/legacy/web/app/store/DeviceImages.js
new file mode 100644
index 00000000..6f8e8cfd
--- /dev/null
+++ b/legacy/web/app/store/DeviceImages.js
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 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.DeviceImages', {
+ extend: 'Ext.data.Store',
+ fields: ['key', 'name', 'svg', 'fillId', 'rotateId', 'scaleId'],
+
+ data: (function () {
+ var i, key, data = [];
+ for (i = 0; i < window.Images.length; i++) {
+ key = window.Images[i];
+ data.push({
+ key: key,
+ name: Strings['category' + key.charAt(0).toUpperCase() + key.slice(1)],
+ svg: document.getElementById(key + 'Svg').contentDocument,
+ fillId: key === 'arrow' ? 'arrow' : 'background',
+ rotateId: key === 'arrow' ? 'arrow' : 'background',
+ scaleId: key === 'arrow' ? 'arrow' : 'layer1'
+ });
+ }
+ return data;
+ })()
+});
diff --git a/legacy/web/app/store/DeviceStatuses.js b/legacy/web/app/store/DeviceStatuses.js
new file mode 100644
index 00000000..eafba241
--- /dev/null
+++ b/legacy/web/app/store/DeviceStatuses.js
@@ -0,0 +1,35 @@
+/*
+ * 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.DeviceStatuses', {
+ extend: 'Ext.data.Store',
+ fields: ['id', 'name', 'color'],
+
+ data: [{
+ id: 'online',
+ name: Strings.deviceStatusOnline,
+ color: 'view-color-green'
+ }, {
+ id: 'offline',
+ name: Strings.deviceStatusOffline,
+ color: 'view-color-red'
+ }, {
+ id: 'unknown',
+ name: Strings.deviceStatusUnknown,
+ color: 'view-color-yellow'
+ }]
+});
diff --git a/legacy/web/app/store/Devices.js b/legacy/web/app/store/Devices.js
new file mode 100644
index 00000000..e69c93fa
--- /dev/null
+++ b/legacy/web/app/store/Devices.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.Devices', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Device',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/devices',
+ writer: {
+ writeAllFields: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/DistanceUnits.js b/legacy/web/app/store/DistanceUnits.js
new file mode 100644
index 00000000..e64ce234
--- /dev/null
+++ b/legacy/web/app/store/DistanceUnits.js
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 - 2016 Anton Tananaev (anton@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.DistanceUnits', {
+ extend: 'Ext.data.Store',
+ fields: ['key', 'name', 'factor'],
+
+ data: [{
+ key: 'km',
+ name: Strings.sharedKm,
+ factor: 0.001
+ }, {
+ key: 'mi',
+ name: Strings.sharedMi,
+ factor: 0.000621371
+ }, {
+ key: 'nmi',
+ name: Strings.sharedNmi,
+ factor: 0.000539957
+ }],
+
+ convertValue: function (value, unit, back) {
+ var model;
+ if (!unit) {
+ unit = 'km';
+ }
+ model = this.findRecord('key', unit);
+ return back ? value / model.get('factor') : value * model.get('factor');
+ },
+
+ formatValue: function (value, unit, convert) {
+ var model;
+ if (!unit) {
+ unit = 'km';
+ }
+ model = this.findRecord('key', unit);
+ return (convert ? this.convertValue(value, unit) : value).toFixed(2) + ' ' + model.get('name');
+ }
+});
diff --git a/legacy/web/app/store/Drivers.js b/legacy/web/app/store/Drivers.js
new file mode 100644
index 00000000..fd4ca203
--- /dev/null
+++ b/legacy/web/app/store/Drivers.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.Drivers', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Driver',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/drivers',
+ writer: {
+ writeAllFields: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/EventPositions.js b/legacy/web/app/store/EventPositions.js
new file mode 100644
index 00000000..d984e4b8
--- /dev/null
+++ b/legacy/web/app/store/EventPositions.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.EventPositions', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Position',
+
+ trackRemoved: false,
+
+ proxy: {
+ type: 'rest',
+ url: 'api/positions',
+ headers: {
+ 'Accept': 'application/json'
+ }
+ }
+});
diff --git a/legacy/web/app/store/Events.js b/legacy/web/app/store/Events.js
new file mode 100644
index 00000000..cfa0d568
--- /dev/null
+++ b/legacy/web/app/store/Events.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 - 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.Events', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Event',
+
+ trackRemoved: false,
+
+ proxy: {
+ type: 'rest',
+ url: 'api/events'
+ }
+});
diff --git a/legacy/web/app/store/GeofenceAttributes.js b/legacy/web/app/store/GeofenceAttributes.js
new file mode 100644
index 00000000..b1d48c19
--- /dev/null
+++ b/legacy/web/app/store/GeofenceAttributes.js
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 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.GeofenceAttributes', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.KnownAttribute',
+ proxy: 'memory',
+
+ data: [{
+ key: 'color',
+ name: Strings.attributeColor,
+ valueType: 'color'
+ }, {
+ key: 'speedLimit',
+ name: Strings.attributeSpeedLimit,
+ valueType: 'number',
+ dataType: 'speed'
+ }, {
+ key: 'polylineDistance',
+ name: Strings.attributePolylineDistance,
+ valueType: 'number',
+ dataType: 'distance'
+ }]
+});
diff --git a/legacy/web/app/store/GeofenceTypes.js b/legacy/web/app/store/GeofenceTypes.js
new file mode 100644
index 00000000..45b79897
--- /dev/null
+++ b/legacy/web/app/store/GeofenceTypes.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@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.GeofenceTypes', {
+ extend: 'Ext.data.Store',
+ fields: ['key', 'name'],
+
+ data: [{
+ key: 'Polygon',
+ name: Strings.mapShapePolygon
+ }, {
+ key: 'Circle',
+ name: Strings.mapShapeCircle
+ }, {
+ key: 'LineString',
+ name: Strings.mapShapePolyline
+ }]
+});
diff --git a/legacy/web/app/store/Geofences.js b/legacy/web/app/store/Geofences.js
new file mode 100644
index 00000000..5a7172be
--- /dev/null
+++ b/legacy/web/app/store/Geofences.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@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.Geofences', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Geofence',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/geofences',
+ writer: {
+ writeAllFields: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/GroupAttributes.js b/legacy/web/app/store/GroupAttributes.js
new file mode 100644
index 00000000..589e4ec2
--- /dev/null
+++ b/legacy/web/app/store/GroupAttributes.js
@@ -0,0 +1,32 @@
+/*
+ * 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.GroupAttributes', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.KnownAttribute',
+
+ data: [{
+ key: 'processing.copyAttributes',
+ name: Strings.attributeProcessingCopyAttributes,
+ valueType: 'string'
+ }, {
+ key: 'decoder.timezone',
+ name: Strings.sharedTimezone,
+ valueType: 'string',
+ dataType: 'timezone'
+ }]
+});
diff --git a/legacy/web/app/store/Groups.js b/legacy/web/app/store/Groups.js
new file mode 100644
index 00000000..5f8fa60a
--- /dev/null
+++ b/legacy/web/app/store/Groups.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@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.Groups', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Group',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/groups',
+ writer: {
+ writeAllFields: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/HoursUnits.js b/legacy/web/app/store/HoursUnits.js
new file mode 100644
index 00000000..02f62c65
--- /dev/null
+++ b/legacy/web/app/store/HoursUnits.js
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 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.HoursUnits', {
+ extend: 'Ext.data.Store',
+ fields: ['key', 'name', 'fullName'],
+
+ data: [{
+ key: 'h',
+ name: Strings.sharedHourAbbreviation,
+ fullName: Strings.sharedHour
+ }],
+
+ convertValue: function (value, unit, back) {
+ return back ? value * 3600000 : value / 3600000;
+ },
+
+ formatValue: function (value, unit, convert) {
+ var hours, minutes;
+ if (convert) {
+ hours = Math.floor(value / 3600000);
+ minutes = Math.floor(value % 3600000 / 60000);
+ } else {
+ hours = Math.floor(value);
+ minutes = Math.floor(value % 1 * 60);
+ }
+ return hours + ' ' + Strings.sharedHourAbbreviation + ' ' + minutes + ' ' + Strings.sharedMinuteAbbreviation;
+ }
+});
diff --git a/legacy/web/app/store/KnownCommands.js b/legacy/web/app/store/KnownCommands.js
new file mode 100644
index 00000000..a6089c48
--- /dev/null
+++ b/legacy/web/app/store/KnownCommands.js
@@ -0,0 +1,241 @@
+/*
+ * 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.KnownCommands', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.KnownCommand',
+
+ data: [{
+ type: 'custom',
+ parameters: [{
+ key: 'data',
+ name: Strings.commandData,
+ valueType: 'string'
+ }]
+ }, {
+ type: 'positionPeriodic',
+ parameters: [{
+ key: 'frequency',
+ name: Strings.commandFrequency,
+ valueType: 'number',
+ allowDecimals: false,
+ minValue: 0,
+ dataType: 'frequency'
+ }]
+ }, {
+ type: 'setTimezone',
+ parameters: [{
+ key: 'timezone',
+ name: Strings.commandTimezone,
+ valueType: 'string',
+ dataType: 'timezone'
+ }]
+ }, {
+ type: 'sendSms',
+ parameters: [{
+ key: 'phone',
+ name: Strings.commandPhone,
+ valueType: 'string'
+ }, {
+ key: 'message',
+ name: Strings.commandMessage,
+ valueType: 'string'
+ }]
+ }, {
+ type: 'message',
+ parameters: [{
+ key: 'message',
+ name: Strings.commandMessage,
+ valueType: 'string'
+ }]
+ }, {
+ type: 'sendUssd',
+ parameters: [{
+ key: 'phone',
+ name: Strings.commandPhone,
+ valueType: 'string'
+ }]
+ }, {
+ type: 'sosNumber',
+ parameters: [{
+ key: 'index',
+ name: Strings.commandIndex,
+ valueType: 'number',
+ allowDecimals: false,
+ minValue: 0
+ }, {
+ key: 'phone',
+ name: Strings.commandPhone,
+ valueType: 'string'
+ }]
+ }, {
+ type: 'silenceTime',
+ parameters: [{
+ key: 'data',
+ name: Strings.commandData,
+ valueType: 'string'
+ }]
+ }, {
+ type: 'setPhonebook',
+ parameters: [{
+ key: 'data',
+ name: Strings.commandData,
+ valueType: 'string'
+ }]
+ }, {
+ type: 'voiceMessage',
+ parameters: [{
+ key: 'data',
+ name: Strings.commandData,
+ valueType: 'string'
+ }]
+ }, {
+ type: 'outputControl',
+ parameters: [{
+ key: 'index',
+ name: Strings.commandIndex,
+ valueType: 'number',
+ allowDecimals: false,
+ minValue: 0
+ }, {
+ key: 'data',
+ name: Strings.commandData,
+ valueType: 'string'
+ }]
+ }, {
+ type: 'voiceMonitoring',
+ parameters: [{
+ key: 'enable',
+ name: Strings.commandEnable,
+ valueType: 'boolean'
+ }]
+ }, {
+ type: 'setAgps',
+ parameters: [{
+ key: 'enable',
+ name: Strings.commandEnable,
+ valueType: 'boolean'
+ }]
+ }, {
+ type: 'setIndicator',
+ parameters: [{
+ key: 'data',
+ name: Strings.commandData,
+ valueType: 'string'
+ }]
+ }, {
+ type: 'configuration',
+ parameters: [{
+ key: 'data',
+ name: Strings.commandData,
+ valueType: 'string'
+ }]
+ }, {
+ type: 'setConnection',
+ parameters: [{
+ key: 'server',
+ name: Strings.commandServer,
+ valueType: 'string'
+ }, {
+ key: 'port',
+ name: Strings.commandPort,
+ valueType: 'number',
+ allowDecimals: false,
+ minValue: 1,
+ maxValue: 65535
+ }]
+ }, {
+ type: 'setOdometer',
+ parameters: [{
+ key: 'data',
+ name: Strings.commandData,
+ valueType: 'string'
+ }]
+ }, {
+ type: 'modePowerSaving',
+ parameters: [{
+ key: 'enable',
+ name: Strings.commandEnable,
+ valueType: 'boolean'
+ }]
+ }, {
+ type: 'modeDeepSleep',
+ parameters: [{
+ key: 'enable',
+ name: Strings.commandEnable,
+ valueType: 'boolean'
+ }]
+ }, {
+ type: 'alarmGeofence',
+ parameters: [{
+ key: 'radius',
+ name: Strings.commandRadius,
+ valueType: 'number',
+ allowDecimals: false,
+ minValue: 0
+ }]
+ }, {
+ type: 'alarmBattery',
+ parameters: [{
+ key: 'enable',
+ name: Strings.commandEnable,
+ valueType: 'boolean'
+ }]
+ }, {
+ type: 'alarmSos',
+ parameters: [{
+ key: 'enable',
+ name: Strings.commandEnable,
+ valueType: 'boolean'
+ }]
+ }, {
+ type: 'alarmRemove',
+ parameters: [{
+ key: 'enable',
+ name: Strings.commandEnable,
+ valueType: 'boolean'
+ }]
+ }, {
+ type: 'alarmClock',
+ parameters: [{
+ key: 'data',
+ name: Strings.commandData,
+ valueType: 'string'
+ }]
+ }, {
+ type: 'alarmSpeed',
+ parameters: [{
+ key: 'data',
+ name: Strings.commandData,
+ valueType: 'string'
+ }]
+ }, {
+ type: 'alarmFall',
+ parameters: [{
+ key: 'enable',
+ name: Strings.commandEnable,
+ valueType: 'boolean'
+ }]
+ }, {
+ type: 'alarmVibration',
+ parameters: [{
+ key: 'data',
+ name: Strings.commandData,
+ valueType: 'string'
+ }]
+ }]
+});
diff --git a/legacy/web/app/store/Languages.js b/legacy/web/app/store/Languages.js
new file mode 100644
index 00000000..32d648e0
--- /dev/null
+++ b/legacy/web/app/store/Languages.js
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.Languages', {
+ extend: 'Ext.data.Store',
+ fields: ['code', 'name'],
+
+ data: (function () {
+ var code, data = [];
+ for (code in Locale.languages) {
+ if (Locale.languages.hasOwnProperty(code)) {
+ data.push({
+ code: code,
+ name: Locale.languages[code].name
+ });
+ }
+ }
+ return data;
+ })()
+});
diff --git a/legacy/web/app/store/LatestPositions.js b/legacy/web/app/store/LatestPositions.js
new file mode 100644
index 00000000..f7cf5406
--- /dev/null
+++ b/legacy/web/app/store/LatestPositions.js
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.LatestPositions', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Position'
+});
diff --git a/legacy/web/app/store/MaintenanceTypes.js b/legacy/web/app/store/MaintenanceTypes.js
new file mode 100644
index 00000000..468b67ea
--- /dev/null
+++ b/legacy/web/app/store/MaintenanceTypes.js
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 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.MaintenanceTypes', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.KnownAttribute'
+});
diff --git a/legacy/web/app/store/Maintenances.js b/legacy/web/app/store/Maintenances.js
new file mode 100644
index 00000000..a7aa4a07
--- /dev/null
+++ b/legacy/web/app/store/Maintenances.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 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.Maintenances', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Maintenance',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/maintenance',
+ writer: {
+ writeAllFields: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/MapTypes.js b/legacy/web/app/store/MapTypes.js
new file mode 100644
index 00000000..f517045d
--- /dev/null
+++ b/legacy/web/app/store/MapTypes.js
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.MapTypes', {
+ extend: 'Ext.data.Store',
+ fields: ['key', 'name'],
+
+ data: [{
+ key: 'locationIqStreets',
+ name: Strings.mapLocationIqStreets
+ }, {
+ key: 'osm',
+ name: Strings.mapOsm
+ }, {
+ key: 'carto',
+ name: Strings.mapCarto
+ }, {
+ key: 'autoNavi',
+ name: Strings.mapAutoNavi
+ }, {
+ key: 'bingRoad',
+ name: Strings.mapBingRoad
+ }, {
+ key: 'bingAerial',
+ name: Strings.mapBingAerial
+ }, {
+ key: 'bingHybrid',
+ name: Strings.mapBingHybrid
+ }, {
+ key: 'yandexMap',
+ name: Strings.mapYandexMap
+ }, {
+ key: 'yandexSat',
+ name: Strings.mapYandexSat
+ }, {
+ key: 'custom',
+ name: Strings.mapCustom
+ }, {
+ key: 'customArcgis',
+ name: Strings.mapCustomArcgis
+ }]
+});
diff --git a/legacy/web/app/store/Notifications.js b/legacy/web/app/store/Notifications.js
new file mode 100644
index 00000000..b30505fd
--- /dev/null
+++ b/legacy/web/app/store/Notifications.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.Notifications', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Notification',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/notifications',
+ writer: {
+ writeAllFields: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/PositionAttributes.js b/legacy/web/app/store/PositionAttributes.js
new file mode 100644
index 00000000..5b1206b7
--- /dev/null
+++ b/legacy/web/app/store/PositionAttributes.js
@@ -0,0 +1,269 @@
+/*
+ * 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.PositionAttributes', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.KnownAttribute',
+ proxy: 'memory',
+
+ data: [{
+ key: 'raw',
+ name: Strings.positionRaw,
+ valueType: 'string'
+ }, {
+ key: 'index',
+ name: Strings.positionIndex,
+ valueType: 'number'
+ }, {
+ key: 'hdop',
+ name: Strings.positionHdop,
+ valueType: 'number'
+ }, {
+ key: 'vdop',
+ name: Strings.positionVdop,
+ valueType: 'number'
+ }, {
+ key: 'pdop',
+ name: Strings.positionPdop,
+ valueType: 'number'
+ }, {
+ key: 'sat',
+ name: Strings.positionSat,
+ valueType: 'number'
+ }, {
+ key: 'satVisible',
+ name: Strings.positionSatVisible,
+ valueType: 'number'
+ }, {
+ key: 'rssi',
+ name: Strings.positionRssi,
+ valueType: 'number'
+ }, {
+ key: 'gps',
+ name: Strings.positionGps,
+ valueType: 'number'
+ }, {
+ key: 'roaming',
+ name: Strings.positionRoaming,
+ valueType: 'boolean'
+ }, {
+ key: 'event',
+ name: Strings.positionEvent,
+ valueType: 'string'
+ }, {
+ key: 'alarm',
+ name: Strings.positionAlarm,
+ valueType: 'string'
+ }, {
+ key: 'status',
+ name: Strings.positionStatus,
+ valueType: 'string'
+ }, {
+ key: 'odometer',
+ name: Strings.positionOdometer,
+ valueType: 'number',
+ dataType: 'distance'
+ }, {
+ key: 'serviceOdometer',
+ name: Strings.positionServiceOdometer,
+ valueType: 'number',
+ dataType: 'distance'
+ }, {
+ key: 'tripOdometer',
+ name: Strings.positionTripOdometer,
+ valueType: 'number',
+ dataType: 'distance'
+ }, {
+ key: 'hours',
+ name: Strings.positionHours,
+ valueType: 'number',
+ dataType: 'hours'
+ }, {
+ key: 'steps',
+ name: Strings.positionSteps,
+ valueType: 'number'
+ }, {
+ key: 'input',
+ name: Strings.positionInput,
+ valueType: 'string'
+ }, {
+ key: 'output',
+ name: Strings.positionOutput,
+ valueType: 'string'
+ }, {
+ key: 'power',
+ name: Strings.positionPower,
+ valueType: 'number',
+ dataType: 'voltage'
+ }, {
+ key: 'battery',
+ name: Strings.positionBattery,
+ valueType: 'number',
+ dataType: 'voltage'
+ }, {
+ key: 'batteryLevel',
+ name: Strings.positionBatteryLevel,
+ valueType: 'number',
+ dataType: 'percentage'
+ }, {
+ key: 'fuel',
+ name: Strings.positionFuel,
+ valueType: 'number',
+ dataType: 'volume'
+ }, {
+ key: 'fuelConsumption',
+ name: Strings.positionFuelConsumption,
+ valueType: 'number',
+ dataType: 'consumption'
+ }, {
+ key: 'versionFw',
+ name: Strings.positionVersionFw,
+ valueType: 'string'
+ }, {
+ key: 'versionHw',
+ name: Strings.positionVersionHw,
+ valueType: 'string'
+ }, {
+ key: 'type',
+ name: Strings.sharedType,
+ valueType: 'string'
+ }, {
+ key: 'ignition',
+ name: Strings.positionIgnition,
+ valueType: 'boolean'
+ }, {
+ key: 'flags',
+ name: Strings.positionFlags,
+ valueType: 'string'
+ }, {
+ key: 'charge',
+ name: Strings.positionCharge,
+ valueType: 'boolean'
+ }, {
+ key: 'ip',
+ name: Strings.positionIp,
+ valueType: 'string'
+ }, {
+ key: 'archive',
+ name: Strings.positionArchive,
+ valueType: 'boolean'
+ }, {
+ key: 'distance',
+ name: Strings.positionDistance,
+ valueType: 'number',
+ dataType: 'distance'
+ }, {
+ key: 'totalDistance',
+ name: Strings.deviceTotalDistance,
+ valueType: 'number',
+ dataType: 'distance'
+ }, {
+ key: 'rpm',
+ name: Strings.positionRpm,
+ valueType: 'number'
+ }, {
+ key: 'vin',
+ name: Strings.positionVin,
+ valueType: 'string'
+ }, {
+ key: 'approximate',
+ name: Strings.positionApproximate,
+ valueType: 'boolean'
+ }, {
+ key: 'throttle',
+ name: Strings.positionThrottle,
+ valueType: 'number'
+ }, {
+ key: 'motion',
+ name: Strings.positionMotion,
+ valueType: 'boolean'
+ }, {
+ key: 'armed',
+ name: Strings.positionArmed,
+ valueType: 'number'
+ }, {
+ key: 'geofence',
+ name: Strings.sharedGeofence,
+ valueType: 'string'
+ }, {
+ key: 'acceleration',
+ name: Strings.positionAcceleration,
+ valueType: 'number'
+ }, {
+ key: 'deviceTemp',
+ name: Strings.positionDeviceTemp,
+ valueType: 'number',
+ dataType: 'temperature'
+ }, {
+ key: 'operator',
+ name: Strings.positionOperator,
+ valueType: 'string'
+ }, {
+ key: 'command',
+ name: Strings.deviceCommand,
+ valueType: 'string'
+ }, {
+ key: 'blocked',
+ name: Strings.positionBlocked,
+ valueType: 'boolean'
+ }, {
+ key: 'dtcs',
+ name: Strings.positionDtcs,
+ valueType: 'string'
+ }, {
+ key: 'obdSpeed',
+ name: Strings.positionObdSpeed,
+ valueType: 'number',
+ dataType: 'speed'
+ }, {
+ key: 'obdOdometer',
+ name: Strings.positionObdOdometer,
+ valueType: 'number',
+ dataType: 'distance'
+ }, {
+ key: 'result',
+ name: Strings.eventCommandResult,
+ valueType: 'string'
+ }, {
+ key: 'driverUniqueId',
+ name: Strings.positionDriverUniqueId,
+ valueType: 'string',
+ dataType: 'driverUniqueId'
+ }],
+
+ getAttributeName: function (key, capitalize) {
+ var model = this.getById(key);
+ if (model) {
+ return model.get('name');
+ } else if (capitalize) {
+ return key.replace(/^./, function (match) {
+ return match.toUpperCase();
+ });
+ } else {
+ return key;
+ }
+ },
+
+ getAttributeDataType: function (key) {
+ var model = this.getById(key);
+ if (model && model.get('dataType')) {
+ return model.get('dataType');
+ } else {
+ return null;
+ }
+ }
+});
diff --git a/legacy/web/app/store/Positions.js b/legacy/web/app/store/Positions.js
new file mode 100644
index 00000000..388a3320
--- /dev/null
+++ b/legacy/web/app/store/Positions.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.Positions', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Position',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/positions',
+ headers: {
+ 'Accept': 'application/json'
+ }
+ }
+});
diff --git a/legacy/web/app/store/ReportChartTypes.js b/legacy/web/app/store/ReportChartTypes.js
new file mode 100644
index 00000000..f53d3197
--- /dev/null
+++ b/legacy/web/app/store/ReportChartTypes.js
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 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.ReportChartTypes', {
+ extend: 'Ext.data.Store',
+ fields: ['key', 'name'],
+
+ data: [{
+ key: 'speed',
+ name: Strings.positionSpeed
+ }, {
+ key: 'accuracy',
+ name: Strings.positionAccuracy
+ }, {
+ key: 'altitude',
+ name: Strings.positionAltitude
+ }]
+});
diff --git a/legacy/web/app/store/ReportEventTypes.js b/legacy/web/app/store/ReportEventTypes.js
new file mode 100644
index 00000000..001f159b
--- /dev/null
+++ b/legacy/web/app/store/ReportEventTypes.js
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 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.ReportEventTypes', {
+ extend: 'Ext.data.Store',
+ fields: ['type', 'name'],
+
+ statics: {
+ allEvents: 'allEvents'
+ }
+});
diff --git a/legacy/web/app/store/ReportEvents.js b/legacy/web/app/store/ReportEvents.js
new file mode 100644
index 00000000..061aaa42
--- /dev/null
+++ b/legacy/web/app/store/ReportEvents.js
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@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.ReportEvents', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Event',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/reports/events',
+ timeout: Traccar.Style.reportTimeout,
+ headers: {
+ 'Accept': 'application/json'
+ },
+ listeners: {
+ exception: function (proxy, exception) {
+ Traccar.app.showError(exception);
+ }
+ }
+ }
+});
diff --git a/legacy/web/app/store/ReportPeriods.js b/legacy/web/app/store/ReportPeriods.js
new file mode 100644
index 00000000..542fdce9
--- /dev/null
+++ b/legacy/web/app/store/ReportPeriods.js
@@ -0,0 +1,45 @@
+/*
+ * 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.ReportPeriods', {
+ extend: 'Ext.data.Store',
+ fields: ['key', 'name'],
+
+ data: [{
+ key: 'custom',
+ name: Strings.reportCustom
+ }, {
+ key: 'today',
+ name: Strings.reportToday
+ }, {
+ key: 'yesterday',
+ name: Strings.reportYesterday
+ }, {
+ key: 'thisWeek',
+ name: Strings.reportThisWeek
+ }, {
+ key: 'previousWeek',
+ name: Strings.reportPreviousWeek
+ }, {
+ key: 'thisMonth',
+ name: Strings.reportThisMonth
+ }, {
+ key: 'previousMonth',
+ name: Strings.reportPreviousMonth
+ }]
+});
diff --git a/legacy/web/app/store/ReportRoute.js b/legacy/web/app/store/ReportRoute.js
new file mode 100644
index 00000000..7babe163
--- /dev/null
+++ b/legacy/web/app/store/ReportRoute.js
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@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.ReportRoute', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Position',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/reports/route',
+ timeout: Traccar.Style.reportTimeout,
+ headers: {
+ 'Accept': 'application/json'
+ },
+ listeners: {
+ exception: function (proxy, exception) {
+ Traccar.app.showError(exception);
+ }
+ }
+ }
+});
diff --git a/legacy/web/app/store/ReportStops.js b/legacy/web/app/store/ReportStops.js
new file mode 100644
index 00000000..75c9fc18
--- /dev/null
+++ b/legacy/web/app/store/ReportStops.js
@@ -0,0 +1,36 @@
+/*
+ * 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.ReportStops', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.ReportStop',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/reports/stops',
+ timeout: Traccar.Style.reportTimeout,
+ headers: {
+ 'Accept': 'application/json'
+ },
+ listeners: {
+ exception: function (proxy, exception) {
+ Traccar.app.showError(exception);
+ }
+ }
+ }
+});
diff --git a/legacy/web/app/store/ReportSummary.js b/legacy/web/app/store/ReportSummary.js
new file mode 100644
index 00000000..f328da2d
--- /dev/null
+++ b/legacy/web/app/store/ReportSummary.js
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 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.ReportSummary', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.ReportSummary',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/reports/summary',
+ timeout: Traccar.Style.reportTimeout,
+ headers: {
+ 'Accept': 'application/json'
+ },
+ listeners: {
+ exception: function (proxy, exception) {
+ Traccar.app.showError(exception);
+ }
+ }
+ }
+});
diff --git a/legacy/web/app/store/ReportTrips.js b/legacy/web/app/store/ReportTrips.js
new file mode 100644
index 00000000..057cc7c0
--- /dev/null
+++ b/legacy/web/app/store/ReportTrips.js
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 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.ReportTrips', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.ReportTrip',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/reports/trips',
+ timeout: Traccar.Style.reportTimeout,
+ headers: {
+ 'Accept': 'application/json'
+ },
+ listeners: {
+ exception: function (proxy, exception) {
+ Traccar.app.showError(exception);
+ }
+ }
+ }
+});
diff --git a/legacy/web/app/store/ReportTypes.js b/legacy/web/app/store/ReportTypes.js
new file mode 100644
index 00000000..ceaba9d2
--- /dev/null
+++ b/legacy/web/app/store/ReportTypes.js
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@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.ReportTypes', {
+ extend: 'Ext.data.Store',
+ fields: ['key', 'name'],
+
+ data: [{
+ key: 'route',
+ name: Strings.reportRoute
+ }, {
+ key: 'events',
+ name: Strings.reportEvents
+ }, {
+ key: 'trips',
+ name: Strings.reportTrips
+ }, {
+ key: 'stops',
+ name: Strings.reportStops
+ }, {
+ key: 'summary',
+ name: Strings.reportSummary
+ }, {
+ key: 'daily',
+ name: Strings.reportDaily
+ }, {
+ key: 'chart',
+ name: Strings.reportChart
+ }]
+});
diff --git a/legacy/web/app/store/ServerAttributes.js b/legacy/web/app/store/ServerAttributes.js
new file mode 100644
index 00000000..204f885b
--- /dev/null
+++ b/legacy/web/app/store/ServerAttributes.js
@@ -0,0 +1,23 @@
+/*
+ * 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.ServerAttributes', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.KnownAttribute',
+
+ data: []
+});
diff --git a/legacy/web/app/store/SpeedUnits.js b/legacy/web/app/store/SpeedUnits.js
new file mode 100644
index 00000000..a36be928
--- /dev/null
+++ b/legacy/web/app/store/SpeedUnits.js
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 - 2016 Anton Tananaev (anton@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.SpeedUnits', {
+ extend: 'Ext.data.Store',
+ fields: ['key', 'name', 'factor'],
+
+ data: [{
+ key: 'kn',
+ name: Strings.sharedKn,
+ factor: 1
+ }, {
+ key: 'kmh',
+ name: Strings.sharedKmh,
+ factor: 1.852
+ }, {
+ key: 'mph',
+ name: Strings.sharedMph,
+ factor: 1.15078
+ }],
+
+ convertValue: function (value, unit, back) {
+ var model;
+ if (!unit) {
+ unit = 'kn';
+ }
+ model = this.findRecord('key', unit);
+ return back ? value / model.get('factor') : value * model.get('factor');
+ },
+
+ formatValue: function (value, unit, convert) {
+ var model;
+ if (!unit) {
+ unit = 'kn';
+ }
+ model = this.findRecord('key', unit);
+ return (convert ? this.convertValue(value, unit) : value).toFixed(1) + ' ' + model.get('name');
+ }
+});
diff --git a/legacy/web/app/store/Statistics.js b/legacy/web/app/store/Statistics.js
new file mode 100644
index 00000000..1d44c6e3
--- /dev/null
+++ b/legacy/web/app/store/Statistics.js
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@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.Statistics', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.Statistics',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/statistics'
+ }
+});
diff --git a/legacy/web/app/store/TimeUnits.js b/legacy/web/app/store/TimeUnits.js
new file mode 100644
index 00000000..0d16c4bb
--- /dev/null
+++ b/legacy/web/app/store/TimeUnits.js
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.TimeUnits', {
+ extend: 'Ext.data.Store',
+ fields: ['key', 'name', 'factor'],
+
+ data: [{
+ key: 's',
+ name: Strings.sharedSecondAbbreviation,
+ factor: 1
+ }, {
+ key: 'm',
+ name: Strings.sharedMinuteAbbreviation,
+ factor: 60
+ }, {
+ key: 'h',
+ name: Strings.sharedHourAbbreviation,
+ factor: 3600
+ }],
+
+ convertValue: function (value, unit, back) {
+ var model;
+ if (!unit) {
+ unit = 'kn';
+ }
+ model = this.findRecord('key', unit);
+ return back ? value * model.get('factor') : value / model.get('factor');
+ }
+});
diff --git a/legacy/web/app/store/UserAttributes.js b/legacy/web/app/store/UserAttributes.js
new file mode 100644
index 00000000..dfe69421
--- /dev/null
+++ b/legacy/web/app/store/UserAttributes.js
@@ -0,0 +1,70 @@
+/*
+ * 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.UserAttributes', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.KnownAttribute',
+
+ data: [{
+ key: 'mail.smtp.host',
+ name: Strings.attributeMailSmtpHost,
+ valueType: 'string'
+ }, {
+ key: 'mail.smtp.port',
+ name: Strings.attributeMailSmtpPort,
+ valueType: 'number',
+ allowDecimals: false,
+ minValue: 1,
+ maxValue: 65535
+ }, {
+ key: 'mail.smtp.starttls.enable',
+ name: Strings.attributeMailSmtpStarttlsEnable,
+ valueType: 'boolean'
+ }, {
+ key: 'mail.smtp.starttls.required',
+ name: Strings.attributeMailSmtpStarttlsRequired,
+ valueType: 'boolean'
+ }, {
+ key: 'mail.smtp.ssl.enable',
+ name: Strings.attributeMailSmtpSslEnable,
+ valueType: 'boolean'
+ }, {
+ key: 'mail.smtp.ssl.trust',
+ name: Strings.attributeMailSmtpSslTrust,
+ valueType: 'string'
+ }, {
+ key: 'mail.smtp.ssl.protocols',
+ name: Strings.attributeMailSmtpSslProtocols,
+ valueType: 'string'
+ }, {
+ key: 'mail.smtp.from',
+ name: Strings.attributeMailSmtpFrom,
+ valueType: 'string'
+ }, {
+ key: 'mail.smtp.auth',
+ name: Strings.attributeMailSmtpAuth,
+ valueType: 'boolean'
+ }, {
+ key: 'mail.smtp.username',
+ name: Strings.attributeMailSmtpUsername,
+ valueType: 'string'
+ }, {
+ key: 'mail.smtp.password',
+ name: Strings.attributeMailSmtpPassword,
+ valueType: 'string'
+ }]
+});
diff --git a/legacy/web/app/store/Users.js b/legacy/web/app/store/Users.js
new file mode 100644
index 00000000..0279afea
--- /dev/null
+++ b/legacy/web/app/store/Users.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.Users', {
+ extend: 'Ext.data.Store',
+ model: 'Traccar.model.User',
+
+ proxy: {
+ type: 'rest',
+ url: 'api/users',
+ writer: {
+ writeAllFields: true
+ }
+ }
+});
diff --git a/legacy/web/app/store/VisibleDevices.js b/legacy/web/app/store/VisibleDevices.js
new file mode 100644
index 00000000..db1ca7da
--- /dev/null
+++ b/legacy/web/app/store/VisibleDevices.js
@@ -0,0 +1,22 @@
+/*
+ * 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.VisibleDevices', {
+ extend: 'Ext.data.ChainedStore',
+ source: 'Devices'
+});
diff --git a/legacy/web/app/store/VolumeUnits.js b/legacy/web/app/store/VolumeUnits.js
new file mode 100644
index 00000000..2bdf6684
--- /dev/null
+++ b/legacy/web/app/store/VolumeUnits.js
@@ -0,0 +1,57 @@
+/*
+ * 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.VolumeUnits', {
+ extend: 'Ext.data.Store',
+ fields: ['key', 'name', 'fullName', 'factor'],
+
+ data: [{
+ key: 'ltr',
+ name: Strings.sharedLiterAbbreviation,
+ fullName: Strings.sharedLiter,
+ factor: 1
+ }, {
+ key: 'impGal',
+ name: Strings.sharedGallonAbbreviation,
+ fullName: Strings.sharedImpGallon,
+ factor: 4.546
+ }, {
+ key: 'usGal',
+ name: Strings.sharedGallonAbbreviation,
+ fullName: Strings.sharedUsGallon,
+ factor: 3.785
+ }],
+
+ convertValue: function (value, unit, back) {
+ var model;
+ if (!unit) {
+ unit = 'ltr';
+ }
+ model = this.findRecord('key', unit);
+ return back ? value * model.get('factor') : value / model.get('factor');
+ },
+
+ formatValue: function (value, unit, convert) {
+ var model;
+ if (!unit) {
+ unit = 'ltr';
+ }
+ model = this.findRecord('key', unit);
+ return (convert ? this.convertValue(value, unit) : value).toFixed(1) + ' ' + model.get('name');
+ }
+});
diff --git a/legacy/web/app/view/ArrayListFilter.js b/legacy/web/app/view/ArrayListFilter.js
new file mode 100644
index 00000000..519096eb
--- /dev/null
+++ b/legacy/web/app/view/ArrayListFilter.js
@@ -0,0 +1,50 @@
+/*
+ * 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.ArrayListFilter', {
+ extend: 'Ext.grid.filters.filter.List',
+ alias: 'grid.filter.arraylist',
+
+ type: 'arraylist',
+
+ constructor: function (config) {
+ this.callParent([config]);
+ this.filter.setFilterFn(function (item) {
+ var i, property, value, splits;
+ property = item.get(this.getProperty());
+ value = this.getValue();
+ if (Ext.isArray(property)) {
+ for (i = 0; i < property.length; i++) {
+ if (value.indexOf(property[i]) !== -1) {
+ return true;
+ }
+ }
+ } else if (property.match(/[ ,]+/)) {
+ splits = property.split(/[ ,]+/).filter(Boolean);
+ for (i = 0; i < splits.length; i++) {
+ if (value.indexOf(splits[i]) !== -1) {
+ return true;
+ }
+ }
+ } else if (value.indexOf(property) !== -1) {
+ return true;
+ }
+ return false;
+ });
+ }
+});
diff --git a/legacy/web/app/view/BaseWindow.js b/legacy/web/app/view/BaseWindow.js
new file mode 100644
index 00000000..bf698e08
--- /dev/null
+++ b/legacy/web/app/view/BaseWindow.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015 Anton Tananaev (anton@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.BaseWindow', {
+ extend: 'Ext.window.Window',
+
+ width: Traccar.Style.windowWidth,
+ height: Traccar.Style.windowHeight,
+ layout: 'fit',
+
+ initComponent: function () {
+ if (window.innerWidth < Traccar.Style.windowWidth || window.innerHeight < Traccar.Style.windowHeight) {
+ this.maximized = true;
+ this.style = 'border-width: 0';
+ }
+ this.callParent();
+ }
+});
diff --git a/legacy/web/app/view/ClearableComboBox.js b/legacy/web/app/view/ClearableComboBox.js
new file mode 100644
index 00000000..cf811d1d
--- /dev/null
+++ b/legacy/web/app/view/ClearableComboBox.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.ClearableComboBox', {
+ extend: 'Ext.form.field.ComboBox',
+ xtype: 'clearableComboBox',
+
+ editable: false,
+ triggers: {
+ clear: {
+ cls: 'iconCls: x-fa fa-times',
+ handler: function (button) {
+ button.clearValue();
+ }
+ }
+ }
+});
diff --git a/legacy/web/app/view/ColorPicker.js b/legacy/web/app/view/ColorPicker.js
new file mode 100644
index 00000000..5de03aa3
--- /dev/null
+++ b/legacy/web/app/view/ColorPicker.js
@@ -0,0 +1,43 @@
+/*
+ * 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.ColorPicker', {
+ extend: 'Ext.form.field.Picker',
+ xtype: 'customcolorpicker',
+
+ config: {
+ value: '#008000'
+ },
+
+ editable: false,
+
+ createPicker: function () {
+ return Ext.create('Ext.picker.Color', {
+ floating: true,
+ picker: this,
+ select: function (selColor) {
+ this.picker.setValue('#' + selColor);
+ this.picker.collapse();
+ }
+ });
+ },
+
+ setValue: function (color) {
+ this.callParent([color]);
+ this.setFieldStyle('background-color:' + color);
+ }
+});
diff --git a/legacy/web/app/view/CustomNumberField.js b/legacy/web/app/view/CustomNumberField.js
new file mode 100644
index 00000000..8cfac1ee
--- /dev/null
+++ b/legacy/web/app/view/CustomNumberField.js
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 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.CustomNumberField', {
+ extend: 'Ext.form.field.Number',
+ xtype: 'customNumberField',
+
+ beforeEl: '<div style="width:100%;display:inline-table;">',
+ unitEl: '<div id="numberUnitEl" style="display:table-cell;padding-left:10px;vertical-align:middle;width:1px;white-space:nowrap;">',
+
+ constructor: function (config) {
+ var unitName = '';
+ if (config.dataType) {
+ config.beforeBodyEl = this.beforeEl;
+ switch (config.dataType) {
+ case 'speed':
+ config.units = {};
+ config.units.getStore = function () {
+ return Ext.getStore('SpeedUnits');
+ };
+ config.units.getValue = function () {
+ return Traccar.app.getAttributePreference('speedUnit', 'kn');
+ };
+ unitName = Ext.getStore('SpeedUnits').findRecord('key', config.units.getValue()).get('name');
+ break;
+ case 'distance':
+ config.units = {};
+ config.units.getStore = function () {
+ return Ext.getStore('DistanceUnits');
+ };
+ config.units.getValue = function () {
+ return Traccar.app.getAttributePreference('distanceUnit', 'km');
+ };
+ unitName = Ext.getStore('DistanceUnits').findRecord('key', config.units.getValue()).get('name');
+ break;
+ case 'frequency':
+ if (!config.listeners) {
+ config.listeners = {};
+ }
+ config.listeners.afterrender = function () {
+ if (!this.units) {
+ this.units = Ext.create({
+ xtype: 'combobox',
+ renderTo: 'numberUnitEl',
+ store: 'TimeUnits',
+ displayField: 'name',
+ valueField: 'key',
+ editable: false,
+ numberField: this,
+ value: 's',
+ width: '70px',
+ listeners: {
+ select: function () {
+ this.numberField.step = this.getStore().convertValue(1, this.getValue(), true);
+ }
+ }
+ });
+ }
+ };
+ break;
+ case 'hours':
+ config.units = {};
+ config.units.getStore = function () {
+ return Ext.getStore('HoursUnits');
+ };
+ config.units.getValue = function () {
+ return 'h';
+ };
+ unitName = Strings.sharedHourAbbreviation;
+ break;
+ default:
+ break;
+ }
+ config.afterBodyEl = this.unitEl + unitName + '</div></div>';
+ config.rawToValue = function (rawValue) {
+ if (this.units) {
+ return this.units.getStore().convertValue(this.parseValue(rawValue), this.units.getValue(), true);
+ } else {
+ return this.parseValue(rawValue);
+ }
+ };
+ config.valueToRaw = function (value) {
+ if (this.units) {
+ return String(this.units.getStore().convertValue(value, this.units.getValue(), false));
+ } else {
+ return String(value);
+ }
+ };
+ if (config.units) {
+ config.step = config.units.getStore().convertValue(1, config.units.getValue(), true);
+ }
+ }
+ this.callParent(arguments);
+ }
+});
diff --git a/legacy/web/app/view/CustomTimeField.js b/legacy/web/app/view/CustomTimeField.js
new file mode 100644
index 00000000..c2b44ce1
--- /dev/null
+++ b/legacy/web/app/view/CustomTimeField.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@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.CustomTimeField', {
+ extend: 'Ext.form.field.Time',
+ xtype: 'customTimeField',
+
+ constructor: function (config) {
+ if (Traccar.app.getPreference('twelveHourFormat', false)) {
+ config.format = Traccar.Style.timeFormat12;
+ } else {
+ config.format = Traccar.Style.timeFormat24;
+ }
+ this.callParent(arguments);
+ }
+});
diff --git a/legacy/web/app/view/DeviceMenu.js b/legacy/web/app/view/DeviceMenu.js
new file mode 100644
index 00000000..06b272ad
--- /dev/null
+++ b/legacy/web/app/view/DeviceMenu.js
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 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.DeviceMenu', {
+ extend: 'Ext.button.Button',
+ xtype: 'deviceMenu',
+
+ requires: [
+ 'Traccar.view.DeviceMenuController'
+ ],
+
+ glyph: 'xf013@FontAwesome',
+ tooltip: Strings.settingsTitle,
+ tooltipType: 'title',
+
+ menu: {
+ controller: 'deviceMenu',
+
+ items: [{
+ text: Strings.sharedDrivers,
+ glyph: 'xf084@FontAwesome',
+ handler: 'onDriversClick',
+ reference: 'menuDriversButton'
+ }, {
+ text: Strings.sharedGeofences,
+ glyph: 'xf21d@FontAwesome',
+ handler: 'onGeofencesClick',
+ reference: 'menuGeofencesButton'
+ }, {
+ text: Strings.sharedNotifications,
+ glyph: 'xf003@FontAwesome',
+ handler: 'onNotificationsClick',
+ reference: 'menuNotificationsButton'
+ }, {
+ text: Strings.sharedComputedAttributes,
+ glyph: 'xf0ae@FontAwesome',
+ handler: 'onComputedAttributesClick',
+ reference: 'menuComputedAttributesButton'
+ }, {
+ text: Strings.sharedSavedCommands,
+ glyph: 'xf093@FontAwesome',
+ handler: 'onCommandsClick',
+ reference: 'menuCommandsButton'
+ }, {
+ text: Strings.sharedMaintenance,
+ glyph: 'xf0ad@FontAwesome',
+ handler: 'onMaintenancesClick',
+ reference: 'menuMaintenancesButton'
+ }, {
+ hidden: true,
+ text: Strings.sharedDeviceAccumulators,
+ glyph: 'xf0e4@FontAwesome',
+ handler: 'onDeviceAccumulatorsClick',
+ reference: 'menuDeviceAccumulatorsButton'
+ }]
+ }
+});
diff --git a/legacy/web/app/view/DeviceMenuController.js b/legacy/web/app/view/DeviceMenuController.js
new file mode 100644
index 00000000..830ea7ec
--- /dev/null
+++ b/legacy/web/app/view/DeviceMenuController.js
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 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.DeviceMenuController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.deviceMenu',
+
+ requires: [
+ 'Traccar.view.permissions.Geofences',
+ 'Traccar.view.permissions.Drivers',
+ 'Traccar.view.permissions.Notifications',
+ 'Traccar.view.edit.ComputedAttributes',
+ 'Traccar.view.permissions.SavedCommands',
+ 'Traccar.view.permissions.Maintenances',
+ 'Traccar.view.dialog.DeviceAccumulators',
+ 'Traccar.view.BaseWindow'
+ ],
+
+ init: function () {
+ this.lookupReference('menuDriversButton').setHidden(
+ Traccar.app.getVehicleFeaturesDisabled() || Traccar.app.getBooleanAttributePreference('ui.disableDrivers'));
+ this.lookupReference('menuComputedAttributesButton').setHidden(
+ Traccar.app.getBooleanAttributePreference('ui.disableComputedAttributes'));
+ this.lookupReference('menuCommandsButton').setHidden(Traccar.app.getPreference('limitCommands', false));
+ this.lookupReference('menuDeviceAccumulatorsButton').setHidden(
+ !Traccar.app.getUser().get('administrator') && Traccar.app.getUser().get('userLimit') === 0 || Traccar.app.getVehicleFeaturesDisabled());
+ this.lookupReference('menuMaintenancesButton').setHidden(
+ Traccar.app.getVehicleFeaturesDisabled() || Traccar.app.getBooleanAttributePreference('ui.disableMaintenance'));
+ },
+
+ onGeofencesClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedGeofences,
+ items: {
+ xtype: 'linkGeofencesView',
+ baseObjectName: 'deviceId',
+ linkObjectName: 'geofenceId',
+ storeName: 'Geofences',
+ baseObject: this.getView().up('deviceMenu').device.getId()
+ }
+ }).show();
+ },
+
+ onNotificationsClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedNotifications,
+ items: {
+ xtype: 'linkNotificationsView',
+ baseObjectName: 'deviceId',
+ linkObjectName: 'notificationId',
+ storeName: 'Notifications',
+ baseObject: this.getView().up('deviceMenu').device.getId()
+ }
+ }).show();
+ },
+
+ onComputedAttributesClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedComputedAttributes,
+ items: {
+ xtype: 'linkComputedAttributesView',
+ baseObjectName: 'deviceId',
+ linkObjectName: 'attributeId',
+ storeName: 'ComputedAttributes',
+ baseObject: this.getView().up('deviceMenu').device.getId()
+ }
+ }).show();
+ },
+
+ onDriversClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedDrivers,
+ items: {
+ xtype: 'linkDriversView',
+ baseObjectName: 'deviceId',
+ linkObjectName: 'driverId',
+ storeName: 'Drivers',
+ baseObject: this.getView().up('deviceMenu').device.getId()
+ }
+ }).show();
+ },
+
+ onCommandsClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedSavedCommands,
+ items: {
+ xtype: 'linkSavedCommandsView',
+ baseObjectName: 'deviceId',
+ linkObjectName: 'commandId',
+ storeName: 'Commands',
+ baseObject: this.getView().up('deviceMenu').device.getId()
+ }
+ }).show();
+ },
+
+ onMaintenancesClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedMaintenance,
+ items: {
+ xtype: 'linkMaintenancesView',
+ baseObjectName: 'deviceId',
+ linkObjectName: 'maintenanceId',
+ storeName: 'Maintenances',
+ baseObject: this.getView().up('deviceMenu').device.getId()
+ }
+ }).show();
+ },
+
+ onDeviceAccumulatorsClick: function () {
+ var position, dialog = Ext.create('Traccar.view.dialog.DeviceAccumulators');
+ dialog.deviceId = this.getView().up('deviceMenu').device.getId();
+ position = Ext.getStore('LatestPositions').findRecord('deviceId', dialog.deviceId, 0, false, false, true);
+ if (position) {
+ dialog.lookupReference('totalDistance').setValue(position.get('attributes').totalDistance);
+ dialog.lookupReference('hours').setValue(position.get('attributes').hours);
+ }
+ dialog.show();
+ }
+});
diff --git a/legacy/web/app/view/Events.js b/legacy/web/app/view/Events.js
new file mode 100644
index 00000000..439de5af
--- /dev/null
+++ b/legacy/web/app/view/Events.js
@@ -0,0 +1,117 @@
+/*
+ * 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.Events', {
+ extend: 'Traccar.view.GridPanel',
+ xtype: 'eventsView',
+
+ requires: [
+ 'Traccar.view.EventsController'
+ ],
+
+ controller: 'events',
+
+ store: 'Events',
+
+ stateful: true,
+ stateId: 'events-grid',
+
+ title: Strings.reportEvents,
+
+ sortableColumns: false,
+
+ header: false,
+
+ tbar: {
+ componentCls: 'toolbar-header-style',
+ defaults: {
+ xtype: 'button',
+ tooltipType: 'title',
+ stateEvents: ['toggle'],
+ enableToggle: true,
+ stateful: {
+ pressed: true
+ }
+ },
+ items: [{
+ xtype: 'tbtext',
+ html: Strings.reportEvents,
+ baseCls: 'x-panel-header-title-default'
+ }, {
+ xtype: 'tbfill'
+ }, {
+ glyph: 'xf063@FontAwesome',
+ pressed: true,
+ toggleHandler: 'onScrollToLastClick',
+ stateId: 'events-scroll-to-last-button',
+ tooltip: Strings.eventsScrollToLast,
+ reference: 'scrollToLastButton'
+ }, {
+ id: 'soundButton',
+ glyph: 'xf0a2@FontAwesome',
+ tooltip: Strings.sharedSound,
+ stateId: 'sound-button'
+ }, {
+ glyph: 'xf014@FontAwesome',
+ tooltip: Strings.sharedRemove,
+ handler: 'onRemoveClick',
+ reference: 'removeEventButton',
+ disabled: true,
+ stateful: false,
+ enableToggle: false
+ }, {
+ glyph: 'xf1f8@FontAwesome',
+ tooltip: Strings.reportClear,
+ handler: 'onClearClick',
+ stateful: false,
+ enableToggle: false
+ }, {
+ glyph: 'xf00d@FontAwesome',
+ tooltip: Strings.sharedHide,
+ handler: 'onHideEvents',
+ reference: 'hideEventsButton',
+ hidden: true,
+ stateful: false,
+ enableToggle: false
+ }]
+ },
+
+ listeners: {
+ selectionchange: 'onSelectionChange'
+ },
+
+ columns: {
+ defaults: {
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ },
+ items: [{
+ text: Strings.sharedDevice,
+ dataIndex: 'deviceId',
+ renderer: Traccar.AttributeFormatter.getFormatter('deviceId')
+ }, {
+ flex: 2,
+ text: Strings.positionEvent,
+ dataIndex: 'text'
+ }, {
+ text: Strings.positionFixTime,
+ dataIndex: 'eventTime',
+ renderer: Traccar.AttributeFormatter.getFormatter('eventTime')
+ }]
+ }
+});
diff --git a/legacy/web/app/view/EventsController.js b/legacy/web/app/view/EventsController.js
new file mode 100644
index 00000000..e11b4ff6
--- /dev/null
+++ b/legacy/web/app/view/EventsController.js
@@ -0,0 +1,126 @@
+/*
+ * 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.EventsController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.events',
+
+ config: {
+ listen: {
+ controller: {
+ '*': {
+ selectdevice: 'deselectEvent',
+ selectreport: 'deselectEvent'
+ },
+ 'map': {
+ deselectfeature: 'deselectFeature'
+ }
+ },
+ store: {
+ '#Events': {
+ add: 'onAddEvent'
+ }
+ }
+ }
+ },
+
+ init: function () {
+ var self = this;
+ setInterval(function () {
+ self.getView().getView().refresh();
+ }, Traccar.Style.refreshPeriod);
+
+ if (Traccar.app.isMobile()) {
+ this.lookupReference('hideEventsButton').setHidden(false);
+ }
+ },
+
+ onRemoveClick: function () {
+ var event, positionId;
+ event = this.getView().getSelectionModel().getSelection()[0];
+ if (event) {
+ Ext.getStore('Events').remove(event);
+ positionId = event.get('positionId');
+ if (positionId && !Ext.getStore('Events').findRecord('positionId', positionId, 0, false, false, true)) {
+ Ext.getStore('EventPositions').remove(Ext.getStore('EventPositions').getById(positionId));
+ }
+ }
+ },
+
+ onClearClick: function () {
+ Ext.getStore('Events').removeAll();
+ Ext.getStore('EventPositions').removeAll();
+ },
+
+ onAddEvent: function () {
+ if (this.lookupReference('scrollToLastButton').pressed) {
+ this.getView().scrollBy(0, Number.POSITIVE_INFINITY, true);
+ }
+ },
+
+ onScrollToLastClick: function (button, pressed) {
+ if (pressed) {
+ this.onAddEvent();
+ }
+ },
+
+ onHideEvents: function () {
+ Traccar.app.showEvents(false);
+ },
+
+
+ deselectEvent: function (object) {
+ if (object) {
+ this.deselectFeature();
+ }
+ },
+
+ deselectFeature: function () {
+ this.getView().getSelectionModel().deselectAll();
+ },
+
+ onSelectionChange: function (selection, selected) {
+ var event, positionId, position;
+ event = selected.length > 0 ? selected[0] : null;
+ if (event) {
+ positionId = event.get('positionId');
+ if (positionId) {
+ position = Ext.getStore('EventPositions').getById(positionId);
+ if (position) {
+ this.fireEvent('selectevent', position);
+ } else {
+ Ext.getStore('EventPositions').load({
+ params: {
+ id: positionId
+ },
+ scope: this,
+ addRecords: true,
+ callback: function (records, operation, success) {
+ if (success && records.length > 0) {
+ this.fireEvent('selectevent', records[0]);
+ }
+ }
+ });
+ }
+ } else {
+ this.fireEvent('selectevent');
+ }
+ }
+ this.lookupReference('removeEventButton').setDisabled(!event);
+ }
+});
diff --git a/legacy/web/app/view/GridPanel.js b/legacy/web/app/view/GridPanel.js
new file mode 100644
index 00000000..848af081
--- /dev/null
+++ b/legacy/web/app/view/GridPanel.js
@@ -0,0 +1,34 @@
+/*
+ * 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.GridPanel', {
+ extend: 'Ext.grid.Panel',
+ xtype: 'customGridPanel',
+
+ requires: [
+ 'Ext.grid.filters.Filters'
+ ],
+
+ plugins: 'gridfilters',
+
+ viewConfig: {
+ enableTextSelection: true,
+ getRowClass: function () {
+ return this.enableTextSelection ? 'x-selectable' : '';
+ }
+ }
+});
diff --git a/legacy/web/app/view/Main.js b/legacy/web/app/view/Main.js
new file mode 100644
index 00000000..0504245e
--- /dev/null
+++ b/legacy/web/app/view/Main.js
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.Main', {
+ extend: 'Ext.container.Viewport',
+ alias: 'widget.main',
+
+ requires: [
+ 'Traccar.view.MainController',
+ 'Traccar.view.edit.Devices',
+ 'Traccar.view.State',
+ 'Traccar.view.Report',
+ 'Traccar.view.Events',
+ 'Traccar.view.map.Map'
+ ],
+
+ controller: 'mainController',
+
+ layout: 'border',
+
+ defaults: {
+ header: false,
+ collapsible: true,
+ split: true
+ },
+
+ items: [{
+ region: 'west',
+ layout: 'border',
+ width: Traccar.Style.deviceWidth,
+ title: Strings.devicesAndState,
+ titleCollapse: true,
+ floatable: false,
+ stateful: true,
+ stateId: 'devices-and-state-panel',
+
+ defaults: {
+ split: true,
+ flex: 1
+ },
+
+ items: [{
+ region: 'center',
+ xtype: 'devicesView'
+ }, {
+ region: 'south',
+ xtype: 'stateView'
+ }]
+ }, {
+ region: 'south',
+ xtype: 'reportView',
+ reference: 'reportView',
+ height: Traccar.Style.reportHeight,
+ collapsed: true,
+ titleCollapse: true,
+ floatable: false
+ }, {
+ region: 'center',
+ xtype: 'mapView',
+ collapsible: false
+ }, {
+ region: 'east',
+ xtype: 'eventsView',
+ reference: 'eventsView',
+ width: Traccar.Style.deviceWidth,
+ collapsed: true,
+ titleCollapse: true,
+ floatable: false
+ }]
+});
diff --git a/legacy/web/app/view/MainController.js b/legacy/web/app/view/MainController.js
new file mode 100644
index 00000000..8ed986af
--- /dev/null
+++ b/legacy/web/app/view/MainController.js
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2017 - 2022 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.MainController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.mainController',
+
+ init: function () {
+ this.lookupReference('reportView').setHidden(Traccar.app.getPreference('disableReports', false));
+ this.lookupReference('eventsView').setHidden(Traccar.app.getBooleanAttributePreference('ui.disableEvents'));
+ }
+});
diff --git a/legacy/web/app/view/MainMobile.js b/legacy/web/app/view/MainMobile.js
new file mode 100644
index 00000000..8aab7710
--- /dev/null
+++ b/legacy/web/app/view/MainMobile.js
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.MainMobile', {
+ extend: 'Ext.container.Viewport',
+ alias: 'widget.mainMobile',
+
+ id: 'rootPanel',
+
+ requires: [
+ 'Traccar.view.edit.Devices',
+ 'Traccar.view.State',
+ 'Traccar.view.Report',
+ 'Traccar.view.Events',
+ 'Traccar.view.map.Map'
+ ],
+
+ layout: 'card',
+
+ items: [{
+ layout: 'border',
+
+ defaults: {
+ header: false,
+ collapsible: true,
+ split: true
+ },
+
+ items: [{
+ region: 'east',
+ xtype: 'stateView',
+ title: Strings.stateTitle,
+ flex: 4,
+ collapsed: true,
+ collapseMode: 'mini',
+ titleCollapse: true,
+ floatable: false,
+ stateId: 'mobile-state-grid'
+ }, {
+ region: 'center',
+ xtype: 'mapView',
+ collapsible: false,
+ flex: 2
+ }, {
+ region: 'south',
+ xtype: 'devicesView',
+ title: Strings.deviceTitle,
+ flex: 1,
+ collapsed: true,
+ titleCollapse: true,
+ floatable: false,
+ stateId: 'mobile-devices-grid'
+ }]
+ }, {
+ xtype: 'reportView'
+ }, {
+ xtype: 'eventsView'
+ }]
+});
diff --git a/legacy/web/app/view/Report.js b/legacy/web/app/view/Report.js
new file mode 100644
index 00000000..deedb747
--- /dev/null
+++ b/legacy/web/app/view/Report.js
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2015 - 2016 Anton Tananaev (anton@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.Report', {
+ extend: 'Ext.panel.Panel',
+ xtype: 'reportView',
+
+ requires: [
+ 'Traccar.view.ReportController',
+ 'Traccar.view.GridPanel'
+ ],
+
+ controller: 'report',
+
+ title: Strings.reportTitle,
+
+ tools: [{
+ type: 'close',
+ tooltip: Strings.sharedHide,
+ handler: 'hideReports'
+ }],
+
+ tbar: {
+ scrollable: true,
+ items: [{
+ xtype: 'tbtext',
+ html: Strings.sharedType
+ }, {
+ xtype: 'combobox',
+ reference: 'reportTypeField',
+ store: 'ReportTypes',
+ displayField: 'name',
+ valueField: 'key',
+ editable: false,
+ listeners: {
+ change: 'onTypeChange'
+ }
+ }, '-', {
+ text: Strings.reportConfigure,
+ handler: 'onConfigureClick'
+ }, '-', {
+ text: Strings.reportShow,
+ reference: 'showButton',
+ disabled: true,
+ handler: 'onReportClick'
+ }, {
+ text: Strings.reportExport,
+ reference: 'exportButton',
+ disabled: true,
+ handler: 'onReportClick'
+ }, {
+ text: Strings.reportEmail,
+ reference: 'emailButton',
+ disabled: true,
+ handler: 'onReportClick'
+ }, {
+ text: Strings.reportClear,
+ handler: 'onClearClick'
+ }]
+ },
+
+ layout: 'card',
+
+ items: [{
+ xtype: 'customGridPanel',
+ itemId: 'grid',
+ listeners: {
+ selectionchange: 'onSelectionChange'
+ },
+ columns: {
+ defaults: {
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ },
+ items: [
+ ]
+ },
+ style: Traccar.Style.reportGridStyle
+ }, {
+ xtype: 'cartesian',
+ itemId: 'chart',
+ plugins: {
+ ptype: 'chartitemevents',
+ moveEvents: true
+ },
+ store: 'ReportRoute',
+ axes: [{
+ title: Strings.reportChart,
+ type: 'numeric',
+ position: 'left'
+ }, {
+ type: 'time',
+ position: 'bottom',
+ fields: ['fixTime']
+ }],
+ listeners: {
+ itemclick: 'onChartMarkerClick'
+ },
+ insetPadding: Traccar.Style.chartPadding
+ }]
+});
diff --git a/legacy/web/app/view/ReportController.js b/legacy/web/app/view/ReportController.js
new file mode 100644
index 00000000..8f63bd31
--- /dev/null
+++ b/legacy/web/app/view/ReportController.js
@@ -0,0 +1,678 @@
+/*
+ * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 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.ReportController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.report',
+
+ requires: [
+ 'Traccar.AttributeFormatter',
+ 'Traccar.model.Position',
+ 'Traccar.model.ReportTrip',
+ 'Traccar.view.dialog.ReportConfig',
+ 'Traccar.store.ReportEventTypes'
+ ],
+
+ config: {
+ listen: {
+ controller: {
+ '*': {
+ selectdevice: 'deselectReport',
+ selectevent: 'deselectReport',
+ showsingleevent: 'showSingleEvent'
+ },
+ 'map': {
+ selectreport: 'selectReport',
+ deselectfeature: 'deselectFeature'
+ }
+ },
+ global: {
+ routegeocode: 'onGeocode'
+ },
+ store: {
+ '#ReportEvents': {
+ add: 'loadRelatedPositions',
+ load: 'loadRelatedPositions'
+ },
+ '#ReportRoute': {
+ load: 'loadRoute'
+ },
+ '#ReportStops': {
+ load: 'loadRelatedPositions'
+ }
+ }
+ }
+ },
+
+ hideReports: function () {
+ Traccar.app.showReports(false);
+ },
+
+ getGrid: function () {
+ return this.getView().getComponent('grid');
+ },
+
+ getChart: function () {
+ return this.getView().getComponent('chart');
+ },
+
+ init: function () {
+ var i, data, attribute;
+ data = Ext.getStore('PositionAttributes').getData().items;
+ for (i = 0; i < data.length; i++) {
+ attribute = data[i];
+ this.routeColumns.push({
+ text: attribute.get('name'),
+ dataIndex: 'attribute.' + attribute.get('key'),
+ renderer: Traccar.AttributeFormatter.getAttributeFormatter(attribute.get('key')),
+ hidden: true
+ });
+ }
+ if (Traccar.app.getVehicleFeaturesDisabled()) {
+ for (i = 0; i < this.summaryColumns.length; i++) {
+ if (this.summaryColumns[i].dataIndex.match('engineHours|spentFuel')) {
+ this.summaryColumns[i].hidden = true;
+ }
+ }
+ for (i = 0; i < this.tripsColumns.length; i++) {
+ if (this.tripsColumns[i].dataIndex.match('spentFuel|driverUniqueId')) {
+ this.tripsColumns[i].hidden = true;
+ }
+ }
+ for (i = 0; i < this.stopsColumns.length; i++) {
+ if (this.stopsColumns[i].dataIndex.match('engineHours|spentFuel')) {
+ this.stopsColumns[i].hidden = true;
+ }
+ }
+ }
+ },
+
+ onConfigureClick: function () {
+ var dialog = Ext.create('Traccar.view.dialog.ReportConfig');
+ dialog.lookupReference('eventTypeField').setHidden(this.lookupReference('reportTypeField').getValue() !== 'events');
+ dialog.lookupReference('chartTypeField').setHidden(this.lookupReference('reportTypeField').getValue() !== 'chart');
+ dialog.callingPanel = this;
+ dialog.lookupReference('deviceField').setValue(this.deviceId);
+ dialog.lookupReference('groupField').setValue(this.groupId);
+ if (this.eventType !== undefined) {
+ dialog.lookupReference('eventTypeField').setValue(this.eventType);
+ } else {
+ dialog.lookupReference('eventTypeField').setValue([Traccar.store.ReportEventTypes.allEvents]);
+ }
+ if (this.chartType !== undefined) {
+ dialog.lookupReference('chartTypeField').setValue(this.chartType);
+ }
+ if (this.showMarkers !== undefined) {
+ dialog.lookupReference('showMarkersField').setValue(this.showMarkers);
+ }
+ if (this.fromDate !== undefined) {
+ dialog.lookupReference('fromDateField').setValue(this.fromDate);
+ }
+ if (this.fromTime !== undefined) {
+ dialog.lookupReference('fromTimeField').setValue(this.fromTime);
+ }
+ if (this.toDate !== undefined) {
+ dialog.lookupReference('toDateField').setValue(this.toDate);
+ }
+ if (this.toTime !== undefined) {
+ dialog.lookupReference('toTimeField').setValue(this.toTime);
+ }
+ if (this.period !== undefined) {
+ dialog.lookupReference('periodField').setValue(this.period);
+ }
+ dialog.show();
+ },
+
+ updateButtons: function () {
+ var reportType, disabled, devices, time;
+ reportType = this.lookupReference('reportTypeField').getValue();
+ devices = this.deviceId && this.deviceId.length !== 0 || this.groupId && this.groupId.length !== 0;
+ time = this.fromDate && this.fromTime && this.toDate && this.toTime;
+ disabled = !reportType || !devices || !time || this.reportProgress;
+ this.lookupReference('showButton').setDisabled(disabled);
+ this.lookupReference('exportButton').setDisabled(reportType === 'chart' || disabled);
+ this.lookupReference('emailButton').setDisabled(reportType === 'chart' || disabled);
+ },
+
+ onReportClick: function (button) {
+ var reportType, from, to, store, url, daily;
+
+ this.getGrid().getSelectionModel().deselectAll();
+
+ reportType = this.lookupReference('reportTypeField').getValue();
+ if (reportType && (this.deviceId || this.groupId)) {
+ from = new Date(
+ this.fromDate.getFullYear(), this.fromDate.getMonth(), this.fromDate.getDate(),
+ this.fromTime.getHours(), this.fromTime.getMinutes(), this.fromTime.getSeconds(), this.fromTime.getMilliseconds());
+
+ to = new Date(
+ this.toDate.getFullYear(), this.toDate.getMonth(), this.toDate.getDate(),
+ this.toTime.getHours(), this.toTime.getMinutes(), this.toTime.getSeconds(), this.toTime.getMilliseconds());
+
+ daily = reportType === 'daily';
+
+ this.reportProgress = true;
+ this.updateButtons();
+
+ if (button.reference === 'showButton') {
+ if (reportType === 'chart') {
+ store = this.getChart().getStore();
+ this.getChart().setSeries([]);
+ } else {
+ store = this.getGrid().getStore();
+ }
+ store.showMarkers = this.showMarkers;
+ store.load({
+ scope: this,
+ callback: function () {
+ this.reportProgress = false;
+ this.updateButtons();
+ },
+ params: {
+ deviceId: this.deviceId,
+ groupId: this.groupId,
+ type: this.eventType,
+ from: from.toISOString(),
+ to: to.toISOString(),
+ daily: daily
+ }
+ });
+ } else {
+ url = this.getGrid().getStore().getProxy().url;
+ this.excelReport(url, {
+ deviceId: this.deviceId,
+ groupId: this.groupId,
+ type: this.eventType,
+ from: Ext.Date.format(from, 'c'),
+ to: Ext.Date.format(to, 'c'),
+ daily: daily,
+ mail: button.reference === 'emailButton'
+ });
+ }
+ }
+ },
+
+ onClearClick: function () {
+ var reportType = this.lookupReference('reportTypeField').getValue();
+ this.clearReport(reportType);
+ },
+
+ clearReport: function (reportType) {
+ this.getGrid().getStore().removeAll();
+ if (reportType === 'trips' || reportType === 'events' || reportType === 'stops') {
+ Ext.getStore('ReportRoute').removeAll();
+ }
+ if (reportType === 'chart') {
+ this.getChart().getStore().removeAll();
+ }
+ },
+
+ onSelectionChange: function (selection, selected) {
+ var report;
+ if (selected.length > 0) {
+ report = selected[0];
+ this.fireEvent('selectreport', report, true);
+ if (report instanceof Traccar.model.ReportTrip) {
+ this.selectTrip(report);
+ }
+ if (report instanceof Traccar.model.Event || report instanceof Traccar.model.ReportStop) {
+ this.selectPositionRelated(report);
+ }
+ }
+ },
+
+ selectReport: function (object) {
+ var positionRelated, reportType = this.lookupReference('reportTypeField').getValue();
+ if (object instanceof Traccar.model.Position) {
+ if (reportType === 'route') {
+ this.getGrid().getSelectionModel().select([object], false, true);
+ this.getGrid().getView().focusRow(object);
+ } else if (reportType === 'events' || reportType === 'stops') {
+ positionRelated = this.getGrid().getStore().findRecord('positionId', object.get('id'), 0, false, true, true);
+ this.getGrid().getSelectionModel().select([positionRelated], false, true);
+ this.getGrid().getView().focusRow(positionRelated);
+ }
+ }
+ },
+
+ deselectReport: function (object) {
+ if (object) {
+ this.deselectFeature();
+ }
+ },
+
+ deselectFeature: function () {
+ if (this.lookupReference('reportTypeField').getValue() !== 'trips') {
+ this.getGrid().getSelectionModel().deselectAll();
+ }
+ },
+
+ selectTrip: function (trip) {
+ var from, to;
+ from = new Date(trip.get('startTime'));
+ to = new Date(trip.get('endTime'));
+ Ext.getStore('ReportRoute').removeAll();
+ Ext.getStore('ReportRoute').showMarkers = this.showMarkers;
+ Ext.getStore('ReportRoute').load({
+ params: {
+ deviceId: trip.get('deviceId'),
+ from: from.toISOString(),
+ to: to.toISOString()
+ }
+ });
+ },
+
+ selectPositionRelated: function (report) {
+ var position;
+ if (report.get('positionId')) {
+ position = Ext.getStore('ReportRoute').getById(report.get('positionId'));
+ if (position) {
+ this.fireEvent('selectreport', position, true);
+ }
+ }
+ },
+
+ loadRelatedPositions: function (store, data) {
+ var i, reportObject, positionIds = [];
+ Ext.getStore('ReportRoute').removeAll();
+ if (data) {
+ for (i = 0; i < data.length; i++) {
+ reportObject = data[i];
+ if (reportObject.get('positionId')) {
+ positionIds.push(reportObject.get('positionId'));
+ }
+ }
+ }
+ if (positionIds.length > 0) {
+ Ext.getStore('Positions').load({
+ params: {
+ id: positionIds
+ },
+ scope: this,
+ callback: function (records, operation, success) {
+ if (success) {
+ Ext.getStore('ReportRoute').showMarkers = this.showMarkers;
+ Ext.getStore('ReportRoute').add(records);
+ if (records.length === 1) {
+ this.fireEvent('selectreport', records[0], false);
+ }
+ }
+ }
+ });
+ }
+ },
+
+ loadRoute: function (store) {
+ var i, deviceIds, chartSeries, deviceStore;
+ if (this.lookupReference('reportTypeField').getValue() === 'chart') {
+ this.getChart().getAxes()[0].setTitle(
+ Ext.getStore('ReportChartTypes').findRecord('key', this.chartType).get('name'));
+ chartSeries = [];
+ deviceIds = store.collect('deviceId');
+ for (i = 0; i < deviceIds.length; i++) {
+ deviceStore = Ext.create('Ext.data.ChainedStore', {
+ source: 'ReportRoute',
+ filters: [{
+ property: 'deviceId',
+ value: deviceIds[i]
+ }]
+ });
+ chartSeries.push({
+ type: 'line',
+ store: deviceStore,
+ yField: this.chartType,
+ xField: 'fixTime',
+ highlightCfg: {
+ scaling: Traccar.Style.chartMarkerHighlightScaling
+ },
+ colors: [Traccar.app.getReportColor(deviceIds[i])],
+ marker: {
+ type: 'circle',
+ radius: Traccar.Style.chartMarkerRadius,
+ fill: Traccar.app.getReportColor(deviceIds[i])
+ }
+ });
+ }
+ this.getChart().setSeries(chartSeries);
+ }
+ },
+
+ onChartMarkerClick: function (chart, item) {
+ this.fireEvent('selectreport', item.record, true);
+ },
+
+ showSingleEvent: function (eventId) {
+ this.lookupReference('reportTypeField').setValue('events');
+ Ext.getStore('Events').load({
+ id: eventId,
+ scope: this,
+ callback: function (records, operation, success) {
+ if (success) {
+ Ext.getStore('ReportEvents').add(records);
+ if (records.length > 0) {
+ if (!records[0].get('positionId')) {
+ if (Traccar.app.isMobile()) {
+ Traccar.app.showReports(true);
+ } else {
+ this.getView().expand();
+ }
+ }
+ this.getGrid().getSelectionModel().select([records[0]], false, true);
+ this.getGrid().getView().focusRow(records[0]);
+ }
+ }
+ }
+ });
+ },
+
+ excelReport: function (requestUrl, requestParams) {
+ Ext.Ajax.request({
+ url: requestUrl,
+ method: 'GET',
+ timeout: Traccar.Style.reportTimeout,
+ params: requestParams,
+ headers: {
+ Accept: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
+ },
+ binary: true,
+ scope: this,
+ callback: function (options, success, response) {
+ var disposition, filename, type, blob, url, downloadUrl;
+ if (success && !requestParams.mail) {
+ disposition = response.getResponseHeader('Content-Disposition');
+ filename = disposition.slice(disposition.indexOf('=') + 1, disposition.length);
+ type = response.getResponseHeader('Content-Type');
+ blob = new Blob([response.responseBytes], {type: type});
+ if (typeof window.navigator.msSaveBlob !== 'undefined') {
+ // IE workaround
+ window.navigator.msSaveBlob(blob, filename);
+ } else {
+ url = window.URL || window.webkitURL;
+ downloadUrl = url.createObjectURL(blob);
+ if (filename) {
+ Ext.dom.Helper.append(Ext.getBody(), {
+ tag: 'a',
+ href: downloadUrl,
+ download: filename
+ }).click();
+ }
+ setTimeout(function () {
+ url.revokeObjectURL(downloadUrl);
+ }, 100);
+ }
+ }
+ this.reportProgress = false;
+ this.updateButtons();
+ }
+ });
+ },
+
+ onTypeChange: function (combobox, newValue, oldValue) {
+ if (oldValue !== null) {
+ this.clearReport(oldValue);
+ }
+
+ if (newValue === 'route') {
+ this.getGrid().reconfigure('ReportRoute', this.routeColumns);
+ this.getView().getLayout().setActiveItem('grid');
+ } else if (newValue === 'events') {
+ this.getGrid().reconfigure('ReportEvents', this.eventsColumns);
+ this.getView().getLayout().setActiveItem('grid');
+ } else if (newValue === 'summary' || newValue === 'daily') {
+ this.getGrid().reconfigure('ReportSummary', this.summaryColumns);
+ this.getView().getLayout().setActiveItem('grid');
+ } else if (newValue === 'trips') {
+ this.getGrid().reconfigure('ReportTrips', this.tripsColumns);
+ this.getView().getLayout().setActiveItem('grid');
+ } else if (newValue === 'stops') {
+ this.getGrid().reconfigure('ReportStops', this.stopsColumns);
+ this.getView().getLayout().setActiveItem('grid');
+ } else if (newValue === 'chart') {
+ this.getView().getLayout().setActiveItem('chart');
+ }
+
+ this.updateButtons();
+ },
+
+ onGeocode: function (positionId) {
+ var position = Ext.getStore('ReportRoute').getById(positionId);
+ if (position && !position.get('address')) {
+ Ext.Ajax.request({
+ scope: this,
+ method: 'GET',
+ url: 'api/server/geocode',
+ params: {
+ latitude: position.get('latitude'),
+ longitude: position.get('longitude')
+ },
+ success: function (response) {
+ position.set('address', response.responseText);
+ position.commit();
+ this.fireEvent('selectReport', position);
+ },
+ failure: function (response) {
+ Traccar.app.showError(response);
+ }
+ });
+ }
+ },
+
+ routeColumns: [{
+ text: Strings.reportDeviceName,
+ dataIndex: 'deviceId',
+ renderer: Traccar.AttributeFormatter.getFormatter('deviceId')
+ }, {
+ text: Strings.positionValid,
+ dataIndex: 'valid',
+ renderer: Traccar.AttributeFormatter.getFormatter('valid')
+ }, {
+ text: Strings.positionFixTime,
+ dataIndex: 'fixTime',
+ xtype: 'datecolumn',
+ renderer: Traccar.AttributeFormatter.getFormatter('fixTime')
+ }, {
+ text: Strings.positionLatitude,
+ dataIndex: 'latitude',
+ renderer: Traccar.AttributeFormatter.getFormatter('latitude')
+ }, {
+ text: Strings.positionLongitude,
+ dataIndex: 'longitude',
+ renderer: Traccar.AttributeFormatter.getFormatter('longitude')
+ }, {
+ text: Strings.positionAltitude,
+ dataIndex: 'altitude',
+ renderer: Traccar.AttributeFormatter.getFormatter('altitude')
+ }, {
+ text: Strings.positionSpeed,
+ dataIndex: 'speed',
+ renderer: Traccar.AttributeFormatter.getFormatter('speed')
+ }, {
+ text: Strings.positionAddress,
+ dataIndex: 'address',
+ renderer: function (value, metaData, record) {
+ if (!value) {
+ return '<a href="#" onclick="Ext.fireEvent(\'routegeocode\', ' +
+ record.getId() + ')" >' +
+ Strings.sharedShowAddress + '</a>';
+ }
+ return Traccar.AttributeFormatter.getFormatter('address')(value);
+ }
+ }],
+
+ eventsColumns: [{
+ text: Strings.positionFixTime,
+ dataIndex: 'eventTime',
+ xtype: 'datecolumn',
+ renderer: Traccar.AttributeFormatter.getFormatter('eventTime')
+ }, {
+ text: Strings.reportDeviceName,
+ dataIndex: 'deviceId',
+ renderer: Traccar.AttributeFormatter.getFormatter('deviceId')
+ }, {
+ text: Strings.sharedType,
+ dataIndex: 'type',
+ renderer: function (value) {
+ return Traccar.app.getEventString(value);
+ }
+ }, {
+ text: Strings.positionAlarm,
+ dataIndex: 'attributes',
+ renderer: function (value) {
+ return value['alarm'];
+ }
+ }, {
+ text: Strings.sharedGeofence,
+ dataIndex: 'geofenceId',
+ renderer: Traccar.AttributeFormatter.getFormatter('geofenceId')
+ }, {
+ text: Strings.sharedMaintenance,
+ dataIndex: 'maintenanceId',
+ renderer: Traccar.AttributeFormatter.getFormatter('maintenanceId')
+ }],
+
+ summaryColumns: [{
+ text: Strings.reportDeviceName,
+ dataIndex: 'deviceId',
+ renderer: Traccar.AttributeFormatter.getFormatter('deviceId')
+ }, {
+ text: Strings.reportStartDate,
+ dataIndex: 'startTime',
+ xtype: 'datecolumn',
+ renderer: Traccar.AttributeFormatter.dateFormatter
+ }, {
+ text: Strings.sharedDistance,
+ dataIndex: 'distance',
+ renderer: Traccar.AttributeFormatter.getFormatter('distance')
+ }, {
+ text: Strings.reportStartOdometer,
+ dataIndex: 'startOdometer',
+ renderer: Traccar.AttributeFormatter.getFormatter('distance')
+ }, {
+ text: Strings.reportEndOdometer,
+ dataIndex: 'endOdometer',
+ renderer: Traccar.AttributeFormatter.getFormatter('distance')
+ }, {
+ text: Strings.reportAverageSpeed,
+ dataIndex: 'averageSpeed',
+ renderer: Traccar.AttributeFormatter.getFormatter('speed')
+ }, {
+ text: Strings.reportMaximumSpeed,
+ dataIndex: 'maxSpeed',
+ renderer: Traccar.AttributeFormatter.getFormatter('speed')
+ }, {
+ text: Strings.reportEngineHours,
+ dataIndex: 'engineHours',
+ renderer: Traccar.AttributeFormatter.getFormatter('duration')
+ }, {
+ text: Strings.reportSpentFuel,
+ dataIndex: 'spentFuel',
+ renderer: Traccar.AttributeFormatter.getFormatter('spentFuel')
+ }],
+
+ tripsColumns: [{
+ text: Strings.reportDeviceName,
+ dataIndex: 'deviceId',
+ renderer: Traccar.AttributeFormatter.getFormatter('deviceId')
+ }, {
+ text: Strings.reportStartTime,
+ dataIndex: 'startTime',
+ xtype: 'datecolumn',
+ renderer: Traccar.AttributeFormatter.getFormatter('startTime')
+ }, {
+ text: Strings.reportStartOdometer,
+ dataIndex: 'startOdometer',
+ renderer: Traccar.AttributeFormatter.getFormatter('distance')
+ }, {
+ text: Strings.reportStartAddress,
+ dataIndex: 'startAddress',
+ renderer: Traccar.AttributeFormatter.getFormatter('address')
+ }, {
+ text: Strings.reportEndTime,
+ dataIndex: 'endTime',
+ xtype: 'datecolumn',
+ renderer: Traccar.AttributeFormatter.getFormatter('endTime')
+ }, {
+ text: Strings.reportEndOdometer,
+ dataIndex: 'endOdometer',
+ renderer: Traccar.AttributeFormatter.getFormatter('distance')
+ }, {
+ text: Strings.reportEndAddress,
+ dataIndex: 'endAddress',
+ renderer: Traccar.AttributeFormatter.getFormatter('address')
+ }, {
+ text: Strings.sharedDistance,
+ dataIndex: 'distance',
+ renderer: Traccar.AttributeFormatter.getFormatter('distance')
+ }, {
+ text: Strings.reportAverageSpeed,
+ dataIndex: 'averageSpeed',
+ renderer: Traccar.AttributeFormatter.getFormatter('speed')
+ }, {
+ text: Strings.reportMaximumSpeed,
+ dataIndex: 'maxSpeed',
+ renderer: Traccar.AttributeFormatter.getFormatter('speed')
+ }, {
+ text: Strings.reportDuration,
+ dataIndex: 'duration',
+ renderer: Traccar.AttributeFormatter.getFormatter('duration')
+ }, {
+ text: Strings.reportSpentFuel,
+ dataIndex: 'spentFuel',
+ renderer: Traccar.AttributeFormatter.getFormatter('spentFuel')
+ }, {
+ text: Strings.sharedDriver,
+ dataIndex: 'driverUniqueId',
+ renderer: Traccar.AttributeFormatter.getFormatter('driverUniqueId')
+ }],
+
+ stopsColumns: [{
+ text: Strings.reportDeviceName,
+ dataIndex: 'deviceId',
+ renderer: Traccar.AttributeFormatter.getFormatter('deviceId')
+ }, {
+ text: Strings.reportStartTime,
+ dataIndex: 'startTime',
+ xtype: 'datecolumn',
+ renderer: Traccar.AttributeFormatter.getFormatter('startTime')
+ }, {
+ text: Strings.positionOdometer,
+ dataIndex: 'startOdometer',
+ renderer: Traccar.AttributeFormatter.getFormatter('distance')
+ }, {
+ text: Strings.positionAddress,
+ dataIndex: 'address',
+ renderer: Traccar.AttributeFormatter.getFormatter('address')
+ }, {
+ text: Strings.reportEndTime,
+ dataIndex: 'endTime',
+ xtype: 'datecolumn',
+ renderer: Traccar.AttributeFormatter.getFormatter('endTime')
+ }, {
+ text: Strings.reportDuration,
+ dataIndex: 'duration',
+ renderer: Traccar.AttributeFormatter.getFormatter('duration')
+ }, {
+ text: Strings.reportEngineHours,
+ dataIndex: 'engineHours',
+ renderer: Traccar.AttributeFormatter.getFormatter('duration')
+ }, {
+ text: Strings.reportSpentFuel,
+ dataIndex: 'spentFuel',
+ renderer: Traccar.AttributeFormatter.getFormatter('spentFuel')
+ }]
+});
diff --git a/legacy/web/app/view/SettingsMenu.js b/legacy/web/app/view/SettingsMenu.js
new file mode 100644
index 00000000..0a81d520
--- /dev/null
+++ b/legacy/web/app/view/SettingsMenu.js
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2015 - 2018 Anton Tananaev (anton@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.SettingsMenu', {
+ extend: 'Ext.button.Button',
+ xtype: 'settingsMenu',
+
+ requires: [
+ 'Traccar.view.SettingsMenuController'
+ ],
+
+ glyph: 'xf013@FontAwesome',
+ tooltip: Strings.settingsTitle,
+ tooltipType: 'title',
+
+ menu: {
+ controller: 'settings',
+
+ items: [{
+ hidden: true,
+ text: Strings.settingsUser,
+ glyph: 'xf007@FontAwesome',
+ handler: 'onUserClick',
+ reference: 'settingsUserButton'
+ }, {
+ hidden: true,
+ text: Strings.settingsGroups,
+ glyph: 'xf247@FontAwesome',
+ handler: 'onGroupsClick',
+ reference: 'settingsGroupsButton'
+ }, {
+ hidden: true,
+ text: Strings.sharedDrivers,
+ glyph: 'xf084@FontAwesome',
+ handler: 'onDriversClick',
+ reference: 'settingsDriversButton'
+ }, {
+ hidden: true,
+ text: Strings.sharedGeofences,
+ glyph: 'xf21d@FontAwesome',
+ handler: 'onGeofencesClick',
+ reference: 'settingsGeofencesButton'
+ }, {
+ hidden: true,
+ text: Strings.settingsServer,
+ glyph: 'xf233@FontAwesome',
+ handler: 'onServerClick',
+ reference: 'settingsServerButton'
+ }, {
+ hidden: true,
+ text: Strings.settingsUsers,
+ glyph: 'xf0c0@FontAwesome',
+ handler: 'onUsersClick',
+ reference: 'settingsUsersButton'
+ }, {
+ hidden: true,
+ text: Strings.sharedNotifications,
+ glyph: 'xf003@FontAwesome',
+ handler: 'onNotificationsClick',
+ reference: 'settingsNotificationsButton'
+ }, {
+ hidden: true,
+ text: Strings.sharedComputedAttributes,
+ glyph: 'xf0ae@FontAwesome',
+ handler: 'onComputedAttributesClick',
+ reference: 'settingsComputedAttributesButton'
+ }, {
+ hidden: true,
+ text: Strings.statisticsTitle,
+ glyph: 'xf080@FontAwesome',
+ handler: 'onStatisticsClick',
+ reference: 'settingsStatisticsButton'
+ }, {
+ hidden: true,
+ text: Strings.sharedCalendars,
+ glyph: 'xf073@FontAwesome',
+ handler: 'onCalendarsClick',
+ reference: 'settingsCalendarsButton'
+ }, {
+ hidden: true,
+ text: Strings.sharedSavedCommands,
+ glyph: 'xf093@FontAwesome',
+ handler: 'onCommandsClick',
+ reference: 'settingsCommandsButton'
+ }, {
+ hidden: true,
+ text: Strings.sharedMaintenance,
+ glyph: 'xf0ad@FontAwesome',
+ handler: 'onMaintenancesClick',
+ reference: 'settingsMaintenancesButton'
+ }, {
+ text: Strings.loginLogout,
+ glyph: 'xf08b@FontAwesome',
+ handler: 'onLogoutClick'
+ }]
+ }
+});
diff --git a/legacy/web/app/view/SettingsMenuController.js b/legacy/web/app/view/SettingsMenuController.js
new file mode 100644
index 00000000..c8018f66
--- /dev/null
+++ b/legacy/web/app/view/SettingsMenuController.js
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2015 - 2018 Anton Tananaev (anton@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.SettingsMenuController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.settings',
+
+ requires: [
+ 'Traccar.view.dialog.LoginController',
+ 'Traccar.view.dialog.User',
+ 'Traccar.view.dialog.Server',
+ 'Traccar.view.edit.Users',
+ 'Traccar.view.edit.Groups',
+ 'Traccar.view.edit.Geofences',
+ 'Traccar.view.edit.Drivers',
+ 'Traccar.view.edit.Notifications',
+ 'Traccar.view.edit.ComputedAttributes',
+ 'Traccar.view.Statistics',
+ 'Traccar.view.edit.Calendars',
+ 'Traccar.view.edit.SavedCommands',
+ 'Traccar.view.edit.Maintenances',
+ 'Traccar.view.BaseWindow'
+ ],
+
+ init: function () {
+ var admin, manager, readonly;
+ admin = Traccar.app.getUser().get('administrator');
+ manager = Traccar.app.getUser().get('userLimit') !== 0;
+ readonly = Traccar.app.getPreference('readonly', false);
+ if (admin) {
+ this.lookupReference('settingsServerButton').setHidden(false);
+ this.lookupReference('settingsStatisticsButton').setHidden(false);
+ this.lookupReference('settingsComputedAttributesButton').setHidden(
+ Traccar.app.getBooleanAttributePreference('ui.disableComputedAttributes'));
+ }
+ if (admin || manager) {
+ this.lookupReference('settingsUsersButton').setHidden(false);
+ }
+ if (admin || !readonly) {
+ this.lookupReference('settingsUserButton').setHidden(false);
+ this.lookupReference('settingsGroupsButton').setHidden(false);
+ this.lookupReference('settingsGeofencesButton').setHidden(false);
+ this.lookupReference('settingsNotificationsButton').setHidden(false);
+ this.lookupReference('settingsCalendarsButton').setHidden(
+ Traccar.app.getBooleanAttributePreference('ui.disableCalendars'));
+ this.lookupReference('settingsDriversButton').setHidden(
+ Traccar.app.getVehicleFeaturesDisabled() || Traccar.app.getBooleanAttributePreference('ui.disableDrivers'));
+ this.lookupReference('settingsCommandsButton').setHidden(Traccar.app.getPreference('limitCommands', false));
+ this.lookupReference('settingsMaintenancesButton').setHidden(
+ Traccar.app.getVehicleFeaturesDisabled() || Traccar.app.getBooleanAttributePreference('ui.disableMaintenance'));
+ }
+ },
+
+ onUserClick: function () {
+ var dialog = Ext.create('Traccar.view.dialog.User', {
+ selfEdit: true
+ });
+ dialog.down('form').loadRecord(Traccar.app.getUser());
+ dialog.lookupReference('testNotificationButton').setHidden(false);
+ dialog.show();
+ },
+
+ onGroupsClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.settingsGroups,
+ items: {
+ xtype: 'groupsView'
+ }
+ }).show();
+ },
+
+ onGeofencesClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedGeofences,
+ items: {
+ xtype: 'geofencesView'
+ }
+ }).show();
+ },
+
+ onServerClick: function () {
+ var dialog = Ext.create('Traccar.view.dialog.Server');
+ dialog.down('form').loadRecord(Traccar.app.getServer());
+ dialog.show();
+ },
+
+ onUsersClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.settingsUsers,
+ items: {
+ xtype: 'usersView'
+ }
+ }).show();
+ },
+
+ onNotificationsClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedNotifications,
+ items: {
+ xtype: 'notificationsView'
+ }
+ }).show();
+ },
+
+ onComputedAttributesClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedComputedAttributes,
+ items: {
+ xtype: 'computedAttributesView'
+ }
+ }).show();
+ },
+
+ onStatisticsClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.statisticsTitle,
+ items: {
+ xtype: 'statisticsView'
+ }
+ }).show();
+ },
+
+ onCalendarsClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedCalendars,
+ items: {
+ xtype: 'calendarsView'
+ }
+ }).show();
+ },
+
+ onDriversClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedDrivers,
+ items: {
+ xtype: 'driversView'
+ }
+ }).show();
+ },
+
+ onCommandsClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedSavedCommands,
+ items: {
+ xtype: 'savedCommandsView'
+ }
+ }).show();
+ },
+
+ onMaintenancesClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedMaintenance,
+ items: {
+ xtype: 'maintenancesView'
+ }
+ }).show();
+ },
+
+ onLogoutClick: function () {
+ Ext.create('Traccar.view.dialog.LoginController').logout();
+ }
+});
diff --git a/legacy/web/app/view/State.js b/legacy/web/app/view/State.js
new file mode 100644
index 00000000..c0a430d9
--- /dev/null
+++ b/legacy/web/app/view/State.js
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2015 - 2022 Anton Tananaev (anton@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.State', {
+ extend: 'Traccar.view.GridPanel',
+ xtype: 'stateView',
+
+ requires: [
+ 'Traccar.view.StateController'
+ ],
+
+ controller: 'state',
+ store: 'Attributes',
+
+ stateful: true,
+ stateId: 'state-grid',
+
+ tbar: {
+ componentCls: 'toolbar-header-style',
+ items: [{
+ xtype: 'tbtext',
+ html: Strings.stateTitle,
+ baseCls: 'x-panel-header-title-default'
+ }, {
+ xtype: 'tbfill'
+ }, {
+ xtype: 'button',
+ disabled: true,
+ handler: 'onComputedAttributesClick',
+ reference: 'computedAttributesButton',
+ glyph: 'xf0ae@FontAwesome',
+ tooltip: Strings.sharedComputedAttributes,
+ tooltipType: 'title'
+ }]
+ },
+
+ columns: {
+ defaults: {
+ minWidth: Traccar.Style.columnWidthNormal,
+ flex: 1
+ },
+ items: [{
+ text: Strings.stateName,
+ dataIndex: 'name'
+ }, {
+ text: Strings.stateValue,
+ dataIndex: 'value',
+ cellWrap: true,
+ renderer: function (value, metaData, record) {
+ var position, device, attribute;
+ attribute = record.get('attribute');
+ if (attribute === 'alarm') {
+ metaData.tdCls = 'view-color-red';
+ } else if (attribute === 'address' && !value) {
+ return '<a href="#" onclick="Ext.fireEvent(\'stategeocode\')" >' +
+ Strings.sharedShowAddress + '</a>';
+ } else if (attribute === 'image' || attribute === 'video' || attribute === 'audio') {
+ position = this.getController().position;
+ if (position) {
+ device = Ext.getStore('Devices').getById(position.get('deviceId'));
+ if (device) {
+ return '<a target="_blank" href="/api/media/' +
+ device.get('uniqueId') + '/' + value + '" >' + value + '</a>';
+ }
+ }
+ }
+ return value;
+ }
+ }]
+ }
+});
diff --git a/legacy/web/app/view/StateController.js b/legacy/web/app/view/StateController.js
new file mode 100644
index 00000000..f04d7185
--- /dev/null
+++ b/legacy/web/app/view/StateController.js
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2015 - 2022 Anton Tananaev (anton@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.StateController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.state',
+
+ requires: [
+ 'Traccar.AttributeFormatter',
+ 'Traccar.model.Attribute',
+ 'Traccar.model.Position',
+ 'Traccar.view.BaseWindow',
+ 'Traccar.view.edit.ComputedAttributes'
+ ],
+
+ config: {
+ listen: {
+ controller: {
+ '*': {
+ selectdevice: 'selectDevice',
+ selectreport: 'selectPosition',
+ selectevent: 'selectPosition',
+ deselectfeature: 'deselectFeature'
+ }
+ },
+ global: {
+ stategeocode: 'onGeocode'
+ },
+ store: {
+ '#LatestPositions': {
+ add: 'updateLatest',
+ update: 'updateLatest'
+ },
+ '#ReportRoute': {
+ clear: 'clearReport'
+ }
+ }
+ }
+ },
+
+ init: function () {
+ var i, hideAttributesPreference, attributesList;
+ if (Traccar.app.getUser().get('administrator') ||
+ !Traccar.app.getUser().get('deviceReadonly') && !Traccar.app.getPreference('readonly', false)) {
+ this.lookupReference('computedAttributesButton').setDisabled(
+ Traccar.app.getBooleanAttributePreference('ui.disableComputedAttributes'));
+ }
+ hideAttributesPreference = Traccar.app.getAttributePreference('ui.hidePositionAttributes');
+ this.hideAttributes = {};
+ if (hideAttributesPreference) {
+ attributesList = hideAttributesPreference.split(/[ ,]+/).filter(Boolean);
+ for (i = 0; i < attributesList.length; i++) {
+ this.hideAttributes[attributesList[i]] = true;
+ }
+ }
+ },
+
+ onComputedAttributesClick: function () {
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedComputedAttributes,
+ items: {
+ xtype: 'computedAttributesView'
+ }
+ }).show();
+ },
+
+ keys: (function () {
+ var i, list, result;
+ result = {};
+ list = ['fixTime', 'latitude', 'longitude', 'valid', 'accuracy', 'altitude', 'speed', 'course', 'address', 'protocol'];
+ for (i = 0; i < list.length; i++) {
+ result[list[i]] = {
+ priority: i,
+ name: Strings['position' + list[i].replace(/^\w/g, function (s) {
+ return s.toUpperCase();
+ })]
+ };
+ }
+ return result;
+ })(),
+
+ updateLatest: function (store, data) {
+ var i;
+ if (!Ext.isArray(data)) {
+ data = [data];
+ }
+ for (i = 0; i < data.length; i++) {
+ if (this.deviceId === data[i].get('deviceId')) {
+ this.position = data[i];
+ this.updatePosition();
+ }
+ }
+ },
+
+ formatValue: function (value) {
+ if (typeof id === 'number') {
+ return Number(value.toFixed(2));
+ } else {
+ return value;
+ }
+ },
+
+ findAttribute: function (record) {
+ return record.get('deviceId') === this.position.get('deviceId') && record.get('attribute') === this.lookupAttribute;
+ },
+
+ updatePosition: function () {
+ var attributes, store, key, name, value;
+ store = Ext.getStore('Attributes');
+ store.removeAll();
+
+ 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,
+ attribute: key,
+ value: Traccar.AttributeFormatter.getFormatter(key)(this.position.get(key))
+ }));
+ }
+ }
+
+ attributes = this.position.get('attributes');
+ if (attributes instanceof Object) {
+ for (key in attributes) {
+ if (attributes.hasOwnProperty(key) && !this.hideAttributes[key]) {
+ this.lookupAttribute = key;
+ name = Ext.getStore('PositionAttributes').getAttributeName(key, true);
+ if (this.position.get('attribute.' + key) !== undefined) {
+ value = Traccar.AttributeFormatter.getAttributeFormatter(key)(this.position.get('attribute.' + key));
+ } else {
+ value = Traccar.AttributeFormatter.defaultFormatter(attributes[key]);
+ }
+ store.add(Ext.create('Traccar.model.Attribute', {
+ priority: 1024,
+ name: name,
+ attribute: key,
+ value: value
+ }));
+ }
+ }
+ }
+ },
+
+ selectDevice: function (device) {
+ var position;
+ this.deviceId = device.get('id');
+ position = Ext.getStore('LatestPositions').findRecord('deviceId', this.deviceId, 0, false, false, true);
+ if (position) {
+ this.position = position;
+ this.updatePosition();
+ } else {
+ this.position = null;
+ Ext.getStore('Attributes').removeAll();
+ }
+ },
+
+ selectPosition: function (position) {
+ if (position instanceof Traccar.model.Position) {
+ this.deviceId = null;
+ this.position = position;
+ this.updatePosition();
+ }
+ },
+
+ deselectFeature: function () {
+ this.deviceId = null;
+ this.position = null;
+ Ext.getStore('Attributes').removeAll();
+ },
+
+ clearReport: function () {
+ if (!this.deviceId) {
+ this.position = null;
+ Ext.getStore('Attributes').removeAll();
+ }
+ },
+
+ onGeocode: function () {
+ var positionId = this.position.getId();
+ if (!this.position.get('address')) {
+ Ext.Ajax.request({
+ scope: this,
+ method: 'GET',
+ url: 'api/server/geocode',
+ params: {
+ latitude: this.position.get('latitude'),
+ longitude: this.position.get('longitude')
+ },
+ success: function (response) {
+ if (this.position && this.position.getId() === positionId) {
+ this.position.set('address', response.responseText);
+ this.updatePosition();
+ }
+ },
+ failure: function (response) {
+ Traccar.app.showError(response);
+ }
+ });
+ }
+ }
+});
diff --git a/legacy/web/app/view/Statistics.js b/legacy/web/app/view/Statistics.js
new file mode 100644
index 00000000..af199a02
--- /dev/null
+++ b/legacy/web/app/view/Statistics.js
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.Statistics', {
+ extend: 'Traccar.view.GridPanel',
+ xtype: 'statisticsView',
+
+ requires: [
+ 'Traccar.view.StatisticsController'
+ ],
+
+ controller: 'statistics',
+ store: 'Statistics',
+
+ tbar: {
+ scrollable: true,
+ items: [{
+ xtype: 'tbtext',
+ html: Strings.reportFrom
+ }, {
+ xtype: 'datefield',
+ reference: 'fromDateField',
+ startDay: Traccar.Style.weekStartDay,
+ format: Traccar.Style.dateFormat,
+ value: new Date(new Date().getTime() - 24 * 60 * 60 * 1000)
+ }, '-', {
+ xtype: 'tbtext',
+ html: Strings.reportTo
+ }, {
+ xtype: 'datefield',
+ reference: 'toDateField',
+ startDay: Traccar.Style.weekStartDay,
+ format: Traccar.Style.dateFormat,
+ value: new Date()
+ }, '-', {
+ text: Strings.reportShow,
+ handler: 'onShowClick'
+ }]
+ },
+
+ columns: {
+ defaults: {
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ },
+ items: [{
+ text: Strings.statisticsCaptureTime,
+ dataIndex: 'captureTime',
+ xtype: 'datecolumn',
+ renderer: Traccar.AttributeFormatter.defaultFormatter()
+ }, {
+ text: Strings.statisticsActiveUsers,
+ dataIndex: 'activeUsers'
+ }, {
+ text: Strings.statisticsActiveDevices,
+ dataIndex: 'activeDevices'
+ }, {
+ text: Strings.statisticsRequests,
+ dataIndex: 'requests'
+ }, {
+ text: Strings.statisticsMessagesReceived,
+ dataIndex: 'messagesReceived'
+ }, {
+ text: Strings.statisticsMessagesStored,
+ dataIndex: 'messagesStored'
+ }, {
+ text: Strings.notificatorMail,
+ dataIndex: 'mailSent'
+ }, {
+ text: Strings.notificatorSms,
+ dataIndex: 'smsSent'
+ }, {
+ text: Strings.statisticsGeocoder,
+ dataIndex: 'geocoderRequests'
+ }, {
+ text: Strings.statisticsGeolocation,
+ dataIndex: 'geolocationRequests'
+ }]
+ }
+});
diff --git a/legacy/web/app/view/StatisticsController.js b/legacy/web/app/view/StatisticsController.js
new file mode 100644
index 00000000..c4ce9d37
--- /dev/null
+++ b/legacy/web/app/view/StatisticsController.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 Anton Tananaev (anton@traccar.org)
+ *
+ * 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.StatisticsController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.statistics',
+
+ onShowClick: function () {
+ Ext.getStore('Statistics').load({
+ params: {
+ from: this.lookupReference('fromDateField').getValue().toISOString(),
+ to: this.lookupReference('toDateField').getValue().toISOString()
+ }
+ });
+ }
+});
diff --git a/legacy/web/app/view/TouchFix62.js b/legacy/web/app/view/TouchFix62.js
new file mode 100644
index 00000000..300d4f70
--- /dev/null
+++ b/legacy/web/app/view/TouchFix62.js
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@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/>.
+ */
+
+/*
+ * Workaround for bug in ExtJs 6.2.0.
+ * Resolved in current yet unreleased version
+ */
+
+Ext.define('Traccar.view.TouchFix62', {
+ override: 'Ext.dom.Element'
+},
+function () {
+ var additiveEvents = this.prototype.additiveEvents,
+ eventMap = this.prototype.eventMap;
+ if (Ext.supports.TouchEvents && Ext.firefoxVersion >= 52 && Ext.os.is.Desktop) {
+ eventMap['touchstart'] = 'mousedown';
+ eventMap['touchmove'] = 'mousemove';
+ eventMap['touchend'] = 'mouseup';
+ eventMap['touchcancel'] = 'mouseup';
+ eventMap['click'] = 'click';
+ eventMap['dblclick'] = 'dblclick';
+ additiveEvents['mousedown'] = 'mousedown';
+ additiveEvents['mousemove'] = 'mousemove';
+ additiveEvents['mouseup'] = 'mouseup';
+ additiveEvents['touchstart'] = 'touchstart';
+ additiveEvents['touchmove'] = 'touchmove';
+ additiveEvents['touchend'] = 'touchend';
+ additiveEvents['touchcancel'] = 'touchcancel';
+ additiveEvents['pointerdown'] = 'mousedown';
+ additiveEvents['pointermove'] = 'mousemove';
+ additiveEvents['pointerup'] = 'mouseup';
+ additiveEvents['pointercancel'] = 'mouseup';
+ }
+});
diff --git a/legacy/web/app/view/UnescapedTextAreaField.js b/legacy/web/app/view/UnescapedTextAreaField.js
new file mode 100644
index 00000000..5de267ce
--- /dev/null
+++ b/legacy/web/app/view/UnescapedTextAreaField.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2019 Anton Tananaev (anton@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.UnescapedTextAreaField', {
+ extend: 'Ext.form.field.TextArea',
+ xtype: 'unescapedTextAreaField',
+
+ initComponent: function () {
+ this.callParent();
+ this.on('change', this.onValueChange);
+ },
+
+ onValueChange: function (field, newValue) {
+ field.setValue(Ext.String.htmlDecode(newValue));
+ }
+});
diff --git a/legacy/web/app/view/UnescapedTextField.js b/legacy/web/app/view/UnescapedTextField.js
new file mode 100644
index 00000000..3b1b2798
--- /dev/null
+++ b/legacy/web/app/view/UnescapedTextField.js
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2019 Anton Tananaev (anton@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.UnescapedTextField', {
+ extend: 'Ext.form.field.Text',
+ xtype: 'unescapedTextField',
+
+ initComponent: function () {
+ this.callParent();
+ this.on('change', this.onValueChange);
+ },
+
+ onValueChange: function (field, newValue) {
+ field.setValue(Ext.String.htmlDecode(newValue));
+ }
+});
diff --git a/legacy/web/app/view/dialog/Attribute.js b/legacy/web/app/view/dialog/Attribute.js
new file mode 100644
index 00000000..a85cad05
--- /dev/null
+++ b/legacy/web/app/view/dialog/Attribute.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@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.Attribute', {
+ extend: 'Traccar.view.dialog.Base',
+
+ requires: [
+ 'Traccar.view.dialog.AttributeController',
+ 'Traccar.view.ColorPicker',
+ 'Traccar.view.CustomNumberField',
+ 'Traccar.view.UnescapedTextField'
+ ],
+
+ controller: 'attribute',
+ title: Strings.sharedAttribute,
+
+ items: {
+ xtype: 'form',
+ listeners: {
+ validitychange: 'onValidityChange'
+ },
+ items: [{
+ xtype: 'unescapedTextField',
+ reference: 'nameTextField',
+ name: 'name',
+ allowBlank: false,
+ fieldLabel: Strings.sharedName
+ }, {
+ xtype: 'textfield',
+ name: 'value',
+ reference: 'valueField',
+ allowBlank: false,
+ fieldLabel: Strings.stateValue
+ }]
+ },
+
+ buttons: [{
+ glyph: 'xf00c@FontAwesome',
+ reference: 'saveButton',
+ tooltip: Strings.sharedSave,
+ tooltipType: 'title',
+ minWidth: 0,
+ handler: 'onSaveClick'
+ }, {
+ glyph: 'xf00d@FontAwesome',
+ tooltip: Strings.sharedCancel,
+ tooltipType: 'title',
+ minWidth: 0,
+ handler: 'closeView'
+ }]
+});
diff --git a/legacy/web/app/view/dialog/AttributeController.js b/legacy/web/app/view/dialog/AttributeController.js
new file mode 100644
index 00000000..9fd452a4
--- /dev/null
+++ b/legacy/web/app/view/dialog/AttributeController.js
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2016 - 2018 Anton Tananaev (anton@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.AttributeController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.attribute',
+
+ onSaveClick: function (button) {
+ var dialog, store, record;
+ dialog = button.up('window').down('form');
+ dialog.updateRecord();
+ record = dialog.getRecord();
+ store = record.store;
+ if (store) {
+ if (record.phantom) {
+ store.add(record);
+ }
+ store.sync({
+ failure: function (batch) {
+ store.rejectChanges();
+ Traccar.app.showError(batch.exceptions[0].getError().response);
+ }
+ });
+ } else {
+ record.save();
+ }
+ button.up('window').close();
+ },
+
+ onValidityChange: function (form, valid) {
+ this.lookupReference('saveButton').setDisabled(!valid);
+ },
+
+ defaultFieldConfig: {
+ name: 'value',
+ reference: 'valueField',
+ allowBlank: false,
+ fieldLabel: Strings.stateValue
+ },
+
+ onNameChange: function (combobox, newValue) {
+ var config, attribute, valueField = this.lookupReference('valueField');
+ attribute = combobox.getStore().getById(newValue);
+ if (attribute) {
+ config = Ext.clone(this.defaultFieldConfig);
+ switch (attribute.get('valueType')) {
+ case 'number':
+ config.xtype = 'customNumberField';
+ if (attribute.get('allowDecimals') !== undefined) {
+ config.allowDecimals = attribute.get('allowDecimals');
+ } else {
+ config.allowDecimals = true;
+ }
+ config.dataType = attribute.get('dataType');
+ config.maxValue = attribute.get('maxValue');
+ config.minValue = attribute.get('minValue');
+ break;
+ case 'boolean':
+ config.xtype = 'checkboxfield';
+ config.inputValue = true;
+ config.uncheckedValue = false;
+ break;
+ case 'color':
+ config.xtype = 'customcolorpicker';
+ break;
+ default:
+ if (attribute.get('dataType')) {
+ config.xtype = 'combobox';
+ config.queryMode = 'local';
+ config.editable = false;
+ switch (attribute.get('dataType')) {
+ case 'distanceUnit':
+ config.store = 'DistanceUnits';
+ config.displayField = 'name';
+ config.valueField = 'key';
+ break;
+ case 'speedUnit':
+ config.store = 'SpeedUnits';
+ config.displayField = 'name';
+ config.valueField = 'key';
+ break;
+ case 'volumeUnit':
+ config.store = 'VolumeUnits';
+ config.displayField = 'fullName';
+ config.valueField = 'key';
+ break;
+ case 'timezone':
+ config.store = 'AllTimezones';
+ config.displayField = 'key';
+ break;
+ default:
+ break;
+ }
+ } else {
+ config.xtype = 'textfield';
+ }
+ break;
+ }
+ if (valueField.getXType() !== config.xtype ||
+ config.xtype === 'customNumberField' && valueField.dataType !== config.dataType) {
+ this.getView().down('form').insert(this.getView().down('form').items.indexOf(valueField), config);
+ this.getView().down('form').remove(valueField);
+ } else if (config.xtype === 'customNumberField') {
+ valueField.setConfig(config);
+ valueField.validate();
+ } else if (config.xtype === 'combobox') {
+ valueField.setConfig(config);
+ valueField.setValue();
+ }
+ }
+ }
+});
diff --git a/legacy/web/app/view/dialog/Base.js b/legacy/web/app/view/dialog/Base.js
new file mode 100644
index 00000000..6affb370
--- /dev/null
+++ b/legacy/web/app/view/dialog/Base.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.Base', {
+ extend: 'Ext.window.Window',
+
+ bodyPadding: Traccar.Style.normalPadding,
+ resizable: false,
+ scrollable: true,
+ constrain: true,
+
+ initComponent: function () {
+ if (window.innerHeight) {
+ this.maxHeight = window.innerHeight - Traccar.Style.normalPadding * 2;
+ }
+ this.callParent();
+ }
+});
diff --git a/legacy/web/app/view/dialog/BaseEdit.js b/legacy/web/app/view/dialog/BaseEdit.js
new file mode 100644
index 00000000..286afba5
--- /dev/null
+++ b/legacy/web/app/view/dialog/BaseEdit.js
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.BaseEdit', {
+ extend: 'Traccar.view.dialog.Base',
+
+ requires: [
+ 'Traccar.view.dialog.BaseEditController'
+ ],
+
+ controller: 'baseEdit',
+
+ buttons: [{
+ text: Strings.sharedAttributes,
+ handler: 'showAttributesView'
+ }, {
+ xtype: 'tbfill'
+ }, {
+ glyph: 'xf00c@FontAwesome',
+ reference: 'saveButton',
+ tooltip: Strings.sharedSave,
+ tooltipType: 'title',
+ minWidth: 0,
+ handler: 'onSaveClick'
+ }, {
+ glyph: 'xf00d@FontAwesome',
+ tooltip: Strings.sharedCancel,
+ tooltipType: 'title',
+ minWidth: 0,
+ handler: 'closeView'
+ }]
+});
diff --git a/legacy/web/app/view/dialog/BaseEditController.js b/legacy/web/app/view/dialog/BaseEditController.js
new file mode 100644
index 00000000..91379e2d
--- /dev/null
+++ b/legacy/web/app/view/dialog/BaseEditController.js
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.BaseEditController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.baseEdit',
+
+ requires: [
+ 'Traccar.view.BaseWindow',
+ 'Traccar.view.edit.Attributes'
+ ],
+
+ onSaveClick: function (button) {
+ var dialog, store, record;
+ dialog = button.up('window').down('form');
+ dialog.updateRecord();
+ record = dialog.getRecord();
+ store = record.store;
+ if (store) {
+ if (record.phantom) {
+ store.add(record);
+ }
+ store.sync({
+ failure: function (batch) {
+ store.rejectChanges();
+ Traccar.app.showError(batch.exceptions[0].getError().response);
+ }
+ });
+ } else {
+ record.save();
+ }
+ this.closeView();
+ },
+
+ showAttributesView: function (button) {
+ var dialog, record;
+ dialog = button.up('window').down('form');
+ record = dialog.getRecord();
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedAttributes,
+ items: {
+ xtype: 'attributesView',
+ record: record
+ }
+ }).show();
+ }
+});
diff --git a/legacy/web/app/view/dialog/Calendar.js b/legacy/web/app/view/dialog/Calendar.js
new file mode 100644
index 00000000..5f00a8be
--- /dev/null
+++ b/legacy/web/app/view/dialog/Calendar.js
@@ -0,0 +1,63 @@
+/*
+ * 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.dialog.Calendar', {
+ extend: 'Traccar.view.dialog.BaseEdit',
+
+ requires: [
+ 'Traccar.view.dialog.CalendarController',
+ 'Traccar.view.UnescapedTextField'
+ ],
+
+ controller: 'calendar',
+ title: Strings.sharedCalendar,
+
+ items: {
+ xtype: 'form',
+ items: [{
+ xtype: 'fieldset',
+ title: Strings.sharedRequired,
+ items: [{
+ xtype: 'unescapedTextField',
+ name: 'name',
+ fieldLabel: Strings.sharedName,
+ allowBlank: false
+ }, {
+ xtype: 'filefield',
+ name: 'file',
+ fieldLabel: Strings.sharedFile,
+ allowBlank: false,
+ buttonConfig: {
+ glyph: 'xf093@FontAwesome',
+ text: '',
+ tooltip: Strings.sharedSelectFile,
+ tooltipType: 'title',
+ minWidth: 0
+ },
+ listeners: {
+ change: 'onFileChange'
+ }
+ }]
+ }, {
+ xtype: 'hiddenfield',
+ name: 'data',
+ allowBlank: false,
+ reference: 'dataField'
+ }]
+ }
+});
diff --git a/legacy/web/app/view/dialog/CalendarController.js b/legacy/web/app/view/dialog/CalendarController.js
new file mode 100644
index 00000000..fb8cbff6
--- /dev/null
+++ b/legacy/web/app/view/dialog/CalendarController.js
@@ -0,0 +1,37 @@
+/*
+ * 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.dialog.CalendarController', {
+ extend: 'Traccar.view.dialog.BaseEditController',
+ alias: 'controller.calendar',
+
+ onFileChange: function (fileField) {
+ var reader;
+ if (fileField.fileInputEl.dom.files.length > 0) {
+ reader = new FileReader();
+ reader.onload = function (event) {
+ fileField.up('window').lookupReference('dataField').setValue(
+ event.target.result.substr(event.target.result.indexOf(',') + 1));
+ };
+ reader.onerror = function (event) {
+ Traccar.app.showError(event.target.error);
+ };
+ reader.readAsDataURL(fileField.fileInputEl.dom.files[0]);
+ }
+ }
+});
diff --git a/legacy/web/app/view/dialog/ComputedAttribute.js b/legacy/web/app/view/dialog/ComputedAttribute.js
new file mode 100644
index 00000000..adae7f7b
--- /dev/null
+++ b/legacy/web/app/view/dialog/ComputedAttribute.js
@@ -0,0 +1,84 @@
+/*
+ * 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',
+
+ requires: [
+ 'Traccar.view.dialog.ComputedAttributeController',
+ 'Traccar.view.UnescapedTextField',
+ 'Traccar.view.UnescapedTextAreaField'
+ ],
+
+ controller: 'computedAttribute',
+ title: Strings.sharedComputedAttribute,
+
+ items: {
+ xtype: 'form',
+ items: [{
+ xtype: 'unescapedTextField',
+ name: 'description',
+ fieldLabel: Strings.sharedDescription
+ }, {
+ xtype: 'combobox',
+ name: 'attribute',
+ fieldLabel: Strings.sharedAttribute,
+ store: 'PositionAttributes',
+ displayField: 'name',
+ valueField: 'key',
+ listeners: {
+ change: 'onAttributeChange'
+ }
+ }, {
+ xtype: 'unescapedTextAreaField',
+ reference: 'expressionField',
+ name: 'expression',
+ fieldLabel: Strings.sharedExpression,
+ allowBlank: false
+ }, {
+ xtype: 'combobox',
+ name: 'type',
+ reference: 'typeComboField',
+ store: 'AttributeValueTypes',
+ fieldLabel: Strings.sharedType,
+ displayField: 'name',
+ valueField: 'id',
+ editable: false
+ }]
+ },
+
+ buttons: [{
+ glyph: 'xf128@FontAwesome',
+ tooltip: Strings.sharedCheckComputedAttribute,
+ tooltipType: 'title',
+ minWidth: 0,
+ handler: 'onCheckClick'
+ }, {
+ 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/legacy/web/app/view/dialog/ComputedAttributeController.js b/legacy/web/app/view/dialog/ComputedAttributeController.js
new file mode 100644
index 00000000..f680b1b5
--- /dev/null
+++ b/legacy/web/app/view/dialog/ComputedAttributeController.js
@@ -0,0 +1,45 @@
+/*
+ * 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.ComputedAttributeController', {
+ extend: 'Traccar.view.dialog.BaseEditController',
+ alias: 'controller.computedAttribute',
+
+ requires: [
+ 'Traccar.view.dialog.SelectDevice'
+ ],
+
+ onAttributeChange: function (combobox, newValue) {
+ var attribute = Ext.getStore('PositionAttributes').getById(newValue);
+ if (attribute) {
+ this.getView().lookupReference('typeComboField').setValue(attribute.get('valueType'));
+ this.getView().lookupReference('typeComboField').setReadOnly(true);
+ } else {
+ this.getView().lookupReference('typeComboField').setReadOnly(false);
+ }
+ },
+
+ onCheckClick: function (button) {
+ var dialog, form;
+ dialog = Ext.create('Traccar.view.dialog.SelectDevice');
+ form = button.up('window').down('form');
+ form.updateRecord();
+ dialog.record = form.getRecord();
+ dialog.show();
+ }
+});
diff --git a/legacy/web/app/view/dialog/Device.js b/legacy/web/app/view/dialog/Device.js
new file mode 100644
index 00000000..60a8f716
--- /dev/null
+++ b/legacy/web/app/view/dialog/Device.js
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.Device', {
+ extend: 'Traccar.view.dialog.BaseEdit',
+
+ requires: [
+ 'Traccar.view.ClearableComboBox',
+ 'Traccar.view.dialog.DeviceController',
+ 'Traccar.view.UnescapedTextField'
+ ],
+
+ controller: 'device',
+ title: Strings.sharedDevice,
+
+ items: {
+ xtype: 'form',
+ items: [{
+ xtype: 'fieldset',
+ title: Strings.sharedRequired,
+ items: [{
+ xtype: 'unescapedTextField',
+ name: 'name',
+ fieldLabel: Strings.sharedName,
+ allowBlank: false
+ }, {
+ xtype: 'unescapedTextField',
+ name: 'uniqueId',
+ fieldLabel: Strings.deviceIdentifier,
+ allowBlank: false
+ }]
+ }, {
+ xtype: 'fieldset',
+ title: Strings.sharedExtra,
+ collapsible: true,
+ collapsed: true,
+ items: [{
+ xtype: 'clearableComboBox',
+ name: 'groupId',
+ fieldLabel: Strings.groupParent,
+ store: 'Groups',
+ queryMode: 'local',
+ displayField: 'name',
+ valueField: 'id'
+ }, {
+ xtype: 'unescapedTextField',
+ name: 'phone',
+ fieldLabel: Strings.sharedPhone
+ }, {
+ xtype: 'unescapedTextField',
+ name: 'model',
+ fieldLabel: Strings.deviceModel
+ }, {
+ xtype: 'unescapedTextField',
+ name: 'contact',
+ fieldLabel: Strings.deviceContact
+ }, {
+ xtype: 'combobox',
+ name: 'category',
+ fieldLabel: Strings.deviceCategory,
+ store: 'DeviceImages',
+ queryMode: 'local',
+ displayField: 'name',
+ valueField: 'key',
+ editable: false,
+ listConfig: {
+ getInnerTpl: function () {
+ return '<table><tr valign="middle" ><td><div align="center" style="width:40px;height:40px;" >' +
+ '{[new XMLSerializer().serializeToString(Traccar.DeviceImages.getImageSvg(' +
+ 'Traccar.Style.mapColorOnline, false, 0, values.key))]}</div></td>' +
+ '<td>{name}</td></tr></table>';
+ }
+ }
+ }, {
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'disabled',
+ fieldLabel: Strings.sharedDisabled,
+ hidden: true,
+ reference: 'disabledField'
+ }]
+ }]
+ }
+});
diff --git a/legacy/web/app/view/dialog/DeviceAccumulators.js b/legacy/web/app/view/dialog/DeviceAccumulators.js
new file mode 100644
index 00000000..eaa4e9f5
--- /dev/null
+++ b/legacy/web/app/view/dialog/DeviceAccumulators.js
@@ -0,0 +1,55 @@
+/*
+ * 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.dialog.DeviceAccumulators', {
+ extend: 'Traccar.view.dialog.Base',
+
+ requires: [
+ 'Traccar.view.dialog.DeviceAccumulatorsController'
+ ],
+
+ controller: 'deviceAccumulators',
+ title: Strings.sharedDeviceAccumulators,
+
+ items: [{
+ xtype: 'customNumberField',
+ dataType: 'distance',
+ reference: 'totalDistance',
+ fieldLabel: Strings.deviceTotalDistance
+ }, {
+ xtype: 'customNumberField',
+ dataType: 'hours',
+ reference: 'hours',
+ fieldLabel: Strings.positionHours
+ }],
+
+ buttons: [{
+ reference: 'setButton',
+ glyph: 'xf00c@FontAwesome',
+ tooltip: Strings.sharedSet,
+ tooltipType: 'title',
+ minWidth: 0,
+ handler: 'onSetClick'
+ }, {
+ glyph: 'xf00d@FontAwesome',
+ tooltip: Strings.sharedCancel,
+ tooltipType: 'title',
+ minWidth: 0,
+ handler: 'closeView'
+ }]
+});
diff --git a/legacy/web/app/view/dialog/DeviceAccumulatorsController.js b/legacy/web/app/view/dialog/DeviceAccumulatorsController.js
new file mode 100644
index 00000000..2fdae6c5
--- /dev/null
+++ b/legacy/web/app/view/dialog/DeviceAccumulatorsController.js
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2018 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.DeviceAccumulatorsController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.deviceAccumulators',
+
+ onSetClick: function () {
+ var totalDistance, hours, data = {
+ deviceId: this.getView().deviceId
+ };
+ totalDistance = this.lookupReference('totalDistance');
+ if (!isNaN(totalDistance.getRawValue())) {
+ data.totalDistance = totalDistance.getValue();
+ }
+ hours = this.lookupReference('hours');
+ if (!isNaN(hours.getRawValue())) {
+ data.hours = hours.getValue();
+ }
+ Ext.Ajax.request({
+ scope: this,
+ method: 'PUT',
+ url: 'api/devices/' + data.deviceId + '/accumulators',
+ jsonData: Ext.util.JSON.encode(data),
+ callback: function (options, success, response) {
+ if (!success) {
+ Traccar.app.showError(response);
+ }
+ }
+ });
+ this.closeView();
+ }
+});
diff --git a/legacy/web/app/view/dialog/DeviceController.js b/legacy/web/app/view/dialog/DeviceController.js
new file mode 100644
index 00000000..d7a4493b
--- /dev/null
+++ b/legacy/web/app/view/dialog/DeviceController.js
@@ -0,0 +1,29 @@
+/*
+ * 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.DeviceController', {
+ extend: 'Traccar.view.dialog.BaseEditController',
+ alias: 'controller.device',
+
+ init: function () {
+ if (Traccar.app.getUser().get('administrator')) {
+ this.lookupReference('disabledField').setHidden(false);
+ }
+ }
+
+});
diff --git a/legacy/web/app/view/dialog/Driver.js b/legacy/web/app/view/dialog/Driver.js
new file mode 100644
index 00000000..9b1c17b5
--- /dev/null
+++ b/legacy/web/app/view/dialog/Driver.js
@@ -0,0 +1,46 @@
+/*
+ * 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.Driver', {
+ extend: 'Traccar.view.dialog.BaseEdit',
+
+ requires: [
+ 'Traccar.view.UnescapedTextField'
+ ],
+
+ title: Strings.sharedDriver,
+
+ items: {
+ xtype: 'form',
+ items: [{
+ xtype: 'fieldset',
+ title: Strings.sharedRequired,
+ items: [{
+ xtype: 'unescapedTextField',
+ name: 'name',
+ fieldLabel: Strings.sharedName,
+ allowBlank: false
+ }, {
+ xtype: 'unescapedTextField',
+ name: 'uniqueId',
+ fieldLabel: Strings.deviceIdentifier,
+ allowBlank: false
+ }]
+ }]
+ }
+});
diff --git a/legacy/web/app/view/dialog/Geofence.js b/legacy/web/app/view/dialog/Geofence.js
new file mode 100644
index 00000000..1e22cd7b
--- /dev/null
+++ b/legacy/web/app/view/dialog/Geofence.js
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@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.Geofence', {
+ extend: 'Traccar.view.dialog.BaseEdit',
+
+ requires: [
+ 'Traccar.view.ClearableComboBox',
+ 'Traccar.view.dialog.GeofenceController',
+ 'Traccar.view.UnescapedTextField'
+ ],
+
+ controller: 'geofence',
+ title: Strings.sharedGeofence,
+
+ items: {
+ xtype: 'form',
+ items: [{
+ xtype: 'fieldset',
+ title: Strings.sharedRequired,
+ items: [{
+ xtype: 'unescapedTextField',
+ name: 'name',
+ fieldLabel: Strings.sharedName
+ }]
+ }, {
+ xtype: 'fieldset',
+ title: Strings.sharedExtra,
+ collapsible: true,
+ collapsed: true,
+ items: [{
+ xtype: 'unescapedTextField',
+ name: 'description',
+ fieldLabel: Strings.sharedDescription
+ }, {
+ xtype: 'clearableComboBox',
+ reference: 'calendarCombo',
+ name: 'calendarId',
+ store: 'Calendars',
+ queryMode: 'local',
+ displayField: 'name',
+ valueField: 'id',
+ fieldLabel: Strings.sharedCalendar
+ }, {
+ xtype: 'hiddenfield',
+ name: 'area',
+ allowBlank: false,
+ reference: 'areaField'
+ }]
+ }]
+ },
+
+ buttons: [{
+ text: Strings.sharedArea,
+ glyph: 'xf21d@FontAwesome',
+ handler: 'onAreaClick'
+ }, {
+ text: Strings.sharedAttributes,
+ handler: 'showAttributesView'
+ }, {
+ xtype: 'tbfill'
+ }, {
+ 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/legacy/web/app/view/dialog/GeofenceController.js b/legacy/web/app/view/dialog/GeofenceController.js
new file mode 100644
index 00000000..e4ac5a2e
--- /dev/null
+++ b/legacy/web/app/view/dialog/GeofenceController.js
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@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.GeofenceController', {
+ extend: 'Traccar.view.dialog.BaseEditController',
+ alias: 'controller.geofence',
+
+ requires: [
+ 'Traccar.view.BaseWindow',
+ 'Traccar.view.map.GeofenceMap'
+ ],
+
+ config: {
+ listen: {
+ controller: {
+ '*': {
+ savearea: 'saveArea'
+ }
+ }
+ }
+ },
+
+ init: function () {
+ this.lookupReference('calendarCombo').setHidden(
+ Traccar.app.getBooleanAttributePreference('ui.disableCalendars'));
+ },
+
+ saveArea: function (value) {
+ this.lookupReference('areaField').setValue(value);
+ },
+
+ onAreaClick: function (button) {
+ var dialog, record;
+ dialog = button.up('window').down('form');
+ record = dialog.getRecord();
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedArea,
+ items: {
+ xtype: 'geofenceMapView',
+ area: record.get('area')
+ }
+ }).show();
+ }
+});
diff --git a/legacy/web/app/view/dialog/Group.js b/legacy/web/app/view/dialog/Group.js
new file mode 100644
index 00000000..61ca193d
--- /dev/null
+++ b/legacy/web/app/view/dialog/Group.js
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@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.Group', {
+ extend: 'Traccar.view.dialog.BaseEdit',
+
+ requires: [
+ 'Traccar.view.ClearableComboBox',
+ 'Traccar.view.UnescapedTextField'
+ ],
+
+ title: Strings.groupDialog,
+
+ items: {
+ xtype: 'form',
+ items: [{
+ xtype: 'fieldset',
+ title: Strings.sharedRequired,
+ items: [{
+ xtype: 'unescapedTextField',
+ name: 'name',
+ fieldLabel: Strings.sharedName,
+ allowBlank: false
+ }]
+ }, {
+ xtype: 'fieldset',
+ title: Strings.sharedExtra,
+ collapsible: true,
+ collapsed: true,
+ items: [{
+ xtype: 'clearableComboBox',
+ name: 'groupId',
+ fieldLabel: Strings.groupParent,
+ store: 'Groups',
+ queryMode: 'local',
+ displayField: 'name',
+ valueField: 'id'
+ }]
+ }]
+ }
+});
diff --git a/legacy/web/app/view/dialog/Login.js b/legacy/web/app/view/dialog/Login.js
new file mode 100644
index 00000000..592efb33
--- /dev/null
+++ b/legacy/web/app/view/dialog/Login.js
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2015 - 2023 Anton Tananaev (anton@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.Login', {
+ extend: 'Traccar.view.dialog.Base',
+ alias: 'widget.login',
+
+ requires: [
+ 'Traccar.view.dialog.LoginController'
+ ],
+
+ controller: 'login',
+
+ header: false,
+ closable: false,
+
+ items: {
+ xtype: 'form',
+ reference: 'form',
+
+ autoEl: {
+ tag: 'form',
+ method: 'POST',
+ action: 'fake-login.html',
+ target: 'submitTarget'
+ },
+
+ items: [{
+ xtype: 'image',
+ src: 'logo.svg',
+ alt: Strings.loginLogo,
+ width: 240,
+ height: 64,
+ style: {
+ display: 'block',
+ margin: '10px auto 25px'
+ }
+ }, {
+ xtype: 'pickerfield',
+ fieldLabel: Strings.settingsServer,
+ editable: false,
+ value: window.location.host,
+ hidden: !window.appInterface && !(window.webkit && window.webkit.messageHandlers.appInterface),
+ createPicker: function () {
+ var self = this, popup = Ext.create({
+ xtype: 'window',
+ closeAction: 'hide',
+ referenceHolder: true,
+ minWidth: 204,
+ layout: 'form',
+ header: false,
+ resizable: true,
+ items: [{
+ xtype: 'textfield',
+ anchor: '100%',
+ reference: 'serverAddress',
+ value: window.location.href
+ }],
+ fbar: [{
+ text: Strings.sharedSet,
+ handler: function () {
+ var message = 'server|' + popup.lookupReference('serverAddress').getValue();
+ if (window.webkit && window.webkit.messageHandlers.appInterface) {
+ window.webkit.messageHandlers.appInterface.postMessage(message);
+ }
+ if (window.appInterface) {
+ window.appInterface.postMessage(message);
+ }
+ }
+ }, {
+ text: Strings.sharedCancel,
+ handler: function () {
+ self.collapse();
+ }
+ }]
+ });
+ return popup;
+ }
+ }, {
+ xtype: 'combobox',
+ name: 'language',
+ fieldLabel: Strings.loginLanguage,
+ store: 'Languages',
+ displayField: 'name',
+ valueField: 'code',
+ editable: false,
+ submitValue: false,
+ listeners: {
+ select: 'onSelectLanguage'
+ },
+ reference: 'languageField'
+ }, {
+ xtype: 'textfield',
+ name: 'email',
+ reference: 'userField',
+ fieldLabel: Strings.userEmail,
+ allowBlank: false,
+ enableKeyEvents: true,
+ listeners: {
+ specialKey: 'onSpecialKey',
+ afterrender: 'onAfterRender'
+ },
+ inputAttrTpl: ['autocomplete="on" autocapitalize="none"']
+ }, {
+ xtype: 'textfield',
+ name: 'password',
+ reference: 'passwordField',
+ fieldLabel: Strings.userPassword,
+ inputType: 'password',
+ allowBlank: false,
+ enableKeyEvents: true,
+ listeners: {
+ specialKey: 'onSpecialKey'
+ },
+ inputAttrTpl: ['autocomplete="on"']
+ }, {
+ xtype: 'component',
+ html: '<iframe id="submitTarget" name="submitTarget" style="display:none"></iframe>'
+ }, {
+ xtype: 'component',
+ html: '<input type="submit" id="submitButton" style="display:none">'
+ }]
+ },
+
+ buttons: [{
+ text: Strings.loginReset,
+ handler: 'onResetClick',
+ reference: 'resetButton'
+ }, {
+ text: Strings.loginRegister,
+ handler: 'onRegisterClick',
+ reference: 'registerButton'
+ }, {
+ text: Strings.loginLogin,
+ handler: 'onLoginClick'
+ }]
+});
diff --git a/legacy/web/app/view/dialog/LoginController.js b/legacy/web/app/view/dialog/LoginController.js
new file mode 100644
index 00000000..a21866eb
--- /dev/null
+++ b/legacy/web/app/view/dialog/LoginController.js
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2015 - 2023 Anton Tananaev (anton@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.LoginController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.login',
+
+ requires: [
+ 'Traccar.view.dialog.Register'
+ ],
+
+ init: function () {
+ this.lookupReference('resetButton').setHidden(!Traccar.app.getServer().get('emailEnabled'));
+ this.lookupReference('registerButton').setDisabled(!Traccar.app.getServer().get('registration'));
+ this.lookupReference('languageField').setValue(Locale.language);
+ },
+
+ login: function () {
+ var form = this.lookupReference('form');
+ if (form.isValid()) {
+ Ext.get('spinner').setVisible(true);
+ this.getView().setVisible(false);
+ Ext.Ajax.request({
+ scope: this,
+ method: 'POST',
+ url: 'api/session',
+ params: form.getValues(),
+ callback: function (options, success, response) {
+ Ext.get('spinner').setVisible(false);
+ if (success) {
+ Traccar.app.setUser(Ext.decode(response.responseText));
+ this.fireViewEvent('login');
+ } else {
+ this.getView().setVisible(true);
+ if (response.status === 401) {
+ Traccar.app.showError(Strings.loginFailed);
+ } else {
+ Traccar.app.showError(response.responseText);
+ }
+ }
+ }
+ });
+ }
+ },
+
+ logout: function () {
+ Ext.util.Cookies.clear('user');
+ Ext.util.Cookies.clear('password');
+ Ext.Ajax.request({
+ scope: this,
+ method: 'DELETE',
+ url: 'api/session',
+ callback: function () {
+ window.location.reload();
+ }
+ });
+ },
+
+ onSelectLanguage: function (selected) {
+ var paramName, paramValue, url, prefix, suffix;
+ paramName = 'locale';
+ paramValue = selected.getValue();
+ url = window.location.href;
+ if (url.indexOf(paramName + '=') >= 0) {
+ prefix = url.substring(0, url.indexOf(paramName));
+ suffix = url.substring(url.indexOf(paramName));
+ suffix = suffix.substring(suffix.indexOf('=') + 1);
+ suffix = suffix.indexOf('&') >= 0 ? suffix.substring(suffix.indexOf('&')) : '';
+ url = prefix + paramName + '=' + paramValue + suffix;
+ } else if (url.indexOf('?') < 0) {
+ url += '?' + paramName + '=' + paramValue;
+ } else {
+ url += '&' + paramName + '=' + paramValue;
+ }
+ window.location.href = url;
+ },
+
+ onAfterRender: function (field) {
+ field.focus();
+ },
+
+ onSpecialKey: function (field, e) {
+ if (e.getKey() === e.ENTER) {
+ this.login();
+ }
+ },
+
+ onLoginClick: function () {
+ Ext.getElementById('submitButton').click();
+ this.login();
+ },
+
+ onRegisterClick: function () {
+ Ext.create('Traccar.view.dialog.Register').show();
+ },
+
+ onResetClick: function () {
+ Ext.Msg.prompt(Strings.loginReset, Strings.userEmail, function (btn, text) {
+ if (btn === 'ok') {
+ Ext.Ajax.request({
+ scope: this,
+ method: 'POST',
+ url: 'api/password/reset',
+ params: {
+ email: text
+ },
+ callback: function (options, success, response) {
+ if (success) {
+ Traccar.app.showToast(Strings.loginResetSuccess);
+ } else {
+ Traccar.app.showError(response.responseText);
+ }
+ }
+ });
+ }
+ });
+ }
+});
diff --git a/legacy/web/app/view/dialog/Maintenance.js b/legacy/web/app/view/dialog/Maintenance.js
new file mode 100644
index 00000000..d844d259
--- /dev/null
+++ b/legacy/web/app/view/dialog/Maintenance.js
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 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.Maintenance', {
+ extend: 'Traccar.view.dialog.BaseEdit',
+
+ requires: [
+ 'Traccar.view.dialog.MaintenanceController',
+ 'Traccar.view.CustomNumberField',
+ 'Traccar.view.UnescapedTextField'
+ ],
+
+ controller: 'maintenance',
+
+ title: Strings.sharedMaintenance,
+
+ items: {
+ xtype: 'form',
+ listeners: {
+ validitychange: 'onValidityChange'
+ },
+ items: [{
+ xtype: 'fieldset',
+ title: Strings.sharedRequired,
+ items: [{
+ xtype: 'unescapedTextField',
+ name: 'name',
+ fieldLabel: Strings.sharedName,
+ allowBlank: false
+ }, {
+ xtype: 'combobox',
+ name: 'type',
+ reference: 'typeComboField',
+ fieldLabel: Strings.sharedType,
+ displayField: 'name',
+ valueField: 'key',
+ allowBlank: false,
+ queryMode: 'local',
+ store: 'MaintenanceTypes',
+ listeners: {
+ change: 'onNameChange'
+ }
+ }, {
+ xtype: 'customNumberField',
+ name: 'start',
+ reference: 'startField',
+ fieldLabel: Strings.maintenanceStart
+ }, {
+ xtype: 'customNumberField',
+ name: 'period',
+ reference: 'periodField',
+ allowBlank: false,
+ fieldLabel: Strings.maintenancePeriod,
+ validator: function (value) {
+ return this.parseValue(value) !== 0 ? true : Strings.errorZero;
+ }
+ }]
+ }]
+ }
+});
diff --git a/legacy/web/app/view/dialog/MaintenanceController.js b/legacy/web/app/view/dialog/MaintenanceController.js
new file mode 100644
index 00000000..d5a27b54
--- /dev/null
+++ b/legacy/web/app/view/dialog/MaintenanceController.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 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.MaintenanceController', {
+ extend: 'Traccar.view.dialog.BaseEditController',
+ alias: 'controller.maintenance',
+
+ init: function () {
+ this.startConfig = Ext.clone(this.lookupReference('startField').initialConfig);
+ this.startConfig.value = 0;
+ this.periodConfig = Ext.clone(this.lookupReference('periodField').initialConfig);
+ this.periodConfig.value = 0;
+ this.lookupReference('saveButton').setDisabled(true);
+ },
+
+ onValidityChange: function (form, valid) {
+ this.lookupReference('saveButton').setDisabled(!valid);
+ },
+
+ updateFieldConfig: function (fieldReference, initialConfig, newConfig) {
+ var field = this.lookupReference(fieldReference);
+ if (field.dataType !== newConfig.dataType) {
+ this.getView().down('fieldset').insert(this.getView().down('fieldset').items.indexOf(field),
+ Ext.merge({}, initialConfig, newConfig));
+ this.getView().down('fieldset').remove(field);
+ this.lookupReference(fieldReference).validate();
+ } else {
+ field.setConfig(newConfig);
+ field.validate();
+ }
+ },
+
+ onNameChange: function (combobox, newValue) {
+ var attribute, config = {};
+ attribute = combobox.getStore().getById(newValue);
+ if (attribute) {
+ if (attribute.get('allowDecimals') !== undefined) {
+ config.allowDecimals = attribute.get('allowDecimals');
+ } else {
+ config.allowDecimals = true;
+ }
+ config.dataType = attribute.get('dataType');
+ config.maxValue = attribute.get('maxValue');
+ config.minValue = attribute.get('minValue');
+ }
+
+ this.updateFieldConfig('startField', this.startConfig, config);
+ this.updateFieldConfig('periodField', this.periodConfig, config);
+ }
+});
diff --git a/legacy/web/app/view/dialog/MapPickerController.js b/legacy/web/app/view/dialog/MapPickerController.js
new file mode 100644
index 00000000..8641e377
--- /dev/null
+++ b/legacy/web/app/view/dialog/MapPickerController.js
@@ -0,0 +1,42 @@
+/*
+ * 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.dialog.MapPickerController', {
+ extend: 'Traccar.view.dialog.BaseEditController',
+ alias: 'controller.mapPicker',
+
+ config: {
+ listen: {
+ controller: {
+ '*': {
+ mapstate: 'setMapState'
+ }
+ }
+ }
+ },
+
+ getMapState: function () {
+ this.fireEvent('mapstaterequest');
+ },
+
+ setMapState: function (lat, lon, zoom) {
+ this.lookupReference('latitude').setValue(lat);
+ this.lookupReference('longitude').setValue(lon);
+ this.lookupReference('zoom').setValue(zoom);
+ }
+});
diff --git a/legacy/web/app/view/dialog/Notification.js b/legacy/web/app/view/dialog/Notification.js
new file mode 100644
index 00000000..51af5b8e
--- /dev/null
+++ b/legacy/web/app/view/dialog/Notification.js
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 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.Notification', {
+ extend: 'Traccar.view.dialog.BaseEdit',
+
+ requires: [
+ 'Traccar.view.ClearableComboBox',
+ 'Traccar.view.dialog.NotificationController'
+ ],
+
+ controller: 'notification',
+ title: Strings.sharedNotification,
+
+ items: {
+ xtype: 'form',
+ items: [{
+ xtype: 'fieldset',
+ title: Strings.sharedRequired,
+ items: [{
+ xtype: 'combobox',
+ name: 'type',
+ fieldLabel: Strings.sharedType,
+ store: 'AllNotificationTypes',
+ queryMode: 'local',
+ displayField: 'name',
+ valueField: 'type',
+ editable: false,
+ allowBlank: false,
+ listeners: {
+ change: 'onTypeChange'
+ }
+ }, {
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'always',
+ fieldLabel: Strings.notificationAlways
+ }, {
+ xtype: 'tagfield',
+ reference: 'alarmsField',
+ fieldLabel: Strings.sharedAlarms,
+ maxWidth: Traccar.Style.formFieldWidth,
+ store: 'AlarmTypes',
+ valueField: 'key',
+ displayField: 'name',
+ queryMode: 'local',
+ hidden: true,
+ listeners: {
+ beforerender: 'onAlarmsLoad',
+ change: 'onAlarmsChange'
+ }
+ }, {
+ xtype: 'tagfield',
+ fieldLabel: Strings.notificationNotificators,
+ name: 'notificators',
+ maxWidth: Traccar.Style.formFieldWidth,
+ store: 'AllNotificators',
+ valueField: 'type',
+ displayField: 'name',
+ queryMode: 'local'
+ }]
+ }, {
+ xtype: 'fieldset',
+ title: Strings.sharedExtra,
+ collapsible: true,
+ collapsed: true,
+ items: [{
+ xtype: 'clearableComboBox',
+ reference: 'calendarCombo',
+ name: 'calendarId',
+ store: 'Calendars',
+ queryMode: 'local',
+ displayField: 'name',
+ valueField: 'id',
+ fieldLabel: Strings.sharedCalendar
+ }]
+ }]
+ }
+});
diff --git a/legacy/web/app/view/dialog/NotificationController.js b/legacy/web/app/view/dialog/NotificationController.js
new file mode 100644
index 00000000..5da669a4
--- /dev/null
+++ b/legacy/web/app/view/dialog/NotificationController.js
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 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.NotificationController', {
+ extend: 'Traccar.view.dialog.BaseEditController',
+ alias: 'controller.notification',
+
+ init: function () {
+ this.lookupReference('calendarCombo').setHidden(
+ Traccar.app.getBooleanAttributePreference('ui.disableCalendars'));
+ },
+
+ onTypeChange: function (view, value) {
+ this.lookupReference('alarmsField').setHidden(value !== 'alarm');
+ },
+
+ onAlarmsLoad: function (view) {
+ var attributes, record = view.up('form').getRecord();
+ attributes = record.get('attributes') || {};
+ if (attributes['alarms']) {
+ view.suspendEvents(false);
+ view.setValue(attributes['alarms'].split(','));
+ view.resumeEvents();
+ }
+ },
+
+ onAlarmsChange: function (view, value) {
+ var attributes, record = view.up('window').down('form').getRecord();
+ attributes = record.get('attributes') || {};
+
+ value = value.join();
+ if (attributes['alarms'] !== value) {
+ attributes['alarms'] = value;
+ record.set('attributes', attributes);
+ record.dirty = true;
+ }
+ }
+});
diff --git a/legacy/web/app/view/dialog/Register.js b/legacy/web/app/view/dialog/Register.js
new file mode 100644
index 00000000..f9608cef
--- /dev/null
+++ b/legacy/web/app/view/dialog/Register.js
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.Register', {
+ extend: 'Traccar.view.dialog.Base',
+
+ requires: [
+ 'Traccar.view.dialog.RegisterController'
+ ],
+
+ controller: 'register',
+
+ title: Strings.loginRegister,
+
+ items: {
+ xtype: 'form',
+ reference: 'form',
+ jsonSubmit: true,
+
+ items: [{
+ xtype: 'textfield',
+ name: 'name',
+ fieldLabel: Strings.sharedName,
+ allowBlank: false
+ }, {
+ xtype: 'textfield',
+ name: 'email',
+ fieldLabel: Strings.userEmail,
+ validator: function (val) {
+ if (/(.+)@(.+)\.(.{2,})/.test(val)) {
+ return true;
+ } else {
+ return Ext.form.field.VTypes.emailText;
+ }
+ },
+ allowBlank: false
+ }, {
+ xtype: 'textfield',
+ name: 'password',
+ fieldLabel: Strings.userPassword,
+ inputType: 'password',
+ allowBlank: false
+ }]
+ },
+
+ buttons: [{
+ text: Strings.sharedSave,
+ handler: 'onCreateClick'
+ }, {
+ text: Strings.sharedCancel,
+ handler: 'closeView'
+ }]
+});
diff --git a/legacy/web/app/view/dialog/RegisterController.js b/legacy/web/app/view/dialog/RegisterController.js
new file mode 100644
index 00000000..c102581e
--- /dev/null
+++ b/legacy/web/app/view/dialog/RegisterController.js
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.RegisterController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.register',
+
+ onCreateClick: function () {
+ var form = this.lookupReference('form');
+ if (form.isValid()) {
+ Ext.Ajax.request({
+ scope: this,
+ method: 'POST',
+ url: 'api/users',
+ jsonData: form.getValues(),
+ callback: this.onCreateReturn
+ });
+ }
+ },
+
+ onCreateReturn: function (options, success, response) {
+ if (success) {
+ this.closeView();
+ Traccar.app.showToast(Strings.loginCreated);
+ } else {
+ Traccar.app.showError(response);
+ }
+ }
+
+});
diff --git a/legacy/web/app/view/dialog/ReportConfig.js b/legacy/web/app/view/dialog/ReportConfig.js
new file mode 100644
index 00000000..35cc95b4
--- /dev/null
+++ b/legacy/web/app/view/dialog/ReportConfig.js
@@ -0,0 +1,136 @@
+/*
+ * 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.dialog.ReportConfig', {
+ extend: 'Traccar.view.dialog.Base',
+
+ requires: [
+ 'Traccar.view.dialog.ReportConfigController',
+ 'Traccar.view.CustomTimeField'
+ ],
+
+ controller: 'reportConfig',
+ title: Strings.reportConfigure,
+
+ items: [{
+ fieldLabel: Strings.reportDevice,
+ xtype: 'tagfield',
+ reference: 'deviceField',
+ maxWidth: Traccar.Style.formFieldWidth,
+ store: 'Devices',
+ valueField: 'id',
+ displayField: 'name',
+ queryMode: 'local'
+ }, {
+ fieldLabel: Strings.reportGroup,
+ xtype: 'tagfield',
+ reference: 'groupField',
+ maxWidth: Traccar.Style.formFieldWidth,
+ store: 'Groups',
+ valueField: 'id',
+ displayField: 'name',
+ queryMode: 'local'
+ }, {
+ fieldLabel: Strings.reportEventTypes,
+ xtype: 'tagfield',
+ reference: 'eventTypeField',
+ maxWidth: Traccar.Style.formFieldWidth,
+ store: 'ReportEventTypes',
+ hidden: true,
+ valueField: 'type',
+ displayField: 'name',
+ queryMode: 'local'
+ }, {
+ fieldLabel: Strings.reportChartType,
+ xtype: 'combobox',
+ reference: 'chartTypeField',
+ store: 'ReportChartTypes',
+ hidden: true,
+ value: 'speed',
+ valueField: 'key',
+ displayField: 'name',
+ queryMode: 'local'
+ }, {
+ fieldLabel: Strings.reportShowMarkers,
+ xtype: 'checkbox',
+ reference: 'showMarkersField',
+ inputValue: true,
+ uncheckedValue: false,
+ value: false
+ }, {
+ fieldLabel: Strings.reportPeriod,
+ reference: 'periodField',
+ xtype: 'combobox',
+ store: 'ReportPeriods',
+ editable: false,
+ valueField: 'key',
+ displayField: 'name',
+ queryMode: 'local',
+ listeners: {
+ change: 'onPeriodChange'
+ }
+ }, {
+ xtype: 'fieldcontainer',
+ layout: 'vbox',
+ reference: 'fromContainer',
+ hidden: true,
+ fieldLabel: Strings.reportFrom,
+ items: [{
+ xtype: 'datefield',
+ reference: 'fromDateField',
+ startDay: Traccar.Style.weekStartDay,
+ format: Traccar.Style.dateFormat,
+ value: new Date(new Date().getTime() - 30 * 60 * 1000)
+ }, {
+ xtype: 'customTimeField',
+ reference: 'fromTimeField',
+ value: new Date(new Date().getTime() - 30 * 60 * 1000)
+ }]
+ }, {
+ xtype: 'fieldcontainer',
+ layout: 'vbox',
+ reference: 'toContainer',
+ hidden: true,
+ fieldLabel: Strings.reportTo,
+ items: [{
+ xtype: 'datefield',
+ reference: 'toDateField',
+ startDay: Traccar.Style.weekStartDay,
+ format: Traccar.Style.dateFormat,
+ value: new Date()
+ }, {
+ xtype: 'customTimeField',
+ reference: 'toTimeField',
+ value: new Date()
+ }]
+ }],
+
+ 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/legacy/web/app/view/dialog/ReportConfigController.js b/legacy/web/app/view/dialog/ReportConfigController.js
new file mode 100644
index 00000000..6d029428
--- /dev/null
+++ b/legacy/web/app/view/dialog/ReportConfigController.js
@@ -0,0 +1,99 @@
+/*
+ * 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.dialog.ReportConfigController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.reportConfig',
+
+ requires: [
+ 'Traccar.store.ReportEventTypes',
+ 'Traccar.store.AllNotifications'
+ ],
+
+ onSaveClick: function (button) {
+ var eventType, callingPanel;
+ callingPanel = this.getView().callingPanel;
+
+ callingPanel.deviceId = this.lookupReference('deviceField').getValue();
+ callingPanel.groupId = this.lookupReference('groupField').getValue();
+ eventType = this.lookupReference('eventTypeField').getValue();
+ if (eventType.indexOf(Traccar.store.ReportEventTypes.allEvents) > -1) {
+ eventType = [Traccar.store.ReportEventTypes.allEvents];
+ } else if (eventType.length === this.lookupReference('eventTypeField').getStore().getCount() - 1) {
+ eventType = [Traccar.store.ReportEventTypes.allEvents];
+ }
+ callingPanel.eventType = eventType;
+ callingPanel.chartType = this.lookupReference('chartTypeField').getValue();
+ callingPanel.showMarkers = this.lookupReference('showMarkersField').getValue();
+ callingPanel.fromDate = this.lookupReference('fromDateField').getValue();
+ callingPanel.fromTime = this.lookupReference('fromTimeField').getValue();
+ callingPanel.toDate = this.lookupReference('toDateField').getValue();
+ callingPanel.toTime = this.lookupReference('toTimeField').getValue();
+ callingPanel.period = this.lookupReference('periodField').getValue();
+ callingPanel.updateButtons();
+ button.up('window').close();
+ },
+
+ onPeriodChange: function (combobox, newValue) {
+ var day, first, from, to, custom = newValue === 'custom';
+ this.lookupReference('fromContainer').setHidden(!custom);
+ this.lookupReference('toContainer').setHidden(!custom);
+ if (!custom) {
+ from = new Date();
+ to = new Date();
+ switch (newValue) {
+ case 'today':
+ to.setDate(to.getDate() + 1);
+ break;
+ case 'yesterday':
+ from.setDate(to.getDate() - 1);
+ break;
+ case 'thisWeek':
+ day = from.getDay();
+ first = from.getDate() - day + (day === 0 ? -6 : 1);
+ from.setDate(first);
+ to.setDate(first + 7);
+ break;
+ case 'previousWeek':
+ day = from.getDay();
+ first = from.getDate() - day + (day === 0 ? -6 : 1);
+ from.setDate(first - 7);
+ to.setDate(first);
+ break;
+ case 'thisMonth':
+ from.setDate(1);
+ to.setDate(1);
+ to.setMonth(from.getMonth() + 1);
+ break;
+ case 'previousMonth':
+ from.setDate(1);
+ from.setMonth(from.getMonth() - 1);
+ to.setDate(1);
+ break;
+ default:
+ break;
+ }
+ from.setHours(0, 0, 0, 0);
+ to.setHours(0, 0, 0, 0);
+ this.lookupReference('fromDateField').setValue(from);
+ this.lookupReference('fromTimeField').setValue(from);
+ this.lookupReference('toDateField').setValue(to);
+ this.lookupReference('toTimeField').setValue(to);
+ }
+ }
+});
diff --git a/legacy/web/app/view/dialog/SavedCommand.js b/legacy/web/app/view/dialog/SavedCommand.js
new file mode 100644
index 00000000..b1aeae73
--- /dev/null
+++ b/legacy/web/app/view/dialog/SavedCommand.js
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.SavedCommand', {
+ extend: 'Traccar.view.dialog.BaseEdit',
+
+ requires: [
+ 'Traccar.view.dialog.SavedCommandController',
+ 'Traccar.view.UnescapedTextField'
+ ],
+
+ controller: 'savedCommand',
+ title: Strings.sharedSavedCommand,
+
+ items: [{
+ xtype: 'form',
+ listeners: {
+ validitychange: 'onValidityChange'
+ },
+ items: [{
+ xtype: 'fieldset',
+ title: Strings.sharedRequired,
+ items: [{
+ xtype: 'unescapedTextField',
+ name: 'description',
+ fieldLabel: Strings.sharedDescription
+ }, {
+ xtype: 'checkboxfield',
+ name: 'textChannel',
+ inputValue: true,
+ uncheckedValue: false,
+ fieldLabel: Strings.commandSendSms
+ }, {
+ xtype: 'combobox',
+ name: 'type',
+ reference: 'commandType',
+ fieldLabel: Strings.sharedType,
+ store: 'AllCommandTypes',
+ queryMode: 'local',
+ displayField: 'name',
+ valueField: 'type',
+ editable: false,
+ allowBlank: false,
+ listeners: {
+ change: 'onTypeChange'
+ }
+ }, {
+ xtype: 'fieldcontainer',
+ reference: 'parameters'
+ }]
+ }]
+ }],
+
+ buttons: [{
+ glyph: 'xf00c@FontAwesome',
+ reference: 'saveButton',
+ tooltip: Strings.sharedSave,
+ tooltipType: 'title',
+ minWidth: 0,
+ disabled: true,
+ handler: 'onSaveClick'
+ }, {
+ glyph: 'xf00d@FontAwesome',
+ tooltip: Strings.sharedCancel,
+ tooltipType: 'title',
+ minWidth: 0,
+ handler: 'closeView'
+ }]
+});
diff --git a/legacy/web/app/view/dialog/SavedCommandController.js b/legacy/web/app/view/dialog/SavedCommandController.js
new file mode 100644
index 00000000..37c56603
--- /dev/null
+++ b/legacy/web/app/view/dialog/SavedCommandController.js
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.SavedCommandController', {
+ extend: 'Traccar.view.dialog.BaseEditController',
+ alias: 'controller.savedCommand',
+
+ defaultFieldConfig: {
+ allowBlank: false
+ },
+
+ onTypeChange: function (combo, newValue) {
+ var i, config, command, parameters, parameter, record;
+ record = combo.up('window').down('form').getRecord();
+ this.lookupReference('parameters').removeAll();
+ command = Ext.getStore('KnownCommands').getById(newValue);
+ if (command && command.get('parameters')) {
+ parameters = command.get('parameters');
+ for (i = 0; i < parameters.length; i++) {
+ parameter = new Traccar.model.KnownAttribute(parameters[i]);
+ config = Ext.clone(this.defaultFieldConfig);
+ config.key = parameter.get('key');
+ config.fieldLabel = parameter.get('name');
+ if (record.get('attributes')) {
+ config.value = record.get('attributes')[parameter.get('key')];
+ }
+ config.disabled = combo.isDisabled();
+ switch (parameter.get('valueType')) {
+ case 'number':
+ config.xtype = 'customNumberField';
+ if (parameter.get('allowDecimals') !== undefined) {
+ config.allowDecimals = parameter.get('allowDecimals');
+ } else {
+ config.allowDecimals = true;
+ }
+ config.dataType = parameter.get('dataType');
+ config.maxValue = parameter.get('maxValue');
+ config.minValue = parameter.get('minValue');
+ break;
+ case 'boolean':
+ config.xtype = 'checkboxfield';
+ config.inputValue = true;
+ config.uncheckedValue = false;
+ break;
+ default:
+ if (parameter.get('dataType') === 'timezone') {
+ config.xtype = 'combobox';
+ config.queryMode = 'local';
+ config.displayField = 'key';
+ config.editable = false;
+ config.store = 'AllTimezones';
+ } else {
+ config.xtype = 'textfield';
+ }
+ }
+ this.lookupReference('parameters').add(config);
+ }
+ }
+ },
+
+ fillAttributes: function (button) {
+ var i, form, record, parameters, attributes = {};
+
+ form = button.up('window').down('form');
+ form.updateRecord();
+ record = form.getRecord();
+ parameters = this.lookupReference('parameters').items.items;
+
+ for (i = 0; i < parameters.length; i++) {
+ attributes[parameters[i].key] = parameters[i].getValue();
+ }
+
+ record.set('attributes', attributes);
+ },
+
+ onSaveClick: function (button) {
+ this.fillAttributes(button);
+ this.callParent(arguments);
+ },
+
+ onValidityChange: function (form, valid) {
+ this.lookupReference('saveButton').setDisabled(!valid);
+ }
+
+});
diff --git a/legacy/web/app/view/dialog/SelectDevice.js b/legacy/web/app/view/dialog/SelectDevice.js
new file mode 100644
index 00000000..5b11c03f
--- /dev/null
+++ b/legacy/web/app/view/dialog/SelectDevice.js
@@ -0,0 +1,59 @@
+/*
+ * 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.SelectDevice', {
+ extend: 'Traccar.view.dialog.Base',
+
+ requires: [
+ 'Traccar.view.dialog.SelectDeviceController'
+ ],
+
+ controller: 'selectDevice',
+ title: Strings.sharedDevice,
+
+ items: {
+ xtype: 'form',
+ items: [{
+ xtype: 'combobox',
+ reference: 'deviceField',
+ store: 'Devices',
+ queryMode: 'local',
+ displayField: 'name',
+ valueField: 'id',
+ editable: false,
+ listeners: {
+ change: 'onDeviceChange'
+ }
+ }]
+ },
+
+ buttons: [{
+ glyph: 'xf00c@FontAwesome',
+ reference: 'saveButton',
+ tooltip: Strings.sharedSave,
+ tooltipType: 'title',
+ minWidth: 0,
+ handler: 'onSaveClick',
+ disabled: true
+ }, {
+ glyph: 'xf00d@FontAwesome',
+ tooltip: Strings.sharedCancel,
+ tooltipType: 'title',
+ minWidth: 0,
+ handler: 'closeView'
+ }]
+});
diff --git a/legacy/web/app/view/dialog/SelectDeviceController.js b/legacy/web/app/view/dialog/SelectDeviceController.js
new file mode 100644
index 00000000..9437991c
--- /dev/null
+++ b/legacy/web/app/view/dialog/SelectDeviceController.js
@@ -0,0 +1,45 @@
+/*
+ * 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.SelectDeviceController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.selectDevice',
+
+ onSaveClick: function (button) {
+ var deviceId, record;
+ deviceId = this.lookupReference('deviceField').getValue();
+ record = this.getView().record.data;
+ Ext.Ajax.request({
+ url: 'api/attributes/computed/test?deviceId=' + deviceId,
+ method: 'POST',
+ jsonData: Ext.util.JSON.encode(record),
+ callback: function (options, success, response) {
+ if (success) {
+ Ext.Msg.alert(Strings.sharedInfoTitle, response.responseText || response.statusText);
+ } else {
+ Traccar.app.showError(response);
+ }
+ }
+ });
+ button.up('window').close();
+ },
+
+ onDeviceChange: function (combobox, newValue) {
+ this.lookupReference('saveButton').setDisabled(newValue === null);
+ }
+});
diff --git a/legacy/web/app/view/dialog/SendCommand.js b/legacy/web/app/view/dialog/SendCommand.js
new file mode 100644
index 00000000..79954739
--- /dev/null
+++ b/legacy/web/app/view/dialog/SendCommand.js
@@ -0,0 +1,98 @@
+/*
+ * 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.SendCommand', {
+ extend: 'Traccar.view.dialog.Base',
+
+ requires: [
+ 'Traccar.view.dialog.SendCommandController'
+ ],
+
+ controller: 'sendCommand',
+ title: Strings.commandTitle,
+
+ items: [{
+ xtype: 'combobox',
+ reference: 'commandsComboBox',
+ fieldLabel: Strings.deviceCommand,
+ displayField: 'description',
+ valueField: 'id',
+ store: 'DeviceCommands',
+ queryMode: 'local',
+ editable: false,
+ allowBlank: false,
+ listeners: {
+ select: 'onCommandSelect'
+ }
+ }, {
+ xtype: 'form',
+ listeners: {
+ validitychange: 'onValidityChange'
+ },
+ items: [{
+ xtype: 'fieldset',
+ reference: 'newCommandFields',
+ disabled: true,
+ items: [{
+ xtype: 'checkboxfield',
+ name: 'textChannel',
+ reference: 'textChannelCheckBox',
+ inputValue: true,
+ uncheckedValue: false,
+ fieldLabel: Strings.commandSendSms,
+ listeners: {
+ change: 'onTextChannelChange'
+ }
+ }, {
+ xtype: 'combobox',
+ name: 'type',
+ reference: 'commandType',
+ fieldLabel: Strings.sharedType,
+ store: 'CommandTypes',
+ displayField: 'name',
+ valueField: 'type',
+ editable: false,
+ allowBlank: false,
+ listeners: {
+ change: 'onTypeChange'
+ }
+ }, {
+ xtype: 'fieldcontainer',
+ reference: 'parameters'
+ }]
+ }]
+ }],
+
+ buttons: [{
+ xtype: 'tbfill'
+ }, {
+ glyph: 'xf093@FontAwesome',
+ tooltip: Strings.sharedSend,
+ tooltipType: 'title',
+ minWidth: 0,
+ disabled: true,
+ reference: 'sendButton',
+ handler: 'onSendClick'
+ }, {
+ glyph: 'xf00d@FontAwesome',
+ tooltip: Strings.sharedCancel,
+ tooltipType: 'title',
+ minWidth: 0,
+ handler: 'closeView'
+ }]
+});
diff --git a/legacy/web/app/view/dialog/SendCommandController.js b/legacy/web/app/view/dialog/SendCommandController.js
new file mode 100644
index 00000000..c6351587
--- /dev/null
+++ b/legacy/web/app/view/dialog/SendCommandController.js
@@ -0,0 +1,78 @@
+/*
+ * 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.SendCommandController', {
+ extend: 'Traccar.view.dialog.SavedCommandController',
+ alias: 'controller.sendCommand',
+
+ requires: [
+ 'Traccar.view.permissions.SavedCommands'
+ ],
+
+ onSendClick: function (button) {
+ var record;
+ this.fillAttributes(button);
+ record = button.up('window').down('form').getRecord();
+
+ Ext.Ajax.request({
+ scope: this,
+ url: 'api/commands/send',
+ jsonData: record.getData(),
+ callback: this.onSendResult
+ });
+ },
+
+ onValidityChange: function (form, valid) {
+ this.lookupReference('sendButton').setDisabled(!valid ||
+ this.lookupReference('commandsComboBox').getValue() === null);
+ },
+
+ onTextChannelChange: function (checkbox, newValue) {
+ var typesStore = this.lookupReference('commandType').getStore();
+ typesStore.getProxy().setExtraParam('textChannel', newValue);
+ typesStore.reload();
+ },
+
+ onCommandSelect: function (selected) {
+ var record, form, command = selected.getStore().getById(selected.getValue());
+ command.set('deviceId', this.getView().deviceId);
+ form = selected.up('window').down('form');
+ record = form.getRecord();
+ form.loadRecord(command);
+ if (record && command.get('type') === record.get('type')) {
+ this.onTypeChange(this.lookupReference('commandType'), command.get('type'));
+ }
+
+ this.lookupReference('newCommandFields').setDisabled(command.getId() !== 0);
+ this.lookupReference('sendButton').setDisabled(command.getId() === 0);
+ },
+
+ onSendResult: function (options, success, response) {
+ if (success) {
+ this.closeView();
+ Traccar.app.showToast(response.status === 202 ? Strings.commandQueued : Strings.commandSent);
+ } else {
+ Traccar.app.showError(response);
+ }
+ },
+
+ closeView: function () {
+ this.lookupReference('commandsComboBox').getStore().removeAll();
+ this.callParent(arguments);
+ }
+});
diff --git a/legacy/web/app/view/dialog/Server.js b/legacy/web/app/view/dialog/Server.js
new file mode 100644
index 00000000..6ee250b6
--- /dev/null
+++ b/legacy/web/app/view/dialog/Server.js
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2015 - 2018 Anton Tananaev (anton@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.Server', {
+ extend: 'Traccar.view.dialog.BaseEdit',
+
+ requires: [
+ 'Traccar.view.ClearableComboBox',
+ 'Traccar.view.dialog.MapPickerController',
+ 'Traccar.view.UnescapedTextField'
+ ],
+
+ controller: 'mapPicker',
+ title: Strings.serverTitle,
+
+ items: {
+ xtype: 'form',
+ items: [{
+ xtype: 'fieldset',
+ title: Strings.sharedPreferences,
+ items: [{
+ xtype: 'clearableComboBox',
+ name: 'map',
+ fieldLabel: Strings.mapLayer,
+ store: 'MapTypes',
+ displayField: 'name',
+ valueField: 'key'
+ }, {
+ xtype: 'unescapedTextField',
+ name: 'bingKey',
+ fieldLabel: Strings.mapBingKey
+ }, {
+ xtype: 'unescapedTextField',
+ reference: 'mapUrlField',
+ name: 'mapUrl',
+ fieldLabel: Strings.mapCustomLabel
+ }, {
+ xtype: 'numberfield',
+ reference: 'latitude',
+ name: 'latitude',
+ fieldLabel: Strings.positionLatitude,
+ decimalPrecision: Traccar.Style.coordinatePrecision
+ }, {
+ xtype: 'numberfield',
+ reference: 'longitude',
+ name: 'longitude',
+ fieldLabel: Strings.positionLongitude,
+ decimalPrecision: Traccar.Style.coordinatePrecision
+ }, {
+ xtype: 'numberfield',
+ reference: 'zoom',
+ name: 'zoom',
+ fieldLabel: Strings.serverZoom
+ }, {
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'twelveHourFormat',
+ fieldLabel: Strings.settingsTwelveHourFormat
+ }, {
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'forceSettings',
+ fieldLabel: Strings.serverForceSettings
+ }, {
+ xtype: 'clearableComboBox',
+ name: 'coordinateFormat',
+ fieldLabel: Strings.settingsCoordinateFormat,
+ store: 'CoordinateFormats',
+ displayField: 'name',
+ valueField: 'key'
+ }, {
+ xtype: 'unescapedTextField',
+ name: 'poiLayer',
+ fieldLabel: Strings.mapPoiLayer
+ }, {
+ xtype: 'unescapedTextField',
+ name: 'announcement',
+ fieldLabel: Strings.serverAnnouncement
+ }]
+ }, {
+ xtype: 'fieldset',
+ title: Strings.sharedPermissions,
+ collapsible: true,
+ collapsed: true,
+ items: [{
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'registration',
+ fieldLabel: Strings.serverRegistration
+ }, {
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'readonly',
+ fieldLabel: Strings.serverReadonly
+ }, {
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'deviceReadonly',
+ fieldLabel: Strings.userDeviceReadonly
+ }, {
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'limitCommands',
+ fieldLabel: Strings.userLimitCommands
+ }, {
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'disableReports',
+ fieldLabel: Strings.userDisableReports
+ }]
+ }]
+ },
+
+ buttons: [{
+ text: Strings.sharedAttributes,
+ handler: 'showAttributesView'
+ }, {
+ glyph: 'xf041@FontAwesome',
+ minWidth: 0,
+ handler: 'getMapState',
+ tooltip: Strings.sharedGetMapState,
+ tooltipType: 'title'
+ }, {
+ xtype: 'tbfill'
+ }, {
+ 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/legacy/web/app/view/dialog/User.js b/legacy/web/app/view/dialog/User.js
new file mode 100644
index 00000000..5da56424
--- /dev/null
+++ b/legacy/web/app/view/dialog/User.js
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2015 - 2018 Anton Tananaev (anton@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.User', {
+ extend: 'Traccar.view.dialog.BaseEdit',
+
+ requires: [
+ 'Traccar.view.ClearableComboBox',
+ 'Traccar.view.dialog.UserController',
+ 'Traccar.view.UnescapedTextField'
+ ],
+
+ controller: 'user',
+ title: Strings.settingsUser,
+
+ items: {
+ xtype: 'form',
+ items: [{
+ xtype: 'fieldset',
+ title: Strings.sharedRequired,
+ items: [{
+ xtype: 'unescapedTextField',
+ name: 'name',
+ fieldLabel: Strings.sharedName
+ }, {
+ xtype: 'unescapedTextField',
+ name: 'email',
+ fieldLabel: Strings.userEmail,
+ allowBlank: false
+ }, {
+ xtype: 'textfield',
+ name: 'password',
+ fieldLabel: Strings.userPassword,
+ inputType: 'password',
+ allowBlank: false
+ }]
+ }, {
+ xtype: 'fieldset',
+ title: Strings.sharedPreferences,
+ collapsible: true,
+ collapsed: true,
+ items: [{
+ xtype: 'unescapedTextField',
+ name: 'phone',
+ fieldLabel: Strings.sharedPhone
+ }, {
+ xtype: 'clearableComboBox',
+ name: 'map',
+ fieldLabel: Strings.mapLayer,
+ store: 'MapTypes',
+ displayField: 'name',
+ valueField: 'key'
+ }, {
+ xtype: 'numberfield',
+ reference: 'latitude',
+ name: 'latitude',
+ fieldLabel: Strings.positionLatitude,
+ decimalPrecision: Traccar.Style.coordinatePrecision
+ }, {
+ xtype: 'numberfield',
+ reference: 'longitude',
+ name: 'longitude',
+ fieldLabel: Strings.positionLongitude,
+ decimalPrecision: Traccar.Style.coordinatePrecision
+ }, {
+ xtype: 'numberfield',
+ reference: 'zoom',
+ name: 'zoom',
+ fieldLabel: Strings.serverZoom
+ }, {
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'twelveHourFormat',
+ fieldLabel: Strings.settingsTwelveHourFormat
+ }, {
+ xtype: 'clearableComboBox',
+ name: 'coordinateFormat',
+ fieldLabel: Strings.settingsCoordinateFormat,
+ store: 'CoordinateFormats',
+ displayField: 'name',
+ valueField: 'key'
+ }, {
+ xtype: 'unescapedTextField',
+ name: 'poiLayer',
+ fieldLabel: Strings.mapPoiLayer
+ }]
+ }, {
+ xtype: 'fieldset',
+ title: Strings.sharedPermissions,
+ collapsible: true,
+ collapsed: true,
+ items: [{
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'disabled',
+ fieldLabel: Strings.sharedDisabled,
+ disabled: true,
+ reference: 'disabledField'
+ }, {
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'administrator',
+ fieldLabel: Strings.userAdmin,
+ disabled: true,
+ reference: 'adminField'
+ }, {
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'readonly',
+ fieldLabel: Strings.serverReadonly,
+ disabled: true,
+ reference: 'readonlyField'
+ }, {
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'deviceReadonly',
+ fieldLabel: Strings.userDeviceReadonly,
+ disabled: true,
+ reference: 'deviceReadonlyField'
+ }, {
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'limitCommands',
+ fieldLabel: Strings.userLimitCommands,
+ disabled: true,
+ reference: 'limitCommandsField'
+ }, {
+ xtype: 'checkboxfield',
+ inputValue: true,
+ uncheckedValue: false,
+ name: 'disableReports',
+ fieldLabel: Strings.userDisableReports,
+ disabled: true,
+ reference: 'disableReportsField'
+ }, {
+ xtype: 'datefield',
+ name: 'expirationTime',
+ fieldLabel: Strings.userExpirationTime,
+ disabled: true,
+ reference: 'expirationTimeField',
+ startDay: Traccar.Style.weekStartDay,
+ format: Traccar.Style.dateFormat
+ }, {
+ xtype: 'numberfield',
+ name: 'deviceLimit',
+ fieldLabel: Strings.userDeviceLimit,
+ disabled: true,
+ reference: 'deviceLimitField'
+ }, {
+ xtype: 'numberfield',
+ name: 'userLimit',
+ fieldLabel: Strings.userUserLimit,
+ disabled: true,
+ reference: 'userLimitField'
+ }]
+ }]
+ },
+
+ buttons: [{
+ text: Strings.sharedAttributes,
+ handler: 'showAttributesView'
+ }, {
+ glyph: 'xf041@FontAwesome',
+ minWidth: 0,
+ handler: 'getMapState',
+ tooltip: Strings.sharedGetMapState,
+ tooltipType: 'title'
+ }, {
+ glyph: 'xf003@FontAwesome',
+ minWidth: 0,
+ handler: 'testNotification',
+ hidden: true,
+ reference: 'testNotificationButton',
+ tooltip: Strings.sharedTestNotification,
+ tooltipType: 'title'
+ }, {
+ xtype: 'tbfill'
+ }, {
+ 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/legacy/web/app/view/dialog/UserController.js b/legacy/web/app/view/dialog/UserController.js
new file mode 100644
index 00000000..0d620614
--- /dev/null
+++ b/legacy/web/app/view/dialog/UserController.js
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.UserController', {
+ extend: 'Traccar.view.dialog.MapPickerController',
+ alias: 'controller.user',
+
+ init: function () {
+ if (Traccar.app.getUser().get('administrator')) {
+ this.lookupReference('adminField').setDisabled(false);
+ this.lookupReference('deviceLimitField').setDisabled(false);
+ this.lookupReference('userLimitField').setDisabled(false);
+ }
+ if (Traccar.app.getUser().get('administrator') || !this.getView().selfEdit) {
+ this.lookupReference('readonlyField').setDisabled(false);
+ this.lookupReference('disabledField').setDisabled(false);
+ this.lookupReference('expirationTimeField').setDisabled(false);
+ this.lookupReference('deviceReadonlyField').setDisabled(false);
+ this.lookupReference('limitCommandsField').setDisabled(false);
+ this.lookupReference('disableReportsField').setDisabled(false);
+ }
+ },
+
+ testNotification: function () {
+ Ext.Ajax.request({
+ url: 'api/notifications/test',
+ method: 'POST',
+ failure: function (response) {
+ Traccar.app.showError(response);
+ }
+ });
+ },
+
+ onSaveClick: function (button) {
+ var dialog, record, store;
+ dialog = button.up('window').down('form');
+ dialog.updateRecord();
+ record = dialog.getRecord();
+ if (record === Traccar.app.getUser()) {
+ record.save();
+ } else {
+ store = Ext.getStore('Users');
+ if (record.phantom) {
+ store.add(record);
+ }
+ store.sync({
+ failure: function (batch) {
+ store.rejectChanges();
+ Traccar.app.showError(batch.exceptions[0].getError().response);
+ }
+ });
+ }
+ button.up('window').close();
+ }
+});
diff --git a/legacy/web/app/view/edit/Attributes.js b/legacy/web/app/view/edit/Attributes.js
new file mode 100644
index 00000000..af4f5a90
--- /dev/null
+++ b/legacy/web/app/view/edit/Attributes.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@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.Attributes', {
+ extend: 'Traccar.view.GridPanel',
+ xtype: 'attributesView',
+
+ requires: [
+ 'Traccar.view.edit.AttributesController',
+ 'Traccar.view.edit.Toolbar'
+ ],
+
+ controller: 'attributes',
+
+ tbar: {
+ xtype: 'editToolbar'
+ },
+
+ listeners: {
+ selectionchange: 'onSelectionChange'
+ },
+
+ columns: {
+ defaults: {
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ },
+ items: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ filter: 'string',
+ renderer: function (value) {
+ var attribute;
+ if (this.attributesStore) {
+ attribute = Ext.getStore(this.attributesStore).getById(value);
+ }
+ return attribute && attribute.get('name') || value;
+ }
+ }, {
+ text: Strings.stateValue,
+ dataIndex: 'value',
+ renderer: function (value, metaData, record) {
+ var attribute;
+ if (this.attributesStore) {
+ attribute = Ext.getStore(this.attributesStore).getById(record.get('name'));
+ }
+ return Traccar.AttributeFormatter.renderAttribute(value, attribute);
+ }
+ }]
+ }
+});
diff --git a/legacy/web/app/view/edit/AttributesController.js b/legacy/web/app/view/edit/AttributesController.js
new file mode 100644
index 00000000..84ff6adf
--- /dev/null
+++ b/legacy/web/app/view/edit/AttributesController.js
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@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.AttributesController', {
+ extend: 'Traccar.view.edit.ToolbarController',
+ alias: 'controller.attributes',
+
+ requires: [
+ 'Traccar.view.dialog.Attribute',
+ 'Traccar.store.Attributes',
+ 'Traccar.model.Attribute'
+ ],
+
+ removeTitle: Strings.stateName,
+
+ init: function () {
+ var store, propertyName, i = 0, attributes;
+ store = Ext.create('Traccar.store.Attributes');
+ store.setProxy(Ext.create('Ext.data.proxy.Memory'));
+ if (typeof this.getView().record.get('attributes') === 'undefined') {
+ this.getView().record.set('attributes', {});
+ }
+ attributes = this.getView().record.get('attributes');
+ for (propertyName in attributes) {
+ if (attributes.hasOwnProperty(propertyName)) {
+ store.add(Ext.create('Traccar.model.Attribute', {
+ priority: i++,
+ name: propertyName,
+ value: attributes[propertyName]
+ }));
+ }
+ }
+ store.addListener('add', function (store, records) {
+ var i, view;
+ view = this.getView();
+ for (i = 0; i < records.length; i++) {
+ view.record.get('attributes')[records[i].get('name')] = records[i].get('value');
+ }
+ view.record.dirty = true;
+ }, this);
+ store.addListener('update', function (store, record, operation) {
+ var view;
+ view = this.getView();
+ if (operation === Ext.data.Model.EDIT) {
+ if (record.modified.name !== record.get('name')) {
+ delete view.record.get('attributes')[record.modified.name];
+ }
+ view.record.get('attributes')[record.get('name')] = record.get('value');
+ view.record.dirty = true;
+ }
+ }, this);
+ store.addListener('remove', function (store, records) {
+ var i, view;
+ view = this.getView();
+ for (i = 0; i < records.length; i++) {
+ delete view.record.get('attributes')[records[i].get('name')];
+ }
+ view.record.dirty = true;
+ }, this);
+
+ this.getView().setStore(store);
+ if (this.getView().record instanceof Traccar.model.Device) {
+ this.getView().attributesStore = 'DeviceAttributes';
+ } else if (this.getView().record instanceof Traccar.model.Geofence) {
+ this.getView().attributesStore = 'GeofenceAttributes';
+ } else if (this.getView().record instanceof Traccar.model.Group) {
+ this.getView().attributesStore = 'GroupAttributes';
+ } else if (this.getView().record instanceof Traccar.model.Server) {
+ this.getView().attributesStore = 'ServerAttributes';
+ } else if (this.getView().record instanceof Traccar.model.User) {
+ this.getView().attributesStore = 'UserAttributes';
+ }
+ },
+
+ comboConfig: {
+ xtype: 'combobox',
+ reference: 'nameComboField',
+ name: 'name',
+ fieldLabel: Strings.sharedName,
+ displayField: 'name',
+ valueField: 'key',
+ allowBlank: false,
+ queryMode: 'local',
+ listeners: {
+ change: 'onNameChange'
+ }
+ },
+
+ initDialog: function (record) {
+ var nameTextField, dialog = Ext.create('Traccar.view.dialog.Attribute');
+ if (this.getView().attributesStore) {
+ this.comboConfig.store = this.getView().attributesStore;
+ nameTextField = dialog.lookupReference('nameTextField');
+ dialog.down('form').insert(0, this.comboConfig);
+ dialog.down('form').remove(nameTextField);
+ }
+ dialog.down('form').loadRecord(record);
+ dialog.show();
+ },
+
+ onAddClick: function () {
+ var objectInstance = Ext.create('Traccar.model.Attribute');
+ objectInstance.store = this.getView().getStore();
+ this.initDialog(objectInstance);
+ },
+
+ onEditClick: function () {
+ this.initDialog(this.getView().getSelectionModel().getSelection()[0]);
+ }
+});
diff --git a/legacy/web/app/view/edit/Calendars.js b/legacy/web/app/view/edit/Calendars.js
new file mode 100644
index 00000000..23f20e25
--- /dev/null
+++ b/legacy/web/app/view/edit/Calendars.js
@@ -0,0 +1,50 @@
+/*
+ * 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.Calendars', {
+ extend: 'Traccar.view.GridPanel',
+ xtype: 'calendarsView',
+
+ requires: [
+ 'Traccar.view.edit.CalendarsController',
+ 'Traccar.view.edit.Toolbar'
+ ],
+
+ controller: 'calendars',
+ store: 'Calendars',
+
+ tbar: {
+ xtype: 'editToolbar'
+ },
+
+ listeners: {
+ selectionchange: 'onSelectionChange'
+ },
+
+ columns: {
+ defaults: {
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ },
+ items: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ filter: 'string'
+ }]
+ }
+});
diff --git a/legacy/web/app/view/edit/CalendarsController.js b/legacy/web/app/view/edit/CalendarsController.js
new file mode 100644
index 00000000..d11ec379
--- /dev/null
+++ b/legacy/web/app/view/edit/CalendarsController.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.CalendarsController', {
+ extend: 'Traccar.view.edit.ToolbarController',
+ alias: 'controller.calendars',
+
+ requires: [
+ 'Traccar.view.dialog.Calendar',
+ 'Traccar.model.Calendar'
+ ],
+
+ objectModel: 'Traccar.model.Calendar',
+ objectDialog: 'Traccar.view.dialog.Calendar',
+ removeTitle: Strings.sharedCalendar
+});
diff --git a/legacy/web/app/view/edit/ComputedAttributes.js b/legacy/web/app/view/edit/ComputedAttributes.js
new file mode 100644
index 00000000..9f0b9396
--- /dev/null
+++ b/legacy/web/app/view/edit/ComputedAttributes.js
@@ -0,0 +1,80 @@
+/*
+ * 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: 'Traccar.view.GridPanel',
+ 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',
+ filter: 'string'
+ }, {
+ text: Strings.sharedAttribute,
+ dataIndex: 'attribute',
+ filter: {
+ type: 'list',
+ labelField: 'name',
+ store: 'PositionAttributes'
+ },
+ renderer: function (value) {
+ return Ext.getStore('PositionAttributes').getAttributeName(value);
+ }
+ }, {
+ text: Strings.sharedExpression,
+ dataIndex: 'expression'
+ }, {
+ text: Strings.sharedType,
+ dataIndex: 'type',
+ filter: {
+ type: 'list',
+ labelField: 'name',
+ store: 'AttributeValueTypes'
+ },
+ renderer: function (value) {
+ var type = Ext.getStore('AttributeValueTypes').getById(value);
+ if (type) {
+ return type.get('name');
+ } else {
+ return value;
+ }
+ }
+ }]
+ }
+});
diff --git a/legacy/web/app/view/edit/ComputedAttributesController.js b/legacy/web/app/view/edit/ComputedAttributesController.js
new file mode 100644
index 00000000..6ae14102
--- /dev/null
+++ b/legacy/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/legacy/web/app/view/edit/Devices.js b/legacy/web/app/view/edit/Devices.js
new file mode 100644
index 00000000..5f54202a
--- /dev/null
+++ b/legacy/web/app/view/edit/Devices.js
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.Devices', {
+ extend: 'Traccar.view.GridPanel',
+ xtype: 'devicesView',
+
+ requires: [
+ 'Traccar.AttributeFormatter',
+ 'Traccar.view.edit.DevicesController',
+ 'Traccar.view.ArrayListFilter',
+ 'Traccar.view.DeviceMenu'
+ ],
+
+ controller: 'devices',
+
+ store: 'VisibleDevices',
+
+ stateful: true,
+ stateId: 'devices-grid',
+
+ tbar: {
+ componentCls: 'toolbar-header-style',
+ defaults: {
+ xtype: 'button',
+ disabled: true,
+ tooltipType: 'title'
+ },
+ items: [{
+ xtype: 'tbtext',
+ html: Strings.deviceTitle,
+ baseCls: 'x-panel-header-title-default'
+ }, {
+ xtype: 'tbfill',
+ disabled: false
+ }, {
+ handler: 'onAddClick',
+ reference: 'toolbarAddButton',
+ glyph: 'xf067@FontAwesome',
+ tooltip: Strings.sharedAdd
+ }, {
+ handler: 'onEditClick',
+ reference: 'toolbarEditButton',
+ glyph: 'xf040@FontAwesome',
+ tooltip: Strings.sharedEdit
+ }, {
+ handler: 'onRemoveClick',
+ reference: 'toolbarRemoveButton',
+ glyph: 'xf00d@FontAwesome',
+ tooltip: Strings.sharedRemove
+ }, {
+ handler: 'onCommandClick',
+ reference: 'deviceCommandButton',
+ glyph: 'xf093@FontAwesome',
+ tooltip: Strings.deviceCommand
+ }, {
+ xtype: 'deviceMenu',
+ reference: 'toolbarDeviceMenu',
+ enableToggle: false
+ }]
+ },
+
+ listeners: {
+ selectionchange: 'onSelectionChange'
+ },
+
+ viewConfig: {
+ enableTextSelection: true,
+ getRowClass: function (record) {
+ var result = '', status = record.get('status');
+ if (record.get('disabled')) {
+ result = 'view-item-disabled ';
+ }
+ if (status) {
+ result += Ext.getStore('DeviceStatuses').getById(status).get('color');
+ }
+ return result;
+ }
+ },
+
+ columns: {
+ defaults: {
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ },
+ items: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ filter: 'string'
+ }, {
+ text: Strings.deviceIdentifier,
+ dataIndex: 'uniqueId',
+ hidden: true,
+ filter: 'string'
+ }, {
+ text: Strings.sharedPhone,
+ dataIndex: 'phone',
+ hidden: true
+ }, {
+ text: Strings.deviceModel,
+ dataIndex: 'model',
+ hidden: true
+ }, {
+ text: Strings.deviceContact,
+ dataIndex: 'contact',
+ hidden: true
+ }, {
+ text: Strings.groupDialog,
+ dataIndex: 'groupId',
+ hidden: true,
+ filter: {
+ type: 'list',
+ labelField: 'name',
+ store: 'Groups'
+ },
+ renderer: Traccar.AttributeFormatter.getFormatter('groupId')
+ }, {
+ text: Strings.sharedDisabled,
+ dataIndex: 'disabled',
+ renderer: Traccar.AttributeFormatter.getFormatter('disabled'),
+ hidden: true,
+ filter: 'boolean'
+ }, {
+ text: Strings.deviceStatus,
+ dataIndex: 'status',
+ filter: {
+ type: 'list',
+ labelField: 'name',
+ store: 'DeviceStatuses'
+ },
+ renderer: function (value) {
+ var status;
+ if (value) {
+ status = Ext.getStore('DeviceStatuses').getById(value);
+ if (status) {
+ return status.get('name');
+ }
+ }
+ return null;
+ }
+ }, {
+ text: Strings.deviceLastUpdate,
+ dataIndex: 'lastUpdate',
+ renderer: Traccar.AttributeFormatter.getFormatter('lastUpdate')
+ }]
+ }
+});
diff --git a/legacy/web/app/view/edit/DevicesController.js b/legacy/web/app/view/edit/DevicesController.js
new file mode 100644
index 00000000..16e54b21
--- /dev/null
+++ b/legacy/web/app/view/edit/DevicesController.js
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.DevicesController', {
+ extend: 'Traccar.view.edit.ToolbarController',
+ alias: 'controller.devices',
+
+ requires: [
+ 'Traccar.view.dialog.SendCommand',
+ 'Traccar.view.dialog.Device',
+ 'Traccar.view.permissions.Geofences',
+ 'Traccar.view.permissions.ComputedAttributes',
+ 'Traccar.view.permissions.Drivers',
+ 'Traccar.view.permissions.SavedCommands',
+ 'Traccar.view.BaseWindow',
+ 'Traccar.model.Device',
+ 'Traccar.model.Command'
+ ],
+
+ config: {
+ listen: {
+ controller: {
+ '*': {
+ selectreport: 'deselectDevice',
+ selectevent: 'deselectDevice'
+ },
+ 'root': {
+ selectdevice: 'selectDevice'
+ },
+ 'map': {
+ selectdevice: 'selectDevice',
+ deselectfeature: 'deselectFeature'
+ }
+ },
+ store: {
+ '#Devices': {
+ update: 'onUpdateDevice'
+ }
+ }
+ }
+ },
+
+ objectModel: 'Traccar.model.Device',
+ objectDialog: 'Traccar.view.dialog.Device',
+ removeTitle: Strings.sharedDevice,
+
+ init: function () {
+ var self = this, readonly, deviceReadonly;
+ deviceReadonly = Traccar.app.getPreference('deviceReadonly', false) && !Traccar.app.getUser().get('administrator');
+ readonly = Traccar.app.getPreference('readonly', false) && !Traccar.app.getUser().get('administrator');
+ this.lookupReference('toolbarAddButton').setDisabled(readonly || deviceReadonly);
+ this.lookupReference('toolbarDeviceMenu').setHidden(readonly || deviceReadonly);
+
+ setInterval(function () {
+ self.getView().getView().refresh();
+ }, Traccar.Style.refreshPeriod);
+ },
+
+ onCommandClick: function () {
+ var device, deviceId, dialog, typesStore, commandsStore;
+ device = this.getView().getSelectionModel().getSelection()[0];
+ deviceId = device.get('id');
+
+ dialog = Ext.create('Traccar.view.dialog.SendCommand');
+ dialog.deviceId = deviceId;
+
+ commandsStore = dialog.lookupReference('commandsComboBox').getStore();
+ commandsStore.getProxy().setExtraParam('deviceId', deviceId);
+ if (!Traccar.app.getPreference('limitCommands', false)) {
+ commandsStore.add({
+ id: 0,
+ description: Strings.sharedNew
+ });
+ }
+ commandsStore.load({
+ addRecords: true
+ });
+
+ typesStore = dialog.lookupReference('commandType').getStore();
+ typesStore.getProxy().setExtraParam('deviceId', deviceId);
+ typesStore.load();
+
+ dialog.show();
+ },
+
+ updateButtons: function (selected) {
+ var readonly, deviceReadonly, empty, deviceMenu;
+ deviceReadonly = Traccar.app.getPreference('deviceReadonly', false) && !Traccar.app.getUser().get('administrator');
+ readonly = Traccar.app.getPreference('readonly', false) && !Traccar.app.getUser().get('administrator');
+ empty = selected.length === 0;
+ this.lookupReference('toolbarEditButton').setDisabled(empty || readonly || deviceReadonly);
+ this.lookupReference('toolbarRemoveButton').setDisabled(empty || readonly || deviceReadonly);
+ deviceMenu = this.lookupReference('toolbarDeviceMenu');
+ deviceMenu.device = empty ? null : selected[0];
+ deviceMenu.setDisabled(empty);
+ this.lookupReference('deviceCommandButton').setDisabled(empty || readonly);
+ },
+
+ onSelectionChange: function (el, records) {
+ if (records && records.length) {
+ this.updateButtons(records);
+ this.fireEvent('selectdevice', records[0], true);
+ }
+ },
+
+ selectDevice: function (device) {
+ this.getView().getSelectionModel().select([device], false, true);
+ this.updateButtons(this.getView().getSelectionModel().getSelected().items);
+ this.getView().getView().focusRow(device);
+ },
+
+ deselectDevice: function (object) {
+ if (object) {
+ this.deselectFeature();
+ }
+ },
+
+ onUpdateDevice: function () {
+ this.updateButtons(this.getView().getSelectionModel().getSelected().items);
+ },
+
+ deselectFeature: function () {
+ this.getView().getSelectionModel().deselectAll();
+ }
+});
diff --git a/legacy/web/app/view/edit/Drivers.js b/legacy/web/app/view/edit/Drivers.js
new file mode 100644
index 00000000..7bd10a68
--- /dev/null
+++ b/legacy/web/app/view/edit/Drivers.js
@@ -0,0 +1,54 @@
+/*
+ * 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.Drivers', {
+ extend: 'Traccar.view.GridPanel',
+ xtype: 'driversView',
+
+ requires: [
+ 'Traccar.view.edit.DriversController',
+ 'Traccar.view.edit.Toolbar'
+ ],
+
+ controller: 'drivers',
+ store: 'Drivers',
+
+ tbar: {
+ xtype: 'editToolbar'
+ },
+
+ listeners: {
+ selectionchange: 'onSelectionChange'
+ },
+
+ columns: {
+ defaults: {
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ },
+ items: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ filter: 'string'
+ }, {
+ text: Strings.deviceIdentifier,
+ dataIndex: 'uniqueId',
+ filter: 'string'
+ }]
+ }
+});
diff --git a/legacy/web/app/view/edit/DriversController.js b/legacy/web/app/view/edit/DriversController.js
new file mode 100644
index 00000000..6c8a63cc
--- /dev/null
+++ b/legacy/web/app/view/edit/DriversController.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.edit.DriversController', {
+ extend: 'Traccar.view.edit.ToolbarController',
+ alias: 'controller.drivers',
+
+ requires: [
+ 'Traccar.view.dialog.Driver',
+ 'Traccar.model.Driver'
+ ],
+
+ objectModel: 'Traccar.model.Driver',
+ objectDialog: 'Traccar.view.dialog.Driver',
+ removeTitle: Strings.sharedDriver
+});
diff --git a/legacy/web/app/view/edit/Geofences.js b/legacy/web/app/view/edit/Geofences.js
new file mode 100644
index 00000000..0e1e6773
--- /dev/null
+++ b/legacy/web/app/view/edit/Geofences.js
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016 - 2018 Anton Tananaev (anton@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.Geofences', {
+ extend: 'Traccar.view.GridPanel',
+ xtype: 'geofencesView',
+
+ requires: [
+ 'Traccar.view.edit.GeofencesController',
+ 'Traccar.view.edit.Toolbar'
+ ],
+
+ controller: 'geofences',
+ store: 'Geofences',
+
+ tbar: {
+ xtype: 'editToolbar'
+ },
+
+ listeners: {
+ selectionchange: 'onSelectionChange'
+ },
+
+ columns: {
+ defaults: {
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ },
+ items: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ filter: 'string'
+ }, {
+ text: Strings.sharedDescription,
+ dataIndex: 'description',
+ filter: 'string'
+ }, {
+ text: Strings.sharedCalendar,
+ dataIndex: 'calendarId',
+ hidden: true,
+ filter: {
+ type: 'list',
+ labelField: 'name',
+ store: 'AllCalendars'
+ },
+ renderer: Traccar.AttributeFormatter.getFormatter('calendarId')
+ }]
+ }
+});
diff --git a/legacy/web/app/view/edit/GeofencesController.js b/legacy/web/app/view/edit/GeofencesController.js
new file mode 100644
index 00000000..73d367ac
--- /dev/null
+++ b/legacy/web/app/view/edit/GeofencesController.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@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.GeofencesController', {
+ extend: 'Traccar.view.edit.ToolbarController',
+ alias: 'controller.geofences',
+
+ requires: [
+ 'Traccar.view.dialog.Geofence',
+ 'Traccar.model.Geofence'
+ ],
+
+ objectModel: 'Traccar.model.Geofence',
+ objectDialog: 'Traccar.view.dialog.Geofence',
+ removeTitle: Strings.sharedGeofence
+});
diff --git a/legacy/web/app/view/edit/Groups.js b/legacy/web/app/view/edit/Groups.js
new file mode 100644
index 00000000..8b09316c
--- /dev/null
+++ b/legacy/web/app/view/edit/Groups.js
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2016 - 2018 Anton Tananaev (anton@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.Groups', {
+ extend: 'Traccar.view.GridPanel',
+ xtype: 'groupsView',
+
+ requires: [
+ 'Traccar.AttributeFormatter',
+ 'Traccar.view.edit.GroupsController',
+ 'Traccar.view.edit.Toolbar'
+ ],
+
+ controller: 'groups',
+ store: 'Groups',
+
+ tbar: {
+ xtype: 'editToolbar',
+ items: [{
+ xtype: 'button',
+ disabled: true,
+ handler: 'onGeofencesClick',
+ reference: 'toolbarGeofencesButton',
+ glyph: 'xf21d@FontAwesome',
+ tooltip: Strings.sharedGeofences,
+ tooltipType: 'title'
+ }, {
+ xtype: 'button',
+ disabled: true,
+ handler: 'onAttributesClick',
+ reference: 'toolbarAttributesButton',
+ glyph: 'xf0ae@FontAwesome',
+ tooltip: Strings.sharedComputedAttributes,
+ tooltipType: 'title'
+ }, {
+ xtype: 'button',
+ disabled: true,
+ handler: 'onDriversClick',
+ reference: 'toolbarDriversButton',
+ glyph: 'xf084@FontAwesome',
+ tooltip: Strings.sharedDrivers,
+ tooltipType: 'title'
+ }, {
+ xtype: 'button',
+ disabled: true,
+ handler: 'onCommandsClick',
+ reference: 'toolbarCommandsButton',
+ glyph: 'xf093@FontAwesome',
+ tooltip: Strings.sharedSavedCommands,
+ tooltipType: 'title'
+ }, {
+ xtype: 'button',
+ disabled: true,
+ handler: 'onNotificationsClick',
+ reference: 'toolbarNotificationsButton',
+ glyph: 'xf003@FontAwesome',
+ tooltip: Strings.sharedNotifications,
+ tooltipType: 'title'
+ }, {
+ xtype: 'button',
+ disabled: true,
+ handler: 'onMaintenancesClick',
+ reference: 'toolbarMaintenancesButton',
+ glyph: 'xf0ad@FontAwesome',
+ tooltip: Strings.sharedMaintenance,
+ tooltipType: 'title'
+ }]
+ },
+
+ listeners: {
+ selectionchange: 'onSelectionChange'
+ },
+
+ columns: {
+ defaults: {
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ },
+ items: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ filter: 'string'
+ }, {
+ text: Strings.groupDialog,
+ dataIndex: 'groupId',
+ hidden: true,
+ filter: {
+ type: 'list',
+ labelField: 'name',
+ store: 'AllGroups'
+ },
+ renderer: Traccar.AttributeFormatter.getFormatter('groupId')
+ }]
+ }
+});
diff --git a/legacy/web/app/view/edit/GroupsController.js b/legacy/web/app/view/edit/GroupsController.js
new file mode 100644
index 00000000..ae96a248
--- /dev/null
+++ b/legacy/web/app/view/edit/GroupsController.js
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2016 - 2018 Anton Tananaev (anton@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.GroupsController', {
+ extend: 'Traccar.view.edit.ToolbarController',
+ alias: 'controller.groups',
+
+ requires: [
+ 'Traccar.view.dialog.Group',
+ 'Traccar.view.permissions.Geofences',
+ 'Traccar.view.permissions.ComputedAttributes',
+ 'Traccar.view.permissions.Drivers',
+ 'Traccar.view.permissions.SavedCommands',
+ 'Traccar.view.permissions.Maintenances',
+ 'Traccar.view.BaseWindow',
+ 'Traccar.model.Group'
+ ],
+
+ objectModel: 'Traccar.model.Group',
+ objectDialog: 'Traccar.view.dialog.Group',
+ removeTitle: Strings.groupDialog,
+
+ init: function () {
+ this.lookupReference('toolbarDriversButton').setHidden(
+ Traccar.app.getVehicleFeaturesDisabled() || Traccar.app.getBooleanAttributePreference('ui.disableDrivers'));
+ this.lookupReference('toolbarAttributesButton').setHidden(
+ Traccar.app.getBooleanAttributePreference('ui.disableComputedAttributes'));
+ this.lookupReference('toolbarCommandsButton').setHidden(Traccar.app.getPreference('limitCommands', false));
+ this.lookupReference('toolbarMaintenancesButton').setHidden(
+ Traccar.app.getVehicleFeaturesDisabled() || Traccar.app.getBooleanAttributePreference('ui.disableMaintenance'));
+ },
+
+ onGeofencesClick: function () {
+ var group = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedGeofences,
+ items: {
+ xtype: 'linkGeofencesView',
+ baseObjectName: 'groupId',
+ linkObjectName: 'geofenceId',
+ storeName: 'Geofences',
+ baseObject: group.getId()
+ }
+ }).show();
+ },
+
+ onAttributesClick: function () {
+ var group = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedComputedAttributes,
+ items: {
+ xtype: 'linkComputedAttributesView',
+ baseObjectName: 'groupId',
+ linkObjectName: 'attributeId',
+ storeName: 'ComputedAttributes',
+ baseObject: group.getId()
+ }
+ }).show();
+ },
+
+ onDriversClick: function () {
+ var group = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedDrivers,
+ items: {
+ xtype: 'linkDriversView',
+ baseObjectName: 'groupId',
+ linkObjectName: 'driverId',
+ storeName: 'Drivers',
+ baseObject: group.getId()
+ }
+ }).show();
+ },
+
+ onCommandsClick: function () {
+ var group = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedSavedCommands,
+ items: {
+ xtype: 'linkSavedCommandsView',
+ baseObjectName: 'groupId',
+ linkObjectName: 'commandId',
+ storeName: 'Commands',
+ baseObject: group.getId()
+ }
+ }).show();
+ },
+
+ onNotificationsClick: function () {
+ var group = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedNotifications,
+ items: {
+ xtype: 'linkNotificationsView',
+ baseObjectName: 'groupId',
+ linkObjectName: 'notificationId',
+ storeName: 'Notifications',
+ baseObject: group.getId()
+ }
+ }).show();
+ },
+
+ onMaintenancesClick: function () {
+ var group = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedMaintenance,
+ items: {
+ xtype: 'linkMaintenancesView',
+ baseObjectName: 'groupId',
+ linkObjectName: 'maintenanceId',
+ storeName: 'Maintenances',
+ baseObject: group.getId()
+ }
+ }).show();
+ },
+
+ onSelectionChange: function (selection, selected) {
+ var disabled = selected.length === 0;
+ this.lookupReference('toolbarGeofencesButton').setDisabled(disabled);
+ this.lookupReference('toolbarAttributesButton').setDisabled(disabled);
+ this.lookupReference('toolbarDriversButton').setDisabled(disabled);
+ this.lookupReference('toolbarCommandsButton').setDisabled(disabled);
+ this.lookupReference('toolbarNotificationsButton').setDisabled(disabled);
+ this.lookupReference('toolbarMaintenancesButton').setDisabled(disabled);
+ this.callParent(arguments);
+ }
+});
diff --git a/legacy/web/app/view/edit/Maintenances.js b/legacy/web/app/view/edit/Maintenances.js
new file mode 100644
index 00000000..da129154
--- /dev/null
+++ b/legacy/web/app/view/edit/Maintenances.js
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 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.Maintenances', {
+ extend: 'Traccar.view.GridPanel',
+ xtype: 'maintenancesView',
+
+ requires: [
+ 'Traccar.view.edit.MaintenancesController',
+ 'Traccar.view.edit.Toolbar'
+ ],
+
+ controller: 'maintenances',
+ store: 'Maintenances',
+
+ tbar: {
+ xtype: 'editToolbar'
+ },
+
+ listeners: {
+ selectionchange: 'onSelectionChange'
+ },
+
+ columns: {
+ defaults: {
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ },
+ items: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ filter: 'string'
+ }, {
+ text: Strings.sharedType,
+ dataIndex: 'type',
+ filter: {
+ type: 'list',
+ idField: 'key',
+ labelField: 'name',
+ store: 'MaintenanceTypes'
+ },
+ renderer: function (value) {
+ var attribute = Ext.getStore('MaintenanceTypes').getById(value);
+ return attribute && attribute.get('name') || value;
+ }
+ }, {
+ text: Strings.maintenanceStart,
+ dataIndex: 'start',
+ renderer: function (value, metaData, record) {
+ return Traccar.AttributeFormatter.renderAttribute(
+ value, Ext.getStore('MaintenanceTypes').getById(record.get('type')));
+ }
+ }, {
+ text: Strings.maintenancePeriod,
+ dataIndex: 'period',
+ renderer: function (value, metaData, record) {
+ return Traccar.AttributeFormatter.renderAttribute(
+ value, Ext.getStore('MaintenanceTypes').getById(record.get('type')));
+ }
+ }]
+ }
+});
diff --git a/legacy/web/app/view/edit/MaintenancesController.js b/legacy/web/app/view/edit/MaintenancesController.js
new file mode 100644
index 00000000..19762e61
--- /dev/null
+++ b/legacy/web/app/view/edit/MaintenancesController.js
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 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.MaintenancesController', {
+ extend: 'Traccar.view.edit.ToolbarController',
+ alias: 'controller.maintenances',
+
+ requires: [
+ 'Traccar.view.dialog.Maintenance',
+ 'Traccar.model.Maintenance'
+ ],
+
+ objectModel: 'Traccar.model.Maintenance',
+ objectDialog: 'Traccar.view.dialog.Maintenance',
+ removeTitle: Strings.sharedMaintenance
+});
diff --git a/legacy/web/app/view/edit/Notifications.js b/legacy/web/app/view/edit/Notifications.js
new file mode 100644
index 00000000..9cf97b19
--- /dev/null
+++ b/legacy/web/app/view/edit/Notifications.js
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 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.Notifications', {
+ extend: 'Traccar.view.GridPanel',
+ xtype: 'notificationsView',
+
+ requires: [
+ 'Traccar.view.edit.NotificationsController',
+ 'Traccar.view.edit.Toolbar'
+ ],
+
+ controller: 'notifications',
+ store: 'Notifications',
+
+ tbar: {
+ xtype: 'editToolbar'
+ },
+
+ listeners: {
+ selectionchange: 'onSelectionChange'
+ },
+
+ columns: {
+ defaults: {
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ },
+ items: [{
+ text: Strings.notificationType,
+ dataIndex: 'type',
+ flex: 2,
+ renderer: function (value) {
+ return Traccar.app.getEventString(value);
+ },
+ filter: {
+ type: 'list',
+ idField: 'type',
+ labelField: 'name',
+ store: 'AllNotificationTypes'
+ }
+ }, {
+ text: Strings.notificationAlways,
+ dataIndex: 'always',
+ renderer: Traccar.AttributeFormatter.getFormatter('always'),
+ filter: 'boolean'
+ }, {
+ text: Strings.sharedAlarms,
+ dataIndex: 'attributes',
+ renderer: function (value) {
+ var i, key, result = '', alarms = value && value['alarms'];
+ if (alarms) {
+ alarms = alarms.split(',');
+ for (i = 0; i < alarms.length; i++) {
+ key = 'alarm' + alarms[i].charAt(0).toUpperCase() + alarms[i].slice(1);
+ if (result) {
+ result += ', ';
+ }
+ result += Strings[key] || key;
+ }
+ }
+ return result;
+ }
+ }, {
+ text: Strings.notificationNotificators,
+ dataIndex: 'notificators',
+ flex: 2,
+ filter: {
+ type: 'arraylist',
+ idField: 'type',
+ labelField: 'name',
+ store: 'AllNotificators'
+ },
+ renderer: function (value) {
+ var result = '', i, notificators;
+ if (value) {
+ notificators = value.split(/[ ,]+/).filter(Boolean);
+ for (i = 0; i < notificators.length; i++) {
+ result += Traccar.app.getNotificatorString(notificators[i]) + (i < notificators.length - 1 ? ', ' : '');
+ }
+ }
+ return result;
+ }
+ }, {
+ text: Strings.sharedCalendar,
+ dataIndex: 'calendarId',
+ hidden: true,
+ filter: {
+ type: 'list',
+ labelField: 'name',
+ store: 'AllCalendars'
+ },
+ renderer: Traccar.AttributeFormatter.getFormatter('calendarId')
+ }]
+ }
+});
diff --git a/legacy/web/app/view/edit/NotificationsController.js b/legacy/web/app/view/edit/NotificationsController.js
new file mode 100644
index 00000000..ad22a686
--- /dev/null
+++ b/legacy/web/app/view/edit/NotificationsController.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.edit.NotificationsController', {
+ extend: 'Traccar.view.edit.ToolbarController',
+ alias: 'controller.notifications',
+
+ requires: [
+ 'Traccar.view.dialog.Notification',
+ 'Traccar.model.Notification'
+ ],
+
+ objectModel: 'Traccar.model.Notification',
+ objectDialog: 'Traccar.view.dialog.Notification',
+ removeTitle: Strings.sharedNotification
+});
diff --git a/legacy/web/app/view/edit/SavedCommands.js b/legacy/web/app/view/edit/SavedCommands.js
new file mode 100644
index 00000000..9e5f4869
--- /dev/null
+++ b/legacy/web/app/view/edit/SavedCommands.js
@@ -0,0 +1,65 @@
+/*
+ * 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.SavedCommands', {
+ extend: 'Traccar.view.GridPanel',
+ xtype: 'savedCommandsView',
+
+ requires: [
+ 'Traccar.view.edit.SavedCommandsController',
+ 'Traccar.view.edit.Toolbar'
+ ],
+
+ controller: 'savedCommands',
+ store: 'Commands',
+
+ tbar: {
+ xtype: 'editToolbar'
+ },
+
+ listeners: {
+ selectionchange: 'onSelectionChange'
+ },
+
+ columns: {
+ defaults: {
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ },
+ items: [{
+ text: Strings.sharedDescription,
+ dataIndex: 'description',
+ filter: 'string'
+ }, {
+ text: Strings.sharedType,
+ dataIndex: 'type',
+ filter: {
+ type: 'list',
+ idField: 'type',
+ labelField: 'name',
+ store: 'AllCommandTypes'
+ },
+ renderer: Traccar.AttributeFormatter.getFormatter('commandType')
+ }, {
+ text: Strings.commandSendSms,
+ dataIndex: 'textChannel',
+ renderer: Traccar.AttributeFormatter.getFormatter('textChannel'),
+ filter: 'boolean'
+ }]
+ }
+});
diff --git a/legacy/web/app/view/edit/SavedCommandsController.js b/legacy/web/app/view/edit/SavedCommandsController.js
new file mode 100644
index 00000000..1511661e
--- /dev/null
+++ b/legacy/web/app/view/edit/SavedCommandsController.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.edit.SavedCommandsController', {
+ extend: 'Traccar.view.edit.ToolbarController',
+ alias: 'controller.savedCommands',
+
+ requires: [
+ 'Traccar.view.dialog.SavedCommand',
+ 'Traccar.model.Command'
+ ],
+
+ objectModel: 'Traccar.model.Command',
+ objectDialog: 'Traccar.view.dialog.SavedCommand',
+ removeTitle: Strings.sharedSavedCommand
+});
diff --git a/legacy/web/app/view/edit/Toolbar.js b/legacy/web/app/view/edit/Toolbar.js
new file mode 100644
index 00000000..6999030b
--- /dev/null
+++ b/legacy/web/app/view/edit/Toolbar.js
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.Toolbar', {
+ extend: 'Ext.toolbar.Toolbar',
+ xtype: 'editToolbar',
+
+ initComponent: function () {
+ this.callParent(arguments);
+ this.add(0, [{
+ xtype: 'button',
+ handler: 'onAddClick',
+ reference: 'toolbarAddButton',
+ glyph: 'xf067@FontAwesome',
+ tooltip: Strings.sharedAdd,
+ tooltipType: 'title'
+ }, {
+ xtype: 'button',
+ disabled: true,
+ handler: 'onEditClick',
+ reference: 'toolbarEditButton',
+ glyph: 'xf040@FontAwesome',
+ tooltip: Strings.sharedEdit,
+ tooltipType: 'title'
+ }, {
+ xtype: 'button',
+ disabled: true,
+ handler: 'onRemoveClick',
+ reference: 'toolbarRemoveButton',
+ glyph: 'xf00d@FontAwesome',
+ tooltip: Strings.sharedRemove,
+ tooltipType: 'title'
+ }]);
+ }
+});
diff --git a/legacy/web/app/view/edit/ToolbarController.js b/legacy/web/app/view/edit/ToolbarController.js
new file mode 100644
index 00000000..d3ca9de6
--- /dev/null
+++ b/legacy/web/app/view/edit/ToolbarController.js
@@ -0,0 +1,70 @@
+/*
+ * 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.ToolbarController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.toolbarController',
+
+ onAddClick: function () {
+ var dialog, objectInstance = Ext.create(this.objectModel);
+ objectInstance.store = this.getView().getStore();
+ if (objectInstance.store instanceof Ext.data.ChainedStore) {
+ objectInstance.store = objectInstance.store.getSource();
+ }
+ dialog = Ext.create(this.objectDialog);
+ dialog.down('form').loadRecord(objectInstance);
+ dialog.show();
+ },
+
+ onEditClick: function () {
+ var dialog, objectInstance = this.getView().getSelectionModel().getSelection()[0];
+ dialog = Ext.create(this.objectDialog);
+ dialog.down('form').loadRecord(objectInstance);
+ dialog.show();
+ },
+
+ onRemoveClick: function () {
+ var objectInstance = this.getView().getSelectionModel().getSelection()[0];
+ Ext.Msg.show({
+ title: this.removeTitle,
+ message: Strings.sharedRemoveConfirm,
+ buttons: Ext.Msg.YESNO,
+ buttonText: {
+ yes: Strings.sharedRemove,
+ no: Strings.sharedCancel
+ },
+ fn: function (btn) {
+ var store = objectInstance.store;
+ if (btn === 'yes') {
+ store.remove(objectInstance);
+ store.sync({
+ failure: function (batch) {
+ store.rejectChanges();
+ Traccar.app.showError(batch.exceptions[0].getError().response);
+ }
+ });
+ }
+ }
+ });
+ },
+
+ onSelectionChange: function (selection, selected) {
+ var disabled = selected.length === 0;
+ this.lookupReference('toolbarEditButton').setDisabled(disabled);
+ this.lookupReference('toolbarRemoveButton').setDisabled(disabled);
+ }
+});
diff --git a/legacy/web/app/view/edit/Users.js b/legacy/web/app/view/edit/Users.js
new file mode 100644
index 00000000..5d9a14f0
--- /dev/null
+++ b/legacy/web/app/view/edit/Users.js
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2018 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.Users', {
+ extend: 'Traccar.view.GridPanel',
+ xtype: 'usersView',
+
+ requires: [
+ 'Traccar.view.edit.UsersController',
+ 'Traccar.view.edit.Toolbar'
+ ],
+
+ controller: 'users',
+ store: 'Users',
+
+ tbar: {
+ xtype: 'editToolbar',
+ scrollable: true,
+ items: [{
+ disabled: true,
+ handler: 'onGeofencesClick',
+ reference: 'userGeofencesButton',
+ glyph: 'xf21d@FontAwesome',
+ tooltip: Strings.sharedGeofences,
+ tooltipType: 'title'
+ }, {
+ disabled: true,
+ handler: 'onDevicesClick',
+ reference: 'userDevicesButton',
+ glyph: 'xf248@FontAwesome',
+ tooltip: Strings.deviceTitle,
+ tooltipType: 'title'
+ }, {
+ disabled: true,
+ handler: 'onGroupsClick',
+ reference: 'userGroupsButton',
+ glyph: 'xf247@FontAwesome',
+ tooltip: Strings.settingsGroups,
+ tooltipType: 'title'
+ }, {
+ disabled: true,
+ handler: 'onUsersClick',
+ reference: 'userUsersButton',
+ glyph: 'xf0c0@FontAwesome',
+ tooltip: Strings.settingsUsers,
+ tooltipType: 'title'
+ }, {
+ disabled: true,
+ handler: 'onNotificationsClick',
+ reference: 'userNotificationsButton',
+ glyph: 'xf003@FontAwesome',
+ tooltip: Strings.sharedNotifications,
+ tooltipType: 'title'
+ }, {
+ disabled: true,
+ handler: 'onCalendarsClick',
+ reference: 'userCalendarsButton',
+ glyph: 'xf073@FontAwesome',
+ tooltip: Strings.sharedCalendars,
+ tooltipType: 'title'
+ }, {
+ disabled: true,
+ handler: 'onAttributesClick',
+ reference: 'userAttributesButton',
+ glyph: 'xf0ae@FontAwesome',
+ tooltip: Strings.sharedComputedAttributes,
+ tooltipType: 'title'
+ }, {
+ disabled: true,
+ handler: 'onDriversClick',
+ reference: 'userDriversButton',
+ glyph: 'xf084@FontAwesome',
+ tooltip: Strings.sharedDrivers,
+ tooltipType: 'title'
+ }, {
+ xtype: 'button',
+ disabled: true,
+ handler: 'onCommandsClick',
+ reference: 'userCommandsButton',
+ glyph: 'xf093@FontAwesome',
+ tooltip: Strings.sharedSavedCommands,
+ tooltipType: 'title'
+ }, {
+ xtype: 'button',
+ disabled: true,
+ handler: 'onMaintenancesClick',
+ reference: 'userMaintenancesButton',
+ glyph: 'xf0ad@FontAwesome',
+ tooltip: Strings.sharedMaintenance,
+ tooltipType: 'title'
+ }]
+ },
+
+ listeners: {
+ selectionchange: 'onSelectionChange'
+ },
+
+ columns: {
+ defaults: {
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal
+ },
+ items: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ filter: 'string'
+ }, {
+ text: Strings.userEmail,
+ dataIndex: 'email',
+ filter: 'string'
+ }, {
+ text: Strings.userAdmin,
+ dataIndex: 'administrator',
+ renderer: Traccar.AttributeFormatter.getFormatter('administrator'),
+ filter: 'boolean'
+ }, {
+ text: Strings.serverReadonly,
+ dataIndex: 'readonly',
+ hidden: true,
+ renderer: Traccar.AttributeFormatter.getFormatter('readonly'),
+ filter: 'boolean'
+ }, {
+ text: Strings.userDeviceReadonly,
+ dataIndex: 'deviceReadonly',
+ renderer: Traccar.AttributeFormatter.getFormatter('deviceReadonly'),
+ hidden: true,
+ filter: 'boolean'
+ }, {
+ text: Strings.sharedDisabled,
+ dataIndex: 'disabled',
+ renderer: Traccar.AttributeFormatter.getFormatter('disabled'),
+ filter: 'boolean'
+ }, {
+ text: Strings.userExpirationTime,
+ dataIndex: 'expirationTime',
+ hidden: true,
+ renderer: Traccar.AttributeFormatter.getFormatter('expirationTime'),
+ filter: 'date'
+ }]
+ }
+});
diff --git a/legacy/web/app/view/edit/UsersController.js b/legacy/web/app/view/edit/UsersController.js
new file mode 100644
index 00000000..9e810435
--- /dev/null
+++ b/legacy/web/app/view/edit/UsersController.js
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2015 - 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.UsersController', {
+ extend: 'Traccar.view.edit.ToolbarController',
+ alias: 'controller.users',
+
+ requires: [
+ 'Traccar.view.dialog.User',
+ 'Traccar.view.permissions.Devices',
+ 'Traccar.view.permissions.Groups',
+ 'Traccar.view.permissions.Geofences',
+ 'Traccar.view.permissions.Calendars',
+ 'Traccar.view.permissions.Users',
+ 'Traccar.view.permissions.ComputedAttributes',
+ 'Traccar.view.permissions.Drivers',
+ 'Traccar.view.permissions.SavedCommands',
+ 'Traccar.view.permissions.Notifications',
+ 'Traccar.view.permissions.Maintenances',
+ 'Traccar.view.BaseWindow',
+ 'Traccar.model.User'
+ ],
+
+ objectModel: 'Traccar.model.User',
+ objectDialog: 'Traccar.view.dialog.User',
+ removeTitle: Strings.settingsUser,
+
+ init: function () {
+ Ext.getStore('Users').load();
+ this.lookupReference('userUsersButton').setHidden(!Traccar.app.getUser().get('administrator'));
+ this.lookupReference('userDriversButton').setHidden(
+ Traccar.app.getVehicleFeaturesDisabled() || Traccar.app.getBooleanAttributePreference('ui.disableDrivers'));
+ this.lookupReference('userAttributesButton').setHidden(
+ Traccar.app.getBooleanAttributePreference('ui.disableComputedAttributes'));
+ this.lookupReference('userCalendarsButton').setHidden(
+ Traccar.app.getBooleanAttributePreference('ui.disableCalendars'));
+ this.lookupReference('userCommandsButton').setHidden(Traccar.app.getPreference('limitCommands', false));
+ this.lookupReference('userMaintenancesButton').setHidden(
+ Traccar.app.getVehicleFeaturesDisabled() || Traccar.app.getBooleanAttributePreference('ui.disableMaintenance'));
+ },
+
+ onEditClick: function () {
+ var dialog, user = this.getView().getSelectionModel().getSelection()[0];
+ dialog = Ext.create('Traccar.view.dialog.User', {
+ selfEdit: user.get('id') === Traccar.app.getUser().get('id')
+ });
+ dialog.down('form').loadRecord(user);
+ dialog.show();
+ },
+
+ onAddClick: function () {
+ var user, dialog;
+ user = Ext.create('Traccar.model.User');
+ if (Traccar.app.getUser().get('administrator')) {
+ user.set('deviceLimit', -1);
+ }
+ if (Traccar.app.getUser().get('expirationTime')) {
+ user.set('expirationTime', Traccar.app.getUser().get('expirationTime'));
+ }
+ dialog = Ext.create('Traccar.view.dialog.User');
+ dialog.down('form').loadRecord(user);
+ dialog.show();
+ },
+
+ onDevicesClick: function () {
+ var user = this.getView().getSelectionModel().getSelection()[0];
+ Ext.getStore('AllGroups').load();
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.deviceTitle,
+ items: {
+ xtype: 'linkDevicesView',
+ baseObjectName: 'userId',
+ linkObjectName: 'deviceId',
+ storeName: 'AllDevices',
+ linkStoreName: 'Devices',
+ baseObject: user.getId()
+ }
+ }).show();
+ },
+
+ onGroupsClick: function () {
+ var user = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.settingsGroups,
+ items: {
+ xtype: 'linkGroupsView',
+ baseObjectName: 'userId',
+ linkObjectName: 'groupId',
+ storeName: 'AllGroups',
+ linkStoreName: 'Groups',
+ baseObject: user.getId()
+ }
+ }).show();
+ },
+
+ onGeofencesClick: function () {
+ var user = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedGeofences,
+ items: {
+ xtype: 'linkGeofencesView',
+ baseObjectName: 'userId',
+ linkObjectName: 'geofenceId',
+ storeName: 'AllGeofences',
+ linkStoreName: 'Geofences',
+ baseObject: user.getId()
+ }
+ }).show();
+ },
+
+ onNotificationsClick: function () {
+ var user = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedNotifications,
+ items: {
+ xtype: 'linkNotificationsView',
+ baseObjectName: 'userId',
+ linkObjectName: 'notificationId',
+ storeName: 'AllNotifications',
+ linkStoreName: 'Notifications',
+ baseObject: user.getId()
+ }
+ }).show();
+ },
+
+ onCalendarsClick: function () {
+ var user = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedCalendars,
+ items: {
+ xtype: 'linkCalendarsView',
+ baseObjectName: 'userId',
+ linkObjectName: 'calendarId',
+ storeName: 'AllCalendars',
+ linkStoreName: 'Calendars',
+ baseObject: user.getId()
+ }
+ }).show();
+ },
+
+ onUsersClick: function () {
+ var user = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.settingsUsers,
+ items: {
+ xtype: 'linkUsersView',
+ baseObjectName: 'userId',
+ linkObjectName: 'managedUserId',
+ storeName: 'Users',
+ baseObject: user.getId()
+ }
+ }).show();
+ },
+
+ onAttributesClick: function () {
+ var user = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedComputedAttributes,
+ items: {
+ xtype: 'linkComputedAttributesView',
+ baseObjectName: 'userId',
+ linkObjectName: 'attributeId',
+ storeName: 'AllComputedAttributes',
+ linkStoreName: 'ComputedAttributes',
+ baseObject: user.getId()
+ }
+ }).show();
+ },
+
+ onDriversClick: function () {
+ var user = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedDrivers,
+ items: {
+ xtype: 'linkDriversView',
+ baseObjectName: 'userId',
+ linkObjectName: 'driverId',
+ storeName: 'AllDrivers',
+ linkStoreName: 'Drivers',
+ baseObject: user.getId()
+ }
+ }).show();
+ },
+
+ onCommandsClick: function () {
+ var user = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedSavedCommands,
+ items: {
+ xtype: 'linkSavedCommandsView',
+ baseObjectName: 'userId',
+ linkObjectName: 'commandId',
+ storeName: 'AllCommands',
+ linkStoreName: 'Commands',
+ baseObject: user.getId()
+ }
+ }).show();
+ },
+
+ onMaintenancesClick: function () {
+ var user = this.getView().getSelectionModel().getSelection()[0];
+ Ext.create('Traccar.view.BaseWindow', {
+ title: Strings.sharedMaintenance,
+ items: {
+ xtype: 'linkMaintenancesView',
+ baseObjectName: 'userId',
+ linkObjectName: 'maintenanceId',
+ storeName: 'AllMaintenances',
+ linkStoreName: 'Maintenances',
+ baseObject: user.getId()
+ }
+ }).show();
+ },
+
+ onSelectionChange: function (selection, selected) {
+ var disabled = selected.length === 0;
+ this.lookupReference('userDevicesButton').setDisabled(disabled);
+ this.lookupReference('userGroupsButton').setDisabled(disabled);
+ this.lookupReference('userGeofencesButton').setDisabled(disabled);
+ this.lookupReference('userNotificationsButton').setDisabled(disabled);
+ this.lookupReference('userCalendarsButton').setDisabled(disabled);
+ this.lookupReference('userAttributesButton').setDisabled(disabled);
+ this.lookupReference('userDriversButton').setDisabled(disabled);
+ this.lookupReference('userCommandsButton').setDisabled(disabled);
+ this.lookupReference('userMaintenancesButton').setDisabled(disabled);
+ this.lookupReference('userUsersButton').setDisabled(disabled || selected[0].get('userLimit') === 0);
+ this.callParent(arguments);
+ }
+});
diff --git a/legacy/web/app/view/map/BaseMap.js b/legacy/web/app/view/map/BaseMap.js
new file mode 100644
index 00000000..9192a53b
--- /dev/null
+++ b/legacy/web/app/view/map/BaseMap.js
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2016 - 2021 Anton Tananaev (anton@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.map.BaseMap', {
+ extend: 'Ext.panel.Panel',
+ xtype: 'baseMapView',
+
+ layout: 'fit',
+
+ getMap: function () {
+ return this.map;
+ },
+
+ getMapView: function () {
+ return this.mapView;
+ },
+
+ initMap: function () {
+ var server, layer, type, bingKey, locationIqKey, lat, lon, zoom, maxZoom, target, poiLayer, self = this;
+
+ server = Traccar.app.getServer();
+
+ type = Traccar.app.getPreference('map', null);
+ bingKey = server.get('bingKey');
+ locationIqKey = Traccar.app.getAttributePreference('locationIqKey', 'pk.0f147952a41c555a5b70614039fd148b');
+
+ layer = new ol.layer.Group({
+ title: Strings.mapLayer,
+ layers: [
+ new ol.layer.Tile({
+ title: Strings.mapCustom,
+ type: 'base',
+ visible: type === 'custom',
+ source: new ol.source.XYZ({
+ url: Ext.String.htmlDecode(server.get('mapUrl')),
+ attributions: ''
+ })
+ }),
+ new ol.layer.Tile({
+ title: Strings.mapCustomArcgis,
+ type: 'base',
+ visible: type === 'customArcgis',
+ source: new ol.source.TileArcGISRest({
+ url: Ext.String.htmlDecode(server.get('mapUrl'))
+ })
+ }),
+ new ol.layer.Tile({
+ title: Strings.mapBingRoad,
+ type: 'base',
+ visible: type === 'bingRoad',
+ source: new ol.source.BingMaps({
+ key: bingKey,
+ imagerySet: 'Road'
+ })
+ }),
+ new ol.layer.Tile({
+ title: Strings.mapBingAerial,
+ type: 'base',
+ visible: type === 'bingAerial',
+ source: new ol.source.BingMaps({
+ key: bingKey,
+ imagerySet: 'Aerial'
+ })
+ }),
+ new ol.layer.Tile({
+ title: Strings.mapBingHybrid,
+ type: 'base',
+ visible: type === 'bingHybrid',
+ source: new ol.source.BingMaps({
+ key: bingKey,
+ imagerySet: 'AerialWithLabels'
+ })
+ }),
+ new ol.layer.Tile({
+ title: Strings.mapCarto,
+ type: 'base',
+ visible: type === 'carto',
+ source: new ol.source.XYZ({
+ url: 'https://cartodb-basemaps-{a-d}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png',
+ attributions: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> ' +
+ 'contributors, &copy; <a href="https://carto.com/attributions">CARTO</a>'
+ })
+ }),
+ new ol.layer.Tile({
+ title: Strings.mapAutoNavi,
+ type: 'base',
+ visible: type === 'autoNavi' || type === 'baidu',
+ source: new ol.source.OSM({
+ url: 'https://webrd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}'
+ })
+ }),
+ new ol.layer.Tile({
+ title: Strings.mapYandexMap,
+ type: 'base',
+ visible: type === 'yandexMap',
+ source: new ol.source.XYZ({
+ url: 'https://core-renderer-tiles.maps.yandex.net/tiles?l=map&x={x}&y={y}&z={z}',
+ projection: 'EPSG:3395',
+ attributions: '&copy; <a href="https://yandex.com/maps/">Yandex</a>'
+ })
+ }),
+ new ol.layer.Tile({
+ title: Strings.mapYandexSat,
+ type: 'base',
+ visible: type === 'yandexSat',
+ source: new ol.source.XYZ({
+ url: 'https://core-sat.maps.yandex.net/tiles?l=sat&x={x}&y={y}&z={z}',
+ projection: 'EPSG:3395',
+ attributions: '&copy; <a href="https://yandex.com/maps/">Yandex</a>'
+ })
+ }),
+ new ol.layer.Tile({
+ title: Strings.mapOsm,
+ type: 'base',
+ visible: type === 'osm',
+ source: new ol.source.OSM({})
+ }),
+ new ol.layer.Tile({
+ title: Strings.mapLocationIqStreets,
+ type: 'base',
+ visible: type === 'locationIqStreets' || type === 'wikimedia' || !type,
+ source: new ol.source.XYZ({
+ url: 'https://{a-c}-tiles.locationiq.com/v3/streets/r/{z}/{x}/{y}.png?key=' + locationIqKey,
+ attributions: '&copy; <a href="https://locationiq.com/">LocationIQ</a>'
+ })
+ })
+ ]
+ });
+
+ lat = Traccar.app.getPreference('latitude', Traccar.Style.mapDefaultLat);
+ lon = Traccar.app.getPreference('longitude', Traccar.Style.mapDefaultLon);
+ zoom = Traccar.app.getPreference('zoom', Traccar.Style.mapDefaultZoom);
+ maxZoom = Traccar.app.getAttributePreference('web.maxZoom', Traccar.Style.mapMaxZoom);
+
+ this.mapView = new ol.View({
+ center: ol.proj.fromLonLat([lon, lat]),
+ zoom: zoom,
+ maxZoom: maxZoom
+ });
+
+ this.map = new ol.Map({
+ target: this.body.dom.id,
+ layers: [layer],
+ view: this.mapView
+ });
+
+ poiLayer = Traccar.app.getPreference('poiLayer', null);
+
+ if (poiLayer) {
+ this.map.addLayer(new ol.layer.Vector({
+ source: new ol.source.Vector({
+ url: poiLayer,
+ format: new ol.format.KML()
+ })
+ }));
+ }
+
+ switch (Traccar.app.getAttributePreference('distanceUnit', 'km')) {
+ case 'mi':
+ this.map.addControl(new ol.control.ScaleLine({
+ units: 'us'
+ }));
+ break;
+ case 'nmi':
+ this.map.addControl(new ol.control.ScaleLine({
+ units: 'nautical'
+ }));
+ break;
+ default:
+ this.map.addControl(new ol.control.ScaleLine());
+ break;
+ }
+
+ this.map.addControl(new ol.control.LayerSwitcher());
+
+ target = this.map.getTarget();
+ if (typeof target === 'string') {
+ target = Ext.get(target).dom;
+ }
+
+ this.map.on('pointermove', function (e) {
+ var hit = this.forEachFeatureAtPixel(e.pixel, function () {
+ return true;
+ });
+ if (hit) {
+ target.style.cursor = 'pointer';
+ } else {
+ target.style.cursor = '';
+ }
+ });
+
+ this.map.on('click', function (e) {
+ var i, features = self.map.getFeaturesAtPixel(e.pixel, {
+ layerFilter: function (layer) {
+ return !layer.get('name');
+ }
+ });
+ if (features) {
+ for (i = 0; i < features.length; i++) {
+ self.fireEvent('selectfeature', features[i]);
+ }
+ } else {
+ self.fireEvent('deselectfeature');
+ }
+ });
+
+ this.map.once('postrender', function () {
+ self.fireEvent('mapready');
+ });
+ },
+
+ listeners: {
+ afterrender: function () {
+ this.initMap();
+ },
+
+ resize: function () {
+ this.map.updateSize();
+ }
+ }
+}, function () {
+ var projection;
+ proj4.defs('EPSG:3395', '+proj=merc +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs');
+ ol.proj.proj4.register(proj4);
+ projection = ol.proj.get('EPSG:3395');
+ if (projection) {
+ projection.setExtent([-20037508.342789244, -20037508.342789244, 20037508.342789244, 20037508.342789244]);
+ }
+});
diff --git a/legacy/web/app/view/map/GeofenceMap.js b/legacy/web/app/view/map/GeofenceMap.js
new file mode 100644
index 00000000..cc1b7efe
--- /dev/null
+++ b/legacy/web/app/view/map/GeofenceMap.js
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2016 - 2021 Anton Tananaev (anton@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.map.GeofenceMap', {
+ extend: 'Traccar.view.map.BaseMap',
+ xtype: 'geofenceMapView',
+
+ requires: [
+ 'Traccar.view.map.GeofenceMapController',
+ 'Traccar.GeofenceConverter'
+ ],
+
+ controller: 'geofenceMap',
+ bodyBorder: true,
+
+ tbar: {
+ items: [{
+ xtype: 'combobox',
+ store: 'GeofenceTypes',
+ valueField: 'key',
+ displayField: 'name',
+ editable: false,
+ listeners: {
+ select: 'onTypeSelect'
+ }
+ }, '-', {
+ xtype: 'tbtext',
+ html: Strings.sharedImport
+ }, {
+ xtype: 'filefield',
+ name: 'file',
+ buttonConfig: {
+ glyph: 'xf093@FontAwesome',
+ text: '',
+ tooltip: Strings.sharedSelectFile,
+ tooltipType: 'title'
+ },
+ listeners: {
+ change: 'onFileChange',
+ afterrender: function (fileField) {
+ fileField.fileInputEl.set({
+ accept: '.gpx'
+ });
+ }
+ }
+ }, {
+ xtype: 'tbfill'
+ }, {
+ glyph: 'xf00c@FontAwesome',
+ tooltip: Strings.sharedSave,
+ tooltipType: 'title',
+ minWidth: 0,
+ handler: 'onSaveClick'
+ }, {
+ glyph: 'xf00d@FontAwesome',
+ tooltip: Strings.sharedCancel,
+ tooltipType: 'title',
+ minWidth: 0,
+ handler: 'onCancelClick'
+ }]
+ },
+
+ getFeatures: function () {
+ return this.features;
+ },
+
+ initMap: function () {
+ var map, mapView, featureOverlay, geometry, fillColor;
+ this.callParent();
+
+ map = this.map;
+ mapView = this.mapView;
+
+ this.features = new ol.Collection();
+ if (this.area) {
+ geometry = Traccar.GeofenceConverter.wktToGeometry(mapView, this.area);
+ this.features.push(new ol.Feature(geometry));
+ this.map.once('postrender', function () {
+ mapView.fit(geometry, {
+ padding: [20, 20, 20, 20]
+ });
+ });
+ } else {
+ this.controller.fireEvent('mapstaterequest');
+ }
+ fillColor = ol.color.asArray(Traccar.Style.mapGeofenceColor);
+ fillColor[3] = Traccar.Style.mapGeofenceOverlayOpacity;
+ featureOverlay = new ol.layer.Vector({
+ source: new ol.source.Vector({
+ features: this.features
+ }),
+ style: new ol.style.Style({
+ fill: new ol.style.Fill({
+ color: fillColor
+ }),
+ stroke: new ol.style.Stroke({
+ color: Traccar.Style.mapGeofenceColor,
+ width: Traccar.Style.mapGeofenceWidth
+ }),
+ image: new ol.style.Circle({
+ radius: Traccar.Style.mapGeofenceRadius,
+ fill: new ol.style.Fill({
+ color: Traccar.Style.mapGeofenceColor
+ })
+ })
+ })
+ });
+ featureOverlay.setMap(map);
+
+ map.addInteraction(new ol.interaction.Modify({
+ features: this.features,
+ deleteCondition: function (event) {
+ return ol.events.condition.shiftKeyOnly(event) && ol.events.condition.singleClick(event);
+ }
+ }));
+ },
+
+ addInteraction: function (type) {
+ var self = this;
+ this.draw = new ol.interaction.Draw({
+ features: this.features,
+ type: type
+ });
+ this.draw.on('drawstart', function () {
+ self.features.clear();
+ });
+ this.map.addInteraction(this.draw);
+ },
+
+ removeInteraction: function () {
+ if (this.draw) {
+ this.map.removeInteraction(this.draw);
+ this.draw = null;
+ }
+ }
+});
diff --git a/legacy/web/app/view/map/GeofenceMapController.js b/legacy/web/app/view/map/GeofenceMapController.js
new file mode 100644
index 00000000..31ab586c
--- /dev/null
+++ b/legacy/web/app/view/map/GeofenceMapController.js
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@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.map.GeofenceMapController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.geofenceMap',
+
+ requires: [
+ 'Traccar.GeofenceConverter'
+ ],
+
+ config: {
+ listen: {
+ controller: {
+ '*': {
+ mapstate: 'setMapState'
+ }
+ }
+ }
+ },
+
+ onFileChange: function (fileField) {
+ var reader, view = this.getView();
+ if (fileField.fileInputEl.dom.files.length > 0) {
+ reader = new FileReader();
+ reader.onload = function () {
+ var parser, xml, segment, projection, points = [];
+ parser = new DOMParser();
+ xml = parser.parseFromString(reader.result, 'text/xml');
+ segment = xml.getElementsByTagName('trkseg')[0];
+ projection = view.mapView.getProjection();
+ Array.from(segment.getElementsByTagName('trkpt')).forEach(function (point) {
+ var lat, lon;
+ lat = Number(point.getAttribute('lat'));
+ lon = Number(point.getAttribute('lon'));
+ points.push(ol.proj.transform([lon, lat], 'EPSG:4326', projection));
+ });
+ view.getFeatures().clear();
+ view.getFeatures().push(new ol.Feature(new ol.geom.LineString(points)));
+ };
+ reader.onerror = function (event) {
+ Traccar.app.showError(event.target.error);
+ };
+ reader.readAsText(fileField.fileInputEl.dom.files[0]);
+ }
+ },
+
+ onSaveClick: function (button) {
+ var geometry, projection;
+ if (this.getView().getFeatures().getLength() > 0) {
+ geometry = this.getView().getFeatures().pop().getGeometry();
+ projection = this.getView().getMapView().getProjection();
+ this.fireEvent('savearea', Traccar.GeofenceConverter.geometryToWkt(projection, geometry));
+ button.up('window').close();
+ }
+ },
+
+ onCancelClick: function (button) {
+ button.up('window').close();
+ },
+
+ onTypeSelect: function (combo) {
+ this.getView().removeInteraction();
+ this.getView().addInteraction(combo.getValue());
+ },
+
+ setMapState: function (lat, lon, zoom) {
+ this.getView().getMapView().setCenter(ol.proj.fromLonLat([lon, lat]));
+ this.getView().getMapView().setZoom(zoom);
+ }
+});
diff --git a/legacy/web/app/view/map/Map.js b/legacy/web/app/view/map/Map.js
new file mode 100644
index 00000000..36e81de7
--- /dev/null
+++ b/legacy/web/app/view/map/Map.js
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.map.Map', {
+ extend: 'Traccar.view.map.BaseMap',
+ xtype: 'mapView',
+
+ requires: [
+ 'Traccar.view.map.MapController',
+ 'Traccar.view.SettingsMenu'
+ ],
+
+ controller: 'map',
+
+ title: Strings.mapTitle,
+ tbar: {
+ componentCls: 'toolbar-header-style',
+ defaults: {
+ xtype: 'button',
+ tooltipType: 'title',
+ stateEvents: ['toggle'],
+ enableToggle: true,
+ stateful: {
+ pressed: true
+ }
+ },
+ items: [{
+ xtype: 'tbtext',
+ html: Strings.mapTitle,
+ baseCls: 'x-panel-header-title-default'
+ }, {
+ xtype: 'tbfill'
+ }, {
+ handler: 'showReports',
+ reference: 'showReportsButton',
+ glyph: 'xf0f6@FontAwesome',
+ stateful: false,
+ enableToggle: false,
+ tooltip: Strings.reportTitle
+ }, {
+ handler: 'showEvents',
+ reference: 'showEventsButton',
+ glyph: 'xf27b@FontAwesome',
+ stateful: false,
+ enableToggle: false,
+ tooltip: Strings.reportEvents
+ }, {
+ handler: 'updateGeofences',
+ reference: 'showGeofencesButton',
+ glyph: 'xf21d@FontAwesome',
+ pressed: true,
+ stateId: 'show-geofences-button',
+ tooltip: Strings.sharedGeofences
+ }, {
+ handler: 'showAccuracy',
+ reference: 'showAccuracyButton',
+ glyph: 'xf140@FontAwesome',
+ pressed: true,
+ stateId: 'show-accuracy-button',
+ tooltip: Strings.positionAccuracy
+ }, {
+ handler: 'showCurrentLocation',
+ glyph: 'xf124@FontAwesome',
+ tooltip: Strings.mapCurrentLocation
+ }, {
+ handler: 'showLiveRoutes',
+ reference: 'showLiveRoutes',
+ glyph: 'xf1b0@FontAwesome',
+ stateId: 'show-live-routes-button',
+ tooltip: Strings.mapLiveRoutes
+ }, {
+ reference: 'deviceFollowButton',
+ glyph: 'xf05b@FontAwesome',
+ tooltip: Strings.deviceFollow,
+ stateId: 'device-follow-button',
+ toggleHandler: 'onFollowClick'
+ }, {
+ xtype: 'settingsMenu',
+ enableToggle: false
+ }]
+ },
+
+ getMarkersSource: function () {
+ return this.markersSource;
+ },
+
+ getAccuracySource: function () {
+ return this.accuracySource;
+ },
+
+ getAccuracyLayer: function () {
+ return this.accuracyLayer;
+ },
+
+ getRouteSource: function () {
+ return this.routeSource;
+ },
+
+ getGeofencesSource: function () {
+ return this.geofencesSource;
+ },
+
+ getLiveRouteSource: function () {
+ return this.liveRouteSource;
+ },
+
+ getLiveRouteLayer: function () {
+ return this.liveRouteLayer;
+ },
+
+ initMap: function () {
+ this.callParent();
+
+ this.geofencesSource = new ol.source.Vector({});
+ this.map.addLayer(new ol.layer.Vector({
+ name: 'geofencesLayer',
+ source: this.geofencesSource
+ }));
+
+ this.liveRouteSource = new ol.source.Vector({});
+ this.liveRouteLayer = new ol.layer.Vector({
+ source: this.liveRouteSource,
+ visible: this.lookupReference('showLiveRoutes').pressed
+ });
+ this.map.addLayer(this.liveRouteLayer);
+
+ this.routeSource = new ol.source.Vector({});
+ this.map.addLayer(new ol.layer.Vector({
+ source: this.routeSource
+ }));
+
+ this.accuracySource = new ol.source.Vector({});
+ this.accuracyLayer = new ol.layer.Vector({
+ name: 'accuracyLayer',
+ source: this.accuracySource
+ });
+ this.map.addLayer(this.accuracyLayer);
+
+ this.markersSource = new ol.source.Vector({});
+ this.map.addLayer(new ol.layer.Vector({
+ source: this.markersSource
+ }));
+ }
+});
diff --git a/legacy/web/app/view/map/MapController.js b/legacy/web/app/view/map/MapController.js
new file mode 100644
index 00000000..f6d88eed
--- /dev/null
+++ b/legacy/web/app/view/map/MapController.js
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2015 - 2022 Anton Tananaev (anton@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.map.MapController', {
+ extend: 'Traccar.view.map.MapMarkerController',
+ alias: 'controller.map',
+
+ requires: [
+ 'Traccar.GeofenceConverter'
+ ],
+
+ config: {
+ listen: {
+ controller: {
+ '*': {
+ mapstaterequest: 'getMapState',
+ zoomtoalldevices: 'zoomToAllDevices'
+ }
+ },
+ store: {
+ '#Geofences': {
+ load: 'updateGeofences',
+ add: 'updateGeofences',
+ update: 'updateGeofences',
+ remove: 'updateGeofences'
+ }
+ }
+ }
+ },
+
+ init: function () {
+ this.callParent();
+ this.lookupReference('showReportsButton').setVisible(
+ Traccar.app.isMobile() && !Traccar.app.getPreference('disableReports', false));
+ this.lookupReference('showEventsButton').setVisible(
+ Traccar.app.isMobile() && !Traccar.app.getBooleanAttributePreference('ui.disableEvents'));
+ },
+
+ showReports: function () {
+ Traccar.app.showReports(true);
+ },
+
+ showEvents: function () {
+ Traccar.app.showEvents(true);
+ },
+
+ onFollowClick: function (button, pressed) {
+ if (pressed && this.selectedMarker) {
+ this.getView().getMapView().setCenter(this.selectedMarker.getGeometry().getCoordinates());
+ }
+ },
+
+ showLiveRoutes: function (button) {
+ this.getView().getLiveRouteLayer().setVisible(button.pressed);
+ },
+
+ showAccuracy: function (button) {
+ this.getView().getAccuracyLayer().setVisible(button.pressed);
+ },
+
+ getMapState: function () {
+ var zoom, center, projection;
+ projection = this.getView().getMapView().getProjection();
+ center = ol.proj.transform(this.getView().getMapView().getCenter(), projection, 'EPSG:4326');
+ zoom = this.getView().getMapView().getZoom();
+ this.fireEvent('mapstate', center[1], center[0], zoom);
+ },
+
+ updateGeofences: function () {
+ this.getView().getGeofencesSource().clear();
+ if (this.lookupReference('showGeofencesButton').pressed) {
+ Ext.getStore('Geofences').each(function (geofence) {
+ var feature = new ol.Feature(
+ Traccar.GeofenceConverter.wktToGeometry(this.getView().getMapView(), geofence.get('area')));
+ feature.setStyle(this.getAreaStyle(
+ Ext.String.htmlDecode(geofence.get('name')),
+ geofence.get('attributes') ? geofence.get('attributes').color : null));
+ this.getView().getGeofencesSource().addFeature(feature);
+ return true;
+ }, this);
+ }
+ },
+
+ zoomToAllDevices: function () {
+ this.zoomToAllPositions(Ext.getStore('LatestPositions').getData().items);
+ }
+});
diff --git a/legacy/web/app/view/map/MapMarkerController.js b/legacy/web/app/view/map/MapMarkerController.js
new file mode 100644
index 00000000..2fef4870
--- /dev/null
+++ b/legacy/web/app/view/map/MapMarkerController.js
@@ -0,0 +1,687 @@
+/*
+ * Copyright 2015 - 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.map.MapMarkerController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.mapMarker',
+
+ requires: [
+ 'Traccar.model.Position',
+ 'Traccar.model.Device',
+ 'Traccar.DeviceImages'
+ ],
+
+ config: {
+ listen: {
+ controller: {
+ '*': {
+ selectdevice: 'selectDevice',
+ selectreport: 'selectReport',
+ selectevent: 'selectEvent'
+ },
+ 'devices': {
+ deselectfeature: 'deselectDevice'
+ }
+ },
+ store: {
+ '#Devices': {
+ add: 'updateDevice',
+ update: 'updateDevice',
+ remove: 'removeDevice'
+ },
+ '#VisibleDevices': {
+ add: 'updateVisibleDevices',
+ update: 'updateVisibleDevices',
+ remove: 'updateVisibleDevices',
+ refresh: 'filterDevices'
+ },
+ '#LatestPositions': {
+ add: 'updateLatest',
+ update: 'updateLatest'
+ },
+ '#ReportRoute': {
+ add: 'addReportMarkers',
+ load: 'loadReport',
+ clear: 'clearReport'
+ },
+ '#Events': {
+ remove: 'clearEvent',
+ clear: 'clearEvent'
+ }
+ },
+ component: {
+ '#': {
+ mapready: 'initGeolocation',
+ selectfeature: 'selectFeature',
+ deselectfeature: 'deselectFeature'
+ }
+ }
+ }
+ },
+
+ init: function () {
+ this.latestMarkers = {};
+ this.reportMarkers = {};
+ this.accuracyCircles = {};
+ this.liveRoutes = {};
+ this.liveRouteLength = Traccar.app.getAttributePreference('web.liveRouteLength', 10);
+ this.selectZoom = Traccar.app.getAttributePreference('web.selectZoom', 0);
+ },
+
+ initGeolocation: function () {
+ var geolocation, accuracyFeature, positionFeature;
+
+ geolocation = new ol.Geolocation({
+ trackingOptions: {
+ enableHighAccuracy: true
+ },
+ projection: this.getView().getMapView().getProjection()
+ });
+
+ geolocation.on('error', function (error) {
+ Traccar.app.showError(error.message);
+ });
+
+ accuracyFeature = new ol.Feature();
+ geolocation.on('change:accuracyGeometry', function () {
+ accuracyFeature.setGeometry(geolocation.getAccuracyGeometry());
+ });
+
+ positionFeature = new ol.Feature();
+ positionFeature.setStyle(new ol.style.Style({
+ image: new ol.style.Circle({
+ radius: 6,
+ fill: new ol.style.Fill({
+ color: '#3399CC'
+ }),
+ stroke: new ol.style.Stroke({
+ color: '#fff',
+ width: 2
+ })
+ })
+ }));
+
+ geolocation.on('change:position', function () {
+ var coordinates = geolocation.getPosition();
+ positionFeature.setGeometry(coordinates ? new ol.geom.Point(coordinates) : null);
+ });
+
+ this.getView().getAccuracySource().addFeature(accuracyFeature);
+ this.getView().getMarkersSource().addFeature(positionFeature);
+
+ this.geolocation = geolocation;
+ },
+
+ showCurrentLocation: function (view) {
+ this.geolocation.setTracking(view.pressed);
+ },
+
+ getAreaStyle: function (label, color) {
+ var fillColor, strokeColor, styleConfig;
+ if (color) {
+ fillColor = ol.color.asArray(color);
+ strokeColor = color;
+ } else {
+ fillColor = ol.color.asArray(Traccar.Style.mapGeofenceColor);
+ strokeColor = Traccar.Style.mapGeofenceColor;
+ }
+ fillColor[3] = Traccar.Style.mapGeofenceOverlayOpacity;
+ styleConfig = {
+ fill: new ol.style.Fill({
+ color: fillColor
+ }),
+ stroke: new ol.style.Stroke({
+ color: strokeColor,
+ width: Traccar.Style.mapGeofenceWidth
+ })
+ };
+ if (label) {
+ styleConfig.text = new ol.style.Text({
+ text: label,
+ overflow: true,
+ fill: new ol.style.Fill({
+ color: Traccar.Style.mapGeofenceTextColor
+ }),
+ stroke: new ol.style.Stroke({
+ color: Traccar.Style.mapTextStrokeColor,
+ width: Traccar.Style.mapTextStrokeWidth
+ }),
+ font: Traccar.Style.mapTextFont
+ });
+ }
+ return new ol.style.Style(styleConfig);
+ },
+
+ getDeviceColor: function (device) {
+ switch (device.get('status')) {
+ case 'online':
+ return Traccar.Style.mapColorOnline;
+ case 'offline':
+ return Traccar.Style.mapColorOffline;
+ default:
+ return Traccar.Style.mapColorUnknown;
+ }
+ },
+
+ updateDevice: function (store, data) {
+ var i, device, deviceId, deviceName, marker, style;
+
+ if (!Ext.isArray(data)) {
+ data = [data];
+ }
+
+ for (i = 0; i < data.length; i++) {
+ device = data[i];
+ deviceId = device.get('id');
+
+ if (deviceId in this.latestMarkers) {
+ marker = this.latestMarkers[deviceId];
+ style = marker.getStyle();
+ if (style.getImage().fill !== this.getDeviceColor(device) ||
+ style.getImage().category !== device.get('category')) {
+ this.updateDeviceMarker(style, this.getDeviceColor(device), device.get('category'));
+ marker.changed();
+ }
+ deviceName = Ext.String.htmlDecode(device.get('name'));
+ if (style.getText().getText() !== deviceName) {
+ style.getText().setText(deviceName);
+ marker.changed();
+ }
+ }
+ }
+ },
+
+ removeDevice: function (store, data) {
+ var i, deviceId, markersSource;
+ if (!Ext.isArray(data)) {
+ data = [data];
+ }
+
+ markersSource = this.getView().getMarkersSource();
+
+ for (i = 0; i < data.length; i++) {
+ deviceId = data[i].get('id');
+ if (this.latestMarkers[deviceId]) {
+ if (markersSource.getFeatureById(this.latestMarkers[deviceId].getId())) {
+ markersSource.removeFeature(this.latestMarkers[deviceId]);
+ }
+ delete this.latestMarkers[deviceId];
+ }
+ if (this.accuracyCircles[deviceId]) {
+ if (markersSource.getFeatureById(this.accuracyCircles[deviceId].getId())) {
+ markersSource.removeFeature(this.accuracyCircles[deviceId]);
+ }
+ delete this.accuracyCircles[deviceId];
+ }
+ if (this.liveRoutes[deviceId]) {
+ if (markersSource.getFeatureById(this.liveRoutes[deviceId].getId())) {
+ markersSource.removeFeature(this.liveRoutes[deviceId]);
+ }
+ delete this.liveRoutes[deviceId];
+ }
+ }
+ },
+
+ animateMarker: function (marker, geometry, course) {
+ var start, end, duration, timeout, line, updatePosition, self, follow;
+
+ start = marker.getGeometry().getCoordinates();
+ end = geometry.getCoordinates();
+ line = new ol.geom.LineString([start, end]);
+ duration = Traccar.Style.mapAnimateMarkerDuration;
+ timeout = Traccar.Style.mapAnimateMarkerTimeout;
+ self = this;
+ follow = this.lookupReference('deviceFollowButton').pressed;
+
+ updatePosition = function (position, marker) {
+ var coordinate, style;
+ coordinate = marker.get('line').getCoordinateAt(position / (duration / timeout));
+ style = marker.getStyle();
+ marker.setGeometry(new ol.geom.Point(coordinate));
+ if (marker === self.selectedMarker && follow) {
+ self.getView().getMapView().setCenter(marker.getGeometry().getCoordinates());
+ }
+ if (position < duration / timeout) {
+ setTimeout(updatePosition, timeout, position + 1, marker);
+ } else {
+ if (style.getImage().angle !== marker.get('nextCourse')) {
+ self.rotateMarker(style, marker.get('nextCourse'));
+ }
+ marker.set('animating', false);
+ }
+ };
+
+ marker.set('line', line);
+ marker.set('nextCourse', course);
+ if (!marker.get('animating')) {
+ marker.set('animating', true);
+ updatePosition(1, marker);
+ }
+ },
+
+ updateLatest: function (store, data) {
+ var i, position, device, deviceStore;
+
+ if (!Ext.isArray(data)) {
+ data = [data];
+ }
+
+ deviceStore = Ext.getStore('Devices');
+
+ for (i = 0; i < data.length; i++) {
+ position = data[i];
+ device = deviceStore.getById(position.get('deviceId'));
+
+ if (device) {
+ this.updateAccuracy(position, device);
+ this.updateLatestMarker(position, device);
+ this.updateLiveRoute(position, device);
+ }
+ }
+ },
+
+ updateAccuracy: function (position, device) {
+ var center, radius, feature;
+ feature = this.accuracyCircles[position.get('deviceId')];
+
+ if (position.get('accuracy')) {
+ center = ol.proj.fromLonLat([position.get('longitude'), position.get('latitude')]);
+ radius = Ext.getStore('DistanceUnits').convertValue(
+ position.get('accuracy'), Traccar.app.getAttributePreference('distanceUnit'), true);
+
+ if (feature) {
+ feature.getGeometry().setCenter(center);
+ feature.getGeometry().setRadius(radius);
+ } else {
+ feature = new ol.Feature(new ol.geom.Circle(center, radius));
+ feature.setStyle(this.getAreaStyle(null, Traccar.Style.mapAccuracyColor));
+ feature.setId(position.get('deviceId'));
+ this.accuracyCircles[position.get('deviceId')] = feature;
+ if (this.isDeviceVisible(device)) {
+ this.getView().getAccuracySource().addFeature(feature);
+ }
+ }
+ } else {
+ if (feature && this.getView().getAccuracySource().getFeatureById(feature.getId())) {
+ this.getView().getAccuracySource().removeFeature(feature);
+ }
+ delete this.accuracyCircles[position.get('deviceId')];
+ }
+ },
+
+ updateLatestMarker: function (position, device) {
+ var geometry, deviceId, marker, style;
+ geometry = new ol.geom.Point(ol.proj.fromLonLat([
+ position.get('longitude'),
+ position.get('latitude')
+ ]));
+ deviceId = position.get('deviceId');
+ if (deviceId in this.latestMarkers) {
+ marker = this.latestMarkers[deviceId];
+ this.animateMarker(marker, geometry, position.get('course'));
+ } else {
+ marker = new ol.Feature(geometry);
+ marker.set('record', device);
+
+ style = this.getLatestMarker(this.getDeviceColor(device),
+ position.get('course'),
+ device.get('category'));
+ style.getText().setText(Ext.String.htmlDecode(device.get('name')));
+ marker.setStyle(style);
+ marker.setId(device.get('id'));
+ this.latestMarkers[deviceId] = marker;
+ if (this.isDeviceVisible(device)) {
+ this.getView().getMarkersSource().addFeature(marker);
+ }
+ if (marker === this.selectedMarker && this.lookupReference('deviceFollowButton').pressed) {
+ this.getView().getMapView().setCenter(marker.getGeometry().getCoordinates());
+ }
+ }
+ },
+
+ updateLiveRoute: function (position, device) {
+ var deviceId, liveLine, liveCoordinates, lastLiveCoordinates, newCoordinates;
+ deviceId = position.get('deviceId');
+ if (deviceId in this.liveRoutes) {
+ liveCoordinates = this.liveRoutes[deviceId].getGeometry().getCoordinates();
+ lastLiveCoordinates = liveCoordinates[liveCoordinates.length - 1];
+ newCoordinates = ol.proj.fromLonLat([position.get('longitude'), position.get('latitude')]);
+ if (lastLiveCoordinates[0] === newCoordinates[0] &&
+ lastLiveCoordinates[1] === newCoordinates[1]) {
+ return;
+ }
+ if (liveCoordinates.length >= this.liveRouteLength) {
+ liveCoordinates.shift();
+ }
+ liveCoordinates.push(newCoordinates);
+ this.liveRoutes[deviceId].getGeometry().setCoordinates(liveCoordinates);
+ } else {
+ liveLine = new ol.Feature({
+ geometry: new ol.geom.LineString([
+ ol.proj.fromLonLat([
+ position.get('longitude'),
+ position.get('latitude')
+ ])
+ ])
+ });
+ liveLine.setStyle(this.getRouteStyle(deviceId));
+ liveLine.setId(deviceId);
+ this.liveRoutes[deviceId] = liveLine;
+ if (this.isDeviceVisible(device)) {
+ this.getView().getMarkersSource().addFeature(liveLine);
+ }
+ }
+ },
+
+ loadReport: function (store, data) {
+ var i, position, point, routeSource;
+ if (data) {
+ this.addReportMarkers(store, data);
+ routeSource = this.getView().getRouteSource();
+
+ this.reportRoute = [];
+ for (i = 0; i < data.length; i++) {
+ position = data[i];
+ point = ol.proj.fromLonLat([
+ position.get('longitude'),
+ position.get('latitude')
+ ]);
+ if (i === 0 || data[i].get('deviceId') !== data[i - 1].get('deviceId')) {
+ this.reportRoute.push(new ol.Feature({
+ geometry: new ol.geom.LineString([])
+ }));
+ this.reportRoute[this.reportRoute.length - 1].setStyle(this.getRouteStyle(data[i].get('deviceId')));
+ routeSource.addFeature(this.reportRoute[this.reportRoute.length - 1]);
+ }
+ this.reportRoute[this.reportRoute.length - 1].getGeometry().appendCoordinate(point);
+ }
+ }
+ },
+
+ addReportMarker: function (position) {
+ var geometry, marker, style, point = ol.proj.fromLonLat([
+ position.get('longitude'),
+ position.get('latitude')
+ ]);
+ geometry = new ol.geom.Point(point);
+ marker = new ol.Feature(geometry);
+ marker.set('record', position);
+ style = this.getReportMarker(position.get('deviceId'), position.get('course'));
+ marker.setStyle(style);
+ this.getView().getMarkersSource().addFeature(marker);
+ return marker;
+ },
+
+ addReportMarkers: function (store, data) {
+ var i;
+ this.clearReport();
+ for (i = 0; i < data.length; i++) {
+ if (store.showMarkers) {
+ this.reportMarkers[data[i].get('id')] = this.addReportMarker(data[i]);
+ }
+ }
+ this.zoomToAllPositions(data);
+ },
+
+ clearReport: function () {
+ var key, i, reportSource, markersSource;
+
+ reportSource = this.getView().getRouteSource();
+
+ if (this.reportRoute) {
+ for (i = 0; i < this.reportRoute.length; i++) {
+ reportSource.removeFeature(this.reportRoute[i]);
+ }
+ this.reportRoute = null;
+ }
+
+ if (this.reportMarkers) {
+ markersSource = this.getView().getMarkersSource();
+ for (key in this.reportMarkers) {
+ if (this.reportMarkers.hasOwnProperty(key)) {
+ markersSource.removeFeature(this.reportMarkers[key]);
+ }
+ }
+ this.reportMarkers = {};
+ }
+
+ if (this.selectedMarker && !this.selectedMarker.get('event') &&
+ this.selectedMarker.get('record') instanceof Traccar.model.Position) {
+ this.selectedMarker = null;
+ }
+ },
+
+ clearEvent: function () {
+ if (this.selectedMarker && this.selectedMarker.get('event')) {
+ this.selectMarker(null, false);
+ }
+ },
+
+ getRouteStyle: function (deviceId) {
+ return new ol.style.Style({
+ stroke: new ol.style.Stroke({
+ color: Traccar.app.getReportColor(deviceId),
+ width: Traccar.Style.mapRouteWidth
+ })
+ });
+ },
+
+ getMarkerStyle: function (zoom, color, angle, category) {
+ var image = Traccar.DeviceImages.getImageIcon(color, zoom, angle, category);
+ return new ol.style.Style({
+ image: image,
+ text: new ol.style.Text({
+ textBaseline: 'bottom',
+ fill: new ol.style.Fill({
+ color: Traccar.Style.mapTextColor
+ }),
+ stroke: new ol.style.Stroke({
+ color: Traccar.Style.mapTextStrokeColor,
+ width: Traccar.Style.mapTextStrokeWidth
+ }),
+ offsetY: -image.getSize()[1] / 2 - Traccar.Style.mapTextOffset,
+ font: Traccar.Style.mapTextFont
+ })
+ });
+ },
+
+ getLatestMarker: function (color, angle, category) {
+ return this.getMarkerStyle(false, color, angle, category);
+ },
+
+ getReportMarker: function (deviceId, angle) {
+ return this.getMarkerStyle(false, Traccar.app.getReportColor(deviceId), angle, 'arrow');
+ },
+
+ resizeMarker: function (style, zoom) {
+ var image, text;
+ image = Traccar.DeviceImages.getImageIcon(
+ style.getImage().fill, zoom, style.getImage().angle, style.getImage().category);
+ text = style.getText();
+ text.setOffsetY(-image.getSize()[1] / 2 - Traccar.Style.mapTextOffset);
+ style.setText(text);
+ style.setImage(image);
+ },
+
+ rotateMarker: function (style, angle) {
+ style.setImage(Traccar.DeviceImages.getImageIcon(
+ style.getImage().fill, style.getImage().zoom, angle, style.getImage().category));
+ },
+
+ updateDeviceMarker: function (style, color, category) {
+ var image, text;
+ image = Traccar.DeviceImages.getImageIcon(
+ color, style.getImage().zoom, style.getImage().angle, category);
+ text = style.getText();
+ text.setOffsetY(-image.getSize()[1] / 2 - Traccar.Style.mapTextOffset);
+ style.setText(text);
+ style.setImage(image);
+ },
+
+ selectMarker: function (marker, center) {
+ if (this.selectedMarker) {
+ if (this.selectedMarker.get('event')) {
+ this.getView().getMarkersSource().removeFeature(this.selectedMarker);
+ } else if (!Ext.getStore('ReportRoute').showMarkers &&
+ this.selectedMarker.get('record') instanceof Traccar.model.Position) {
+ this.getView().getMarkersSource().removeFeature(this.selectedMarker);
+ delete this.reportMarkers[this.selectedMarker.get('record').get('id')];
+ } else {
+ this.resizeMarker(this.selectedMarker.getStyle(), false);
+ this.selectedMarker.getStyle().setZIndex(0);
+ this.selectedMarker.changed();
+ }
+ }
+
+ if (marker) {
+ this.resizeMarker(marker.getStyle(), true);
+ marker.getStyle().setZIndex(1);
+ marker.changed();
+ if (center) {
+ this.getView().getMapView().setCenter(marker.getGeometry().getCoordinates());
+ if (this.selectZoom !== 0 && this.selectZoom > this.getView().getMapView().getZoom()) {
+ this.getView().getMapView().setZoom(this.selectZoom);
+ }
+ }
+ }
+
+ this.selectedMarker = marker;
+ },
+
+ selectDevice: function (device, center) {
+ this.selectMarker(this.latestMarkers[device.get('id')], center);
+ },
+
+ selectReport: function (position, center) {
+ if (position instanceof Traccar.model.Position) {
+ if (!Ext.getStore('ReportRoute').showMarkers) {
+ this.reportMarkers[position.get('id')] = this.addReportMarker(position);
+ }
+ this.selectMarker(this.reportMarkers[position.get('id')], center);
+ } else if (this.selectedMarker) {
+ this.selectMarker(null, false);
+ }
+ },
+
+ selectEvent: function (position) {
+ var marker;
+ if (position) {
+ marker = this.addReportMarker(position);
+ marker.set('event', true);
+ this.selectMarker(marker, true);
+ } else if (this.selectedMarker && this.selectedMarker.get('event')) {
+ this.selectMarker(null, false);
+ }
+ },
+
+ selectFeature: function (feature) {
+ var record = feature.get('record');
+ if (record) {
+ if (record instanceof Traccar.model.Device) {
+ this.fireEvent('selectdevice', record, false);
+ } else {
+ this.fireEvent('selectreport', record, false);
+ }
+ }
+ },
+
+ deselectFeature: function () {
+ this.deselectDevice();
+ this.fireEvent('deselectfeature');
+ },
+
+ deselectDevice: function () {
+ this.selectMarker(null, false);
+ },
+
+ zoomToAllPositions: function (data) {
+ var i, point, minx, miny, maxx, maxy;
+ for (i = 0; i < data.length; i++) {
+ point = ol.proj.fromLonLat([
+ data[i].get('longitude'),
+ data[i].get('latitude')
+ ]);
+ if (i === 0) {
+ minx = maxx = point[0];
+ miny = maxy = point[1];
+ } else {
+ minx = Math.min(point[0], minx);
+ miny = Math.min(point[1], miny);
+ maxx = Math.max(point[0], maxx);
+ maxy = Math.max(point[1], maxy);
+ }
+ }
+ if (minx !== maxx || miny !== maxy) {
+ this.getView().getMapView().fit([minx, miny, maxx, maxy]);
+ } else if (point) {
+ this.getView().getMapView().fit(new ol.geom.Point(point));
+ }
+ },
+
+ updateVisibleDevices: function (store, data) {
+ var i, device;
+
+ if (!Ext.isArray(data)) {
+ data = [data];
+ }
+
+ for (i = 0; i < data.length; i++) {
+ device = data[i];
+ if (device.get('id') in this.latestMarkers) {
+ this.updateDeviceVisibility(device);
+ }
+ }
+ },
+
+ isDeviceVisible: function (device) {
+ return Ext.getStore('VisibleDevices').contains(device);
+ },
+
+ updateDeviceVisibility: function (device) {
+ var deviceId, accuracy, liveLine, marker;
+ deviceId = device.get('id');
+ marker = this.latestMarkers[deviceId];
+ accuracy = this.accuracyCircles[deviceId];
+ liveLine = this.liveRoutes[deviceId];
+ if (this.isDeviceVisible(device)) {
+ if (marker && !this.getView().getMarkersSource().getFeatureById(marker.getId())) {
+ this.getView().getMarkersSource().addFeature(marker);
+ }
+ if (accuracy && !this.getView().getAccuracySource().getFeatureById(accuracy.getId())) {
+ this.getView().getAccuracySource().addFeature(accuracy);
+ }
+ if (liveLine && !this.getView().getLiveRouteSource().getFeatureById(liveLine.getId())) {
+ this.getView().getLiveRouteSource().addFeature(liveLine);
+ }
+ } else {
+ if (marker && this.getView().getMarkersSource().getFeatureById(marker.getId())) {
+ this.getView().getMarkersSource().removeFeature(marker);
+ }
+ if (accuracy && this.getView().getAccuracySource().getFeatureById(accuracy.getId())) {
+ this.getView().getAccuracySource().removeFeature(accuracy);
+ }
+ if (liveLine && this.getView().getLiveRouteSource().getFeatureById(liveLine.getId())) {
+ this.getView().getLiveRouteSource().removeFeature(liveLine);
+ }
+ }
+ },
+
+ filterDevices: function () {
+ Ext.getStore('Devices').each(this.updateDeviceVisibility, this, false);
+ }
+});
diff --git a/legacy/web/app/view/permissions/Base.js b/legacy/web/app/view/permissions/Base.js
new file mode 100644
index 00000000..57017531
--- /dev/null
+++ b/legacy/web/app/view/permissions/Base.js
@@ -0,0 +1,37 @@
+/*
+ * 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.Base', {
+ extend: 'Traccar.view.GridPanel',
+
+ requires: [
+ 'Traccar.view.permissions.BaseController'
+ ],
+
+ controller: 'base',
+
+ selModel: {
+ selType: 'checkboxmodel',
+ checkOnly: true,
+ showHeaderCheckbox: false
+ },
+
+ listeners: {
+ beforedeselect: 'onBeforeDeselect',
+ beforeselect: 'onBeforeSelect'
+ }
+});
diff --git a/legacy/web/app/view/permissions/BaseController.js b/legacy/web/app/view/permissions/BaseController.js
new file mode 100644
index 00000000..5cb9c302
--- /dev/null
+++ b/legacy/web/app/view/permissions/BaseController.js
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@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.BaseController', {
+ extend: 'Ext.app.ViewController',
+ alias: 'controller.base',
+
+ init: function () {
+ var params = {}, linkStoreName, storeName;
+ params[this.getView().baseObjectName] = this.getView().baseObject;
+ linkStoreName = this.getView().linkStoreName;
+ storeName = this.getView().storeName;
+ linkStoreName = typeof linkStoreName === 'undefined' ? storeName : linkStoreName;
+ this.getView().setStore(Ext.getStore(storeName));
+ this.getView().getStore().load({
+ scope: this,
+ callback: function () {
+ var linkStore = Ext.create('Traccar.store.' + linkStoreName);
+ linkStore.load({
+ params: params,
+ scope: this,
+ callback: function (records, operation, success) {
+ var i, index;
+ if (success) {
+ for (i = 0; i < records.length; i++) {
+ index = this.getView().getStore().getById(records[i].getId());
+ this.getView().getSelectionModel().select(index, true, true);
+ }
+ }
+ }
+ });
+ }
+ });
+ },
+
+ onBeforeSelect: function (selection, record) {
+ var data = {};
+ data[this.getView().baseObjectName] = this.getView().baseObject;
+ data[this.getView().linkObjectName] = record.getId();
+ Ext.Ajax.request({
+ scope: this,
+ url: 'api/permissions',
+ jsonData: Ext.util.JSON.encode(data),
+ callback: function (options, success, response) {
+ if (!success) {
+ selection.deselect(record, true);
+ Traccar.app.showError(response);
+ }
+ }
+ });
+ },
+
+ onBeforeDeselect: function (selection, record) {
+ var data = {};
+ data[this.getView().baseObjectName] = this.getView().baseObject;
+ data[this.getView().linkObjectName] = record.getId();
+ Ext.Ajax.request({
+ scope: this,
+ method: 'DELETE',
+ url: 'api/permissions',
+ jsonData: Ext.util.JSON.encode(data),
+ callback: function (options, success, response) {
+ if (!success) {
+ selection.select(record, true, true);
+ Traccar.app.showError(response);
+ }
+ }
+ });
+ }
+});
diff --git a/legacy/web/app/view/permissions/Calendars.js b/legacy/web/app/view/permissions/Calendars.js
new file mode 100644
index 00000000..3d08efca
--- /dev/null
+++ b/legacy/web/app/view/permissions/Calendars.js
@@ -0,0 +1,32 @@
+/*
+ * 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.permissions.Calendars', {
+ extend: 'Traccar.view.permissions.Base',
+ xtype: 'linkCalendarsView',
+
+ columns: {
+ items: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ filter: 'string'
+ }]
+ }
+});
diff --git a/legacy/web/app/view/permissions/ComputedAttributes.js b/legacy/web/app/view/permissions/ComputedAttributes.js
new file mode 100644
index 00000000..19af72ad
--- /dev/null
+++ b/legacy/web/app/view/permissions/ComputedAttributes.js
@@ -0,0 +1,45 @@
+/*
+ * 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.ComputedAttributes', {
+ extend: 'Traccar.view.permissions.Base',
+ xtype: 'linkComputedAttributesView',
+
+ columns: {
+ items: [{
+ text: Strings.sharedDescription,
+ dataIndex: 'description',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ filter: 'string'
+ }, {
+ text: Strings.sharedAttribute,
+ dataIndex: 'attribute',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ filter: {
+ type: 'list',
+ labelField: 'name',
+ store: 'PositionAttributes'
+ },
+ renderer: function (value) {
+ return Ext.getStore('PositionAttributes').getAttributeName(value);
+ }
+ }]
+ }
+});
diff --git a/legacy/web/app/view/permissions/Devices.js b/legacy/web/app/view/permissions/Devices.js
new file mode 100644
index 00000000..3180b107
--- /dev/null
+++ b/legacy/web/app/view/permissions/Devices.js
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2015 - 2017 Anton Tananaev (anton@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.Devices', {
+ extend: 'Traccar.view.permissions.Base',
+ xtype: 'linkDevicesView',
+
+ requires: [
+ 'Traccar.AttributeFormatter'
+ ],
+
+ columns: {
+ items: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ filter: 'string'
+ }, {
+ text: Strings.deviceIdentifier,
+ dataIndex: 'uniqueId',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ filter: 'string'
+ }, {
+ text: Strings.sharedPhone,
+ dataIndex: 'phone',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ hidden: true,
+ filter: 'string'
+ }, {
+ text: Strings.deviceModel,
+ dataIndex: 'model',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ hidden: true,
+ filter: 'string'
+ }, {
+ text: Strings.deviceContact,
+ dataIndex: 'contact',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ hidden: true,
+ filter: 'string'
+ }, {
+ text: Strings.sharedDisabled,
+ dataIndex: 'disabled',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ renderer: Traccar.AttributeFormatter.getFormatter('disabled'),
+ hidden: true,
+ filter: 'boolean'
+ }, {
+ text: Strings.groupDialog,
+ dataIndex: 'groupId',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ hidden: true,
+ filter: {
+ type: 'list',
+ labelField: 'name',
+ store: 'AllGroups'
+ },
+ renderer: Traccar.AttributeFormatter.getFormatter('groupId')
+ }]
+ }
+});
diff --git a/legacy/web/app/view/permissions/Drivers.js b/legacy/web/app/view/permissions/Drivers.js
new file mode 100644
index 00000000..33cf2f76
--- /dev/null
+++ b/legacy/web/app/view/permissions/Drivers.js
@@ -0,0 +1,38 @@
+/*
+ * 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.Drivers', {
+ extend: 'Traccar.view.permissions.Base',
+ xtype: 'linkDriversView',
+
+ columns: {
+ items: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ filter: 'string'
+ }, {
+ text: Strings.deviceIdentifier,
+ dataIndex: 'uniqueId',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ filter: 'string'
+ }]
+ }
+});
diff --git a/legacy/web/app/view/permissions/Geofences.js b/legacy/web/app/view/permissions/Geofences.js
new file mode 100644
index 00000000..e2e85a36
--- /dev/null
+++ b/legacy/web/app/view/permissions/Geofences.js
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016 - 2018 Anton Tananaev (anton@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.Geofences', {
+ extend: 'Traccar.view.permissions.Base',
+ xtype: 'linkGeofencesView',
+
+ columns: {
+ items: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ filter: 'string'
+ }, {
+ text: Strings.sharedCalendar,
+ dataIndex: 'calendarId',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ hidden: true,
+ filter: {
+ type: 'list',
+ labelField: 'name',
+ store: 'AllCalendars'
+ },
+ renderer: Traccar.AttributeFormatter.getFormatter('calendarId')
+ }]
+ }
+});
diff --git a/legacy/web/app/view/permissions/Groups.js b/legacy/web/app/view/permissions/Groups.js
new file mode 100644
index 00000000..91a639c0
--- /dev/null
+++ b/legacy/web/app/view/permissions/Groups.js
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2016 - 2017 Anton Tananaev (anton@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.Groups', {
+ extend: 'Traccar.view.permissions.Base',
+ xtype: 'linkGroupsView',
+
+ requires: [
+ 'Traccar.AttributeFormatter'
+ ],
+
+ columns: {
+ items: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ filter: 'string'
+ }, {
+ text: Strings.groupDialog,
+ dataIndex: 'groupId',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ hidden: true,
+ filter: {
+ type: 'list',
+ labelField: 'name',
+ store: 'AllGroups'
+ },
+ renderer: Traccar.AttributeFormatter.getFormatter('groupId')
+ }]
+ }
+});
diff --git a/legacy/web/app/view/permissions/Maintenances.js b/legacy/web/app/view/permissions/Maintenances.js
new file mode 100644
index 00000000..c5255769
--- /dev/null
+++ b/legacy/web/app/view/permissions/Maintenances.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2018 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.Maintenances', {
+ extend: 'Traccar.view.permissions.Base',
+ xtype: 'linkMaintenancesView',
+
+ columns: {
+ items: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ filter: 'string'
+ }, {
+ text: Strings.sharedType,
+ dataIndex: 'type',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ filter: {
+ type: 'list',
+ idField: 'key',
+ labelField: 'name',
+ store: 'MaintenanceTypes'
+ },
+ renderer: function (value) {
+ var attribute = Ext.getStore('MaintenanceTypes').getById(value);
+ return attribute && attribute.get('name') || value;
+ }
+ }, {
+ text: Strings.maintenanceStart,
+ dataIndex: 'start',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ renderer: function (value, metaData, record) {
+ return Traccar.AttributeFormatter.renderAttribute(
+ value, Ext.getStore('MaintenanceTypes').getById(record.get('type')));
+ }
+ }, {
+ text: Strings.maintenancePeriod,
+ dataIndex: 'period',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ renderer: function (value, metaData, record) {
+ return Traccar.AttributeFormatter.renderAttribute(
+ value, Ext.getStore('MaintenanceTypes').getById(record.get('type')));
+ }
+ }]
+ }
+});
diff --git a/legacy/web/app/view/permissions/Notifications.js b/legacy/web/app/view/permissions/Notifications.js
new file mode 100644
index 00000000..a8570fea
--- /dev/null
+++ b/legacy/web/app/view/permissions/Notifications.js
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2017 - 2018 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2018 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.Notifications', {
+ extend: 'Traccar.view.permissions.Base',
+ xtype: 'linkNotificationsView',
+
+ columns: {
+ items: [{
+ text: Strings.notificationType,
+ dataIndex: 'type',
+ flex: 2,
+ renderer: function (value) {
+ return Traccar.app.getEventString(value);
+ },
+ filter: {
+ type: 'list',
+ idField: 'type',
+ labelField: 'name',
+ store: 'AllNotificationTypes'
+ }
+ }, {
+ text: Strings.notificationAlways,
+ dataIndex: 'always',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ renderer: Traccar.AttributeFormatter.getFormatter('always'),
+ filter: 'boolean'
+ }, {
+ text: Strings.notificationNotificators,
+ dataIndex: 'notificators',
+ flex: 2,
+ filter: {
+ type: 'arraylist',
+ idField: 'type',
+ labelField: 'name',
+ store: 'AllNotificators'
+ },
+ renderer: function (value) {
+ var result = '', i, notificators;
+ if (value) {
+ notificators = value.split(/[ ,]+/).filter(Boolean);
+ for (i = 0; i < notificators.length; i++) {
+ result += Traccar.app.getNotificatorString(notificators[i]) + (i < notificators.length - 1 ? ', ' : '');
+ }
+ }
+ return result;
+ }
+ }, {
+ text: Strings.sharedCalendar,
+ dataIndex: 'calendarId',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ hidden: true,
+ filter: {
+ type: 'list',
+ labelField: 'name',
+ store: 'AllCalendars'
+ },
+ renderer: Traccar.AttributeFormatter.getFormatter('calendarId')
+ }]
+ }
+});
diff --git a/legacy/web/app/view/permissions/SavedCommands.js b/legacy/web/app/view/permissions/SavedCommands.js
new file mode 100644
index 00000000..b57c07a0
--- /dev/null
+++ b/legacy/web/app/view/permissions/SavedCommands.js
@@ -0,0 +1,50 @@
+/*
+ * 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.SavedCommands', {
+ extend: 'Traccar.view.permissions.Base',
+ xtype: 'linkSavedCommandsView',
+
+ columns: {
+ items: [{
+ text: Strings.sharedDescription,
+ dataIndex: 'description',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ filter: 'string'
+ }, {
+ text: Strings.sharedType,
+ dataIndex: 'type',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ filter: {
+ type: 'list',
+ idField: 'type',
+ labelField: 'name',
+ store: 'AllCommandTypes'
+ },
+ renderer: Traccar.AttributeFormatter.getFormatter('commandType')
+ }, {
+ text: Strings.commandSendSms,
+ dataIndex: 'textChannel',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ filter: 'boolean'
+ }]
+ }
+});
diff --git a/legacy/web/app/view/permissions/Users.js b/legacy/web/app/view/permissions/Users.js
new file mode 100644
index 00000000..66cf5d62
--- /dev/null
+++ b/legacy/web/app/view/permissions/Users.js
@@ -0,0 +1,32 @@
+/*
+ * 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.Users', {
+ extend: 'Traccar.view.permissions.Base',
+ xtype: 'linkUsersView',
+
+ columns: {
+ items: [{
+ text: Strings.sharedName,
+ dataIndex: 'name',
+ flex: 1,
+ minWidth: Traccar.Style.columnWidthNormal,
+ filter: 'string'
+ }]
+ }
+});