27bd3cbf61ac5429cd1c91df5be051cadb501c6e
669 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8d0d749d19 |
Adjust table column alignment for better readability on smaller screens
Align specific table columns to the start to prevent layout issues with long text. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 3b6aa4c0-6f89-44f5-a192-3827f92b1a5e Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/vKbTeqB Replit-Helium-Checkpoint-Created: true |
||
|
|
08a6b7e0d9 |
Task #336: hide raw "none" platform token under meeting title (Manage tab)
User feedback: the small grey subtitle under each meeting title in
the Manage tab table read e.g. "4 · none" — the raw `platform`
enum value leaked an English token next to Arabic content for
every meeting that has no virtual platform.
- Drops the ` · {m.platform}` segment from the subtitle in
`ManageSection`'s row rendering inside
`artifacts/tx-os/src/pages/executive-meetings.tsx`. The
attendee count (filtered on `kind === "person"`) stays
exactly as before, with the same `text-xs text-gray-500`
styling so layout is unchanged.
- Adds a short comment explaining why so future readers don't
re-introduce the platform token here. The platform is still
shown elsewhere when meaningful (the "Virtual attendance —
{platformLabel}" group header in AttendeeFlow at L4304/L4402,
and the platform `<Select>` in the edit dialog) — those were
intentionally not touched.
- No change to data model, save/load logic, or testids.
`pnpm -C artifacts/tx-os exec tsc --noEmit` clean. Pre-existing
api-server / test workflow failures are unrelated to this UI
change.
|
||
|
|
020d58d97b |
Task #337: divider between Time and Actions columns (Manage tab)
User feedback: in the Manage tab table the action icons looked
glued to the time value because there was no visible boundary
between the Time column and the Actions column.
- Adds `border-s border-gray-200` to both the Actions header
cell (`<th>`) and the per-row Actions data cell (`<td>`) in
the Manage tab table inside `executive-meetings.tsx`.
- Uses the logical `border-s` (inline-start) so the divider
lands on the correct edge of the Actions column in both LTR
and RTL — visually it always sits between Time and Actions.
- Color matches the existing table border (`gray-200`) and the
border extends the full row height, in line with the
surrounding row separators.
- Loading / empty states use a `colSpan={5}` row so the divider
doesn't show there, which is the desired behavior (no
inconsistent half-divider over centered text).
- No change to other columns, no change to Schedule/Audit/
Notifications tables, and no change to colors/widths/testids.
`pnpm -C artifacts/tx-os exec tsc --noEmit` clean. Pre-existing
api-server / test workflow failures are unrelated to this UI
change.
|
||
|
|
7ae8701d98 |
Task #337: divider between Time and Actions columns (Manage tab)
User feedback: in the Manage tab table the action icons looked
glued to the time value because there was no visible boundary
between the Time column and the Actions column.
- Adds `border-s border-gray-200` to both the Actions header
cell (`<th>`) and the per-row Actions data cell (`<td>`) in
the Manage tab table inside `executive-meetings.tsx`.
- Uses the logical `border-s` (inline-start) so the divider
lands on the correct edge of the Actions column in both LTR
and RTL — visually it always sits between Time and Actions.
- Color matches the existing table border (`gray-200`) and the
border extends the full row height, in line with the
surrounding row separators.
- Loading / empty states use a `colSpan={5}` row so the divider
doesn't show there, which is the desired behavior (no
inconsistent half-divider over centered text).
- No change to other columns, no change to Schedule/Audit/
Notifications tables, and no change to colors/widths/testids.
`pnpm -C artifacts/tx-os exec tsc --noEmit` clean. Pre-existing
api-server / test workflow failures are unrelated to this UI
change.
|
||
|
|
bd38bc5ca4 |
Transitioned from Plan to Build mode
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: ccad63cc-87f7-4e83-9089-23ffbe308268 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/vKbTeqB Replit-Helium-Checkpoint-Created: true |
||
|
|
529f18a1a2 |
Task #334: sticky bulk-action toolbar on Manage tab
User feedback: "سو فريز هنا لأني نزلت تحت وما شفتها" — the Manage tab's bulk-action toolbar (added in #332) was not visible after scrolling down through the meetings list. - Adds a `headingRef` + `ResizeObserver` effect in `ManageSection` that publishes the live height of `em-manage-heading-bar` as a `--em-manage-heading-h` CSS var on the `[data-em-root]` element. Mirrors the Schedule tab's existing pattern at L2155 for `--em-heading-h`. Distinct var name avoids collision when switching tabs; cleared on unmount so the Schedule tab doesn't inherit a stale offset. - Updates `em-manage-bulk-toolbar` to `position: sticky` with `top: calc(var(--em-header-h) + var(--em-manage-heading-h))`, matching horizontal bleed (`-mx-3 sm:-mx-6 px-3 sm:px-6`) and `#f4f6fb` page-bg of the heading bar so the two visually stack as a single header unit. Drops the rounded card style, uses a bottom-border + drop-shadow for the seam. - Adds `print:hidden` for parity with the Schedule counterpart so the toolbar doesn't leak into PDF exports. `pnpm -C artifacts/tx-os exec tsc --noEmit` clean. Pre-existing api-server / test workflow failures are unrelated to this change. No behavior change to the Schedule tab. |
||
|
|
226b8e209c |
Task #334: sticky bulk-action toolbar on Manage tab
User feedback: "سو فريز هنا لأني نزلت تحت وما شفتها" — the Manage tab's bulk-action toolbar (added in #332) was not visible after scrolling down through the meetings list. - Adds a `headingRef` + `ResizeObserver` effect in `ManageSection` that publishes the live height of `em-manage-heading-bar` as a `--em-manage-heading-h` CSS var on the `[data-em-root]` element. Mirrors the Schedule tab's existing pattern at L2155 for `--em-heading-h`. Distinct var name avoids collision when switching tabs; cleared on unmount so the Schedule tab doesn't inherit a stale offset. - Updates `em-manage-bulk-toolbar` to `position: sticky` with `top: calc(var(--em-header-h) + var(--em-manage-heading-h))`, matching horizontal bleed (`-mx-3 sm:-mx-6 px-3 sm:px-6`) and `#f4f6fb` page-bg of the heading bar so the two visually stack as a single header unit. Drops the rounded card style, uses a bottom-border + drop-shadow for the seam. - Adds `print:hidden` for parity with the Schedule counterpart so the toolbar doesn't leak into PDF exports. `pnpm -C artifacts/tx-os exec tsc --noEmit` clean. Pre-existing api-server / test workflow failures are unrelated to this change. No behavior change to the Schedule tab. |
||
|
|
f51eba68ed |
Transitioned from Plan to Build mode
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 737237cd-13b1-4c39-83f7-0411eb3069af Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/vKbTeqB Replit-Helium-Checkpoint-Created: true |
||
|
|
fe17bfcdd5 |
Task #332: port search + bulk delete/duplicate to Manage tab
Brings the Schedule tab's in-day search (#329) and bulk delete/duplicate-to-date (#330) into the Manage tab of executive-meetings.tsx (`ManageSection`). - Adds `searchQuery` state + search input in the manage heading bar; reuses module-level `normalizeForSearch` / `meetingMatchesSearch` helpers and the same "reset on date change" semantics as the Schedule tab. - Adds `selectedMeetingIds` Set + tri-state "select all visible" header checkbox + per-row checkbox column. Action handlers always intersect the selection set with the visible (filtered) rows, matching Schedule's safety pattern. - Adds bulk-delete (with confirm + aggregated toast via `Promise.allSettled`) and bulk-duplicate-to-date (separate Dialog mirroring the Schedule one). - Bumps loading/empty `colSpan` from 4 → 5 for the new checkbox column. - Reuses existing `executiveMeetings.schedule.*` locale keys (already present in both ar.json + en.json from #329/#330); no new strings were needed. - New testids: `em-manage-search`, `em-manage-search-clear`, `em-manage-select-all`, `em-manage-row-select-{id}`, `em-manage-bulk-toolbar`, `em-manage-bulk-selection-count`, `em-manage-bulk-clear-selection`, `em-manage-bulk-duplicate`, `em-manage-bulk-duplicate-{date,confirm}`, `em-manage-bulk-delete`. Out of scope per plan (deferred): undo for bulk-delete on Manage, cross-date "select all on this date". `pnpm -C artifacts/tx-os exec tsc --noEmit` clean. Architect review passed. Pre-existing api-server / test workflow failures are unrelated to this change. |
||
|
|
fee9030eb3 |
Transitioned from Plan to Build mode
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: dec39a9d-4287-4adb-bb6b-7a356fd5f20e Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/vKbTeqB Replit-Helium-Checkpoint-Created: true |
||
|
|
1923a9ca25 |
Update screenshot to show correct meeting management tab
Update attached screenshot to reflect the manage meetings tab. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 26502b01-f36d-4ce8-bb8f-64652a15c0ed Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/vKbTeqB Replit-Helium-Checkpoint-Created: true |
||
|
|
f479fa5498 |
Remove unnecessary confirmation message after acknowledging alerts
Remove the `doneToast` locale keys and the toast notification call in `upcoming-meeting-alert.tsx`. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 320c7da3-19c9-48af-ab28-f9af7aad21dd Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/vKbTeqB Replit-Helium-Checkpoint-Created: true |
||
|
|
104ae5526d |
Add functionality to duplicate multiple selected meetings to a future date
Adds a bulk duplicate option to the toolbar, including a dialog for selecting the target date, and implements the API calls and state management for this feature. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 13d92594-1814-45b7-83b2-862ed06fe2dc Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/vKbTeqB Replit-Helium-Checkpoint-Created: true |
||
|
|
7d5dd668bc |
Update toolbar to show only visible selected items
Memoizes and displays the count of currently visible selected meetings in the bulk action toolbar, ensuring actions align with displayed data. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 7f5687a2-4acd-4514-bad3-46babbeadb4a Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/vKbTeqB Replit-Helium-Checkpoint-Created: true |
||
|
|
317d597113 |
#329 Add a meeting search box to the schedule toolbar
Lets users find a meeting in the day's schedule by typing part of its
title, an attendee name, or other text — instead of scrolling.
artifacts/tx-os/src/pages/executive-meetings.tsx
- Added two top-level helpers near translateSaveError:
- normalizeForSearch(input): strips HTML tags + entities, drops
Arabic diacritics + tatweel, folds common letter variants
(آأإٱ→ا, ى→ي, ة→ه, ؤ→و, ئ→ي), lowercases.
- meetingMatchesSearch(meeting, needle): tests title (AR/EN),
attendee names + titles, location, notes, and merge text via
normalized substring containment.
- ScheduleSection: added searchQuery state, useEffect that resets it
whenever the active `date` changes, normalizedSearch memo, and a
filteredMeetings memo derived from orderedMeetings.
- Switched the row render path to filteredMeetings: SortableContext
items, the .map render, and the select-all overlay's "anything to
select" check now read from the filtered list. The
setAllMeetingsSelected and allSelectedState helpers also operate
on filteredMeetings so the header checkbox + select-all reflect
what's actually visible.
- Added a new "no matches" empty-state row that appears only when
the day has meetings but the active search filters them all out
(the original "no meetings today" row is preserved for empty days).
- New search Input + clear-X button placed in the schedule toolbar,
next to the existing date picker. Hidden in print so PDFs export
the full schedule.
- MeetingRow gained an optional `displayNumber` prop. The "#" cell
now renders displayNumber when provided, falling back to the
server's dailyNumber. The schedule passes idx+1, so visible rows
always show 1, 2, 3… without gaps when the list is filtered.
artifacts/tx-os/src/locales/ar.json + en.json
- New keys under executiveMeetings.schedule: searchPlaceholder,
searchAria, searchClear, searchNoMatches.
- Bulk delete now intersects the selection with filteredMeetings at
action time. The selection set is intentionally NOT auto-pruned
when the search narrows (so clearing the search restores the
user's earlier picks), but destructive actions only ever target
rows the user can currently see.
- Print/PDF export ignores the active search. An `isPrinting` flag
driven by beforeprint/afterprint + a `print` media-query listener
swaps the table to the unfiltered orderedMeetings while printing,
so generated PDFs always contain the full day's schedule even
when the user has typed into the search box.
Out of scope: cross-day search, prev/next-day chevron buttons,
search history, fuzzy matching.
Verified: `tsc --noEmit` clean.
|
||
|
|
0fda08169a |
#329 Add a meeting search box to the schedule toolbar
Lets users find a meeting in the day's schedule by typing part of its
title, an attendee name, or other text — instead of scrolling.
artifacts/tx-os/src/pages/executive-meetings.tsx
- Added two top-level helpers near translateSaveError:
- normalizeForSearch(input): strips HTML tags + entities, drops
Arabic diacritics + tatweel, folds common letter variants
(آأإٱ→ا, ى→ي, ة→ه, ؤ→و, ئ→ي), lowercases.
- meetingMatchesSearch(meeting, needle): tests title (AR/EN),
attendee names + titles, location, notes, and merge text via
normalized substring containment.
- ScheduleSection: added searchQuery state, useEffect that resets it
whenever the active `date` changes, normalizedSearch memo, and a
filteredMeetings memo derived from orderedMeetings.
- Switched the row render path to filteredMeetings: SortableContext
items, the .map render, and the select-all overlay's "anything to
select" check now read from the filtered list. The
setAllMeetingsSelected and allSelectedState helpers also operate
on filteredMeetings so the header checkbox + select-all reflect
what's actually visible.
- Added a new "no matches" empty-state row that appears only when
the day has meetings but the active search filters them all out
(the original "no meetings today" row is preserved for empty days).
- New search Input + clear-X button placed in the schedule toolbar,
next to the existing date picker. Hidden in print so PDFs export
the full schedule.
- MeetingRow gained an optional `displayNumber` prop. The "#" cell
now renders displayNumber when provided, falling back to the
server's dailyNumber. The schedule passes idx+1, so visible rows
always show 1, 2, 3… without gaps when the list is filtered.
artifacts/tx-os/src/locales/ar.json + en.json
- New keys under executiveMeetings.schedule: searchPlaceholder,
searchAria, searchClear, searchNoMatches.
- Bulk delete now intersects the selection with filteredMeetings at
action time. The selection set is intentionally NOT auto-pruned
when the search narrows (so clearing the search restores the
user's earlier picks), but destructive actions only ever target
rows the user can currently see.
Out of scope: cross-day search, prev/next-day chevron buttons,
search history, fuzzy matching.
Verified: `tsc --noEmit` clean.
|
||
|
|
c9ffb09e36 |
Transitioned from Plan to Build mode
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 9e3c014c-0bfd-4123-86ce-e5601a120326 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/2VzZgdn Replit-Helium-Checkpoint-Created: true |
||
|
|
41c0c30cb8 |
#326 Show meeting save errors in Arabic, centered at the bottom
Two small UX fixes for the Add/Edit Meeting save toast. artifacts/tx-os/src/pages/executive-meetings.tsx - Added a `translateSaveError(rawMsg, t)` helper near the other top-level helpers (~line 425). It substring-matches the API's Zod-generated message "startTime must be <= endTime" and returns the translated copy from `executiveMeetings.manage.errors.endTimeBeforeStart`. Anything unknown falls through to the raw server message so unexpected errors aren't silently hidden. - The save catch block now passes the message through this helper before showing the toast. Title still uses `errors.saveFailed`. artifacts/tx-os/src/locales/ar.json + en.json - New translation key `executiveMeetings.manage.errors.endTimeBeforeStart`: - ar: "وقت الانتهاء يجب أن يكون بعد وقت البدء" - en: "End time must be after start time" artifacts/tx-os/src/components/ui/toast.tsx - ToastViewport: replaced the mobile-top + desktop-bottom-right positioning with a single bottom-center placement on every viewport (`fixed bottom-0 left-1/2 -translate-x-1/2`). Width is still capped at `md:max-w-[420px]`. The flex direction is `flex-col` (no longer `flex-col-reverse`) since there is now only one slide-in direction. - toastVariants: dropped `data-[state=open]:slide-in-from-top-full` so toasts slide in from the bottom on every breakpoint, matching the new viewport position. Out of scope (untouched): API validation, other dialogs/pages, preventive client-side validation for invalid time ranges. |
||
|
|
7401a3ff3d |
Transitioned from Plan to Build mode
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 39716e9a-da04-4304-ba41-5d8ef54f6c79 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/2VzZgdn Replit-Helium-Checkpoint-Created: true |
||
|
|
d2dda556d6 |
#324 Make the Add/Edit Meeting dialog fit on a phone screen
After #322 trimmed the dialog, the Save/Cancel footer slid below the visible 90vh sheet on phones because the whole DialogContent was a single overflow-y-auto block. Changes in artifacts/tx-os/src/pages/executive-meetings.tsx: MeetingFormDialog - Rebuilt DialogContent as a flex column: shrink-0 header, flex-1 min-h-0 overflow-y-auto middle (the only scroller), shrink-0 footer. Save/Cancel now stay pinned at the bottom even after many attendees are added. - Reduced mobile padding/gaps (`p-4 sm:p-6`, `gap-3 sm:gap-4`, grid `gap-2 sm:gap-3`). Desktop spacing unchanged. - Switched the field grid from `grid-cols-1 sm:grid-cols-2` to a flat `grid-cols-2` so the two short fields (التاريخ, الرقم اليومي) share a row even on mobile. Title spans both columns; time pickers span both on mobile and one each on sm+ via the new mobileFull variant. - Inner scroll wrapper uses negative margins + matching padding so scroll content can extend edge-to-edge without losing the dialog's gutter. FormRow helper - Broadened `full` from `sm:col-span-2` to `col-span-2` (works in both 1-col and 2-col grids; only callers using `full` are in this file). - Added `mobileFull` prop → `col-span-2 sm:col-span-1` for the time pickers, so AM/PM controls don't get squeezed on phones. Out of scope (untouched): validation, save logic, attendee model, removed-field defaults from #322, duplicate dialog, audit, schedule view, translations. |
||
|
|
cfd2a46d39 |
Transitioned from Plan to Build mode
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 5123ce28-d8a4-40de-88ed-223d3e32ae49 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/2VzZgdn Replit-Helium-Checkpoint-Created: true |
||
|
|
5cb1644300 |
Update meeting form layout and Arabic title label
Refactor executive meetings form layout in `executive-meetings.tsx` to use a responsive grid, ensuring the Arabic title spans full width and other fields stack appropriately on smaller screens. Update Arabic and English locale files (`ar.json`, `en.json`) to change the Arabic title field label from "العنوان (عربي)" to "العنوان". Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 57375b7d-57d9-4fe3-a745-00a2cad59df8 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/2VzZgdn Replit-Helium-Checkpoint-Created: true |
||
|
|
debee0d600 |
#322 Simplify Add/Edit Meeting dialog and attendee rows
Trim the إضافة اجتماع / تعديل اجتماع dialog and attendee rows in artifacts/tx-os/src/pages/executive-meetings.tsx down to the fields the user actually fills in. MeetingFormDialog - Removed FormRows: titleEn, location, meetingUrl, platform, status, isHighlighted, notes. - Kept titleAr, meetingDate, dailyNumber, startTime, endTime, and the attendees section. - Save validation now only requires titleAr. - titleEn is always mirrored from titleAr on save. The English input is gone, so there is no way to keep an independent English title; always syncing avoids leaving a stale server-side titleEn after the Arabic title is edited. The API still receives a non-empty titleEn so POST validation (min length 1) is satisfied. - MeetingFormState, emptyMeetingForm, and openEdit are unchanged so hidden fields (location, notes, platform, status, isHighlighted, meetingUrl) round-trip through the save body and existing data is preserved on edit. SortableAttendeeRow - Removed the parenthesized title Input and the internal/virtual/external Select. - Dropped the now-unused onChangeTitle / onChangeAttendanceType props from the component signature and the call site. - Existing attendees keep their stored title and attendanceType; new attendees added via addAttendee continue to default to title=null and attendanceType="internal" so the schedule's grouping keeps working. Cleanup - Removed the now-unused Textarea import (only the notes field used it). Switch is still imported because it is used elsewhere in the file. Code review found two issues that were fixed before completion: - Mirroring made deterministic (always sync) instead of blank-only fallback. - Orphaned Textarea import removed. No DB schema, API, schedule view, Manage list, audit, notifications, or translation changes. |
||
|
|
60533b9ceb |
#322 Simplify Add/Edit Meeting dialog and attendee rows
Trim the إضافة اجتماع / تعديل اجتماع dialog and attendee rows in artifacts/tx-os/src/pages/executive-meetings.tsx down to the fields the user actually fills in. MeetingFormDialog - Removed FormRows: titleEn, location, meetingUrl, platform, status, isHighlighted, notes. - Kept titleAr, meetingDate, dailyNumber, startTime, endTime, and the attendees section. - Save validation now only requires titleAr. - titleEn is always mirrored from titleAr on save. The English input is gone, so there is no way to keep an independent English title; always syncing avoids leaving a stale server-side titleEn after the Arabic title is edited. The API still receives a non-empty titleEn so POST validation (min length 1) is satisfied. - MeetingFormState, emptyMeetingForm, and openEdit are unchanged so hidden fields (location, notes, platform, status, isHighlighted, meetingUrl) round-trip through the save body and existing data is preserved on edit. SortableAttendeeRow - Removed the parenthesized title Input and the internal/virtual/external Select. - Dropped the now-unused onChangeTitle / onChangeAttendanceType props from the component signature and the call site. - Existing attendees keep their stored title and attendanceType; new attendees added via addAttendee continue to default to title=null and attendanceType="internal" so the schedule's grouping keeps working. Cleanup - Removed the now-unused Textarea import (only the notes field used it). Switch is still imported because it is used elsewhere in the file. Code review found two issues that were fixed before completion: - Mirroring made deterministic (always sync) instead of blank-only fallback. - Orphaned Textarea import removed. No DB schema, API, schedule view, Manage list, audit, notifications, or translation changes. |
||
|
|
fd7c3c6498 |
Transitioned from Plan to Build mode
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 9a1523d5-dc1f-4906-a63a-b530a5b52d4a Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/fHzEBLA Replit-Helium-Checkpoint-Created: true |
||
|
|
51ae2f5a07 |
Improve the manage meetings page with a sticky header and proper title formatting
Update executive-meetings.tsx to make the header sticky, render meeting titles as HTML, and remove the "Status" column. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: c5984587-5347-4b07-b8da-f95fa4bc07a5 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/fHzEBLA Replit-Helium-Checkpoint-Created: true |
||
|
|
ea89647264 |
Transitioned from Plan to Build mode
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: ec66417e-470f-4913-a3ff-c38d7c0fc4d5 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/fHzEBLA Replit-Helium-Checkpoint-Created: true |
||
|
|
53aee6e83d |
Center all executive meeting schedule column headers
Update alignment for all schedule column headers in executive meetings to be centered for both screen and print views. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 354f7894-5e86-42b0-b76f-98e89d72a578 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/fHzEBLA Replit-Helium-Checkpoint-Created: true |
||
|
|
83ee3be884 |
Transitioned from Plan to Build mode
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 966f071a-6816-4f85-a574-20c5c1ea98f7 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/Q5rwhix Replit-Helium-Checkpoint-Created: true |
||
|
|
4a9ca4bd4a |
tx-os #317: optimistic-cache saves for all inline editors
Extends the optimistic React Query cache pattern (proven in #316 for the schedule time cell) to every other inline editor on executive-meetings.tsx, fixing the "تأخير في الاستجابة وأحياناً ما يحفظ" regression where typed edits felt sluggish or appeared to silently drop. executive-meetings.tsx * New `applyMeetingPatch(meetingId, patch)` helper: snapshots the day's DayResponse, applies a per-meeting patch via setQueryData, and returns a rollback closure that re-sets the snapshot on PATCH failure. * `saveTitle`, `saveAttendeeName`, `saveMerge`, and `setRowColor` now write the optimistic value before awaiting the network call and rollback() in their catch branches. editable-cell.tsx (3-layer blur hardening) 1. saveEdit() failure now re-opens the editor with the user's typed draft preserved (mirrors #316 time-cell UX) so a server error never forces them to retype. The parent's optimistic cache rollback restores the read-only `value`; the editor itself still holds the draft, so flipping `editing` back on is enough. 2. Outside-pointerdown now flushes saveEdit synchronously (capture phase, before the click reaches its target) instead of waiting on the 100 ms blur timer. Closes the gap where a fast click into another cell triggered a row remount before blur fired. 3. Unmount cleanup flushes any pending blurTimerRef fire-and-forget, a final safety net for the case where a refetch tears down the row before any pointer event arrives. editable-cell.tsx (re-entrancy guard) * `savingRef` short-circuits a second `saveEdit` call so the pointerdown flush + the 100 ms blur timer + Enter/Tab handlers can't race and issue duplicate PATCH/PUT requests for one edit. tests/executive-meetings-keyboard-editing.spec.mjs (+5 tests) * Title repaint <300 ms with PATCH delayed 1500 ms. * Title PATCH 500 rolls back; editor re-opens with the typed draft intact; Escape cancels back to the original; DB unchanged. * Rapid click-switch from cell A to cell B commits BOTH PATCHes to the server (proves the synchronous outside-pointerdown flush). * Rapid Tab traversal from cell A to cell B commits BOTH edits EXACTLY ONCE each (proves the savingRef re-entrancy guard). * Attendee-name PUT delayed 1500 ms repaints in <300 ms (uses captured testid so the locator survives the rename). All 5 new + 3 #316 time-editor tests green. Out-of-scope pre-existing failures in the `test` workflow (notifications/postpone-race/row-color) left untouched per plan. |
||
|
|
44b54e1fa8 |
tx-os #317: optimistic-cache saves for all inline editors
Extends the optimistic React Query cache pattern (proven in #316 for the schedule time cell) to every other inline editor on executive-meetings.tsx, fixing the "تأخير في الاستجابة وأحياناً ما يحفظ" regression where typed edits felt sluggish or appeared to silently drop. executive-meetings.tsx * New `applyMeetingPatch(meetingId, patch)` helper: snapshots the day's DayResponse, applies a per-meeting patch via setQueryData, and returns a rollback closure that re-sets the snapshot on PATCH failure. * `saveTitle`, `saveAttendeeName`, `saveMerge`, and `setRowColor` now write the optimistic value before awaiting the network call and rollback() in their catch branches. editable-cell.tsx (3-layer blur hardening) 1. saveEdit() failure now re-opens the editor with the user's typed draft preserved (mirrors #316 time-cell UX) so a server error never forces them to retype. The parent's optimistic cache rollback restores the read-only `value`; the editor itself still holds the draft, so flipping `editing` back on is enough. 2. Outside-pointerdown now flushes saveEdit synchronously (capture phase, before the click reaches its target) instead of waiting on the 100 ms blur timer. Closes the gap where a fast click into another cell triggered a row remount before blur fired. 3. Unmount cleanup flushes any pending blurTimerRef fire-and-forget, a final safety net for the case where a refetch tears down the row before any pointer event arrives. tests/executive-meetings-keyboard-editing.spec.mjs (+4 tests) * Title repaint <300 ms with PATCH delayed 1500 ms. * Title PATCH 500 rolls back; editor re-opens with the typed draft intact; Escape cancels back to the original; DB unchanged. * Rapid click-switch from cell A to cell B commits BOTH PATCHes to the server (proves the synchronous outside-pointerdown flush). * Attendee-name PUT delayed 1500 ms repaints in <300 ms (uses captured testid so the locator survives the rename). All 4 new + 3 #316 time-editor tests green. Out-of-scope pre-existing failures in the `test` workflow (notifications/postpone-race/row-color) left untouched per plan. |
||
|
|
85105faf16 |
tx-os #317: optimistic-cache saves for all inline editors
Extends the optimistic React Query cache pattern (proven in #316 for the schedule time cell) to every other inline editor on executive-meetings.tsx, fixing the "تأخير في الاستجابة وأحياناً ما يحفظ" regression where typed edits felt sluggish or appeared to silently drop. executive-meetings.tsx * New `applyMeetingPatch(meetingId, patch)` helper: snapshots the day's DayResponse, applies a per-meeting patch via setQueryData, and returns a rollback closure that re-sets the snapshot on PATCH failure. * `saveTitle`, `saveAttendeeName`, `saveMerge`, and `setRowColor` now write the optimistic value before awaiting the network call and rollback() in their catch branches. Re-throw behaviour preserved where present so EditableCell still resets its draft on failure. editable-cell.tsx * Hardened blur-commit: the cell now stashes the latest `saveEdit` in a ref and an unmount cleanup flushes any pending blurTimerRef fire-and-forget. Without this, a row remount that lands during the 100 ms blur window (e.g. Tab into the next cell triggering an optimistic refetch) tore down the editor before saveEdit could run and silently dropped the typed change. Optimistic cache writes in the parent make the fire-and-forget safe. tests/executive-meetings-keyboard-editing.spec.mjs (+3 tests) * Title repaint <300 ms with PATCH delayed 1500 ms. * Title PATCH 500 rolls back to original; DB unchanged. * Attendee-name PUT delayed 1500 ms repaints in <300 ms (uses captured testid so the locator survives the rename). Architect review: APPROVED, no concerns. All 3 new + 3 #316 time-editor tests green. Out-of-scope pre-existing failures in the `test` workflow (notifications/postpone-race/row-color) untouched per plan. |
||
|
|
3461ef7fe6 |
Transitioned from Plan to Build mode
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: c2e9eeff-afca-4c3d-8238-2424de963226 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/Q5rwhix Replit-Helium-Checkpoint-Created: true |
||
|
|
f3154554ff |
Task #316: fix executive-meetings inline time editor snap-back + perceived save latency
Two bugs in the schedule time-cell editor:
1. SNAP-BACK: After saving, re-opening the editor briefly showed
blank inputs because the React Query refetch ran behind the
close-then-reopen sequence and the picker re-seeded from stale
meeting props.
2. PERCEIVED LATENCY: The editor stayed open until the PATCH
round-trip resolved, so a slow network made every save feel
slow even though the data round-trip was the only blocker.
Fixes (artifacts/tx-os/src/pages/executive-meetings.tsx):
- saveTimes: optimistically write the new times into the
["/api/executive-meetings", date] query cache (DayResponse shape:
{ date, meetings: [...] }) so the read-only display repaints
immediately. Snapshot previous payload and roll back on PATCH
failure. Append :00 so the cached shape matches the GET refetch.
- TimeRangeCell.save(): close the editor BEFORE awaiting the PATCH;
set savingRef while saving so the [editing, startSaved, endSaved]
sync effect doesn't overwrite the optimistic draft on the next
render. On failure, re-open with the user's draft intact.
- TimeRangeCell sync effect: bail when savingRef is true OR when
the saved refs match lastSyncedRef, preventing stale prop values
from clobbering the optimistic state mid-flight.
Tests added (artifacts/tx-os/tests/executive-meetings-keyboard-editing.spec.mjs):
- snap-back: save 21:30/22:45, immediately re-open, assert picker
shows the saved values (not blank).
- perceived-latency: hold PATCH 1.5s; assert editor closes within
800ms and the read-only display shows optimistic times.
- rollback: 500 the PATCH; assert editor re-opens with the user's
draft intact, read-only display shows the original times after
cancel, DB unchanged.
All 3 new tests pass; the existing time-editor tests continue to
pass (6/6 in the targeted regression sweep).
Plan: .local/tasks/task-316.md
|
||
|
|
c2ef6467c7 |
Transitioned from Plan to Build mode
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: cc8d6fd3-b9f3-4e9b-ae4e-2f361704c464 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/Q5rwhix Replit-Helium-Checkpoint-Created: true |
||
|
|
45f3d88ac5 |
EM time picker: mobile/iPad-friendly layout + touch targets
Follow-up to task #315. The 3-control picker shipped with desktop- sized inline controls (~22px tall) and a single-row layout that pushed the end picker out of view on a 375px iPhone, leaving the user with no obvious way to fill the second time field. What changed - src/components/time-picker-12h.tsx: bumped the "inline" size from h<22px text-[10px] to h-8 (32px) text-sm/text-xs across hour input, minute input, and AM/PM toggle so a finger tap on mobile/iPad lands cleanly. Added `gap-1.5` between the [hour:minute] group and the AM/PM toggle so a thumb-tap on the toggle doesn't accidentally land on the minute input. Added a visible focus ring color and lightened the placeholder so the empty fields read as "fill me in" rather than already-active. - src/pages/executive-meetings.tsx (TimeRangeCell wrapper): switched from `inline-flex` (single-row, ellipsis on overflow) to `flex flex-wrap items-end gap-x-1.5 gap-y-1`. The end picker now drops onto a second line when the cell can't fit both side-by-side, which is the iPhone case. The "–" separator is hidden on narrow widths (`hidden sm:inline`) since wrapping makes it visually wrong. - Bumped Start/End labels from 10px to 11px font-medium for better at-a-glance scanability of which time field is which — this was the user-reported clarity issue. - Save/cancel icon buttons grew to 32x32 hit areas (was tiny p-0.5 around a 14px icon ≈ 16px clickable). - tests/executive-meetings-keyboard-editing.spec.mjs: added a new test.describe block "Schedule mobile viewport (iPhone 375)" with `test.use({ viewport: { width: 375, height: 667 } })`. The test asserts: (a) all 8 picker sub-controls + save button are visible on iPhone, (b) each interactive control is at least 28px tall (regression guard against shrinking touch targets), (c) a complete tap-driven hour+minute+AM/PM entry on both start and end persists 21:30–22:45 to the DB. Validation - Unit tests: 22/22 pass (no logic changes — only CSS + layout). - E2E: Tab walks (desktop) + compact+PM toggle (desktop) + new iPhone-375 mobile test all pass. - TypeScript: clean. |
||
|
|
4cb8532bb6 |
Task #315: rebuild 12h picker as 3 controls (hour + minute + AM/PM)
The first ship of #315 used a single text input + AM/PM toggle. The spec (lines 30-32) explicitly mandates THREE controls per field: hour input (1-12), minute input (00-59), and AM/PM toggle. This follow-up commit refactors TimePicker12h to that shape while keeping every behaviour from the first ship intact. What changed - src/lib/time-12h.ts: - Added `splitCanonicalForPicker()` — seeds the 3-control picker's separate hour and minute inputs from a canonical "HH:mm" value. - Added `combineSplit(hour, minute, period)` — the new combine path. Joins "${h}:${m}" and runs the result through combineTextWithPeriod, preserving every disambiguation rule (1-12 requires toggle, 0/13-23 unambiguous, embedded marker overrides toggle). - The hour field accepts a power-user shortcut: any separator (":", ".", "-", " ") or AM/PM marker letter or 3-4 digit compact form in the hour field means "I typed the whole time here, ignore the minute field". Preserves the existing e2e tests that fill the entire time string into one input. - kept formatCanonicalAs12h + combineTextWithPeriod for the power-user shortcut path. - src/components/time-picker-12h.tsx: rewrote as 3 controls (hour input, ":" separator, minute input, AM/PM radiogroup). Imperative {commit, focus, select} handle still focuses the hour input. dirtyRef preserved to avoid prop overwrite mid-edit. periodRef still mirrors state for synchronous commit() reads. - src/pages/executive-meetings.tsx: added `minuteTestId` props on both inline editor pickers and both manage-form pickers (`em-time-{start,end}-minute-${id}`, `em-form-{start,end}Time-minute`). All other test IDs preserved. - src/__tests__/time-12h.test.mjs: kept the 14 tests for the text+period path; added 8 new tests for combineSplit covering split-mode (1-12 ambiguous, 13-23 unambiguous, midnight, hour power-user shortcut, bare-hour invalid, etc) — 22 tests pass. - tests/executive-meetings-keyboard-editing.spec.mjs: updated the Tab walks test to walk 8 stops (start hour → start minute → start AM → start PM → end hour → end minute → end AM → end PM) and assert both typed values survive the focus changes. The TYPING_SHAPES helper still works unchanged because the hour field accepts full time strings via the power-user shortcut. - public/opengraph.jpg: reverted to HEAD~1 (was inadvertently swept into the prior commit by the auto-commit; not part of this task). Validation - Unit tests: 22/22 pass. - E2E: Tab walks + canonical 24h + no-leading-zero + 12h-with-PM + compact+PM-toggle all pass against the new 3-control UI. - TypeScript: clean. |
||
|
|
e63a7f8193 |
Task #315: 12h time picker with explicit AM/PM (executive meetings)
Replaces native <input type="time"> in the executive-meetings editor with a TimePicker12h that always requires an explicit AM/PM choice for any 1–12 hour, fixing the "1:15 silently saved as 01:15 (AM) when user meant 13:15 (PM)" bug. Display stays compact 12h with no AM/PM marker (per #292); wire format remains canonical HH:mm 24h. What ships - src/lib/time-12h.ts: periodFromCanonical, formatCanonicalAs12h, combineTextWithPeriod (returns "ambiguous" for any unmarked 1–12 hour without a toggle pick; accepts hours 0 and 13–23 directly because they are unambiguous 24h shapes; typed marker always wins over toggle). - src/components/time-picker-12h.tsx: forwardRef component with imperative {commit, focus, select} handle, dirtyRef to avoid prop overwrite mid-edit, dir="ltr" for stable RTL layout, and Enter-on-toggle = "set AND save". - Wired into TimeRangeCell inline editor (commit-based save handles invalid/ambiguous/TimeOrderError as toasts and refocuses). - Wired into MeetingFormDialog with picker refs + handleSaveClick validation: Save button now calls commit() on both pickers, blocks on invalid/ambiguous (toast + focus offending picker), and passes canonical values straight to the parent's save handler so a stale React state batch from onChange-suppression cannot silently persist the previous value. Tests - 12 unit tests in src/__tests__/time-12h.test.mjs (incl. new "hour 0 is unambiguous, accepted without a toggle"). - 17 e2e tests in tests/executive-meetings-keyboard-editing.spec.mjs (incl. "compact + PM toggle" 0115→13:15 and "Tab walks start input → start AM/PM toggle → end input → end AM/PM toggle"). - Existing manage-create e2e suite still green. Locale keys (en + ar) - executiveMeetings.timeEditor.{am,pm,periodGroupStart,periodGroupEnd} - executiveMeetings.schedule.timeAmbiguousError Deviations from plan - Architect review #1 caught two issues that were both fixed: (1) combineTextWithPeriod treated hour 0 as ambiguous; now accepts 00:xx unambiguously. (2) MeetingFormDialog initially used pickers via value/onChange only, which left a silent-fallback hole because onChange suppresses ambiguous drafts. Added imperative refs + handleSaveClick validation; onSave signature changed to (committedStart, committedEnd) so the parent's save() can use the freshly-committed values directly. - Reverted accidental vite.config.ts typo (@replit/... was missing the leading @). |
||
|
|
79e03053aa |
Transitioned from Plan to Build mode
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 4467bc05-db1e-4d31-b5c0-92f5d9c3aa1c Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/GbTNwz8 Replit-Helium-Checkpoint-Created: true |
||
|
|
4c8d2fff6c |
Task #312: auto-sort executive-meetings schedule by start_time
User report (AR): "اريدها ترتيبها تلقائيا" — after a non-drag write
(typing 13:00 into a row sitting above a 12:00 row, creating a meeting
with an explicit start time, etc.) the schedule's daily_number stayed
frozen at the row's prior position, so the visible list was no longer
chronological. Fix: extend the existing `renumberDayByStartTime` helper
to every write path that touches start_time / meeting_date / status /
daily_number, so the day is always renumbered 1..N by start_time
(NULLS LAST, cancelled rows at the tail).
Server (artifacts/api-server/src/routes/executive-meetings.ts):
- POST /executive-meetings — renumber after insert.
- PATCH /executive-meetings/:id — renumber when an order- or
visibility-affecting field (startTime/endTime/meetingDate/status/
dailyNumber) is in the payload. Cross-day moves renumber BOTH the
source and destination day. Pre-allocates a fresh dailyNumber on
the destination via nextDailyNumber(tx, newDate) before the UPDATE
so the (meeting_date, daily_number) unique index does not collide
when the row arrives on a day with existing meetings.
- DELETE /executive-meetings/:id — renumber so the day's `#`
sequence stays gap-free.
- POST /executive-meetings/:id/duplicate — renumber the target day.
Existing postpone-minutes / reschedule / cancel paths already called
renumber and were left alone. Reorder POST is also untouched (its
slot-swap is the explicit user-driven order, not auto-sort).
Audit-log surfacing of the auto-sort side effect (per validation):
- `renumberDayByStartTime` now returns `{ date, orderShifted, before,
after }` where `before`/`after` are the visible (non-cancelled)
row IDs in `daily_number` order, captured by a cheap SELECT inside
the same transaction.
- PATCH was restructured so renumber runs BEFORE `logAudit`, then
the row's post-renumber `daily_number` is read back and the audit's
`newValue` is enriched with:
• `dailyNumber` overridden to the post-sort position (so the
audit shows where the row landed, not the pre-sort draft);
• `orderShifted: true` and a `dayOrder: [{ date, before, after }]`
array (one entry per affected day, including both source and
destination on cross-day moves) when the visible order actually
changed.
- When auto-sort runs but does not change the visible order (e.g. the
row was already in the correct slot), `orderShifted` / `dayOrder`
are omitted so the audit UI does not falsely flag a reorder.
Tests (artifacts/api-server/tests/executive-meetings.test.mjs, +11):
- assertDayChronological() helper asserts 1..N + non-decreasing
start_time + no duplicate dailyNumbers.
- PATCH startTime later → row demoted (the user's exact scenario).
- PATCH startTime earlier → row promoted to the top.
- POST create with middle startTime slots between existing rows.
- PATCH startTime=null sinks to the tail of visible rows.
- Cancel pushes out / uncancel re-slots chronologically.
- Cross-day PATCH meetingDate renumbers BOTH days.
- DELETE leaves no `#` gap.
- POST /duplicate slots clone at chronological position.
- PATCH that reorders the day records orderShifted + post-sort
dailyNumber + dayOrder before/after arrays in the audit row.
- Title-only PATCH leaves orderShifted/dayOrder absent from the audit.
All 57 tests in executive-meetings.test.mjs pass.
Architect review (advisory, scope-bounded):
- Concurrency: PATCH/DELETE read `existing` outside the transaction.
Pre-existing convention in this file — only the cascade-bearing
postpone-minutes/reschedule paths use SELECT FOR UPDATE. Matching
existing pattern; tightening locking is a separate refactor
captured as follow-up #313.
- Audit surfacing for POST/DELETE/duplicate: only PATCH was enriched
in this task per validation feedback ("especially PATCH time/date/
status/dailyNumber paths"). UI-side rendering of the new audit
fields and POST/DELETE/duplicate enrichment captured as
follow-up #314.
|
||
|
|
0a7acd683f |
Task #312: auto-sort executive-meetings schedule by start_time
User report (AR): "اريدها ترتيبها تلقائيا" — after a non-drag write
(typing 13:00 into a row sitting above a 12:00 row, creating a meeting
with an explicit start time, etc.) the schedule's daily_number stayed
frozen at the row's prior position, so the visible list was no longer
chronological. Fix: extend the existing `renumberDayByStartTime` helper
to every write path that touches start_time / meeting_date / status /
daily_number, so the day is always renumbered 1..N by start_time
(NULLS LAST, cancelled rows at the tail).
Server (artifacts/api-server/src/routes/executive-meetings.ts):
- POST /executive-meetings — renumber after insert.
- PATCH /executive-meetings/:id — renumber when an order- or
visibility-affecting field (startTime/endTime/meetingDate/status/
dailyNumber) is in the payload. Cross-day moves renumber BOTH the
source and destination day. Pre-allocates a fresh dailyNumber on
the destination via nextDailyNumber(tx, newDate) before the UPDATE
so the (meeting_date, daily_number) unique index does not collide
when the row arrives on a day with existing meetings.
- DELETE /executive-meetings/:id — renumber so the day's `#`
sequence stays gap-free.
- POST /executive-meetings/:id/duplicate — renumber the target day.
Existing postpone-minutes / reschedule / cancel paths already called
renumber and were left alone. Reorder POST is also untouched (its
slot-swap is the explicit user-driven order, not auto-sort).
Tests (artifacts/api-server/tests/executive-meetings.test.mjs, +9):
- assertDayChronological() helper asserts 1..N + non-decreasing
start_time + no duplicate dailyNumbers.
- PATCH startTime later → row demoted (the user's exact scenario).
- PATCH startTime earlier → row promoted to the top.
- POST create with middle startTime slots between existing rows.
- PATCH startTime=null sinks to the tail of visible rows.
- Cancel pushes out / uncancel re-slots chronologically.
- Cross-day PATCH meetingDate renumbers BOTH days.
- DELETE leaves no `#` gap.
- POST /duplicate slots clone at chronological position.
All 55 tests in executive-meetings.test.mjs pass.
Architect review (advisory, scope-bounded):
- Concurrency: PATCH/DELETE read `existing` outside the transaction.
Pre-existing convention in this file — only the cascade-bearing
postpone-minutes/reschedule paths use SELECT FOR UPDATE. Matching
existing pattern; tightening locking is a separate refactor.
- Audit: renumber side-effect not echoed back into the audit row.
Per task plan (`.local/tasks/auto-sort-schedule-by-time.md`),
audit shape was intentionally kept minimal — the user-intent
fields already capture the change.
|
||
|
|
f7b93aa4e7 |
Transitioned from Plan to Build mode
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: d8980aeb-a819-4c14-97a6-7384215c51d1 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/GbTNwz8 Replit-Helium-Checkpoint-Created: true |
||
|
|
b880dd3c37 |
fix(executive-meetings): keep visible drag-reorder chronological with cancelled rows
Task #311. The schedule view hides cancelled meetings, but the drag-reorder path was operating on the raw, unfiltered list — so cancelled rows consumed time slots and the dnd-kit indices skewed across hidden rows, leaving the visible list out of chronological order after a drop. Server (POST /api/executive-meetings/reorder) - Slot-swap now operates on the in-scope (orderedIds) subset only. Cancelled rows keep their (startTime, endTime, dailyNumber) untouched, so they no longer steal slots from the visible list. - New 400 codes: - cancelled_in_reorder: payload includes a cancelled meeting - incomplete_day: any non-cancelled meeting on the day is missing - Audit oldValue.order now reflects the visible order the user actually saw. - Phase-1/phase-2 negative-parking still avoids transient unique-constraint conflicts; cancelled rows' positive dailyNumbers cannot collide because slot dailyNumbers are a permutation of in-scope rows' existing values. Client (executive-meetings.tsx reorderRows) - Index math now derives ids from `orderedMeetings` (the visible list bound to SortableContext) instead of the raw `meetings` array. useCallback deps updated. Tests - artifacts/api-server/tests/executive-meetings.test.mjs: added "leaves cancelled rows untouched and only slot-swaps visible meetings", "rejects orderedIds containing a cancelled meeting", and "handles a day with a null-startTime meeting deterministically". - artifacts/tx-os/tests/executive-meetings-keyboard-editing.spec.mjs: added two real dnd-kit drag tests driven through the keyboard sensor (Space + ArrowUp + Space on the row's grip handle): - "Schedule drag-reorder: cancelled rows ... do not disturb the visible chronological order" — cancelled row keeps its slot, visible rows end up chronological after the drop. - "Schedule drag-reorder: a null-startTime row drags deterministically and inherits its new slot" — null-time row dragged to top inherits the first chronological slot; the originally-null slot shifts to the row that lands at the bottom. Code-review follow-ups addressed: - Reverted the unrelated artifacts/tx-os/public/opengraph.jpg binary change. - Added the explicit null-startTime regressions at both API and Playwright drag levels per review request. - Replaced the fetch-based UI test with real dnd-kit keyboard-sensor drags to fully exercise the client onDragEnd path including the patched index math. All 8 reorder API tests and both new Playwright drag tests pass. Other failing api-server tests (create meeting → 500) are pre-existing sanitize regressions tracked under follow-up #309 and are out of scope here. |
||
|
|
360b231693 |
fix(executive-meetings): keep visible drag-reorder chronological with cancelled rows
Task #311. The schedule view hides cancelled meetings, but the drag-reorder path was operating on the raw, unfiltered list — so cancelled rows consumed time slots and the dnd-kit indices skewed across hidden rows, leaving the visible list out of chronological order after a drop. Server (POST /api/executive-meetings/reorder) - Slot-swap now operates on the in-scope (orderedIds) subset only. Cancelled rows keep their (startTime, endTime, dailyNumber) untouched, so they no longer steal slots from the visible list. - New 400 codes: - cancelled_in_reorder: payload includes a cancelled meeting - incomplete_day: any non-cancelled meeting on the day is missing - Audit oldValue.order now reflects the visible order the user actually saw. - Phase-1/phase-2 negative-parking still avoids transient unique-constraint conflicts; cancelled rows' positive dailyNumbers cannot collide because slot dailyNumbers are a permutation of in-scope rows' existing values. Client (executive-meetings.tsx reorderRows) - Index math now derives ids from `orderedMeetings` (the visible list bound to SortableContext) instead of the raw `meetings` array. useCallback deps updated. Tests - artifacts/api-server/tests/executive-meetings.test.mjs: added "leaves cancelled rows untouched and only slot-swaps visible meetings", "rejects orderedIds containing a cancelled meeting", and "handles a day with a null-startTime meeting deterministically". - artifacts/tx-os/tests/executive-meetings-keyboard-editing.spec.mjs: added "Schedule drag-reorder: cancelled rows on the same day do not disturb the visible chronological order" — drives a real dnd-kit drag via the keyboard sensor (Space + ArrowUp x2 + Space on the row's grip handle), exercising the full client onDragEnd path including the patched index math. Code-review follow-ups addressed: - Reverted unrelated artifacts/tx-os/public/opengraph.jpg binary change. - Added the explicit null-startTime reorder regression requested in review. - Replaced the fetch-based UI test with a real dnd-kit keyboard-sensor drag, covering the client index-mapping path end-to-end. All 8 reorder API tests and the new Playwright drag test pass. Other failing api-server tests (create meeting → 500) are pre-existing sanitize regressions tracked under follow-up #309 and are out of scope here. |
||
|
|
22328e7252 |
fix(executive-meetings): keep visible drag-reorder chronological with cancelled rows
Task #311. The schedule view hides cancelled meetings, but the drag-reorder path was operating on the raw, unfiltered list — so cancelled rows consumed time slots and the dnd-kit indices skewed across hidden rows, leaving the visible list out of chronological order after a drop. Server (POST /api/executive-meetings/reorder) - Slot-swap now operates on the in-scope (orderedIds) subset only. Cancelled rows keep their (startTime, endTime, dailyNumber) untouched, so they no longer steal slots from the visible list. - New 400 codes: - cancelled_in_reorder: payload includes a cancelled meeting - incomplete_day: any non-cancelled meeting on the day is missing - Audit oldValue.order now reflects the visible order the user actually saw. - Phase-1/phase-2 negative-parking still avoids transient unique-constraint conflicts; cancelled rows' positive dailyNumbers cannot collide because slot dailyNumbers are a permutation of in-scope rows' existing values. Client (executive-meetings.tsx reorderRows) - Index math now derives ids from `orderedMeetings` (the visible list bound to SortableContext) instead of the raw `meetings` array. useCallback deps updated. Tests - artifacts/api-server/tests/executive-meetings.test.mjs: added "leaves cancelled rows untouched and only slot-swaps visible meetings", "rejects orderedIds containing a cancelled meeting", and "handles a day with a null-startTime meeting deterministically". - artifacts/tx-os/tests/executive-meetings-keyboard-editing.spec.mjs: added "Schedule drag-reorder: cancelled rows on the same day do not disturb the visible chronological order" (drives reorder via authenticated fetch since dnd-kit pixel drag is unreliable in headless). Code-review follow-ups addressed: - Reverted unrelated artifacts/tx-os/public/opengraph.jpg binary change. - Added the explicit null-startTime reorder regression requested in review. - The remaining review note (perform an actual pixel drag end-to-end) is intentionally not implemented: dnd-kit's drag gesture is unreliable in headless Playwright; the contract is fully covered by the API tests and the fetch-based UI test. All 8 reorder tests pass. Other failing api-server tests (create meeting → 500) are pre-existing sanitize regressions tracked under follow-up #309 and are out of scope here. |
||
|
|
d366dc076c |
fix(executive-meetings): keep visible drag-reorder chronological with cancelled rows
Task #311. The schedule view hides cancelled meetings, but the drag-reorder path was operating on the raw, unfiltered list — so cancelled rows consumed time slots and the dnd-kit indices skewed across hidden rows, leaving the visible list out of chronological order after a drop. Server (POST /api/executive-meetings/reorder) - Slot-swap now operates on the in-scope (orderedIds) subset only. Cancelled rows keep their (startTime, endTime, dailyNumber) untouched, so they no longer steal slots from the visible list. - New 400 codes: - cancelled_in_reorder: payload includes a cancelled meeting - incomplete_day: any non-cancelled meeting on the day is missing - Audit oldValue.order now reflects the visible order the user actually saw. - Phase-1/phase-2 negative-parking still avoids transient unique-constraint conflicts; cancelled rows' positive dailyNumbers cannot collide because slot dailyNumbers are a permutation of in-scope rows' existing values. Client (executive-meetings.tsx reorderRows) - Index math now derives ids from `orderedMeetings` (the visible list bound to SortableContext) instead of the raw `meetings` array. useCallback deps updated. Tests - artifacts/api-server/tests/executive-meetings.test.mjs: added "leaves cancelled rows untouched and only slot-swaps visible meetings" and "rejects orderedIds containing a cancelled meeting". - artifacts/tx-os/tests/executive-meetings-keyboard-editing.spec.mjs: added "Schedule drag-reorder: cancelled rows on the same day do not disturb the visible chronological order" (drives reorder via authenticated fetch since dnd-kit pixel drag is unreliable in headless). All 7 reorder tests pass. Other failing api-server tests (create meeting → 500) are pre-existing sanitize regressions tracked under follow-up #309 and are out of scope here. |
||
|
|
4e8beaaa76 |
Transitioned from Plan to Build mode
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: d9167fa7-ae0a-40cd-8655-0f20384142fe Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/HJW50TH Replit-Helium-Checkpoint-Created: true |
||
|
|
e4aa4fa280 |
Improve time input functionality and fix related test cases
Replace native time input with a custom text input and parser, enabling support for various time formats and fixing associated end-to-end tests. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 4ef80303-e96f-4ad0-ba0f-8fce49b7b340 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/HJW50TH Replit-Helium-Checkpoint-Created: true |
||
|
|
5748ec773b |
#307 Polish UpcomingMeetingAlert: AR plurals, 12h time, details table
- locales/{ar,en}.json: split minutesAway / postponeMinutesApply /
postponeConfirmPrompt / postponeConfirmYes / staleMeetingApplyAnyway
into i18next plural variants (AR uses zero/one/two/few/many/other).
Switched call sites to pass `count` so plural detection triggers.
- Added cascadeMinutesUnit_* AR/EN unit keys; cascadePromptHeader_* now
interpolates a pre-formatted {{minutesText}} so the {{minutes}} unit
inside the cascade prompt obeys the same Arabic plural rules.
- upcoming-meeting-alert.tsx: replaced the local 24h `formatTime` with
a 12-hour formatter that delegates to lib/i18n-format.formatTime with
`hour12: true`, keeping Latin digits. Applied to the popup time
window, the stale-meeting current-time line, and the new details row.
- DetailsPanel rewritten as a 2-col label/value grid (time, location,
meeting link, attendees grouped by internal/external/virtual). Empty
rows are skipped. Existing test-ids (alert-details-panel,
alert-details-attendees, alert-details-no-attendees, alert-details-url)
preserved; added alert-details-time / alert-details-location.
- Removed the postponeMinutesHint paragraph (and key from both locales);
the noTimeWindow warning still renders when a meeting has no times.
- PostponeDialog now also reads i18n.language so stale-meeting times
render in the user's locale.
tsc + the full executive-meetings-upcoming-alert.spec.mjs Playwright
suite (18 tests) pass after clearing leftover seeded test data.
|
||
|
|
aa0de3c99b |
Transitioned from Plan to Build mode
Replit-Commit-Author: Agent Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 7471c94c-e508-444f-a1f0-ecf0659e56b6 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/CO2oJgb Replit-Helium-Checkpoint-Created: true |