From 52be043c1d7034dbc1f87943534a37df04be993c Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Sat, 13 Jun 2026 00:17:22 -0400 Subject: [PATCH] Add dim-period/cols endpoint and replace dim_period_col text input with select GET /api/dim-period/cols queries information_schema for pf.dim_period columns (excluding sdat/edat/drange/ndays) so the UI always reflects actual columns. Setup col_meta editor now shows a dropdown populated from that endpoint instead of a free-text field, preventing invalid column names like the cash source had. Co-Authored-By: Claude Sonnet 4.6 --- routes/sources.js | 16 ++++++++++++++++ ui/src/views/Setup.jsx | 13 ++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/routes/sources.js b/routes/sources.js index 6376264..f09d77e 100644 --- a/routes/sources.js +++ b/routes/sources.js @@ -280,6 +280,22 @@ module.exports = function(pool) { }); // deregister a source — does not drop existing forecast tables + router.get('/dim-period/cols', async (req, res) => { + try { + const result = await pool.query(` + SELECT column_name + FROM information_schema.columns + WHERE table_schema = 'pf' AND table_name = 'dim_period' + AND column_name NOT IN ('sdat', 'edat', 'drange', 'ndays') + ORDER BY ordinal_position + `); + res.json(result.rows.map(r => r.column_name)); + } catch (err) { + console.error(err); + res.status(500).json({ error: err.message }); + } + }); + router.delete('/sources/:id', async (req, res) => { try { const result = await pool.query( diff --git a/ui/src/views/Setup.jsx b/ui/src/views/Setup.jsx index 52480ae..c60273e 100644 --- a/ui/src/views/Setup.jsx +++ b/ui/src/views/Setup.jsx @@ -24,9 +24,11 @@ export default function Setup({ refreshSources }) { const [saving, setSaving] = useState(false) const [generating, setGenerating] = useState(false) const [msg, setMsg] = useState(null) + const [dimPeriodCols, setDimPeriodCols] = useState([]) useEffect(() => { fetch('/api/tables').then(r => r.json()).then(setTables).catch(console.error) + fetch('/api/dim-period/cols').then(r => r.json()).then(setDimPeriodCols).catch(console.error) loadSources() }, []) @@ -324,14 +326,15 @@ export default function Setup({ refreshSources }) { /> - updateCol(i, 'dim_period_col', e.target.value || null)} - placeholder="—" disabled={col.role !== 'dimension' || !col.dim_group} - className="border border-transparent hover:border-gray-200 focus:border-gray-300 rounded px-1.5 py-0.5 w-full outline-none bg-transparent disabled:opacity-20 disabled:cursor-default font-mono text-xs" - /> + className="text-xs px-1.5 py-0.5 rounded border border-transparent hover:border-gray-200 focus:border-gray-300 outline-none bg-transparent disabled:opacity-20 disabled:cursor-default font-mono w-full" + > + + {dimPeriodCols.map(c => )} +