diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0f52024b89..246e3eb5c9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -91,18 +91,34 @@ jobs: # ./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: 24 + cache: pnpm + cache-dependency-path: photon-client/pnpm-lock.yaml + - name: Typecheck Client + working-directory: photon-client + run: | + pnpm install --frozen-lockfile + 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 - uses: actions/setup-java@v5 with: java-version: 25 @@ -136,7 +152,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..aa86eb2261 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"] @@ -42,10 +42,13 @@ export default defineConfigWithVueTs( "vue/no-use-v-else-with-v-for": "error", "vue/no-useless-mustaches": "error", "vue/no-useless-v-bind": "error", + "vue/prefer-use-template-ref": "error", "vue/require-default-prop": "off", + "vue/require-typed-ref": "error", "vue/v-for-delimiter-style": "error", "vue/v-on-event-hyphenation": "off", - "@typescript-eslint/no-explicit-any": "off", + "@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 fc7070e138..9859aef8e6 100644 --- a/photon-client/package.json +++ b/photon-client/package.json @@ -17,8 +17,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 --noEmit" }, "dependencies": { "@fontsource/prompt": "^5.2.6", @@ -40,6 +40,7 @@ "@types/node": "^24.0.0", "@types/three": "^0.178.0", "@vitejs/plugin-vue": "^6.0.6", + "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 a27154d89c..1ac335e64c 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@8.0.10(@types/node@24.12.2)(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: @@ -500,6 +503,15 @@ packages: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.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==} @@ -541,6 +553,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==} @@ -596,6 +611,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'} @@ -1154,6 +1172,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} @@ -1184,6 +1205,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'} @@ -1455,6 +1479,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} @@ -1466,6 +1493,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: @@ -1874,6 +1907,18 @@ snapshots: vite: 8.0.10(@types/node@24.12.2)(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 @@ -1946,6 +1991,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.4 + '@vue/reactivity@3.5.13': dependencies: '@vue/shared': 3.5.13 @@ -2002,6 +2057,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 @@ -2522,6 +2579,8 @@ snapshots: ms@2.1.3: {} + muggle-string@0.4.1: {} + nanoid@3.3.11: {} natural-compare@1.4.0: {} @@ -2554,6 +2613,8 @@ snapshots: dependencies: callsites: 3.1.0 + path-browserify@1.0.1: {} + path-exists@4.0.0: {} path-key@3.1.1: {} @@ -2778,6 +2839,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 @@ -2796,6 +2859,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..44b336068e 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..ed02cc320d 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 @@