From 4d5f2225d73263643ba6f31f1d33240b16096520 Mon Sep 17 00:00:00 2001 From: Eric Joanis Date: Mon, 5 Oct 2026 15:35:36 -0400 Subject: [PATCH 1/6] feat: add just-serve target so I can skip slow update-browserlist --- packages/studio-web/project.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/studio-web/project.json b/packages/studio-web/project.json index a0f58f971..efc71bba5 100644 --- a/packages/studio-web/project.json +++ b/packages/studio-web/project.json @@ -84,6 +84,12 @@ "update-browserslist": { "command": "npx -y update-browserslist-db@latest" }, + "just-serve": { + "executor": "@angular-builders/custom-webpack:dev-server", + "options": { + "buildTarget": "studio-web:build:development,en" + } + }, "serve": { "executor": "@angular-builders/custom-webpack:dev-server", "dependsOn": ["update-browserslist"], From 094e8837738a66619183d91c8941dbc66bd3f2d0 Mon Sep 17 00:00:00 2001 From: Eric Joanis Date: Tue, 6 Oct 2026 11:34:05 -0400 Subject: [PATCH 2/6] ci: we always want the playwright artifact --- .github/workflows/end-to-end-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/end-to-end-tests.yml b/.github/workflows/end-to-end-tests.yml index bd59c246f..1a1fba1b5 100644 --- a/.github/workflows/end-to-end-tests.yml +++ b/.github/workflows/end-to-end-tests.yml @@ -113,6 +113,7 @@ jobs: run: npx nx e2e studio-web - name: Upload HTML report + if: always() uses: actions/upload-artifact@v6 with: name: playwright-report--attempt-${{ github.run_attempt }} From 7d94305ab9bf4df1cd8da385ecf99142dccbb0c5 Mon Sep 17 00:00:00 2001 From: Eric Joanis Date: Mon, 5 Oct 2026 15:49:02 -0400 Subject: [PATCH 3/6] refactor: use signals instead of state Booleans --- packages/studio-web/src/app/app.component.ts | 11 +++-- .../src/app/editor/editor.component.html | 2 +- .../src/app/editor/editor.service.ts | 11 +++++ .../studio-web/src/app/privacy-dialog.html | 2 +- .../src/app/upload/upload.component.html | 32 +++++-------- .../src/app/upload/upload.component.ts | 48 +++++++++++-------- 6 files changed, 60 insertions(+), 46 deletions(-) diff --git a/packages/studio-web/src/app/app.component.ts b/packages/studio-web/src/app/app.component.ts index 9d42d010a..9bff06a8b 100644 --- a/packages/studio-web/src/app/app.component.ts +++ b/packages/studio-web/src/app/app.component.ts @@ -56,20 +56,21 @@ export class AppComponent implements OnInit { }) export class PrivacyDialog { private dialogRef = inject(MatDialogRef); - protected analyticsExcluded = - window.localStorage.getItem("plausible_ignore") === "true"; + protected analyticsExcluded = signal( + window.localStorage.getItem("plausible_ignore") === "true", + ); ngOnInit() { this.dialogRef.updateSize("100%"); } toggleAnalytics() { - if (this.analyticsExcluded) { + if (this.analyticsExcluded()) { window.localStorage.removeItem("plausible_ignore"); - this.analyticsExcluded = false; + this.analyticsExcluded.set(false); } else { window.localStorage.setItem("plausible_ignore", "true"); - this.analyticsExcluded = true; + this.analyticsExcluded.set(true); } } } diff --git a/packages/studio-web/src/app/editor/editor.component.html b/packages/studio-web/src/app/editor/editor.component.html index 61f9afdea..2091a1444 100644 --- a/packages/studio-web/src/app/editor/editor.component.html +++ b/packages/studio-web/src/app/editor/editor.component.html @@ -22,7 +22,7 @@

- @if (editorService.uploadFormGroup.valid) { + @if (editorService.uploadFormValid()) {
this.uploadFormGroup.valid), + ), + { + initialValue: this.uploadFormGroup.valid, + }, + ); temporaryBlob: Blob | undefined = undefined; } diff --git a/packages/studio-web/src/app/privacy-dialog.html b/packages/studio-web/src/app/privacy-dialog.html index e7a2fc99e..5c6645408 100644 --- a/packages/studio-web/src/app/privacy-dialog.html +++ b/packages/studio-web/src/app/privacy-dialog.html @@ -34,7 +34,7 @@

Privacy Policy

style="display: flex; justify-content: space-evenly; margin-top: 1em" >
- @if(analyticsExcluded) { + @if(analyticsExcluded()) { - @if (recording) { + @if (recording()) { } - @if ( - !recording && - studioService.audioControl$.value !== null && - playing - ) { + @if (!recording() && has_audio() && playing()) {
- @if (!recording && studioService.audioControl$.value !== null) { + @if (!recording() && has_audio()) {
- @if (!recording && studioService.audioControl$.value !== null) { + @if (!recording() && has_audio()) { - @if (loading) { + @if (loading()) { = []; - protected loading = false; - protected starting_to_record = false; - protected recording = false; - protected playing = false; + protected loading = signal(false); + protected starting_to_record = signal(false); + protected recording = signal(false); + protected has_audio = signal(false); + protected playing = signal(false); private player: any = null; protected contactLink = environment.packageJson.contact; protected progressMode: ProgressBarMode = "indeterminate"; @@ -103,7 +105,7 @@ export class UploadComponent implements OnInit { this.ssjsService.modelLoaded .pipe(takeUntilDestroyed(this.destroyRef$)) .subscribe((loaded) => { - this.isLoaded = loaded; + this.isLoaded.set(loaded); }); // If the textControl$ changes to a Blob or null, reset the @@ -274,13 +276,16 @@ Please check it to make sure all words are spelled out completely, e.g. write "4 } async startRecording() { - if (this.recording) + if (this.recording()) // Not sure why the button stays clickable, but oh well return; try { - this.starting_to_record = true; + this.starting_to_record.set(true); + console.log("About to startRecording()"); await this.microphoneService.startRecording(); - this.recording = true; + console.log("After startRecording()"); + this.recording.set(true); + console.log(this.recording()); } catch (err: any) { let message; if (err.name === "NotAllowedError") { @@ -292,35 +297,35 @@ Please check it to make sure all words are spelled out completely, e.g. write "4 timeOut: 15000, }); } finally { - this.starting_to_record = false; + this.starting_to_record.set(false); } } pauseRecording() { this.microphoneService.pause(); - this.recording = false; + this.recording.set(false); } resumeRecording() { this.microphoneService.resume(); - this.recording = true; + this.recording.set(true); } playRecording() { - if (!this.playing && this.studioService.audioControl$.value !== null) { + if (!this.playing() && this.studioService.audioControl$.value !== null) { let player = new window.Audio(); this.player = player; player.src = URL.createObjectURL(this.studioService.audioControl$.value); player.onended = () => this.stopPlayback(); player.onerror = () => this.stopPlayback(); player.load(); - this.playing = true; + this.playing.set(true); player.play(); } } stopPlayback() { - this.playing = false; + this.playing.set(false); this.player?.pause(); this.player = null; } @@ -328,10 +333,11 @@ Please check it to make sure all words are spelled out completely, e.g. write "4 deleteRecording() { this.audioFileUpload.nativeElement.value = ""; this.studioService.audioControl$.setValue(null); + this.has_audio.set(false); } async stopRecording() { - this.recording = false; + this.recording.set(false); try { let output = await this.microphoneService.stopRecording(); // possibly check for zero-length output and throw here @@ -340,7 +346,10 @@ Please check it to make sure all words are spelled out completely, e.g. write "4 $localize`Yay!`, { timeOut: 10000 }, ); + console.log(output); this.studioService.audioControl$.setValue(output); + this.has_audio.set(true); + console.log(this.studioService.audioControl$.value); // do any post output steps } catch (err: any) { if (err === "Recorder didn't hear anything") { @@ -500,7 +509,7 @@ Please check it to make sure all words are spelled out completely, e.g. write "4 } // Show progress bar - this.loading = true; + this.loading.set(true); this.progressMode = "query"; // Determine text type for API request let input_type; @@ -582,7 +591,7 @@ Please check it to make sure all words are spelled out completely, e.g. write "4 .subscribe({ next: (progress) => { if (progress.hypseg !== undefined) { - this.loading = false; + this.loading.set(false); this.toastr.toasts.forEach((toast) => { // clean all outstanding success and error toasts on alignment success, // they are no longer relevant, but keep the warnings, they are typically @@ -613,7 +622,7 @@ Please check it to make sure all words are spelled out completely, e.g. write "4 } }, error: (err: Error) => { - this.loading = false; + this.loading.set(false); if (err instanceof HttpErrorResponse) { this.reportRasError(err); } else if (err.message.includes("align")) { @@ -629,6 +638,7 @@ Please check it to make sure all words are spelled out completely, e.g. write "4 const el = event.target as HTMLInputElement; if (!el.files || el.files.length !== 1) { this.studioService.audioControl$.setValue(null); + this.has_audio.set(false); return; } From dbc9a262e9ae69de21ef977f51f81386a3fd952f Mon Sep 17 00:00:00 2001 From: Eric Joanis Date: Tue, 6 Oct 2026 11:44:58 -0400 Subject: [PATCH 4/6] fix: up signals --- .../app/shared/wc-styling/wc-styling.component.html | 2 +- .../app/shared/wc-styling/wc-styling.component.ts | 13 +++++++------ .../studio-web/src/app/upload/upload.component.ts | 1 + 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/studio-web/src/app/shared/wc-styling/wc-styling.component.html b/packages/studio-web/src/app/shared/wc-styling/wc-styling.component.html index 527adf2ac..e1295d5ac 100644 --- a/packages/studio-web/src/app/shared/wc-styling/wc-styling.component.html +++ b/packages/studio-web/src/app/shared/wc-styling/wc-styling.component.html @@ -143,7 +143,7 @@

- @if (canUseClipBoard) { + @if (canUseClipBoard()) {