mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
fix(web): write VAPID key only after hub registration; make running-section toggle keyboard-accessible with correct filtered state
This commit is contained in:
@@ -253,13 +253,18 @@ export function NewSession(props: {
|
||||
if (!props.api) {
|
||||
return
|
||||
}
|
||||
props.api.getClaudeCustomModels().then((result) => {
|
||||
if (!cancelled) {
|
||||
setClaudeCustomModels(Array.isArray(result.models) ? result.models : [])
|
||||
}
|
||||
}).catch(() => {
|
||||
// Custom models are optional — fall back to the built-in presets.
|
||||
})
|
||||
try {
|
||||
props.api.getClaudeCustomModels().then((result) => {
|
||||
if (!cancelled) {
|
||||
setClaudeCustomModels(Array.isArray(result.models) ? result.models : [])
|
||||
}
|
||||
}).catch(() => {
|
||||
// Custom models are optional — fall back to the built-in presets.
|
||||
})
|
||||
} catch {
|
||||
// Partial api clients (tests, older hub versions) without the
|
||||
// method must not break the New Session form.
|
||||
}
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
|
||||
@@ -462,9 +462,11 @@ describe('SessionList collapse behavior', () => {
|
||||
const runningPanel = () => screen.getByTitle('In progress').nextElementSibling
|
||||
|
||||
expect(runningPanel()?.getAttribute('data-open')).toBe('true')
|
||||
expect(screen.getByTitle('In progress').getAttribute('aria-expanded')).toBe('true')
|
||||
|
||||
fireEvent.click(screen.getByTitle('In progress'))
|
||||
expect(runningPanel()?.getAttribute('data-open')).toBeNull()
|
||||
expect(screen.getByTitle('In progress').getAttribute('aria-expanded')).toBe('false')
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Search sessions' }))
|
||||
fireEvent.change(screen.getByPlaceholderText('Search sessions…'), {
|
||||
@@ -472,6 +474,31 @@ describe('SessionList collapse behavior', () => {
|
||||
})
|
||||
|
||||
expect(runningPanel()?.getAttribute('data-open')).toBe('true')
|
||||
// The section stays reported open while searching even though the
|
||||
// underlying collapsed state is still set.
|
||||
expect(screen.getByTitle('In progress').getAttribute('aria-expanded')).toBe('true')
|
||||
})
|
||||
|
||||
it('toggles the running section with the keyboard', () => {
|
||||
const sessions = [
|
||||
makeSession({
|
||||
id: 'session-running',
|
||||
active: true,
|
||||
thinking: true,
|
||||
updatedAt: 100,
|
||||
metadata: { path: '/work/hapi', name: 'Running task', flavor: 'codex' },
|
||||
}),
|
||||
]
|
||||
render(renderSessionList(sessions))
|
||||
|
||||
const header = screen.getByRole('button', { name: /In progress/ })
|
||||
expect(header.getAttribute('aria-expanded')).toBe('true')
|
||||
|
||||
fireEvent.keyDown(header, { key: 'Enter' })
|
||||
expect(header.getAttribute('aria-expanded')).toBe('false')
|
||||
|
||||
fireEvent.keyDown(header, { key: ' ' })
|
||||
expect(header.getAttribute('aria-expanded')).toBe('true')
|
||||
})
|
||||
|
||||
it('keeps the previous selected path open when selection moves', async () => {
|
||||
|
||||
@@ -1427,10 +1427,19 @@ export function SessionList(props: {
|
||||
<div key="running-section">
|
||||
<div
|
||||
className="group/running flex min-w-0 w-full select-none cursor-pointer items-center gap-2 rounded-lg py-1.5 pl-2 pr-2 transition-colors hover:bg-[var(--app-secondary-bg)]"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
aria-expanded={!runningSectionCollapsed || isFiltering}
|
||||
onClick={() => setRunningSectionCollapsed((value) => !value)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault()
|
||||
setRunningSectionCollapsed((value) => !value)
|
||||
}
|
||||
}}
|
||||
title={t('sessions.runningSection')}
|
||||
>
|
||||
<ChevronIcon className="h-3.5 w-3.5 text-[var(--app-hint)] shrink-0" collapsed={runningSectionCollapsed} />
|
||||
<ChevronIcon className="h-3.5 w-3.5 text-[var(--app-hint)] shrink-0" collapsed={runningSectionCollapsed && !isFiltering} />
|
||||
<span className="inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center" aria-hidden="true">
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-[var(--app-badge-success-text)] animate-pulse" />
|
||||
</span>
|
||||
|
||||
@@ -143,7 +143,6 @@ export function usePushNotifications(api: ApiClient | null) {
|
||||
applicationServerKey
|
||||
})
|
||||
}
|
||||
writeStoredVapidKey(publicKey)
|
||||
|
||||
const json = subscription.toJSON()
|
||||
const keys = json.keys
|
||||
@@ -158,6 +157,11 @@ export function usePushNotifications(api: ApiClient | null) {
|
||||
auth: keys.auth
|
||||
}
|
||||
})
|
||||
// Only record the key after the hub registration succeeded. A
|
||||
// failed registration must leave the previous key in place so the
|
||||
// next load retries the replacement instead of reusing a
|
||||
// subscription the hub never learned about.
|
||||
writeStoredVapidKey(publicKey)
|
||||
setIsSubscribed(true)
|
||||
return true
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user