[object Object]

← back to Nationalrealestate

USRE grid: CSV export honors active filters — export filtered+sorted rows client-side (was dumping ALL rows) (v0.7.0)

966b6289d0711426b5902b83016ce0b83a3399e9 · 2026-07-26 19:57:46 -0700 · Steve

Files touched

Diff

commit 966b6289d0711426b5902b83016ce0b83a3399e9
Author: Steve <steve@designerwallcoverings.com>
Date:   Sun Jul 26 19:57:46 2026 -0700

    USRE grid: CSV export honors active filters — export filtered+sorted rows client-side (was dumping ALL rows) (v0.7.0)
---
 package-lock.json   |  4 ++--
 package.json        |  2 +-
 public/crcp-grid.js | 29 ++++++++++++++++++++++++++++-
 public/markets.html |  8 ++++++++
 4 files changed, 39 insertions(+), 4 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 7aefdd2..a3d5d85 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "nationalrealestate",
-  "version": "0.6.0",
+  "version": "0.7.0",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "nationalrealestate",
-      "version": "0.6.0",
+      "version": "0.7.0",
       "dependencies": {
         "better-sqlite3": "^13.0.1",
         "dotenv": "^16.4.5",
diff --git a/package.json b/package.json
index fb69a74..c6b2c3c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "nationalrealestate",
-  "version": "0.6.0",
+  "version": "0.7.0",
   "private": true,
   "type": "module",
   "description": "USRealEstate — national U.S. residential market explorer. Free-data v1 (Redfin Data Center, Zillow Research, Census ACS, FHFA). Internal analyst tool behind basic auth.",
diff --git a/public/crcp-grid.js b/public/crcp-grid.js
index d68eff5..a7a36dd 100644
--- a/public/crcp-grid.js
+++ b/public/crcp-grid.js
@@ -299,8 +299,35 @@
       });
     }
 
+    // Export the CURRENTLY filtered + sorted rows (uncapped) as a CSV Blob — so a
+    // download reflects exactly what the user filtered to, not the whole dataset.
+    function exportCSV(opts) {
+      opts = opts || {};
+      const rows = sortRows(data.filter(pass));
+      const cols = fields.filter(f => !f.badge && f.k !== 'name'); // 'name' handled as the title column
+      const csvEsc = v => { if (v == null) return ''; v = String(v); return /[",\n]/.test(v) ? '"' + v.replace(/"/g, '""') + '"' : v; };
+      const header = ['Name'].concat(cols.map(f => f.l));
+      const lines = [header.map(csvEsc).join(',')];
+      rows.forEach(r => {
+        const t = O.title ? O.title(r) : { name: r.name || '' };
+        lines.push([csvEsc(t.name)].concat(cols.map(f => csvEsc(fval(r, f)))).join(','));
+      });
+      const blob = new Blob([lines.join('\n')], { type: 'text/csv;charset=utf-8' });
+      const url = URL.createObjectURL(blob);
+      const a = document.createElement('a');
+      a.href = url; a.download = opts.filename || 'export.csv';
+      document.body.appendChild(a); a.click(); a.remove();
+      setTimeout(() => URL.revokeObjectURL(url), 1000);
+      return rows.length;
+    }
+
     buildTop(); buildRail(); render();
-    return { render, setData(d) { O.data.length = 0; d.forEach(x => O.data.push(x)); buildRail(); render(); } };
+    return {
+      render,
+      setData(d) { O.data.length = 0; d.forEach(x => O.data.push(x)); buildRail(); render(); },
+      exportCSV,
+      filteredCount() { return data.filter(pass).length; },
+    };
   }
 
   global.CrcpGrid = { mount: opts => new CrcpGrid(opts) };
diff --git a/public/markets.html b/public/markets.html
index a82d865..b61ab53 100644
--- a/public/markets.html
+++ b/public/markets.html
@@ -151,6 +151,14 @@ document.getElementById('typeSeg').addEventListener('click', e => {
   const b = e.target.closest('button[data-type]');
   if (b && b.dataset.type !== TYPE) load(b.dataset.type);
 });
+// CSV export now honors the active filters — export the grid's filtered+sorted rows
+// client-side instead of hitting the server endpoint (which dumps ALL rows).
+document.getElementById('exportcsv').addEventListener('click', e => {
+  if (!grid) return; // fall back to the href if the grid isn't ready
+  e.preventDefault();
+  const n = grid.exportCSV({ filename: `usre-markets-${TYPE}.csv` });
+  console.log(`exported ${n} filtered ${TYPE} rows`);
+});
 load(TYPE);
 </script>
 <script src="/nav-drawer.js"></script>

← 6e08a2b auto-save: 2026-07-26T17:14:46 (2 files) — src/ingest/parcel  ·  back to Nationalrealestate  ·  USRE grid: polished empty state — icon + message + one-click 46b0b58 →