From b392a4af78e01c8e0f50aad5468e9583675b24be Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 6 Apr 2024 09:17:52 -0700 Subject: Move to the legacy folder --- legacy/web/app/view/ArrayListFilter.js | 50 ++ legacy/web/app/view/BaseWindow.js | 32 + legacy/web/app/view/ClearableComboBox.js | 31 + legacy/web/app/view/ColorPicker.js | 43 ++ legacy/web/app/view/CustomNumberField.js | 109 ++++ legacy/web/app/view/CustomTimeField.js | 30 + legacy/web/app/view/DeviceMenu.js | 72 +++ legacy/web/app/view/DeviceMenuController.js | 134 ++++ legacy/web/app/view/Events.js | 117 ++++ legacy/web/app/view/EventsController.js | 126 ++++ legacy/web/app/view/GridPanel.js | 34 + legacy/web/app/view/Main.js | 84 +++ legacy/web/app/view/MainController.js | 26 + legacy/web/app/view/MainMobile.js | 73 +++ legacy/web/app/view/Report.js | 115 ++++ legacy/web/app/view/ReportController.js | 678 ++++++++++++++++++++ legacy/web/app/view/SettingsMenu.js | 111 ++++ legacy/web/app/view/SettingsMenuController.js | 176 ++++++ legacy/web/app/view/State.js | 85 +++ legacy/web/app/view/StateController.js | 216 +++++++ legacy/web/app/view/Statistics.js | 93 +++ legacy/web/app/view/StatisticsController.js | 29 + legacy/web/app/view/TouchFix62.js | 48 ++ legacy/web/app/view/UnescapedTextAreaField.js | 29 + legacy/web/app/view/UnescapedTextField.js | 29 + legacy/web/app/view/dialog/Attribute.js | 65 ++ legacy/web/app/view/dialog/AttributeController.js | 126 ++++ legacy/web/app/view/dialog/Base.js | 32 + legacy/web/app/view/dialog/BaseEdit.js | 46 ++ legacy/web/app/view/dialog/BaseEditController.js | 61 ++ legacy/web/app/view/dialog/Calendar.js | 63 ++ legacy/web/app/view/dialog/CalendarController.js | 37 ++ legacy/web/app/view/dialog/ComputedAttribute.js | 84 +++ .../app/view/dialog/ComputedAttributeController.js | 45 ++ legacy/web/app/view/dialog/Device.js | 99 +++ legacy/web/app/view/dialog/DeviceAccumulators.js | 55 ++ .../view/dialog/DeviceAccumulatorsController.js | 48 ++ legacy/web/app/view/dialog/DeviceController.js | 29 + legacy/web/app/view/dialog/Driver.js | 46 ++ legacy/web/app/view/dialog/Geofence.js | 89 +++ legacy/web/app/view/dialog/GeofenceController.js | 58 ++ legacy/web/app/view/dialog/Group.js | 55 ++ legacy/web/app/view/dialog/Login.js | 151 +++++ legacy/web/app/view/dialog/LoginController.js | 132 ++++ legacy/web/app/view/dialog/Maintenance.js | 75 +++ .../web/app/view/dialog/MaintenanceController.js | 65 ++ legacy/web/app/view/dialog/MapPickerController.js | 42 ++ legacy/web/app/view/dialog/Notification.js | 95 +++ .../web/app/view/dialog/NotificationController.js | 53 ++ legacy/web/app/view/dialog/Register.js | 67 ++ legacy/web/app/view/dialog/RegisterController.js | 44 ++ legacy/web/app/view/dialog/ReportConfig.js | 136 ++++ .../web/app/view/dialog/ReportConfigController.js | 99 +++ legacy/web/app/view/dialog/SavedCommand.js | 83 +++ .../web/app/view/dialog/SavedCommandController.js | 99 +++ legacy/web/app/view/dialog/SelectDevice.js | 59 ++ .../web/app/view/dialog/SelectDeviceController.js | 45 ++ legacy/web/app/view/dialog/SendCommand.js | 98 +++ .../web/app/view/dialog/SendCommandController.js | 78 +++ legacy/web/app/view/dialog/Server.js | 159 +++++ legacy/web/app/view/dialog/User.js | 211 +++++++ legacy/web/app/view/dialog/UserController.js | 69 +++ legacy/web/app/view/edit/Attributes.js | 65 ++ legacy/web/app/view/edit/AttributesController.js | 124 ++++ legacy/web/app/view/edit/Calendars.js | 50 ++ legacy/web/app/view/edit/CalendarsController.js | 31 + legacy/web/app/view/edit/ComputedAttributes.js | 80 +++ .../app/view/edit/ComputedAttributesController.js | 31 + legacy/web/app/view/edit/Devices.js | 161 +++++ legacy/web/app/view/edit/DevicesController.js | 139 +++++ legacy/web/app/view/edit/Drivers.js | 54 ++ legacy/web/app/view/edit/DriversController.js | 31 + legacy/web/app/view/edit/Geofences.js | 63 ++ legacy/web/app/view/edit/GeofencesController.js | 30 + legacy/web/app/view/edit/Groups.js | 109 ++++ legacy/web/app/view/edit/GroupsController.js | 141 +++++ legacy/web/app/view/edit/Maintenances.js | 77 +++ legacy/web/app/view/edit/MaintenancesController.js | 31 + legacy/web/app/view/edit/Notifications.js | 111 ++++ .../web/app/view/edit/NotificationsController.js | 31 + legacy/web/app/view/edit/SavedCommands.js | 65 ++ .../web/app/view/edit/SavedCommandsController.js | 31 + legacy/web/app/view/edit/Toolbar.js | 49 ++ legacy/web/app/view/edit/ToolbarController.js | 70 +++ legacy/web/app/view/edit/Users.js | 156 +++++ legacy/web/app/view/edit/UsersController.js | 244 ++++++++ legacy/web/app/view/map/BaseMap.js | 243 ++++++++ legacy/web/app/view/map/GeofenceMap.js | 150 +++++ legacy/web/app/view/map/GeofenceMapController.js | 85 +++ legacy/web/app/view/map/Map.js | 158 +++++ legacy/web/app/view/map/MapController.js | 101 +++ legacy/web/app/view/map/MapMarkerController.js | 687 +++++++++++++++++++++ legacy/web/app/view/permissions/Base.js | 37 ++ legacy/web/app/view/permissions/BaseController.js | 84 +++ legacy/web/app/view/permissions/Calendars.js | 32 + .../web/app/view/permissions/ComputedAttributes.js | 45 ++ legacy/web/app/view/permissions/Devices.js | 82 +++ legacy/web/app/view/permissions/Drivers.js | 38 ++ legacy/web/app/view/permissions/Geofences.js | 43 ++ legacy/web/app/view/permissions/Groups.js | 47 ++ legacy/web/app/view/permissions/Maintenances.js | 65 ++ legacy/web/app/view/permissions/Notifications.js | 78 +++ legacy/web/app/view/permissions/SavedCommands.js | 50 ++ legacy/web/app/view/permissions/Users.js | 32 + 104 files changed, 9499 insertions(+) create mode 100644 legacy/web/app/view/ArrayListFilter.js create mode 100644 legacy/web/app/view/BaseWindow.js create mode 100644 legacy/web/app/view/ClearableComboBox.js create mode 100644 legacy/web/app/view/ColorPicker.js create mode 100644 legacy/web/app/view/CustomNumberField.js create mode 100644 legacy/web/app/view/CustomTimeField.js create mode 100644 legacy/web/app/view/DeviceMenu.js create mode 100644 legacy/web/app/view/DeviceMenuController.js create mode 100644 legacy/web/app/view/Events.js create mode 100644 legacy/web/app/view/EventsController.js create mode 100644 legacy/web/app/view/GridPanel.js create mode 100644 legacy/web/app/view/Main.js create mode 100644 legacy/web/app/view/MainController.js create mode 100644 legacy/web/app/view/MainMobile.js create mode 100644 legacy/web/app/view/Report.js create mode 100644 legacy/web/app/view/ReportController.js create mode 100644 legacy/web/app/view/SettingsMenu.js create mode 100644 legacy/web/app/view/SettingsMenuController.js create mode 100644 legacy/web/app/view/State.js create mode 100644 legacy/web/app/view/StateController.js create mode 100644 legacy/web/app/view/Statistics.js create mode 100644 legacy/web/app/view/StatisticsController.js create mode 100644 legacy/web/app/view/TouchFix62.js create mode 100644 legacy/web/app/view/UnescapedTextAreaField.js create mode 100644 legacy/web/app/view/UnescapedTextField.js create mode 100644 legacy/web/app/view/dialog/Attribute.js create mode 100644 legacy/web/app/view/dialog/AttributeController.js create mode 100644 legacy/web/app/view/dialog/Base.js create mode 100644 legacy/web/app/view/dialog/BaseEdit.js create mode 100644 legacy/web/app/view/dialog/BaseEditController.js create mode 100644 legacy/web/app/view/dialog/Calendar.js create mode 100644 legacy/web/app/view/dialog/CalendarController.js create mode 100644 legacy/web/app/view/dialog/ComputedAttribute.js create mode 100644 legacy/web/app/view/dialog/ComputedAttributeController.js create mode 100644 legacy/web/app/view/dialog/Device.js create mode 100644 legacy/web/app/view/dialog/DeviceAccumulators.js create mode 100644 legacy/web/app/view/dialog/DeviceAccumulatorsController.js create mode 100644 legacy/web/app/view/dialog/DeviceController.js create mode 100644 legacy/web/app/view/dialog/Driver.js create mode 100644 legacy/web/app/view/dialog/Geofence.js create mode 100644 legacy/web/app/view/dialog/GeofenceController.js create mode 100644 legacy/web/app/view/dialog/Group.js create mode 100644 legacy/web/app/view/dialog/Login.js create mode 100644 legacy/web/app/view/dialog/LoginController.js create mode 100644 legacy/web/app/view/dialog/Maintenance.js create mode 100644 legacy/web/app/view/dialog/MaintenanceController.js create mode 100644 legacy/web/app/view/dialog/MapPickerController.js create mode 100644 legacy/web/app/view/dialog/Notification.js create mode 100644 legacy/web/app/view/dialog/NotificationController.js create mode 100644 legacy/web/app/view/dialog/Register.js create mode 100644 legacy/web/app/view/dialog/RegisterController.js create mode 100644 legacy/web/app/view/dialog/ReportConfig.js create mode 100644 legacy/web/app/view/dialog/ReportConfigController.js create mode 100644 legacy/web/app/view/dialog/SavedCommand.js create mode 100644 legacy/web/app/view/dialog/SavedCommandController.js create mode 100644 legacy/web/app/view/dialog/SelectDevice.js create mode 100644 legacy/web/app/view/dialog/SelectDeviceController.js create mode 100644 legacy/web/app/view/dialog/SendCommand.js create mode 100644 legacy/web/app/view/dialog/SendCommandController.js create mode 100644 legacy/web/app/view/dialog/Server.js create mode 100644 legacy/web/app/view/dialog/User.js create mode 100644 legacy/web/app/view/dialog/UserController.js create mode 100644 legacy/web/app/view/edit/Attributes.js create mode 100644 legacy/web/app/view/edit/AttributesController.js create mode 100644 legacy/web/app/view/edit/Calendars.js create mode 100644 legacy/web/app/view/edit/CalendarsController.js create mode 100644 legacy/web/app/view/edit/ComputedAttributes.js create mode 100644 legacy/web/app/view/edit/ComputedAttributesController.js create mode 100644 legacy/web/app/view/edit/Devices.js create mode 100644 legacy/web/app/view/edit/DevicesController.js create mode 100644 legacy/web/app/view/edit/Drivers.js create mode 100644 legacy/web/app/view/edit/DriversController.js create mode 100644 legacy/web/app/view/edit/Geofences.js create mode 100644 legacy/web/app/view/edit/GeofencesController.js create mode 100644 legacy/web/app/view/edit/Groups.js create mode 100644 legacy/web/app/view/edit/GroupsController.js create mode 100644 legacy/web/app/view/edit/Maintenances.js create mode 100644 legacy/web/app/view/edit/MaintenancesController.js create mode 100644 legacy/web/app/view/edit/Notifications.js create mode 100644 legacy/web/app/view/edit/NotificationsController.js create mode 100644 legacy/web/app/view/edit/SavedCommands.js create mode 100644 legacy/web/app/view/edit/SavedCommandsController.js create mode 100644 legacy/web/app/view/edit/Toolbar.js create mode 100644 legacy/web/app/view/edit/ToolbarController.js create mode 100644 legacy/web/app/view/edit/Users.js create mode 100644 legacy/web/app/view/edit/UsersController.js create mode 100644 legacy/web/app/view/map/BaseMap.js create mode 100644 legacy/web/app/view/map/GeofenceMap.js create mode 100644 legacy/web/app/view/map/GeofenceMapController.js create mode 100644 legacy/web/app/view/map/Map.js create mode 100644 legacy/web/app/view/map/MapController.js create mode 100644 legacy/web/app/view/map/MapMarkerController.js create mode 100644 legacy/web/app/view/permissions/Base.js create mode 100644 legacy/web/app/view/permissions/BaseController.js create mode 100644 legacy/web/app/view/permissions/Calendars.js create mode 100644 legacy/web/app/view/permissions/ComputedAttributes.js create mode 100644 legacy/web/app/view/permissions/Devices.js create mode 100644 legacy/web/app/view/permissions/Drivers.js create mode 100644 legacy/web/app/view/permissions/Geofences.js create mode 100644 legacy/web/app/view/permissions/Groups.js create mode 100644 legacy/web/app/view/permissions/Maintenances.js create mode 100644 legacy/web/app/view/permissions/Notifications.js create mode 100644 legacy/web/app/view/permissions/SavedCommands.js create mode 100644 legacy/web/app/view/permissions/Users.js (limited to 'legacy/web/app/view') 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 . + */ + +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 . + */ + +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 . + */ +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 . + */ +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 . + */ +Ext.define('Traccar.view.CustomNumberField', { + extend: 'Ext.form.field.Number', + xtype: 'customNumberField', + + beforeEl: '
', + unitEl: '
', + + 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 + '
'; + 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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ +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 . + */ + +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 . + */ +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 . + */ + +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 . + */ + +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 . + */ + +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 '' + + Strings.sharedShowAddress + ''; + } + 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 . + */ + +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 . + */ + +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 . + */ + +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 '' + + Strings.sharedShowAddress + ''; + } 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 '' + value + ''; + } + } + } + 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 . + */ + +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 . + */ + +/* + * 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 . + */ +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 . + */ +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 '' + + '
' + + '{[new XMLSerializer().serializeToString(Traccar.DeviceImages.getImageSvg(' + + 'Traccar.Style.mapColorOnline, false, 0, values.key))]}
{name}
'; + } + } + }, { + 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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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: '' + }, { + xtype: 'component', + html: '' + }] + }, + + 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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ +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 . + */ + +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 . + */ + +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 . + */ + +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: '© OpenStreetMap ' + + 'contributors, © CARTO' + }) + }), + 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: '© Yandex' + }) + }), + 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: '© Yandex' + }) + }), + 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: '© LocationIQ' + }) + }) + ] + }); + + 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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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 . + */ + +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' + }] + } +}); -- cgit v1.2.3