Commit Graph

6 Commits

Author SHA1 Message Date
riyadhafraa f53f7307da Task #489: row-wide drag rotates meeting content; time + daily numbers anchored
Backend
- New POST /api/executive-meetings/rotate-content (zod-validated) rotates
  ONLY meeting content through fixed (start_time, end_time, daily_number)
  slots. Same-date enforced; per-meeting expectedUpdatedAt → 409 stale;
  incomplete day (missing visible row) → 400.
- ExecutiveMeetingsRotateContentBody added in lib/api-zod (manual.ts).
- 6 backend tests cover happy path, stale, different_dates, 401, 403,
  incomplete_day. Existing /swap-times tests still pass.

Frontend (artifacts/tx-os)
- Whole <tr> is now the drag handle (the dedicated GripVertical button is
  retired). useSortable is gated on canMutate; safeRowDragListeners
  filters drags whose target is an interactive descendant (button, input,
  edit/time cells, row-actions, bulk-select). useSortable `attributes`
  are spread only when canMutate so view-mode rows stay clickable
  (otherwise aria-disabled blocked the popover trigger).
- onRowDragEnd → rotateContent(fromId, toId): optimistic patch reassigns
  each chronological slot's tuple to the new occupant; rolls back + toast
  on failure.
- Quick-actions popover now contains only Postpone (#486 Move up/down
  buttons removed).

Tests (artifacts/tx-os)
- New tests/executive-meetings-row-drag.spec.mjs: drags Alpha → Charlie
  position by # cell, asserts rotate-content fires and slots stay
  anchored.
- tests/executive-meetings-row-quick-actions.spec.mjs: drops up/down
  cases, keeps Postpone + skip-surfaces + viewer.
- tests/executive-meetings-schedule-features.spec.mjs: two legacy grip
  drag tests rewritten to drag the row body and target /rotate-content
  (the legacy /reorder route + tests are intentionally untouched).

Drift / notes
- Architect flagged a medium-severity hardening note: rotate-content
  FOR UPDATE locks orderedIds but not the day-scope completeness query.
  Out of #489 scope; no follow-up created (proposeFollowUpTasks was
  already consumed on #486).
2026-05-11 12:14:08 +00:00
riyadhafraa f0888b6b82 Task #188: Add browser test for reorder rollback when the API rejects a row drag
Added a Playwright e2e scenario in
`artifacts/tx-os/tests/executive-meetings-schedule-features.spec.mjs`
that exercises the optimistic-update + onError rollback path in
`reorderRows()` (artifacts/tx-os/src/pages/executive-meetings.tsx ~L1484).

What the test does:
- Seeds two meetings (A, B) on a unique future date via direct DB inserts.
- Logs in as admin, navigates to /executive-meetings, jumps to that date,
  enables edit mode.
- Captures the original DOM order [A, B].
- Installs a `page.route("**/api/executive-meetings/reorder")` override
  that responds with 500 + `{ error: "Simulated reorder failure" }`. The
  `error` field (not `message`) is intentional so apiJson() throws that
  exact string into the destructive toast description.
- Drags row B above row A using the same mechanic as the success-path
  reorder test (warm-up move past dnd-kit's 6px PointerSensor activation
  distance, then a stepped move targeting just above the row's vertical
  center).
- Waits for the intercepted 500, then asserts the toast description
  ("Simulated reorder failure") and a localized title (en or ar) is
  visible — proving the user-facing error surfaced.
- Polls the DOM to confirm the row order rolled back to [A, B].
- Defense-in-depth: queries the DB to confirm daily_number / start_time /
  end_time for both rows are unchanged, so a future regression that
  somehow bypasses the route override can't hide.
- Cleans up: page.unroute, and the existing afterAll deletes the seeded
  rows.

Test seeding:
- Uses uniqueFutureDate(6); offsets 1..5 are already claimed by other
  tests in this file, and the file-level afterAll cleanup means two
  tests sharing date + daily_number would collide on the
  UNIQUE (meeting_date, daily_number) index.

Verified by running:
  npx playwright test --grep "rolls back to the original order"
and the prior success-path drag test together — both pass.

No production code changes; this is a pure test addition.

Replit-Task-Id: 02cfe898-1db8-40e9-ba6b-cd5df9f0a3f4
2026-05-01 12:53:59 +00:00
riyadhafraa a29f7a25c6 Add browser test for drag-to-reorder schedule columns (task #187)
Adds a Playwright scenario to
artifacts/tx-os/tests/executive-meetings-schedule-features.spec.mjs that:
- Logs in as admin, seeds one meeting on a far-future date, and lands
  on the schedule for that date.
- Hops to the Settings tab to confirm the column customizer panel
  (em-customize-columns-panel) still surfaces the feature, then
  bounces back to the schedule.
- Enters edit mode (required for SortableHeader to register dnd-kit
  attributes/listeners) and asserts the default header order
  (number, meeting, attendees, time) via th[data-testid^=em-col-header-].
- Drags the "attendees" header above the "meeting" header using a
  warm-up move past the 6px PointerSensor activation distance and a
  stepped pointer move whose end point lands slightly LEFT of the
  target's horizontal center (horizontalListSortingStrategy needs the
  drop point on the leading side to insert before the target).
- Polls the rendered headers for the new order
  (number, attendees, meeting, time), then reads
  em-schedule-cols-v1 from localStorage to confirm persistence.
- Reloads the page and re-asserts the new order to prove it restores
  from localStorage rather than reverting to DEFAULT_COLUMNS.

Deviation from the task wording: the task description says the test
should "open the customize-columns popover" and "drag one column chip
above another". The customize panel is no longer a popover — it was
moved into the Settings tab in #265 — and it never had draggable
chips; column reordering is wired to the SortableHeader cells inside
the schedule's floating thead. The new test honors the spirit of the
task by visiting the Settings panel for sanity, then performing the
actual reorder gesture on the table headers (the only mechanism the
codebase exposes).

Validation: the new test passes in isolation and as part of the
schedule-features suite. One unrelated existing test
("custom highlight color paints the current meeting's box-shadow
ring") is currently flaky/failing on its own without my changes;
left untouched as it is outside this task's scope.

Replit-Task-Id: 06c14e68-096b-407d-86b9-bd5a45674aee
2026-05-01 11:18:40 +00:00
riyadhafraa d55c7ee8bb Add browser test for editing attendee names with formatting (Task #186)
Original task: cover the inline attendee-name edit flow in the
Executive Meetings schedule. The attendee row uses the same
EditableCell + Tiptap toolbar as titles (parent task #122), but until
now only the title path had end-to-end coverage. A regression in
attendee-name formatting would only have surfaced via manual QA.

Changes:
- Extended artifacts/tx-os/tests/executive-meetings-schedule-features.spec.mjs
  with a new scenario:
  * seeds a meeting + one plain-text attendee directly in the DB,
  * logs in as admin, navigates to the schedule, jumps to the seeded
    date, flips on edit mode,
  * clicks the inline attendee EditableCell, selects all, applies bold
    + the red color swatch via the toolbar, and saves via the check
    button while waiting for PUT /api/executive-meetings/:id/attendees
    to succeed,
  * reloads the page, re-navigates to the date, and asserts the
    rendered HTML in the cell still contains <strong>/<b> and the red
    color (#dc2626 or rgb(220,38,38)),
  * additionally queries executive_meeting_attendees.name in the DB to
    confirm the formatted HTML round-tripped through the server, not
    just survived in the local Tiptap document.
- Added a small insertAttendee helper in the same spec to seed initial
  state without driving the manage-dialog flow.
- The existing afterAll already deletes attendee rows for the created
  meetings (cascade-safe), so no cleanup changes were needed.

Verification: ran the new test in isolation (passed in 9.1s) and the
full schedule-features spec (5/5 passed in 40.1s). No code changes
outside the test file.

Follow-up filed: #270 — browser test for clearing an attendee's name
to trigger the delete-row gesture (separate documented behavior path
with no end-to-end coverage today).

Replit-Task-Id: 68a0ce72-6cdf-45e0-a7c7-4fea9c833fe7
2026-05-01 11:02:39 +00:00
riyadhafraa 310baa41ab #265: unify Executive Meetings header into single Settings tab
Header
- Removed the standalone Font Settings nav button and the bilingual
  language toggle. The header now exposes only Export PDF.
- Renamed the SECTIONS key `fontSettings` → `settings` (Settings icon
  retained) and updated visibility checks + render switch.

Settings tab
- New SettingsSection wraps the existing FontSettingsSection plus a
  new ColumnsCustomizerPanel (extracted from the old popover body) so
  column visibility / current-meeting highlight live with the rest of
  user prefs.
- Removed the old ColumnsCustomizer popover trigger from the schedule
  toolbar; the inline panel inside Settings is the single entry point.

State lifting
- columns/setColumns and highlightPrefs/setHighlightPrefs lifted from
  ScheduleSection up to ExecutiveMeetingsPage so both tabs read/write
  the same state. Storage keys (COLS_STORAGE_KEY, HIGHLIGHT_STORAGE_KEY)
  unchanged so existing user prefs continue to load.
- Per code-reviewer follow-up: moved the columns localStorage write
  effect up to the page as well so edits made in Settings persist even
  when ScheduleSection is unmounted.

Locales
- ar.json + en.json: renamed nav.fontSettings → nav.settings
  ("الإعدادات" / "Settings"); removed the now-unused
  executiveMeetings.fontSettings header label.
- Removed unused Languages and Type lucide imports.

Tests
- Updated executive-meetings-bulk-actions.spec.mjs and
  executive-meetings-schedule-features.spec.mjs to navigate via
  em-nav-settings instead of the removed em-customize-columns-trigger.
- All 226 sequential api tests pass; both updated playwright specs
  pass.
2026-05-01 08:52:33 +00:00
riyadhafraa 11f169f8c5 Add Playwright e2e tests for Executive Meetings schedule features
Task #129 — added 4 browser test scenarios in
artifacts/tx-os/tests/executive-meetings-schedule-features.spec.mjs:

1. Rich-text title editing (bold + red color via Tiptap toolbar)
   round-trips through the API and persists after reload — checks
   both the rendered cell HTML and the DB column.
2. Drag-to-reorder rows: dragging row 2 above row 1 swaps daily
   numbers AND start times; verified after page reload.
3. Custom highlight color from the customize popover paints the
   current meeting row with an inset box-shadow ring matching the
   chosen swatch (default green vs custom red).
4. A non-mutate user (executive_viewer) sees no grip handle and no
   edit-mode toggle on the schedule.

Implementation notes / drift:
- Tests seed meetings directly via DATABASE_URL using pg.Pool and
  clean up in afterAll (meetings, attendees, audit logs, and any
  granted executive_viewer role assignments are revoked).
- Meeting dates use a per-process random base ~1+ year out so reruns
  never collide on the (meeting_date, daily_number) unique key.
- The bold+color assertion checks whichever language column was
  written (title_ar vs title_en), since admin's preferredLanguage
  overrides the localStorage tx-lang init script after login.
- Re-used existing test IDs already exposed by the schedule UI
  (em-edit-title, em-edit-toolbar, em-edit-bold, em-edit-color-red,
  em-edit-save, em-row-grip, em-customize-columns-trigger,
  em-highlight-toggle, em-highlight-color-#hex, em-edit-mode-toggle,
  data-current-meeting). No production code changes.

All 4 tests pass against the live workflows (40s total).

Replit-Task-Id: 761dc96a-5bcb-47ef-bdb2-acfbebc68fc5
2026-04-30 05:31:34 +00:00