Skip to content

Commit 20bd014

Browse files
os-zhuangclaude
andauthored
fix(approvals): Approval Center density + amount emphasis (#2762 P2) (#2805)
- Inbox table column rebalance: Record (primary) widest, Request moderate, Status/Submitted fixed widths — 审批事项 no longer over-wide vs cramped 状态 - Drawer summary card leads with the decision-critical amount as a filled figure at the top instead of buried in the field grid (deduped from it) Light mode (already supported via ConsoleShell ThemeProvider defaultTheme= system + ModeToggle) and batch actions (bulk approve/reject bar already present) need no change — verified, noted in changeset. Refs objectui#2762 Claude-Session: https://claude.ai/code/session_01Cu48mLFUdRBmMh8Z8R3CVz Co-authored-by: Claude <noreply@anthropic.com>
1 parent 0b10bc3 commit 20bd014

2 files changed

Lines changed: 55 additions & 11 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
"@object-ui/console": patch
3+
---
4+
5+
fix(approvals): Approval Center density + amount emphasis (#2762 P2)
6+
7+
- **Column rebalance** — the inbox table gave five auto columns equal width,
8+
leaving 审批事项 (Request) over-wide next to a cramped 状态 (Status). The
9+
Record column (the primary content) now gets the widest share, Request a
10+
moderate one, and Status/Submitted fixed widths so they never crowd.
11+
- **Lead with the amount** — the drawer summary card now surfaces the
12+
decision-critical amount as a filled figure at the top of the card instead
13+
of burying it in the generic field grid (and drops it from that grid so it
14+
shows once).
15+
16+
Also verified two P2 items need no change: light mode already works —
17+
`ConsoleShell` mounts `ThemeProvider defaultTheme="system"` (follows the OS
18+
`prefers-color-scheme`) with a `ModeToggle`, and the page's own classes carry
19+
full light/dark variants; and the queue already has a bulk approve/reject
20+
toolbar for the select-all/per-row selection.

apps/console/src/pages/system/ApprovalsInboxPage.tsx

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -268,11 +268,13 @@ function payloadSummary(
268268
payload: unknown,
269269
display?: Record<string, string>,
270270
max = 6,
271+
excludeKey?: string,
271272
): Array<[string, string]> {
272273
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return [];
273274
const out: Array<[string, string]> = [];
274275
for (const [k, v] of Object.entries(payload as Record<string, unknown>)) {
275276
if (PAYLOAD_SYSTEM_KEYS.has(k)) continue;
277+
if (excludeKey && k === excludeKey) continue; // shown as the lead amount
276278
if (v == null || typeof v === 'object') continue;
277279
if (String(v).trim() === '') continue;
278280
const resolved = display?.[k];
@@ -300,7 +302,7 @@ const AMOUNT_KEY_RE = /(amount|total|price|value|cost|sum|budget|salary|fee|reve
300302
*/
301303
function decisionAmountEntry(
302304
r: ApprovalRequestRow,
303-
): { label: string; value: number; display: string } | null {
305+
): { key: string; label: string; value: number; display: string } | null {
304306
const payload = r.payload;
305307
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) return null;
306308
for (const [k, v] of Object.entries(payload as Record<string, unknown>)) {
@@ -310,7 +312,7 @@ function decisionAmountEntry(
310312
? v
311313
: (typeof v === 'string' && v.trim() !== '' && Number.isFinite(Number(v)) ? Number(v) : null);
312314
if (num == null || !Number.isFinite(num)) continue;
313-
return { label: prettifyKey(k), value: num, display: r.payload_display?.[k] ?? num.toLocaleString() };
315+
return { key: k, label: prettifyKey(k), value: num, display: r.payload_display?.[k] ?? num.toLocaleString() };
314316
}
315317
return null;
316318
}
@@ -1294,12 +1296,17 @@ export function ApprovalsInboxPage() {
12941296
/>
12951297
</TableHead>
12961298
)}
1297-
<TableHead>{tr('colRequest', 'Request')}</TableHead>
1298-
<TableHead>{tr('colRecord', 'Record')}</TableHead>
1299-
<TableHead>{tr('colRequester', 'Requester')}</TableHead>
1300-
{/* min-width keeps the status pill on one line (#2762 P0-1) */}
1301-
<TableHead className="min-w-[96px] whitespace-nowrap">{tr('colStatus', 'Status')}</TableHead>
1302-
<TableHead>{tr('colWaiting', 'Submitted')}</TableHead>
1299+
{/* Column widths rebalanced (#2762 P2): the Record is the
1300+
primary content so it gets the widest share, the
1301+
Request a moderate one, and Status/Submitted fixed
1302+
widths so they never crowd — instead of the browser
1303+
spreading five auto columns evenly and leaving 审批事项
1304+
over-wide next to a cramped 状态. */}
1305+
<TableHead className="w-[22%]">{tr('colRequest', 'Request')}</TableHead>
1306+
<TableHead className="w-[30%]">{tr('colRecord', 'Record')}</TableHead>
1307+
<TableHead className="w-[16%]">{tr('colRequester', 'Requester')}</TableHead>
1308+
<TableHead className="w-[110px] min-w-[96px] whitespace-nowrap">{tr('colStatus', 'Status')}</TableHead>
1309+
<TableHead className="w-[132px]">{tr('colWaiting', 'Submitted')}</TableHead>
13031310
<TableHead className="w-20" aria-label={tr('colActions', 'Actions')} />
13041311
</TableRow>
13051312
</TableHeader>
@@ -1558,6 +1565,13 @@ export function ApprovalsInboxPage() {
15581565
</div>
15591566

15601567
{/* Business summary card */}
1568+
{(() => {
1569+
// Decision-critical amount leads the card (#2762 P2) — a filled
1570+
// figure at the top instead of a value buried bottom-right in the
1571+
// generic field grid. Excluded from that grid below so it shows once.
1572+
const drawerAmount = decisionAmountEntry(selected);
1573+
const summary = payloadSummary(selected.payload, selected.payload_display, 6, drawerAmount?.key);
1574+
return (
15611575
<Card>
15621576
<CardContent className="p-4 space-y-3">
15631577
<div className="flex items-start justify-between gap-2">
@@ -1587,9 +1601,17 @@ export function ApprovalsInboxPage() {
15871601
</div>
15881602
</div>
15891603
</div>
1590-
{payloadSummary(selected.payload, selected.payload_display).length > 0 && (
1591-
<div className="grid grid-cols-2 gap-x-4 gap-y-2 text-sm border-t pt-3">
1592-
{payloadSummary(selected.payload, selected.payload_display).map(([k, v]) => (
1604+
{drawerAmount && (
1605+
<div className="border-t pt-3">
1606+
<div className="text-[11px] text-muted-foreground">{drawerAmount.label}</div>
1607+
<div className="text-xl font-semibold tabular-nums" title={drawerAmount.display}>
1608+
{drawerAmount.display}
1609+
</div>
1610+
</div>
1611+
)}
1612+
{summary.length > 0 && (
1613+
<div className={cn('grid grid-cols-2 gap-x-4 gap-y-2 text-sm', !drawerAmount && 'border-t pt-3')}>
1614+
{summary.map(([k, v]) => (
15931615
<div key={k} className="min-w-0">
15941616
<div className="text-[11px] text-muted-foreground">{k}</div>
15951617
<div className="truncate" title={v}>{v}</div>
@@ -1695,6 +1717,8 @@ export function ApprovalsInboxPage() {
16951717
)}
16961718
</CardContent>
16971719
</Card>
1720+
);
1721+
})()}
16981722

16991723
{(selected.flow_steps?.length ?? 0) > 1 && (
17001724
<div className="flex items-center px-1" aria-label={tr('stepProgress', 'Approval steps')}>

0 commit comments

Comments
 (0)