Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/console/src/app/NetworkMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ function InfoRow({ k, v, href, truncate, title }: { k: string; v: string; href?:
<div className="flex items-center justify-between gap-3 py-0.5">
<span className="flex-none text-muted">{k}</span>
{href ? (
<a href={href} target="_blank" rel="noreferrer" title={title ?? v} className={`min-w-0 font-medium text-primary hover:underline ${truncate ? "truncate" : ""}`}>
<a href={href} target="_blank" rel="noreferrer" title={title ?? v} className={`min-w-0 rounded font-medium text-primary outline-none hover:underline focus-visible:ring-2 focus-visible:ring-primary/40 ${truncate ? "truncate" : ""}`}>
{v}
</a>
) : (
Expand Down
7 changes: 4 additions & 3 deletions apps/console/src/app/Shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export function Shell() {
<div className="truncate text-[12px] text-muted">{session?.member.name ?? "Signed in"}</div>
</div>
</div>
<button role="menuitem" onClick={() => { setMenu(null); nav("/settings"); }} className="flex w-full items-center gap-2 px-3.5 py-2.5 text-left text-[13px] text-[#3a4452] transition hover:bg-[#f4f3ef]">
<button role="menuitem" onClick={() => { setMenu(null); nav("/settings"); }} className="flex w-full items-center gap-2 px-3.5 py-2.5 text-left text-[13px] text-[#3a4452] outline-none transition hover:bg-[#f4f3ef] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary/40">
<Settings size={15} className="text-[#8a9099]" /> Settings &amp; team
</button>
<div className="border-t border-border px-3.5 py-2.5 text-[11.5px] text-muted">
Expand All @@ -151,7 +151,8 @@ export function Shell() {
<div className="relative flex-none">
<button
onClick={() => setMenu((m) => (m === "bell" ? null : "bell"))}
aria-label="Notifications"
aria-label={pending ? `Notifications — ${pending} awaiting approval` : "Notifications"}
title={pending ? `${pending} awaiting approval` : "Notifications"}
aria-haspopup="menu"
aria-expanded={menu === "bell"}
data-testid="notifications"
Expand All @@ -173,7 +174,7 @@ export function Shell() {
>
<div className="border-b border-border px-3.5 py-3 text-[13px] font-semibold text-ink">Notifications</div>
{pending ? (
<button onClick={() => { setMenu(null); nav("/approvals"); }} className="flex w-full items-start gap-2.5 px-3.5 py-3 text-left transition hover:bg-[#f4f3ef]">
<button onClick={() => { setMenu(null); nav("/approvals"); }} className="flex w-full items-start gap-2.5 px-3.5 py-3 text-left outline-none transition hover:bg-[#f4f3ef] focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary/40">
<span className="mt-0.5 flex h-7 w-7 flex-none items-center justify-center rounded-full bg-primary/10 text-primary"><CheckCheck size={15} /></span>
<span className="min-w-0">
<span className="block text-[13px] font-medium text-ink">{pending} payment{pending === 1 ? "" : "s"} awaiting approval</span>
Expand Down
4 changes: 2 additions & 2 deletions apps/console/src/screens/AuditLog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ export function AuditLog() {
<div className="font-mono text-[12px] text-white/56">Merkle root {formatAddress(packet.anchor.merkleRoot, 8, 6)}</div>
{anchor?.onChain ? <div className="font-mono text-[12px] text-white/56">On-chain · sequence {anchor.sequence}</div> : null}
{anchor?.explorer ? (
<a href={anchor.explorer} target="_blank" rel="noreferrer" className="inline-flex items-center gap-1 text-[12px] font-semibold text-primary hover:underline">
<a href={anchor.explorer} target="_blank" rel="noreferrer" className="inline-flex items-center gap-1 rounded text-[12px] font-semibold text-primary outline-none hover:underline focus-visible:ring-2 focus-visible:ring-primary/40">
View root transaction <ExternalLink size={12} />
</a>
) : null}
Expand All @@ -268,7 +268,7 @@ export function AuditLog() {
title="Audit log"
subtitle="A tamper-evident double-entry record of every movement. Corrections are reversals, never edits."
action={
<Button onClick={generatePacket} data-testid="generate-packet">
<Button onClick={generatePacket} loading={packetState.phase !== "idle"} data-testid="generate-packet">
<ShieldAlert size={15} /> Generate auditor packet
</Button>
}
Expand Down
2 changes: 1 addition & 1 deletion apps/console/src/screens/Contractors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ export function Contractors() {
<span className="w-20 font-medium text-fg">{e.period}</span>
<StatusPill status={e.status} />
{e.txHash ? (
<a href={explorerTxUrl(e.txHash)} target="_blank" rel="noreferrer" className="text-[11px] font-semibold text-primary hover:underline">on-chain receipt</a>
<a href={explorerTxUrl(e.txHash)} target="_blank" rel="noreferrer" className="rounded text-[11px] font-semibold text-primary outline-none hover:underline focus-visible:ring-2 focus-visible:ring-primary/40">on-chain receipt</a>
) : null}
<span className="ml-auto"><Amount minor={e.amount} tabular /></span>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/console/src/screens/Grants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ export function Grants() {
<div className="w-48">
<Input label="Period" placeholder="2026-Q2" value={period} onChange={(e) => setPeriod(e.target.value)} data-testid="att-period" />
</div>
<Button onClick={exportPeriodTotal} data-testid="gen-period-total">
<Button onClick={exportPeriodTotal} loading={attState.phase !== "idle"} data-testid="gen-period-total">
<ShieldCheck size={15} /> Generate attestation
</Button>
</div>
Expand Down
4 changes: 2 additions & 2 deletions apps/console/src/screens/Pay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,11 @@ export function Pay() {
: "Payment created."}
</span>
{result.status === "needs_approval" ? (
<button onClick={() => nav("/approvals")} className="inline-flex flex-none items-center gap-1 font-semibold text-primary hover:underline">
<button onClick={() => nav("/approvals")} className="inline-flex flex-none items-center gap-1 rounded font-semibold text-primary outline-none hover:underline focus-visible:ring-2 focus-visible:ring-primary/40">
Approvals <ArrowRight size={13} />
</button>
) : result.unpayable ? (
<button onClick={() => nav("/contractors")} className="inline-flex flex-none items-center gap-1 font-semibold text-primary hover:underline">
<button onClick={() => nav("/contractors")} className="inline-flex flex-none items-center gap-1 rounded font-semibold text-primary outline-none hover:underline focus-visible:ring-2 focus-visible:ring-primary/40">
Contractors <ArrowRight size={13} />
</button>
) : null}
Expand Down
6 changes: 3 additions & 3 deletions apps/console/src/screens/Payroll.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -454,10 +454,10 @@ export function Payroll() {
) : null}
</div>
<div className="flex items-center gap-4">
<button onClick={() => downloadPayslips(drawerBatch)} className="inline-flex items-center gap-1 text-[12px] font-semibold text-primary hover:underline" data-testid="download-payslips" type="button">
<button onClick={() => downloadPayslips(drawerBatch)} className="inline-flex items-center gap-1 rounded text-[12px] font-semibold text-primary outline-none hover:underline focus-visible:ring-2 focus-visible:ring-primary/40" data-testid="download-payslips" type="button">
<Download size={13} /> Payslips
</button>
<button onClick={() => exportCsv(drawerBatch)} className="inline-flex items-center gap-1 text-[12px] font-semibold text-primary hover:underline" data-testid="export-csv" type="button">
<button onClick={() => exportCsv(drawerBatch)} className="inline-flex items-center gap-1 rounded text-[12px] font-semibold text-primary outline-none hover:underline focus-visible:ring-2 focus-visible:ring-primary/40" data-testid="export-csv" type="button">
<Download size={13} /> Export CSV
</button>
</div>
Expand Down Expand Up @@ -506,7 +506,7 @@ export function Payroll() {
<div className="flex items-center gap-2">
{l.status === "paid" && !l.onChain ? <Pill tone="warning">not on-chain</Pill> : <StatusPill status={l.status} />}
{l.txHash ? (
<a href={explorerTxUrl(l.txHash)} target="_blank" rel="noreferrer" className="text-[12px] font-semibold text-primary hover:underline">receipt</a>
<a href={explorerTxUrl(l.txHash)} target="_blank" rel="noreferrer" className="rounded text-[12px] font-semibold text-primary outline-none hover:underline focus-visible:ring-2 focus-visible:ring-primary/40">receipt</a>
) : null}
</div>
</Td>
Expand Down
4 changes: 2 additions & 2 deletions apps/console/src/screens/Treasury.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ export function Treasury() {
<Send size={14} /> Sent on-chain
</div>
{sendResult.txHash ? (
<a href={explorerTxUrl(sendResult.txHash)} target="_blank" rel="noreferrer" className="mt-1 inline-flex items-center gap-1 text-[12px] font-semibold text-primary hover:underline">
<a href={explorerTxUrl(sendResult.txHash)} target="_blank" rel="noreferrer" className="mt-1 inline-flex items-center gap-1 rounded text-[12px] font-semibold text-primary outline-none hover:underline focus-visible:ring-2 focus-visible:ring-primary/40">
View on explorer <ArrowUpRight size={12} />
</a>
) : null}
Expand Down Expand Up @@ -675,7 +675,7 @@ function FundReceipt({ txHash }: { txHash?: string }) {
</div>
<div className="text-white/60">It's now part of your dual-controlled private balance — hidden from the public blockchain.</div>
{txHash ? (
<a href={explorerTxUrl(txHash)} target="_blank" rel="noreferrer" className="inline-flex items-center gap-1 text-[12px] font-semibold text-white hover:underline">
<a href={explorerTxUrl(txHash)} target="_blank" rel="noreferrer" className="inline-flex items-center gap-1 rounded text-[12px] font-semibold text-white outline-none hover:underline focus-visible:ring-2 focus-visible:ring-white/50">
View on {NETWORK_LABEL} explorer <ArrowUpRight size={12} />
</a>
) : null}
Expand Down
25 changes: 23 additions & 2 deletions apps/console/src/ui/controls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,28 @@ export function Td({ children, align = "left", className = "" }: { children?: Re
return <td className={`border-t border-border px-4 py-2.5 text-fg ${ALIGN[align]} ${className}`}>{children}</td>;
}
export function Tr({ children, onClick, className = "", ...rest }: { children: ReactNode; onClick?: () => void; className?: string } & Omit<HTMLAttributes<HTMLTableRowElement>, "onClick">) {
return <tr onClick={onClick} className={`${onClick ? "cursor-pointer hover:bg-border/30" : ""} ${className}`} {...rest}>{children}</tr>;
// A clickable row is keyboard-operable: focusable, Enter/Space activate it, and it
// shows an inset focus ring. Non-interactive rows stay out of the tab order.
return (
<tr
onClick={onClick}
tabIndex={onClick ? 0 : undefined}
onKeyDown={
onClick
? (e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
onClick();
}
}
: undefined
}
className={`${onClick ? "cursor-pointer outline-none hover:bg-border/30 focus-visible:bg-border/30 focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary/40" : ""} ${className}`}
{...rest}
Comment on lines +154 to +167

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve the row keyboard contract and ignore nested-control events.

Because {...rest} is spread after this handler, a caller-provided onKeyDown or tabIndex can overwrite Tr’s computed behavior. AuditLog.tsx supplies both, and its row handler also receives bubbled keys from nested copy and receipt controls. Destructure/combine the caller handler, keep controlled props after the spread, and only activate the row when event.target === event.currentTarget.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/console/src/ui/controls.tsx` around lines 143 - 154, Update the Tr
keyboard handling to preserve its row behavior: destructure the caller-provided
onKeyDown and tabIndex from rest, invoke the caller handler while retaining the
row handler, spread remaining props before controlled values, and set the
computed tabIndex afterward. In the row handler, only process Enter or Space
when event.target === event.currentTarget so bubbled events from nested controls
are ignored.

>
{children}
</tr>
);
Comment thread
greptile-apps[bot] marked this conversation as resolved.
}

// ---------------------------------------------------------------- tabs
Expand Down Expand Up @@ -209,7 +230,7 @@ export function CopyButton({ value }: { value: string }) {
void copyTextToClipboard(value).then((ok) => setDone(ok ? "copied" : "blocked"));
setTimeout(() => setDone("idle"), 1200);
}}
className="rounded p-1 text-muted outline-none transition hover:bg-border/50 focus-visible:ring-2 focus-visible:ring-primary/40"
className="inline-flex h-6 w-6 items-center justify-center rounded text-muted outline-none transition hover:bg-border/50 focus-visible:ring-2 focus-visible:ring-primary/40"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Increase the copy control hit area to the required minimum.

h-6 w-6 renders a 24×24px target, conflicting with the PR objective requiring interactive targets of at least 40px. Keep the icon small, but make the button itself at least h-10 w-10.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/console/src/ui/controls.tsx` at line 233, The copy control’s 24px hit
area is below the required minimum. In the copy button near the `className`
using `h-6 w-6`, change the button dimensions to at least `h-10 w-10` while
preserving the icon’s smaller size.

aria-label={done === "blocked" ? "Copy blocked" : done === "copied" ? "Copied" : "Copy"}
title={done === "blocked" ? "Copy blocked. Select the value manually." : done === "copied" ? "Copied" : "Copy"}
>
Expand Down
8 changes: 4 additions & 4 deletions apps/console/src/ui/onchain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export function OnChainDetail({ refData, label = "View on-chain" }: { refData: O
<button
type="button"
onClick={() => setOpen(true)}
className="inline-flex items-center gap-1 text-[12px] font-semibold text-primary transition hover:underline"
className="inline-flex items-center gap-1 rounded text-[12px] font-semibold text-primary outline-none transition hover:underline focus-visible:ring-2 focus-visible:ring-primary/40"
data-testid="view-onchain"
>
{label} <ArrowUpRight size={12} />
Expand All @@ -82,7 +82,7 @@ export function OnChainDetail({ refData, label = "View on-chain" }: { refData: O
<div className="flex items-center gap-2 text-sm font-semibold text-fg">
<ShieldCheck size={15} className="text-primary" /> {refData.label ?? "On-chain proof"}
</div>
<button type="button" onClick={() => setOpen(false)} className="rounded-md p-1 text-muted hover:bg-border/50" aria-label="Close"><X size={16} /></button>
<button type="button" onClick={() => setOpen(false)} className="rounded-md p-1 text-muted outline-none hover:bg-border/50 focus-visible:ring-2 focus-visible:ring-primary/40" aria-label="Close"><X size={16} /></button>
</div>
<div className="px-5 py-4">
<div className="mb-2 flex items-center gap-2">
Expand All @@ -97,10 +97,10 @@ export function OnChainDetail({ refData, label = "View on-chain" }: { refData: O
{refData.root ? <Row k="Merkle root" v={formatAddress(refData.root, 8, 6)} mono /> : null}
{refData.composeHash ? <Row k="Prover build hash" v={formatAddress(refData.composeHash, 8, 6)} mono /> : null}
{refData.verified && refData.verifier ? (
<Row k="Verifier contract" v={<a className="inline-flex items-center gap-1 text-primary hover:underline" href={explorerContractUrl(refData.verifier, net)} target="_blank" rel="noreferrer">{formatAddress(refData.verifier, 6, 4)} <ArrowUpRight size={11} /></a>} />
<Row k="Verifier contract" v={<a className="inline-flex items-center gap-1 rounded text-primary outline-none hover:underline focus-visible:ring-2 focus-visible:ring-primary/40" href={explorerContractUrl(refData.verifier, net)} target="_blank" rel="noreferrer">{formatAddress(refData.verifier, 6, 4)} <ArrowUpRight size={11} /></a>} />
) : null}
{refData.verified && refData.txHash ? (
<Row k="Transaction" v={<a className="inline-flex items-center gap-1 text-primary hover:underline" href={explorerTxUrl(refData.txHash, net)} target="_blank" rel="noreferrer">{formatAddress(refData.txHash, 6, 4)} <ArrowUpRight size={11} /></a>} />
<Row k="Transaction" v={<a className="inline-flex items-center gap-1 rounded text-primary outline-none hover:underline focus-visible:ring-2 focus-visible:ring-primary/40" href={explorerTxUrl(refData.txHash, net)} target="_blank" rel="noreferrer">{formatAddress(refData.txHash, 6, 4)} <ArrowUpRight size={11} /></a>} />
) : null}
</div>
<p className="mt-3 text-[11.5px] leading-relaxed text-muted">
Expand Down
Loading