diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 48c8ec87..6976a909 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -1,7 +1,8 @@ name: Playwright Tests on: pull_request: - branches: [main, master] + branches: + - main jobs: test: timeout-minutes: 60 @@ -10,21 +11,27 @@ jobs: image: mcr.microsoft.com/playwright:v1.42.1-jammy steps: - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: node-version: "20.x" registry-url: "https://registry.npmjs.org" - cache: yarn + - name: Install node modules run: yarn --frozen-lockfile --prefer-offline + - name: Run linter run: yarn lint + - name: Run ESLint run: npx eslint . + - name: Run prettier run: npx prettier -c ./src + - name: Run Playwright tests run: yarn playwright test + - uses: actions/upload-artifact@v4 if: always() with: diff --git a/Dockerfile b/Dockerfile index 2ed131f1..a7158ea2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,4 +8,4 @@ RUN yarn install --frozen-lockfile && yarn build FROM nginx:stable -COPY --from=builder /build/dist/ /usr/share/nginx/html +COPY --from=builder /build/dist/browser /usr/share/nginx/html diff --git a/angular.json b/angular.json index 046c1768..8a728863 100644 --- a/angular.json +++ b/angular.json @@ -15,11 +15,11 @@ "prefix": "app", "architect": { "build": { - "builder": "@angular-devkit/build-angular:browser-esbuild", + "builder": "@angular-devkit/build-angular:application", "options": { "outputPath": "dist/", "index": "src/index.html", - "main": "src/main.ts", + "browser": "src/main.ts", "tsConfig": "tsconfig.app.json", "aot": true, "assets": [ @@ -96,8 +96,6 @@ "sourceMap": false, "namedChunks": false, "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, "budgets": [ { "type": "initial", @@ -118,18 +116,16 @@ "with": "src/environments/environment.dev.ts" } ], - "optimization": true, + "optimization": false, "outputHashing": "all", - "sourceMap": false, + "sourceMap": true, "namedChunks": false, - "extractLicenses": true, - "vendorChunk": false, - "buildOptimizer": true, + "extractLicenses": false, "budgets": [ { "type": "initial", - "maximumWarning": "2mb", - "maximumError": "5mb" + "maximumWarning": "5mb", + "maximumError": "10mb" }, { "type": "anyComponentStyle", diff --git a/package.json b/package.json index 36c03883..119feb80 100644 --- a/package.json +++ b/package.json @@ -33,10 +33,11 @@ "@blockly/field-bitmap": "^4.0.13", "@blockly/workspace-backpack": "^5.3.3", "@fortawesome/fontawesome-free": "^6.1.1", - "@leaphy-robotics/avrdude-webassembly": "^1.4.0", + "@leaphy-robotics/avrdude-webassembly": "1.5.0", "@leaphy-robotics/dfu-util-wasm": "1.0.2", "@leaphy-robotics/leaphy-blocks": "2.0.3", "@leaphy-robotics/picotool-wasm": "1.0.2", + "@leaphy-robotics/webusb-ftdi": "^1.0.0", "@ngx-translate/core": "^14.0.0", "@ngx-translate/http-loader": "^7.0.0", "@serialport/parser-readline": "^10.3.0", diff --git a/playwright.config.ts b/playwright.config.ts index 64fc0dcb..cf01205d 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -63,5 +63,6 @@ export default defineConfig({ command: "yarn start", url: "http://localhost:4200/", reuseExistingServer: !process.env.CI, + timeout: 5 * 60 * 1000, }, }); diff --git a/src/app/services/arduino-uploader/protocols/avrdude/index.ts b/src/app/services/arduino-uploader/protocols/avrdude/index.ts index 169da443..7a8da3e0 100644 --- a/src/app/services/arduino-uploader/protocols/avrdude/index.ts +++ b/src/app/services/arduino-uploader/protocols/avrdude/index.ts @@ -43,8 +43,12 @@ export default class Avrdude extends BaseProtocol { // create a promise that resolves when the port.ondisconnect event is fired const disconnectPromise = new Promise((resolve) => { - // todo: add compatibility for fallback devices if required, currently no avrdude devices support this - if (!(this.port instanceof SerialPort)) return; + // todo: add disconnect events for fallback, driver currently does not support this + if ( + typeof SerialPort === "undefined" || + !(this.port instanceof SerialPort) + ) + return; this.port.ondisconnect = resolve; }); @@ -73,6 +77,7 @@ export default class Avrdude extends BaseProtocol { } throw new Error("Avrdude failed"); } + await this.port.open({ baudRate: 115200 }); this.uploadState.statusMessage = "UPDATE_COMPLETE"; return; } diff --git a/src/app/state/robot.wired.state.ts b/src/app/state/robot.wired.state.ts index a386b26e..9b5b2d8b 100644 --- a/src/app/state/robot.wired.state.ts +++ b/src/app/state/robot.wired.state.ts @@ -2,9 +2,13 @@ import { Injectable } from "@angular/core"; import { ChartDataset } from "chart.js"; import { ReplaySubject, BehaviorSubject, Observable } from "rxjs"; import { map, scan } from "rxjs/operators"; -import { SerialPort as MockedSerialPort } from "web-serial-polyfill"; +import { SerialPort as MockedCDCSerialPort } from "web-serial-polyfill"; +import MockedFTDISerialPort from "@leaphy-robotics/webusb-ftdi"; -export type LeaphyPort = SerialPort | MockedSerialPort; +export type LeaphyPort = + | SerialPort + | MockedCDCSerialPort + | MockedFTDISerialPort; @Injectable({ providedIn: "root", @@ -107,8 +111,12 @@ export class RobotWiredState { } } else if (navigator.usb) { if (!forcePrompt) { - const devices = await navigator.usb.getDevices(); - if (devices[0]) port = new MockedSerialPort(devices[0]); + const [device] = await navigator.usb.getDevices(); + if (device) { + if (device.vendorId === 1027) + port = new MockedFTDISerialPort(device); + else port = new MockedCDCSerialPort(device); + } } if (!port && allowPrompt) { const device = await navigator.usb.requestDevice({ @@ -119,7 +127,9 @@ export class RobotWiredState { ), }); try { - port = new MockedSerialPort(device); + if (device.vendorId === 1027) + port = new MockedFTDISerialPort(device); + else port = new MockedCDCSerialPort(device); } catch { throw new Error("WebUSB device is not supported"); } diff --git a/yarn.lock b/yarn.lock index d5e781bb..8984d5f4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1829,10 +1829,12 @@ resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60" integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA== -"@leaphy-robotics/avrdude-webassembly@^1.4.0": - version "1.4.0" - resolved "https://registry.yarnpkg.com/@leaphy-robotics/avrdude-webassembly/-/avrdude-webassembly-1.4.0.tgz#ee5babb8c3202f5346dba45bb07263ae2ce9c185" - integrity sha512-S4vPUIsVWQuEL+GCXfAH+CisJSITNd8cs1PqzBMVwjrbFzs3XnXj/5OJ1xlgOwQkmFHQnmyWcRkQG2C43VGosg== +"@leaphy-robotics/avrdude-webassembly@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@leaphy-robotics/avrdude-webassembly/-/avrdude-webassembly-1.5.0.tgz#8c1bea9864b0d4064b8b79ef4b1121a327c10703" + integrity sha512-8vy45vH7pnMwKBixNeTNWwt8fbuyeREK5oPzPiKiqkQ+AXv+aWi3BojlJyZlVsO10nJpcwgPlDYDRjbDS5Hkuw== + dependencies: + "@leaphy-robotics/webusb-ftdi" "^1.0.0" "@leaphy-robotics/dfu-util-wasm@1.0.2": version "1.0.2" @@ -1851,6 +1853,11 @@ resolved "https://registry.yarnpkg.com/@leaphy-robotics/picotool-wasm/-/picotool-wasm-1.0.2.tgz#648150c5e29204f063750e5348b66dae3f5db14a" integrity sha512-ux3RyjjcHJopr/zOyTkEEtZTgzYTNd5zKNAMXvaVNDqRJIm9jCVTUytIpYPkUV7myXAt23jXl5dIVhsCiEDsqw== +"@leaphy-robotics/webusb-ftdi@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@leaphy-robotics/webusb-ftdi/-/webusb-ftdi-1.0.0.tgz#999a9de85cef82747f09b1dfa6e01374bd85ba07" + integrity sha512-/M3XdqQ9h0EPlPdE1FRCZYz8VUzP4JZe1sidUNPMOBmzwALiXElPa6jLu2eArPupt23cN1PN9yXNpSjOwtRi0Q== + "@leichtgewicht/ip-codec@^2.0.1": version "2.0.4" resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b"