Skip to content

Commit da0fd3c

Browse files
ctw-joao-luisrodrigo-p-rodriguesdependabot[bot]gabriela-almeida-ctwaneuwald-ctw
authored
Release v1.23.1 (#917)
## User-Facing Changes Release to push to production a fix to User Scripts panel input bug ## Description <!-- link relevant GitHub issues --> <!-- add `docs` label if this PR requires documentation updates --> <!-- add relevant metric tracking for experimental / new features --> ## Checklist - [ ] The web version was tested and it is running ok - [ ] The desktop version was tested and it is running ok - [ ] This change is covered by unit tests - [ ] Files constants.ts, types.ts and *.style.ts have been checked and relevant code snippets have been relocated --------- Signed-off-by: Bezerra Luiz, (Luiz.Bezerra@ctw.bmwgroup.com) <luiz.bezerra+QCOM@ctw.bmwgroup.com> Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: ctw-joao-luis <Joao.Luis@ctw.bmwgroup.com> Signed-off-by: Thomas Sedlmayer <tsedlmayer@pmsfit.de> Signed-off-by: Taeseung Sohn <paulsohnjp@gmail.com> Signed-off-by: Gabriela Almeida <gabriela.almeida@criticaltechworks.com> Co-authored-by: Rodrigo CTW <rodrigo.PE.rodrigues@ctw.bmwgroup.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Gabriela Almeida <gabriela.almeida@criticaltechworks.com> Co-authored-by: Alexandre Neuwald CTW <Alexandre.Neuwald@ctw.bmwgroup.com> Co-authored-by: Luiz Bezerra <luiz.bezerra@ctw.bmwgroup.com> Co-authored-by: Bezerra Luiz, (Luiz.Bezerra@ctw.bmwgroup.com) <luiz.bezerra+QCOM@ctw.bmwgroup.com> Co-authored-by: Alexandre Neuwald <alexandre.neuwald@criticaltechworks.com> Co-authored-by: Bruno Abreu <bmachadorj@gmail.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Bezerra Luiz, (Luiz.Bezerra@ctw.bmwgroup.com) <198787532+luiz-bezerra-ctw-bmwgroup-com_QCOM@users.noreply.github.com> Co-authored-by: Thomas Sedlmayer <tsedlmayer@pmsfit.de> Co-authored-by: Taeseung Sohn <paulsohnjp@gmail.com> Co-authored-by: Planck-Ho <wenloong.he@gmail.com> Co-authored-by: lichtblick-bot <lichtblick@bmwgroup.com>
1 parent aaf05b2 commit da0fd3c

11 files changed

Lines changed: 478 additions & 26 deletions

File tree

‎.github/workflows/pre-build.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
- name: Set up Node.js
2121
uses: actions/setup-node@v6
2222
with:
23-
node-version: 16.17
23+
node-version: 20
2424

2525
- name: Enable corepack
2626
run: corepack enable yarn
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# studio-extension-turtlesim version history
2+
3+
## 0.0.0
4+
5+
- Alpha testing
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# studio-extension-turtlesim
2+
3+
## _A Foxglove Studio Extension_
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "studio-extension-turtlesim",
3+
"version": "0.0.1",
4+
"displayName": "turtlesim",
5+
"description": "",
6+
"publisher": "Foxglove Inc.",
7+
"license": "MPL-2.0",
8+
"main": "./dist/extension.js",
9+
"scripts": {
10+
"foxglove:prepublish": "fox build --mode production",
11+
"build": "fox build",
12+
"package": "fox build --mode production && fox package",
13+
"local-install": "fox build && fox install",
14+
"pretest": "fox pretest"
15+
},
16+
"devDependencies": {
17+
"@foxglove/fox": "file:../fox",
18+
"@foxglove/studio": "0.11.0",
19+
"typescript": "4.3.2"
20+
}
21+
}

‎e2e/fixtures/electron.ts‎

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,25 @@ import path from "path";
1010
export type ElectronFixtures = {
1111
electronApp: ElectronApplication;
1212
mainWindow: Page;
13+
preInstalledExtensions?: string[];
1314
};
1415

1516
const WEBPACK_PATH = path.resolve(__dirname, "../../desktop/.webpack");
1617

1718
export const test = base.extend<ElectronFixtures & { electronArgs: string[] }>({
1819
electronArgs: [],
19-
electronApp: async ({ electronArgs }, use) => {
20+
preInstalledExtensions: [],
21+
22+
electronApp: async ({ electronArgs, preInstalledExtensions }, use) => {
2023
checkBuild(WEBPACK_PATH);
2124

22-
// Create a new user data directory for each test, which bypasses the `app.requestSingleInstanceLock()`
2325
const userDataDir = await mkdtemp(path.join(os.tmpdir(), "e2e-test-"));
24-
25-
// Create a new home directory for each test, which creates a brand new .lcihtblick-suite directory for e2e testing
2626
const homeDir = await mkdtemp(path.join(os.tmpdir(), "home-e2e-test-"));
2727

28+
for (const filename of preInstalledExtensions ?? []) {
29+
preInstallExtensionInUserFolder(homeDir, filename);
30+
}
31+
2832
const app = await electron.launch({
2933
args: [
3034
WEBPACK_PATH,
@@ -54,4 +58,23 @@ function checkBuild(webpackPath: string): void {
5458
}
5559
}
5660

61+
function preInstallExtensionInUserFolder(homeDir: string, filename: string): void {
62+
const source = path.join(process.cwd(), "e2e", "fixtures", "assets", filename);
63+
64+
if (!fs.existsSync(source)) {
65+
throw new Error(`Extension asset not found: ${source}`);
66+
}
67+
68+
const extensionsDir = path.join(homeDir, ".lichtblick-suite", "extensions");
69+
fs.mkdirSync(extensionsDir, { recursive: true });
70+
71+
const stats = fs.statSync(source);
72+
if (stats.isDirectory()) {
73+
const destDir = path.join(extensionsDir, filename);
74+
fs.cpSync(source, destDir, { recursive: true });
75+
} else {
76+
fs.copyFileSync(source, path.join(extensionsDir, filename));
77+
}
78+
}
79+
5780
export { expect } from "@playwright/test";
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// SPDX-FileCopyrightText: Copyright (C) 2023-2026 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)<lichtblick@bmwgroup.com>
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
import { test, expect } from "../../../fixtures/electron";
5+
6+
const extensionSourceFolder = "lichtblick.suite-extension-turtlesim-0.0.1";
7+
8+
/**
9+
* GIVEN turtlesim extension in already on root level folder
10+
* WHEN the extensions menu is opened
11+
* AND searched for turtlesim
12+
* THEN the turtlesim extension should appear on the extensions list
13+
*/
14+
test.use({
15+
preInstalledExtensions: [extensionSourceFolder],
16+
});
17+
18+
test("should install an extension (user folder)", async ({ mainWindow }) => {
19+
// When
20+
await mainWindow.getByTestId("DataSourceDialog").getByTestId("CloseIcon").click();
21+
22+
await mainWindow.getByTestId("user-button").click();
23+
await mainWindow.getByRole("menuitem", { name: "Extensions" }).click();
24+
const searchBar = mainWindow.getByPlaceholder("Search Extensions...");
25+
await searchBar.fill("turtlesim");
26+
const turtlesimExtension = mainWindow
27+
.locator('[data-testid="extension-list-entry"]')
28+
.filter({ hasText: "turtlesim" })
29+
.filter({ hasText: "0.0.1" });
30+
31+
// Then
32+
await expect(turtlesimExtension).toBeVisible();
33+
});
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// SPDX-FileCopyrightText: Copyright (C) 2023-2026 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)<lichtblick@bmwgroup.com>
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
import { test, expect } from "@playwright/test";
5+
6+
import { loadFiles } from "../../fixtures/load-files";
7+
8+
const MCAP_FILENAME = "example.mcap";
9+
10+
/**
11+
* GIVEN a .mcap file and layout are loaded
12+
* AND the player time is initialized
13+
* WHEN the playback timestamp is manually edited in the player input
14+
* AND the new timestamp is confirmed
15+
* THEN the URL time parameter should update to the new ISO timestamp
16+
*/
17+
18+
test("is able to manually edit the timestamp display on the player", async ({ page }) => {
19+
// Given
20+
const getTimeParam = () => new URL(page.url()).searchParams.get("time");
21+
22+
await page.goto("/");
23+
await loadFiles({ mainWindow: page, filenames: MCAP_FILENAME });
24+
const urlInitialTimestamp = "2025-02-26T10:37:15.547000000Z";
25+
26+
// When
27+
await page.evaluate((time) => {
28+
const url = new URL(window.location.href);
29+
url.searchParams.set("time", time);
30+
window.history.replaceState({}, "", url.toString());
31+
}, urlInitialTimestamp);
32+
await page.waitForURL(() => getTimeParam() === urlInitialTimestamp);
33+
34+
// Then
35+
expect(getTimeParam()).toBe(urlInitialTimestamp);
36+
37+
// When
38+
const timestampInput = page.getByTestId("PlaybackTime-text").locator("input");
39+
const newTimestamp = "2025-02-26 10:37:18.499 AM WET";
40+
await timestampInput.click();
41+
await timestampInput.fill(newTimestamp);
42+
await timestampInput.press("Enter");
43+
await timestampInput.blur();
44+
45+
// Then
46+
const urlNewTimestamp = "2025-02-26T10:37:18.499000000Z";
47+
await page.waitForURL(() => getTimeParam() === urlNewTimestamp);
48+
expect(getTimeParam()).toBe(urlNewTimestamp);
49+
});
50+
51+
/**
52+
* GIVEN a .mcap file and layout are loaded
53+
* AND the playback time display is switched to epoch format
54+
* AND the player time is initialized
55+
* WHEN the playback timestamp is manually edited using an epoch value
56+
* AND the new timestamp is confirmed
57+
* THEN the URL time parameter should update to the corresponding ISO timestamp
58+
*/
59+
60+
test("is able to manually edit the timestamp display (epoch format) on the player", async ({
61+
page,
62+
}) => {
63+
// Given
64+
const getTimeParam = () => new URL(page.url()).searchParams.get("time");
65+
66+
await page.goto("/");
67+
await loadFiles({ mainWindow: page, filenames: MCAP_FILENAME });
68+
const urlInitialTimestamp = "2025-02-26T10:37:15.547000000Z";
69+
70+
// When
71+
const playerStartingTime = page.getByTestId("PlaybackTime-text").locator("div");
72+
// Playback time display needs to be hovered first so clicking on it is possible
73+
await playerStartingTime.hover();
74+
await page.getByTestId("playback-time-display-toggle-button").click();
75+
await page.getByTestId("playback-time-display-option-SEC").click();
76+
77+
// When
78+
await page.evaluate((time) => {
79+
const url = new URL(window.location.href);
80+
url.searchParams.set("time", time);
81+
window.history.replaceState({}, "", url.toString());
82+
}, urlInitialTimestamp);
83+
await page.waitForURL(() => getTimeParam() === urlInitialTimestamp);
84+
85+
// Then
86+
expect(getTimeParam()).toBe(urlInitialTimestamp);
87+
88+
// When
89+
const timestampInput = page.getByTestId("PlaybackTime-text").locator("input");
90+
const newEpochTimestamp = "1740566238.499000000";
91+
await timestampInput.click();
92+
await timestampInput.fill(newEpochTimestamp);
93+
await timestampInput.press("Enter");
94+
await timestampInput.blur();
95+
96+
// Then
97+
const urlNewTimestamp = "2025-02-26T10:37:18.499000000Z";
98+
await page.waitForURL(() => getTimeParam() === urlNewTimestamp);
99+
expect(getTimeParam()).toBe(urlNewTimestamp);
100+
});

‎package.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@
7979
"dompurify": "3.2.4",
8080
"js-yaml": "4.1.1",
8181
"qs": "6.14.1",
82-
"tar": "7.5.4"
82+
"tar": "7.5.7",
83+
"undici": "6.23.0"
8384
},
8485
"devDependencies": {
8586
"@actions/core": "1.11.1",

0 commit comments

Comments
 (0)