Numeric dates; progress items without words

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Krzysztof Rudnicki 2026-11-11 11:57:55 +01:00
parent 8dbcc462c0
commit f73d2fa513
6 changed files with 11 additions and 9 deletions

View File

@ -241,7 +241,8 @@ class WaitReporter:
# Floor, so 99.99 never reads as done before the depot is.
progress.advance(self._label, step=int(snap.percent or 0))
else:
progress.advance(f"{_clock(snap.elapsed_seconds)} elapsed", step=0)
# The web UI paints the item (textgate): glyph + number, no word.
progress.advance(f"⏱️ {_clock(snap.elapsed_seconds)}", step=0)
if now - self._last_echo >= ECHO_SECONDS:
self._last_echo = now
_echo(f" Fast-installing {self._label}: {snap.describe()}")

View File

@ -213,7 +213,7 @@ class TestWaitReporter:
progress.phase.assert_called_once_with(
"Fast-installing G: shutting Steam down", None
)
progress.advance.assert_called_once_with("12s elapsed", step=0)
progress.advance.assert_called_once_with("⏱️ 12s", step=0)
def test_echo_is_throttled_to_30_seconds(self, tmp_path: Path) -> None:
reporter = self._reporter(tmp_path, _upto(" 46.90%"))

View File

@ -91,7 +91,7 @@ const install: Script = async (ctx) => {
const dir = await ctx.prompt('text', 'Steam library folder to install into:', { default: '/mnt/games/SteamLibrary' })
ctx.log(`steam://install/${world.currentAppId} → ${dir || '/mnt/games/SteamLibrary'}`)
for (let i = 1; i <= 20; i += 1) {
ctx.progress(i, 20, 'Downloading', `${name} — ${(i * 0.6).toFixed(1)} of 12.0 GB`, (20 - i) * 0.4)
ctx.progress(i, 20, 'Downloading', `${name} · ${(i * 0.6).toFixed(1)}/12.0 GB`, (20 - i) * 0.4)
await ctx.sleep(400)
}
return { summary: `${name} installed.` }

View File

@ -13,8 +13,8 @@ import './daemonCard'
import './serverCard'
import './setupCard'
/** Content inside a painted string: dates as dateTime() paints them, sizes, ids. */
const CONTENT = [/[A-Z][a-z]{2} \d{1,2}, \d{1,2}:\d{2}( [AP]M)?/g, /\d[\d.,]* (B|KB|MB|GB)\b/g, /\d{8}-\d{6}/g]
/** Content inside a painted string: sizes and backup ids (dates are numeric). */
const CONTENT = [/\d[\d.,]* (B|KB|MB|GB)\b/g, /\d{8}-\d{6}/g]
const chrome = (root: Element, allowed: string[] = []): string[] =>
visibleWords(root, allowed).filter((w) => /[A-Za-z]{2,}/.test(CONTENT.reduce((s, re) => s.replace(re, ''), w)))

View File

@ -31,7 +31,7 @@ describe('ui format', () => {
it('dateTime formats or dashes', () => {
expect(dateTime(null)).toBe('—')
expect(dateTime('2026-10-10T12:00:00Z')).toMatch(/\d/)
expect(dateTime('2026-10-10T12:00:00Z')).toMatch(/^\d\d-\d\d \d\d:\d\d$/)
})
it('duration spans start to end, or to now while running', () => {

View File

@ -31,11 +31,12 @@ export function ago(iso: string | null, now: number = Date.now()): string {
return `${Math.round(s / 86_400)} d ago`
}
/** Local `MM-DD HH:MM`: numbers only (textgate: no month names). */
export function dateTime(iso: string | null): string {
if (!iso) return '—'
return new Date(iso).toLocaleString(undefined, {
month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit',
})
const d = new Date(iso)
const p = (n: number) => String(n).padStart(2, '0')
return `${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`
}
export function duration(startIso: string | null, endIso: string | null, now: number = Date.now()): string {