fix: keep restart controls disabled while request is pending

This commit is contained in:
VAIO73
2026-10-28 17:30:44 +00:00
parent 707a45e639
commit 79cdf814ed
2 changed files with 12 additions and 4 deletions
+2 -2
View File
@@ -88,7 +88,7 @@ export function RestartAfterUpdate({ getApiUrl, disabled, label, detail, icon }:
<div className="flex items-start gap-2 flex-1 min-w-0 text-[10px] sm:text-xs"><span className="shrink-0">{icon}</span>
<div><span className="font-medium mr-2">{label}</span><span className="text-muted-foreground break-words">{detail}</span></div></div>
<Button variant="outline" className={`${compact} self-start sm:shrink-0 border-amber-500/40 text-amber-500`}
disabled={disabled || accepted} onClick={() => setOpen(true)}>{t("healthStatus.restart.button")}</Button>
disabled={disabled || pending || accepted} onClick={() => setOpen(true)}>{t("healthStatus.restart.button")}</Button>
</div>
{disabled && <p className="mt-2 text-xs text-muted-foreground">{t("healthStatus.restart.blocked")}</p>}
{accepted && <p role="status" className="mt-2 text-xs text-blue-500">{t("healthStatus.restart.accepted")}</p>}
@@ -103,7 +103,7 @@ export function RestartAfterUpdate({ getApiUrl, disabled, label, detail, icon }:
{(error || context?.reason === "unknown") && <p role="alert" className="mt-3 text-xs text-amber-500">{t("healthStatus.restart.unconfirmed")}</p>}
<div className="mt-5 flex justify-end gap-2.5">
<Confirm.Cancel asChild><Button variant="outline" className={compact} disabled={pending}>{t("healthStatus.restart.cancel")}</Button></Confirm.Cancel>
<Confirm.Action asChild><Button variant="destructive" className={compact} disabled={disabled || !context?.allowed || submitted}
<Confirm.Action asChild><Button variant="destructive" className={compact} disabled={disabled || !context?.allowed || pending || submitted}
onClick={event => { event.preventDefault(); void confirm() }}>{t("healthStatus.restart.confirm")}</Button></Confirm.Action>
</div>
</Confirm.Content>
+10 -2
View File
@@ -2,8 +2,14 @@
const assert=require('node:assert/strict'),fs=require('node:fs'),path=require('node:path'),vm=require('node:vm')
const app=path.resolve(__dirname,'../AppImage'),ts=require(path.join(app,'node_modules/typescript'))
const tree=ts.createSourceFile('controls.tsx',fs.readFileSync(path.join(app,'components/host-update-status.tsx'),'utf8'),ts.ScriptTarget.Latest,true,ts.ScriptKind.TSX)
let callback
function walk(n){if(ts.isVariableDeclaration(n)&&n.name.getText(tree)==='confirm')callback=n.initializer.getText(tree);ts.forEachChild(n,walk)}
let callback,triggerDisabled
function walk(n){
if(ts.isVariableDeclaration(n)&&n.name.getText(tree)==='confirm')callback=n.initializer.getText(tree)
if(ts.isJsxElement(n)&&n.openingElement.tagName.getText(tree)==='Button'&&n.children.some(c=>c.getText(tree).includes('healthStatus.restart.button'))){
triggerDisabled=n.openingElement.attributes.properties.find(p=>p.name?.getText(tree)==='disabled').initializer.expression.getText(tree)
}
ts.forEachChild(n,walk)
}
walk(tree);assert.ok(callback)
function fixture(){
const calls=[],events=[]
@@ -16,6 +22,8 @@ function fixture(){
return {scope,calls,events,run}
}
async function main(){
assert.ok(triggerDisabled)
assert.equal(vm.runInNewContext(triggerDisabled,{disabled:false,accepted:false,pending:true}),true,'closing confirmation while its request is pending must not enable another request')
for(const block of ['disabled','submitted','sending','missing-context','not-allowed']){
const x=fixture()
if(block==='sending')x.scope.sending.current=true