Commit Graph

7 Commits

Author SHA1 Message Date
Maurice 9e216f5ae4 fix(docsync): let the trip owner edit or remove a stored document-store connection
Once a store was connected for a trip, its address and login could only be
entered again after a sync run had been refused, and the stored connection
could not be removed at all: the server's DELETE route had no way in from the
app. A binding's settings now open the connection at any time, the folder
picker leads back to it before a folder is chosen, and the connection form
removes a stored connection after a confirmation, on the desktop panel and the
phone sheet alike. Removing it drops the trip's bindings through it; documents
stay on both sides.

Closes #2842
2026-10-27 14:45:17 +01:00
Maurice 74e1853c39 refactor(docsync): share the scope picker, lane switch and folder name between desktop and phone
useScopePicker holds the provider's containers, binding one, and making
and binding a new one under the suggested name; the desktop dialog keeps
its search filter. docSyncModel holds the direction a lane switch leads to
and the folder name made from the trip title, which the panel and the
phone sheet each carried a copy of.
2026-10-09 15:19:43 +02:00
Maurice ba70ad28b8 fix(client): spacing and alignment follow the reading direction
Arabic runs the app right to left, but margins, paddings, insets, text
alignment, borders and corner radii were written for the left side, so
icons sat against the wrong edge of their labels, indents and badges
pointed the wrong way and amount columns aligned left. They now use the
logical forms (ms-, ps-, start-, text-start, marginInlineStart,
insetInlineEnd and their CSS equivalents), which are the very same sides
in a left to right language. Geometry stays physical on purpose: maps,
positions measured from the pointer or a bounding box, time axes,
sliders, transforms and print output.

Amounts drawn as several spans keep their order in a right to left row,
the time picker keeps hours before minutes, and two switches whose thumb
slid out of its track in Arabic now move the right way.

lint:rtl counts what is still physical per file against a baseline that
may only shrink (1512 uses in 370 files before, 319 in 113 now), and CI
runs it, so new code reaches for the logical forms.
2026-10-07 22:33:58 +00:00
Maurice 0dd07befa7 feat(planner): bring the plan tab and every trip dialog into the new look
The Plan tab was the last trip tab still in the old design. It now reads
like Bookings, Costs, Lists, Files and Collab, without losing a function:

- Day plan: each day is a card with a head band (day tile with weather,
  stay and rental pills, a "+" menu for place, stay, transport, transit
  and note), rows with "..." menus, white badges and a white route bar.
- Places column: add, search and filters in three rows, a show dropdown,
  category and rating filters, and a selection bar at the foot.
- Place inspector, day details and the stay editor on the shared dialog
  frame; the place form in the editor look with the name in the head band.
- Clicking a booking or transport anywhere on the plan opens the booking
  detail popup first; Edit leads to the editor. The popup is one host
  shared with the Bookings and Transports tabs.
- Files and Collab dialogs, notes, polls, links and chat moved to the same
  frame; shared DialogShell and dialogParts hold the building blocks.
- The map hover card shows the place photo and follows the theme.

Every new and reworded string is translated into all locales, and a few
older English leftovers (help center, cost split, import hints) with them.
Phone screens keep their own look.
2026-09-27 21:00:19 +02:00
Maurice 843582863c fix(docsync): offer the sync button only where something is behind it
The Documents addon put a "Document sync" button on every trip's Files
tab, and the seed ships every provider switched off, so after the
upgrade each of those buttons led into "No document providers are
available". The button now shows on a trip that is already bound, to
every member, and otherwise only to somebody who may bind the trip on
an instance that offers a provider. Without it the Files toolbar is
the one from before the feature, trash flush right, on both shells.

/api/addons carries no document providers for a normal user, so the
answer comes from the docsync routes through a new online-only
docSyncRepo and is kept per session in docSyncOfferStore. A revisit
renders the last answer at once and checks it again; offline nothing
is asked and the last answer stands. Creating a binding, removing one
and removing a connection now ping the trip with docsync:changed and
zero counts, so a member already on the Files tab sees the button come
and go without leaving it.

Both shells keep listing a binding whose provider the admin has since
switched off instead of claiming there are no providers, and name its
store through one storeName() helper. A load that answers 403 or 404
clears the bindings as well, so they do not linger once the Documents
addon is gone.

The phone admin screen gets the Documents shelf the desktop one has:
the document providers as sub rows under the addon, toggled through the
same admin route and re-read after Documents itself is toggled, because
the server switches the providers off with it.

isTripOwner and the isOwner prop become canManageSync and canManage,
which is what canManageDocSync answers. Both folder pickers take
loadScopes out of the sync object before their effect, so
exhaustive-deps is satisfied without the effect running on every
render.
2026-09-19 13:36:33 +02:00
Maurice 9f531d1cd9 feat(docsync): make the conflict answer real and give a conflict a way out
The binding asked at setup what should happen when both sides changed, stored
the answer, and nothing ever read it: every conflict was manual whatever the
binding said. The planner now acts on it — provider_wins pulls, trek_wins
pushes, anything else parks the row — and never in the direction the binding
forbids.

Conflicts themselves had no exit in either shell. The server has resolved them
since the first version and the strings have been in the locales just as long,
but neither the panel nor the phone sheet ever listed the rows, so the only way
to answer one was the MCP tool. Both shells now list them through one shared
hook with the same three answers.

Also:
- The desktop connect dialog shows a refused save instead of looking as though
  nothing happened.
- An error the server phrases as a sentence no longer reaches the screen as a
  raw translation key.
- The scope pickers depend on the stable callback rather than the hook object,
  so opening one no longer re-lists the provider's folders on every render
  above it.
2026-09-19 00:57:57 +02:00
Maurice 1430056d24 fix(docsync): read the retry limit back out, debounce the webhook, and cover the UI
The attempt counter and the backoff were written on every failure and never
consulted when planning the next run: rows were found in a live database at 46
attempts against a limit of 6, so a document a provider refuses — one it reads
as corrupt, a type it will not take, a full quota — was re-uploaded on every
cron tick forever. planReconcile now skips a row that is shelved or still inside
its window, and a manual run clears the counters, which is what "waits for a
person" has to mean.

The webhook had the same shape of bug: WEBHOOK_NUDGE_DEBOUNCE_SECONDS existed,
with a comment explaining it, and nothing read it. Providers fire once per
document, so twenty files dropped into a watched folder were twenty runs — the
in-flight guard answered `busy` to nineteen of them, throwing away nineteen
announcements, and the one run that did start had begun before most of the
changes landed. A burst now folds into one trailing run, and the binding is
re-read when the timer fires so a sync switched off in between does not get a
last run out of a stale row.

Four defects the new suites turned up, all fixed: the sync button lost its
accessible name below sm, where its label is hidden; the stored address was
never shown in the connect dialog although the form kept submitting it; the
allow-self-signed switch only read the connection at mount, so a stored "on"
showed as off and the next save wrote that back; and a refused folder create
escaped as an unhandled rejection with nothing said to anybody.

Also here: the phone shell gets the same feature (one sheet, four views, the
same hook as the desktop), the marks come from the product's own icon files
rather than redrawn approximations, and the 22 non-English locales carry the
new keys.

ADMIN-SVC-069 asserted that `documents` has no MCP surface. It does now, so the
test takes its example from MCP_GATED_ADDON_IDS instead of naming one.
2026-09-18 22:44:45 +02:00