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