Repository navigation
fix(web): host videos explain missing file access instead of offering a retry #21088
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
fe0a9fb
08412b8
b2a0acb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| import { MISSING_FILE_ACCESS_MESSAGE } from "@t3tools/client-runtime/state/assets"; | ||
| import { createContext, useContext } from "react"; | ||
| import { MediaVideoPlayer } from "../../components/MediaVideoPlayer"; | ||
| import { useAssetUrlState, useRefreshAssetUrl } from "../../state/assets"; | ||
|
|
@@ -39,6 +40,11 @@ export function ThreadMarkdownVideo(props: { | |
| thumbnailKey={thumbnailKey} | ||
| thumbnailVisible={visible} | ||
| unavailable={"resource" in source && asset._tag === "Failure"} | ||
| unavailableDetail={ | ||
| "resource" in source && asset._tag === "Failure" && asset.reason === "missing-file-access" | ||
| ? MISSING_FILE_ACCESS_MESSAGE | ||
| : undefined | ||
|
Comment on lines
+43
to
+46
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The embedded-tile follow-up now passes this detail, but fresh evidence is the normal host-video link path: a link such as AGENTS.md reference: AGENTS.md:L67-L70 Useful? React with 👍 / 👎. |
||
| } | ||
| actionsSource={source.actionsSource} | ||
| /> | ||
| ); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1517,6 +1517,7 @@ function ChatMarkdownVideo(props: { | |
| readonly copyMarkdown: string | undefined; | ||
| readonly originalUrl?: string | undefined; | ||
| readonly sourceFailed?: boolean | undefined; | ||
| readonly unavailableDetail?: string | undefined; | ||
| readonly style?: CSSProperties | undefined; | ||
| readonly mediaIdentity?: string | undefined; | ||
| readonly actionsSource?: MediaActionSource | undefined; | ||
|
|
@@ -1527,6 +1528,7 @@ function ChatMarkdownVideo(props: { | |
| key={props.mediaIdentity ?? props.copyMarkdown ?? props.src} | ||
| src={props.src} | ||
| sourceFailed={props.sourceFailed} | ||
| unavailableDetail={props.unavailableDetail} | ||
| label={props.alt} | ||
| originalUrl={props.originalUrl} | ||
| style={props.style} | ||
|
|
@@ -1592,6 +1594,10 @@ export const ChatMarkdownAssetImage = memo(function ChatMarkdownAssetImage(props | |
| : undefined; | ||
| const relativePath = reference?.kind === "file" ? reference.relativePath : undefined; | ||
| const fallbackSrc = assetUrl._tag === "Failure" ? props.fallbackSrc : undefined; | ||
| const missingFileAccess = | ||
| assetUrl._tag === "Failure" && | ||
| assetUrl.reason === "missing-file-access" && | ||
| fallbackSrc === undefined; | ||
| const src = | ||
| assetUrl._tag === "Success" | ||
| ? assetUrl.url + (props.srcFragment ?? "") | ||
|
|
@@ -1633,12 +1639,14 @@ export const ChatMarkdownAssetImage = memo(function ChatMarkdownAssetImage(props | |
| <ChatMarkdownVideo | ||
| src={src} | ||
| sourceFailed={assetUrl._tag === "Failure" && fallbackSrc === undefined} | ||
| unavailableDetail={missingFileAccess ? MISSING_FILE_ACCESS_MESSAGE : undefined} | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
On the mobile client, when a host video is viewed over a connection without AGENTS.md reference: AGENTS.md:L67-L70 Useful? React with 👍 / 👎.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, it is the same defect on mobile. Fixed in 08412b8: |
||
| alt={props.alt} | ||
| copyMarkdown={props.copyMarkdown} | ||
| originalUrl={props.originalUrl} | ||
| style={props.style} | ||
| mediaIdentity={JSON.stringify([props.environmentId, props.resource, props.srcFragment])} | ||
| onRetry={refreshAssetUrl} | ||
| // A retry signs a new URL; it cannot grant the file access this connection lacks. | ||
| onRetry={missingFileAccess ? undefined : refreshAssetUrl} | ||
| actionsSource={actionsSource} | ||
| /> | ||
| ); | ||
|
|
@@ -1649,13 +1657,7 @@ export const ChatMarkdownAssetImage = memo(function ChatMarkdownAssetImage(props | |
| key={JSON.stringify([props.environmentId, props.resource, props.srcFragment])} | ||
| src={src} | ||
| sourceFailed={assetUrl._tag === "Failure" && fallbackSrc === undefined} | ||
| unavailableDetail={ | ||
| assetUrl._tag === "Failure" && | ||
| assetUrl.reason === "missing-file-access" && | ||
| fallbackSrc === undefined | ||
| ? MISSING_FILE_ACCESS_MESSAGE | ||
| : undefined | ||
| } | ||
| unavailableDetail={missingFileAccess ? MISSING_FILE_ACCESS_MESSAGE : undefined} | ||
| alt={props.alt} | ||
| copyMarkdown={props.copyMarkdown} | ||
| standalone={props.standalone ?? true} | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,7 @@ interface MediaVideoPlayerProps { | |
| readonly src: string | null; | ||
| readonly label: string; | ||
| readonly sourceFailed?: boolean | undefined; | ||
| readonly unavailableDetail?: string | undefined; | ||
| readonly originalUrl?: string | undefined; | ||
| readonly revision?: string | null | undefined; | ||
| readonly preload?: "visible" | "metadata" | undefined; | ||
|
|
@@ -31,6 +32,7 @@ export function MediaVideoPlayer({ | |
| src: latestSrc, | ||
| label, | ||
| sourceFailed = false, | ||
| unavailableDetail, | ||
| originalUrl, | ||
| revision = null, | ||
| preload = "visible", | ||
|
|
@@ -137,9 +139,9 @@ export function MediaVideoPlayer({ | |
| stateClassName, | ||
| )} | ||
| > | ||
| <span className="inline-flex items-center gap-1.5"> | ||
| <span data-thread-find-ignore className="inline-flex items-center gap-1.5"> | ||
| <TriangleAlertIcon aria-hidden className="size-3.5 shrink-0" /> | ||
| Video unavailable{label ? ` · ${label}` : ""} | ||
| {["Video unavailable", label, unavailableDetail].filter(Boolean).join(" · ")} | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When an access-denied video appears before real message text containing a word from this new boilerplate (for example Useful? React with 👍 / 👎.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. Fixed in 08412b8: the video label now carries |
||
| </span> | ||
| <span className="flex flex-wrap items-center justify-center gap-2"> | ||
| {latestSrc !== null || onRetry ? ( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a host video is blocked on iOS or Android with VoiceOver/TalkBack enabled, this new text is nested inside a
Pressablewhose explicitaccessibilityLabelremainsPlay ${props.name}(line 148). The pressable is the accessible element and that label replaces its descendant text, so users hear only “Play Demo, disabled” and never the pairing explanation; set a failure-specific label includingunavailableDetailwhenunavailableis true.Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Fixed in b2a0acb: when the tile is unavailable its
accessibilityLabelis now ". Video unavailable. ", built from the same text the tile shows, so VoiceOver and TalkBack read the explanation. A playable tile still announces "Play ". Checked withtsc-rs --noEmitand lint inapps/mobile; not run on a device.