Skip to content

Commit 0024d96

Browse files
committed
feat: convert configuration tab to vue and fix connection issues
- Convert Configuration tab to Vue component - Fix 'Save and Reboot' modal race condition and connection handling - Fix localization key mismatches and restore legacy keys - Code cleanup and import fixes
1 parent fece39d commit 0024d96

File tree

6 files changed

+1064
-34
lines changed

6 files changed

+1064
-34
lines changed

src/components/tabs/ConfigurationTab.vue

Lines changed: 1040 additions & 0 deletions
Large diffs are not rendered by default.

src/js/main.js

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import CliAutoComplete from "./CliAutoComplete.js";
1313
import DarkTheme, { setDarkTheme } from "./DarkTheme.js";
1414
import { isExpertModeEnabled } from "./utils/isExpertModeEnabled.js";
1515
import { updateTabList } from "./utils/updateTabList.js";
16-
import { mountVueTab } from "./vue_tab_mounter.js";
16+
import { mountVueTab, unmountVueTab } from "./vue_tab_mounter.js";
1717
import * as THREE from "three";
1818
import NotificationManager from "./utils/notifications.js";
1919

@@ -27,12 +27,6 @@ import("./msp/debug/msp_debug_tools.js")
2727
console.warn("Failed to load MSP debug tools:", err);
2828
});
2929

30-
if (typeof String.prototype.replaceAll === "undefined") {
31-
String.prototype.replaceAll = function (match, replace) {
32-
return this.replace(new RegExp(match, "g"), () => replace);
33-
};
34-
}
35-
3630
$(document).ready(function () {
3731
appReady();
3832
});
@@ -216,6 +210,7 @@ function startProcess() {
216210

217211
// detach listeners and remove element data
218212
const content = $("#content");
213+
unmountVueTab();
219214
content.empty();
220215

221216
// display loading screen
@@ -291,9 +286,7 @@ function startProcess() {
291286
import("./tabs/setup_osd").then(({ setup_osd }) => setup_osd.initialize(content_ready));
292287
break;
293288
case "configuration":
294-
import("./tabs/configuration").then(({ configuration }) =>
295-
configuration.initialize(content_ready),
296-
);
289+
mountVueTab("configuration", content_ready);
297290
break;
298291
case "pid_tuning":
299292
import("./tabs/pid_tuning").then(({ pid_tuning }) => pid_tuning.initialize(content_ready));

src/js/msp/MSPHelper.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ import huffmanDecodeBuf from "../huffman";
1414
import { defaultHuffmanTree, defaultHuffmanLenIndex } from "../default_huffman_tree";
1515
import { updateTabList } from "../utils/updateTabList";
1616
import { showErrorDialog } from "../utils/showErrorDialog";
17-
import GUI, { TABS } from "../gui";
17+
import GUI from "../gui";
1818
import { OSD } from "../tabs/osd";
19-
import { reinitializeConnection } from "../serial_backend";
2019

2120
// Used for LED_STRIP
2221
const ledDirectionLetters = ["n", "e", "s", "w", "u", "d"]; // in LSB bit order
@@ -2944,7 +2943,7 @@ MspHelper.prototype.writeConfiguration = function (reboot, callback) {
29442943
console.log("Configuration saved to EEPROM");
29452944
if (reboot) {
29462945
GUI.tab_switch_cleanup(function () {
2947-
return reinitializeConnection();
2946+
return GUI.reinitializeConnection();
29482947
});
29492948
}
29502949
if (callback) {

src/js/serial_backend.js

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ export function initializeSerialBackend() {
6161

6262
EventBus.$on("port-handler:auto-select-serial-device", function () {
6363
if (
64-
!GUI.connected_to &&
65-
!GUI.connecting_to &&
66-
!["cli", "firmware_flasher"].includes(GUI.active_tab) &&
67-
PortHandler.portPicker.autoConnect &&
68-
!isCliOnlyMode() &&
69-
(connectionTimestamp === null || connectionTimestamp > 0) ||
70-
(Date.now() - rebootTimestamp <= REBOOT_CONNECT_MAX_TIME_MS)
64+
(!GUI.connected_to &&
65+
!GUI.connecting_to &&
66+
!["cli", "firmware_flasher"].includes(GUI.active_tab) &&
67+
PortHandler.portPicker.autoConnect &&
68+
!isCliOnlyMode() &&
69+
(connectionTimestamp === null || connectionTimestamp > 0)) ||
70+
Date.now() - rebootTimestamp <= REBOOT_CONNECT_MAX_TIME_MS
7171
) {
7272
connectDisconnect();
7373
}
@@ -128,12 +128,6 @@ function connectDisconnect() {
128128
return;
129129
}
130130

131-
// When rebooting, adhere to the auto-connect setting
132-
if (!PortHandler.portPicker.autoConnect && Date.now() - rebootTimestamp < REBOOT_GRACE_PERIOD_MS) {
133-
console.log(`${logHead} Rebooting, not connecting`);
134-
return;
135-
}
136-
137131
const portName = selectedPort === "manual" ? PortHandler.portPicker.portOverride : selectedPort;
138132

139133
console.log(`${logHead} Connecting to: ${portName}`);
@@ -608,6 +602,7 @@ function finishOpen() {
608602
onConnect();
609603

610604
GUI.selectDefaultTabWhenConnected();
605+
rebootTimestamp = 0;
611606
}
612607

613608
function connectCli() {
@@ -808,6 +803,9 @@ export function reinitializeConnection() {
808803
// Send reboot command to the flight controller
809804
MSP.send_message(MSPCodes.MSP_SET_REBOOT, false, false);
810805

806+
// Force connection invalid to ensure reboot dialog waits for reconnection
807+
CONFIGURATOR.connectionValid = false;
808+
811809
if (currentPort.startsWith("bluetooth")) {
812810
if (!PortHandler.portPicker.autoConnect) {
813811
return setTimeout(function () {
@@ -816,14 +814,6 @@ export function reinitializeConnection() {
816814
}
817815
}
818816

819-
// Show reboot progress modal except for cli and presets tab
820-
if (["cli", "presets"].includes(GUI.active_tab)) {
821-
console.log(`${logHead} Rebooting in ${GUI.active_tab} tab, skipping reboot dialog`);
822-
gui_log(i18n.getMessage("deviceRebooting"));
823-
gui_log(i18n.getMessage("deviceReady"));
824-
825-
return;
826-
}
827817
// Show reboot progress modal
828818
showRebootDialog();
829819
}
@@ -926,3 +916,5 @@ function showRebootDialog() {
926916
return dialog;
927917
}
928918
}
919+
920+
GUI.reinitializeConnection = reinitializeConnection;

src/js/vue_components.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ import PortPicker from "../components/port-picker/PortPicker.vue";
77
import HelpTab from "../components/tabs/HelpTab.vue";
88
import LandingTab from "../components/tabs/LandingTab.vue";
99
import OptionsTab from "../components/tabs/OptionsTab.vue";
10+
import ConfigurationTab from "../components/tabs/ConfigurationTab.vue";
1011

1112
// Registry of Vue tab components - used by main.js for dynamic mounting
1213
export const VueTabComponents = {
1314
help: HelpTab,
1415
landing: LandingTab,
1516
options: OptionsTab,
17+
configuration: ConfigurationTab,
1618
};
1719

1820
// Create a Vue plugin that registers all components globally
@@ -28,5 +30,6 @@ export const BetaflightComponents = {
2830
app.component("HelpTab", HelpTab);
2931
app.component("LandingTab", LandingTab);
3032
app.component("OptionsTab", OptionsTab);
33+
app.component("ConfigurationTab", ConfigurationTab);
3134
},
3235
};

src/js/vue_tab_mounter.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ export function mountVueTab(tabName, contentReadyCallback) {
6363
currentTabApp.provide("betaflightModel", window.vm);
6464
}
6565

66+
// Set active tab for legacy compatibility
67+
GUI.active_tab = tabName;
68+
6669
// Mount to content
6770
currentTabApp.mount(contentEl);
6871

0 commit comments

Comments
 (0)