Commit Graph

1243 Commits

Author SHA1 Message Date
Aurélien Sibiril
06f3f8aecf Add Okta logo and API-key dialog mapping
Add the Okta brand mark to the ThirdParties atoms (export, logo map,
and ThirdPartyLogo wiring) and map the generic "domain" extra setting
to the oktaDomain field in the add-access-source dialog so the
API-key connect flow submits the org domain.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-06-04 19:23:26 +02:00
Bryan Frimin
fca7f2a1e6 Fix login redirect password only
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-06-04 14:37:37 +02:00
Aurélien Sibiril
929bf81161 Add Datadog region selector to connect dialog
Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-06-03 17:16:26 +02:00
Aurélien Sibiril
b4e6f73b78 Merge PostHog self-hosted into a single PostHog provider
Fold POSTHOG_SELF_HOSTED into POSTHOG: one provider now covers Cloud (OAuth + region-pinned API key) and self-hosted (API key + instance URL), since both already share the driver, name resolver, and PostHogConnectorSettings{BaseURL}. The API-key form picks a deployment (Cloud US/EU or self-hosted URL); the resolver requires exactly one of region/instanceUrl.

Drop the POSTHOG_SELF_HOSTED enum value, registration, migration, and logo mapping. Extract the deployment selector into a dedicated PostHogDeploymentField component. Point the driver tests at us.posthog.com instead of the legacy app.posthog.com host.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-06-03 17:00:07 +02:00
Aurélien Sibiril
760f950a48 Simplify PostHog region select rendering
Replace the nested ternary in the extra-settings map with an
early-return body and a shared setter, so the region select and the
free-text field each read cleanly.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-06-03 17:00:07 +02:00
Aurélien Sibiril
836fbfbe26 Add PostHog source UI with region select
Show a US/EU region dropdown for the PostHog Cloud API-key form and
an instance-URL field for Self-Hosted, map both to the connector inputs,
and register the PostHog logo for the self-hosted provider.

Signed-off-by: Aurélien Sibiril <81782+aureliensibiril@users.noreply.github.com>
2026-06-03 17:00:07 +02:00
Émile Ré
9c4b6aff18 Link cookie policy doc and revamp tracker rows
Expose the generated cookie policy Document on the CookieBanner
GraphQL type through a nullable policyDocument field and resolver,
and surface a link to it from the banner configuration header next
to the origin and ID. The link is hidden until a banner version is
published and the document exists.

Rework the tracker table rows: drop the Source column in favour of
a tracker Type badge, and move each tracker's description inline
beneath its name (and into the add/edit row inputs) instead of a
separate Description column.

Signed-off-by: Émile Ré <emile@probo.com>
2026-06-02 16:21:01 +02:00
Émile Ré
f702edabf0 Move cookie banner display tab first
Signed-off-by: Émile Ré <emile@probo.com>
2026-06-02 16:21:01 +02:00
Sacha Al Himdani
6e7c96732f Add async third-party vetting
Queue vetting on third_parties with PENDING, PROCESSING,
COMPLETED, and FAILED states. Expose enqueue and status through
GraphQL, MCP, CLI, and n8n, validate vet requests, tune the
worker via config, and poll the detail page while vetting runs.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-06-02 11:39:51 +02:00
Cursor Agent
4084554daa Add document archive row action
Allow documents to be archived or unarchived directly from the
list row actions, matching the detail-page behavior. Remove the
row from the active or archived connection after the status change
so filtered lists update immediately.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-30 11:22:17 -07:00
Émile Ré
1b8bd1895e Rework tracker and resource row actions
Turn the category column into an inline Select so a tracker pattern or
resource can be recategorised in place. On the pattern row the move is
gated by a confirm that surfaces the existing behaviour of promoting or
linking a third party. The remaining row actions (include/exclude and
delete) move into a single action dropdown, leaving only Edit inline.

Add a Max Age column to the pattern table and a Category column to the
resource table, and lay the edit forms out with the name above the
inputs so the description can use the full row width. Shrink the action
column to its content so the freed space goes to the data columns.

Signed-off-by: Émile Ré <emile@probo.com>
2026-05-29 15:49:21 +02:00
Émile Ré
12f9dfa352 Expose HTTP cookie source through the console API
The coredata CookieSource enum and the ingestion path both support an
HTTP source, but the GraphQL CookieSource enum never declared it. The
generated marshaler is a plain map lookup with no fallback, so an HTTP
value missed the map and serialized to an empty string. The console UI
treats that empty string as falsy and rendered no source badge at all,
making HTTP-sourced trackers look sourceless.

Add the HTTP member to the GraphQL enum so the value round-trips, and
fold the duplicated tracker-type and tracker-source badge helpers from
three components into a shared @probo/helpers module, adding an explicit
HTTP label while consolidating.

Signed-off-by: Émile Ré <emile@probo.com>
2026-05-29 12:56:36 +02:00
Émile Ré
7f4a66b310 Skip third-party promotion for uncategorised trackers
Catalog resolution (common_tracker_pattern_id) still runs for every
pattern, but promoteThirdParty is now gated on the tracker's cookie
category: patterns still sitting in the uncategorised bucket are not
promoted to an org ThirdParty until the user moves them to a real
category, which re-triggers the worker via SetMappingRequested.

Signed-off-by: Émile Ré <emile@probo.com>
2026-05-29 10:07:30 +02:00
Émile Ré
33ddba9770 Do not use avatar for tracker third party
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-29 10:07:30 +02:00
Émile Ré
af4b8a3476 Show third parties on banner trackers page
Wire the new CookieBanner.linkedThirdParties aggregation and the
TrackerPattern.thirdParty / commonThirdParty fields into the trackers
configuration UI. Three surfaces change:

CookieBannerTrackersPage: a new dedicated "Third party" column sits
between Name and Source so the link is visible at a glance, and a
fourth Select to the right of the category filter exposes the deduped
list returned by linkedThirdParties. The Select sends the chosen GID
straight through; the backend dispatches on the entity-type prefix
(ThirdParty vs CommonThirdParty), so the frontend stays oblivious to
which table the filter ends up hitting. The "%other" branch of the
union is filtered out before render to keep TypeScript happy if the
backend grows the union later.

TrackerPatternRow: extends the row fragment with thirdParty and
commonThirdParty, prefers the org-scoped link (mirroring the resolver
priority), and renders an Avatar + name. The org-scoped ThirdParty has
no logoUrl in the schema today so the Avatar falls back to initials;
CommonThirdParty supplies its catalog logo.

TrackerPatternPropertiesSection: same priority logic in a PropertyRow
under Category, so the detail page surfaces the same information.

The third-party Select uses the same set as the underlying patterns,
so picking a value never produces an empty list — the linkedThirdParties
resolver only walks rows the user can see.

Signed-off-by: Émile Ré <emile@probo.com>
2026-05-29 10:07:29 +02:00
Cursor Agent
0920785bdf Add Metabase access review source
Implement Metabase as a first-class access review connector backed by
GET /api/user, including account mapping and error handling in the
driver. Register the provider with API-key auth metadata and required
instance URL settings so connectors can be created and resolved
consistently.

Expose Metabase through the console GraphQL and UI flows by adding the
provider enum value, API-key extra setting field wiring, and source
label mapping. Add migration support for the connector_provider enum and
cover driver/provider behavior with focused tests.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
Signed-off-by: Cursor Agent <cursoragent@cursor.com>
2026-05-28 18:36:36 -07:00
Cursor Agent
f5a632ffac Add Grafana access review connector support
Add Grafana as an access review connector-backed source.

This introduces a Grafana access-review driver, provider registration,
and connector settings for the Grafana base URL. It also wires the
new provider through GraphQL and access-review UI input mapping so
API-key connectors can be created from the product.

A connector_provider enum migration is included so Grafana can be
persisted in existing databases.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-28 18:35:01 -07:00
Cursor Agent
dd547471e6 Disable role sorting in people list
The role order field is not supported on the GraphQL profile ordering
path, which makes role-based sorting fail at runtime.

Keep the role column visible for users who can manage roles, but render
it as a regular table header instead of a sortable one.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-28 12:23:18 -07:00
Bryan Frimin
80be22fe8a Show SCIM error message
Signed-off-by: Bryan Frimin <bryan@probo.com>
2026-05-28 09:46:26 -07:00
Sacha Al Himdani
c78a713adf Refactor risks frontend to follow page arborescence conventions
- Split layout's monolithic query: each child route now owns its query
  via its own *PageLoader + *Page (overview/measures/documents/controls/
  obligations/scenarios).
- Rename tabs/RiskXTab.tsx -> <resource>/RiskXPage.tsx; drop UI-named
  tabs/ and dialogs/ folders.
- Move FormRiskDialog, PublishRiskListDialog and the extracted RiskRow
  into _components/ as named exports.
- Move risk form fragment ownership into FormRiskDialog: define
  FormRiskDialog_risk in the dialog and pass plain data to useRiskForm
  so spread sites colocate cleanly without disable comments.
- Align risk components with react-components.md naming: rename Relay
  fragments to ComponentName_typeName and replace 'type Props' aliases
  with 'interface ComponentNameProps'.
- Guard risk pages against null node and mutation errors: add
  __typename narrowing to every node(id) query, surface deleteRisk
  errors via toast, and resolve the confirm promise on error so the
  dialog no longer hangs.
- Replace deprecated useMutationWithToasts (FormRiskDialog) and
  useLazyLoadQuery (LinkScenarioDialog) with useMutation+useToast and
  useQueryLoader+usePreloadedQuery.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-28 15:02:09 +02:00
Sacha Al Himdani
e6b40957ee Add invitingOrganizations field on viewer
Expose viewer.invitingOrganizations: [Organization!]! returning the
organizations that have a live pending invitation directed at the
current identity (accepted_at IS NULL AND expires_at > NOW()). The
list is rendered under a "Pending invitations" section on the
memberships page and in the organization selector dropdown, so a user
already signed in with an existing identity can see which
organizations have invited them without having to dig through their
inbox.

The new field is gated by iam:invitation:list against the viewer's
own identity, so it does not loosen authorization on Organization
elsewhere. E2E coverage validates the live-pending case, the
no-invitation and post-accept cases, and a multi-org scenario.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-28 13:42:29 +02:00
Cursor Agent
6f4ac54a27 Expose bridge sync errors in SCIM API
Add a dedicated SCIMBridge syncError field to the Connect GraphQL API
and populate it from the core bridge model.

Update the connector cards to read bridge state and syncError directly
from the bridge object instead of inferring failures from event
history.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 18:10:22 -07:00
Cursor Agent
83ce4286f8 Alias bridge event field to fix Relay build
Alias the connector card event selection so it does not conflict with
the SCIM event list fragment querying the same  field with
different arguments.

This resolves the Relay compilation failure in CI while keeping the
latest bridge error message available for the error-state callout.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 18:10:22 -07:00
Cursor Agent
f02c3b88b7 Show bridge errors in connector cards
Display SCIM bridge state directly on Google Workspace and Microsoft
365 connector cards so admins can quickly identify failing bridges.

When a bridge is failed, render an inline error callout and surface the
latest provisioning event error message to make troubleshooting visible
without leaving the connector section.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 18:10:22 -07:00
Cursor Agent
f50289a755 Harden archive organization scoping
Validate ArchiveUser organization input against the loaded profile and\nuse the profile organization for owner checks and webhook emission.\n\nAlso disable both PersonPage destructive actions while either archive\nor remove mutation is pending to prevent double-submit races.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 12:23:19 -07:00
Cursor Agent
1e08a23ddc Split user remove and archive actions
Restore RemoveUser as a hard delete operation and surface dependency\nconflicts with a dedicated IAM error.\n\nAdd a new ArchiveUser flow that deactivates profiles while keeping the\nmember in the organization, then expose both actions across Connect, MCP,\nCLI, n8n, console UI, and e2e coverage.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>

Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
2026-05-27 12:23:17 -07:00
Cursor Agent
23070b18b5 Sync user archive across all interfaces
Align user-removal UX and API surface semantics with the new archive\nbehavior for manually managed users.\n\nFrontend copy and actions now use archive wording, and list rows are\nrefetched after the mutation so archived users reappear as inactive.\n\nMCP removeUser now documents and returns archived_user_id, n8n labels\nand response mapping now use archive semantics, and the CLI gains a\nuser archive command backed by the same mutation.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>
2026-05-27 12:23:16 -07:00
Émile Ré
27a9f83825 Promote on detection
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-26 18:06:54 +02:00
Sacha Al Himdani
6dfdd7ca49 Link measures to third parties
Add a many-to-many relationship between measures and third parties,
surfaced as a measures tab on the third party detail page and a third
parties tab on the measure detail page. Each side gets a paginated
list with a link/unlink dialog.

Also remove the right-hand drawer on the measure detail page and
expose the state as a badge in the page header, mirroring how the
compliance page surfaces its active flag.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-26 15:49:17 +02:00
Sacha Al Himdani
b6b1e801b1 Add third-party self-referential relations
Introduce a self-referential many-to-many relation table so a
third party can have child third parties. Each relation is
directional (parent to child); both directions can coexist as
independent rows.

Add a first_level boolean on third_parties (default true) with
a filter on the list page that defaults to showing only
first-level third parties.

Frontend adds a "Third Parties" tab on the detail page where
users can link existing third parties or create new ones from
the common third party catalog (created as non-first-level).
The list page gets a First Level/All toggle filter.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-26 15:21:38 +02:00
Émile Ré
1c3ce56b48 Mark page-world extension writes with EXTENSION source
The previous cleanup deleted every isExtensionCaller() site, including
the one in cookie/storage detectors that did fire reliably for the
residual case: page-world extensions (MV3 main world, userscripts with
@grant none) whose stack contains a chrome-/moz-/safari-web-extension
frame at the synchronous write. Recover that signal for free by
returning fromExtension from getInitiatorURL (it already walks the
stack and discards extension frames via continue), and have the cookie
and storage detectors report source: "extension" instead of "script"
when the flag is set.

End-to-end plumbing reuses the existing source column: extend the
cookie_source Postgres enum with EXTENSION, add the CookieSourceExtension
constant with a doc block describing each bucket's actual semantics,
add the handler.go switch cases, expose EXTENSION on the GraphQL and
MCP CookieSource enums, and add the Extension option to the console
source filter.

Update bestSource in the pattern analysis worker so a glob merging
only extension-attributed exact patterns is no longer silently rolled
up to PRE_EXISTING. New precedence is SCRIPT > EXTENSION > PRE_EXISTING,
matching the upsert SQL's "page-script wins" rule and the asymmetric
signal strength of each bucket.

Out of scope: any behavioural use of EXTENSION (auto-exclusion,
denylist classification, dashboard surfacing) -- that belongs in the
follow-up backend denylist plan.

Signed-off-by: Émile Ré <emile@probo.com>
2026-05-26 11:14:48 +02:00
Sacha Al Himdani
83445c6e34 Fix signature count mismatch with signatures tab on documents
The badge on a document version showed signatures filtered by
activeContract: true, while the signatures tab fetched signatures with
no filter and listed people filtered by contractEnded: false and
state: ACTIVE. The two views disagreed both when a signer's contract had
ended and when a signer was deactivated while still under contract.

Add a state: ProfileState field to DocumentVersionSignatureFilter
alongside the existing activeContract filter, so the signature query
can mirror the same predicates as the people query. Pass
{ activeContract: true, state: ACTIVE } from the badge, the document
list item, and the signatures tab fragment. The same filter is now
evaluated on both the count and the list.

Threaded through the console and MCP resolvers, the MCP spec, and the
n8n getAllSignatures operation.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-22 14:34:35 +02:00
Émile Ré
b46f2656f5 Add tracker pattern detail page with properties and detected trackers sections
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-22 11:54:44 +02:00
Émile Ré
5abd670707 Update console tracker page
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-22 10:20:07 +02:00
Sacha Al Himdani
eedfdcecc8 Render mermaid diagram per risk assessment scope
Each scope card now shows a flowchart of its nodes, processes, and
threats, with a distinct shape per type: stadium for entities,
hexagon for boundaries, rectangle for assets, cylinder for data, and
a red hexagon for threats attached via dashed edges to their process
target. The Mermaid source is built on the backend and exposed as a
new `mermaid` field on RiskAssessmentScope; the frontend just renders
it via @probo/ui's MermaidDiagram and shows a copy button + legend.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-19 21:44:28 +02:00
Sacha Al Himdani
b9262b5150 Add risk assessment system
Introduce a hierarchical risk assessment model with six entity types:

- Risk Assessment: top-level container scoped to an organization
- Risk Assessment Scope: sub-container for scoping threat modeling
  exercises within an assessment
- Risk Assessment Node: DFD elements typed as ENTITY, BOUNDARY,
  ASSET, or DATA within a scope
- Risk Assessment Process: directed data flows between two nodes
- Risk Assessment Threat: descriptive threats attached to a process
  with a free-text category (e.g. Confidentiality, Integrity)
- Risk Scenario: thin join linking a threat to a risk from the
  register, carrying only a name and description

Risk scoring (likelihood, impact, treatment) remains on the existing
Risk entity. Threats are purely descriptive. Risk Scenarios connect
the threat model to the risk register without duplicating scores.

Backend: migration with PG enum for node types, coredata structs,
service layer with full CRUD and validation, GraphQL schema with
18 mutations and paginated connections, authorization actions and
policies, and base_resolvers.go Node dispatch for all entity types.

Frontend: Risk Assessments list page with create dialog, detail page
showing scopes as cards with nodes/processes/threats tables, inline
create/edit/delete actions on all entities, and a Scenarios tab on
the Risk detail page linking threats to risks. Existing RiskGraph.ts
hook file removed in favor of colocated queries in page files.

E2E tests cover CRUD for all entity types, RBAC, and tenant
isolation.

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-19 21:44:27 +02:00
Émile Ré
b3c67fb0e2 Move third parties data.json and remove @probo/third-parties
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-18 19:05:10 +04:00
Cursor Agent
e4005e0f74 Filter inactive people from signature request recipients
The signature request recipient lists (both the multi-select dialog
and the document signatures page) included people who were inactive
via SCIM deactivation. The existing filter only excluded people with
ended contracts but not those with an INACTIVE state.

This adds state: ACTIVE to the ProfileFilter in both frontend queries
and introduces a server-side ErrProfileInactive validation in the
RequestSignature and BulkRequestSignatures service methods to reject
inactive profiles even if called directly via API.

Co-authored-by: Émile Ré <nemile.re@gmail.com>
Signed-off-by: Émile Ré <emile@getprobo.com>
Signed-off-by: Émile Ré <emile@probo.com>
2026-05-18 17:03:53 +04:00
Sacha Al Himdani
eecbe4c46c Rename vendors to third parties
Renames the user-facing 'vendor' concept to 'third party' across the
entire codebase. The shared common_third_parties reference table is
unchanged.

Migration. Renames the vendor_category enum, the vendors and
vendor_<entity> tables (contacts, services, compliance_reports,
business_associate_agreements, data_privacy_agreements,
risk_assessments) and their vendor_id columns, the asset_vendors /
data_vendors / processing_activity_vendors junction tables,
generated_documents.vendors_document_id, the webhook_event_type
'vendor:<verb>' values, and the snapshots_type 'VENDORS' value.

Backend. Renames coredata models and SQL queries, probo services,
GraphQL / MCP API surface, console / trust / webhook resolvers and
types, the CLI (prb vendor* -> prb third-party*; pkg/cmd/vendormgmt
-> pkg/cmd/thirdpartymgmt), the document generator, vetting agent
prompts, and the common-third-parties-import command.

Frontend, packages, n8n, e2e. Renames apps/console pages, components,
hooks, routes, dialogs, and tabs; the shared @probo/vendors package
(now @probo/third-parties); the @probo/ui Vendors atoms (now
ThirdParties, VendorLogo -> ThirdPartyLogo); the n8n community node
actions/vendor folder (now actions/thirdParty); and the e2e Go test
suite (console and MCP). Filesystem and URL paths use kebab-case
(third-parties), GraphQL fields and TypeScript identifiers use
camelCase (thirdParty / thirdParties), Go types use PascalCase
(ThirdParty), and human-facing text uses 'third party' with a space.

Co-authored-by: Bryan Frimin <bryan@getprobo.com>
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
2026-05-13 21:21:39 +02:00
Émile Ré
e739473bcd Derive consent mode from geolocation, not banner config
The consent mode is now determined dynamically by the visitor's
country and its applicable regulation. The configured consent_mode
column is dropped from cookie_banners and added to
cookie_consent_records to persist the geo-derived mode at
consent-recording time. When no regulation matches, the default
is OPT_OUT.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-13 12:49:13 +04:00
Émile Ré
1d367ad51f Use distinct badge colors for resource and tracker types
Map each resource type and tracker type to a specific badge
variant instead of only distinguishing scripts from everything
else. Drop the manual BadgeVariant type alias in favor of
as-const inference.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-13 12:49:12 +04:00
Émile Ré
10ac52eff3 Fix PR review feedback
- Preserve SSRF protection by wrapping the existing transport
  instead of replacing it with a bare http.Transport
- Strip DSN from url.Parse error to avoid leaking credentials
- Gate CommonThirdPartyCombobox on search length to prevent
  showing stale results when input is shortened
- Handle multi-value and uppercase sizes attributes in
  parseSizeAttr for correct icon-size ranking
- Match rel tokens containing "icon" (e.g. "shortcut icon")
  instead of requiring an exact match
- Limit HTML response body to 10 MiB before parsing
- Reject sslmode=prefer explicitly in both import tools

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:37 +04:00
Émile Ré
6383457e6b Fix issue with fragment read inline
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:37 +04:00
Émile Ré
6c2037e013 Debounce vendor search query with usehooks-ts
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:37 +04:00
Émile Ré
684fadea3e Remove unused description column from common_third_parties
The description field was never surfaced in the UI and added no value.
Drop it from the database, Go structs, GraphQL schema, import tool,
frontend fragment, and vendor seed data.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:36 +04:00
Émile Ré
4a405ce16c Self-host common third party logos via S3
Fetch favicons at import time instead of calling Google's favicon
service per page load. Logos are stored as public files in S3 and
served through the existing /api/files/v1/{id} endpoint.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:36 +04:00
Émile Ré
7099a3d702 Replace vendor JSON with common third parties API
The CreateVendorDialog previously loaded the entire @probo/vendors
JSON bundle client-side and used MiniSearch for fuzzy search. This
replaces it with a GraphQL query against the common_third_parties
database table, searched server-side via ILIKE filtering.

Backend: adds CommonThirdParty GraphQL type, a pkg/thirdparty
service, and a commonThirdParties(name) root query. Frontend:
splits into CommonThirdPartyCombobox (display) and an @inline
fragment read on selection via readInlineData.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-12 16:43:36 +04:00
Émile Ré
6bf1e54a50 Fix SQL corruption in FindMatchingPattern by using strings.Replace
fmt.Sprintf interprets the literal % characters in the LIKE escape
clause as format verbs, corrupting the query and causing a 500 on
the /report endpoint.  Reorder tracker type / source filters in the
trackers page.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-11 17:42:51 +04:00
Émile Ré
10313069c8 Remove tracker pattern row updatedAt column
Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-11 16:36:47 +04:00
Émile Ré
71a33e412b Add tracker type filter and color-coded badges
The trackers page now lets users filter by tracker type
(Cookie, localStorage, sessionStorage, IndexedDB, Cache
Storage) in addition to the existing source filter. Each
tracker type and cookie source badge uses a distinct color
for quick visual scanning.

Signed-off-by: Émile Ré <emile@getprobo.com>
2026-05-11 15:34:24 +04:00