Skip to content

Commit d163f1e

Browse files
Merge pull request #468 from Hyperloop-UPV/control-station/config-versioning
feat: add app and config.toml versioning It is missin to test toml versioning, I will write a comment after I test it.
2 parents 1d23230 + 2e662c1 commit d163f1e

55 files changed

Lines changed: 2162 additions & 343 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ jobs:
9090
if: runner.os == 'Linux'
9191
run: |
9292
sudo apt-get update
93-
sudo apt-get install -y rpm libarchive-tools
9493
9594
# Download ONLY the appropriate backend for this platform
9695
- name: Download Linux backend
@@ -188,8 +187,6 @@ jobs:
188187
electron-app/dist/*.exe
189188
electron-app/dist/*.AppImage
190189
electron-app/dist/*.deb
191-
electron-app/dist/*.rpm
192-
electron-app/dist/*.pacman
193190
electron-app/dist/*.dmg
194191
electron-app/dist/*.zip
195192
electron-app/dist/*.yml

README.md

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Hyperloop Control Station H11
2-
![Testing View](https://raw.githubusercontent.com/Hyperloop-UPV/webpage/5c1c827d82d380689856ee61af43da30da22e0fc/src/assets/backgrounds/testing-view.png)
2+
3+
![Testing View](https://raw.githubusercontent.com/Hyperloop-UPV/webpage/5c1c827d82d380689856ee61af43da30da22e0fc/src/assets/backgrounds/testing-view.png)
34

45
## Monorepo usage
56

@@ -20,17 +21,17 @@ Before starting, ensure you have the following installed:
2021

2122
Our `pnpm-workspace.yaml` defines the following workspaces:
2223

23-
| Workspace | Language | Description |
24-
| :----------------------------- | :------- | :--------------------------------------------- |
25-
| `testing-view` | TS/React | Web interface for telemetry testing |
26-
| `competition-view` | TS/React | UI for the competition |
27-
| `backend` | Go | Data ingestion and pod communication server |
28-
| `packet-sender` | Rust | Utility for simulating vehicle packets |
29-
| `electron-app` | JS | The main Control Station desktop application |
30-
| `@workspace/ui` | TS/React | Shared UI component library (frontend-kit) |
31-
| `@workspace/core` | TS | Shared business logic and types (frontend-kit) |
32-
| `@workspace/eslint-config` | ESLint | Common ESLint configuration (frontend-kit) |
33-
| `@workspace/typescript-config` | TS | Common TypeScript configuration (frontend-kit) |
24+
| Workspace | Language | Description |
25+
| :----------------------------- | :------- | :---------------------------------------------------- |
26+
| `testing-view` | TS/React | Web interface for telemetry testing |
27+
| `competition-view` | TS/React | UI for the competition |
28+
| `backend` | Go | Data ingestion and pod communication server |
29+
| `packet-sender` | Rust | Utility for simulating vehicle packets |
30+
| `hyperloop-control-station` | JS | The main Control Station electron desktop application |
31+
| `@workspace/ui` | TS/React | Shared UI component library (frontend-kit) |
32+
| `@workspace/core` | TS | Shared business logic and types (frontend-kit) |
33+
| `@workspace/eslint-config` | ESLint | Common ESLint configuration (frontend-kit) |
34+
| `@workspace/typescript-config` | TS | Common TypeScript configuration (frontend-kit) |
3435

3536
---
3637

electron-app/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,5 @@ coverage
8181

8282
# Config and config backups
8383
config.toml
84-
config.toml.backup-*
84+
config.toml.backup-*
85+
version.toml

electron-app/BUILD.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
# Hyperloop Control Station Build System
22

3-
The project uses a unified, modular build script (`electron-app/build.mjs`) to handle building the backend (Go), packet sender (Rust), and frontends (React/Vite) for the Electron application.
3+
The project uses a unified, modular build script (`electron-app/build.mjs`) to handle building the backend (Go), and frontends (React/Vite) for the Electron application.
44

55
## Prerequisites
66

77
- **Node.js** & **pnpm**
88
- **Go** (1.21+)
9-
- **Rust/Cargo** (for Packet Sender)
109

1110
## Basic Usage
1211

1312
Run the build script from the `electron-app` directory (or via npm scripts).
1413

1514
```sh
16-
# Build EVERYTHING (Backend, Packet Sender, Frontends)
15+
# Build EVERYTHING (Backend, Frontends)
1716
pnpm build
1817

1918
# OR
@@ -34,9 +33,6 @@ node build.mjs --backend
3433

3534
# Build only the Testing View
3635
node build.mjs --testing-view
37-
38-
# Build only the Packet Sender
39-
node build.mjs --packet-sender
4036
```
4137

4238
## Platform Targeting

electron-app/build.mjs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,13 +222,21 @@ scriptArgs.forEach((arg) => {
222222
});
223223

224224
const specificTargets = Object.keys(CONFIG).filter((key) =>
225-
scriptArgs.includes(`--${key}`)
225+
scriptArgs.includes(`--${key}`),
226226
);
227227
const targetsToBuild =
228228
specificTargets.length > 0 ? specificTargets : Object.keys(CONFIG);
229229

230230
// --- Main Execution ---
231231

232+
console.log(`
233+
______ __ ______ _____ ____________ __
234+
___ / / /____ ________________________ /___________________ __ / / /__ __ \\_ | / /
235+
__ /_/ /__ / / /__ __ \\ _ \\_ ___/_ /_ __ \\ __ \\__ __ \\ _ / / /__ /_/ /_ | / /
236+
_ __ / _ /_/ /__ /_/ / __/ / _ / / /_/ / /_/ /_ /_/ / / /_/ / _ ____/__ |/ /
237+
/_/ /_/ _\\__, / _ .___/\\___//_/ /_/ \\____/\\____/_ .___/ \\____/ /_/ _____/
238+
/____/ /_/ /_/ `);
239+
232240
logger.header("Hyperloop Control Station Build");
233241

234242
(async () => {
@@ -254,7 +262,10 @@ logger.header("Hyperloop Control Station Build");
254262

255263
if (frontendBuilt && !process.env.CI) {
256264
logger.info("Finalizing Electron...");
257-
run("pnpm --filter electron-app install --frozen-lockfile", __dirname);
265+
run(
266+
"pnpm --filter hyperloop-control-station install --frozen-lockfile",
267+
__dirname,
268+
);
258269
}
259270

260271
if (allSuccess) {

electron-app/main.js

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ if (process.platform === "linux") {
3636
// Setup IPC handlers for renderer process communication
3737
setupIpcHandlers();
3838

39-
app.setName("hyperloop-control-station");
40-
4139
// App lifecycle: wait for Electron to be ready
4240
app.whenReady().then(async () => {
4341
// Get the screen width and height
@@ -59,7 +57,6 @@ app.whenReady().then(async () => {
5957
logger.electron.header("Backend process spawned");
6058
} catch (error) {
6159
// Start backend already shows these errors
62-
return;
6360
}
6461

6562
// Create main application window
@@ -118,11 +115,11 @@ app.on("window-all-closed", () => {
118115
});
119116

120117
// Cleanup before app quits
121-
app.on("before-quit", () => {
122-
// Stop backend process gracefully
123-
stopBackend();
124-
// Stop packet sender process gracefully
125-
stopPacketSender();
118+
app.on("before-quit", (e) => {
119+
e.preventDefault();
120+
Promise.all([stopBackend(), stopPacketSender()])
121+
.catch((error) => logger.electron.error("Error during shutdown:", error))
122+
.finally(() => app.exit());
126123
});
127124

128125
// Handle uncaught exceptions globally

electron-app/package.json

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "electron-app",
2+
"name": "hyperloop-control-station",
33
"version": "1.0.0",
44
"description": "Hyperloop UPV Control Station",
55
"main": "main.js",
@@ -57,7 +57,7 @@
5757
"owner": "Hyperloop-UPV",
5858
"repo": "software"
5959
},
60-
"productName": "Hyperloop-Control-Station",
60+
"productName": "Hyperloop-Ctrl",
6161
"directories": {
6262
"output": "dist"
6363
},
@@ -107,9 +107,7 @@
107107
"linux": {
108108
"target": [
109109
"AppImage",
110-
"deb",
111-
"rpm",
112-
"pacman"
110+
"deb"
113111
],
114112
"icon": "icons/512x512.png",
115113
"category": "Utility",

electron-app/preload.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ contextBridge.exposeInMainWorld("electronAPI", {
3737
// Open folder selection dialog
3838
selectFolder: () => ipcRenderer.invoke("select-folder"),
3939
// Receive log message from backend
40-
onLog: (callback) =>
41-
ipcRenderer.on("log", (_event, value) => callback(value)),
40+
onLog: (callback) => {
41+
const listener = (_event, value) => callback(value);
42+
ipcRenderer.removeAllListeners("log");
43+
ipcRenderer.on("log", listener);
44+
return () => ipcRenderer.removeListener("log", listener);
45+
},
4246
});

electron-app/src/config/__tests__/ConfigManager.initialization.test.js

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { describe, it, expect, beforeEach, vi } from "vitest";
21
import fs from "fs";
2+
import { beforeEach, describe, expect, it, vi } from "vitest";
33
import { ConfigManager } from "../configManager.js";
44

55
// Mock fs module
@@ -8,15 +8,24 @@ vi.mock("fs");
88
describe("ConfigManager - Initialization", () => {
99
const templatePath = "/path/to/template.toml";
1010
const userConfigPath = "/path/to/user.toml";
11+
const versionFilePath = "/path/to/version.toml";
12+
const appVersion = "1.0.0";
13+
const appVersionReturnValue = `version = "${appVersion}"`;
1114

1215
beforeEach(() => {
1316
vi.clearAllMocks();
1417
});
1518

1619
it("should create config manager instance", () => {
1720
fs.existsSync.mockReturnValue(true);
21+
fs.readFileSync.mockReturnValue(appVersionReturnValue);
1822

19-
const manager = new ConfigManager(userConfigPath, templatePath);
23+
const manager = new ConfigManager(
24+
userConfigPath,
25+
templatePath,
26+
versionFilePath,
27+
appVersion,
28+
);
2029

2130
expect(manager.userConfigPath).toBe(userConfigPath);
2231
expect(manager.templatePath).toBe(templatePath);
@@ -28,8 +37,9 @@ describe("ConfigManager - Initialization", () => {
2837
return true;
2938
});
3039
fs.mkdirSync.mockImplementation(() => {});
40+
fs.readFileSync.mockReturnValue(appVersionReturnValue);
3141

32-
new ConfigManager(userConfigPath, templatePath);
42+
new ConfigManager(userConfigPath, templatePath, versionFilePath, appVersion);
3343

3444
expect(fs.mkdirSync).toHaveBeenCalledWith("/path/to", {
3545
recursive: true,
@@ -39,17 +49,17 @@ describe("ConfigManager - Initialization", () => {
3949
it("should copy template if user config does not exist", () => {
4050
fs.existsSync.mockImplementation((path) => {
4151
if (path === userConfigPath) return false;
42-
if (path === templatePath) return true;
4352
return true;
4453
});
4554
fs.copyFileSync.mockImplementation(() => {});
55+
fs.writeFileSync.mockImplementation(() => {});
4656
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => {});
4757

48-
new ConfigManager(userConfigPath, templatePath);
58+
new ConfigManager(userConfigPath, templatePath, versionFilePath, appVersion);
4959

5060
expect(fs.copyFileSync).toHaveBeenCalledWith(templatePath, userConfigPath);
5161
expect(consoleSpy).toHaveBeenCalledWith(
52-
expect.stringContaining("Created config from template")
62+
expect.stringContaining("Created config from template"),
5363
);
5464

5565
consoleSpy.mockRestore();
@@ -59,7 +69,7 @@ describe("ConfigManager - Initialization", () => {
5969
fs.existsSync.mockReturnValue(false);
6070

6171
expect(() => {
62-
new ConfigManager(userConfigPath, templatePath);
72+
new ConfigManager(userConfigPath, templatePath, versionFilePath, appVersion);
6373
}).toThrow("Template not found");
6474
});
6575
});

0 commit comments

Comments
 (0)