131 Commits

Author SHA1 Message Date
Émile Ré
afdf0aacc7 Show locale mismatch banner for visitors
Visitors have no Identity.locale, so the banner now falls
back to a supported navigator language match and omits the
persist action. Unsupported browser languages stay silent
instead of pretending English is preferred.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-31 11:53:58 +02:00
Émile Ré
4d8d26aad2 Split Link/Anchor from button navigators
Rename button-styled Link/Anchor to ButtonLink/
ButtonAnchor and add underlined text Link/Anchor
so names match look and element. Hero meta uses
plain Anchors for contact and custom links.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-31 10:59:20 +02:00
Émile Ré
93818d8292 Polish portal banner actions and alignment
Prefer the saved locale as the primary CTA, soften secondary
and NDA actions, tint dismiss hovers to the banner palette,
and center the leading icon with the message.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:28 +02:00
Émile Ré
2c52360bd6 Use Sign for the NDA page CTA
The button is on the review page itself, so Review and sign
is redundant. Console keeps its own reviewAndSign key.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:28 +02:00
Émile Ré
404b9e347a Extract shared Banner for portal notices
Locale and NDA notices shared layout chrome but were not kit
Callouts. Pull the full-bleed band into Banner and rename the
feature wrappers so the names match the role.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:28 +02:00
Émile Ré
51ba02cedd Differentiate portal callout colors and width
When both banners stack they read as one band if they share
gold. Use sky (info) for locale and amber (warning) for NDA,
and keep content inside the same max-w-5xl column as TopBar.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:28 +02:00
Émile Ré
1e8690aaae Extract locale mismatch callout variants
Match the unsigned-NDA banner layout: keep layout classes in
tv slots so the callout shell stays free of raw utilities.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:27 +02:00
Émile Ré
7f7c836e57 Show unsigned NDA banner in the portal shell
Signed-in users with an incomplete portal NDA need a clear
path to review and sign without waiting for a private
document export to fail the gate.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:27 +02:00
Émile Ré
312cb67106 Add Documents back link on the NDA gate
Match the document viewer header so users can leave without
signing, returning to the list instead of the continue URL
that would re-trigger the gate.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:27 +02:00
Émile Ré
c96bf22e1c Handle auth gates in every portal mutation
Mutations never reach route error boundaries, so each call
site reimplemented sign-in / full-name / NDA redirects.
Consume those gates in the shared useMutation notifier and
drop the duplicated handlers.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:27 +02:00
Émile Ré
693ee7002b Redirect viewer export to the NDA gate
Document export is a mutation, so NDA_SIGNATURE_REQUIRED never
reaches the route boundary. Catch it in the export hook, stop
re-firing on mutate identity churn, and match gate errors by
name when instanceof fails across package copies.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-30 17:21:26 +02:00
Émile Ré
b2e2d15582 Share copy-link helper and fix UK plurals
List rows and the viewer toolbar used the same clipboard
toast path; Ukrainian moreRegions needs one/few/many forms.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:55 +02:00
Émile Ré
b0ad5796b6 Portal drawer selects onto the viewport
The swipe Popup keeps a CSS transform that re-roots
position:fixed, so Base UI's modal inert cutout missed
the locale trigger and blocked hover and clicks.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:55 +02:00
Émile Ré
72ca18e204 Extract document viewer toolbar component
Keeps DocumentViewer focused on layout and preview state, and
gives the page/zoom/copy/download chrome its own home.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:55 +02:00
Émile Ré
e9d0825b5e Keep document title on locked viewer
Unauthorized visitors still need the document identity and a
way back to the list; only the preview toolbar is withheld,
with the access CTA replacing the file body.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:55 +02:00
Émile Ré
98e1177aab Label document share as copy link
Sharing only copies the viewer URL, so rename the action and
expose the same control on each documents list row.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:55 +02:00
Émile Ré
5469a960e2 Truncate long country lists with a popover
AWS-scale region lists blew out subprocessor cards. Cap the
visible labels and open the rest from a +N trigger using a
new Base UI Popover in the v2 kit.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:55 +02:00
Émile Ré
69721c6afd Stretch Trusted by tiles to equal row height
When a reference name wraps to two lines, sibling cards in the
same grid row stayed shorter because MediaTile only sized to its
content. Fill the grid cell and grow the caption so peers match.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:54 +02:00
Émile Ré
1d19879b51 Add in-tab display mode toggle for users
Let signed-in visitors override the OS color scheme from
the account menu without persisting across reloads, and
keep themed logos in sync with the effective mode.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:54 +02:00
Émile Ré
7c6ab85916 Stack TopBar brand and shorten nav labels
Long nav copy was squeezing the entity name into an
ellipsis inside max-w-5xl. Stack name over the tagline,
hide brand text below lg, and shorten the longest
topBar.nav strings so the brand stays readable.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:54 +02:00
Émile Ré
b1b23988fc Show locale code in guest language select
Full language names (e.g. Bahasa Indonesia) made the
guest top-bar control too wide next to Get access.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-29 18:53:54 +02:00
Émile Ré
1e79755121 Derive selection count from live locked rows
The bar read the raw selection size for its count, so after a request
succeeded and Relay flipped the rows to pending the left count stayed
stale while the action count dropped to zero. Resolve the selection
against the current rows instead, so requested rows leave the count at
once and the bar closes without depending on a clear that may not run.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:21 +02:00
Émile Ré
d0c9327e99 Require explicit portal access request IDs
Drop the request-all shortcut so callers always name the
documents, reports, and files to request. TopBar Get Access
now only signs in; bulk selection is the multi-resource path.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:21 +02:00
Émile Ré
baa5a3588a Lock only document rows without an access record
The bulk request skips any id that already has an access record, so
rejected or revoked rows reported success while creating nothing. Treat a
row as requestable only when the viewer is unauthorized and no access
record exists yet, keeping the selection CTA count honest.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:21 +02:00
Émile Ré
d2638a3d78 Extract selection bar styles into a tailwind variant
The bottom selection action bar carried its layout as inline class
strings on the container divs. Move them into a slotted tv in the
documents variants module, matching the documentsLayout pattern, so the
component consumes named slots instead of ad hoc className literals.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:20 +02:00
Émile Ré
1d6218cb7d Disable row selection for non-lockable documents
Public / already-authorized and already-requested rows could be ticked
even though they never contribute to "Request Access (N)", making the
selection count look inconsistent with the CTA. Restrict selection to
locked rows: their checkbox is disabled otherwise, and "Select all" now
picks only the lockable rows.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:20 +02:00
Émile Ré
9353d85d03 Add bulk request access to portal documents
Visitors could only request access to one document, report, or file at
a time. Add row checkboxes and a bottom selection toolbar to the
compliance portal documents page so a visitor can select several rows
and request access to all still-locked ones in a single round-trip.

Expose a selection-scoped requestAccesses mutation that forwards the
chosen id lists to the existing RequestPortalAccess service (one
transaction, one NDA/auth gate). The resolver loads and tenant-checks
every target before requesting so a foreign id is rejected before any
access row is written, and echoes the affected nodes so the client
flips each row to pending in place.

Add a styled Base UI Checkbox to the v2 kit, a local selection context
shared by the independent row fragments, and mirror the new selection
strings across all locales.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-27 18:27:20 +02:00
Émile Ré
0f7b639d2f Freeze backdrop pose when the pointer leaves
Leaving mid-ease left the 150ms transition running toward the last
target; snapshot the computed transform and clear transition instead.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-22 17:42:39 +02:00
Émile Ré
0689ac7d14 Defer parallax snap until pointer is idle
Reset the enter-ease timer on each move so transition:none cannot
cut off a retargeted interpolation mid-flight.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-22 17:42:39 +02:00
Émile Ré
1fc453f839 Smooth backdrop parallax on pointer enter
The first eased frame was cancelled by the next pointermove flipping
transition to none, which snapped the blur when entering at an edge.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-22 17:42:39 +02:00
Émile Ré
87f1ee9081 Add pointer parallax to logo backdrops
MediaTile and BackdropCard share opposite-pointer blur tracking over
the full card, with Figma-matched opacity/zoom per surface, eased
enter, and a frozen pose on leave.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-22 17:42:38 +02:00
Émile Ré
397f548937 Avoid Turkish locative on dynamic names
A hardcoded 'de breaks vowel harmony for many
entity names. Use "için" instead so the hero
title stays grammatical for any {{name}}.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-22 13:08:03 +02:00
Émile Ré
cb4fb1f3f4 Align hero titles with compliance wording
Non-English heroTitle strings still used "trust"
equivalents. Switch them to each locale's IT
compliance term so they match English and the
portal tagline.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-22 13:08:02 +02:00
Émile Ré
0d832508c9 Replace portal title with entity name
Store a short entity name instead of the full home
heading so orgs can brand portals for sub-entities.
Restore hero i18n composition and keep the English
document title composed from the entity name.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-22 13:08:02 +02:00
Émile Ré
a9a476a343 Fix mobile locale select under drawer
Select menus portal at z-3 while drawers sit at z-5, so
the popup opened behind the drawer. Portal into the drawer
panel instead. Point .env.example VITE_API_URL at the slug
subdomain with a local Vite note.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-22 12:32:01 +02:00
Émile Ré
59f053e8f9 Fix portal SEO, Korean copy, and favicon
Custom-domain base URLs included the request path, so
canonical/hreflang doubled routes; emit SEO links only with
an absolute origin. Rewrite Korean mismatch strings to avoid
literal particle parentheses, rename HtmlLang to HTMLLang, and
ship public favicons so Vite no longer 404s the fallback icon.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-21 18:50:34 +02:00
Émile Ré
418bb5a8f8 Address review feedback on portal i18n
Swallow locale mutation rejections after the toast, close the
mobile drawer on locale change, escape SEO paths, share the
IAM locale list with SEO, and finish dropping /trust leftovers.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-21 18:43:50 +02:00
Émile Ré
e4260d50d3 Drop leftover /trust path prefix handling
Portals are host-routed on slug subdomains, so SEO path
stripping and the frontend basename helper were dead code.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-21 18:43:49 +02:00
Émile Ré
87033df505 Smooth locale switches with a React transition
Schedule persist and navigate together, and defer the
mismatch banner so a one-frame URL/identity desync does
not flash during language changes from the menu.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-21 18:43:49 +02:00
Émile Ré
03252b4883 Close the menu cleanly when changing locale
Dismiss the user menu on language pick, and update the
URL together with an optimistic identity write so the
mismatch callout does not flash mid-switch.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-21 18:43:49 +02:00
Émile Ré
5d161173c8 Localize mismatch actions and polish locale UI
Render the switch-to-saved button in the identity locale,
translate remaining locale stubs, and use a checkmark for
selected dropdown radio items.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-21 18:43:49 +02:00
Émile Ré
199289b42b Polish the locale mismatch banner layout
Use a full-bleed bar with clearer actions and a stacked
mobile layout so long language labels stay usable.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-21 18:43:48 +02:00
Émile Ré
acd41b72f3 Seed identity locale from the URL when null
Signed-in viewers with no saved preference get the current
URL locale once so later unprefixed visits have a default.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-21 18:43:48 +02:00
Émile Ré
c223873e96 Put locale in compliance portal URLs
Path-segment locales make each language crawlable with self
canonical and hreflang, while identity.locale persists an
explicit choice without client storage or cookie banners.

Signed-off-by: Émile Ré <emile@probo.com>
2026-07-21 18:43:48 +02:00
Bryan Frimin
63dffe801e Store full portal titles as home headings
The UI composed "Compliance at {{name}}." via i18n while the
DB only held the org name. Persist the full heading, backfill
existing rows, and drop the unused heroTitle locale keys.

Also use clientip.Extract for NDA signing events and default
the portal base domain to probopage.localhost for local runs.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-07-21 15:44:29 +02:00
Bryan Frimin
0aec27adf5 Remove magic-link auth strings from portal locales
OAuth /initiate replaced magic-link sign-in, but eleven non-English
locale files still carried the old auth copy. Drop those keys so every
catalog matches en-US and fr-FR.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-07-21 15:44:27 +02:00
Bryan Frimin
3f6795001a Finish compliance portal rename leftovers across portal, trust, and n8n.
Update mailing list queries to currentCompliancePortal, and include regenerated console resolvers plus sorted n8n/frontend imports from the rename.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-07-21 15:44:27 +02:00
Bryan Frimin
d914cb9ac7 Rename portal and trust frontends
Update visitor-facing apps to Compliance Portal
types, hooks, and resolvers so they match the
backend GraphQL rename.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-07-21 15:44:26 +02:00
Bryan Frimin
69a7c5fca7 Port data-request feature after main rebase
Main's new compliance-portal data-request pages (rights request
submission and listing) still referenced the sign-in dialog and
package names the earlier rebase's OAuth /initiate migration and
compliancepage -> complianceportal rename had already replaced.
Gate the "New Request" button behind OAuth like the rest of the
portal and point resolvers at the flattened visitor.Service methods.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-07-21 15:44:23 +02:00
Bryan Frimin
bc128ec516 Port trust center features after main rebase
Move Emile's commitment CRUD into complianceportal management,
wire console and visitor GraphQL, and drop portal magic-link
sign-in in favor of OAuth /initiate while keeping documents,
NDA/full-name gates, and access-request resume markers.

Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-07-21 15:44:21 +02:00