diff --git a/locales/en/messages.json b/locales/en/messages.json index 4b617c60..81630c0e 100644 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -2461,7 +2461,7 @@ "message": "Load from file" }, "cliConfirmSnippetDialogTitle": { - "message": "Review loaded commands" + "message": "Loaded file {{fileName}}. Review the loaded commands" }, "cliConfirmSnippetNote": { "message": "Note: You can review and edit commands before execution." diff --git a/src/js/Analytics.js b/src/js/Analytics.js index 192bc364..6dce7111 100644 --- a/src/js/Analytics.js +++ b/src/js/Analytics.js @@ -35,7 +35,6 @@ var Analytics = function (trackingId, userId, appName, appVersion, changesetId, FIRMWARE_TYPE: 'firmwareType', FIRMWARE_VERSION: 'firmwareVersion', FIRMWARE_NAME: 'firmwareName', - FIRMWARE_CHECKSUM: 'firmwareChecksum', FIRMWARE_SOURCE: 'firmwareSource', FIRMWARE_CHANNEL: 'firmwareChannel', FIRMWARE_ERASE_ALL: 'firmwareEraseAll', @@ -158,7 +157,6 @@ Analytics.prototype._rebuildFirmwareEvent = function () { this.setDimension(this.DIMENSIONS.FIRMWARE_ERASE_ALL, this._firmwareData[this.DATA.FIRMWARE_ERASE_ALL]); this.setDimension(this.DIMENSIONS.FIRMWARE_CHANNEL, this._firmwareData[this.DATA.FIRMWARE_CHANNEL]); this.setMetric(this.METRICS.FIRMWARE_SIZE, this._firmwareData[this.DATA.FIRMWARE_SIZE]); - this._googleAnalytics.set('eventLabel', this._firmwareData[this.DATA.FIRMWARE_CHECKSUM]); } Analytics.prototype.setFirmwareData = function (property, value) { diff --git a/src/js/CliAutoComplete.js b/src/js/CliAutoComplete.js index 84f1d97f..f4fe5837 100644 --- a/src/js/CliAutoComplete.js +++ b/src/js/CliAutoComplete.js @@ -51,6 +51,8 @@ CliAutoComplete.setEnabled = function(enable) { }; CliAutoComplete.initialize = function($textarea, sendLine, writeToOutput) { + analytics.sendEvent(analytics.EVENT_CATEGORIES.APPLICATION, 'CliAutoComplete', this.configEnabled); + this.$textarea = $textarea; this.forceOpen = false, this.sendLine = sendLine; diff --git a/src/js/localization.js b/src/js/localization.js index f2e74d17..354d7345 100644 --- a/src/js/localization.js +++ b/src/js/localization.js @@ -12,8 +12,7 @@ const languagesAvailables = ['ca', 'de', 'en', 'es', 'fr', 'gl', 'hr', 'id', 'it * Functions that depend on the i18n framework */ i18n.init = function(cb) { - - getStoredUserLocale(function(userLanguage){ + getStoredUserLocale(function(userLanguage) { i18next .use(i18nextXHRBackend) diff --git a/src/js/main.js b/src/js/main.js index e1dd7bd1..d2deb2d0 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -21,6 +21,11 @@ $(document).ready(function () { } i18n.init(function() { startProcess(); + + checkSetupAnalytics(function (analytics) { + analytics.sendEvent(analytics.EVENT_CATEGORIES.APPLICATION, 'SelectedLanguage', i18n.selectedLanguage); + }); + initializeSerialBackend(); }); }); @@ -106,7 +111,7 @@ function startProcess() { i18n.localizePage(); // alternative - window.navigator.appVersion.match(/Chrome\/([0-9.]*)/)[1]; - GUI.log(i18n.getMessage('infoVersions',{operatingSystem: GUI.operating_system, + GUI.log(i18n.getMessage('infoVersions', { operatingSystem: GUI.operating_system, chromeVersion: window.navigator.appVersion.replace(/.*Chrome\/([0-9.]*).*/, "$1"), configuratorVersion: CONFIGURATOR.version })); @@ -391,7 +396,7 @@ function startProcess() { var checked = $(this).is(':checked'); ConfigStorage.set({'darkTheme': checked}); - DarkTheme.setConfig(checked); + setDarkTheme(checked); }).change(); function close_and_cleanup(e) { @@ -543,10 +548,18 @@ function startProcess() { }); ConfigStorage.get('darkTheme', function (result) { - DarkTheme.setConfig(result.darkTheme); + setDarkTheme(result.darkTheme); }); }; +function setDarkTheme(enabled) { + DarkTheme.setConfig(enabled); + + checkSetupAnalytics(function (analytics) { + analytics.sendEvent(analytics.EVENT_CATEGORIES.APPLICATION, 'DarkTheme', enabled); + }); +} + function checkForConfiguratorUpdates() { var releaseChecker = new ReleaseChecker('configurator', 'https://api.github.com/repos/betaflight/betaflight-configurator/releases'); diff --git a/src/js/tabs/cli.js b/src/js/tabs/cli.js index c3974029..3386e157 100644 --- a/src/js/tabs/cli.js +++ b/src/js/tabs/cli.js @@ -46,6 +46,7 @@ function getCliCommand(command, cliBuffer) { function copyToClipboard(text) { function onCopySuccessful() { + analytics.sendEvent(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'CliCopyToClipboard', text.length); const button = $('.tab-cli .copy'); const origText = button.text(); const origWidth = button.css("width"); @@ -207,13 +208,16 @@ TABS.cli.initialize = function (callback) { let previewArea = $("#snippetpreviewcontent textarea#preview"); - function executeSnippet() { + function executeSnippet(fileName) { const commands = previewArea.val(); + + analytics.sendEvent(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'CliExecuteFromFile', fileName); + executeCommands(commands); self.GUI.snippetPreviewWindow.close(); } - function previewCommands(result) { + function previewCommands(result, fileName) { if (!self.GUI.snippetPreviewWindow) { self.GUI.snippetPreviewWindow = new jBox("Modal", { id: "snippetPreviewWindow", @@ -222,10 +226,10 @@ TABS.cli.initialize = function (callback) { closeButton: 'title', animation: false, isolateScroll: false, - title: i18n.getMessage("cliConfirmSnippetDialogTitle"), + title: i18n.getMessage("cliConfirmSnippetDialogTitle", { fileName: fileName }), content: $('#snippetpreviewcontent'), onCreated: () => - $("#snippetpreviewcontent a.confirm").click(() => executeSnippet()) + $("#snippetpreviewcontent a.confirm").click(() => executeSnippet(fileName)) , }); } @@ -236,7 +240,7 @@ TABS.cli.initialize = function (callback) { entry.file((file) => { let reader = new FileReader(); reader.onload = - () => previewCommands(reader.result); + () => previewCommands(reader.result, file.name); reader.onerror = () => console.error(reader.error); reader.readAsText(file); }); diff --git a/src/js/tabs/configuration.js b/src/js/tabs/configuration.js index b1772620..e26cd50e 100644 --- a/src/js/tabs/configuration.js +++ b/src/js/tabs/configuration.js @@ -353,6 +353,42 @@ TABS.configuration.initialize = function (callback, scrollPosition) { orientation_acc_e.val(SENSOR_ALIGNMENT.align_acc); orientation_mag_e.val(SENSOR_ALIGNMENT.align_mag); + orientation_gyro_e.change(function () { + let value = parseInt($(this).val()); + + let newValue = undefined; + if (value !== SENSOR_ALIGNMENT.align_gyro) { + newValue = $(this).find('option:selected').text(); + } + self.analyticsChanges['GyroAlignment'] = newValue; + + SENSOR_ALIGNMENT.align_gyro = value; + }); + + orientation_acc_e.change(function () { + let value = parseInt($(this).val()); + + let newValue = undefined; + if (value !== SENSOR_ALIGNMENT.align_acc) { + newValue = $(this).find('option:selected').text(); + } + self.analyticsChanges['AccAlignment'] = newValue; + + SENSOR_ALIGNMENT.align_acc = value; + }); + + orientation_mag_e.change(function () { + let value = parseInt($(this).val()); + + let newValue = undefined; + if (value !== SENSOR_ALIGNMENT.align_mag) { + newValue = $(this).find('option:selected').text(); + } + self.analyticsChanges['MagAlignment'] = newValue; + + SENSOR_ALIGNMENT.align_mag = value; + }); + // Multi gyro config if (semver.gte(CONFIG.apiVersion, "1.41.0")) { @@ -393,6 +429,30 @@ TABS.configuration.initialize = function (callback, scrollPosition) { $('.gyro_alignment_inputs_second').toggle(detected_gyro_2); $('.gyro_alignment_inputs_selection').toggle(detected_gyro_1 || detected_gyro_2); $('.gyro_alignment_inputs_notfound').toggle(!detected_gyro_1 && !detected_gyro_2); + + orientation_gyro_1_align_e.change(function () { + let value = parseInt($(this).val()); + + let newValue = undefined; + if (value !== SENSOR_ALIGNMENT.gyro_1_align) { + newValue = $(this).find('option:selected').text(); + } + self.analyticsChanges['Gyro1Alignment'] = newValue; + + SENSOR_ALIGNMENT.gyro_1_align = value; + }); + + orientation_gyro_2_align_e.change(function () { + let value = parseInt($(this).val()); + + let newValue = undefined; + if (value !== SENSOR_ALIGNMENT.gyro_2_align) { + newValue = $(this).find('option:selected').text(); + } + self.analyticsChanges['Gyro2Alignment'] = newValue; + + SENSOR_ALIGNMENT.gyro_2_align = value; + }); } } @@ -437,8 +497,24 @@ TABS.configuration.initialize = function (callback, scrollPosition) { $('input[id="unsyncedPWMSwitch"]').prop('checked', PID_ADVANCED_CONFIG.use_unsyncedPwm !== 0).change(); $('input[name="unsyncedpwmfreq"]').val(PID_ADVANCED_CONFIG.motor_pwm_rate); $('input[name="digitalIdlePercent"]').val(PID_ADVANCED_CONFIG.digitalIdlePercent); - $('input[id="dshotBidir"]').prop('checked', MOTOR_CONFIG.use_dshot_telemetry).change(); - $('input[name="motorPoles"]').val(MOTOR_CONFIG.motor_poles); + if (semver.gte(CONFIG.apiVersion, "1.42.0")) { + let dshotBidirectional_e = $('input[id="dshotBidir"]'); + dshotBidirectional_e.prop('checked', MOTOR_CONFIG.use_dshot_telemetry).change(); + + dshotBidirectional_e.change(function () { + let value = $(this).prop('checked'); + + var newValue = undefined; + if (value !== MOTOR_CONFIG.use_dshot_telemetry) { + newValue = value ? 'On' : 'Off'; + } + self.analyticsChanges['BidirectionalDshot'] = newValue; + + MOTOR_CONFIG.use_dshot_telemetry = value; + }); + + $('input[name="motorPoles"]').val(MOTOR_CONFIG.motor_poles); + } esc_protocol_e.val(PID_ADVANCED_CONFIG.fast_pwm_protocol + 1); esc_protocol_e.change(function () { @@ -1069,7 +1145,6 @@ TABS.configuration.initialize = function (callback, scrollPosition) { MOTOR_CONFIG.mincommand = parseInt($('input[name="mincommand"]').val()); if(semver.gte(CONFIG.apiVersion, "1.42.0")) { MOTOR_CONFIG.motor_poles = parseInt($('input[name="motorPoles"]').val()); - MOTOR_CONFIG.use_dshot_telemetry = $('input[id="dshotBidir"]').prop('checked'); } if(self.SHOW_OLD_BATTERY_CONFIG) { @@ -1089,13 +1164,8 @@ TABS.configuration.initialize = function (callback, scrollPosition) { MOTOR_3D_CONFIG.neutral = parseInt($('input[name="3dneutral"]').val()); } - SENSOR_ALIGNMENT.align_gyro = parseInt(orientation_gyro_e.val()); - SENSOR_ALIGNMENT.align_acc = parseInt(orientation_acc_e.val()); - SENSOR_ALIGNMENT.align_mag = parseInt(orientation_mag_e.val()); if (semver.gte(CONFIG.apiVersion, "1.41.0")) { SENSOR_ALIGNMENT.gyro_to_use = parseInt(orientation_gyro_to_use_e.val()); - SENSOR_ALIGNMENT.gyro_1_align = parseInt(orientation_gyro_1_align_e.val()); - SENSOR_ALIGNMENT.gyro_2_align = parseInt(orientation_gyro_2_align_e.val()); } PID_ADVANCED_CONFIG.fast_pwm_protocol = parseInt(esc_protocol_e.val()-1); diff --git a/src/js/tabs/firmware_flasher.js b/src/js/tabs/firmware_flasher.js index cd16951e..f4ceefdb 100644 --- a/src/js/tabs/firmware_flasher.js +++ b/src/js/tabs/firmware_flasher.js @@ -6,6 +6,12 @@ TABS.firmware_flasher = { jenkinsLoader: new JenkinsLoader('https://ci.betaflight.tech'), localFirmwareLoaded: false, selectedBoard: undefined, + intel_hex: undefined, // standard intel hex in string format + parsed_hex: undefined, // parsed raw hex in array format + unifiedTargetConfig: undefined, // the Unified Target configuration to be spliced into the configuration + unifiedTargetConfigName: undefined, + isConfigLocal: false, // Set to true if the user loads one locally + remoteUnifiedTargetConfig: undefined, // Unified target configuration loaded from the menu, used when throwing out a local config }; TABS.firmware_flasher.initialize = function (callback) { @@ -15,25 +21,15 @@ TABS.firmware_flasher.initialize = function (callback) { GUI.active_tab = 'firmware_flasher'; } - TABS.firmware_flasher.selectedBoard = undefined; - TABS.firmware_flasher.localFirmwareLoaded = false; - var intel_hex = false; // standard intel hex in string format - var parsed_hex = false; // parsed raw hex in array format - var targetConfig; // the Unified Target configuration to be spliced into the configuration - var isConfigLocal = false; // Set to true if the user loads one locally - var unifiedConfig; // Unified target configuration loaded from the menu, used when throwing out a local config + self.selectedBoard = undefined; + self.localFirmwareLoaded = false; + self.isConfigLocal = false; + self.intel_hex = undefined; + self.parsed_hex = undefined; var unifiedSource = 'https://api.github.com/repos/betaflight/unified-targets/contents/configs/default'; - // These two functions are handy for peeking under the hood. Please don't call them in code. - self.peekTargetConfig = function () { - return targetConfig; - } - self.peekHex = function () { - return parsed_hex; - } - /** * Change boldness of firmware option depending on cache status * @@ -64,7 +60,7 @@ TABS.firmware_flasher.initialize = function (callback) { worker.postMessage(str); } function show_loaded_hex(summary) { - self.flashingMessage('' + i18n.getMessage('firmwareFlasherFirmwareOnlineLoaded', parsed_hex.bytes_total) + '', + self.flashingMessage('' + i18n.getMessage('firmwareFlasherFirmwareOnlineLoaded', self.parsed_hex.bytes_total) + '', self.FLASH_MESSAGE_TYPES.NEUTRAL); self.enableFlashing(true); @@ -83,18 +79,16 @@ TABS.firmware_flasher.initialize = function (callback) { $('div.release_info').slideDown(); } function process_hex(data, summary) { - intel_hex = data; + self.intel_hex = data; - analytics.setFirmwareData(analytics.DATA.FIRMWARE_CHECKSUM, objectHash.sha1(intel_hex)); + parse_hex(self.intel_hex, function (data) { + self.parsed_hex = data; - parse_hex(intel_hex, function (data) { - parsed_hex = data; - - if (parsed_hex) { - analytics.setFirmwareData(analytics.DATA.FIRMWARE_SIZE, parsed_hex.bytes_total); + if (self.parsed_hex) { + analytics.setFirmwareData(analytics.DATA.FIRMWARE_SIZE, self.parsed_hex.bytes_total); if (!FirmwareCache.has(summary)) { - FirmwareCache.put(summary, intel_hex); + FirmwareCache.put(summary, self.intel_hex); } show_loaded_hex(summary) @@ -418,7 +412,7 @@ TABS.firmware_flasher.initialize = function (callback) { if (targetVersions) { versions_element.append($("".format(i18n.getMessage('firmwareFlasherOptionLabelSelectFirmwareVersionFor'), target))); targetVersions.forEach(function(descriptor) { - if (unifiedConfig && !checkOneVersionForUnification(descriptor.version)) { + if (self.remoteUnifiedTargetConfig && !checkOneVersionForUnification(descriptor.version)) { return; } var select_e = @@ -453,24 +447,27 @@ TABS.firmware_flasher.initialize = function (callback) { // a target might request a firmware with the same name, remove configuration in this case. if (bareBoard == target) { console.log(bareBoard, '==', target); - if (!isConfigLocal) { - targetConfig = undefined; - unifiedConfig = undefined; + if (!self.isConfigLocal) { + self.unifiedTargetConfig = undefined; + self.unifiedTargetConfigName = undefined; + self.remoteUnifiedTargetConfig = undefined; } else { - unifiedConfig = undefined; + self.remoteUnifiedTargetConfig = undefined; } } else { - targetConfig = configText; - isConfigLocal = false; - unifiedConfig = configText; + self.unifiedTargetConfig = configText; + self.unifiedTargetConfigName = `${target}.config`; + self.isConfigLocal = false; + self.remoteUnifiedTargetConfig = configText; } } function clearBufferedFirmware() { - isConfigLocal = false; - targetConfig = undefined; - unifiedConfig = undefined; - intel_hex = false; - parsed_hex = false; + self.isConfigLocal = false; + self.unifiedTargetConfig = undefined; + self.unifiedTargetConfigName = undefined; + self.remoteUnifiedTargetConfig = undefined; + self.intel_hex = undefined; + self.parsed_hex = undefined; self.localFirmwareLoaded = false; } @@ -481,10 +478,11 @@ TABS.firmware_flasher.initialize = function (callback) { if (!GUI.connect_lock) { if (TABS.firmware_flasher.selectedBoard != target) { // We're sure the board actually changed - if (isConfigLocal) { + if (self.isConfigLocal) { console.log('Board changed, unloading local config'); - isConfigLocal = false; - targetConfig = undefined; + self.isConfigLocal = false; + self.unifiedTargetConfig = undefined; + self.unifiedTargetConfigName = undefined; } } ConfigStorage.set({'selected_board': target}); @@ -541,9 +539,10 @@ TABS.firmware_flasher.initialize = function (callback) { populateVersions(versions_e, TABS.firmware_flasher.releases[bareBoard], target); }).fail(xhr => { //TODO error, populate nothing? - targetConfig = undefined; - isConfigLocal = false; - unifiedConfig= undefined; + self.unifiedTargetConfig = undefined; + self.unifiedTargetConfigName = undefined; + self.isConfigLocal = false; + self.remoteUnifiedTargetConfig = undefined; let baseFileName = TABS.firmware_flasher.unifiedConfigs[target].reverse()[0]; GUI.log(i18n.getMessage('firmwareFlasherFailedToLoadUnifiedConfig', {remote_file: baseFileName})); @@ -559,11 +558,12 @@ TABS.firmware_flasher.initialize = function (callback) { } }); } else { - if (!isConfigLocal) { - targetConfig = undefined; - unifiedConfig = undefined; + if (!self.isConfigLocal) { + self.unifiedTargetConfig = undefined; + self.unifiedTargetConfigName = undefined; + self.remoteUnifiedTargetConfig = undefined; } else { - unifiedConfig = undefined; + self.remoteUnifiedTargetConfig = undefined; } TABS.firmware_flasher.bareBoard = target; populateVersions(versions_e, TABS.firmware_flasher.releases[target], target); @@ -575,16 +575,16 @@ TABS.firmware_flasher.initialize = function (callback) { function flashingMessageLocal() { // used by the a.load_file hook, evaluate the loaded information, and enable flashing if suitable - if (isConfigLocal && !parsed_hex) { + if (self.isConfigLocal && !self.parsed_hex) { self.flashingMessage(i18n.getMessage('firmwareFlasherLoadedConfig'), self.FLASH_MESSAGE_TYPES.NEUTRAL); } - if (isConfigLocal && parsed_hex && !self.localFirmwareLoaded) { + if (self.isConfigLocal && self.parsed_hex && !self.localFirmwareLoaded) { self.enableFlashing(true); - self.flashingMessage(i18n.getMessage('firmwareFlasherFirmwareLocalLoaded', parsed_hex.bytes_total), self.FLASH_MESSAGE_TYPES.NEUTRAL); + self.flashingMessage(i18n.getMessage('firmwareFlasherFirmwareLocalLoaded', self.parsed_hex.bytes_total), self.FLASH_MESSAGE_TYPES.NEUTRAL); } if (self.localFirmwareLoaded) { self.enableFlashing(true); - self.flashingMessage(i18n.getMessage('firmwareFlasherFirmwareLocalLoaded', parsed_hex.bytes_total), self.FLASH_MESSAGE_TYPES.NEUTRAL); + self.flashingMessage(i18n.getMessage('firmwareFlasherFirmwareLocalLoaded', self.parsed_hex.bytes_total), self.FLASH_MESSAGE_TYPES.NEUTRAL); } } // UI Hooks @@ -625,16 +625,15 @@ TABS.firmware_flasher.initialize = function (callback) { console.log('File loaded (' + e.loaded + ')'); if (file.name.split('.').pop() === "hex") { - intel_hex = e.target.result; + self.intel_hex = e.target.result; - analytics.setFirmwareData(analytics.DATA.FIRMWARE_CHECKSUM, objectHash.sha1(intel_hex)); + parse_hex(self.intel_hex, function (data) { + self.parsed_hex = data; - parse_hex(intel_hex, function (data) { - parsed_hex = data; - - if (parsed_hex) { - analytics.setFirmwareData(analytics.DATA.FIRMWARE_SIZE, parsed_hex.bytes_total); + if (self.parsed_hex) { + analytics.setFirmwareData(analytics.DATA.FIRMWARE_SIZE, self.parsed_hex.bytes_total); self.localFirmwareLoaded = true; + flashingMessageLocal(); } else { self.flashingMessage('firmwareFlasherHexCorrupted', self.FLASH_MESSAGE_TYPES.INVALID); @@ -642,8 +641,9 @@ TABS.firmware_flasher.initialize = function (callback) { }); } else { clearBufferedFirmware(); - targetConfig = e.target.result; - isConfigLocal = true; + self.unifiedTargetConfig = e.target.result; + self.unifiedTargetConfigName = file.name; + self.isConfigLocal = true; flashingMessageLocal(); } } @@ -664,11 +664,11 @@ TABS.firmware_flasher.initialize = function (callback) { if (!self.localFirmwareLoaded) { self.enableFlashing(false); self.flashingMessage(i18n.getMessage('firmwareFlasherLoadFirmwareFile'), self.FLASH_MESSAGE_TYPES.NEUTRAL); - if(parsed_hex && parsed_hex.bytes_total) { + if(self.parsed_hex && self.parsed_hex.bytes_total) { // Changing the board triggers a version change, so we need only dump it here. console.log('throw out loaded hex'); - intel_hex = false; - parsed_hex = false; + self.intel_hex = undefined; + self.parsed_hex = undefined; } } @@ -711,7 +711,7 @@ TABS.firmware_flasher.initialize = function (callback) { var summary = $('select[name="firmware_version"] option:selected').data('summary'); if (summary) { // undefined while list is loading or while running offline - if (isConfigLocal && FirmwareCache.has(summary)) { + if (self.isConfigLocal && FirmwareCache.has(summary)) { // Load the .hex from Cache if available when the user is providing their own config. analytics.setFirmwareData(analytics.DATA.FIRMWARE_SOURCE, 'cache'); FirmwareCache.get(summary, cached => { @@ -757,7 +757,7 @@ TABS.firmware_flasher.initialize = function (callback) { baud = parseInt($('#flash_manual_baud_rate').val()); } - analytics.sendEvent(analytics.EVENT_CATEGORIES.FIRMWARE, 'Flashing'); + analytics.sendEvent(analytics.EVENT_CATEGORIES.FIRMWARE, 'Flashing', self.unifiedTargetConfigName || null); STM32.connect(port, baud, firmware, options); } else { @@ -765,7 +765,7 @@ TABS.firmware_flasher.initialize = function (callback) { GUI.log(i18n.getMessage('firmwareFlasherNoValidPort')); } } else { - analytics.sendEvent(analytics.EVENT_CATEGORIES.FIRMWARE, 'Flashing'); + analytics.sendEvent(analytics.EVENT_CATEGORIES.FIRMWARE, 'Flashing', self.unifiedTargetConfigName || null); STM32DFU.connect(usbDevices, firmware, options); } @@ -774,21 +774,22 @@ TABS.firmware_flasher.initialize = function (callback) { $('a.flash_firmware').click(function () { if (!$(this).hasClass('disabled')) { if (!GUI.connect_lock) { // button disabled while flashing is in progress - if (parsed_hex != false) { + if (self.parsed_hex != false) { try { - if (targetConfig && !parsed_hex.configInserted) { + if (self.unifiedTargetConfig && !self.parsed_hex.configInserted) { var configInserter = new ConfigInserter(); - if (configInserter.insertConfig(parsed_hex, targetConfig)) { - parsed_hex.configInserted = true; + if (configInserter.insertConfig(self.parsed_hex, self.unifiedTargetConfig)) { + self.parsed_hex.configInserted = true; } else { console.log('Firmware does not support custom defaults.'); - targetConfig = undefined; + self.unifiedTargetConfig = undefined; + self.unifiedTargetConfigName = undefined; } } - flashFirmware(parsed_hex); + flashFirmware(self.parsed_hex); } catch (e) { console.log(`Flashing failed: ${e.message}`); } @@ -814,7 +815,7 @@ TABS.firmware_flasher.initialize = function (callback) { // check if file is writable chrome.fileSystem.isWritableEntry(fileEntry, function (isWritable) { if (isWritable) { - var blob = new Blob([intel_hex], {type: 'text/plain'}); + var blob = new Blob([self.intel_hex], {type: 'text/plain'}); fileEntry.createWriter(function (writer) { var truncated = false; @@ -1007,7 +1008,6 @@ TABS.firmware_flasher.FLASH_MESSAGE_TYPES = {NEUTRAL : 'NEUTRAL', ACTION : 'ACTION'}; TABS.firmware_flasher.flashingMessage = function(message, type) { - let self = this; let progressLabel_e = $('span.progressLabel'); diff --git a/src/js/tabs/ports.js b/src/js/tabs/ports.js index e9c3ff7b..763f8fb3 100644 --- a/src/js/tabs/ports.js +++ b/src/js/tabs/ports.js @@ -176,6 +176,7 @@ TABS.ports.initialize = function (callback, scrollPosition) { blackbox_baudrate_e.append(''); } + let lastVtxControlSelected; var ports_e = $('.tab-ports .ports'); var port_configuration_template_e = $('#tab-ports-templates .portConfiguration'); @@ -259,6 +260,10 @@ TABS.ports.initialize = function (callback, scrollPosition) { if (serialPort.functions.indexOf(functionName) >= 0) { select_e.val(functionName); + + if (column === 'peripherals' && (functionName === "TBS_SMARTAUDIO" || functionName === "IRC_TRAMP")) { + lastVtxControlSelected = functionName; + } } if (column === 'telemetry') { @@ -279,30 +284,42 @@ TABS.ports.initialize = function (callback, scrollPosition) { ports_e.find('tbody').append(port_configuration_e); } + + let vtxTableNotConfigured = true; if (semver.gte(CONFIG.apiVersion, "1.42.0")) { - var vtxTableNotConfigured = VTX_CONFIG.vtx_table_available && + vtxTableNotConfigured = VTX_CONFIG.vtx_table_available && (VTX_CONFIG.vtx_table_bands == 0 || VTX_CONFIG.vtx_table_channels == 0 || VTX_CONFIG.vtx_table_powerlevels == 0); - const pheripheralsSelectElement = $('select[name="function-peripherals"]'); - pheripheralsSelectElement.change(function() { - let vtxControlSelected = false; - pheripheralsSelectElement.each(function() { - const el = $(this); - if (el.val() == "TBS_SMARTAUDIO" || el.val() == "IRC_TRAMP") { - vtxControlSelected = true; - } - }); + } else { + $('.vtxTableNotSet').hide(); + } + + const pheripheralsSelectElement = $('select[name="function-peripherals"]'); + pheripheralsSelectElement.change(function() { + let vtxControlSelected = undefined; + pheripheralsSelectElement.each(function() { + const el = $(this); + if (el.val() === "TBS_SMARTAUDIO" || el.val() === "IRC_TRAMP") { + vtxControlSelected = el.val(); + } + }); + + if (lastVtxControlSelected !== vtxControlSelected) { + self.analyticsChanges['VtxControl'] = vtxControlSelected; + + lastVtxControlSelected = vtxControlSelected; + } + + if (semver.gte(CONFIG.apiVersion, "1.42.0")) { if (vtxControlSelected && vtxTableNotConfigured) { $('.vtxTableNotSet').show(); } else { $('.vtxTableNotSet').hide(); } - }); - pheripheralsSelectElement.change(); - } else { - $('.vtxTableNotSet').hide(); - } + } + }); + pheripheralsSelectElement.change(); } function on_tab_loaded_handler() { diff --git a/src/js/tabs/vtx.js b/src/js/tabs/vtx.js index 1ed7795c..8b34b883 100644 --- a/src/js/tabs/vtx.js +++ b/src/js/tabs/vtx.js @@ -8,14 +8,18 @@ TABS.vtx = { MAX_BAND_CHANNELS_VALUES: 8, VTXTABLE_BAND_LIST: [], VTXTABLE_POWERLEVEL_LIST: [], + analyticsChanges: {}, }; TABS.vtx.initialize = function (callback) { + var self = this; if (GUI.active_tab != 'vtx') { GUI.active_tab = 'vtx'; } + self.analyticsChanges = {}; + this.supported = semver.gte(CONFIG.apiVersion, "1.42.0"); if (!this.supported) { @@ -304,6 +308,13 @@ TABS.vtx.initialize = function (callback) { } $("#vtx_table_channels").on('input', showHideBandChannels).trigger('input'); + $("#vtx_table").change(function() { + let fromScratch = true; + if (self.analyticsChanges['VtxTableLoadFromClipboard'] !== undefined || self.analyticsChanges['VtxTableLoadFromFile'] !== undefined) { + fromScratch = false; + } + self.analyticsChanges['VtxTableEdit'] = fromScratch ? 'modificationOnly' : 'fromTemplate'; + }); /*** Helper functions */ @@ -527,19 +538,19 @@ TABS.vtx.initialize = function (callback) { }; writer.onwriteend = function() { - - // we get here at the end of the truncate method, change to the new end - writer.onwriteend = function() { - console.log('Write VTX file end'); - GUI.log(i18n.getMessage('vtxSavedFileOk')); - } - dump_html_to_msp(); let vtxConfig = createVtxConfigInfo(); let text = JSON.stringify(vtxConfig, null, 4); let data = new Blob([text], { type: "application/json" }); - writer.write(data); + // we get here at the end of the truncate method, change to the new end + writer.onwriteend = function() { + analytics.sendEvent(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'VtxTableSave', text.length); + console.log('Write VTX file end'); + GUI.log(i18n.getMessage('vtxSavedFileOk')); + } + + writer.write(data); }; writer.truncate(0); @@ -584,6 +595,9 @@ TABS.vtx.initialize = function (callback) { TABS.vtx.vtxTableSavePending = true; + self.analyticsChanges['VtxTableLoadFromClipboard'] = undefined; + self.analyticsChanges['VtxTableLoadFromFile'] = file.name; + console.log('Load VTX file end'); GUI.log(i18n.getMessage('vtxLoadFileOk')); @@ -616,6 +630,9 @@ TABS.vtx.initialize = function (callback) { TABS.vtx.vtxTableSavePending = true; + self.analyticsChanges['VtxTableLoadFromFile'] = undefined; + self.analyticsChanges['VtxTableLoadFromClipboard'] = text.length; + console.log('Load VTX clipboard end'); GUI.log(i18n.getMessage('vtxLoadClipboardOk')); @@ -640,6 +657,8 @@ TABS.vtx.initialize = function (callback) { // Start MSP saving save_vtx_config(); + analytics.sendChangeEvents(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, self.analyticsChanges); + function save_vtx_config() { MSP.send_message(MSPCodes.MSP_SET_VTX_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_VTX_CONFIG), false, save_vtx_powerlevels); } diff --git a/src/tabs/vtx.html b/src/tabs/vtx.html index 9a312fa3..e6e12bdb 100644 --- a/src/tabs/vtx.html +++ b/src/tabs/vtx.html @@ -186,7 +186,7 @@
-