VPR-59 [3/4] CMS migration: management SPA (frontend)#253
Conversation
Slice 3/3 of the restacked CMS migration (tip file states). The Vue 3 management UI: files, content blocks with QEditor and version diffs, left-nav editor, link collections, import and bulk-encrypt tools, the redesigned hub with the recent-activity rail, shared sortable-list / server-table / dialog components, mobile card mode, and the full frontend test suite. Completes the stack; the tree now matches the development branch tip exactly.
There was a problem hiding this comment.
Pull request overview
Completes the CMS migration by landing the Vue 3 + Quasar “management SPA” for CMS tools (files, content blocks, left-nav menus), alongside shared SPA infrastructure (router scroll/focus behavior), reusable list/table composables, shared UI components, and an expanded frontend test suite.
Changes:
- Added CMS management pages/components (hub, files audit, bulk encrypt, content history/diff, left-nav menu management) plus shared CMS composables/types and utilities.
- Introduced shared frontend building blocks:
createSpaRouter(hash + query-aware scroll),useRouteFocusrefinements,useReorder+SortableList, and server-paged table composables with URL-synced filters. - Updated global styles/tokens/utilities for surfaces, focus rings, and responsive list/table/card layouts; minor Effort audit filter layout adjustments.
Reviewed changes
Copilot reviewed 85 out of 85 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| VueApp/src/styles/colors.css | Adds surface/diff/focus tokens and bg utilities for secondary palette colors. |
| VueApp/src/styles/base.css | Adds global a11y/layout helpers (focus, list headers, dialog sizing, card-mode table styling). |
| VueApp/src/Students/router/index.ts | Switches router factory import to create-spa-router. |
| VueApp/src/shared/createSpaRouter.ts | Removes old router factory module (renamed/replaced). |
| VueApp/src/shared/create-spa-router.ts | New router factory with improved base-url normalization and scroll behavior (hash + query-aware). |
| VueApp/src/shared/tests/create-spa-router.test.ts | Tests router scroll behavior and route-focus behavior. |
| VueApp/src/layouts/ViperLayout.vue | Adds “Skip to section menu” skip link when left nav exists. |
| VueApp/src/layouts/LeftNav.vue | Improves left-nav a11y (skip target focusability, roles, landmark labeling). |
| VueApp/src/Effort/router/index.ts | Switches router factory import to create-spa-router. |
| VueApp/src/Effort/pages/AuditList.vue | Reworks search + clear-filters placement to match CMS audit UX. |
| VueApp/src/Effort/components/EffortLeftNav.vue | Makes left nav skip target focusable (tabindex=-1). |
| VueApp/src/CTS/router/index.ts | Switches router factory import to create-spa-router. |
| VueApp/src/config/colors.ts | Extends accessible text-color logic for the new arboretum background color. |
| VueApp/src/Computing/router/index.ts | Switches router factory import to create-spa-router. |
| VueApp/src/composables/ViperFetch.ts | Adds postForm/putForm helpers for multipart uploads; minor object shorthand cleanup. |
| VueApp/src/composables/use-route-focus.ts | Avoids focus-steal on same-path navigations (query-only/hash-only). |
| VueApp/src/composables/use-reorder.ts | New reorder composable (move math + “just moved” highlight state). |
| VueApp/src/composables/tests/use-reorder.test.ts | Unit tests for useReorder. |
| VueApp/src/components/SortableList.vue | New shared sortable list component (drag + buttons + a11y announcements + animations). |
| VueApp/src/components/BreadcrumbHeading.vue | New breadcrumb-style <h1> component for subpages. |
| VueApp/src/components/tests/sortable-list.test.ts | Unit tests for SortableList. |
| VueApp/src/CMS/types/index.ts | Expands CMS TypeScript types for files, blocks, nav, audit/history, and activity rail. |
| VueApp/src/CMS/router/routes.ts | Defines CMS SPA routes and shared home-permission set. |
| VueApp/src/CMS/router/index.ts | Uses new router factory and adds CMS area-root canonicalization to Home. |
| VueApp/src/CMS/pages/LeftNavMenus.vue | New CMS page: list/manage left-nav menus (filters + add dialog + delete). |
| VueApp/src/CMS/pages/FileAuditLog.vue | New CMS page: server-paged file audit trail with URL-synced filters. |
| VueApp/src/CMS/pages/ContentBlockHistory.vue | New CMS page: cross-block edit history with diff viewer. |
| VueApp/src/CMS/pages/CmsHome.vue | Redesigns CMS hub with permission-scoped cards and purge-soon warning. |
| VueApp/src/CMS/pages/BulkEncrypt.vue | New CMS tool page: server-paged list for bulk encryption. |
| VueApp/src/CMS/file-types.ts | Centralizes accepted file extension allow-list for uploads. |
| VueApp/src/CMS/composables/use-url-filtered-table.ts | New composable: URL-synced filters layered over server paging. |
| VueApp/src/CMS/composables/use-server-table.ts | New composable: server-paged QTable core with stale-response guard. |
| VueApp/src/CMS/composables/use-content-diff-viewer.ts | New shared diff-viewer state/helpers for ContentDiffDialog consumers. |
| VueApp/src/CMS/components/StatusIcon.vue | New component: tooltip + sr-only label pattern for status icons. |
| VueApp/src/CMS/components/RecentActivity.vue | New component: CMS hub activity rail + latest-diff helpers. |
| VueApp/src/CMS/components/PersonSelector.vue | New component: server-searched people selector with stale-response guard. |
| VueApp/src/CMS/components/PermissionSelector.vue | New component: lazy-loaded permission selector with client-side filtering. |
| VueApp/src/CMS/components/PermissionChips.vue | New component: compact permission/person-count chip rendering. |
| VueApp/src/CMS/components/ModifiedStamp.vue | New component: shared “MM/DD/YY by user” stamp for table + card modes. |
| VueApp/src/CMS/components/ListCardField.vue | New component: label/value rows for QTable card/grid mode. |
| VueApp/src/CMS/components/ListCard.vue | New component: shared QTable card/grid wrapper for CMS list pages. |
| VueApp/src/CMS/components/LinkCollections.vue | Optimizes grouping/filtering behavior and adjusts filter UX. |
| VueApp/src/CMS/components/Link.vue | Uses StatusBadge for tags and updates tag palette to non-semantic brand roles. |
| VueApp/src/CMS/components/LeftNavMenuSettingsFields.vue | New shared settings form for left-nav menu create/edit. |
| VueApp/src/CMS/components/LeftNavMenuDialog.vue | New create-menu dialog with validation + unsaved-changes guard. |
| VueApp/src/CMS/components/EditButton.vue | New shared edit action button component for tables/cards. |
| VueApp/src/CMS/components/DeleteRestoreButtons.vue | New shared delete/restore action button component. |
| VueApp/src/CMS/components/DateRangeFilter.vue | New shared from/to date filter inputs. |
| VueApp/src/CMS/components/ContentDiffDialog.vue | New diff dialog for content history comparisons. |
| VueApp/src/CMS/components/ContentBlock.vue | Fixes content fetch behavior (avoid duplicate/deep watch) and handles fetch failure. |
| VueApp/src/CMS/components/ActivityRow.vue | New component: recent-activity row layout with safe whole-row click behavior. |
| VueApp/src/CMS/tests/use-url-filtered-table.test.ts | Tests URL-synced server table behavior and equality-guard. |
| VueApp/src/CMS/tests/use-server-table.test.ts | Tests server table behavior and stale-response guard. |
| VueApp/src/CMS/tests/url.test.ts | Tests CMS URL safety helpers (scheme allow/block, malformed handling). |
| VueApp/src/CMS/tests/test-utils.ts | CMS test harness utilities (Quasar/Pinia/router + seeded permissions). |
| VueApp/src/CMS/tests/router-canonicalization.test.ts | Tests CMS /CMS/ → Home canonicalization across permission shapes. |
| VueApp/src/CMS/tests/person-selector.test.ts | Tests PersonSelector min-chars gate and stale-response guard. |
| VueApp/src/CMS/tests/permission-selector.test.ts | Tests PermissionSelector lazy load + filtering + null-clear behavior. |
| VueApp/src/CMS/tests/modified-stamp.test.ts | Tests ModifiedStamp formatting and dual render modes. |
| VueApp/src/CMS/tests/link.test.ts | Tests Link URL safety rendering and tag color cycling behavior. |
| VueApp/src/CMS/tests/left-nav-menus.test.ts | Tests left-nav menu list behavior (filters, deep-link add dialog, delete flow). |
| VueApp/src/CMS/tests/left-nav-menu-dialog.test.ts | Tests create-menu dialog validation and POST success/failure behavior. |
| VueApp/src/CMS/tests/file-form-dialog-conflict.test.ts | Tests file upload name-conflict flows and multipart upload helpers usage. |
| VueApp/src/CMS/tests/date-range-filter.test.ts | Tests DateRangeFilter v-model and change emission. |
| VueApp/src/CMS/tests/content-diff-dialog.test.ts | Tests ContentDiffDialog close/legend/empty behaviors. |
| VueApp/src/CMS/tests/content-block-history.test.ts | Tests history list URL sync + diff viewer behaviors. |
| VueApp/src/CMS/tests/content-block-edit-diff.test.ts | Tests ContentBlockEdit diff-against-current behaviors. |
| VueApp/src/CMS/tests/cms-home.test.ts | Tests CMS hub permission-gated sections and purge warning behavior. |
| VueApp/src/ClinicalScheduler/router/index.ts | Switches router factory import to create-spa-router. |
| VueApp/src/CAHFS/router/index.ts | Switches router factory import to create-spa-router. |
Keyboard-initiated focus on #main-content / #leftNavMenu keeps a :focus-visible ring; programmatic and mouse focus stay quiet.
…p category A groupByTagCategory that matches no tag category on the collection left the grouped branch iterating an empty value set, rendering a blank page on a public-facing component instead of the links.
Dialog width classes used px, so they ignored the root font-size step at the 768px breakpoint and user font settings; DESIGN.md mandates rem sizing throughout.
Frontend half of the item-save concurrency guard: the items PUT now carries lastModifiedOn, a 409 opens the Edit Conflict dialog, and the stamp advances after a successful items save (it bumps the menu ModifiedOn server-side, so the next save 409ed against the user's own change).
The legacy-selector focus rule hard-coded #258cfb while newer rules use var(--focus-ring-color); one token keeps the rings from drifting.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 89 out of 89 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
VueApp/src/CMS/components/ListCard.vue:24
- This SFC has a top-level HTML comment after the block. Vue SFC parsers/tooling typically expect only /<script>/<style> (and named custom blocks) at the top level; leaving a stray comment outside those blocks can break compilation or linting in some setups. Move the comment inside the (or into a <script> block comment) to keep the file strictly valid.
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@VueApp/src/Effort/components/ChangeDetailDiff.vue`:
- Around line 7-19: The ChangeDetailDiff.vue template currently distinguishes
old and new values only with text-negative/text-positive color classes and an
arrow, which lacks non-color meaning. Update the detail rendering in the
ChangeDetailDiff component to add accessible text labels for the old and new
values, preferably visually hidden so the UI stays unchanged, and make sure the
labels are tied to the existing oldValue/newValue spans. Check whether
AuditList.vue already provides announced “Old” and “New” headers before adding
redundant labels.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 8c045652-6a9b-4e40-9b5a-89dac02b1f31
📒 Files selected for processing (29)
VueApp/src/CMS/__tests__/file-form-dialog-conflict.test.tsVueApp/src/CMS/__tests__/inline-file-upload.test.tsVueApp/src/CMS/__tests__/left-nav-edit.test.tsVueApp/src/CMS/__tests__/link-collections.test.tsVueApp/src/CMS/__tests__/test-utils.tsVueApp/src/CMS/components/ActivityRow.vueVueApp/src/CMS/components/ContentBlock.vueVueApp/src/CMS/components/FileFormDialog.vueVueApp/src/CMS/components/InlineFileUpload.vueVueApp/src/CMS/components/LeftNavMenuDialog.vueVueApp/src/CMS/components/LeftNavMenuSettingsFields.vueVueApp/src/CMS/components/LinkCollections.vueVueApp/src/CMS/components/PersonSelector.vueVueApp/src/CMS/pages/ContentBlockEdit.vueVueApp/src/CMS/pages/FileAuditLog.vueVueApp/src/CMS/pages/Files.vueVueApp/src/CMS/pages/LeftNavEdit.vueVueApp/src/CMS/pages/ManageLinkCollections.vueVueApp/src/CMS/types/index.tsVueApp/src/Effort/components/ChangeDetailDiff.vueVueApp/src/Effort/pages/AuditList.vueVueApp/src/components/SortableList.vueVueApp/src/components/__tests__/sortable-list.test.tsVueApp/src/composables/ViperFetch.tsVueApp/src/composables/__tests__/use-audit-colors.test.tsVueApp/src/composables/use-audit-colors.tsVueApp/src/shared/__tests__/create-spa-router.test.tsVueApp/src/shared/create-spa-router.tsVueApp/src/styles/base.css
feature/clinical-scheduler-audit-log merges to main first and reworked the same regions of AuditList (filter card, search row, change-detail markup). Adopt its version wholesale - including AuditChangeDetail, byte-identical, extended to the desktop layout - and re-apply only the shared audit palette, so the later main merge resolves cleanly. ChangeDetailDiff is superseded and removed.
Slice 3 of 4 (stacks on #252; the diff shows only this slice). Built from the CI-verified branch tip — see #251 for why the earlier 6-PR stack (#245-#250) was replaced. Merging this completes the CMS migration as originally scoped; slice 4 (#255) adds delegated block editing on top.
Scope — the CMS management SPA (Vue 3 + Quasar)
/CMS/ManageFiles: server-paged list with shareable URL-synced filters, upload/edit dialog with name-conflict and 409 edit-conflict handling, audit trail, import and bulk-encrypt tools.SortableList+ live-region announcements) and independent settings/items save; link collections management.use-server-tablewith stale-response guard,use-url-filtered-table,use-reorder, route-focus a11y), mobile card mode for the five dense list tables, WCAG-focused polish, and the full frontend test suite (1,026 tests).Deploy notes (whole stack)
CMS:LegacyWebrootPath(import tool),viperfiles.txtkey file must exist, optionalCMS:FileStorageRoot/CMS:ProfilePhotoPath/CMS:EncryptionKeyFileoverrides,CMS:DownloadRateLimitlimits,Cms:TrashPurgeEnabledstays false until the legacy VIPER 1 purge is retired.Development→ TEST first, per repo convention.