diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1f475a2060..d7aa188171 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -91,19 +91,34 @@ jobs: run: | ./gradlew build ./gradlew clean - + typecheck-client: + name: "Typecheck Client" + runs-on: ubuntu-24.04 + steps: + - name: Checkout code + uses: actions/checkout@v6 + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 10 + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 22 + cache: pnpm + cache-dependency-path: photon-client/pnpm-lock.yaml + - name: Typecheck Client + working-directory: photon-client + run: | + pnpm install + pnpm type-check playwright-tests: name: "Playwright E2E tests" runs-on: ubuntu-24.04 needs: [validation] steps: - # Checkout code. - name: Checkout code uses: actions/checkout@v6 - with: - fetch-depth: 0 - - name: Fetch tags - run: git fetch --tags --force - name: Install Java 17 uses: actions/setup-java@v5 with: @@ -138,7 +153,6 @@ jobs: runs-on: ubuntu-24.04 needs: [validation] steps: - # Checkout code. - name: Checkout code uses: actions/checkout@v6 with: diff --git a/photon-client/env.d.ts b/photon-client/env.d.ts index 11f02fe2a0..c5d1606877 100644 --- a/photon-client/env.d.ts +++ b/photon-client/env.d.ts @@ -1 +1,3 @@ /// + +declare module "vue3-virtual-scroll-list"; diff --git a/photon-client/eslint.config.mjs b/photon-client/eslint.config.mjs index 7191125429..4721ca0a8a 100644 --- a/photon-client/eslint.config.mjs +++ b/photon-client/eslint.config.mjs @@ -5,7 +5,7 @@ import skipFormattingConfig from "@vue/eslint-config-prettier/skip-formatting"; export default defineConfigWithVueTs( pluginVue.configs["flat/recommended-error"], - vueTsConfigs.recommended, + vueTsConfigs.recommendedTypeChecked, skipFormattingConfig, { ignores: ["**/dist/**", "playwright-report"] @@ -39,13 +39,16 @@ export default defineConfigWithVueTs( "vue/no-undef-properties": "error", "vue/no-unused-properties": "error", "vue/no-unused-refs": "error", + "vue/prefer-use-template-ref": "error", "vue/no-use-v-else-with-v-for": "error", "vue/no-useless-mustaches": "error", "vue/no-useless-v-bind": "error", "vue/require-default-prop": "off", "vue/v-for-delimiter-style": "error", "vue/v-on-event-hyphenation": "off", - "@typescript-eslint/no-explicit-any": "off", + "vue/require-typed-ref": "error", + "@typescript-eslint/no-empty-object-type": "error", + "@typescript-eslint/no-explicit-any": "error", "vue/valid-v-slot": ["error", { allowModifiers: true }] } } diff --git a/photon-client/package.json b/photon-client/package.json index b5b11dbade..0000df4f9f 100644 --- a/photon-client/package.json +++ b/photon-client/package.json @@ -14,8 +14,8 @@ "format-ci": "prettier --check src/", "test": "playwright test", "test-ui": "playwright test --ui", - "test-setup": "playwright install --with-deps" - + "test-setup": "playwright install --with-deps", + "type-check": "vue-tsc" }, "dependencies": { "@fontsource/prompt": "^5.2.6", @@ -37,6 +37,7 @@ "@types/node": "^22.15.14", "@types/three": "^0.178.0", "@vitejs/plugin-vue": "^6.0.0", + "vue-tsc": "^3.2.5", "@vue/eslint-config-prettier": "^10.2.0", "@vue/eslint-config-typescript": "^14.5.0", "@vue/tsconfig": "^0.7.0", diff --git a/photon-client/pnpm-lock.yaml b/photon-client/pnpm-lock.yaml index 1168ca0b1d..cdb50493ba 100644 --- a/photon-client/pnpm-lock.yaml +++ b/photon-client/pnpm-lock.yaml @@ -90,6 +90,9 @@ importers: vite-plugin-vuetify: specifier: ^2.1.1 version: 2.1.1(vite@7.0.5(@types/node@22.15.14)(sass@1.89.2))(vue@3.5.13(typescript@5.8.3))(vuetify@3.8.3) + vue-tsc: + specifier: ^3.2.5 + version: 3.2.5(typescript@5.8.3) packages: @@ -379,36 +382,42 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.1': resolution: {integrity: sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.1': resolution: {integrity: sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.1': resolution: {integrity: sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.1': resolution: {integrity: sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.1': resolution: {integrity: sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@parcel/watcher-win32-arm64@2.5.1': resolution: {integrity: sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==} @@ -478,56 +487,67 @@ packages: resolution: {integrity: sha512-de6TFZYIvJwRNjmW3+gaXiZ2DaWL5D5yGmSYzkdzjBDS3W+B9JQ48oZEsmMvemqjtAFzE16DIBLqd6IQQRuG9Q==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.40.2': resolution: {integrity: sha512-urjaEZubdIkacKc930hUDOfQPysezKla/O9qV+O89enqsqUmQm8Xj8O/vh0gHg4LYfv7Y7UsE3QjzLQzDYN1qg==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.40.2': resolution: {integrity: sha512-KlE8IC0HFOC33taNt1zR8qNlBYHj31qGT1UqWqtvR/+NuCVhfufAq9fxO8BMFC22Wu0rxOwGVWxtCMvZVLmhQg==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.40.2': resolution: {integrity: sha512-j8CgxvfM0kbnhu4XgjnCWJQyyBOeBI1Zq91Z850aUddUmPeQvuAy6OiMdPS46gNFgy8gN1xkYyLgwLYZG3rBOg==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.40.2': resolution: {integrity: sha512-Ybc/1qUampKuRF4tQXc7G7QY9YRyeVSykfK36Y5Qc5dmrIxwFhrOzqaVTNoZygqZ1ZieSWTibfFhQ5qK8jpWxw==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-powerpc64le-gnu@4.40.2': resolution: {integrity: sha512-3FCIrnrt03CCsZqSYAOW/k9n625pjpuMzVfeI+ZBUSDT3MVIFDSPfSUgIl9FqUftxcUXInvFah79hE1c9abD+Q==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.40.2': resolution: {integrity: sha512-QNU7BFHEvHMp2ESSY3SozIkBPaPBDTsfVNGx3Xhv+TdvWXFGOSH2NJvhD1zKAT6AyuuErJgbdvaJhYVhVqrWTg==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.40.2': resolution: {integrity: sha512-5W6vNYkhgfh7URiXTO1E9a0cy4fSgfE4+Hl5agb/U1sa0kjOLMLC1wObxwKxecE17j0URxuTrYZZME4/VH57Hg==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.40.2': resolution: {integrity: sha512-B7LKIz+0+p348JoAL4X/YxGx9zOx3sR+o6Hj15Y3aaApNfAshK8+mWZEf759DXfRLeL2vg5LYJBB7DdcleYCoQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.40.2': resolution: {integrity: sha512-lG7Xa+BmBNwpjmVUbmyKxdQJ3Q6whHjMjzQplOs5Z+Gj7mxPtWakGHqzMqNER68G67kmCX9qX57aRsW5V0VOng==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.40.2': resolution: {integrity: sha512-tD46wKHd+KJvsmije4bUskNuvWKFcTOIM9tZ/RrmIvcXnbi0YK/cKS9FzFtAm7Oxi2EhV5N2OpfFB348vSQRXA==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.40.2': resolution: {integrity: sha512-Bjv/HG8RRWLNkXwQQemdsWw4Mg+IJ29LK+bJPW2SCzPKOUaMmPEppQlu/Fqk1d7+DX3V7JbFdbkh/NMmurT6Pg==} @@ -625,6 +645,15 @@ packages: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 vue: ^3.2.25 + '@volar/language-core@2.4.28': + resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==} + + '@volar/source-map@2.4.28': + resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==} + + '@volar/typescript@2.4.28': + resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==} + '@vue/compiler-core@3.5.13': resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} @@ -666,6 +695,9 @@ packages: typescript: optional: true + '@vue/language-core@3.2.5': + resolution: {integrity: sha512-d3OIxN/+KRedeM5wQ6H6NIpwS3P5gC9nmyaHgBk+rO6dIsjY+tOh4UlPpiZbAh3YtLdCGEX4M16RmsBqPmJV+g==} + '@vue/reactivity@3.5.13': resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} @@ -721,6 +753,9 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + alien-signals@3.1.2: + resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -1205,6 +1240,9 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -1235,6 +1273,9 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -1503,6 +1544,9 @@ packages: yaml: optional: true + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + vue-eslint-parser@10.1.3: resolution: {integrity: sha512-dbCBnd2e02dYWsXoqX5yKUZlOt+ExIpq7hmHKPb5ZqKcjf++Eo0hMseFTZMLKThrUk61m+Uv6A2YSBve6ZvuDQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1514,6 +1558,12 @@ packages: peerDependencies: vue: ^3.2.0 + vue-tsc@3.2.5: + resolution: {integrity: sha512-/htfTCMluQ+P2FISGAooul8kO4JMheOTCbCy4M6dYnYYjqLe3BExZudAua6MSIKSFYQtFOYAll7XobYwcpokGA==} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + vue3-virtual-scroll-list@0.2.1: resolution: {integrity: sha512-G4KxITUOy9D4ro15zOp40D6ogmMefzjIyMsBKqN3xGbV1P6dlKYMx+BBXCKm3Nr/6iipcUKM272Sh2AJRyWMyQ==} peerDependencies: @@ -1976,6 +2026,18 @@ snapshots: vite: 7.0.5(@types/node@22.15.14)(sass@1.89.2) vue: 3.5.13(typescript@5.8.3) + '@volar/language-core@2.4.28': + dependencies: + '@volar/source-map': 2.4.28 + + '@volar/source-map@2.4.28': {} + + '@volar/typescript@2.4.28': + dependencies: + '@volar/language-core': 2.4.28 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + '@vue/compiler-core@3.5.13': dependencies: '@babel/parser': 7.27.2 @@ -2048,6 +2110,16 @@ snapshots: transitivePeerDependencies: - supports-color + '@vue/language-core@3.2.5': + dependencies: + '@volar/language-core': 2.4.28 + '@vue/compiler-dom': 3.5.13 + '@vue/shared': 3.5.13 + alien-signals: 3.1.2 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + picomatch: 4.0.2 + '@vue/reactivity@3.5.13': dependencies: '@vue/shared': 3.5.13 @@ -2104,6 +2176,8 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + alien-signals@3.1.2: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -2601,6 +2675,8 @@ snapshots: ms@2.1.3: {} + muggle-string@0.4.1: {} + nanoid@3.3.11: {} natural-compare@1.4.0: {} @@ -2633,6 +2709,8 @@ snapshots: dependencies: callsites: 3.1.0 + path-browserify@1.0.1: {} + path-exists@4.0.0: {} path-key@3.1.1: {} @@ -2863,6 +2941,8 @@ snapshots: fsevents: 2.3.3 sass: 1.89.2 + vscode-uri@3.1.0: {} + vue-eslint-parser@10.1.3(eslint@9.31.0): dependencies: debug: 4.4.0 @@ -2881,6 +2961,12 @@ snapshots: '@vue/devtools-api': 6.6.4 vue: 3.5.13(typescript@5.8.3) + vue-tsc@3.2.5(typescript@5.8.3): + dependencies: + '@volar/typescript': 2.4.28 + '@vue/language-core': 3.2.5 + typescript: 5.8.3 + vue3-virtual-scroll-list@0.2.1(vue@3.5.13(typescript@5.8.3)): dependencies: vue: 3.5.13(typescript@5.8.3) diff --git a/photon-client/src/App.vue b/photon-client/src/App.vue index f24875a0c9..edcdc365c1 100644 --- a/photon-client/src/App.vue +++ b/photon-client/src/App.vue @@ -11,9 +11,10 @@ import { useTheme } from "vuetify"; import { restoreThemeConfig } from "@/lib/ThemeManager"; const is_demo = import.meta.env.MODE === "demo"; +const backendHost = inject("backendHost"); if (!is_demo) { const websocket = new AutoReconnectingWebsocket( - `ws://${inject("backendHost")}/websocket_data`, + `ws://${backendHost}/websocket_data`, () => { useStateStore().$patch({ backendConnected: true }); }, diff --git a/photon-client/src/components/app/photon-3d-visualizer.vue b/photon-client/src/components/app/photon-3d-visualizer.vue index 9f457ded77..cde1d3c720 100644 --- a/photon-client/src/components/app/photon-3d-visualizer.vue +++ b/photon-client/src/components/app/photon-3d-visualizer.vue @@ -3,7 +3,7 @@ import type { PhotonTarget } from "@/types/PhotonTrackingTypes"; // @ts-expect-error Intellisense says these conflict with the dynamic imports below import type { Mesh, Object3D, PerspectiveCamera, Scene, WebGLRenderer } from "three"; // @ts-expect-error Intellisense says these conflict with the dynamic imports below -import type { TrackballControls } from "three/examples/jsm/controls/TrackballControls"; +import type { TrackballControls } from "three/examples/jsm/controls/TrackballControls.js"; import { onBeforeUnmount, onMounted, watchEffect } from "vue"; const { ArrowHelper, @@ -20,7 +20,7 @@ const { Scene, WebGLRenderer } = await import("three"); -const { TrackballControls } = await import("three/examples/jsm/controls/TrackballControls"); +const { TrackballControls } = await import("three/examples/jsm/controls/TrackballControls.js"); import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore"; import { createPerspectiveCamera } from "@/lib/ThreeUtils"; @@ -213,14 +213,14 @@ onMounted(async () => { renderer.render(scene, camera); }; - drawTargets(props.targets); + await drawTargets(props.targets); animate(); }); onBeforeUnmount(() => { window.removeEventListener("resize", onWindowResize); }); watchEffect(() => { - drawTargets(props.targets); + void drawTargets(props.targets); }); diff --git a/photon-client/src/components/app/photon-calibration-visualizer.vue b/photon-client/src/components/app/photon-calibration-visualizer.vue index 31910269ce..246a722f69 100644 --- a/photon-client/src/components/app/photon-calibration-visualizer.vue +++ b/photon-client/src/components/app/photon-calibration-visualizer.vue @@ -1,5 +1,13 @@ diff --git a/photon-client/src/components/app/photon-camera-stream.vue b/photon-client/src/components/app/photon-camera-stream.vue index 5c0e76d3fe..ffbbf959f0 100644 --- a/photon-client/src/components/app/photon-camera-stream.vue +++ b/photon-client/src/components/app/photon-camera-stream.vue @@ -1,5 +1,5 @@ diff --git a/photon-client/src/components/app/photon-log-view.vue b/photon-client/src/components/app/photon-log-view.vue index 5d219fc104..0f9a17b797 100644 --- a/photon-client/src/components/app/photon-log-view.vue +++ b/photon-client/src/components/app/photon-log-view.vue @@ -1,5 +1,5 @@