Cover the new v2 kit primitives in Storybook: the Dialog (uncontrolled
trigger, controlled open state, and skeleton) and the Toaster (title-only
toasts as the common case, plus a title+description variant).
Signed-off-by: Émile Ré <emile@probo.com>
The compliance portal's "Get Access" button was inert and the portal
had no way to authenticate or request trust-center access. Add a modal
sign-in flow (magic link + OIDC) that gates the requestAllAccesses
mutation, mirroring the trust app's flow but as a dialog instead of a
full /connect page.
Introduce the two v2 UI-kit primitives this depends on: a headless
Base UI Dialog and a styled Toaster (mutation toasts had no host yet).
Wire the top-bar button to open the dialog, resume the deferred access
request once authenticated, and add standalone routes for magic-link
verification and the full-name gate.
Signed-off-by: Émile Ré <emile@probo.com>
Add a full-page viewer at /documents/:alias that resolves the aliased
node, exports its watermarked bytes, and renders them: PDFs via react-pdf
with page navigation and zoom, images inline, and a download fallback for
other file types. Unauthorized visitors see a locked state.
Wire the documents list "View" action to link into the viewer (fragments
now select alias) and drop the previous open-in-new-tab helpers, since the
viewer owns the export.
Bound MainLayout to the viewport so the top bar and footer stay fixed and
the page area scrolls on its own; the viewer then keeps its toolbar fixed
while the PDF body scrolls, matching the design.
Add the react-pdf dependency with the pdf.js worker bundled via Vite (for
CSP safety) and a headless v2 Separator kit component for the toolbar.
Signed-off-by: Émile Ré <emile@probo.com>
Fold the review feedback from the documents page work into the shared
components and helpers:
- Toaster: give the close control the kit's focus-visible ring, and wrap
the title/description in Toast.Content so stacked toasts get Base UI's
height measurement and overflow handling.
- TabsSkeleton: spread rest before the fixed aria-hidden so the
decorative subtree can't be exposed to assistive tech.
- DocumentsPage: reconcile the active tab against the tab the preloaded
query actually loaded with, so a tab change during the initial preload
no longer shows the wrong slice.
- Grouping: drop the duplicated bucketing helpers and reuse the shared
groupBy from @probo/helpers, keeping field-specific sorting/labeling in
the callers.
- Documents list items: extract a shared DocumentEntry row and a
useExportAndOpen hook so the three item components stop repeating the
export/access behavior while keeping their own fragments.
- Subprocessors skeleton: reuse SelectSkeleton/TextFieldSkeleton instead
of hand-rolled placeholders.
- useDocumentTab: derive DocumentTab and URL validation from a single
DOCUMENT_TABS source of truth.
Signed-off-by: Émile Ré <emile@probo.com>
Replace the minimal placeholder Toaster with the richer implementation
already built on compliance-portal-auth (per-type icons plus warning and
info variants, and its stories). Both branches now share the exact same
component and app-root wiring, so they converge instead of colliding
when they merge. Align App.tsx provider ordering to match.
Signed-off-by: Émile Ré <emile@probo.com>
Build the Trust Center documents page: a unified list of published
documents, uploaded files, and audit reports, grouped into category
sections. An All/Public/Private tab bar filters the list by trust
center visibility.
Expose that filter over the trust v1 API by adding a
TrustCenterVisibility enum and a shared TrustCenterVisibilityFilter
input, wiring it through the documents, audits, and trustCenterFiles
connections down to the existing coredata SQL filters. "All" keeps the
default public+private slice; the other tabs pin a single visibility.
Access controls are display-only for now (auth is handled separately):
authorized or public entries open their exported PDF via the export
mutations, requested entries show a pending state, and everything else
shows an inert Get Access affordance.
Add the v2 Tabs and Toaster kit components (Base UI headless) needed by
the page and mount a toast provider at the app root for mutation
feedback.
Signed-off-by: Émile Ré <emile@probo.com>
- Log delete failures in deleteSubscription instead of swallowing them
- Correct codex node prefix to @probo/n8n-nodes-probo.proboTrigger
- Replace unsupported codex categories with Development and Utility
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
Update webhook events now carry a top-level "updatedFrom" field
alongside "data", containing a full snapshot of the entity as it was
before the update. This lets subscribers diff old vs new state (for
example the prior membership role on user:updated) without tracking
prior state themselves. It is a complete snapshot with the same shape as
"data", not a partial diff, so consumers select whatever fields they
need. The field is omitted for non-update events.
The webhook_data table gains a nullable updated_from JSONB column, and
webhook.InsertUpdateData enqueues both snapshots; InsertData delegates to
it with a nil updatedFrom so non-update callers are unaffected. Each
*:updated emission site snapshots the entity right after load, before
mutation: obligation, third-party, user (org and SCIM flows), document,
document-version, and document-version-approval-quorum. The document
emit helpers gained an optional updatedFrom argument threaded through to
the payload.
For document-version-approval-quorum:updated the snapshot requires an
extra query, so it is now gated behind the same subscription-existence
check the emitter uses: when no subscriber is configured the load is
skipped entirely rather than running (and potentially failing the
approval) for an event nobody receives.
Add integration tests (against a real Postgres, skipped when none is
reachable) covering the updated_from round-trip, the SQL NULL behavior
when no snapshot is provided, and the no-op when no subscription matches,
plus a unit test asserting updatedFrom is omitted from the payload when
absent.
Document the new field in the probod and n8n changelogs and the n8n
README.
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
Guard ErrorBoundary against a falsy thrown value: track a separate
hasError flag and accept the caught value as unknown, so throwing null,
0, or "" still renders the fallback instead of looping back into the
failing subtree.
Add role="alert" to InlineError and ErrorState so assistive tech
announces errors that appear dynamically after a fetch or query failure.
Fix the RecentUpdatesSection doc example, which showed onRetry={reset}
with @throwOnFieldError even though reset cannot clear a field error;
use a reload and point to the retry table.
Signed-off-by: Émile Ré <emile@probo.com>
Introduce global, page, and section-level error handling for the
compliance portal so a failure is contained at the smallest possible
scope instead of blanking the whole page.
Add a portal-local Relay fetch that throws only request-level errors
(and always redirects on UNAUTHENTICATED) while leaving field-level
errors in the response, so Relay surfaces them at the reading component
through @throwOnFieldError and the nearest boundary. Add a NotFoundError
for node __typename mismatches mapped to a not-found page.
Ship reusable v2 kit primitives (ErrorBoundary, ErrorState, InlineError)
matching the Figma global/local/inline designs, wire the bootstrap and
route boundaries, and demonstrate section and row boundaries on the home
page. Update the error-handling and relay guides accordingly.
Signed-off-by: Émile Ré <emile@probo.com>
The source headers, LICENSE files, and license metadata had drifted
apart. Align the entire project to MIT:
- Convert every source-file header to the MIT text across all comment
styles (Go, TS, TSX, JS, MJS, SQL, CSS, GraphQL, shell), including
SPDX-License-Identifier tags
- Set the root and cookie-banner LICENSE files to the MIT text with a
"MIT License" title line
- Switch the package.json license fields, Docker image label, and
cookie-banner README to MIT
- Update docs and the genmodels header generator accordingly
- Normalize copyright lines to a single format
(Copyright (c) <year(s)> Probo Inc <hello@probo.com>.): unify the
hello@getprobo.com and hello@probo.inc emails to hello@probo.com and
the comma-separated years to a hyphenated range
Genuine third-party references are intentionally left untouched: the
Lucide icon attributions (Lucide is ISC) and the trivy dependency
license allowlist.
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
readJsonObject fails when catalog files parse to null, arrays,
or other non-object roots so structural checks cannot be skipped.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Parse and check Claude and Codex marketplace catalogs for
required fields, plugin sources, and npm package name alignment.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Add ISC header to COMPATIBILITY.md, validate Claude marketplace
json, record access-review notes after API success, checksum npm
pack contents, trim dead package.json files entries, and mark
listUsers organization_id as required.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Drop empty agents/ and hooks/ directory placeholders until
those folders have real content.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Ship compliance skills and agent plugin wiring for Claude Code,
Codex, OpenCode, and Cursor via Probo MCP (OAuth 2.0). Includes
access-review and missing-signatures workflows, repo-root Git
marketplaces, validation, and npm release CI.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Forward className on PaginationSkeleton to match the kit skeleton API,
and move the Next arrow to iconEnd per the forward-arrow convention.
Size the updates list skeleton to the page size so the placeholder no
longer jumps when the loaded page renders, and dispose the detail
query on updateId change to avoid a flash of the previous update.
Signed-off-by: Émile Ré <emile@probo.com>
Cover the playground, the both/first/last arrow states that show the
reserved-slot positioning, the optional label, and the skeleton.
Signed-off-by: Émile Ré <emile@probo.com>
Build the public Updates pages in the compliance portal: a
cursor-paginated list of sent mailing-list updates and a detail view
for a single update, replacing the previous stub page.
Add a MailingListUpdate case to the trust API node resolver, guarded so
only SENT updates belonging to the current trust center's mailing list
are exposed, so the detail page can load an update by URL.
Add a Prev/Next Pagination primitive to the v2 UI kit. Page numbers are
omitted because cursor pagination cannot derive an ordinal page index;
each arrow only shows when its page exists while keeping its slot
reserved so a visible arrow never shifts position.
Relocate the shared MailingListUpdateListItem to its own component
folder and wrap each row in a link to the detail page, so both the home
recent-updates section and the list navigate to detail.
Signed-off-by: Émile Ré <emile@probo.com>
Address the review comments on the subprocessors work:
- Reject invalid category/country filter values in the Subprocessors
resolver with an INVALID error instead of relying solely on transport
coercion, so a malformed request fails fast and explicitly.
- Use pgx.StrictNamedArgs in the new distinct facet queries so missing
or extra SQL placeholders stay detectable, matching sibling queries.
- Default a nil ThirdPartyFilter at the service boundary to avoid a nil
dereference in the coredata list/count paths.
- Expose the category group label as an aria heading for assistive tech.
- Add the missing space in the Select "Selected:" story label.
Signed-off-by: Émile Ré <emile@probo.com>
The compliance-portal Subprocessors toolbar needs a dropdown filter and a
search input, which the v2 kit did not provide. Add Select (styled over
Base UI's headless select) and TextField (over Base UI's input) following
the v2 conventions: Base UI primitives, tailwind-variants/lite slots,
flat folders, bundle-safe variants, and paired skeletons. Both map the
Figma semantic colors to the Radix sand/gold token scales.
Signed-off-by: Émile Ré <emile@probo.com>
Add FERPA and PCI DSS framework datasets (controls plus light/dark
logos), their logo components, and register both in the framework
selector so they can be imported like the existing frameworks.
Co-authored-by: Antoine Bouchardy <antoine@getprobo.com>
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
The DocumentVersionSignatureFilter exposed a field named `state` that
actually filters on the signatory's profile state, which was ambiguous
next to the signature `states` field. Rename it to `profileState`
(GraphQL) / `profile_state` (MCP) across the schema, spec, resolvers,
console app, and n8n node for clarity.
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
Guard the content field against empty strings so adding it in the UI
without a value no longer sends content: "" to the API, which is not
valid ProseMirror content. This matches the existing defaultApproverIds
guard.
Also expose title, classification, and document type on the update
operation. Like content, these edit the current draft version, creating
one from the latest published version when none exists.
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
Remove the createDraftVersion document operation from the n8n node and
instead expose the document body on the update operation. Updating the
body edits the current draft version, or creates one from the latest
published version when none exists, so a dedicated draft-creation
operation is redundant.
Also correct the content field help text across the document
operations: the API expects a ProseMirror document JSON string, not
markdown.
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
The n8n marketplace review flagged the codex node field as using
the wrong identifier format. Update it to match the scoped package
name and the probo node name declared in Probo.node.ts.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Marketplace review flagged Developer Tools and Automation as
unsupported n8n codex category values. Keep Development and use
Utility per review guidance.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
The Probo node implements execute() directly, so n8n never applies
requestDefaults from the node description. Drop the dead block flagged
in marketplace review.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Replace the legacy console.getprobo.com hostnames in the n8n README
and credential default with the current regional Probo URLs.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
The n8n marketplace review requires a README in packages/n8n-node.
Document installation, Probo API credentials, and workflow examples
so users can configure the community node without reading the source.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Add a resource-oriented set of webhook events for the document
lifecycle. Each event carries the document plus only the sub-resource
it concerns (version, signature or approval).
Events:
- document.created / updated / archived / unarchived / deleted
- document.version.created / updated / published / rejected / deleted
- document.version.signature.requested / signed / cancelled
- document.version.approval.requested / approved / rejected / voided
Wires the new types through the migration, Go enum, GraphQL schema,
CLI, n8n nodes and the console webhooks settings UI.
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
Long Mermaid node labels rendered as a single constrained line, which
caused text to be clipped in risk assessment diagrams. Share a Mermaid
render configuration that enables flowchart label wrapping before layout
so nodes expand for multi-line labels.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Sacha Al Himdani <SachaProbo@users.noreply.github.com>
The n8n package could already manage webhook subscriptions through API
CRUD, but had no way to start a workflow when Probo emitted an event. A
user had to drop in the generic Webhook node, create a subscription by
hand, and verify the HMAC signature themselves.
Add a ProboTrigger node that owns the subscription lifecycle: it creates
the subscription on activation pointing at n8n's generated webhook URL,
re-checks and re-registers it if the URL drifts, and deletes it on
deactivation. The webhook handler recomputes the HMAC-SHA256 over the raw
request body and compares it constant-time against the delivered
signature, failing closed when the bytes or headers are absent.
Drop the MEETING_* event choices from the webhook create and update
operations and the CLI event list. They are not part of the backend
WebhookEventType enum, so selecting them only produced API rejections.
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
Radix can report a pointer down as outside the dialog while a
portaled select or dropdown is open. When the pointer coordinates
still fall within the dialog content bounds, keep the dialog open so
the child popup can close without discarding form state.
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
The Organization "Get Many" operation listed all viewer profiles without
filtering by state, then selected each profile's nested organization field.
Inactive profiles (e.g. unaccepted invitations) have no active membership,
so the per-org iam:organization:get authorization check failed and the whole
operation errored.
Filter profiles to ACTIVE state, matching the `prb org list` CLI behavior, so
only organizations the identity is an active member of are fetched.
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
Bump @n8n/node-cli to 0.37.1 (the `^0.24.1` range was trapping it at
0.24.x), which pulls an updated toolchain and clears the eslint@8,
glob@7, inflight, rimraf@3, @humanwhocodes/*, node-domexception and
uuid@10 deprecation warnings at the source.
Add a glob override (^13.0.6) so rimraf@6 no longer pulls the
deprecated glob@11, and trim the overrides list down to the three that
actually do work (uuid, js-yaml, glob); the rest were redundant or dead.
npm audit reports 0 vulnerabilities.
The upgraded @n8n/eslint-plugin-community-nodes rules flagged two
pre-existing issues in the Probo node, now fixed: handle
continueOnFail() in execute() and throw NodeOperationError instead of
raw Error.
The only remaining warning is @langchain/community, whose entire
package is deprecated upstream and is a hard dependency of
@n8n/ai-utilities.
Signed-off-by: Sacha Al Himdani <sacha@probo.com>
Address PR review feedback identified by cubic:
- Re-key CardInset off the Card's resolved padding (shared via context)
instead of size, so insets line up even when padding is decoupled from
size via the padding prop; padding="none" becomes a no-op.
- Give ProboLogo a default aria-label so its role="img" SVG has an
accessible name when used standalone; callers can still override it.
- Make the ProboLogo story render spread args so Storybook controls work.
Signed-off-by: Émile Ré <emile@probo.com>