Make the change log fit its dialog
Adding the Value column pushed the table past max-w-4xl: roughly 624px of declared column widths inside an 896px dialog, leaving Slice and Note to fight over the rest. With auto table layout the cells won and the table grew wider than its container, so the dialog got a horizontal scrollbar along the bottom. table-fixed makes the declared widths hold and the free-text columns truncate instead of widening the table -- which is what the truncate classes on them already assumed. Dialog widened to max-w-6xl, gutters down from px-4 to px-3, and Note given an explicit share rather than whatever was left. max-w-xs on the slice and note cells was doing nothing useful under fixed layout and is now overflow-hidden, which is what makes truncate work in a table cell. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1d2fc97eee
commit
2bc6c5ec1a
@ -1394,7 +1394,7 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio
|
||||
{/* History modal */}
|
||||
{showLog && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40" onClick={() => setShowLog(false)}>
|
||||
<div className="bg-white rounded-lg shadow-xl w-full max-w-4xl mx-4 flex flex-col max-h-[80vh]" onClick={e => e.stopPropagation()}>
|
||||
<div className="bg-white rounded-lg shadow-xl w-full max-w-6xl mx-4 flex flex-col max-h-[85vh]" onClick={e => e.stopPropagation()}>
|
||||
<div className="flex items-center justify-between px-5 py-3 border-b border-gray-200 shrink-0">
|
||||
<span className="font-medium text-gray-700 text-sm">Change History</span>
|
||||
<button onClick={() => setShowLog(false)} className="text-gray-400 hover:text-gray-600 text-lg leading-none">×</button>
|
||||
@ -1406,29 +1406,29 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio
|
||||
) : logEntries.length === 0 ? (
|
||||
<div className="p-8 text-center text-sm text-gray-400">No log entries yet.</div>
|
||||
) : (
|
||||
<table className="w-full text-xs border-collapse">
|
||||
<table className="w-full text-xs border-collapse table-fixed">
|
||||
<thead className="sticky top-0 bg-gray-50 text-gray-400 uppercase tracking-wide" style={{fontSize:'10px'}}>
|
||||
<tr>
|
||||
<th className="text-left px-4 py-2 font-medium w-32">Time</th>
|
||||
<th className="text-left px-4 py-2 font-medium w-24">Op</th>
|
||||
<th className="text-left px-4 py-2 font-medium">Slice</th>
|
||||
<th className="text-left px-4 py-2 font-medium w-40">Tag</th>
|
||||
<th className="text-left px-4 py-2 font-medium">Note</th>
|
||||
<th className="text-right px-4 py-2 font-medium w-28">Value</th>
|
||||
<th className="text-right px-4 py-2 font-medium w-16">Rows</th>
|
||||
<th className="px-4 py-2 w-16"></th>
|
||||
<th className="text-left px-3 py-2 font-medium w-28">Time</th>
|
||||
<th className="text-left px-3 py-2 font-medium w-20">Op</th>
|
||||
<th className="text-left px-3 py-2 font-medium">Slice</th>
|
||||
<th className="text-left px-3 py-2 font-medium w-32">Tag</th>
|
||||
<th className="text-left px-3 py-2 font-medium w-48">Note</th>
|
||||
<th className="text-right px-3 py-2 font-medium w-28">Value</th>
|
||||
<th className="text-right px-3 py-2 font-medium w-16">Rows</th>
|
||||
<th className="px-3 py-2 w-16"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{logEntries.map(entry => (
|
||||
<tr key={entry.id} className="border-t border-gray-100 hover:bg-gray-50">
|
||||
<td className="px-4 py-2 text-gray-400 whitespace-nowrap">{fmtStamp(entry.stamp)}</td>
|
||||
<td className="px-4 py-2">
|
||||
<td className="px-3 py-2 text-gray-400 whitespace-nowrap">{fmtStamp(entry.stamp)}</td>
|
||||
<td className="px-3 py-2">
|
||||
<span className={`px-1.5 py-0.5 rounded text-xs font-medium ${opBadge(entry.operation)}`}>
|
||||
{entry.operation}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-2 text-gray-600 font-mono max-w-xs">
|
||||
<td className="px-3 py-2 text-gray-600 font-mono overflow-hidden">
|
||||
<button
|
||||
onClick={() => setExpandedLog(prev => prev === entry.id ? null : entry.id)}
|
||||
className="text-left w-full truncate hover:text-blue-600"
|
||||
@ -1447,13 +1447,13 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio
|
||||
)} />
|
||||
<LogCell entry={entry} field="note" placeholder="add note"
|
||||
editing={editingCell} setEditing={setEditingCell} onSave={saveLogField} />
|
||||
<td className={`px-4 py-2 text-right tabular-nums whitespace-nowrap ${
|
||||
<td className={`px-3 py-2 text-right tabular-nums whitespace-nowrap ${
|
||||
entry.value_total > 0 ? 'text-green-700' : entry.value_total < 0 ? 'text-red-600' : 'text-gray-400'}`}>
|
||||
{entry.value_total == null ? '—'
|
||||
: entry.value_total.toLocaleString(undefined, { maximumFractionDigits: 0 })}
|
||||
</td>
|
||||
<td className="px-4 py-2 text-right text-gray-500 tabular-nums">{entry.row_count ?? '—'}</td>
|
||||
<td className="px-4 py-2">
|
||||
<td className="px-3 py-2 text-right text-gray-500 tabular-nums">{entry.row_count ?? '—'}</td>
|
||||
<td className="px-3 py-2">
|
||||
<button
|
||||
onClick={() => undoEntry(entry.id)}
|
||||
disabled={undoingId === entry.id}
|
||||
@ -1467,7 +1467,7 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio
|
||||
if (expandedLog !== entry.id) return [row]
|
||||
return [row, (
|
||||
<tr key={`${entry.id}-detail`} className="bg-gray-50 border-t border-gray-100">
|
||||
<td colSpan={8} className="px-4 py-3">
|
||||
<td colSpan={8} className="px-3 py-3">
|
||||
<div className="grid gap-3 md:grid-cols-2">
|
||||
<LogJson label="slice" value={entry.slice} />
|
||||
<LogJson label="params" value={entry.params} />
|
||||
@ -1616,7 +1616,7 @@ function LogCell({ entry, field, placeholder, editing, setEditing, onSave, listI
|
||||
|
||||
if (active) {
|
||||
return (
|
||||
<td className="px-4 py-2">
|
||||
<td className="px-3 py-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<input autoFocus value={editing.text} list={listId}
|
||||
onChange={e => setEditing(c => ({ ...c, text: e.target.value }))}
|
||||
@ -1635,7 +1635,7 @@ function LogCell({ entry, field, placeholder, editing, setEditing, onSave, listI
|
||||
}
|
||||
|
||||
return (
|
||||
<td className="px-4 py-2 text-gray-700 max-w-xs">
|
||||
<td className="px-3 py-2 text-gray-700 overflow-hidden">
|
||||
<span onClick={() => setEditing({ id: entry.id, field, text: value })}
|
||||
className="cursor-text hover:bg-blue-50 rounded px-1 -mx-1 block truncate"
|
||||
title={value || `Click to ${placeholder}`}>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user