From 9a46a0daece6b6ce573d1f16cb42d714de90c7d9 Mon Sep 17 00:00:00 2001 From: Giorgio Gilestro Date: Wed, 27 May 2026 14:55:29 +0200 Subject: [PATCH] =?UTF-8?q?portfolio:=20render=20hidden=20=C3=97=20per=20r?= =?UTF-8?q?ow;=20empty=20state=20shows=20add=20form?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- app/static/js/portfolio.js | 23 ++++++++++++++++++----- app/static/js/portfolio_edit.js | 14 ++++++++++++++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/app/static/js/portfolio.js b/app/static/js/portfolio.js index f030024..dfbcbfa 100644 --- a/app/static/js/portfolio.js +++ b/app/static/js/portfolio.js @@ -180,17 +180,22 @@ function renderEmpty(mount) { const expired = consumeBackupExpiredNotice(); const notice = expired - ? '
' + - 'Your previous cloud backup couldn’t be restored on this server. ' + + ? '
Your encrypted cloud backup expired. ' + 'Please re-upload your portfolio to refresh it.' + '
' : ''; + var panel = document.getElementById('portfolio-panel'); + if (panel) panel.classList.add('pf-empty'); mount.innerHTML = '
' + notice + - 'No portfolio loaded in this browser. ' + - 'Import a portfolio CSV →' + + 'Welcome — start by adding a position above, or ' + + 'import a CSV from your broker →' + '
'; + // When empty, the add form should be visible by default — the + // edit module toggles it via the pf-empty class. + var form = document.getElementById('pf-add-form'); + if (form) form.hidden = false; } // Silently remove an unrecoverable cloud blob and re-render. The user @@ -265,6 +270,9 @@ } function renderPanel(mount, pie, enriched, agg) { + var panel = document.getElementById('portfolio-panel'); + if (panel) panel.classList.remove('pf-empty'); + const ccyPills = Object.keys(agg.by_currency) .sort((a, b) => agg.by_currency[b] - agg.by_currency[a]) .map(c => { @@ -293,6 +301,10 @@ '' + lastDisplay + fxBadge + '' + '' + signed(p._ppl) + '' + '' + pct(p._ppl_pct) + '' + + '' + + '' + + '' + ''; }).join(''); @@ -349,6 +361,7 @@ 'QtyAvg' + 'LastP/L' + '%' + + '' + '' + '' + rows + '' + '' + @@ -483,7 +496,7 @@ } const base = pie.base_currency || 'GBP'; const fx = (universeCache && universeCache.fx) || null; - const enriched = pie.positions.map(p => enrichPosition(p, base, fx)) + const enriched = pie.positions.map((p, i) => Object.assign(enrichPosition(p, base, fx), { _orig_idx: i })) .sort((a, b) => (b._value || 0) - (a._value || 0)); const agg = aggregate(enriched); renderPanel(mount, pie, enriched, agg); diff --git a/app/static/js/portfolio_edit.js b/app/static/js/portfolio_edit.js index 68225f4..ff7b614 100644 --- a/app/static/js/portfolio_edit.js +++ b/app/static/js/portfolio_edit.js @@ -248,4 +248,18 @@ } dateInput.addEventListener('blur', fetchHistorical); + + // ---- Per-row delete (event delegation) ----------------------------- + + panel.addEventListener('click', function (e) { + const btn = e.target.closest('.pf-row-del'); + if (!btn) return; + const idx = parseInt(btn.dataset.idx, 10); + if (!Number.isInteger(idx)) return; + const pie = window.CassandraPortfolio.loadPie(); + if (!pie || !pie.positions || idx < 0 || idx >= pie.positions.length) return; + pie.positions.splice(idx, 1); + window.CassandraPortfolio.savePie(pie); + window.CassandraPortfolio.mountAndRender(); + }); })();