Conversation
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (21)
📝 WalkthroughWalkthroughThis PR introduces white-label branding support across the explorer. Environment variables define chain naming and color customization, a new backend API endpoint (/api/config) exposes branding configuration, and frontend context providers fetch and apply these settings dynamically without requiring rebuilds. Changes
Sequence DiagramsequenceDiagram
participant App as Frontend App
participant BP as BrandingProvider
participant API as Backend /api/config
participant AppState as Server AppState
participant CSS as Document Root
App->>BP: Mount & Render
BP->>API: GET /api/config
API->>AppState: Read branding fields
AppState-->>API: Return BrandingConfig
API-->>BP: JSON response
BP->>BP: deriveSurfaceShades(accent_color, theme)
BP->>CSS: applyPalette(derived colors)
CSS->>CSS: Set CSS custom properties
BP->>BP: Provide via BrandingContext
App->>App: useContext(BrandingContext)
App->>App: Render with dynamic branding
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~40 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
.env.example (1)
23-27: Consider quoting hex color values for parser compatibility.Some
.envparsers may interpret#as the start of a comment, even without a preceding space. Quoting ensures the full hex value is captured.🔧 Suggested fix
-ACCENT_COLOR=#dc2626 # Primary accent color (links, buttons, active states) -BACKGROUND_COLOR_DARK=#050505 # Dark mode base background -BACKGROUND_COLOR_LIGHT=#f4ede6 # Light mode base background -SUCCESS_COLOR=#22c55e # Success indicator color -ERROR_COLOR=#dc2626 # Error indicator color +ACCENT_COLOR="#dc2626" # Primary accent color (links, buttons, active states) +BACKGROUND_COLOR_DARK="#050505" # Dark mode base background +BACKGROUND_COLOR_LIGHT="#f4ede6" # Light mode base background +SUCCESS_COLOR="#22c55e" # Success indicator color +ERROR_COLOR="#dc2626" # Error indicator color🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.env.example around lines 23 - 27, The hex color values in the .env example (ACCENT_COLOR, BACKGROUND_COLOR_DARK, BACKGROUND_COLOR_LIGHT, SUCCESS_COLOR, ERROR_COLOR) may be parsed incorrectly due to the leading #; update each variable to wrap the hex value in quotes (e.g., change ACCENT_COLOR=#dc2626 to ACCENT_COLOR="#dc2626") and apply the same quoting to any other color vars in the file so parsers don't treat # as a comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@backend/crates/atlas-api/src/main.rs`:
- Line 51: The CHAIN_NAME env handling currently accepts an empty string; change
the retrieval logic for chain_name (the variable initialized where
std::env::var("CHAIN_NAME") is called) to treat empty or whitespace-only values
as unset by checking the env var result and falling back to "Atlas" when the
value is Err or when the Ok string is empty/only whitespace (e.g., trim and test
is_empty), so chain_name uses the default branding unless a non-empty value is
provided.
In `@docs/WHITE_LABELING.md`:
- Around line 5-13: The docs currently conflict on the default branding: the
intro claims the explorer falls back to "ev-node" branding while the CHAIN_NAME
table lists the default as "Atlas"; pick one canonical default and make the text
consistent by updating either the opening paragraph (replace "ev-node" with
"Atlas") or the table default (replace "`Atlas`" with "`ev-node`"), and ensure
the CHAIN_NAME entry and any other references to default branding in
WHITE_LABELING.md use that same value.
In `@frontend/src/context/BrandingContext.tsx`:
- Line 76: The forEach callback currently implicitly returns the result of
root.style.removeProperty(v) (vars.forEach(v => root.style.removeProperty(v));)
which violates the useIterableCallbackReturn rule; change the callback to a
block body so it returns void (e.g., vars.forEach(v => {
root.style.removeProperty(v); });) making sure the callback for vars.forEach
does not return any value.
In `@frontend/src/utils/color.ts`:
- Around line 34-40: Normalize and validate the input inside hexToRgb: trim and
ensure it starts with or without '#', accept 3- or 6-character hex forms (expand
3-char shorthand to 6-char), verify the final cleaned string is exactly 6 hex
digits (0-9a-f/A-F), and if validation fails either throw a clear error or
return a safe default RGB; then parse r/g/b with parseInt on the validated
string to avoid NaN channels. Ensure these checks are implemented in hexToRgb so
downstream CSS variable generation never receives invalid channel values.
---
Nitpick comments:
In @.env.example:
- Around line 23-27: The hex color values in the .env example (ACCENT_COLOR,
BACKGROUND_COLOR_DARK, BACKGROUND_COLOR_LIGHT, SUCCESS_COLOR, ERROR_COLOR) may
be parsed incorrectly due to the leading #; update each variable to wrap the hex
value in quotes (e.g., change ACCENT_COLOR=#dc2626 to ACCENT_COLOR="#dc2626")
and apply the same quoting to any other color vars in the file so parsers don't
treat # as a comment.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (18)
.env.exampleREADME.mdbackend/crates/atlas-api/src/handlers/config.rsbackend/crates/atlas-api/src/handlers/mod.rsbackend/crates/atlas-api/src/main.rsdocker-compose.ymldocs/WHITE_LABELING.mdfrontend/nginx.conffrontend/src/App.tsxfrontend/src/api/config.tsfrontend/src/components/Layout.tsxfrontend/src/context/BrandingContext.tsxfrontend/src/context/branding-context.tsfrontend/src/hooks/useBranding.tsfrontend/src/index.cssfrontend/src/pages/WelcomePage.tsxfrontend/src/utils/color.tsfrontend/tailwind.config.js
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
backend/crates/atlas-api/src/main.rs (1)
17-30:⚠️ Potential issue | 🟠 Major
AppState.chain_idbootstrap is still missing.Line 17-Line 30 has no
chain_id: u64field, and Line 45-Line 94 does not fetcheth_chainIdonce at startup. This leaves themain.rsstartup contract incomplete.Based on learnings: "Applies to /atlas-api//main.rs : Fetch chain ID from RPC using
eth_chainIdonce at startup and store inAppState.chain_idasu64".Also applies to: 45-94
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/crates/atlas-api/src/main.rs` around lines 17 - 30, Add a chain_id: u64 field to the AppState struct and populate it once during startup by calling eth_chainId on the configured RPC URL; specifically, update the AppState definition to include pub chain_id: u64, then in main (the startup/initialization block where PgPool, rpc_url, solc_path, and admin_api_key are created) perform a single JSON-RPC call to eth_chainId using the rpc_url, parse the hex result to a u64, and assign that value to AppState.chain_id before constructing the AppState instance (handle RPC errors gracefully and bubble them up or log and exit).
🧹 Nitpick comments (1)
backend/crates/atlas-api/src/main.rs (1)
55-68: Normalize whitespace-only optional branding vars as unset.Line 57, Line 58, Line 61, Line 64, Line 67, and Line 68 only check
is_empty(), so values like" "are treated as configured. Consider trimming likeCHAIN_NAMEfor consistent optional behavior.Proposed refactor
let chain_logo_url = std::env::var("CHAIN_LOGO_URL") .ok() - .filter(|s| !s.is_empty()); -let accent_color = std::env::var("ACCENT_COLOR").ok().filter(|s| !s.is_empty()); + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()); +let accent_color = std::env::var("ACCENT_COLOR") + .ok() + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()); let background_color_dark = std::env::var("BACKGROUND_COLOR_DARK") .ok() - .filter(|s| !s.is_empty()); + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()); let background_color_light = std::env::var("BACKGROUND_COLOR_LIGHT") .ok() - .filter(|s| !s.is_empty()); + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()); let success_color = std::env::var("SUCCESS_COLOR") .ok() - .filter(|s| !s.is_empty()); -let error_color = std::env::var("ERROR_COLOR").ok().filter(|s| !s.is_empty()); + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()); +let error_color = std::env::var("ERROR_COLOR") + .ok() + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty());🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@backend/crates/atlas-api/src/main.rs` around lines 55 - 68, The optional branding env vars (chain_logo_url, accent_color, background_color_dark, background_color_light, success_color, error_color) currently only check .is_empty(), so whitespace-only values remain treated as set; update each std::env::var(...).ok().filter(|s| !s.is_empty()) to trim the string before emptiness check (e.g., .filter(|s| !s.trim().is_empty()) or map to s.trim().to_string() then check), mirroring the handling used for CHAIN_NAME, so whitespace-only values are normalized to unset.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@backend/crates/atlas-api/src/main.rs`:
- Around line 51-54: The chain_name fallback is incorrect: update the code that
sets chain_name (the
std::env::var("CHAIN_NAME").ok().filter(...).unwrap_or_else(...) expression) to
return "Unknown" instead of "Atlas" so the project uses the required default
when CHAIN_NAME is not provided.
In `@docs/WHITE_LABELING.md`:
- Around line 27-34: The fenced code block that starts with ``` in
WHITE_LABELING.md is untyped and triggers MD040; update the opening fence to
include a language tag (e.g., change ``` to ```text) so the block becomes a
typed fenced code block and resolves the lint warning for the snippet showing
the atlas/ directory tree.
---
Outside diff comments:
In `@backend/crates/atlas-api/src/main.rs`:
- Around line 17-30: Add a chain_id: u64 field to the AppState struct and
populate it once during startup by calling eth_chainId on the configured RPC
URL; specifically, update the AppState definition to include pub chain_id: u64,
then in main (the startup/initialization block where PgPool, rpc_url, solc_path,
and admin_api_key are created) perform a single JSON-RPC call to eth_chainId
using the rpc_url, parse the hex result to a u64, and assign that value to
AppState.chain_id before constructing the AppState instance (handle RPC errors
gracefully and bubble them up or log and exit).
---
Nitpick comments:
In `@backend/crates/atlas-api/src/main.rs`:
- Around line 55-68: The optional branding env vars (chain_logo_url,
accent_color, background_color_dark, background_color_light, success_color,
error_color) currently only check .is_empty(), so whitespace-only values remain
treated as set; update each std::env::var(...).ok().filter(|s| !s.is_empty()) to
trim the string before emptiness check (e.g., .filter(|s| !s.trim().is_empty())
or map to s.trim().to_string() then check), mirroring the handling used for
CHAIN_NAME, so whitespace-only values are normalized to unset.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a0a0d972-42cd-42be-b6dd-536c88ac6b04
📒 Files selected for processing (3)
backend/crates/atlas-api/src/main.rsdocs/WHITE_LABELING.mdfrontend/src/utils/color.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/src/utils/color.ts
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.env.example:
- Line 22: Replace the whitespace placeholder assignment for CHAIN_LOGO_URL with
a clean empty value (use CHAIN_LOGO_URL=) and move the explanatory text into a
commented line (e.g., # URL or path to logo (e.g., /branding/logo.png). Default:
bundled ev-node logo) so the env var is empty by default and the description
remains for contributors; update the CHAIN_LOGO_URL line in the example file
accordingly.
- Around line 23-27: Update the .env.example so the hex color values are quoted
to avoid parser/linter issues: wrap the values for ACCENT_COLOR,
BACKGROUND_COLOR_DARK, BACKGROUND_COLOR_LIGHT, SUCCESS_COLOR, and ERROR_COLOR in
quotes (e.g., " #... " or ' #... ') while keeping the existing inline comments
intact; this ensures cross-tool compatibility for dotenv parsers and linters
without changing the variable names or comments.
In `@backend/crates/atlas-api/src/main.rs`:
- Around line 55-68: Env vars for optional branding (chain_logo_url,
accent_color, background_color_dark, background_color_light, success_color,
error_color) should be normalized by trimming whitespace before empty-checking;
update each initializer to trim the retrieved String (e.g., via mapping to
s.trim().to_string() or using filter_map with s.trim()) and then filter out
empty results so whitespace-only values are treated as empty and not passed to
the frontend.
- Around line 51-68: Add a #[cfg(test)] mod tests block in the same file that
exercises the new env-parsing logic by setting and unsetting environment
variables and asserting the resulting values of chain_name, chain_logo_url,
accent_color, background_color_dark, background_color_light, success_color, and
error_color; specifically write tests for (1) unset vars producing None or the
default "Unknown" for chain_name, (2) empty-string vars treated as missing, and
(3) whitespace-only chain_name trimmed to default, using std::env::set_var and
std::env::remove_var to control state and re-evaluating the parsing code (call
the same expressions or extract the parsing into a small helper you can invoke
in tests), and run via cargo test --workspace.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b624a402-1e4c-4f38-9404-4e900ecf6480
📒 Files selected for processing (5)
.env.examplebackend/crates/atlas-api/src/main.rsdocker-compose.ymldocs/WHITE_LABELING.mdfrontend/src/context/branding-context.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- frontend/src/context/branding-context.ts
- docker-compose.yml
- docs/WHITE_LABELING.md
tac0turtle
left a comment
There was a problem hiding this comment.
how does it look on a slow internets, the default color would throw things off before the api config is loaded or is there a loading screen?
Add runtime-configurable branding via environment variables so each chain deployment can customize name, logo, colors without rebuilding. Backend: new /api/config endpoint serving branding config from env vars (CHAIN_NAME, CHAIN_LOGO_URL, ACCENT_COLOR, BACKGROUND_COLOR_DARK, BACKGROUND_COLOR_LIGHT, SUCCESS_COLOR, ERROR_COLOR). Frontend: BrandingContext fetches config once on load and applies CSS custom properties for accent, success/error, and derived surface palettes. Logo, chain name, favicon, and page title update dynamically. All values are optional with sensible defaults matching current Atlas branding.
- Run cargo fmt to wrap long env var lines in main.rs - Remove unused rgbToHex function and mode parameter in color.ts - Fix react-refresh/only-export-components by separating BrandingContext definition into branding-context.ts and useBranding hook into its own file Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Explain how to customize chain name, logo, and color scheme via environment variables. Includes examples for blue, green, and minimal configurations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The default branding comes from ev-node, not Atlas.
- Treat empty/whitespace CHAIN_NAME as unset, falling back to "Atlas" - Validate hex input in hexToRgb: trim, support 3-char shorthand, reject malformed values to avoid NaN CSS variables
Make the table header and intro consistent so operators understand that "Atlas" is the default ev-node branding, not a separate brand.
- Use block body in forEach to avoid implicit return (Biome rule) - Add language tag to fenced code block in docs (MD040) - Update CLAUDE.md to reflect "Atlas" as CHAIN_NAME default
Atlas is the indexer name, not a chain name. Deployers should always set CHAIN_NAME to their chain's actual name.
- Fix Tailwind accent colors to use rgb(var(...) / <alpha-value>) pattern so opacity modifiers (e.g. accent-primary/40) work correctly - Store accent CSS vars as RGB triplets instead of hex values - Convert hex to RGB triplets in BrandingContext via hexToRgbTriplet helper - Fix symlink frontend/public/branding to use relative path ../../branding - Add unit tests for BrandingConfig serialization in config.rs - Extract env-parsing into testable parse_chain_name/parse_optional_env helpers - Add unit tests for env-parsing (unset, empty, whitespace, valid values) - Trim whitespace on all optional branding env vars before filtering empties - Quote hex color values in .env.example for cross-tool compatibility - Clean up CHAIN_LOGO_URL whitespace placeholder in .env.example
6090c62 to
610df4a
Compare
- Fix cargo fmt: collapse parse_optional_env chain to single line - Remove frontend/public/branding symlink from git — it breaks CI and Docker builds where the target doesn't exist. Add to .gitignore so developers can create it locally per docs/WHITE_LABELING.md
The branding/ folder is needed for the docker-compose volume mount but its contents are chain-specific and should not be committed.
Summary
CHAIN_NAME,CHAIN_LOGO_URL,ACCENT_COLOR,BACKGROUND_COLOR_DARK,BACKGROUND_COLOR_LIGHT,SUCCESS_COLOR,ERROR_COLOR)GET /api/configendpoint serves branding config from environment variablesBrandingContextfetches config once on load, applies CSS custom properties for accent colors and derives surface palettes from background colorsTest plan
CHAIN_NAMEandACCENT_COLORin.env, verify title/links/buttons changeBACKGROUND_COLOR_DARK/BACKGROUND_COLOR_LIGHT, verify surface colors adapt in both themesCHAIN_LOGO_URLpointing to mounted branding asset, verify logo in navbar and welcome pagebunx vite buildsucceedsdocker compose build && docker compose up -dworks end-to-end🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
Documentation