diff --git a/ui/src/components/OperationPanel.jsx b/ui/src/components/OperationPanel.jsx index dc6292a..15e02ca 100644 --- a/ui/src/components/OperationPanel.jsx +++ b/ui/src/components/OperationPanel.jsx @@ -97,7 +97,12 @@ const LABEL_W = 'w-24' // which put a line of prose beside every toggle -- and a line of prose beside a // toggle is skipped, while still costing the dock a row. Hovering gives it // (native title, which nothing can clip), clicking pins it. -function Help({ text }) { +// +// It opens upward, because the settings it explains sit low in a dock that +// scrolls -- a popover hanging below them is cut off by the dock's own edge. +// `dir="down"` is for the few that sit at the top of the panel, where up is the +// clipped direction instead. +function Help({ text, dir = 'up' }) { const [open, setOpen] = useState(false) if (!text) return null return ( @@ -108,8 +113,9 @@ function Help({ text }) { open ? 'border-blue-400 text-blue-600 bg-blue-50' : 'border-gray-300 text-gray-500 hover:text-blue-600 hover:border-blue-400'}`} style={{ fontSize: '10px' }}>? {open && ( - + {text} )} @@ -120,11 +126,11 @@ function Help({ text }) { // `stack` puts the label above its control instead of beside it. The aligned // label column costs 6rem, which is most of a narrow zone -- the tag field in // the bottom dock had 12rem of box left to type an initiative name into. -function Field({ label, children, hint, stack }) { +function Field({ label, children, hint, hintDir, stack }) { if (stack) { return (
- {label} + {label}
{children}
) @@ -134,7 +140,7 @@ function Field({ label, children, hint, stack }) { {label}
{children} - +
) @@ -1312,6 +1318,20 @@ function RequestPreview({ payload, op, versionId }) { ) } +// What the three operations are, for the ? beside them. Written for somebody +// who has been handed the app, not for whoever wrote the SQL: what it does to +// the numbers, and what it leaves alone. +const OP_HELP = { + scale: 'Moves the selection to a number you name — a new total, a change, or a percentage. ' + + 'The rows already there are left alone: the difference is written as new rows underneath them, ' + + 'so the pivot re-sums and the whole thing is one entry you can undo.', + recode: 'Moves the selection to different dimension values — another customer, part or program. ' + + 'It writes the original back out as a negative and the same amounts in at the new coordinates, ' + + 'so nothing is lost and both halves undo together.', + clone: 'Copies the selection to new rows, optionally shifted in time and scaled. The original is untouched. ' + + 'This is how a period with no baseline of its own borrows its shape from prior year or plan.', +} + export default function OperationPanel({ dock, slices, setSlices, distinctSlices, @@ -1500,6 +1520,9 @@ export default function OperationPanel({ submitOp(activeOp)} busy={!!opBusy}> {opBusy ? POSTING : POST} + {opBusy && writing rows…} @@ -1517,7 +1540,7 @@ export default function OperationPanel({ with no heading over it, so the panel never said what it was about to do until you read the button. */}
- +
{['scale', 'recode', 'clone'].map(op => (