55 lines
2.2 KiB
TypeScript
55 lines
2.2 KiB
TypeScript
import { pausedReason as pausedReasonWords } from '../api';
|
||
import type { Book, ConnectionState, Run } from '../api';
|
||
import { languageName, remaining, translatedPercent } from './format';
|
||
import styles from './Status.module.css';
|
||
|
||
interface Props {
|
||
book?: Book;
|
||
run: Run | null;
|
||
connection: ConnectionState;
|
||
chapter: string;
|
||
}
|
||
|
||
/**
|
||
* The status bar. One fraction and no phase names: what happens inside the pipeline is not the
|
||
* user's business (prompt §4.1). The phasing stays where it belongs — in the data and in the sum —
|
||
* because a per-phase fraction would read zero for the whole draft wave.
|
||
*/
|
||
export function Status({ book, run, connection, chapter }: Props) {
|
||
const paused = run?.status === 'paused';
|
||
const eta = remaining(book?.progress.eta_seconds);
|
||
|
||
return (
|
||
<>
|
||
<span>
|
||
{book?.title ?? '—'}
|
||
{chapter !== '' && ` / ${chapter}`}
|
||
</span>
|
||
<span className={styles.right}>
|
||
{paused ? (
|
||
// A ceiling stop is resumable, so it is stated as a fact and not as a failure. The phrase
|
||
// is the owner's; the API carries only the machine reason.
|
||
<span className={styles.paused}>
|
||
{pausedReasonWords.describe(run.paused_reason).label}
|
||
</span>
|
||
) : (
|
||
book && <span>переведено {translatedPercent(book.progress)}%</span>
|
||
)}
|
||
{/* `null` is a legal value, not just an absent field: there is nothing to estimate from
|
||
before the first calls of a wave, and a bare "осталось" with no number is worse than
|
||
saying nothing. */}
|
||
{!paused && eta !== null && <span>осталось {eta}</span>}
|
||
{/* Losing the live channel is its own state: the reads still work, so the screen must say
|
||
the numbers have stopped moving rather than let a frozen counter look healthy. */}
|
||
{(connection === 'lost' || connection === 'refused') && (
|
||
<span className={styles.offline}>живой прогресс недоступен</span>
|
||
)}
|
||
{book && (
|
||
<span>
|
||
{languageName(book.source_lang)} → {languageName(book.target_lang)}
|
||
</span>
|
||
)}
|
||
</span>
|
||
</>
|
||
);
|
||
}
|