Pivot: round numbers in inspector to 2 decimals with adjustable precision

formatVal now rounds numeric values using toLocaleString with
configurable decimal places (default 2, range 0-8). Adds -/+ controls
in the inspector header to adjust on the fly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Paul Trowbridge 2026-04-15 08:54:34 -04:00
parent 8d3cc24094
commit 420bc1bbe8

View File

@ -30,12 +30,15 @@ function loadPerspective() {
return perspectivePromise return perspectivePromise
} }
function formatVal(v) { function formatVal(v, decimals = 2) {
if (v == null) return null if (v == null) return null
if (typeof v === 'number' && v > 1e11 && v < 2e12) { if (typeof v === 'number') {
if (v > 1e11 && v < 2e12) {
const d = new Date(v) const d = new Date(v)
if (!isNaN(d)) return d.toISOString().slice(0, 10) if (!isNaN(d)) return d.toISOString().slice(0, 10)
} }
return v.toLocaleString(undefined, { minimumFractionDigits: decimals, maximumFractionDigits: decimals })
}
return String(v) return String(v)
} }
@ -87,6 +90,7 @@ export default function Pivot({ source }) {
const [error, setError] = useState('') const [error, setError] = useState('')
const [inspectedRows, setInspectedRows] = useState(null) const [inspectedRows, setInspectedRows] = useState(null)
const [clickDetail, setClickDetail] = useState(null) const [clickDetail, setClickDetail] = useState(null)
const [decimals, setDecimals] = useState(2)
// Named layouts // Named layouts
const [layouts, setLayouts] = useState([]) const [layouts, setLayouts] = useState([])
@ -412,9 +416,18 @@ export default function Pivot({ source }) {
<span className="text-xs font-semibold text-gray-600 uppercase tracking-wide"> <span className="text-xs font-semibold text-gray-600 uppercase tracking-wide">
{inspectedRows.length} row{inspectedRows.length !== 1 ? 's' : ''} {inspectedRows.length} row{inspectedRows.length !== 1 ? 's' : ''}
</span> </span>
<div className="flex items-center gap-2">
<div className="flex items-center gap-0.5">
<button onClick={() => setDecimals(d => Math.max(0, d - 1))}
className="text-xs text-gray-400 hover:text-gray-600 w-4 text-center"></button>
<span className="text-xs text-gray-400 w-4 text-center">{decimals}</span>
<button onClick={() => setDecimals(d => Math.min(8, d + 1))}
className="text-xs text-gray-400 hover:text-gray-600 w-4 text-center">+</button>
</div>
<button onClick={() => { setInspectedRows(null); setClickDetail(null) }} <button onClick={() => { setInspectedRows(null); setClickDetail(null) }}
className="text-gray-300 hover:text-gray-500 leading-none text-lg">×</button> className="text-gray-300 hover:text-gray-500 leading-none text-lg">×</button>
</div> </div>
</div>
<div className="flex-1 overflow-y-auto"> <div className="flex-1 overflow-y-auto">
{/* Cell coordinates */} {/* Cell coordinates */}
@ -434,7 +447,7 @@ export default function Pivot({ source }) {
return ( return (
<div key={k} className={`flex justify-between py-0.5 gap-2 ${isSelected ? 'font-semibold' : ''}`}> <div key={k} className={`flex justify-between py-0.5 gap-2 ${isSelected ? 'font-semibold' : ''}`}>
<span className={`text-xs font-mono shrink-0 ${isSelected ? 'text-gray-700' : 'text-gray-400'}`}>{k}</span> <span className={`text-xs font-mono shrink-0 ${isSelected ? 'text-gray-700' : 'text-gray-400'}`}>{k}</span>
<span className={`text-xs font-mono text-right ${isSelected ? 'text-blue-600' : 'text-gray-700'}`}>{formatVal(v)}</span> <span className={`text-xs font-mono text-right ${isSelected ? 'text-blue-600' : 'text-gray-700'}`}>{formatVal(v, decimals)}</span>
</div> </div>
) )
})} })}
@ -468,7 +481,7 @@ export default function Pivot({ source }) {
{inspectedRows.map((row, i) => ( {inspectedRows.map((row, i) => (
<tr key={i} className="border-t border-gray-50 hover:bg-gray-50"> <tr key={i} className="border-t border-gray-50 hover:bg-gray-50">
{cols.map(c => { {cols.map(c => {
const f = formatVal(row[c]) const f = formatVal(row[c], decimals)
return ( return (
<td key={c} className="px-2 py-1 font-mono whitespace-nowrap text-gray-700 max-w-40 truncate"> <td key={c} className="px-2 py-1 font-mono whitespace-nowrap text-gray-700 max-w-40 truncate">
{f == null ? <span className="text-gray-300"></span> : f} {f == null ? <span className="text-gray-300"></span> : f}