From 61268f2a7a5d4b1942a1c683d053dcac40974b42 Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Fri, 18 Sep 2026 12:03:06 -0400 Subject: [PATCH] Say who made each change, and which ones you can undo The change log showed what happened and never who did it, which stops being a detail the moment more than one person is in the version. The Undo button greys out on entries belonging to someone else, with the reason on hover. The server already refused them; the button offered the click anyway and answered with a 403, which reads as a fault rather than a rule. Co-Authored-By: Claude Opus 5 (1M context) --- ui/src/views/Forecast.jsx | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/ui/src/views/Forecast.jsx b/ui/src/views/Forecast.jsx index affd063..fe05b10 100644 --- a/ui/src/views/Forecast.jsx +++ b/ui/src/views/Forecast.jsx @@ -1,5 +1,6 @@ import { useState, useEffect, useRef } from 'react' import useTheme from '../theme.jsx' +import useAuth from '../auth.jsx' import OperationPanel from '../components/OperationPanel.jsx' import BridgeView from '../components/BridgeView.jsx' @@ -54,6 +55,11 @@ const DEAD_ORDER_EXPRS = ['pf_bucket_ord', 'pf_segment_ord', 'Bucket', 'Segment' export default function Forecast({ sources = [], sourceId, versions = [], versionId, refreshSources }) { const { dark } = useTheme() + const { user } = useAuth() + // Undo removes an entry's rows wholesale, so the server allows it only to the + // account that made it, or an admin. Mirrored here to say so before the click + // rather than after the 403. + const canUndo = (entry) => !!user && (user.is_admin || entry.pf_user === user.username) const [loading, setLoading] = useState(false) const [largeDataset, setLargeDataset] = useState(false) // The pivot's own filter, refreshed whenever the ledger recomputes. A ref @@ -1902,6 +1908,7 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio Slice Tag Note + By Value Rows @@ -1935,6 +1942,9 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio )} /> + + {entry.pf_user || '—'} + 0 ? 'text-green-700' : entry.value_total < 0 ? 'text-red-600' : 'text-gray-400'}`}> {entry.value_total == null ? '—' @@ -1944,8 +1954,15 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio @@ -1955,7 +1972,7 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio if (expandedLog !== entry.id) return [row] return [row, ( - +