From cca0a7461b67393148bd8e6d827f47e0da4af9f9 Mon Sep 17 00:00:00 2001
From: Mathias
Date: Thu, 1 Oct 2026 18:43:14 +0200
Subject: [PATCH] feat(web): tell the user when a video track was ignored, in
every state
A Teams meeting with the camera off is still a video file. It is accepted, only
its audio is transcribed, and the page says so in queued, transcribing, done and
failed -- not just at the end.
Co-Authored-By: Claude Sonnet 5.5
---
internal/web/uploads.templ | 15 +++++
internal/web/uploads_templ.go | 117 ++++++++++++++++++++++++----------
2 files changed, 100 insertions(+), 32 deletions(-)
diff --git a/internal/web/uploads.templ b/internal/web/uploads.templ
index b084c10..f4bf11b 100644
--- a/internal/web/uploads.templ
+++ b/internal/web/uploads.templ
@@ -60,6 +60,7 @@ templ uploadStatus(u domain.UploadedTranscript, chatEnabled bool) {
switch u.Status {
case domain.UploadDone:
+ @videoNotice(u.HadVideo)
Transcribed { uploads.FormatDuration(time.Duration(u.AudioSeconds * float64(time.Second))) }
of audio by { u.Endpoint }.
@@ -74,6 +75,7 @@ templ uploadStatus(u domain.UploadedTranscript, chatEnabled bool) {
case domain.UploadFailed:
+ @videoNotice(u.HadVideo)
{ uploadFailureMessage(u.ErrorKind) }
default:
@@ -84,6 +86,7 @@ templ uploadStatus(u domain.UploadedTranscript, chatEnabled bool) {
hx-trigger={ "every " + uploadPollEvery }
hx-swap="outerHTML"
>
+ @videoNotice(u.HadVideo)
if u.Status == domain.UploadTranscribing {
Transcribing… a long recording takes a few minutes.
} else {
@@ -108,3 +111,15 @@ templ UploadChatPage(u domain.UploadedTranscript, v chatView) {
}
}
+
+// videoNotice tells the user a video track was present and what became of it. A
+// Teams meeting with the camera off is still a video file; it is accepted, only the
+// audio is transcribed, and the picture is thrown away — so say so, in every state,
+// instead of leaving the user to wonder (ADR-033).
+templ videoNotice(hadVideo bool) {
+ if hadVideo {
+
+ This file contained a video track. Only its audio was used; the video was discarded and nothing from it was kept.
+
+ }
+}
diff --git a/internal/web/uploads_templ.go b/internal/web/uploads_templ.go
index c848d97..396b7f2 100644
--- a/internal/web/uploads_templ.go
+++ b/internal/web/uploads_templ.go
@@ -5,10 +5,8 @@ package web
//lint:file-ignore SA4006 This context is only used if a nested component is present.
-import (
- "github.com/a-h/templ"
- templruntime "github.com/a-h/templ/runtime"
-)
+import "github.com/a-h/templ"
+import templruntime "github.com/a-h/templ/runtime"
import (
"fmt"
@@ -268,133 +266,153 @@ func uploadStatus(u domain.UploadedTranscript, chatEnabled bool) templ.Component
ctx = templ.ClearChildren(ctx)
switch u.Status {
case domain.UploadDone:
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "Transcribed ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = videoNotice(u.HadVideo).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "
Transcribed ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var13 string
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(uploads.FormatDuration(time.Duration(u.AudioSeconds * float64(time.Second))))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 64, Col: 95}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 65, Col: 95}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, " of audio by ")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, " of audio by ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var14 string
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(u.Endpoint)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 65, Col: 48}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 66, Col: 48}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, ".
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, ".")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if chatEnabled {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "
Ask about this recording
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "\">Ask about this recording")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "
Transcript
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "Transcript
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var16 string
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(u.Content)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 72, Col: 40}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 73, Col: 40}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
case domain.UploadFailed:
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = videoNotice(u.HadVideo).Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var17 string
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(uploadFailureMessage(u.ErrorKind))
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 77, Col: 42}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 79, Col: 42}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
default:
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "\" hx-swap=\"outerHTML\">")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = videoNotice(u.HadVideo).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if u.Status == domain.UploadTranscribing {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "
Transcribing… a long recording takes a few minutes.
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "
Transcribing… a long recording takes a few minutes.
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
} else {
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "
Queued — waiting for its turn to be transcribed.
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "
Queued — waiting for its turn to be transcribed.
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -438,20 +456,20 @@ func UploadChatPage(u domain.UploadedTranscript, v chatView) templ.Component {
}()
}
ctx = templ.InitializeContext(ctx)
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var22 string
templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(u.Title)
if templ_7745c5c3_Err != nil {
- return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 101, Col: 16}
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/uploads.templ`, Line: 104, Col: 16}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "
Ask about this recording
Answers come only from this recording's transcript, which is private to you.
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "
Ask about this recording
Answers come only from this recording's transcript, which is private to you.
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -459,20 +477,20 @@ func UploadChatPage(u domain.UploadedTranscript, v chatView) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "Back to the transcript
")
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "\">Back to the transcript
")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@@ -486,4 +504,39 @@ func UploadChatPage(u domain.UploadedTranscript, v chatView) templ.Component {
})
}
+// videoNotice tells the user a video track was present and what became of it. A
+// Teams meeting with the camera off is still a video file; it is accepted, only the
+// audio is transcribed, and the picture is thrown away — so say so, in every state,
+// instead of leaving the user to wonder (ADR-033).
+func videoNotice(hadVideo bool) templ.Component {
+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+ return templ_7745c5c3_CtxErr
+ }
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var24 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var24 == nil {
+ templ_7745c5c3_Var24 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ if hadVideo {
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "This file contained a video track. Only its audio was used; the video was discarded and nothing from it was kept.
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ }
+ return nil
+ })
+}
+
var _ = templruntime.GeneratedTemplate