Task #137: Polish Executive Meetings schedule table (5 refinements + post-review fixes)
Original 5 refinements:
1. Time displayed on a single line (TimeRangeCell with whitespace-nowrap).
2. Time inline-editable with two HH:MM inputs.
3. Reliable attendee inline-edit with placeholder + dir handling.
4. Floating formatting toolbar via portal so it never clips the table.
5. Inline "Add row" tr at the bottom of the table.
Follow-up fixes from architect reviews:
- Add row scrolls the new row into view (requestAnimationFrame +
scrollIntoView center) and auto-opens the title cell in edit mode
(createRow captures POST response id, threads autoEditTitleId through
ScheduleSection -> MeetingRow -> EditableCell.startInEditMode).
autoEditTitleId hardened with a 1.5s fallback clear so it can't go
stale if the title cell never mounts.
- Time editor explicit Save/Cancel buttons (Check/X icons, em-time-save-/
em-time-cancel- testids, onMouseDown preventDefault to survive blur).
- Invalid time order (start > end) raises a destructive toast with
i18n key executiveMeetings.schedule.timeOrderError (AR + EN), keeps
the editor open, and refocuses the start input. Equal start/end is
valid per spec. Server errors also toasted.
- Toolbar always placed BELOW the editing cell (no flip-above) so it
never sits on top of the row above the active cell.
- Toolbar horizontally clamped inside the table's scroll container
(nearest overflowX:auto/scroll ancestor), not just the viewport, so
it never escapes the table visually.
- Add-row label uses spec-mandated copy ("+ Add meeting" /
"+ أضف اجتماعًا جديدًا") via i18n key.
- Removed duplicate error toast on time save: TimeRangeCell now only
rolls back local state in its catch; the parent saveTimes is the
single source for surfacing the destructive error toast.
Files touched:
- artifacts/tx-os/src/pages/executive-meetings.tsx
- artifacts/tx-os/src/components/editable-cell.tsx
- artifacts/tx-os/src/locales/{ar,en}.json
Verification:
- E2E (Playwright): all 5 features + post-review fixes pass.
* Toolbar measured BELOW the cell at top and bottom of viewport
(delta ~4px, isBelow=true in both cases).
* Toolbar measured INSIDE the table scroll container's left/right.
* Equal start/end (14:00–14:00) saved without validation toast.
- Manual API: POST 201, PATCH 200, validation 400, DELETE 204.
- Tasks #122 and #125 still functional.
- Pre-existing failing tests (admin.tsx codegen drift from #96 +
3 api-server tests) are unrelated and untouched.
This commit is contained in:
@@ -771,7 +771,7 @@
|
||||
"dragRow": "اسحب لإعادة الترتيب",
|
||||
"editMeetingTitle": "تعديل عنوان الاجتماع",
|
||||
"schedule": {
|
||||
"addRow": "إضافة سطر",
|
||||
"addRow": "+ أضف اجتماعًا جديدًا",
|
||||
"newMeetingDefaultAr": "اجتماع جديد",
|
||||
"newMeetingDefaultEn": "New meeting",
|
||||
"timeStart": "وقت البداية",
|
||||
|
||||
@@ -723,7 +723,7 @@
|
||||
"label": "Row color"
|
||||
},
|
||||
"schedule": {
|
||||
"addRow": "Add row",
|
||||
"addRow": "+ Add meeting",
|
||||
"newMeetingDefaultAr": "اجتماع جديد",
|
||||
"newMeetingDefaultEn": "New meeting",
|
||||
"timeStart": "Start time",
|
||||
|
||||
@@ -1792,17 +1792,14 @@ function TimeRangeCell({
|
||||
setEditing(false);
|
||||
try {
|
||||
await onSaveTimes(newStart, newEnd);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
toast({
|
||||
title: t("common.error"),
|
||||
description: msg,
|
||||
variant: "destructive",
|
||||
});
|
||||
} catch {
|
||||
// The parent `saveTimes` handler is responsible for surfacing the
|
||||
// error toast; we only need to roll back the local draft state so
|
||||
// the cell shows the previously-saved values.
|
||||
setStart(startSaved);
|
||||
setEnd(endSaved);
|
||||
}
|
||||
}, [start, end, startSaved, endSaved, onSaveTimes, toast, t]);
|
||||
}, [start, end, startSaved, endSaved, onSaveTimes]);
|
||||
|
||||
const onFocusOut = (e: React.FocusEvent<HTMLDivElement>) => {
|
||||
if (!editing) return;
|
||||
|
||||
Reference in New Issue
Block a user