From 9d08638a9224b84704d62309b0605a98c0b1e69a Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Fri, 18 Sep 2026 11:52:00 -0400 Subject: [PATCH] Read territory at login, and survive having none The login query names its columns, and territory and is_admin were not among them -- so every session carried an empty list, every account scoped to FALSE, and the forecast page came back with nothing however the grant was set. The CLI had written it correctly; nothing read it. The empty case then aborted twice over. First on the index, fixed already. Then on the layout: an empty table has no schema, so restoring a saved config asks for the dtype of a column that is not there and the worker dies -- "Could not get dtype for column `sseas_e`". With no rows there is nothing to lay out, so nothing is restored, and the saved layout waits in localStorage for rows to come back. Co-Authored-By: Claude Opus 5 (1M context) --- routes/auth.js | 3 ++- ui/src/views/Forecast.jsx | 11 +++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/routes/auth.js b/routes/auth.js index 1c64b51..34ac0cf 100644 --- a/routes/auth.js +++ b/routes/auth.js @@ -46,7 +46,8 @@ module.exports = function(pool) { try { const result = await pool.query( - `SELECT id, username, display_name, pass_hash, is_active + `SELECT id, username, display_name, pass_hash, is_active, + is_admin, territory FROM pf.app_user WHERE lower(username) = lower($1)`, [username] ); diff --git a/ui/src/views/Forecast.jsx b/ui/src/views/Forecast.jsx index 0510d42..affd063 100644 --- a/ui/src/views/Forecast.jsx +++ b/ui/src/views/Forecast.jsx @@ -806,8 +806,15 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio // restore last-used layout or build default // Strip cfg.table — table is already loaded by reference above; a stale name // in a saved config would cause Perspective to fail the name lookup. - const saved = localStorage.getItem(LAYOUT_KEY(vid)) - if (saved) { + // + // An empty table has no schema at all, so any config naming any column + // aborts the worker -- "Could not get dtype for column `sseas_e`". There + // is nothing to lay out, so nothing is restored; the saved layout stays in + // localStorage and comes back when there are rows again. + const saved = rowCount > 0 ? localStorage.getItem(LAYOUT_KEY(vid)) : null + if (rowCount === 0) { + await viewer.restore({ settings: false, plugin_config: { edit_mode: 'SELECT_REGION' } }) + } else if (saved) { const { table: _t, ...rest } = cleanLayout(JSON.parse(saved), validCols) const cfg = { ...rest, plugin_config: { ...(rest.plugin_config || {}), edit_mode: 'SELECT_REGION' } } await viewer.restore(cfg)