Skip to content

feat(consent): manage cookies from Settings, not from a card in the workspace - #6835

Merged
waleedlatif1 merged 2 commits into
stagingfrom
feat/consent-in-app-settings
Aug 19, 2026
Merged

feat(consent): manage cookies from Settings, not from a card in the workspace#6835
waleedlatif1 merged 2 commits into
stagingfrom
feat/consent-in-app-settings

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

Follow-up to #6832. The consent banner mounted in the root layout, so it appeared on every page — including inside the product. This moves in-app consent to Settings and fixes the theme mismatch the banner was working around rather than papering over it.

The banner never appears in the workspace

ConsentProvider returns before the dynamic() boundary on any /workspace path, so the product pays neither the consent chunk nor its init request — the surface with the most hard page loads. Gating inside the lazily-loaded module would still have downloaded it.

Consent inside the product is managed from Settings → Privacy instead, which is the documented pattern for authenticated surfaces: a floating card is the wrong shape once someone is signed in.

One store, structurally

The banner sits behind an ssr: false boundary that cannot wrap the app, so nothing reaches its store through React context. Both surfaces therefore mount their own provider — but getOrCreateConsentRuntime caches manager and store by the option values, so they share one of each. CONSENT_OPTIONS now lives inside ConsentStoreProvider and is not exported, which makes that invariant unbreakable rather than conventional.

Verified directly rather than trusting the docs:

same store instance: true
same manager instance: true
different backendURL -> different store: true

The theme fix, at the cause

The banner previously pinned the light token layer with a comment explaining why. The actual problem is that LandingShell pins light on a wrapper inside the page while <html> keeps the visitor's theme, so any landing route missing from ThemeProvider's hand-written list rendered a light page under dark root chrome — scrollbars, color-scheme, and anything portalled to <body>.

LANDING_ROUTES becomes one source of truth in lib/landing/routes.ts, read by both next.config.ts (COEP exemptions) and ThemeProvider (forced light). That is the same drift that let /cookie-policy ship without its COEP exemption in the last PR. The banner now simply inherits the theme.

Two pre-existing gaps closed along the way: /cli/auth and /credential-groups/complete both render AuthShell (which pins light) and were in neither list.

Type of Change

  • New feature
  • Bug fix

Testing

  • type-check, lint:check, all 29 check:audits, and 155 tests pass.
  • Diffed forced-light behavior old vs new across every real route: 16 landing routes gain the correct <html> theme, nothing regresses in the other direction.
  • Browser-verified the theme inheritance: /pricing under a dark system theme renders <html class="light"> with a light card; /playground renders <html class="dark"> with a #1b1b1b card. The banner no longer decides for itself.
  • /workspace needs auth, so the gate is covered by tests asserting the dynamic loader is never invoked on /workspace, /workspace/abc, /workspace/abc/logs — verified those fail when the gate is removed.
  • Reviewers should focus on the ThemeProvider change: it moves from startsWith prefix matching to first-segment set membership, and that route-classification diff is the riskiest part of this PR.

Known gap (unchanged from #6832)

Prior blocking is still not implemented — GTM, GA, and PostHog load before consent. This PR makes that more load-bearing, not less: a visitor who reaches the workspace with no consent record is now never prompted. It closes properly when the analytics scripts move behind consent, since nothing non-essential loads without a record at all.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

… workspace

The banner no longer mounts inside the workspace at all. The gate sits above
the dynamic() boundary rather than inside the lazily-loaded module, so the
product pays neither the consent chunk nor its init request on the surface with
the most hard loads. A signed-in user manages the same choice from
Settings -> Privacy, which shares one store with the banner: the options live
in ConsentStoreProvider and are not exported, so two call sites cannot drift
into two stores.

The banner also stops pinning the light token layer and simply inherits. The
cause it was working around is that LandingShell pins light on a wrapper inside
the page while <html> keeps the visitor's theme, so landing routes missing from
ThemeProvider's hand-written list rendered light pages under dark root chrome.
LANDING_ROUTES becomes one source of truth in lib/landing/routes, read by both
next.config (COEP) and ThemeProvider (forced light) -- the same drift that let
/cookie-policy ship without its COEP exemption. Diffed old against new across
every real route: 16 landing routes gain the correct theme and nothing
regresses. /cli/auth and /credential-groups/complete are added too; both render
AuthShell and were never covered.

Verified the shared-store assumption directly rather than trusting the docs:
getOrCreateConsentRuntime returns the same store and manager for equal options.
@vercel

vercel Bot commented Aug 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Aug 19, 2026 1:05am

Request Review

@cursor

cursor Bot commented Aug 19, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
ThemeProvider route classification changed from prefix matching to first-segment sets—mislisted routes could force wrong theme or miss COEP exemptions. Workspace users with no consent record are no longer prompted until analytics gating ships.

Overview
Moves in-app cookie consent off a floating banner and into Settings → Privacy on hosted deployments, while fixing root-level theme drift that forced the banner to pin light on its own.

Workspace: ConsentProvider skips loading the consent runtime on /workspace paths (before dynamic()), so the product avoids the chunk and init request. Privacy settings mounts ConsentStoreProvider and reuses shared ConsentPreferences switches with save/discard.

Shared consent layer: ConsentStoreProvider centralizes hosted CONSENT_OPTIONS (iframe blocker disabled); banner and settings share one runtime store. Banner drops hardcoded light and uses inherited theme.

Theme / routing: LANDING_ROUTES in lib/landing/routes.ts is the single list for COEP exemptions (next.config.ts) and forced light on <html> (ThemeProvider), using first path-segment set membership instead of ad hoc startsWith lists; adds segments like cli and credential-groups.

Reviewed by Cursor Bugbot for commit 15dd69a. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR moves hosted cookie-consent controls into unified workspace Settings and prevents the floating consent runtime from loading on workspace routes. It also centralizes landing-route classification for theme and COEP behavior.

  • Adds a hosted-only Privacy section backed by the shared consent runtime.
  • Removes Privacy from the standalone account-settings plane, resolving its fallthrough into Mothership.
  • Shares landing-route definitions between ThemeProvider and next.config.ts.
  • Adds coverage for workspace consent gating, Privacy save/discard behavior, and settings navigation.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the previously reported Privacy account-settings fallthrough is eliminated by keeping Privacy exclusively on the hosted unified settings surface.

Important Files Changed

Filename Overview
apps/sim/components/settings/navigation.ts Registers Privacy only in hosted unified settings, removing the account-plane projection that caused the previously reported renderer fallthrough.
apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx Renders Privacy for hosted workspace settings and safely redirects self-hosted requests to General.
apps/sim/app/workspace/[workspaceId]/settings/components/privacy/privacy.tsx Adds cookie-preference editing with dirty-state tracking, save/discard actions, and consent-store integration.
apps/sim/app/_shell/consent/consent-provider.tsx Prevents the consent runtime and its dynamic chunk from loading on workspace paths.
apps/sim/app/_shell/providers/theme-provider.tsx Replaces prefix-based forced-light classification with exact first-segment membership from centralized route definitions.
apps/sim/lib/landing/routes.ts Defines the shared landing-route segments consumed by theme and COEP configuration.
apps/sim/next.config.ts Reuses the centralized landing-route list without changing the effective COEP exemption set.

Reviews (2): Last reviewed commit: "fix(consent): keep Privacy on one settin..." | Re-trigger Greptile

Comment thread apps/sim/components/settings/navigation.ts Outdated
Comment thread apps/sim/components/settings/navigation.ts Outdated
Projecting the section into the account plane put it in a catalog that
buildPlaneSettingsItems does not gate on requiresHosted, so a self-hosted
deployment would list a Privacy entry, and AccountSettingsRenderer's catch-all
rendered Mothership for it. The unified settings already gate the section and
redirect self-hosted deployments to General, so the section lives there only.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 15dd69a. Configure here.

@waleedlatif1
waleedlatif1 merged commit ff23279 into staging Aug 19, 2026
30 checks passed
@waleedlatif1
waleedlatif1 deleted the feat/consent-in-app-settings branch August 19, 2026 01:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant