feat(enterprise): cloud whitelabeling for enterprise orgs#4047
feat(enterprise): cloud whitelabeling for enterprise orgs#4047waleedlatif1 merged 20 commits intostagingfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryMedium Risk Overview Updates the workspace UI to consume org branding dynamically: a new Reviewed by Cursor Bugbot for commit ebe7e5c. Configure here. |
Greptile SummaryThis PR adds a cloud whitelabeling feature for enterprise orgs, storing per-org branding config (logo, colors, brand name, links, hide-powered-by toggle) in a new Confidence Score: 5/5Safe to merge — all previously flagged issues have been resolved and the two remaining findings are minor P2 suggestions. The critical concerns from prior review rounds (enterprise plan scope check, onSuccess→onSettled, auth layering) have all been addressed. The two new findings — a serial fetch waterfall causing a brief flash of default branding, and redundant CSS variable declarations in generateOrgThemeCSS — are both P2 style suggestions that do not affect correctness or data integrity. The migration is purely additive (nullable column), the API guards are correctly layered, and color values are strictly validated before CSS injection. apps/sim/ee/whitelabeling/components/branding-provider.tsx (waterfall fetch), apps/sim/ee/whitelabeling/org-branding-utils.ts (duplicate CSS declarations)
|
| Filename | Overview |
|---|---|
| apps/sim/app/api/organizations/[id]/whitelabel/route.ts | New GET/PUT API route for org whitelabel settings; enterprise plan check correctly scoped to target org, membership + role guards in place, audit logging wired |
| apps/sim/ee/whitelabeling/components/branding-provider.tsx | Client-side context provider merging instance and org branding; serial fetch waterfall (orgs → whitelabel) can cause brief flash of default colors |
| apps/sim/ee/whitelabeling/components/whitelabeling-settings.tsx | Settings form with logo upload, color pickers, link fields; render-phase setState pattern is consistent with other forms; enterprise/role guards applied behind billing flag |
| apps/sim/ee/whitelabeling/hooks/whitelabel.ts | React Query hooks for fetching and mutating whitelabel settings; correctly uses onSettled for cache invalidation, signal forwarded, staleTime set |
| apps/sim/ee/whitelabeling/org-branding-utils.ts | Merge helpers and CSS variable generator; duplicate CSS declarations when both primaryColor and primaryHoverColor are set (functionally correct but redundant) |
| apps/sim/ee/whitelabeling/org-branding.ts | Server-side org branding fetch utility, correctly logs errors and returns null on failure |
| apps/sim/lib/branding/types.ts | Adds OrganizationWhitelabelSettings interface as the shared source of truth for org branding fields |
| packages/db/schema.ts | Adds whitelabel_settings JSON column to the organization table; inline type is consistent with cross-package boundary constraints |
| packages/db/migrations/0188_short_luke_cage.sql | Additive migration: ALTER TABLE adds nullable json column — safe to run on live data |
| apps/sim/app/workspace/[workspaceId]/layout.tsx | Wraps workspace in BrandingProvider; correct placement ensures sidebar and all child components can consume org brand config |
| apps/sim/app/workspace/[workspaceId]/settings/navigation.ts | Adds whitelabeling nav item under enterprise section, correctly gated with requiresHosted and requiresEnterprise flags |
Sequence Diagram
sequenceDiagram
participant Browser
participant BrandingProvider
participant OrgQuery as useOrganizations()
participant WLQuery as useWhitelabelSettings()
participant API as /api/organizations/[id]/whitelabel
Browser->>BrandingProvider: Mount workspace layout
BrandingProvider->>OrgQuery: fetch active org
OrgQuery-->>BrandingProvider: { activeOrganization: { id } }
BrandingProvider->>WLQuery: fetch whitelabel settings (orgId)
WLQuery->>API: GET /api/organizations/:id/whitelabel
API-->>WLQuery: { data: OrganizationWhitelabelSettings }
WLQuery-->>BrandingProvider: orgSettings
BrandingProvider->>Browser: inject CSS vars + provide BrandConfig context
Note over Browser: Sidebar reads useOrgBrandConfig() → org logo & brand name
Browser->>API: PUT /api/organizations/:id/whitelabel
Note over API: Checks: session → member → admin/owner → enterprise plan
API-->>Browser: { data: updated settings }
Note over Browser: onSettled invalidates whitelabelKeys + organizationKeys.detail
Reviews (3): Last reviewed commit: "fix(enterprise): remove webp from logo a..." | Re-trigger Greptile
…mpty update result
|
@greptile |
|
@cursor review |
apps/sim/ee/whitelabeling/components/whitelabeling-settings.tsx
Outdated
Show resolved
Hide resolved
…ad hook validation
|
@greptile |
|
@cursor review |
|
@greptile |
|
@cursor review |
There was a problem hiding this comment.
✅ 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 ebe7e5c. Configure here.
…on non-hosted environments
…eturns /api/files/serve/ paths
…lash on repeat visits
…o flash before paint
…rg settings resolve
… remove mutation from useCallback deps
…sh on all page loads
… injection React Query returns isLoading: false with data: undefined during SSR, so the previous brandingLoading condition was always false on the server — initialCache was never injected into brandConfig. Changing to !orgSettings correctly applies the cookie cache both during SSR and while the client-side query loads, eliminating the logo flash on hard refresh.
* feat(enterprise): cloud whitelabeling for enterprise orgs * fix(enterprise): scope enterprise plan check to target org in whitelabel PUT * fix(enterprise): use isOrganizationOnEnterprisePlan for org-scoped enterprise check * fix(enterprise): allow clearing whitelabel fields and guard against empty update result * fix(enterprise): remove webp from logo accept attribute to match upload hook validation * improvement(billing): use isBillingEnabled instead of isProd for plan gate bypasses * fix(enterprise): show whitelabeling nav item when billing is enabled on non-hosted environments * fix(enterprise): accept relative paths for logoUrl since upload API returns /api/files/serve/ paths * fix(whitelabeling): prevent logo flash on refresh by hiding logo while branding loads * fix(whitelabeling): wire hover color through CSS token on tertiary buttons * fix(whitelabeling): show sim logo by default, only replace when org logo loads * fix(whitelabeling): cache org logo url in localstorage to eliminate flash on repeat visits * feat(whitelabeling): add wordmark support with drag/drop upload * updated turbo * fix(whitelabeling): defer localstorage read to effect to prevent hydration mismatch * fix(whitelabeling): use layout effect for cache read to eliminate logo flash before paint * fix(whitelabeling): cache theme css to eliminate color flash before org settings resolve * fix(whitelabeling): deduplicate HEX_COLOR_REGEX into lib/branding and remove mutation from useCallback deps * fix(whitelabeling): use cookie-based SSR cache to eliminate brand flash on all page loads * fix(whitelabeling): use !orgSettings condition to fix SSR brand cache injection React Query returns isLoading: false with data: undefined during SSR, so the previous brandingLoading condition was always false on the server — initialCache was never injected into brandConfig. Changing to !orgSettings correctly applies the cookie cache both during SSR and while the client-side query loads, eliminating the logo flash on hard refresh.
* fix(billing): skip billing on streamed workflows with byok * Simplify logic * Address comments, skip tokenization billing fallback * Fix tool usage billing for streamed outputs * fix(webhook): throw webhook errors as 4xxs (#4050) * fix(webhook): throw webhook errors as 4xxs * Fix shadowing body var --------- Co-authored-by: Theodore Li <theo@sim.ai> * feat(enterprise): cloud whitelabeling for enterprise orgs (#4047) * feat(enterprise): cloud whitelabeling for enterprise orgs * fix(enterprise): scope enterprise plan check to target org in whitelabel PUT * fix(enterprise): use isOrganizationOnEnterprisePlan for org-scoped enterprise check * fix(enterprise): allow clearing whitelabel fields and guard against empty update result * fix(enterprise): remove webp from logo accept attribute to match upload hook validation * improvement(billing): use isBillingEnabled instead of isProd for plan gate bypasses * fix(enterprise): show whitelabeling nav item when billing is enabled on non-hosted environments * fix(enterprise): accept relative paths for logoUrl since upload API returns /api/files/serve/ paths * fix(whitelabeling): prevent logo flash on refresh by hiding logo while branding loads * fix(whitelabeling): wire hover color through CSS token on tertiary buttons * fix(whitelabeling): show sim logo by default, only replace when org logo loads * fix(whitelabeling): cache org logo url in localstorage to eliminate flash on repeat visits * feat(whitelabeling): add wordmark support with drag/drop upload * updated turbo * fix(whitelabeling): defer localstorage read to effect to prevent hydration mismatch * fix(whitelabeling): use layout effect for cache read to eliminate logo flash before paint * fix(whitelabeling): cache theme css to eliminate color flash before org settings resolve * fix(whitelabeling): deduplicate HEX_COLOR_REGEX into lib/branding and remove mutation from useCallback deps * fix(whitelabeling): use cookie-based SSR cache to eliminate brand flash on all page loads * fix(whitelabeling): use !orgSettings condition to fix SSR brand cache injection React Query returns isLoading: false with data: undefined during SSR, so the previous brandingLoading condition was always false on the server — initialCache was never injected into brandConfig. Changing to !orgSettings correctly applies the cookie cache both during SSR and while the client-side query loads, eliminating the logo flash on hard refresh. * fix(editor): stop highlighting start.input as blue when block is not connected to starter (#4054) * fix: merge subblock values in auto-layout to prevent losing router context (#4055) Auto-layout was reading from getWorkflowState() without merging subblock store values, then persisting stale subblock data to the database. This caused runtime-edited values (e.g. router_v2 context) to be overwritten with their initial/empty values whenever auto-layout was triggered. * fix(whitelabeling): eliminate logo flash by fetching org settings server-side (#4057) * fix(whitelabeling): eliminate logo flash by fetching org settings server-side * improvement(whitelabeling): add SVG support for logo and wordmark uploads * skelly in workspace header * remove dead code * fix(whitelabeling): hydration error, SVG support, skeleton shimmer, dead code removal * fix(whitelabeling): blob preview dep cycle and missing color fallback * fix(whitelabeling): use brand-accent as color fallback when workspace color is undefined * chore(whitelabeling): inline hasOrgBrand --------- Co-authored-by: Theodore Li <theo@sim.ai>
Summary
whitelabel_settingsJSON column on theorganizationtableBrandingProviderReact context in the workspace layoutuseOrgBrandConfig()to reflect org branding liveGET/PUT/api/organizations/[id]/whitelabel) with session, membership, role, and enterprise plan checks + audit loggingprofile-picturesstorage context — no new bucket neededType of Change
Testing
Tested manually
Checklist