feat: session quick wins (#51-#55) (#72)
* feat: add session quick wins (#51-#55) - Session timer showing elapsed time in header (#51) - Tab keyboard shortcut to focus notes textarea (#52) - Repeat Last Session button on tree library page (#53) - Auto-recovery banner for incomplete sessions (#54) - Copy individual step to clipboard on session detail (#55) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: add missing delete button to table and list tree views The onDeleteTree prop was accepted but never used in TreeTableView and TreeListView. Now both views show a trash icon (permission-gated) matching the existing grid view behavior. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit was merged in pull request #72.
This commit is contained in:
@@ -82,6 +82,13 @@ export function useTreeNavigationShortcuts({
|
||||
handler: onContinue,
|
||||
enabled: canContinue,
|
||||
},
|
||||
// Tab to focus notes
|
||||
{
|
||||
key: 'Tab',
|
||||
handler: () => {
|
||||
document.getElementById('session-notes')?.focus()
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
useKeyboardShortcuts(shortcuts)
|
||||
|
||||
33
frontend/src/hooks/useSessionTimer.ts
Normal file
33
frontend/src/hooks/useSessionTimer.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
|
||||
export function useSessionTimer(startedAt: string | undefined | null): string | null {
|
||||
const [elapsed, setElapsed] = useState<string | null>(null)
|
||||
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (!startedAt) {
|
||||
setElapsed(null)
|
||||
return
|
||||
}
|
||||
|
||||
const startTime = new Date(startedAt).getTime()
|
||||
|
||||
const tick = () => {
|
||||
const diff = Math.max(0, Math.floor((Date.now() - startTime) / 1000))
|
||||
const hours = Math.floor(diff / 3600)
|
||||
const minutes = Math.floor((diff % 3600) / 60)
|
||||
const seconds = diff % 60
|
||||
const pad = (n: number) => String(n).padStart(2, '0')
|
||||
setElapsed(hours > 0 ? `${pad(hours)}:${pad(minutes)}:${pad(seconds)}` : `${pad(minutes)}:${pad(seconds)}`)
|
||||
}
|
||||
|
||||
tick()
|
||||
intervalRef.current = setInterval(tick, 1000)
|
||||
|
||||
return () => {
|
||||
if (intervalRef.current) clearInterval(intervalRef.current)
|
||||
}
|
||||
}, [startedAt])
|
||||
|
||||
return elapsed
|
||||
}
|
||||
Reference in New Issue
Block a user