fix(whitelabeling): eliminate logo flash by fetching org settings server-side#4057
fix(whitelabeling): eliminate logo flash by fetching org settings server-side#4057waleedlatif1 merged 8 commits intostagingfrom
Conversation
PR SummaryMedium Risk Overview Simplifies Polishes related UI: adds missing Reviewed by Cursor Bugbot for commit 0209873. Configure here. |
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
Also added SVG support for logo/wordmark uploads in this commit — server already accepted it, just needed the client validation and accept attributes updated. |
Greptile SummaryThis PR eliminates the logo flash on hard refresh by fetching org whitelabel settings server-side in the workspace layout and passing them as Confidence Score: 5/5Safe to merge — the server-side fetch correctly eliminates the logo flash, the undefined vs null distinction in the fallback logic is sound, and there are no runtime errors or data-integrity concerns. All changes are P2 or lower. The core fix is architecturally clean: initialOrgSettings is fetched once at SSR time and used synchronously on hydration so the React Query transition never shows the default logo. Error handling in getOrgWhitelabelSettings ensures the layout never throws even on DB failure. No files require special attention.
|
| Filename | Overview |
|---|---|
| apps/sim/app/workspace/[workspaceId]/layout.tsx | Core fix: adds a server-side DB query for org whitelabel settings and passes initialOrgSettings to BrandingProvider; sequential with getSession() (unavoidable since orgId comes from the session), gracefully returns null on failure. |
| apps/sim/ee/whitelabeling/components/branding-provider.tsx | Simplified: drops cookie cache, uses orgSettings !== undefined ? orgSettings : (initialOrgSettings ?? null) to serve server-fetched settings until React Query resolves; correctly distinguishes "loading" (undefined) from "no settings" (null). |
| apps/sim/ee/whitelabeling/org-branding.ts | New server-only module exposing getOrgWhitelabelSettings; uses Drizzle ORM with eq(), has error handling that returns null on failure so layout never throws. |
| apps/sim/ee/whitelabeling/org-branding-utils.ts | Clean utility module for mergeOrgBrandConfig and CSS variable generation; isDarkBackground luminance math is correct; no issues. |
| apps/sim/app/workspace/[workspaceId]/settings/[section]/page.tsx | Adds the missing whitelabeling: 'Whitelabeling' entry to SECTION_TITLES, fixing the broken page title for this settings section. |
| apps/sim/app/workspace/[workspaceId]/settings/hooks/use-profile-picture-upload.ts | Adds image/svg+xml to accepted types; blob preview URLs don't execute SVG scripts; file is properly cleaned up on unmount. |
| apps/sim/ee/whitelabeling/components/whitelabeling-settings.tsx | Settings UI for org branding; uses useProfilePictureUpload for logo/wordmark uploads with proper drag-and-drop and preview; no issues found. |
| apps/sim/components/emcn/components/tooltip/tooltip.tsx | Adds Preview sub-component for video/image tooltips with a shimmer placeholder while video loads; clean implementation. |
| apps/sim/lib/uploads/utils/file-utils.ts | Adds image/svg+xml to MIME_TYPE_MAPPING with a comment explaining it's handled specially for Claude API; createFileContent correctly converts SVG to XML document type. |
| apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workspace-header/workspace-header.tsx | Updates workspace color fallback to var(--brand-accent) so it respects org-level color theming; no issues. |
| apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx | Adds ssr: false to the WhitelabelingSettings dynamic import, appropriate since it's a client-only interactive settings panel. |
| apps/sim/app/workspace/[workspaceId]/settings/components/general/general.tsx | Integrates new Tooltip.Preview component for the auto-connect and error-notification tooltips; no logic changes. |
Sequence Diagram
sequenceDiagram
participant Browser
participant NextServer as Next.js Server
participant DB as Database
participant ReactQuery as React Query (client)
Browser->>NextServer: Hard refresh /workspace/[id]
NextServer->>NextServer: getSession()
NextServer->>DB: getOrgWhitelabelSettings(orgId)
DB-->>NextServer: OrganizationWhitelabelSettings | null
NextServer-->>Browser: HTML with initialOrgSettings baked in
Note over Browser: BrandingProvider hydrates
Note over Browser: effectiveOrgSettings = initialOrgSettings
Note over Browser: (orgSettings still undefined)
Browser->>ReactQuery: useWhitelabelSettings(orgId) fires
ReactQuery-->>Browser: OrganizationWhitelabelSettings
Note over Browser: effectiveOrgSettings = orgSettings (live data)
Reviews (4): Last reviewed commit: "chore(whitelabeling): inline hasOrgBrand" | Re-trigger Greptile
|
@greptile |
|
@cursor review |
...orkspace/[workspaceId]/w/components/sidebar/components/workspace-header/workspace-header.tsx
Outdated
Show resolved
Hide resolved
… color is undefined
|
Both issues addressed: P1 — Blob preview dep cycle (Greptile): Fixed in a3c959e. Removed Missing color fallback (Cursor): Fixed in c70c8ef — using |
|
@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 0209873. Configure here.
…ver-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
* 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
BrandingProvider: drop the cookie-based cache mechanism entirely —effectiveOrgSettingsfalls back to the server-fetchedinitialOrgSettingswhile React Query is in flight, then switches to live data once resolved'whitelabeling'entry inSECTION_TITLESso the page title renders correctlyType of Change
Testing
Tested manually — hard refresh no longer flashes the Sim default logo before showing org branding
Checklist