{"id":"68fe6032e8b89ced6765d7a0","title":"2025 10 25","path":"how-to/committee/release-notes/2025-10-25","contentMarkdown":"# 25th October 2025 — Optimise paste pipeline with client-side detection, server enhancements, and admin UX [#67](https://github.com/nbarrett/ngx-ramblers/issues/66)\n## [build 321](https://github.com/nbarrett/ngx-ramblers/actions/runs/18803315196)\n  ____\nResolves sluggish paste UX by adding client-side filtering, robust server processing for HTML/Markdown/URL content, and admin tools for site config management. Consolidates paste flows, DRY Puppeteer utilities, and fragment handling.  🎯\n  ____\n\n\n**Problem:**\n- Pastes triggered unnecessary server round trips for plain text/trivial HTML (e.g., browser wrappers like <meta charset>, <span> tags).\n- No client-side distinction between significant HTML (images/links/tables) and wrappers, causing lag.\n- URL pastes (view-source:/http) lacked auto-fetch/preview; fragments lacked nested row support.\n- Admin site config lacked paste/copy clipboard; Puppeteer launches were duplicated.\n\n**Solution:**\n- **Client-Side Detection (`PasteDetectionService`)**: `isSignificantHtml()` filters wrappers (prioritizes tags like <img>/<a>/<table> over browser patterns); `hasMarkdownImages()` and `isLocalPath()` moved client-side. Defers server calls until user confirms in prompt.\n- **Server Paste Pipeline**: Preprocessing decodes entities, strips wrappers/anchors/CSS artifacts, normalizes <img> sources, resolves relatives via base URL; Turndown for HTML→Markdown cleanup (e.g., \"Distance: 2.7 miles\"). New APIs: `/html-from-url` (Puppeteer fetch with base auto-detect), `/html-paste-preview`/`/markdown-paste-preview` (return markdown + rows).\n- **Paste UX**: Prompts for base URL (suggested from config); splits images/captions into rows; preserves local paths as plain text. Added \"Convert to Rows\" toolbar button with row count preview (pluralized via `pluraliseWithCount`).\n- **Admin UX**: Site config header buttons for Paste (JSON textarea with validation/apply) and Copy (ClipboardService); duplicate site retained.\n- **Nested Rows & Actions**: Config toggle \"Keep Content Together\"; actions menu with Unnest (previous/next outer row).\n- **Puppeteer DRY**: `puppeteer-utils.ts` centralizes `launchBrowser()`/`deriveBaseUrl()`; refactored migration routes/engine.\n- **Fragments**: Recursive usage detection in nested rows; normalize paths (strip leading /); include both `/fragments` and `fragments` variants; add `/fragments` → `/admin/fragment-index` redirect.\n\n**Benefits:**\n- Instant plain/trivial pastes (no server calls); rich content processed efficiently.\n- Cleaner markdown rows; auto-base for URLs; nested row support for multi-column layouts.\n- Reduced duplication; improved admin workflow (clipboard integration).\n\n**Changes:**\n- New: `PasteDetectionService` (93 lines, 24 tests); APIs; utils; radio buttons for row placement (nested/sibling, smart default by column count).\n- Updated: `markdown-editor.component.ts` (paste flows, toolbar); `dynamic-content-site-edit-text-row.ts` (nested insertion); `migrate-static-site.ts` (Puppeteer); `fragment-index` (recursive traversal).\n- Removed: Duplicate Puppeteer code; CSS artifacts in preprocessing.\n\n**Testing:**\n- 24 unit tests (`paste-detection.service.spec.ts`, `turndown-service-factory.spec.ts`) pass (wrappers, tags, images, entities, anchors, CSS stripping).\n- Server e2e/integration tests for previews/fetch; frontend builds succeed.\n- Manual: Multi-column nested pastes, URL fetch, duplicate columns, fragment redirects.\n\nCloses #67.\n","contentHtml":"<h1>25th October 2025 — Optimise paste pipeline with client-side detection, server enhancements, and admin UX <a href=\"https://github.com/nbarrett/ngx-ramblers/issues/66\">#67</a></h1>\n<h2><a href=\"https://github.com/nbarrett/ngx-ramblers/actions/runs/18803315196\">build 321</a></h2>\n<hr>\n<p>Resolves sluggish paste UX by adding client-side filtering, robust server processing for HTML/Markdown/URL content, and admin tools for site config management. Consolidates paste flows, DRY Puppeteer utilities, and fragment handling.  🎯</p>\n<hr>\n<p><strong>Problem:</strong></p>\n<ul>\n<li>Pastes triggered unnecessary server round trips for plain text/trivial HTML (e.g., browser wrappers like <meta charset>, <span> tags).</li>\n<li>No client-side distinction between significant HTML (images/links/tables) and wrappers, causing lag.</li>\n<li>URL pastes (view-source:/http) lacked auto-fetch/preview; fragments lacked nested row support.</li>\n<li>Admin site config lacked paste/copy clipboard; Puppeteer launches were duplicated.</li>\n</ul>\n<p><strong>Solution:</strong></p>\n<ul>\n<li><strong>Client-Side Detection (<code>PasteDetectionService</code>)</strong>: <code>isSignificantHtml()</code> filters wrappers (prioritizes tags like <img>/<a>/<table> over browser patterns); <code>hasMarkdownImages()</code> and <code>isLocalPath()</code> moved client-side. Defers server calls until user confirms in prompt.</li>\n<li><strong>Server Paste Pipeline</strong>: Preprocessing decodes entities, strips wrappers/anchors/CSS artifacts, normalizes <img> sources, resolves relatives via base URL; Turndown for HTML→Markdown cleanup (e.g., &quot;Distance: 2.7 miles&quot;). New APIs: <code>/html-from-url</code> (Puppeteer fetch with base auto-detect), <code>/html-paste-preview</code>/<code>/markdown-paste-preview</code> (return markdown + rows).</li>\n<li><strong>Paste UX</strong>: Prompts for base URL (suggested from config); splits images/captions into rows; preserves local paths as plain text. Added &quot;Convert to Rows&quot; toolbar button with row count preview (pluralized via <code>pluraliseWithCount</code>).</li>\n<li><strong>Admin UX</strong>: Site config header buttons for Paste (JSON textarea with validation/apply) and Copy (ClipboardService); duplicate site retained.</li>\n<li><strong>Nested Rows &amp; Actions</strong>: Config toggle &quot;Keep Content Together&quot;; actions menu with Unnest (previous/next outer row).</li>\n<li><strong>Puppeteer DRY</strong>: <code>puppeteer-utils.ts</code> centralizes <code>launchBrowser()</code>/<code>deriveBaseUrl()</code>; refactored migration routes/engine.</li>\n<li><strong>Fragments</strong>: Recursive usage detection in nested rows; normalize paths (strip leading /); include both <code>/fragments</code> and <code>fragments</code> variants; add <code>/fragments</code> → <code>/admin/fragment-index</code> redirect.</li>\n</ul>\n<p><strong>Benefits:</strong></p>\n<ul>\n<li>Instant plain/trivial pastes (no server calls); rich content processed efficiently.</li>\n<li>Cleaner markdown rows; auto-base for URLs; nested row support for multi-column layouts.</li>\n<li>Reduced duplication; improved admin workflow (clipboard integration).</li>\n</ul>\n<p><strong>Changes:</strong></p>\n<ul>\n<li>New: <code>PasteDetectionService</code> (93 lines, 24 tests); APIs; utils; radio buttons for row placement (nested/sibling, smart default by column count).</li>\n<li>Updated: <code>markdown-editor.component.ts</code> (paste flows, toolbar); <code>dynamic-content-site-edit-text-row.ts</code> (nested insertion); <code>migrate-static-site.ts</code> (Puppeteer); <code>fragment-index</code> (recursive traversal).</li>\n<li>Removed: Duplicate Puppeteer code; CSS artifacts in preprocessing.</li>\n</ul>\n<p><strong>Testing:</strong></p>\n<ul>\n<li>24 unit tests (<code>paste-detection.service.spec.ts</code>, <code>turndown-service-factory.spec.ts</code>) pass (wrappers, tags, images, entities, anchors, CSS stripping).</li>\n<li>Server e2e/integration tests for previews/fetch; frontend builds succeed.</li>\n<li>Manual: Multi-column nested pastes, URL fetch, duplicate columns, fragment redirects.</li>\n</ul>\n<p>Closes #67.</p>\n"}