Commit Graph

962 Commits

Author SHA1 Message Date
Riyadh 7b4a60daf5 Transitioned from Plan to Build mode 2026-05-25 11:34:03 +00:00
Riyadh 8d9bc7951e Task #632: realtime order delivery for recipients on iPad PWA
Bug: order creator (services manager) saw new orders instantly with
sound, but other users holding orders.receive — even with the app
foregrounded on the Orders screen — got nothing until they force-quit
and reopened the PWA, at which point the orders appeared. Root cause:
Socket.IO silently drops behind Tailscale/NAT on iPad PWA and the
client neither detected it nor refetched missed state on reconnect.
The creator was unaffected because their POST mutation updates their
queries locally without depending on the realtime channel.

Client (artifacts/tx-os/src/hooks/use-notifications-socket.ts):
- Tighten io() options: reconnection {Delay 500, DelayMax 3000,
  Attempts Infinity, timeout 10s}.
- Track `wasDisconnected` flag; on `disconnect` flip it and log the
  reason (skipping the clean "io client disconnect" path).
- On `connect`, if previously disconnected, invalidate every realtime-
  driven query key: notifications, home stats, my/incoming orders,
  notes, note-folders, exec meetings (list/alert-state/notifications),
  apps, /me, roles, permissions. Warmup window is reset BEFORE the
  refetch so any flushed notification_created events post-reconnect
  don't chime.
- Add a `visibilitychange` listener: on foreground return, if the
  socket is disconnected, force `socket.connect()`; if it's "connected"
  but possibly half-open (silent drop), round-trip a 3s-timeout
  `client_health_probe` ack — on timeout, `disconnect().connect()`.
- `connect_error` logger for field debugging.

Server (artifacts/api-server/src/index.ts):
- Tighten Socket.IO pingInterval=10s, pingTimeout=5s (was default
  25s/20s) so dead-connection detection cycle drops from ~45s to ~15s.
- Add `client_health_probe` handler that acks immediately — pairs
  with the client-side half-open probe.

Deviations from plan: skipped the optional UI connection indicator
(point 5) — not necessary to fix the reported bug; can ship later if
users still feel uncertain about connection state.

Architect approved with one minor caveat: severe (>3s) transient
latency on foreground could trigger a one-off socket cycle. Acceptable
tradeoff and explicitly documented in the comment.

Pre-existing TS errors in api-server/src/routes/push.ts are unrelated
to this task and not touched by this diff.
2026-05-24 10:29:04 +00:00
Riyadh 58d7ca500a Transitioned from Plan to Build mode 2026-05-24 10:22:18 +00:00
Riyadh 2cc955ed65 Task #630: keep recipients list visible above iPad keyboard in Send Note
Problem: opening Send Note on iPad, tapping the search field opened the
soft keyboard which covered the recipients list and the Send button —
the dialog stayed centered on the full layout viewport.

Fix (artifacts/tx-os/src/components/notes/send-note-dialog.tsx):

Two-tier keyboard detection:
  1. Primary — `vv.keyboardInset > 0` from useVisualViewport. Works on
     desktop touch laptops, iPad Safari (regular tab), Android Chrome.
     When true, override DialogContent style with
       top = vv.offsetTop + vv.height/2 − 48 (QuickType inset)
       transform: translate(-50%, -50%)
     so the dialog recenters around the visible viewport region.
  2. Fallback — `searchFocused && matchMedia('(pointer: coarse)')`.
     Only used when visualViewport does NOT report an inset, which is
     the iPad PWA (Add to Home Screen) case explicitly called out in
     components/ui/dialog.tsx comment. Top-anchors at 6vh with
     maxHeight 50dvh so the dialog never crosses the screen midpoint.
  3. Neither — pass NO style at all so Radix's default centered layout
     is fully restored (no leftover transition or top).

Touch-only fallback gating (matchMedia pointer:coarse) prevents the
earlier desktop-regression flagged by code review — focusing the
search on a desktop never repositions the dialog.

Other changes:
- onFocus/onBlur on the search input feed the fallback signal.
- Blur is debounced 150ms so tapping a recipient row mid-blur doesn't
  recenter the dialog out from under the finger.
- useEffect cleanup clears pending blur timeout on unmount.

Verification: tsc clean. Architect approved the touch-gated fallback;
follow-up review reconciled the diff with the spec's primary
visualViewport-driven path.
2026-05-24 09:48:10 +00:00
Riyadh cd7e4cfad9 Task #630: keep recipients list visible above iPad keyboard in Send Note
Problem: opening Send Note on iPad PWA, tapping the search field popped
up the soft keyboard which covered the entire people list and the Send
button. The previous fix relied on visualViewport to shrink the list,
but iPad PWAs don't reliably resize visualViewport when the keyboard
opens (see the note in components/ui/dialog.tsx referencing the
reverted #622–#624 global attempts).

Fix (artifacts/tx-os/src/components/notes/send-note-dialog.tsx):
- Track search-input focus directly — the most reliable "keyboard is
  about to open" signal on touch devices, independent of visualViewport.
- Gate the override behind `matchMedia('(pointer: coarse)')` so it
  only fires on touch-primary devices (iPad/iPhone/Android) and never
  on desktop or trackpad laptops — addressing the architect's
  cross-platform regression flag.
- When the gate is active, override DialogContent's Radix center
  anchor (top:50%; translate(-50%,-50%)) with `top:6vh;
  translate(-50%,0); maxHeight:50dvh`. The dialog grows downward from
  a fixed top edge so it always fits in the upper half of the screen,
  leaving the lower half free for the keyboard.
- Cap `listMaxHeight` to ~50% of innerHeight in the same gated
  condition, as a backstop where visualViewport stays full-height.
- Debounce blur by 150ms so a tap on a recipient row doesn't lose
  the row mid-tap to a center-jump animation; clear the timeout on
  unmount.
- Added 120ms ease transition on top/transform so the layout swap
  doesn't snap.

Deviations: original plan used vv.offsetTop+vv.height/2 to reposition,
but that depends on the same unreliable visualViewport. Switched to
a focus + coarse-pointer driven approach which works on iPad PWA.

Verification: tsc clean. Architect re-review pending after the touch
gate was added (first review flagged the missing platform guard,
which this revision addresses directly).
2026-05-24 09:45:38 +00:00
Riyadh 41792d8493 Transitioned from Plan to Build mode 2026-05-24 09:41:06 +00:00
Riyadh 3ceabb85bc Improve notification sound throttling and delivery reliability
Refactor notification sound playback to use per-bucket throttling, adjust socket warmup, and ensure push notifications are sent even if the client is considered connected.
2026-05-24 08:33:53 +00:00
Riyadh 1096217420 Transitioned from Plan to Build mode 2026-05-24 08:16:55 +00:00
Riyadh b4fa097703 Task #626: stop notifications after logout + tighten meeting reminder
- /auth/logout: delete all push_subscriptions rows for the user before
  destroying the session. Best-effort with logger.warn on failure so an
  operator can correlate any leaked-ring report to a real DB error.
- home.tsx handleLogout: call pushSub.disable() before the logout
  mutation, raced against a 1.5s timeout so a stalled service worker
  cannot block sign-out.
- executive-meeting-scheduler: switch the eligibility filter from
  denylist (ne cancelled + ne completed) to whitelist
  (eq status='scheduled'). Postponed / rescheduled / future statuses
  can no longer trigger false 5-minute reminders.
- docker-compose.yml: pin TZ=Asia/Riyadh on postgres, api, and web
  services so the scheduler's naive date/time math matches the
  operator's wall clock instead of UTC.

Gitea push failed with TLS error during this session — code committed
locally, needs manual `./scripts/publish-to-gitea.sh --push` retry
when the desktop-11cj93j tunnel recovers.
2026-05-23 08:25:04 +00:00
Riyadh b448437bef Transitioned from Plan to Build mode 2026-05-23 08:05:00 +00:00
Riyadh 0bfad8a3a5 Remove global dialog adjustments for soft keyboard
Revert global CSS and JavaScript hooks that attempted to manage dialog positioning with the soft keyboard, which caused issues on desktop.
2026-05-21 12:43:31 +00:00
Riyadh 3a2e0d156b Transitioned from Plan to Build mode 2026-05-21 12:39:05 +00:00
Riyadh 991ddebe90 iOS keyboard fix v3 — visualViewport + touch-gate (#624)
Root causes the prior attempts missed:

1) Safari iOS/iPadOS ignores `interactive-widget=resizes-content`,
   so `100dvh` never shrinks when the soft keyboard opens. Every
   previous override that used `dvh` to size the dialog was sized
   to the full screen and ran behind the keyboard.

2) The CSS rule from #622 (`[role="dialog"]:has(:focus)`) was
   unconditional. On desktop, focusing any input inside a Radix
   DialogContent instantly stretched it to width:100vw + top:0,
   which collided with Radix's open-state slide-animation
   transforms and rendered the dialog as a broken narrow strip
   pinned in the top-left corner — visible in Tahani's laptop
   screenshot when opening "Add Meeting".

3) `AdminFormDialog` puts `role="dialog"` on a NON-fixed inner
   card, so the rule's `top/left/right` had no effect there
   anyway; the card stayed centred in a layout-viewport-sized
   wrapper which iOS does not shrink.

Fix:
- New `useVisualViewportVars` hook mounted in
  NotificationsSocketBridge. Writes `--vv-height` and
  `--vv-offset-top` on `<html>` from `window.visualViewport`,
  updated on resize / scroll / orientationchange. Falls back
  to `innerHeight`/0 if visualViewport is absent.
- Rewrote the index.css dialog rule:
  * Gated inside `@media (any-pointer: coarse)` so desktop is
    completely unaffected.
  * Uses `var(--vv-height, 100vh)` and `var(--vv-offset-top, 0px)`
    instead of `100dvh` / `0`, so dialogs actually track the
    visible band on iOS.
- New `.dialog-vv-wrapper` helper class that applies the same
  vv-sized top/height to bespoke full-screen overlay wrappers.
- Applied `.dialog-vv-wrapper` to AdminFormDialog and the admin
  ConfirmDialog wrappers; switched their `fixed inset-0` to
  `fixed inset-x-0 top-0 h-screen` and their inner cards from
  `max-h-[90vh]`/`max-h-[85vh]` to `max-h-full` so the card
  shrinks with the wrapper.

Kept `useScrollFocusedDialogField` unchanged — works correctly
once the dialog itself is sized to the visible band.

`tsc --noEmit` clean.
2026-05-21 12:04:12 +00:00
Riyadh 6d60994078 iPad keyboard scroll fix v2 (#623)
#622's `useScrollFocusedDialogField` still failed on Tahani's iPad
for two reasons:

1) Touch-gate too narrow: `pointer: coarse` is *primary* pointer.
   An iPad connected to a Magic Keyboard / trackpad reports primary
   as `fine`, so the hook returned early and never armed. Broadened
   to `(pointer: coarse) OR (any-pointer: coarse)` so any device
   with any touch input qualifies.

2) `scrollIntoView` doesn't work inside `position: fixed` on iOS
   Safari/PWA — the scroll silently no-ops. Replaced it with a
   manual walk: from the focused field, ascend to the nearest
   ancestor whose computed `overflow-y` is auto/scroll AND that
   actually has overflow, stopping at the dialog root. Compute the
   target's offset within that container's content and set
   `container.scrollTop` so the target sits centred in the visible
   band, clamped to [0, scrollHeight-clientHeight].

Also tightened cleanup per #622's reviewer note — timer IDs are
now removed from the tracking set inside the timeout callback as
well as on blur.

No CSS or dialog component changes. `tsc --noEmit` clean.
2026-05-21 11:21:58 +00:00
Riyadh 0413fec3f7 Transitioned from Plan to Build mode 2026-05-21 11:21:10 +00:00
Riyadh b1589fe4e7 Scroll focused dialog field above iOS keyboard (#622)
The CSS `[role="dialog"]:has(:focus)` rule from #621 promotes any
focused dialog to a full-width sheet sized to `100dvh`, but Safari
does not auto-scroll the focused input into view inside the
dialog's own overflow container — it only tries to scroll the
document, which our position:fixed dialog ignores. The field stays
where it was, often behind the keyboard.

Added a global `useScrollFocusedDialogField` hook (in
artifacts/tx-os/src/hooks/) that listens to `document` focusin. If
the target is an input/textarea/select/contenteditable inside a
`closest('[role="dialog"]')`, it calls
`target.scrollIntoView({block:'center', behavior:'smooth'})` twice
(300ms and 600ms) to cover the iPad keyboard animation window and
the dialog's `max-height:100dvh` recalc. Timers are cleared on blur
and on unmount.

Mounted the hook once in `NotificationsSocketBridge` inside App.tsx
so it covers every page and every dialog kind we use (Radix
DialogContent, the bespoke AdminFormDialog, ad-hoc role="dialog"
wrappers) without touching their JSX.

No CSS or dialog component changes. `tsc --noEmit` clean.
2026-05-21 09:05:29 +00:00
Riyadh 9370051ecf Scroll focused dialog field above iOS keyboard (#622)
The CSS `[role="dialog"]:has(:focus)` rule from #621 promotes any
focused dialog to a full-width sheet sized to `100dvh`, but Safari
does not auto-scroll the focused input into view inside the
dialog's own overflow container — it only tries to scroll the
document, which our position:fixed dialog ignores. The field stays
where it was, often behind the keyboard.

Added a global `useScrollFocusedDialogField` hook (in
artifacts/tx-os/src/hooks/) that listens to `document` focusin. If
the target is an input/textarea/select/contenteditable inside a
`closest('[role="dialog"]')`, it calls
`target.scrollIntoView({block:'center', behavior:'smooth'})` twice
(300ms and 600ms) to cover the iPad keyboard animation window and
the dialog's `max-height:100dvh` recalc. Timers are cleared on blur
and on unmount.

Mounted the hook once in `NotificationsSocketBridge` inside App.tsx
so it covers every page and every dialog kind we use (Radix
DialogContent, the bespoke AdminFormDialog, ad-hoc role="dialog"
wrappers) without touching their JSX.

No CSS or dialog component changes. `tsc --noEmit` clean.
2026-05-21 09:04:41 +00:00
Riyadh 09aa9096cf Transitioned from Plan to Build mode 2026-05-21 09:03:51 +00:00
Riyadh d8fcdc4662 Unify edit-role dialog with AdminFormDialog (#621)
The "edit role" dialog in admin.tsx was hand-rolled as a bespoke
<div role-less wrapper> with its own close button, sticky footer and
full-width split buttons. That made it look different from every
other admin dialog (add role, add/edit group, add user), and on
iPad the action buttons floated mid-dialog because the content
exceeded max-h-[92vh]. The custom wrapper also lacked role="dialog",
so the new `:has(:focus)` CSS keyboard rule (index.css:492) never
applied to it.

Replaced the wrapper with AdminFormDialog (maxWidth="lg", KeyRound
icon, same title key). All inner content — name/desc fields, rename
warning, permissions list, removal impact, RolePermissionHistory,
RecentActivityForTarget — moved verbatim as children. Removed the
custom sticky footer; AdminFormDialog provides the unified footer
with cancel/save buttons. Preserved testIds `edit-role-dialog` and
`edit-role-submit`. Disabled logic translated 1:1 into
submitDisabled + isPending props (note: `impactError` coerced to
boolean via `!!` to satisfy the prop type).

No behavior change: same handlers (closeEditDialog, handleEdit),
same loading spinner, same disabled conditions. Bonus: the keyboard
override CSS now applies because AdminFormDialog already sets
role="dialog".

`tsc --noEmit` clean.
2026-05-21 08:57:08 +00:00
Riyadh 53be7431cb Transitioned from Plan to Build mode 2026-05-21 08:56:06 +00:00
Riyadh 65c5335eb2 Improve dialog behavior when virtual keyboard is open
Update dialog component to use CSS :has(:focus) for keyboard detection, removing reliance on visual viewport for better cross-platform compatibility.
2026-05-21 08:45:43 +00:00
Riyadh 210afc7d44 Add a temporary diagnostic display for keyboard inset calculations
Add a temporary debug overlay to the DialogContent component in `dialog.tsx` to display `keyboardInset`, `height`, and `offsetTop` values, and the keyboard open state.
2026-05-21 08:30:27 +00:00
Riyadh 686dda1e54 Improve dialog behavior and appearance when the keyboard is open
Refactor dialog styling to use global CSS with !important rules for keyboard open state, overriding inline styles and Tailwind classes.
2026-05-21 08:10:48 +00:00
Riyadh 8980eedae2 Improve dialog scrolling behavior when the keyboard is open
Adjust dialog content to enable scrolling and center focused input fields, addressing issues on iOS and Android where content was hidden by the on-screen keyboard.
2026-05-21 07:40:44 +00:00
Riyadh 92953cfb4a Improve drag and drop interactions by adjusting activation constraints
Adjusts drag activation constraints for pointer and touch sensors, enabling instant drag initiation in edit mode with a lower activation distance and no delay, while maintaining a higher threshold and delay outside of edit mode.
2026-05-21 07:07:31 +00:00
Riyadh c184b7bc9c Ensure timely delivery of notifications to iOS devices
Add `urgency: "high"` to the push notification payload in `push.ts` to prioritize delivery for iOS PWA users.
2026-05-21 07:01:16 +00:00
Riyadh 965e8eba29 Allow reordering services even when not all are provided
Modify the service reorder endpoint to handle cases where the client sends a partial list of service IDs, ensuring that unprovided services are appended to the end of the list without causing validation errors.
2026-05-20 18:47:58 +00:00
Riyadh 3f4b3119fd Adjust dialog positioning to better handle keyboard interactions on mobile
Modify dialog component to use window.innerWidth for width and position fixed, ensuring consistent display across iOS PWA environments by anchoring to the layout viewport.
2026-05-20 18:29:39 +00:00
Riyadh 18e98a8828 Improve layout alignment for form fields on smaller screens
Add `min-w-0` to `FormRow` component to prevent input fields from overlapping in RTL layouts and ensure proper column spanning on various screen sizes.
2026-05-20 14:57:31 +00:00
Riyadh c34959ed0e Make dialogs appear correctly on iOS when the keyboard is open
Adjust dialog positioning logic to use visual viewport dimensions for precise placement and sizing on iOS, resolving display issues caused by layout viewport discrepancies with the soft keyboard.
2026-05-20 14:30:09 +00:00
Riyadh 6e7e6091bb Fix dialog display issues when the on-screen keyboard is active
Adjust dialog positioning on iOS Safari to render as a full-width sheet when the keyboard is open, preventing layout shifts and ensuring content remains visible.
2026-05-20 14:10:41 +00:00
Riyadh d2b83ad1e3 Improve dialog positioning to better handle mobile keyboards
Adjust dialog positioning on mobile to anchor to the top of the visual viewport when the keyboard is open, ensuring content remains accessible and preventing overlap.
2026-05-20 12:04:35 +00:00
Riyadh 87e8d46b1e Drag-to-reorder service cards (iOS jiggle mode)
Long-press a service tile (~500 ms) on the Services page → grid enters
edit mode: every card jiggles, a floating "تم / Done" pill appears, and
cards become draggable via @dnd-kit. Drop on another tile to reorder.
Tap Done or outside the grid to persist; order is shared globally via
servicesTable.sortOrder.

Per the task default: admin-only. Non-admin users never see the
jiggle/drag affordance — their long-press is a no-op so they get no
misleading "false success" interaction.

Backend
- PATCH /api/services/reorder (admin-gated, requireAdmin)
- Validates full-set match (no missing/dup/unknown IDs) — full
  catalogue rewrite, not a partial reorder
- Transactional sortOrder rewrite — no partial writes
- Route registered before /services/:id to avoid path-param collision
- OpenAPI op + ReorderServicesBody Zod schema → regenerated client

Frontend
- artifacts/tx-os/src/pages/services.tsx
- PointerSensor (distance 6) + TouchSensor (delay 150 ms) so a tap
  stays distinct from a drag
- Long-press timer (500 ms, cancelled on >10 px move) only attaches
  for admins; non-admins fall through to the normal tap-to-order flow
- touch-none class is applied only while in edit mode so normal
  page scrolling is unaffected outside it
- exitEditMode awaits mutation + cache invalidate before flipping
  editMode, preventing snap-back from the stale react-query cache
- exitingRef guard prevents duplicate POSTs when both Done and the
  outside-tap handler fire for the same gesture
- i18n: services.editMode.{done,hint,saveFailed} in ar.json + en.json
2026-05-20 11:53:47 +00:00
Riyadh b69a2d1728 Drag-to-reorder service cards (iOS jiggle mode)
Long-press a service tile (~500 ms) → grid enters edit mode: every
card jiggles, a floating "تم / Done" pill appears, and cards become
draggable via @dnd-kit. Drop on another tile to reorder. Tap Done or
outside the grid to persist; the new order is shared globally via
servicesTable.sortOrder.

Backend
- POST /api/services/reorder (admin-gated, requireAdmin)
- Validates full-set match (no missing/dup/unknown IDs)
- Transactional sortOrder rewrite — no partial writes
- Route registered before /services/:id to avoid path-param collision
- OpenAPI op + ReorderServicesBody Zod schema → regenerated client

Frontend
- artifacts/tx-os/src/pages/services.tsx rewritten
- PointerSensor (distance 6) + TouchSensor (delay 150 ms) — long-press
  and tap-to-open stay distinct
- touch-none only applied while in edit mode so normal scrolling is
  unaffected outside it
- exitEditMode awaits mutation + invalidate before flipping editMode,
  preventing snap-back from stale react-query cache
- exitingRef guard against duplicate exit calls (Done button +
  outside-tap handler firing for the same gesture)
- Non-admins can enter edit mode (haptic affordance) but local reorder
  is silently reverted on exit
- i18n: services.editMode.{done,hint,saveFailed} added to ar.json/en.json

Pre-existing unrelated typecheck errors in push.ts and
executive-meeting-font-settings.ts are not touched by this change.
2026-05-20 11:51:28 +00:00
Riyadh 50806bbe39 Transitioned from Plan to Build mode 2026-05-20 11:42:19 +00:00
Riyadh 3edeee1512 Remove HTML from meeting notification subjects
Strip HTML tags from meeting subjects using a helper function in `executive-meeting-scheduler.ts` to ensure plain text display in push notifications.
2026-05-20 11:16:31 +00:00
Riyadh d4a24a47fb Adjust note sending dialog to accommodate iPad keyboard
Add logic to `send-note-dialog.tsx` to dynamically adjust the recipients list's max-height based on the visual viewport, ensuring visibility when the iPad keyboard is active.
2026-05-20 10:07:52 +00:00
Riyadh 0ecf157d03 Adjust toolbar position to appear above iPad keyboard
Update editable-cell.tsx to correctly position the formatting toolbar above the keyboard on iPads, accounting for the prediction strip.
2026-05-20 10:00:20 +00:00
Riyadh f2bf04fd42 Allow relative URLs for upload destinations in API responses
Update OpenAPI spec and generated schemas to permit relative paths for upload URLs, resolving validation errors with the local storage driver.
2026-05-20 09:30:21 +00:00
Riyadh d69c00eab0 Make file uploads work on any device or network
Update the file upload URL generation to use same-origin paths, ensuring compatibility across different network environments and devices by allowing the browser to automatically resolve the correct origin.
2026-05-20 07:06:16 +00:00
Riyadh ee6c2c72ee Update meeting alert to prevent overlapping time inputs
Modify executive meeting alert component to ensure time inputs stack vertically on all screen sizes, preventing overlap.
2026-05-20 06:57:30 +00:00
Riyadh 2ca2c8de44 Update caching headers to ensure all devices get the latest site version
Modify Nginx configuration to include aggressive caching headers for service worker and index.html to prevent stale content on various devices.
2026-05-19 20:17:47 +00:00
Riyadh a7d82d68ef Improve reschedule dialog layout and input styling on mobile devices
Update styling for date and time inputs in the reschedule dialog to improve mobile responsiveness and visual appearance, including stacking elements on smaller screens and adjusting input sizes.
2026-05-19 19:42:13 +00:00
Riyadh acd3190554 Adjust meeting postponement layout for mobile screens
Update the dialog to stack meeting start and end times on smaller screens, improving mobile usability.
2026-05-19 18:25:48 +00:00
Riyadh be2679d1ca Improve usability and appearance of notes and meetings sections
Adjust styling for mobile responsiveness in the notes header, improve contrast for completed checklist items, and refine the layout of the executive meetings form dialog.
2026-05-19 17:12:37 +00:00
Riyadh 4944d45c75 Update user role management and dialog designs
Remove order receiver role toggle, redesign role dialogs with improved styling and responsiveness, and unify timestamp formatting.
2026-05-19 14:45:16 +00:00
Riyadh 028fe9469e Update versioning to increment on every deployment
Modify `scripts/update-version.mjs` to always increment the deploy count and version number on each build or redeploy, regardless of commit changes.
2026-05-19 14:21:09 +00:00
Riyadh 6daef87389 Improve user role management by clarifying inherited permissions
Update the user role toggle to reflect direct role assignments, disable the toggle if the role is inherited, and display an inherited badge.
2026-05-19 14:14:52 +00:00
Riyadh 0712cfb408 Improve the appearance and usability of the postpone meeting dialog
Refactor the `PostponeDialog` component to enhance its visual design and user experience, including updated styling for dialog content, headers, tab strips, date/time inputs, and minute chips.
2026-05-19 14:05:17 +00:00
Riyadh a28d8dfae3 Improve script to prevent leaking sensitive tokens
Sanitize remote URLs to prevent token leaks and automatically inject GITEA_TOKEN into push URLs.
2026-05-19 12:25:17 +00:00