The api-server docker build failed on the Mac with:
ERROR: Could not resolve "../../../../version.json"
src/routes/system.ts:4
`version.json` lives at the repo root and is tracked in git, but
`docker/api-server.Dockerfile` never copied it into the `build` stage,
so esbuild (running in /app/artifacts/api-server) couldn't resolve the
`../../../../version.json` import added by commit 80429920.
Fix: added `COPY version.json ./` in the build stage, right after the
tsconfig copy and before `lib`/`scripts`/`artifacts` are copied. No
runtime change is needed — esbuild inlines the JSON into the bundle
via the `with { type: "json" }` import attribute, so the runtime stage
does not need the file on disk.
Local dev (`pnpm --filter @workspace/api-server run dev`) is
unaffected because it builds outside Docker against the real repo
root. tx-os Dockerfile not touched.
Mac side after pulling this commit:
cd ~/Downloads/TX && git pull && docker compose up -d --build api
Two small fixes in artifacts/api-server/src/lib/pdf-html-renderer.ts:
1. Removed `font-weight: bold` from `.num-cell` so the # column inherits
the body font weight (same as meeting/attendees/time columns). The
header (`thead th`) keeps its bold styling unchanged.
2. Changed attendees and time cells in `buildMeetingRow` to use
`coloredStyle` (was empty string ""), so when a row has a `rowColor`,
the tint covers the whole row instead of only the # and meeting
cells. The `numDarkStyle` (dark bg + white digit for variants with
a border color) is preserved.
On-screen schedule, merged-cell rows, and cancelled-row red border
behavior are unchanged. API server restarted clean.
- Replace HeaderClock with richer analog+weekday+digital block, always
centered in the header (both president and normal views). Drop the
PresidentClockBar render from the toolbar; the dead helper is left
in place but unused.
- Lift fullscreen state to ExecutiveMeetingsPageInner with
sessionStorage persistence, Esc handler, auto-exit when the user
leaves the schedule tab. Hide the page header when active and show a
floating "Exit fullscreen" pill. New Maximize/Minimize toggle in the
schedule toolbar portal.
- Add MeetingsQuickNoteTab: a fixed amber vertical pill pinned to the
left edge of the schedule view that navigates to /notes?new=1.
- notes.tsx: detect ?new=1, switch to the Active tab, bump a numeric
openTrigger that the top Composer reacts to by opening + focusing
the textarea, then scrub the query param so navigation doesn't
re-trigger.
- i18n: add executiveMeetings.fullscreen.{enter,exit} and
executiveMeetings.quickNote.label in ar.json and en.json.
tsc clean. Push to Gitea still blocked by Tailscale; user to retry.
- Replace HeaderClock with richer analog+weekday+digital block, always
centered in the header (both president and normal views). Drop the
PresidentClockBar render from the toolbar; the dead helper is left
in place but unused.
- Lift fullscreen state to ExecutiveMeetingsPageInner with
sessionStorage persistence, Esc handler, auto-exit when the user
leaves the schedule tab. Hide the page header when active and show a
floating "Exit fullscreen" pill. New Maximize/Minimize toggle in the
schedule toolbar portal.
- Add MeetingsQuickNoteTab: a fixed amber vertical pill pinned to the
left edge of the schedule view that navigates to /notes?new=1.
- notes.tsx: detect ?new=1, switch to the Active tab, bump a numeric
openTrigger that the top Composer reacts to by opening + focusing
the textarea, then scrub the query param so navigation doesn't
re-trigger.
- i18n: add executiveMeetings.fullscreen.{enter,exit} and
executiveMeetings.quickNote.label in ar.json and en.json.
tsc clean. Push to Gitea still blocked by Tailscale; user to retry.
- Replace HeaderClock with richer analog+weekday+digital block, always
centered in the header (both president and normal views). Drop the
PresidentClockBar render from the toolbar; the dead helper is left
in place but unused.
- Lift fullscreen state to ExecutiveMeetingsPageInner with
sessionStorage persistence, Esc handler, auto-exit when the user
leaves the schedule tab. Hide the page header when active and show a
floating "Exit fullscreen" pill. New Maximize/Minimize toggle in the
schedule toolbar portal.
- Add MeetingsQuickNoteTab: a fixed amber vertical pill pinned to the
left edge of the schedule view that navigates to /notes?new=1.
- notes.tsx: detect ?new=1, switch to the Active tab, bump a numeric
openTrigger that the top Composer reacts to by opening + focusing
the textarea, then scrub the query param so navigation doesn't
re-trigger.
- i18n: add executiveMeetings.fullscreen.{enter,exit} and
executiveMeetings.quickNote.label in ar.json and en.json.
tsc clean. Push to Gitea still blocked by Tailscale; user to retry.
- Replace HeaderClock with richer analog+weekday+digital block, always
centered in the header (both president and normal views). Drop the
PresidentClockBar render from the toolbar; the dead helper is left
in place but unused.
- Lift fullscreen state to ExecutiveMeetingsPageInner with
sessionStorage persistence, Esc handler, auto-exit when the user
leaves the schedule tab. Hide the page header when active and show a
floating "Exit fullscreen" pill. New Maximize/Minimize toggle in the
schedule toolbar portal.
- Add MeetingsQuickNoteTab: a fixed amber vertical pill pinned to the
left edge of the schedule view that navigates to /notes?new=1.
- notes.tsx: detect ?new=1, switch to the Active tab, bump a numeric
openTrigger that the top Composer reacts to by opening + focusing
the textarea, then scrub the query param so navigation doesn't
re-trigger.
- i18n: add executiveMeetings.fullscreen.{enter,exit} and
executiveMeetings.quickNote.label in ar.json and en.json.
tsc clean. Push to Gitea still blocked by Tailscale; user to retry.
- Replace HeaderClock with richer analog+weekday+digital block, always
centered in the header (both president and normal views). Drop the
PresidentClockBar render from the toolbar; the dead helper is left
in place but unused.
- Lift fullscreen state to ExecutiveMeetingsPageInner with
sessionStorage persistence, Esc handler, auto-exit when the user
leaves the schedule tab. Hide the page header when active and show a
floating "Exit fullscreen" pill. New Maximize/Minimize toggle in the
schedule toolbar portal.
- Add MeetingsQuickNoteTab: a fixed amber vertical pill pinned to the
left edge of the schedule view that navigates to /notes?new=1.
- notes.tsx: detect ?new=1, switch to the Active tab, bump a numeric
openTrigger that the top Composer reacts to by opening + focusing
the textarea, then scrub the query param so navigation doesn't
re-trigger.
- i18n: add executiveMeetings.fullscreen.{enter,exit} and
executiveMeetings.quickNote.label in ar.json and en.json.
tsc clean. Push to Gitea still blocked by Tailscale; user to retry.
- Replace HeaderClock with richer analog+weekday+digital block, always
centered in the header (both president and normal views). Drop the
PresidentClockBar render from the toolbar; the dead helper is left
in place but unused.
- Lift fullscreen state to ExecutiveMeetingsPageInner with
sessionStorage persistence, Esc handler, auto-exit when the user
leaves the schedule tab. Hide the page header when active and show a
floating "Exit fullscreen" pill. New Maximize/Minimize toggle in the
schedule toolbar portal.
- Add MeetingsQuickNoteTab: a fixed amber vertical pill pinned to the
left edge of the schedule view that navigates to /notes?new=1.
- notes.tsx: detect ?new=1, switch to the Active tab, bump a numeric
openTrigger that the top Composer reacts to by opening + focusing
the textarea, then scrub the query param so navigation doesn't
re-trigger.
- i18n: add executiveMeetings.fullscreen.{enter,exit} and
executiveMeetings.quickNote.label in ar.json and en.json.
tsc clean. Push to Gitea still blocked by Tailscale; user to retry.
Bug: on iPad / iOS Safari, tapping a meetings-table editable cell hid
the floating formatting toolbar (color swatches, alignment, font, save,
cancel) under the soft keyboard. Users saw only Apple's tiny B/I/U
accessory bar and could not change color or even tap Save/Cancel.
Root cause in `artifacts/tx-os/src/components/editable-cell.tsx`:
FormattingToolbar positioned itself at `rect.bottom + 4` and explicitly
refused to flip above the cell. It also only listened to window scroll
and resize, not to `visualViewport` events, so it did not react to the
keyboard opening or closing.
Fix (single file):
- Import and call the existing `useVisualViewport` hook inside
FormattingToolbar to get reactive `{ height, offsetTop }`.
- Compute the visible viewport bottom as `offsetTop + height` and, when
the toolbar would not fit below the cell without going under that
bottom (keyboard or short viewport), flip it ABOVE the cell:
`top = max(vv.offsetTop + 4, rect.top - tbHeight - 4)`.
- Keep desktop behavior unchanged: when the viewport is full-height the
below position still fits, so we still place below the cell.
- Added `vv.height`, `vv.offsetTop`, `vv.keyboardInset` to the effect
deps so the toolbar tracks the keyboard show/hide animation.
- Replaced the "never flip above" comment block with a comment that
documents the keyboard-coverage exception.
Out of scope (unchanged): toolbar wrapping/overflow on very narrow
iPads, Apple's built-in B/I/U keyboard accessory bar, any other page.
Validation:
- `pnpm --filter @workspace/tx-os exec tsc --noEmit` clean.
- Vite HMR updated editable-cell.tsx without errors.
Cleans up the Notes page after a user creates their first folder:
1. FoldersRail: in `rail` mode (every view except "All notes"), insert a
small "My folders" / "مجلداتي" section header above the user's folder
list so it no longer visually nests under the dark "Unfiled" pill.
New i18n key `notes.folders.myFolders` in en.json and ar.json.
2. notes.tsx filteredNotes: when `folderSelection.kind === "all"`, hide
notes whose `folderId !== null`. Combined with the existing
FoldersBrowser cards this gives a file-manager feel — notes inside a
folder are reachable by opening the folder card and no longer appear
in the flat list, so users stop thinking move = copy. Counts on the
"All notes" rail entry stay as the total (totalCount prop unchanged).
3. notes.tsx grid: replaced the two separate grid cells for
composer/content with a single wrapper that uses `display: contents`
on mobile (children flow into the outer grid honoring order-1/2/3)
and `flex flex-col gap-4` on md+ (composer and content stack in the
same cell, no empty grid-row gap when the FoldersRail is taller than
the composer). Removed unused conditional row-start/row-span on the
inner content div.
Out of scope per plan: dnd-kit behavior, shared-with-me logic, composer
or folder card redesign.
Validation: `pnpm --filter @workspace/tx-os exec tsc --noEmit` clean.
Vite HMR successful after fix; no babel/JSX errors.
The Postpone dialog's "إعادة الجدولة" tab was packing Date + Start +
End into a single 3-column row at `lg:` (≥1024 px), which on iPad
landscape (and small desktops) made iOS Safari's native date/time
spinner glyphs + Arabic AM/PM markers visibly collide between cells.
User reported the boxes looked "غير مرتبه".
Change:
- artifacts/tx-os/src/components/executive-meetings/upcoming-meeting-alert.tsx:
replace the `grid grid-cols-1 gap-3 lg:grid-cols-3` wrapper with a
vertical `space-y-3` stack: Date input on its own full-width row,
then a `grid grid-cols-2 gap-3` row holding Start + End side-by-
side. Same `min-w-0` + `w-full` discipline on every cell so inputs
respect their track.
- Updated the explanatory comment to record why we no longer try a
3-column path: the only layout that stays clean from 320 px phones
up through desktop without depending on a custom picker is the
Date-on-top / Start+End-below stack.
Verified `tsc --noEmit` clean. No DB / locale / API changes. Mac
rebuild = `git pull && ./start.sh rebuild && docker compose up -d
--force-recreate web`. No script run needed.
Remove `enable-default-apps.ts` script, add `disable-deprecated-apps.ts`, update seeding logic in `seed.ts` to set `isActive` to false for documents, and modify `DOCKER.md` and `scripts/package.json` accordingly.
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 77cfe984-2c65-4152-bb7a-0df28274fe66
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: ac51f801-911b-4be5-b27c-e3212d5c0c73
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/c3c252e4-c83d-40ca-9fff-99a3ea60701e/77cfe984-2c65-4152-bb7a-0df28274fe66/1WKAcHk
Replit-Helium-Checkpoint-Created: true
Three connected fixes on the Executive Meetings schedule.
1) Push enable diagnostics (use-push-subscription.ts):
- `enable()` now returns { ok, reason } instead of a bare boolean.
- Reasons: unsupported, unsupported_ios_safari, permission_denied,
vapid_unavailable, subscribe_failed, server_rejected.
- Detects iPhone/iPad Safari not running as a PWA (checks
navigator.standalone + display-mode media query, with iPadOS
MacIntel + maxTouchPoints fallback) and short-circuits with
unsupported_ios_safari so the user gets a concrete
"open from Home Screen first" message instead of a silent fail.
- Wrapped VAPID fetch and pushManager.subscribe in their own
try/catches so each failure mode maps to its own reason.
2) Specific failure toasts (push-enable-prompt.tsx,
notification-settings.tsx):
- Both call sites now look up
`notifSettings.push.errors.<reason>` and fall back to the
legacy generic copy if the key is missing.
- Added enableSuccess toast on the toggle path too — previously
only the prompt-card path showed feedback on success.
- New AR + EN strings under notifSettings.push.errors.*.
3) Quick-actions row sheet (executive-meetings.tsx):
- Edit + Postpone buttons now sit SIDE BY SIDE on every viewport
(flex + flex-1 + min-w-0 instead of flex-wrap + min-w-[11rem]),
same height, equal width — fixes the stacked / over-sized Edit
button shown in the user's iPhone screenshot.
- "Edit" no longer opens the small Meeting edit Dialog. It now
flips the whole schedule into edit mode (same as the toolbar
pencil) and paints a transient accent ring on the originating
row (~1.6s) + smooth-scrolls it into view. Matches image 3 in
#576 where the user expects to see the full editable list.
- Added `highlightEdit` prop on MeetingRow that composes an
extra inset+outer ring on top of the existing quickOpen /
selection / current / press shadows, plus a soft background
tint, and clears automatically when ScheduleSection clears
highlightEditRowId.
Out of scope (left for follow-up tasks): server-side push delivery
(payloads/sounds), the edit-mode UI itself.
Replace generic PWA/favicon assets with the IT-P brand image and layer
the same image over the login page's AnimatedArt panel.
- Generated icon-192/512, maskable-512, and apple-touch-icon (180) from
the attached IT-P photo via ImageMagick (center crop 1110x1110, then
resize). Maskable has #0B1E3F padding so the safe zone is respected
on Android adaptive icons.
- Copied source as public/brand-itp.jpg for the login hero.
- index.html: replaced the generic favicon.svg link with a full
favicon set built from IT-P (favicon.ico + 16/32/48/192/512 PNG),
all cache-busted with ?v=itp1. Deleted public/favicon.svg so no
browser can fall back to the old generic mark.
- Cache-busted apple-touch-icon link the same way so iPad PWA
re-installs pick up the new artwork.
- manifest.webmanifest: same ?v=itp1 cache-bust on all icon entries.
- login.tsx: layered IT-P image over AnimatedArt with mix-blend-screen
(opacity 90%) plus top/bottom and right-edge dark gradients so the
composition reads as one piece and the right edge fades cleanly into
the form panel. Still hidden on < lg per scope.
Did not change favicon.svg itself (kept as last-resort vector
fallback). Mobile (< lg) shows no hero — explicit choice per plan
("إخفاؤها بشكل مدروس").
Replace generic PWA/favicon assets with the IT-P brand image and layer
the same image over the login page's AnimatedArt panel.
- Generated icon-192/512, maskable-512, and apple-touch-icon (180) from
the attached IT-P photo via ImageMagick (center crop 1110x1110, then
resize). Maskable has #0B1E3F padding so the safe zone is respected
on Android adaptive icons.
- Copied source as public/brand-itp.jpg for the login hero.
- index.html: added explicit PNG icon links (192, 512) before the
existing favicon.svg fallback, plus cache-bust query (?v=itp1) on
apple-touch-icon so iPad PWA re-installs pick up the new artwork.
- manifest.webmanifest: same ?v=itp1 cache-bust on all icon entries.
- login.tsx: layered IT-P image over AnimatedArt with mix-blend-screen
(opacity 90%) plus top/bottom and right-edge dark gradients so the
composition reads as one piece and the right edge fades cleanly into
the form panel. Still hidden on < lg per scope.
Did not change favicon.svg itself (kept as last-resort vector
fallback). Mobile (< lg) shows no hero — explicit choice per plan
("إخفاؤها بشكل مدروس").
Task: on fresh installs the Calendar and Notifications apps were
appearing enabled by default, and the home screen showed a
Notifications tile that was redundant with the bell icon already in
the top bar. User wanted both apps disabled by default and the home
tile gone (bell stays).
Changes:
- scripts/src/seed.ts: flip the seed `isActive` for `notifications`
and `calendar` from true → false. The seed inserts apps with
`db.insert(appsTable).values(apps).onConflictDoNothing()`, so this
is fully idempotent: existing environments (where the row already
exists with isActive=true) are NOT changed; only fresh inserts on
new installs pick up the disabled default. Admins can enable
either app from app settings when they want it.
- artifacts/tx-os/src/pages/home.tsx: remove "notifications" from
the `dockApps` filter so the bottom dock no longer renders a
Notifications tile. Filter becomes `["services", "admin"]`. The
top-bar bell icon (and its unread badge) was untouched and still
routes to `/notifications`.
Out of scope (per spec): no migration to disable existing prod
rows; no role/permission changes; bell icon in the top bar stays.
Files:
- scripts/src/seed.ts (notifications block ~L229, calendar block ~L275)
- artifacts/tx-os/src/pages/home.tsx:532
Task: on fresh installs the Calendar and Notifications apps were
appearing enabled by default, and the home screen showed a
Notifications tile that was redundant with the bell icon already in
the top bar. User wanted both apps disabled by default and the home
tile gone (bell stays).
Changes:
- scripts/src/seed.ts: flip the seed `isActive` for `notifications`
and `calendar` from true → false. The seed inserts apps with
`db.insert(appsTable).values(apps).onConflictDoNothing()`, so this
is fully idempotent: existing environments (where the row already
exists with isActive=true) are NOT changed; only fresh inserts on
new installs pick up the disabled default. Admins can enable
either app from app settings when they want it.
- artifacts/tx-os/src/pages/home.tsx: remove "notifications" from
the `dockApps` filter so the bottom dock no longer renders a
Notifications tile. Filter becomes `["services", "admin"]`. The
top-bar bell icon (and its unread badge) was untouched and still
routes to `/notifications`.
Out of scope (per spec): no migration to disable existing prod
rows; no role/permission changes; bell icon in the top bar stays.
Files:
- scripts/src/seed.ts (notifications block ~L229, calendar block ~L275)
- artifacts/tx-os/src/pages/home.tsx:532
Task: on iPad the bulk-selected row was nearly invisible (only a 2px
inset navy ring), and the row-tap Quick Actions dialog had only a
Postpone button — user asked for a real visible selection fill and
an Edit (pencil) action wired to the existing edit-meeting flow.
Changes (artifacts/tx-os/src/pages/executive-meetings.tsx):
- MeetingRow: add `selectionBg = rgba(11,30,63,0.18)` painted on the
row's `<tr>` backgroundColor in addition to the existing
`selectionShadow` 2px navy ring. Composition order in trStyle is
`quickOpenBg ?? selectionBg ?? baseBg` so an open quick-actions
surface still wins (transient action state), user-picked row
colours still show when nothing is selected, and the navy tint
reads clearly on iPad against the table grid.
- MeetingRow: new optional `onQuickEdit?: () => void` prop. Quick
Actions Dialog gains a pencil-icon "Edit" button before the
existing Postpone button, wrapped in `flex flex-wrap gap-2` so the
two buttons sit side-by-side on iPad/desktop and stack on narrow
viewports. Button only renders when a handler is wired
(defensive — `quickActionsCanMutate` already gates the surface).
- ScheduleSection: host a local `editingMeeting` + `editingSaving`
state plus a `MeetingFormDialog` mount, with a save handler whose
body mirrors ManageSection's `save()` exactly (same PATCH payload
projection, same `wrapAsParagraph` / attendee shaping, same
toast/error translation). Edit button on a row opens this in-place
dialog instead of switching the user to the Manage tab.
- Locale: add `executiveMeetings.quickActions.edit` = "تعديل" / "Edit".
Notes:
- No new icon import needed — `Pencil` was already in the lucide
import group.
- Selection ring (`#0B1E3F`) and tint use the same navy so they
read as one cohesive selected state, not competing layers.
- Pre-existing `use-push-subscription.ts` TS noise unchanged.
User asked that when the President (`executive_ceo` role) logs into
the Meetings page he sees a clean "presentation" layout: just the
schedule table, an analog clock plus the weekday/date of the
schedule, and nothing else. The Manage / Notifications / Audit /
PDF tabs and the PDF-export shortcut button are noisy for him and
must disappear — but his backend permissions stay intact.
Changes (frontend only — backend role gates untouched):
- New component `components/executive-meetings/analog-clock.tsx`:
small SVG analog clock (hour/minute/second hands, navy + gold),
ticks every second, ~44px default.
- New inner `PresidentClockBar` component in `executive-meetings.tsx`:
renders the analog clock + weekday + **digital time** (ticking
per second, localized) + selected schedule date in one block.
- `pages/executive-meetings.tsx`:
- Derived `isPresidentView` from the `/me` roles: true iff
`executive_ceo` is present AND the user is NOT also `admin`
or `executive_office_manager` (admins keep full UI).
- Effect forces `section = "schedule"` whenever
`isPresidentView` becomes true, so the president can never
land on a now-hidden tab.
- Hides the header PDF-shortcut button and the entire SECTIONS
tab list when `isPresidentView`. The `#em-toolbar-portal` is
kept so the date picker still mounts.
- `ScheduleSection` accepts two new optional props:
`isPresidentView` and `lang`. When `isPresidentView` is on,
the toolbar renders the AnalogClock next to a label showing
`formatWeekday(date, lang, "long")` and `formatDate(date, lang)`
(e.g. "Sunday · May 17, 2026" / "الأحد · 17 مايو 2026"). The
label updates immediately when the date input changes.
- Edit-mode toggle stays gated on `canMutate`, so the president
(who has canMutate) still gets the inline-edit pencil if he
wants it.
Out of scope: backend role changes, applying the focused view to
other roles, manual presentation-mode toggle. Verified via tsc
(only the pre-existing `use-push-subscription` error remains).
User asked that when the President (`executive_ceo` role) logs into
the Meetings page he sees a clean "presentation" layout: just the
schedule table, an analog clock plus the weekday/date of the
schedule, and nothing else. The Manage / Notifications / Audit /
PDF tabs and the PDF-export shortcut button are noisy for him and
must disappear — but his backend permissions stay intact.
Changes (frontend only — backend role gates untouched):
- New component `components/executive-meetings/analog-clock.tsx`:
small SVG analog clock (hour/minute/second hands, navy + gold),
ticks every second, ~44px default.
- `pages/executive-meetings.tsx`:
- Derived `isPresidentView` from the `/me` roles: true iff
`executive_ceo` is present AND the user is NOT also `admin`
or `executive_office_manager` (admins keep full UI).
- Effect forces `section = "schedule"` whenever
`isPresidentView` becomes true, so the president can never
land on a now-hidden tab.
- Hides the header PDF-shortcut button and the entire SECTIONS
tab list when `isPresidentView`. The `#em-toolbar-portal` is
kept so the date picker still mounts.
- `ScheduleSection` accepts two new optional props:
`isPresidentView` and `lang`. When `isPresidentView` is on,
the toolbar renders the AnalogClock next to a label showing
`formatWeekday(date, lang, "long")` and `formatDate(date, lang)`
(e.g. "Sunday · May 17, 2026" / "الأحد · 17 مايو 2026"). The
label updates immediately when the date input changes.
- Edit-mode toggle stays gated on `canMutate`, so the president
(who has canMutate) still gets the inline-edit pencil if he
wants it.
Out of scope: backend role changes, applying the focused view to
other roles, manual presentation-mode toggle. Verified via tsc
(only the pre-existing `use-push-subscription` error remains).
User requested that deleting a finished order from My Orders happen
silently — one click on the trash icon, no confirmation dialog, no
success toast. Just click and the card disappears.
Changes:
- Removed the delete-confirm AlertDialog from OrderCard along with
its `confirmDeleteOpen` state. The trash icon now calls
`handleDelete` directly.
- Removed `toast({ title: t("myOrders.deleted") })` from
`scheduleDelete`. The 7-second soft-delete grace window stays in
place (pendingDeleteIds filter + setTimeout) so the API DELETE
still fires after the window. The `deleteFailed` error toast is
preserved so silent API failures don't lose orders.
- Dropped the now-unused locale keys from ar.json and en.json:
`deleteConfirmTitle`, `deleteConfirmBody`, `deleteConfirm`,
`deleted`.
- Removed the unused `AlertDialogDescription` import (the remaining
cancel-confirm dialog uses only the title).
Cancel-order flow remains untouched (still shows confirm dialog and
undo toast as in #566).
Per user request on the طلباتي page:
1. Removed the "Clear finished orders" bulk button entirely. The button
was showing as a raw i18n key (myOrder c...) for the user and they
asked for it gone. Dropped the related AlertDialog, confirmClearOpen
state, handleClearFinished handler, and the locale keys
clearFinished_*, clearConfirmTitle/Body_*, clearConfirm,
clearedCount_*, and clearedPartial in both ar.json and en.json.
2. Removed the "تراجع / Undo" ToastAction shown after deleting an
order. The toast now displays only the "Order deleted" title; the
7-second timer + pendingDeleteIds soft-delete window is preserved
so the actual DELETE still fires after the grace period. The undo
closure was deleted since nothing references it anymore. Single-id
call site stays untouched (scheduleDelete still receives [id]).
3. Removed the "ستتاح لك ثوانٍ قليلة للتراجع" description from the
cancel-order confirmation dialog. The cancelConfirmBody key was
dropped from both locales. The AlertDialog now shows only the
title + the two action buttons.
Out of scope (kept as-is):
- The undo ToastAction after CANCEL (user only asked about delete).
- Incoming-orders page.
Notes:
- ToastAction import is still used by the cancel-undo path.
- Trash2 import still used by the per-card delete button.
- Pre-existing TS error in use-push-subscription.ts is unrelated.
User-reported polish on the executive-meetings quick-actions flow on
iPad/mobile. Six fixes, all client-side:
1. Quick-actions surface now opens from ANY click on a meeting row
(was: only the attendees cell). Root cause: handleRowClick guard
skipped any `em-edit-*`, `em-merge-edit-*`, and `em-time-*`
descendants. Those affordances only do anything in edit mode, but
handleRowClick already early-returns when edit mode is on, so the
testid guard was always over-aggressive. Dropped those guards plus
the `[role='button']` rule from the interactive selector, kept the
real `button`/`input`/`textarea`/`a`/`menuitem`/`checkbox`/etc.
guards and the `em-row-actions-*` / `em-row-select-*` testid
guards (those affordances are visible outside edit mode and must
not trigger the surface).
File: artifacts/tx-os/src/pages/executive-meetings.tsx (~L4350).
2. Originating row is now unmistakable on iPad: quickOpenShadow is
`inset 0 0 0 4px highlight, 0 0 0 2px highlight` (was a single
3px inset) and the row background tints to
`rgba(highlight, 0.08)` while quick-actions is open.
File: artifacts/tx-os/src/pages/executive-meetings.tsx
(~L4287, L4344).
3. Postpone dialog header was overlapping the Radix close X in RTL.
Added `pr-8` on the DialogHeader (same pattern already used for
the row-quick mini-dialog).
File: artifacts/tx-os/src/components/executive-meetings/
upcoming-meeting-alert.tsx (~L1447).
4. Reschedule tab: date / start / end inputs collided on iPad
portrait. Grid is now `grid-cols-1 md:grid-cols-3` (single column
through iPad portrait, three across on landscape/desktop), with
`min-w-0` on each cell and `w-full` on every Input so Safari's
native date/time pickers stop overflowing.
Same file (~L1761).
5. Cancel tab X overlap is resolved by the same DialogHeader fix in
step 3 (one Dialog wraps all three tabs).
6. Removed the `cancelHint` paragraph + the `cancelHint` translation
keys in ar.json (L1252) and en.json (L1164) — fully unused now.
NOT pushed to Gitea (Tailscale to desktop-11cj93j still flaky).
Pending pushes: #560 (VAPID), #561 (CEO roles), #563 (this).
User-reported polish on the executive-meetings quick-actions flow on
iPad/mobile. Six fixes, all client-side:
1. Quick-actions surface now opens from ANY click on a meeting row
(was: only the attendees cell). Root cause: handleRowClick guard
skipped any `em-edit-*`, `em-merge-edit-*`, and `em-time-*`
descendants. Those affordances only do anything in edit mode, but
handleRowClick already early-returns when edit mode is on, so the
testid guard was always over-aggressive. Dropped those guards plus
the `[role='button']` rule from the interactive selector, kept the
real `button`/`input`/`textarea`/`a`/`menuitem`/`checkbox`/etc.
guards and the `em-row-actions-*` / `em-row-select-*` testid
guards (those affordances are visible outside edit mode and must
not trigger the surface).
File: artifacts/tx-os/src/pages/executive-meetings.tsx (~L4350).
2. Originating row is now unmistakable on iPad: quickOpenShadow is
`inset 0 0 0 4px highlight, 0 0 0 2px highlight` (was a single
3px inset) and the row background tints to
`rgba(highlight, 0.08)` while quick-actions is open.
File: artifacts/tx-os/src/pages/executive-meetings.tsx
(~L4287, L4344).
3. Postpone dialog header was overlapping the Radix close X in RTL.
Added `pr-8` on the DialogHeader (same pattern already used for
the row-quick mini-dialog).
File: artifacts/tx-os/src/components/executive-meetings/
upcoming-meeting-alert.tsx (~L1447).
4. Reschedule tab: date / start / end inputs collided on iPad
portrait. Grid is now `grid-cols-1 md:grid-cols-3` (single column
through iPad portrait, three across on landscape/desktop), with
`min-w-0` on each cell and `w-full` on every Input so Safari's
native date/time pickers stop overflowing.
Same file (~L1761).
5. Cancel tab X overlap is resolved by the same DialogHeader fix in
step 3 (one Dialog wraps all three tabs).
6. Removed the `cancelHint` paragraph + the `cancelHint` translation
keys in ar.json (L1252) and en.json (L1164) — fully unused now.
NOT pushed to Gitea (Tailscale to desktop-11cj93j still flaky).
Pending pushes: #560 (VAPID), #561 (CEO roles), #563 (this).
User request: السماح للرئيس (executive_ceo) بإنشاء/تعديل/تأجيل/حذف
الاجتماعات، استلام إشعارات Push للتذكير، والاطلاع على سجل التدقيق —
مع إبقاء إعدادات الخطوط/الشعار حصرية على مدير المكتب التنفيذي.
Changes (3 lines added, backend-only):
1. artifacts/api-server/src/routes/executive-meetings.ts
- Added "executive_ceo" to MUTATE_ROLES (line 120) → POST/PATCH/DELETE
on meetings now accepted for the CEO role.
- Added "executive_ceo" to ADMIN_AUDIT_ROLES (line 130) → /audit
endpoint now reachable; canViewAudit=true in the bootstrap payload.
- EM_ADMIN_ROLES intentionally untouched, so font-settings and global
PDF brand assets remain admin + executive_office_manager only.
2. artifacts/api-server/src/lib/executive-meeting-scheduler.ts
- Added "executive_ceo" to EM_NOTIFY_ROLES (line 18) → CEO users with
an active Web Push subscription now receive the LEAD_MINUTES=5
pre-meeting reminder push.
Frontend requires no changes: it gates buttons on canMutate /
canViewAudit booleans returned by the bootstrap endpoint (lines
617-619), which flip to true automatically for the CEO role.
Verification: API workflow restarted clean, scheduler started OK,
/api/executive-meetings and /alert-state respond 304/200.
NOT pushed to Gitea: Tailscale link to desktop-11cj93j is still down
from this sandbox (HTTP=000). Task #560's earlier VAPID fix
(629069b1) is also still pending push. Both will go up together when
the tunnel recovers, or the user can apply the same one-line edits
on the Mac and rebuild the api container.