/* * Copyright (C) 2025 - present Instructure, Inc. * * This file is part of Canvas. * * Canvas is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License as published by the Free * Software Foundation, version 3 of the License. * * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License along * with this program. If not, see . */ import {IconButton} from '@instructure/ui-buttons' import {Flex} from '@instructure/ui-flex' import {IconDownloadLine, IconRefreshLine, IconTrashLine} from '@instructure/ui-icons' import {Text} from '@instructure/ui-text' import {TruncateText} from '@instructure/ui-truncate-text' import {View} from '@instructure/ui-view' import { type ClosedCaptionPanelTranslations, defaultClosedCaptionPanelTranslations, } from './translations' /** * Base props shared across all caption row states */ interface BaseCaptionRowProps { captionName: string deleteButtonRef?: (el: Element | null) => void } /** * Props for a caption in processing state */ interface ProcessingCaptionRowProps extends BaseCaptionRowProps { workflow_state: 'processing' } /** * Props for a caption in failed state */ interface FailedCaptionRowProps extends BaseCaptionRowProps { workflow_state: 'failed' failedOperation?: 'upload' | 'delete' | 'asr' asr?: boolean onRetry?: () => void onDelete?: () => void } /** * Props for a caption in ready state */ interface UploadedCaptionRowProps extends BaseCaptionRowProps { workflow_state: 'ready' filename?: string url?: string onDelete?: () => void isInherited?: boolean } /** * Discriminated union of all caption row prop types */ export type CaptionRowProps = ( | ProcessingCaptionRowProps | FailedCaptionRowProps | UploadedCaptionRowProps ) & {translations?: ClosedCaptionPanelTranslations} export function getStatusText( workflow_state: CaptionRowProps['workflow_state'], failedOperation?: 'upload' | 'delete' | 'asr', asr?: boolean, translations: ClosedCaptionPanelTranslations = defaultClosedCaptionPanelTranslations, ): string | undefined { if (workflow_state === 'processing') { return translations.processing() } if (workflow_state === 'failed') { if (failedOperation === 'delete') return translations.deleteFailed() if (failedOperation === 'asr' || asr) return translations.generationFailed() return translations.uploadFailed() } return undefined } /** * Displays a single caption row with status-specific UI */ export function CaptionRow(props: CaptionRowProps) { const {workflow_state, captionName, translations = defaultClosedCaptionPanelTranslations} = props const {failedOperation, asr} = props as FailedCaptionRowProps const statusText = getStatusText(workflow_state, failedOperation, asr, translations) const ariaLabel = statusText ? `${captionName}, ${statusText}` : captionName return ( {/* Left side: Language and filename */} {/* Right side: Status-specific content */} {workflow_state === 'processing' && ( )} {workflow_state === 'failed' && ( {props.onRetry && ( )} {props.onDelete && ( )} )} {workflow_state === 'ready' && ( )} {workflow_state === 'ready' && props.isInherited && ( {translations.inheritedCaptionsMessage()} )} ) }