drop the built-in Transcribe entry from the file browser context menu

Transcribe Audio covers it as a task, with recursion, multi-select scoping,
skip-if-already-done and a choice of inline or job — none of which the one-shot
menu entry had. Two ways to do the same thing from the same menu is worse than
one good one.

The file viewer's Transcribe button is untouched, and /file-browser/transcribe
stays: it is what both that button and the task call.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
brunorezio
2026-07-26 03:12:58 +01:00
co-authored by Claude Opus 5
parent 06aac5478f
commit 1263a4f851
3 changed files with 2 additions and 41 deletions
@@ -62,7 +62,6 @@ export const FileGrid = ({ fileBrowserManager }: FileGridProps) => {
setRenamingName, setRenamingName,
handleReadAloud, handleReadAloud,
handleOcr, handleOcr,
handleTranscribe,
handleExtractAudio, handleExtractAudio,
handleExtract, handleExtract,
handlePlay, handlePlay,
@@ -181,7 +180,6 @@ export const FileGrid = ({ fileBrowserManager }: FileGridProps) => {
onRenamingChange={setRenamingName} onRenamingChange={setRenamingName}
onReadAloud={handleReadAloud} onReadAloud={handleReadAloud}
onOcr={handleOcr} onOcr={handleOcr}
onTranscribe={handleTranscribe}
onExtractAudio={handleExtractAudio} onExtractAudio={handleExtractAudio}
onExtract={handleExtract} onExtract={handleExtract}
onPlay={handlePlay} onPlay={handlePlay}
@@ -13,7 +13,6 @@ import {
LayoutGrid, LayoutGrid,
Volume2, Volume2,
ScanText, ScanText,
FileText,
AudioLines, AudioLines,
FolderArchive, FolderArchive,
ClipboardCopy, ClipboardCopy,
@@ -65,7 +64,6 @@ export type FileItemProps = {
onRenamingChange: (name: string | null) => void; onRenamingChange: (name: string | null) => void;
onReadAloud: (entry: DirEntry) => void; onReadAloud: (entry: DirEntry) => void;
onOcr: (entry: DirEntry) => void; onOcr: (entry: DirEntry) => void;
onTranscribe: (entry: DirEntry) => void;
onExtractAudio: (entry: DirEntry) => void; onExtractAudio: (entry: DirEntry) => void;
onExtract: (entry: DirEntry) => void; onExtract: (entry: DirEntry) => void;
onPlay: (entry: DirEntry) => void; onPlay: (entry: DirEntry) => void;
@@ -98,7 +96,6 @@ type MenuItemsProps = {
onDownload: (e: DirEntry) => void; onDownload: (e: DirEntry) => void;
onReadAloud: (e: DirEntry) => void; onReadAloud: (e: DirEntry) => void;
onOcr: (e: DirEntry) => void; onOcr: (e: DirEntry) => void;
onTranscribe: (e: DirEntry) => void;
onExtractAudio: (e: DirEntry) => void; onExtractAudio: (e: DirEntry) => void;
onExtract: (e: DirEntry) => void; onExtract: (e: DirEntry) => void;
onPlay: (e: DirEntry) => void; onPlay: (e: DirEntry) => void;
@@ -119,7 +116,6 @@ const DropdownMenuItems = ({
onDownload, onDownload,
onReadAloud, onReadAloud,
onOcr, onOcr,
onTranscribe,
onExtractAudio, onExtractAudio,
onExtract, onExtract,
onPlay, onPlay,
@@ -132,14 +128,12 @@ const DropdownMenuItems = ({
const fileType = entry.type === 'file' ? getFileType(entry.name) : null; const fileType = entry.type === 'file' ? getFileType(entry.name) : null;
const showReadAloud = fileType === 'markdown' || fileType === 'code' || fileType === 'text'; const showReadAloud = fileType === 'markdown' || fileType === 'code' || fileType === 'text';
const showOcr = fileType === 'image'; const showOcr = fileType === 'image';
const showTranscribe = fileType === 'audio';
const showExtractAudio = fileType === 'video'; const showExtractAudio = fileType === 'video';
const showExtract = fileType === 'archive'; const showExtract = fileType === 'archive';
const showPlay = fileType === 'audio' || entry.type === 'directory'; const showPlay = fileType === 'audio' || entry.type === 'directory';
const hasTasks = taskGroups.length > 0; const hasTasks = taskGroups.length > 0;
const hasActions = const hasActions = showPlay || showReadAloud || showOcr || showExtractAudio || showExtract || hasTasks;
showPlay || showReadAloud || showOcr || showTranscribe || showExtractAudio || showExtract || hasTasks;
// Only nest when more than one category matched — a file usually matches a single category, and // Only nest when more than one category matched — a file usually matches a single category, and
// Run Task > Video > Convert would just add a hop. // Run Task > Video > Convert would just add a hop.
const nestTasks = taskGroups.length > 1; const nestTasks = taskGroups.length > 1;
@@ -165,12 +159,6 @@ const DropdownMenuItems = ({
Extract Text (OCR) Extract Text (OCR)
</DropdownMenuItem> </DropdownMenuItem>
)} )}
{showTranscribe && (
<DropdownMenuItem onClick={() => onTranscribe(entry)} className="cursor-pointer">
<FileText className="mr-2 h-4 w-4" />
Transcribe
</DropdownMenuItem>
)}
{showExtractAudio && ( {showExtractAudio && (
<DropdownMenuItem onClick={() => onExtractAudio(entry)} className="cursor-pointer"> <DropdownMenuItem onClick={() => onExtractAudio(entry)} className="cursor-pointer">
<AudioLines className="mr-2 h-4 w-4" /> <AudioLines className="mr-2 h-4 w-4" />
@@ -272,7 +260,6 @@ const ContextMenuItems = ({
onDownload, onDownload,
onReadAloud, onReadAloud,
onOcr, onOcr,
onTranscribe,
onExtractAudio, onExtractAudio,
onExtract, onExtract,
onPlay, onPlay,
@@ -285,14 +272,12 @@ const ContextMenuItems = ({
const fileType = entry.type === 'file' ? getFileType(entry.name) : null; const fileType = entry.type === 'file' ? getFileType(entry.name) : null;
const showReadAloud = fileType === 'markdown' || fileType === 'code' || fileType === 'text'; const showReadAloud = fileType === 'markdown' || fileType === 'code' || fileType === 'text';
const showOcr = fileType === 'image'; const showOcr = fileType === 'image';
const showTranscribe = fileType === 'audio';
const showExtractAudio = fileType === 'video'; const showExtractAudio = fileType === 'video';
const showExtract = fileType === 'archive'; const showExtract = fileType === 'archive';
const showPlay = fileType === 'audio' || entry.type === 'directory'; const showPlay = fileType === 'audio' || entry.type === 'directory';
const hasTasks = taskGroups.length > 0; const hasTasks = taskGroups.length > 0;
const hasActions = const hasActions = showPlay || showReadAloud || showOcr || showExtractAudio || showExtract || hasTasks;
showPlay || showReadAloud || showOcr || showTranscribe || showExtractAudio || showExtract || hasTasks;
// Only nest when more than one category matched — a file usually matches a single category, and // Only nest when more than one category matched — a file usually matches a single category, and
// Run Task > Video > Convert would just add a hop. // Run Task > Video > Convert would just add a hop.
const nestTasks = taskGroups.length > 1; const nestTasks = taskGroups.length > 1;
@@ -318,12 +303,6 @@ const ContextMenuItems = ({
Extract Text (OCR) Extract Text (OCR)
</ContextMenuItem> </ContextMenuItem>
)} )}
{showTranscribe && (
<ContextMenuItem onClick={() => onTranscribe(entry)} className="cursor-pointer">
<FileText className="mr-2 h-4 w-4" />
Transcribe
</ContextMenuItem>
)}
{showExtractAudio && ( {showExtractAudio && (
<ContextMenuItem onClick={() => onExtractAudio(entry)} className="cursor-pointer"> <ContextMenuItem onClick={() => onExtractAudio(entry)} className="cursor-pointer">
<AudioLines className="mr-2 h-4 w-4" /> <AudioLines className="mr-2 h-4 w-4" />
@@ -534,7 +513,6 @@ export const FileItem = ({
onRenamingChange, onRenamingChange,
onReadAloud, onReadAloud,
onOcr, onOcr,
onTranscribe,
onExtractAudio, onExtractAudio,
onExtract, onExtract,
onPlay, onPlay,
@@ -617,7 +595,6 @@ export const FileItem = ({
onDownload, onDownload,
onReadAloud, onReadAloud,
onOcr, onOcr,
onTranscribe,
onExtractAudio, onExtractAudio,
onExtract, onExtract,
onPlay, onPlay,
@@ -457,19 +457,6 @@ export const useFileBrowserApp = (
} }
}; };
const handleTranscribe = async (entry: DirEntry) => {
const filePath = entryPath(entry.name);
const toastId = toast.loading('Transcribing audio...');
try {
const { transcriptionPath } = await files.transcribe(filePath, { saveNextTo: true });
toast.dismiss(toastId);
refresh();
setSearchParams({ view: filePath, ephemeral: transcriptionPath });
} catch {
toast.error('Failed to transcribe audio', { id: toastId });
}
};
const handleExtractAudio = async (entry: DirEntry) => { const handleExtractAudio = async (entry: DirEntry) => {
const filePath = entryPath(entry.name); const filePath = entryPath(entry.name);
const toastId = toast.loading('Extracting audio from video...'); const toastId = toast.loading('Extracting audio from video...');
@@ -778,7 +765,6 @@ export const useFileBrowserApp = (
handleCreateDashboardHere, handleCreateDashboardHere,
handleReadAloud, handleReadAloud,
handleOcr, handleOcr,
handleTranscribe,
handleExtractAudio, handleExtractAudio,
handleExtract, handleExtract,
handlePlay, handlePlay,