Skip to content

Commit eb4dd40

Browse files
committed
fix(drain-plan): focusable caveat trigger; drop stale ack at refresh time
The estimate-caveat tooltip trigger is now a button, so keyboard focus opens it (the Tooltip already handles focus/blur). The emptyDir acknowledgement is cleared synchronously when refresh is clicked rather than by the effect that watches generatedAt, which runs a paint after the refreshed plan renders and would leave one frame where a stale acknowledgement still enables Drain. Claude-Session: https://claude.ai/code/session_01NE55VsYGkb5tV3neKDmtZw
1 parent 6322c70 commit eb4dd40

2 files changed

Lines changed: 23 additions & 2 deletions

File tree

‎packages/k8s-ui/src/components/shared/DrainPlanDialog.test.tsx‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@ describe('DrainPlanContent', () => {
120120
expect(render({ plan: p })).not.toContain('Recompute the plan')
121121
})
122122

123+
it('exposes the estimate caveat on a focusable trigger', () => {
124+
const html = render({ plan: plan([pod('web', 'evict')]) })
125+
expect(html).toMatch(/<button[^>]*aria-label="About this estimate"/)
126+
})
127+
123128
it('offers a retry on a failed plan only when the host can recompute it', () => {
124129
expect(render({ error: 'boom', onRefreshPlan: noop })).toContain('Try again')
125130
expect(render({ error: 'boom' })).not.toContain('Try again')

‎packages/k8s-ui/src/components/shared/DrainPlanDialog.tsx‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,13 @@ export function DrainPlanContent({
178178
<div className="flex items-center gap-1 shrink-0 text-xs text-theme-text-tertiary">
179179
<span>Estimated at {new Date(current.generatedAt).toLocaleTimeString()}</span>
180180
<Tooltip content={ESTIMATE_CAVEAT} className="max-w-xs">
181-
<Info aria-label="About this estimate" className="w-3.5 h-3.5" />
181+
<button
182+
type="button"
183+
aria-label="About this estimate"
184+
className="p-0.5 rounded text-theme-text-tertiary transition-colors hover:text-theme-text-secondary"
185+
>
186+
<Info className="w-3.5 h-3.5" />
187+
</button>
182188
</Tooltip>
183189
{onRefreshPlan && (
184190
<Tooltip content="Recompute the plan">
@@ -280,6 +286,16 @@ export function DrainPlanDialog({
280286
setAcknowledgedEmptyDir(false)
281287
}, [options.force, options.deleteEmptyDirData, open, plan?.generatedAt])
282288

289+
// Drop the acknowledgement at click time, not when the refreshed plan lands:
290+
// the effect above runs a paint after the new plan renders, which would leave
291+
// one frame where a stale acknowledgement still enables Drain.
292+
const refreshPlan = onRefreshPlan
293+
? () => {
294+
setAcknowledgedEmptyDir(false)
295+
onRefreshPlan()
296+
}
297+
: undefined
298+
283299
const confirmEnabled = canConfirmDrain({ plan, nodeName, options, loading, error, acknowledgedEmptyDir, planSupported })
284300

285301
return (
@@ -306,7 +322,7 @@ export function DrainPlanDialog({
306322
planSupported={planSupported}
307323
acknowledgedEmptyDir={acknowledgedEmptyDir}
308324
onAcknowledgeEmptyDir={setAcknowledgedEmptyDir}
309-
onRefreshPlan={onRefreshPlan}
325+
onRefreshPlan={refreshPlan}
310326
/>
311327
</ConfirmDialog>
312328
)

0 commit comments

Comments
 (0)