fix: improve retry feedback and deletion stability

This commit is contained in:
hectorzhao
2026-08-02 20:39:49 +08:00
parent ecc3d7a504
commit 94e997ec4d
9 changed files with 273 additions and 41 deletions
+25 -16
View File
@@ -45,13 +45,17 @@ export function DeleteRiskAction({ portal, targetType, targetId, children = '删
const completed = portal === 'admin'
? await adminApi.deleteGovernedTarget(targetType, targetId, body)
: await clientApi.deleteGovernedTarget(targetType as Exclude<DeletionTargetType, 'channel'>, targetId, body);
setResult(completed); onCompleted?.(completed);
setResult(completed);
} catch (failure) {
setError(failure instanceof Error ? failure.message : '删除失败,请重新检查依赖后重试');
} finally { setSubmitting(false); }
}
function close() { if (!submitting) setOpen(false); }
function close() {
if (submitting) return;
setOpen(false);
if (result) onCompleted?.(result);
}
const blocked = Boolean(preflight && !preflight.allowedActions.includes('delete'));
const footer = (requestClose: () => void) => result ? <Button onClick={close}></Button> : <>
<Button disabled={submitting} onClick={requestClose} variant="ghost"></Button>
@@ -64,20 +68,25 @@ export function DeleteRiskAction({ portal, targetType, targetId, children = '删
<Button disabled={disabled} icon={icon} onClick={() => void begin()} size="sm" variant="danger">{children}</Button>
<Modal dirty={!result && reason.trim().length > 0} footer={({ requestClose }) => footer(requestClose)} onClose={close} open={open} title="删除资格与影响确认">
<div className="risk-action-content delete-risk-action">
{loading ? <p role="status"></p> : null}
{preflight ? <>
<div className="risk-action-identity">
{Object.entries(preflight.identity).map(([key, value]) => <div key={key}><span>{identityLabels[key] ?? key}</span><strong>{value}</strong></div>)}
</div>
<section><h3></h3>{preflight.dependencies.length ? <ul className="delete-risk-dependencies">{preflight.dependencies.map((item) => <li key={item.kind}><strong>{item.label}</strong><span>{item.count} </span>{item.items.length ? <small>{item.items.join('')}</small> : <small></small>}</li>)}</ul> : null}</section>
{preflight.blockedReasons.length
? <ul className="risk-action-blockers">{preflight.blockedReasons.map((item) => <li key={item}><AlertTriangle size={15} />{item}</li>)}</ul>
: <p className="risk-action-passed"><ShieldCheck size={16} /></p>}
<section><h3></h3><ul>{preflight.impacts.map((item) => <li key={item}>{item}</li>)}</ul><p className="muted">{preflight.recoverability.description}</p></section>
{!blocked ? <Textarea label="删除原因" onChange={(event) => setReason(event.target.value)} placeholder="至少填写 4 个字符,原因将写入审计记录" required value={reason} /> : null}
</> : null}
{result ? <div className="risk-action-result" role="status"><ShieldCheck size={20} /><div><strong></strong><span>{result.operationId}{result.replayed ? '(幂等重放)' : ''}</span></div></div> : null}
{error ? <p className="form-error" role="alert">{error}</p> : null}
{result ? (
<div className="risk-action-result" role="status"><ShieldCheck size={20} /><div><strong></strong><span>{result.operationId}{result.replayed ? '(幂等重放)' : ''}</span></div></div>
) : (
<>
{loading ? <p role="status"></p> : null}
{preflight ? <>
<div className="risk-action-identity">
{Object.entries(preflight.identity).map(([key, value]) => <div key={key}><span>{identityLabels[key] ?? key}</span><strong>{value}</strong></div>)}
</div>
<section><h3></h3>{preflight.dependencies.length ? <ul className="delete-risk-dependencies">{preflight.dependencies.map((item) => <li key={item.kind}><strong>{item.label}</strong><span>{item.count} </span>{item.items.length ? <small>{item.items.join('')}</small> : <small></small>}</li>)}</ul> : null}</section>
{preflight.blockedReasons.length
? <ul className="risk-action-blockers">{preflight.blockedReasons.map((item) => <li key={item}><AlertTriangle size={15} />{item}</li>)}</ul>
: <p className="risk-action-passed"><ShieldCheck size={16} /></p>}
<section><h3></h3><ul>{preflight.impacts.map((item) => <li key={item}>{item}</li>)}</ul><p className="muted">{preflight.recoverability.description}</p></section>
{!blocked ? <Textarea label="删除原因" onChange={(event) => setReason(event.target.value)} placeholder="至少填写 4 个字符,原因将写入审计记录" required value={reason} /> : null}
</> : null}
{error ? <p className="form-error" role="alert">{error}</p> : null}
</>
)}
</div>
</Modal>
</>;