Why: Task 11 requires the document render workspace to offer approve, reject and final decisions, rule bind/unbind for document, document type and project default, and the full delivery package, so reviewers and settings holders no longer need other screens. Evidence: vitest 38 files / 419 tests passed (new test/document-render-actions.test.ts covers decision entries from frozen duties, decision payloads without identity fields, package availability, refusal codes, binding candidates and payloads, perm gating and SSR visibility); tsc --noEmit clean; knip unused exports 51 <= baseline 51. Impact: decision entries show only when the command is enabled and the frozen submission lists the session user; binding needs rdm.perm.check project.settings allowed=true; package appears only for ready deliveries; organization-default binding is not offered from the workspace (domain admin only). Refs: unified renderer plan Task 11, 05 section 9, 06 section 6, 07 sections 1 and 5; RDM plugins/rdm/plugin.go review.doc.* and render.profile.* schemas (7169944, 4b7ac2a, 75ba50c). Co-authored-by: Cursor <cursoragent@cursor.com>
34 lines
1.5 KiB
TypeScript
34 lines
1.5 KiB
TypeScript
// 统一渲染的失败与操作状态展示:工作区与各面板共用,只渲染,不持有异步状态。
|
|
// 原始回执只进 Collapsible 折叠区;可读文案由 describeRenderFailure 统一给出。
|
|
import { Btn, Collapsible } from '@ui'
|
|
import { describeRenderFailure, type RenderOperation } from '../documentRenderPresentation'
|
|
|
|
export interface OperationState { op: RenderOperation | null; status: 'idle' | 'running' | 'done' | 'failed'; error: string }
|
|
|
|
export function RenderFailure({ error, id }: { error: unknown; id: string }) {
|
|
const f = describeRenderFailure(error)
|
|
return (
|
|
<div className="drw-failure" role="alert">
|
|
<div className="drw-failure-msg">{f.message}</div>
|
|
<Collapsible id={`drw-failure-${id}`} trigger={<span className="rdm-audit-err-toggle">原始回执</span>}>
|
|
<code className="rdm-audit-err-raw">{f.raw}</code>
|
|
</Collapsible>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function OperationStatus({ state, onRetry, labels }: { state: OperationState; onRetry: () => void; labels: Record<string, string> }) {
|
|
if (state.status === 'idle' || !state.op) return null
|
|
const label = labels[state.op.kind] ?? '操作'
|
|
if (state.status === 'running') return <div className="drw-op"><span className="mk-sweep">{label}进行中</span></div>
|
|
if (state.status === 'failed') {
|
|
return (
|
|
<div className="drw-op">
|
|
<RenderFailure error={state.error} id={`op-${state.op.kind}`} />
|
|
<Btn variant="ghost" onClick={onRetry}>重试</Btn>
|
|
</div>
|
|
)
|
|
}
|
|
return null
|
|
}
|