Commit Graph

468 Commits

Author SHA1 Message Date
Émile Ré
f0b5a13f6f Use URL objects for API endpoint construction
Store baseUrl as URL and build endpoints with new URL(path, base).
Accept URL | string in fetchJSON to avoid unnecessary .href calls.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-20 10:52:35 +04:00
Émile Ré
ce77091e6c Add validation for preference panel and category template
Validate that <probo-preference-panel> contains <probo-category-list>
and <probo-save-button>, and that the category template includes
<probo-category-toggle> and <probo-cookie-list>.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-20 10:52:34 +04:00
Émile Ré
d802ee611f Add headless web components for cookie banner UI
Introduce Shadow DOM-based custom elements that let customers build
their own cookie banner and preference panel while the SDK validates
structural compliance and auto-renders categories/cookies from config.

Components: probo-cookie-banner (root), probo-banner, probo-accept-button,
probo-reject-button, probo-customize-button, probo-preference-panel,
probo-category-list, probo-category, probo-category-toggle,
probo-cookie-list, probo-cookie, probo-save-button, probo-settings-button.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-20 10:52:34 +04:00
Bryan Frimin
0e701ec6e9 Style
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-19 12:00:53 +02:00
Sacha Al Himdani
9c9c60d0eb Add webhook subscription MCP tools and N8N operations
Expose webhook subscription CRUD and event listing through the MCP API
(list, get, create, update, delete subscriptions + list events) and add
a new webhook resource to the N8N node with matching operations.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-17 13:14:49 +02:00
Aurélien Sibiril
6f0e150a06 Refactor sidebar with sticky collapse button
The absolute-positioned collapse button overlapped the nav items
whenever the sidebar content exceeded the viewport. With the page now
scrolling at the document level, the overlap became permanent.

Restructure the aside as a flex column: nav list in a flex-1 region,
collapse button in a sticky bottom-0 container with a border-t
separator. The button pins to the viewport bottom while scrolling and
never overlaps the items above.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-16 15:51:45 +04:00
Aurélien Sibiril
8fb688f19c Use page-level scroll in main layout
The previous layout nested two scroll regions, sidebar and main, each
with its own scrollbar. Combined with the fixed 100vh flex container,
any child overflow (notably the sidebar nav) spilled past bg-level-0
and exposed the browser's default white background -- most visible in
dark mode as a white strip at the bottom of the viewport.

Switch to a single page-level scroll: pin the header with fixed, let
the wrapper grow with min-h-screen, and drop main's internal overflow.
The drawer becomes fixed too so it stays pinned while the page scrolls
and gets an opaque background to cover scrolled content behind it.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-16 15:51:45 +04:00
Émile Ré
d63ce1f68b Fix expired queue entries persisting past MAX_AGE_MS
The flush function pruned expired entries in memory but re-read from
localStorage before writing back, so the age filter was never persisted.
Apply the age cutoff to the final write filter and remove the early
return that skipped the write entirely on full send failure.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:34 +04:00
Émile Ré
eafca11c82 Fix queue flush race condition and missing flush on cookie path
Re-read localStorage after network calls in flush() to avoid
discarding entries added by concurrent enqueue() calls. Also
call flush() in the cookie fast-path of load() so queued
consent retries are always drained.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:33 +04:00
Émile Ré
7d05d43f85 Fix review issues from automated code review
- Rename MAX_RETRIES to MAX_ATTEMPTS (3 total) to fix
  misleading naming
- Skip retry loop on caller-initiated aborts so explicit
  cancellations terminate immediately
- Preserve original script type via data-type attribute
  instead of always forcing text/javascript
- Recreate MutationObserver when consent changes so newly
  added elements use fresh consent data
- Fix package.json exports: point main at ESM bundle and
  add proper exports map with IIFE as separate entry

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:33 +04:00
Émile Ré
75996d2dd6 Tune HTTP timeouts and add localStorage consent retry queue
Reduce timeout/retry defaults (5s timeout, 2 retries, 500ms base delay)
to cap worst-case page-load blocking at ~12s instead of ~36s.

Add a localStorage-backed queue that persists failed consent POSTs and
replays them on next page load, closing the compliance gap where a
network failure could permanently lose the server-side audit record.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:33 +04:00
Émile Ré
cb438c010d Fix polynomial regex CodeQL warning
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:33 +04:00
Émile Ré
14d51b1fe4 Add consent-based element activation
Unblock scripts, iframes, images, and other resource-loading
elements marked with data-cookie-consent when their category
is consented. Uses MutationObserver for dynamically added
elements. Restricted to known resource tags with data-href
support for link elements.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:33 +04:00
Émile Ré
266446be9c Use getRandomValues for wider browser support
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:32 +04:00
Émile Ré
c887e3497f Fix copyright headers
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:32 +04:00
Émile Ré
0abde83a88 Extract visitor ID management into visitor.ts
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:32 +04:00
Émile Ré
5cdf39c4f7 Add SDK client with consent cookie caching
CookieBannerClient wraps the cookie banner REST API with
methods to load config, accept/reject/customize consent,
and manage visitor identity. Consent state is persisted in
a probo_consent cookie to skip API calls on return visits,
with version-aware invalidation and configurable expiry.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:32 +04:00
Émile Ré
5b5c671eb1 Fix build.mjs copyright
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:32 +04:00
Émile Ré
3b677d9464 Add HTTP client with retries and typed errors
Introduces fetchJSON<T> with timeout, exponential backoff
with jitter on network errors and 5xx/429, and error classes
that match the cookie banner API error shape.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:31 +04:00
Émile Ré
be1e94da71 Add @probo/cookie-banner SDK package scaffold
Introduce the boilerplate for a new public npm package that will
serve as the cookie consent banner JavaScript SDK. The package
uses esbuild to produce both an IIFE bundle (for script tag
embedding) and an ESM module. Versioning is independent from the
monorepo: CI compares package.json against npm and only publishes
when the version changes.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-16 14:56:31 +04:00
Sacha Al Himdani
ce1f2fa28c Fix Profile field name in n8n-node GraphQL queries
Rename primaryEmailAddress to emailAddress to match the Profile type
in the GraphQL schema.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-16 12:14:45 +02:00
dependabot[bot]
f9d004422f Bump dompurify from 3.3.3 to 3.4.0
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.3.3 to 3.4.0.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.3.3...3.4.0)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-version: 3.4.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-16 07:21:48 +00:00
Sacha Al Himdani
c635492f75 SOA as document: replace export with publish workflow
Statements of Applicability are no longer exported as one-off PDFs.
Instead, each SOA owns a persistent document that accumulates versions
over time, following the same publish/approve lifecycle as authored
documents.

Publishing without approvers publishes immediately; publishing with
approvers creates a draft pending approval via the existing quorum
system. SOAs can also store default approvers that are pre-populated in
the publish dialog.

The SOA is removed from the snapshot system — applicability statements
are now queried directly (snapshot_id IS NULL) rather than through
snapshot copies.

A standalone migration script (cmd/migrate-soa-snapshots-to-documents)
converts existing SOA snapshots into documents with proper ProseMirror
content, preserving version history and approval decisions.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-16 00:01:13 +02:00
Sacha Al Himdani
891bc02f3e Add document filters to MCP and n8n APIs
Align MCP and n8n document listing endpoints with the GraphQL console
API so every document filter is available across all three interfaces.

MCP:
- listDocuments: add status filter, default to ACTIVE
- listDocumentVersions: add statuses filter
- DocumentOrderField: add UPDATED_AT

n8n:
- document getAll: add query, documentTypes, classifications, status filters (default ACTIVE)
- document getAllVersions: add statuses filter
- document getAllSignatures: add states and activeContract filters

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-15 13:14:04 +02:00
Sacha Al Himdani
58c2415275 Align risk severity across views
Use the shared getSeverity helper from @probo/helpers in SeverityBadge
so the list view displays the same labels (Low/High/Critical) and
thresholds (0/5/15) as the detail view. Also fix the RisksChart legend
and getLevel thresholds to match.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-14 16:52:19 +02:00
Émile Ré
74d7d3ff25 Upgrade Relay to v20.1.1 and unify compiler config
Consolidate the two per-app relay configs (console and trust)
into a single multi-project relay.config.json at the repo root
with three projects: core, iam, and trust. Bump all relay
packages from v19 to v20.1.1 and move relay-compiler to the
root devDependencies. Replace per-workspace relay scripts with
a single root-level npm run relay command and update the
GNUmakefile, CI workflows, and docs accordingly.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-14 16:04:11 +04:00
Sacha Al Himdani
d40b114f0f Add document resource to n8n node and MCP sendSigningNotifications tool
Add a complete document resource to the n8n node with 21 operations
covering documents, versions, and signatures — matching the MCP
specification. Also add the sendSigningNotifications tool to the MCP
API for triggering pending signature reminders.

n8n operations: create, get, getAll, update, delete, archive,
unarchive, getVersion, getAllVersions, createDraftVersion,
updateVersion, deleteDraftVersion, publishMajorVersion,
publishMinorVersion, requestApproval, voidApproval, getSignature,
getAllSignatures, requestSignature, cancelSignature,
sendSigningNotifications.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-13 17:31:06 +02:00
Sacha Al Himdani
ab5f42ad74 Redesign document approval flow
Replace the per-approver add/remove model with a quorum-based approval
system. Documents now have default approvers that are pre-populated when
requesting approval, and the publish dialog lets users adjust the list
before submitting.

Key changes:

- Add PENDING_APPROVAL document version status with dedicated transitions
- Introduce approval quorums with request/approve/reject/void lifecycle
- Add default approvers per document (stored in document_default_approvers)
  with MERGE-based upsert for efficient sync
- Add NoDuplicates validator for slice fields
- Split ALTER TYPE ADD VALUE migrations into separate files (required by
  PostgreSQL when run inside transactions)
- Use VOIDED consistently for both quorum status and decision state enums
- Expose void/approve/reject through GraphQL and MCP, with e2e tests
- Add approval management UI: publish dialog with approver selection,
  approval list with void support, and external approve/reject page

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-09 18:18:30 +02:00
Sacha Al Himdani
5fd580e995 Rename State of Applicability to Statement of Applicability
Rename the entity across the full stack: database table
(states_of_applicability → statements_of_applicability), Go model,
GraphQL types, MCP specification, CLI commands, frontend components,
routes, and display labels. Includes a migration to rename the table
and its foreign key column.

Widen sidebar from 260px to 280px to fit the longer label.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-09 13:06:06 +02:00
Émile Ré
16d4e462c8 Add list keymaps to handle backspaces
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-07 17:13:33 +04:00
Émile Ré
0f674d1980 Better handle list transformation
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-07 17:13:33 +04:00
dependabot[bot]
f4a7eb1a16 Bump vite from 7.3.1 to 7.3.2
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.3.1 to 7.3.2.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.3.2/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.3.2
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-07 11:17:05 +00:00
Émile Ré
9b473b27c2 Fix invisible drag line on Safari
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-06 19:18:09 +04:00
Émile Ré
e4dbf9e2bb Remove --max-warnings from lint scripts
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-06 13:33:51 +04:00
Émile Ré
d82ff8267e Revert change to allow for relative links
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-03 17:21:47 +04:00
Émile Ré
9ebb86ab37 Review fixes
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-03 17:11:48 +04:00
Émile Ré
b9d7beb22c Change import for bullet list in rich editor
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-03 17:07:35 +04:00
Émile Ré
5359fe9931 Update rich editor style to be lighter and closer to printed doc
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-03 17:02:42 +04:00
Émile Ré
6d1a7c846d Add bottom padding to rich editor
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-03 17:02:42 +04:00
Émile Ré
f2c39d1741 Update markdown detection to avoid regex
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-03 17:02:42 +04:00
Émile Ré
0ac3fd1f75 Handle html in markdown during conversion to prosemirror nodes
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-03 17:02:42 +04:00
Émile Ré
2a6845d884 Reimplement ts converter using marked parser
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-03 17:02:42 +04:00
Émile Ré
a850b0f77c Move markdown to prosemirror parser in packages
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-03 17:02:41 +04:00
Émile Ré
3561a6e0b7 Implement markdown parsing for copy paste
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-03 17:02:41 +04:00
Sacha Al Himdani
8adf26ad20 Add in-progress state to tasks
Introduce IN_PROGRESS as a new task state between TODO and DONE across
the full stack: database enum, Go backend, GraphQL, MCP, and frontend.

The task state icon now cycles forward on click (TODO → IN_PROGRESS →
DONE → TODO), and the action dropdown provides explicit "Move to"
options for any state transition. The "All" tab supports drag-and-drop
between state sections to change a task's state.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-03 08:33:37 +02:00
Sacha Al Himdani
9a418a7711 Move document type from document to document version
Follow the same pattern used for classification: document type now lives
exclusively on DocumentVersion. A migration copies existing values from
documents to their versions. The document filter uses a subquery on the
latest version. All three API surfaces (GraphQL, MCP, CLI), resolvers,
frontend, and e2e tests are updated accordingly.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-02 16:32:38 +02:00
Aurélien Sibiril
b396359162 Add access review frontend
Add campaign and source management pages with detail
views, bulk decision and flag controls, connector
provider dialog with OAuth/API-key/client-credentials
flows, vendor logos, shared helpers, and campaign
lifecycle UX (start, complete, cancel).

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-04-02 14:37:29 +02:00
Sacha Al Himdani
324f4ce793 Add task priority enum and rename priority to rank
The existing integer priority field represents positional ordering
within a state, not semantic importance. Rename it to rank and
introduce a new priority field with enum values URGENT, HIGH,
MEDIUM and LOW across the entire stack.

Rank is now scoped to (state, priority) so tasks are ordered
within each priority group. A generated priority_rank column
combines both fields into a single sortable integer for cursor
pagination.

Dragging a task across priority groups updates its priority
automatically based on the drop position neighbors. The backend
first moves the task to the new group then repositions it at the
target rank.

The migration defaults existing rows to MEDIUM priority and
backfills ranks per (state, priority) group.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-04-02 13:35:39 +02:00
Bryan Frimin
a2f0a37b7b Add UNKNOWN and NOT_IMPLEMENTED measure states
Introduce two new measure states across the full stack: database
migration, Go coredata, GraphQL schema, MCP specification, and
frontend UI (labels, badge variants, and colors).

Signed-off-by: Bryan Frimin <bryan@getprobo.com>
2026-04-02 10:59:25 +02:00
Émile Ré
821f66cc20 Review fixes
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-04-01 19:53:25 +04:00