{"id":"69c1d780f6c2aac2b6953b00","title":"2026 03 23","path":"how-to/committee/release-notes/2026-03-23","contentMarkdown":"# 23-Mar-2026 — add committee documents row type, index-based navigation, and draggable swiper [ref #162](https://github.com/nbarrett/ngx-ramblers/issues/162)\n\n## [build 547](https://github.com/nbarrett/ngx-ramblers/actions/runs/23466309751) — [commit d793171](https://github.com/nbarrett/ngx-ramblers/commit/d7931711549df6174c5cc95c6414f46e01f28d96)\n\n_____\n\n## End-User Changes\n### Committee Documents as CMS Content\n- Committee file listings can now be placed on any CMS page as a row type\n- Each year's committee files (AGM minutes, financial returns, etc.) appear\non their own CMS-managed page at `committee/{year}`\n- The root `/committee` page auto-populates with the most recent year's files\n- Images are configurable per year page via the Image Actions editor\n(edit/replace/remove) — the same editor available on text rows\n- The Index automatically picks up each year page's image for its cards\n### Committee Years Navigation\n- Year navigation cards are now generated by an Index row instead of\nhand-maintained action buttons — new years appear automatically\n- The shared fragment `fragments/committee-years` holds the index\nconfiguration so all pages share the same navigation\n- Edit fragment button opens the fragment in a new tab to avoid losing\nsite edit context\n- Fragment inline preview hides markdown edit buttons to reduce clutter\n### Draggable Swiper for Action Buttons\n- Action button carousels can now be dragged/swiped on both desktop (mouse)\nand mobile (touch) to browse cards\n- Cards track the cursor/finger position in real-time during drag\n- Releasing the drag snaps to the nearest grid position with smooth animation\n- Multi-card drag: dragging across multiple card widths advances that many\npositions instead of just one\n- Native browser image drag is suppressed within the swiper\n- Click events are blocked during drag — only a clean tap/click navigates\n- Arrow buttons continue to work alongside drag\n### Fragment Margin Support\n- Margin Top/Bottom settings on shared fragment rows now apply correctly\nin the page view\n## Technical Changes\n### Migration (`20260319000000-convert-committee-page-to-cms`)\n- Fragment path changed from `committee-committee-years` to\n`fragments/committee-years` (required prefix for FragmentService)\n- Fragment content converted from action-button rows to an Index row\n(`ALBUM_INDEX`) with `STARTS_WITH` match on `committee/`, sorted DESC\n- Index configured with `maxColumns: 3`, `showSwiper: true`,\n`indexMarkdown: \"## Committee Years\"`, `autoTitle: false`\n- Hardcoded \"EKWG\" intro text replaced with dynamic lookup from\nsystem config `area.shortName`\n- `new Date()` replaced with `dateTimeFromMillis()` from `dates.ts`\n- Each year page's `committeeDocuments.imageSource` populated from the\nexisting fragment action-button column images\n### Image Discovery for Index\n- `findFirstImageInPage()` in both `IndexService` and\n`LocationExtractionService` now checks `row.committeeDocuments?.imageSource`\nbefore scanning columns — enables Index cards to display committee doc images\n### Committee Documents Site Edit\n- Image Actions dropdown (edit/replace/remove) with image cropper added\nto committee documents row editing\n- Image controls hidden when \"Auto Populate\" is checked (image comes\nfrom child page)\n### Auto-Populate Improvements\n- Replaced fragile `siteLinks`-based child page lookup with direct\n`$regex` database query for reliability\n- Page title derived from child page path instead of URL fragments\n### View Component Changes\n- `hideEditToggle` input threaded through `DynamicContentView` →\n`DynamicContentViewTextRow` → `MarkdownEditorComponent` to suppress\ninline edit buttons in fragment previews\n- `contentDescription` fallback to fragment path prevents\n\"Edit content for undefined\" tooltip\n### Swiper Implementation (action-buttons.ts)\n- Continuous flex strip with `overflow: hidden` viewport replaces\nslice-based `viewableColumns()` for swiper mode\n- `gap: 24px` on flex container with `calc()`-based flex-basis matches\nBootstrap grid spacing\n- Pixel-based `translateX` for both slide position and drag offset\n- Capture-phase click listener blocks navigation during drag\n- `pointer-events: none` and `-webkit-user-drag: none` on images\nprevents native drag interference\n### Route changes\n- Removed hardcoded `/committee` route — committee pages now served\nas CMS dynamic content via `hasDynamicPath` matcher\n- Added `hasSendNotificationPath` URL matcher for `<area>/send-notification/<id>`\n- Added `PathSegment` and `RouteParam` enums replacing hardcoded strings\n- Consolidated `CommitteeEditFileModal` into single-file component\n### Removed\n- `CommitteeHomeComponent`, `CommitteeYearComponent` and templates\n- `CommitteeDocumentsYearFilter` enum, `BuiltInAnchor.COMMITTEE_YEARS`,\n`BuiltInPath.COMMITTEE`, `PageContentPath.COMMITTEE_ACTION_BUTTONS_YEARS`\n- `CommitteeRoutingModule`\n### Bug fixes\n- Fixed `.reverse()` mutation bug in `RouterHistoryService`\n### Backup/restore resilience\n- Added timeout and retry logic for mongorestore operations","contentHtml":"<h1>23-Mar-2026 — add committee documents row type, index-based navigation, and draggable swiper <a href=\"https://github.com/nbarrett/ngx-ramblers/issues/162\">ref #162</a></h1>\n<h2><a href=\"https://github.com/nbarrett/ngx-ramblers/actions/runs/23466309751\">build 547</a> — <a href=\"https://github.com/nbarrett/ngx-ramblers/commit/d7931711549df6174c5cc95c6414f46e01f28d96\">commit d793171</a></h2>\n<hr>\n<h2>End-User Changes</h2>\n<h3>Committee Documents as CMS Content</h3>\n<ul>\n<li>Committee file listings can now be placed on any CMS page as a row type</li>\n<li>Each year&#39;s committee files (AGM minutes, financial returns, etc.) appear\non their own CMS-managed page at <code>committee/{year}</code></li>\n<li>The root <code>/committee</code> page auto-populates with the most recent year&#39;s files</li>\n<li>Images are configurable per year page via the Image Actions editor\n(edit/replace/remove) — the same editor available on text rows</li>\n<li>The Index automatically picks up each year page&#39;s image for its cards</li>\n</ul>\n<h3>Committee Years Navigation</h3>\n<ul>\n<li>Year navigation cards are now generated by an Index row instead of\nhand-maintained action buttons — new years appear automatically</li>\n<li>The shared fragment <code>fragments/committee-years</code> holds the index\nconfiguration so all pages share the same navigation</li>\n<li>Edit fragment button opens the fragment in a new tab to avoid losing\nsite edit context</li>\n<li>Fragment inline preview hides markdown edit buttons to reduce clutter</li>\n</ul>\n<h3>Draggable Swiper for Action Buttons</h3>\n<ul>\n<li>Action button carousels can now be dragged/swiped on both desktop (mouse)\nand mobile (touch) to browse cards</li>\n<li>Cards track the cursor/finger position in real-time during drag</li>\n<li>Releasing the drag snaps to the nearest grid position with smooth animation</li>\n<li>Multi-card drag: dragging across multiple card widths advances that many\npositions instead of just one</li>\n<li>Native browser image drag is suppressed within the swiper</li>\n<li>Click events are blocked during drag — only a clean tap/click navigates</li>\n<li>Arrow buttons continue to work alongside drag</li>\n</ul>\n<h3>Fragment Margin Support</h3>\n<ul>\n<li>Margin Top/Bottom settings on shared fragment rows now apply correctly\nin the page view</li>\n</ul>\n<h2>Technical Changes</h2>\n<h3>Migration (<code>20260319000000-convert-committee-page-to-cms</code>)</h3>\n<ul>\n<li>Fragment path changed from <code>committee-committee-years</code> to\n<code>fragments/committee-years</code> (required prefix for FragmentService)</li>\n<li>Fragment content converted from action-button rows to an Index row\n(<code>ALBUM_INDEX</code>) with <code>STARTS_WITH</code> match on <code>committee/</code>, sorted DESC</li>\n<li>Index configured with <code>maxColumns: 3</code>, <code>showSwiper: true</code>,\n<code>indexMarkdown: &quot;## Committee Years&quot;</code>, <code>autoTitle: false</code></li>\n<li>Hardcoded &quot;EKWG&quot; intro text replaced with dynamic lookup from\nsystem config <code>area.shortName</code></li>\n<li><code>new Date()</code> replaced with <code>dateTimeFromMillis()</code> from <code>dates.ts</code></li>\n<li>Each year page&#39;s <code>committeeDocuments.imageSource</code> populated from the\nexisting fragment action-button column images</li>\n</ul>\n<h3>Image Discovery for Index</h3>\n<ul>\n<li><code>findFirstImageInPage()</code> in both <code>IndexService</code> and\n<code>LocationExtractionService</code> now checks <code>row.committeeDocuments?.imageSource</code>\nbefore scanning columns — enables Index cards to display committee doc images</li>\n</ul>\n<h3>Committee Documents Site Edit</h3>\n<ul>\n<li>Image Actions dropdown (edit/replace/remove) with image cropper added\nto committee documents row editing</li>\n<li>Image controls hidden when &quot;Auto Populate&quot; is checked (image comes\nfrom child page)</li>\n</ul>\n<h3>Auto-Populate Improvements</h3>\n<ul>\n<li>Replaced fragile <code>siteLinks</code>-based child page lookup with direct\n<code>$regex</code> database query for reliability</li>\n<li>Page title derived from child page path instead of URL fragments</li>\n</ul>\n<h3>View Component Changes</h3>\n<ul>\n<li><code>hideEditToggle</code> input threaded through <code>DynamicContentView</code> →\n<code>DynamicContentViewTextRow</code> → <code>MarkdownEditorComponent</code> to suppress\ninline edit buttons in fragment previews</li>\n<li><code>contentDescription</code> fallback to fragment path prevents\n&quot;Edit content for undefined&quot; tooltip</li>\n</ul>\n<h3>Swiper Implementation (action-buttons.ts)</h3>\n<ul>\n<li>Continuous flex strip with <code>overflow: hidden</code> viewport replaces\nslice-based <code>viewableColumns()</code> for swiper mode</li>\n<li><code>gap: 24px</code> on flex container with <code>calc()</code>-based flex-basis matches\nBootstrap grid spacing</li>\n<li>Pixel-based <code>translateX</code> for both slide position and drag offset</li>\n<li>Capture-phase click listener blocks navigation during drag</li>\n<li><code>pointer-events: none</code> and <code>-webkit-user-drag: none</code> on images\nprevents native drag interference</li>\n</ul>\n<h3>Route changes</h3>\n<ul>\n<li>Removed hardcoded <code>/committee</code> route — committee pages now served\nas CMS dynamic content via <code>hasDynamicPath</code> matcher</li>\n<li>Added <code>hasSendNotificationPath</code> URL matcher for <code>&lt;area&gt;/send-notification/&lt;id&gt;</code></li>\n<li>Added <code>PathSegment</code> and <code>RouteParam</code> enums replacing hardcoded strings</li>\n<li>Consolidated <code>CommitteeEditFileModal</code> into single-file component</li>\n</ul>\n<h3>Removed</h3>\n<ul>\n<li><code>CommitteeHomeComponent</code>, <code>CommitteeYearComponent</code> and templates</li>\n<li><code>CommitteeDocumentsYearFilter</code> enum, <code>BuiltInAnchor.COMMITTEE_YEARS</code>,\n<code>BuiltInPath.COMMITTEE</code>, <code>PageContentPath.COMMITTEE_ACTION_BUTTONS_YEARS</code></li>\n<li><code>CommitteeRoutingModule</code></li>\n</ul>\n<h3>Bug fixes</h3>\n<ul>\n<li>Fixed <code>.reverse()</code> mutation bug in <code>RouterHistoryService</code></li>\n</ul>\n<h3>Backup/restore resilience</h3>\n<ul>\n<li>Added timeout and retry logic for mongorestore operations</li>\n</ul>\n"}