a2a-source-edit: write frontend/src/App.jsx

This commit is contained in:
a2a-cloud
2026-07-19 22:13:39 +00:00
parent 01ed304184
commit 337a137b0f

View File

@@ -44,6 +44,7 @@ export function App() {
() => (config && needsSignIn ? signInUrl(config) : null), () => (config && needsSignIn ? signInUrl(config) : null),
[config, needsSignIn], [config, needsSignIn],
); );
const resultState = running ? "loading" : error ? "error" : result?.status === "ok" ? "success" : result ? "error" : "idle";
async function runTriage(event) { async function runTriage(event) {
event.preventDefault(); event.preventDefault();
@@ -58,6 +59,9 @@ export function App() {
max_messages: Number(maxMessages), max_messages: Number(maxMessages),
}); });
setResult(data); setResult(data);
if (data?.status && data.status !== "ok") {
setError(data.summary || "The inbox could not be triaged. Check the pasted messages and try again.");
}
} catch (err) { } catch (err) {
setError(err.message || String(err)); setError(err.message || String(err));
} finally { } finally {
@@ -157,57 +161,61 @@ export function App() {
</div> </div>
</form> </form>
{error ? <section className="error">{error}</section> : null} <section className="results" data-testid="agent-result" data-state={resultState} aria-live="polite">
{running ? <p>Triaging the shared inbox and drafting approval-ready replies...</p> : null}
{error ? <section className="error">{error}</section> : null}
{!running && !error && !result ? <p className="empty-state">Run the prefilled fixture to generate a prioritized queue, drafts, receipt, and JSON download.</p> : null}
{result ? ( {result ? (
<section className="results" data-testid="agent-result"> <>
<div className="result-header"> <div className="result-header">
<div> <div>
<p className="eyebrow">Structured result</p> <p className="eyebrow">Structured result</p>
<h2>{result.summary || result.status}</h2> <h2>{result.summary || result.status}</h2>
</div>
{result.artifact ? (
<button data-testid="agent-download" type="button" onClick={downloadReport}>
Download {result.artifact.name}
</button>
) : null}
</div> </div>
{result.artifact ? (
<button data-testid="agent-download" type="button" onClick={downloadReport}> <p className="boundary">{result.approval_boundary}</p>
Download {result.artifact.name} {result.receipt ? (
</button> <p className={result.receipt.persisted ? "receipt ok" : "receipt warn"}>
Receipt {result.receipt.receipt_id}: {result.receipt.message}
</p>
) : null} ) : null}
</div>
<p className="boundary">{result.approval_boundary}</p> <div className="queue">
{result.receipt ? ( {(result.queue || []).map((item) => (
<p className={result.receipt.persisted ? "receipt ok" : "receipt warn"}> <article className={`queue-card ${item.priority}`} key={item.message_id}>
Receipt {result.receipt.receipt_id}: {result.receipt.message} <div className="queue-top">
</p> <span className="pill">{item.priority}</span>
) : null} <span>{item.category}</span>
<div className="queue">
{(result.queue || []).map((item) => (
<article className={`queue-card ${item.priority}`} key={item.message_id}>
<div className="queue-top">
<span className="pill">{item.priority}</span>
<span>{item.category}</span>
</div>
<h3>{item.subject}</h3>
<p><strong>From:</strong> {item.sender}</p>
<p><strong>Why:</strong> {item.reason}</p>
<p><strong>Next:</strong> {item.next_action}</p>
<details open>
<summary>Approval-ready draft</summary>
<div className="draft">
<p><strong>To:</strong> {item.draft.to}</p>
<p><strong>Subject:</strong> {item.draft.subject}</p>
<pre>{item.draft.body}</pre>
<p><strong>Approval reason:</strong> {item.draft.approval_reason}</p>
<ul>
{(item.draft.policy_basis || []).map((basis) => <li key={basis}>{basis}</li>)}
</ul>
</div> </div>
</details> <h3>{item.subject}</h3>
</article> <p><strong>From:</strong> {item.sender}</p>
))} <p><strong>Why:</strong> {item.reason}</p>
</div> <p><strong>Next:</strong> {item.next_action}</p>
</section> <details open>
) : null} <summary>Approval-ready draft</summary>
<div className="draft">
<p><strong>To:</strong> {item.draft.to}</p>
<p><strong>Subject:</strong> {item.draft.subject}</p>
<pre>{item.draft.body}</pre>
<p><strong>Approval reason:</strong> {item.draft.approval_reason}</p>
<ul>
{(item.draft.policy_basis || []).map((basis) => <li key={basis}>{basis}</li>)}
</ul>
</div>
</details>
</article>
))}
</div>
</>
) : null}
</section>
</main> </main>
); );
} }