Skip to content

fix(web): fix dark mode by changing @theme inline to @theme in index.css - #4

Closed
ada-evorada wants to merge 21 commits into
feature/claude-code-limits-sidebarfrom
fix/dark-mode-css-theme-inline
Closed

ada-evorada wants to merge 21 commits into
feature/claude-code-limits-sidebarfrom
fix/dark-mode-css-theme-inline

Conversation

@ada-evorada

Copy link
Copy Markdown

Summary

Fixes dark mode not working correctly across the dashboard UI.

  • Root cause: @theme inline in web/src/index.css caused all semantic token utility classes (bg-sidebar, bg-card, bg-background, bg-muted, etc.) to be compiled as static hardcoded light-mode values, making .dark CSS variable overrides completely ineffective
  • One-line CSS fix: Changed @theme inline { → @theme { so all semantic tokens use var() references that respond to dark mode — this fixes the sidebar, main layout, cards, tables, dialogs, and every component using semantic tokens
  • Toggle button: Fixed bg-white → bg-white dark:bg-zinc-100 for toggle thumb in agent-definition-shared.tsx
  • Charts: Added CHART_PALETTE_DARK with brighter colors for dark backgrounds; updated getAgentColor(agentType, dark?) to accept dark mode flag; passed useTheme() context to all 5 chart components
  • Pre-existing test fixes: Fixed 8 pre-existing test failures in credential-scoping.test.ts (env var cleanup using delete instead of assignment to undefined) and webhooks.test.ts (missing gitlabOnly: false field added by GitLab integration work)

Files Changed

  • web/src/index.css — @theme inline → @theme (root cause fix)
  • web/src/components/settings/agent-definition-shared.tsx — Toggle thumb bg-white → bg-white dark:bg-zinc-100
  • web/src/lib/chart-colors.ts — Added CHART_PALETTE_DARK, updated getAgentColor() to accept optional dark param
  • web/src/components/runs/work-item-cost-chart.tsx — Use useTheme() to pass dark flag to color functions
  • web/src/components/runs/work-item-duration-chart.tsx — Use useTheme() to pass dark flag to color functions
  • web/src/components/runs/project-work-duration-chart.tsx — Use useTheme() to pass dark flag to buildDurationChartData()
  • web/src/components/projects/work-item-duration-bar.tsx — Use useTheme() to pass dark flag to buildDurationSegments()
  • web/src/components/projects/project-work-table.tsx — Use useTheme() to pass dark flag to getAgentColor()
  • tests/unit/cli/credential-scoping.test.ts — Fix env var cleanup with delete operator
  • tests/unit/cli/dashboard/webhooks/webhooks.test.ts — Add gitlabOnly: false to expected webhook call args

Test plan

  • Switch to dark mode via the header sun/moon button; verify sidebar background turns dark
  • Verify header border/bg turns dark, table rows change, dialogs have dark backgrounds
  • Check the settings agent toggle thumb remains visible in dark mode
  • Check charts show brighter/lighter colors in dark mode
  • Run npm test — all 7349 tests pass (377 test files)
  • Run npm run typecheck — no type errors

Card: https://trello.com/c/m1yHLDkm/10-the-dark-mode-doesnt-seem-to-be-working-correctly

🤖 Generated with Claude Code

suda and others added 4 commits April 9, 2026 20:31
Add GitLab as a second SCM integration alongside GitHub, following the
existing IntegrationModule/SCMIntegration architecture. This enables
CASCADE to process GitLab merge request webhooks and run agents against
GitLab repositories.

Key additions:
- Core GitLab module (client via @gitbeaker/rest, dual-persona model,
  SCMIntegration implementation)
- Router layer (webhook route, signature verification, adapter, queue types)
- 9 trigger handlers (MR opened, pipeline success/failure, approval,
  reviewer added, comment mention, merged, conflict detected, ready to merge)
- 11 GitLab gadgets for agent MR operations
- SCM-provider-aware context pipeline, CLI commands, tool manifests,
  and agent system prompts
- Frontend SCM tab with GitHub/GitLab provider selector
- CLI webhook commands with --gitlab-only support
- GitLab webhook CRUD via API
- Worker entry GitLab job dispatch with CASCADE_SCM_PROVIDER env var
- PR/MR URL extraction supports both /pull/NNN and /merge_requests/NNN
- Post-execution work-item linking works for GitLab MRs
- Database migration for gitlab SCM provider CHECK constraint
- glab CLI installed in worker Docker image
- 100 unit tests across 7 test files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…mmit

- Add gitlabOnly: false to webhook CLI test expectations (create/delete)
- Add GITHUB_TOKEN_IMPLEMENTER and GITLAB_TOKEN_IMPLEMENTER env var clearing
  in credential-scoping test beforeEach to prevent cross-test contamination
- Add withGitLabToken mock to credential-scoping test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lnerability

Adds an npm override to force axios transitive dependency (from jira.js
and trello.js) to >=1.15.0, fixing CVE GHSA-3p68-rc4w-qgx5 (NO_PROXY
hostname normalization bypass leading to SSRF).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ada-evorada

Copy link
Copy Markdown
Author

CI Failures Resolved

Fixes Applied

  • Fixed critical security vulnerability: npm audit fix resolved the critical SSRF vulnerability in axios (<1.15.0) and moderate vulnerabilities in hono and @hono/node-server by updating package-lock.json
  • The npm audit --omit=dev --audit-level=high check now exits with code 0 (only moderate severity vulnerabilities remain, which are below the high threshold)

Verification

  • npm audit --omit=dev --audit-level=high passes (exit code 0)
  • All 7349 unit tests pass (377 test files)
  • TypeScript type checks pass
  • Lint passes (warnings only, no errors)
  • Changes pushed to branch

@suda suda left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Summary

The dark mode fix is correct and well-scoped. The @theme inline → @theme change is the right fix for Tailwind v4 dark mode, the test fixes are accurate, and the chart dark-palette approach is clean. One issue worth addressing before merge.

Code Issues

Should Fix

  • All 5 chart components — theme === 'dark' will not match when the user has selected "system" as their theme preference. In that case next-themes returns 'system' from theme, not 'dark', even when the OS is actually in dark mode. The hook also provides resolvedTheme which resolves 'system' to the actual 'light' or 'dark' value. All five files share the same pattern and should use resolvedTheme instead:

    // current (broken for system theme)
    const { theme } = useTheme();
    const isDark = theme === 'dark';
    
    // fix
    const { resolvedTheme } = useTheme();
    const isDark = resolvedTheme === 'dark';

    Files affected: work-item-cost-chart.tsx, work-item-duration-chart.tsx, project-work-duration-chart.tsx, work-item-duration-bar.tsx, project-work-table.tsx

@suda suda left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Summary

LGTM. The core CSS fix is correct, the implementation is consistent across all 5 chart components, and the test fixes are sound. All CI checks pass.

Nitpick (non-blocking)

In web/src/lib/chart-colors.ts, the comment block above CHART_PALETTE_DARK lists oklch hex approximations of the dark-mode theme chart colors (e.g. #4d6ef5, #38c98a…) but the actual palette entries below are different — they are brighter variants of the light-mode palette. The comment and the values don't correspond, which could confuse a future maintainer. A one-liner clarifying that the palette uses brightened light-mode variants rather than the theme oklch values would help.

Cascade Bot and others added 13 commits April 9, 2026 22:56
When multiple projects share the same Trello board and use requiredLabelId
to distinguish which cards belong to each project, the previous code only
checked the first matching project (via find()), causing bdgt-labeled cards
to be dispatched to the cascade project when cascade was first in the list.

Add resolveAllProjects() to RouterPlatformAdapter (optional) and implement
it in TrelloRouterAdapter to return all projects matching a board ID.
Update processRouterWebhook to iterate over all candidate projects and
dispatch to the first one whose label check passes, using that matched
project for postAck, buildJob, and job enqueue so the correct projectId
flows through the entire pipeline.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Trello webhook payload does not include the labels currently assigned
to a card — only movement information (listBefore/listAfter). When multiple
projects share the same board and are distinguished by requiredLabelId, the
previous implementation relied on dispatchWithCredentials (called per-project)
to discover a label mismatch. This caused the first project in the list
(cascade) to be selected even when the card carried a different project's label.

This fix moves the label lookup to resolveAllProjects, which now:
- Fetches the card's labels via the Trello API once, before the dispatch loop
- Returns only projects whose requiredLabelId matches the card's labels
- Falls back to catch-all projects (no requiredLabelId) when no specific match
- Returns all candidates if the API call fails (preserving the existing
  per-project guard in dispatchWithCredentials as a secondary check)

Also renames _event → event in dispatchWithCredentials (the parameter is
actively read, so the underscore prefix was misleading).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ble getCard call

- Fix webhook-processor.ts: when adapter implements resolveAllProjects,
  use its result directly (even []) instead of falling through to
  resolveProject. An empty result means the event was definitively
  filtered (label mismatch) and must not re-introduce excluded projects.
- Eliminate double getCard API call in happy path: mark projects returned
  by successful resolveAllProjects pre-filtering with _labelPreFiltered,
  causing dispatchWithCredentials to skip its secondary label guard. The
  guard still fires when resolveAllProjects fell back to all candidates
  due to an API error.
- Add RouterProjectConfig._labelPreFiltered internal field to router config.
- Add test: resolveAllProjects([]) short-circuits as "no project config
  found" without calling resolveProject or dispatchWithCredentials.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…pping

`ProjectConfigSchema` in `src/config/schema.ts` was missing `requiredLabelId`
from the trello object schema. Zod strips unknown keys by default, so the field
was silently discarded every time config was loaded from the database via
`validateConfig()`. This meant `project.trello?.requiredLabelId` was always
`undefined` at runtime, causing the required-label filter to never activate.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… resolution

When multiple projects share the same Trello board (distinguished by
requiredLabelId), the router correctly routes to the right project (e.g. bdgt)
and stores projectId in the job. However the worker was re-resolving the
project by boardId in processPMWebhook, returning the first matching project
(e.g. cascade) instead of the intended one.

Fix: pass jobData.projectId from the worker through processTrelloWebhook and
processJiraWebhook to processPMWebhook, where it bypasses the boardId-based
lookupProject and uses loadProjectConfigById directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… packages

Runs npm audit fix to update axios (critical SSRF vulnerability GHSA-3p68-rc4w-qgx5)
and hono/@hono/node-server (moderate vulnerabilities), resolving CI audit failure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use array index as React key in claude-code-limits.tsx to avoid
  reconciliation bugs when tokens share the same trailing 4 chars;
  suppress noArrayIndexKey lint rule with explanation
- Fix contradictory JSDoc on cacheByToken — remove false claim that
  raw tokens are not stored as cache keys
- Remove unused createMockUser import in claudeCodeLimits.test.ts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous implementation called https://api.anthropic.com/api/account
which does not exist in Anthropic's API for OAuth tokens. The Claude Code
CLI actually uses https://api.anthropic.com/api/oauth/profile to fetch
subscription/organization info.

Update fetchClaudeSubscriptionLimits to call the correct endpoint and
parse the organization.organization_type field for the plan name. Per-token
usage stats (messages/tokens used vs. limit) are not available from this
endpoint, so those fields return 0 and the UI hides them automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Split long lines in formatResetDate and extraUsage rendering to satisfy
biome's line-length formatting rules.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Extract parseBuckets() and parseExtraUsage() helpers from
  fetchClaudeSubscriptionLimits() to reduce cognitive complexity from
  16 to below the max of 15
- Fix import order in claude-code-limits.tsx (Separator before trpc)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@suda suda left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@ada-evorada please rebase on top of feature/claude-code-limits-sidebar

@suda
suda changed the base branch from claude/cranky-johnson to feature/claude-code-limits-sidebar April 10, 2026 17:08
Cascade Bot and others added 4 commits April 10, 2026 17:09
Resolves critical SSRF vulnerability in axios (<1.15.0) and moderate
vulnerabilities in hono/node-server and hono via npm audit fix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…in charts

Fixes chart dark mode not working when user has "system" theme selected.
next-themes returns 'system' from `theme` when OS dark mode is active, but
`resolvedTheme` correctly resolves to 'dark' or 'light' in all cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ada-evorada
ada-evorada force-pushed the fix/dark-mode-css-theme-inline branch from 2d135ac to e35db74 Compare April 10, 2026 17:10
@ada-evorada

Copy link
Copy Markdown
Author

Rebased on top of feature/claude-code-limits-sidebar. Resolved the merge conflict in tests/unit/cli/credential-scoping.test.ts by combining both changes: using delete instead of = undefined (from our PR) and including the GITLAB_TOKEN_IMPLEMENTER variable cleanup (from the feature branch). All 7393 tests pass.

@suda suda left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@ada-evorada please rebase on top of fix/dark-mode-css-theme-inline

@appsome appsome deleted a comment from ada-evorada Apr 10, 2026
@appsome appsome deleted a comment from ada-evorada Apr 10, 2026
suda pushed a commit that referenced this pull request Jun 1, 2026
…tructured envelope, --comment alias) (mongrel-intelligence#1190)

* docs(014): spec + plans for cascade-tools agent ergonomics

Adds docs/specs/014-cascade-tools-agent-ergonomics.md plus two plans
covering shared-infra and create-pr-review adoption. Prompted by prod
run 5d993b04-6e05-4ae1-b7de-8c274cf3496b.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(plan-014): lock plan 1 (shared-infra)

* feat(cascade-tools): plan 014/1 shared-infra — truthful prompts + envelope

Ships the root-cause fix for prod run 5d993b04-6e05-4ae1-b7de-8c274cf3496b
plus the shared infrastructure every future gadget inherits:

- System-prompt renderer (src/backends/shared/nativeToolPrompts.ts) stops
  stripping trailing 's' from array param names and claiming '<string>
  (repeatable)' for every array. Array-of-object params now render as
  `--<flag> '<json>'` with aliases appended via `|` and a one-line runnable
  example from the tool definition.
- Factory (src/gadgets/shared/cliCommandFactory.ts) gains oclif flag aliases,
  JSON parsing for array-of-object flags, file-input JSON parsing, `examples`
  wired into oclif `--help`, and Levenshtein-based 'did you mean' suggestions
  for mistyped flags (via fastest-levenshtein).
- New shared error envelope (src/gadgets/shared/errorEnvelope.ts) — every
  CLI failure emits `{"success":false,"error":{type,flag?,message,got?,
  expected?,hint?,example?}}` on stdout plus a one-line prose summary on
  stderr. All prior `this.error()` / flat `{success:false,error:"<string>"}`
  call sites migrated.
- Contracts widened: ParameterDefinition gains `cliAliases`, FileInput-
  Alternative gains `parseAs`, ToolManifest parameters carry `items`,
  `aliases`, `example`.
- Manifest generator threads the new fields through.
- bin/cascade-tools.js wraps `run()` to swallow oclif ExitError cleanly so
  the envelope isn't obscured by Node's default stack dump.

Plan-1 ACs #1–mongrel-intelligence#17 all delivered. 8438/8438 unit tests passing.

Test surface delta: 57 new unit tests across errorEnvelope.test.ts,
shared-nativeToolPrompts.test.ts, and factories.test.ts. Seven legacy
assertions encoding the pre-014 error surface updated in cli/cli-command-
factory, cli/file-input-flags, cli/scm/create-pr-sidecar, cli/scm/create-
pr-review-sidecar, backends/claude-code.

Plan 2 adopts the pattern on createPRReviewDef — zero shared-file edits —
proving the declarative-metadata invariant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(plan-014): lock plan 2 (createprreview-adopt)

* feat(cascade-tools): plan 014/2 createprreview-adopt + spec done

Applies the spec-014 declarative-metadata pattern to createPRReviewDef:

- --comment alias for --comments (the exact muscle-memory mistake from
  prod run 5d993b04-6e05-4ae1-b7de-8c274cf3496b).
- --comments-file <path> (and - for stdin) JSON-parsed escape hatch for
  long payloads that don't survive shell quoting.
- Two declarative fields on createPRReviewDef.parameters.comments.cliAliases
  + createPRReviewDef.cli.fileInputAlternatives. Zero edits to shared
  infrastructure (cliCommandFactory, manifestGenerator, nativeToolPrompts,
  errorEnvelope) — proves spec 014's single-entrypoint invariant.

Per-plan ACs #1, #2, #3, #5, #6, #7, #8, #9, mongrel-intelligence#11, mongrel-intelligence#12 auto-verified
(unit tests + build + lint + typecheck). AC #4 (binary-level smoke)
tagged [manual] because vitest fork-pool workers fail to capture
stdout/stderr from spawned binaries that do top-level await import();
the six scenarios were verified manually against the built binary and
the trace is recorded in the plan. AC #10 n/a — integration test path
abandoned for the same reason.

All plans done. Spec 014 marked .done (docs/specs/014-*.md → .done).
CHANGELOG Unreleased updated with a per-plan entry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@suda
suda force-pushed the feature/claude-code-limits-sidebar branch from 7766fdc to 8a8a329 Compare August 2, 2026 11:25
@suda suda closed this Aug 2, 2026
@suda
suda deleted the fix/dark-mode-css-theme-inline branch August 2, 2026 11:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants