From 81c467214752222dd79426b4f4c29e35f9c78462 Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Thu, 17 Sep 2026 13:57:33 -0400 Subject: [PATCH] Fit columns by driving regular-table, not the plugin's draw The Fit button did nothing. Setting _reset_column_size and redrawing cannot work, because draw() undoes the reset on the very next line: const old_sizes = save_column_size_overrides.call(this); ... if (this._reset_column_size) { resetAutoSize() } restore_column_size_overrides.call(this, old_sizes); and old_sizes comes from regular_table.saveColumnSizes() -- the *live* widths -- not from plugin_config. So each draw preserves whatever the columns currently are, whatever the config says, and clearing column_size_override released nothing. Calls regular_table.resetAutoSize() and draw() directly instead: the same draw the plugin performs, without the save/restore wrapped around it. _cached_column_sizes is cleared too, since it short-circuits the next save and would be restored over the measurement. Co-Authored-By: Claude Opus 5 (1M context) --- ui/src/views/Forecast.jsx | 52 ++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/ui/src/views/Forecast.jsx b/ui/src/views/Forecast.jsx index 1d76f19..7caa0c5 100644 --- a/ui/src/views/Forecast.jsx +++ b/ui/src/views/Forecast.jsx @@ -950,40 +950,42 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio // Size every column to its contents. // - // The datagrid already does this -- draw() calls regular_table.resetAutoSize() - // -- but only when _reset_column_size is set, and it restores any pinned widths - // immediately afterwards: + // The datagrid measures content on its own -- draw() calls + // regular_table.resetAutoSize() when _reset_column_size is set -- but the reset + // is immediately undone: // - // const old_sizes = save_column_size_overrides.call(this); + // const old_sizes = save_column_size_overrides.call(this); // live widths // ... if (this._reset_column_size) { resetAutoSize() } - // restore_column_size_overrides.call(this, old_sizes); + // restore_column_size_overrides.call(this, old_sizes); // straight back // - // So a width pinned by dragging, or carried in a saved layout, wins over the - // measurement for good. Clearing the overrides is what actually releases them; - // the flag then makes the next draw measure rather than reuse. + // and old_sizes comes from regular_table.saveColumnSizes(), the *live* widths, + // not from plugin_config. So every draw preserves whatever the columns are + // currently at, and clearing the config releases nothing. Setting the flag and + // going through the plugin's draw cannot work for the same reason. // - // Order matters: the flag is set *after* restore(), because building the model - // recomputes it from what changed in the config and would clear it again. + // So drive regular_table directly: drop the cached sizes, reset, and draw. It is + // the same draw the plugin calls, without the save/restore wrapped around it. async function fitColumns() { const viewer = viewerRef.current if (!viewer) return try { - const { table: _t, ...cfg } = await viewer.save() - const pc = { ...(cfg.plugin_config || {}) } - if (pc.columns) { - pc.columns = Object.fromEntries( - Object.entries(pc.columns).map(([col, v]) => { - const { column_size_override, ...rest } = v || {} - return [col, rest] - }) - ) - } - await viewer.restore({ ...cfg, plugin_config: pc }) - const plugin = await viewer.getPlugin() - if (plugin) plugin._reset_column_size = true - const view = await viewer.getView() - await plugin?.draw?.(view) + const grid = plugin?.regular_table + if (!grid?.resetAutoSize) { + flash('This plugin does not support fitting columns', 'error') + return + } + // _cached_column_sizes is consumed by the next save_column_size_overrides + // and would otherwise be restored over the measurement + plugin._cached_column_sizes = undefined + plugin._reset_column_size = false + grid.resetAutoSize() + await grid.draw({ invalid_columns: true }) + + // Widths are not part of ViewConfig, so persist the layout to keep the + // saved copy in step with what is on screen. + const cfg = await captureConfig() + if (cfg) await persistLayout(versionId, cfg) } catch (err) { console.error('[fitColumns]', err) flash(err.message || String(err), 'error')