Skip to content

feat: redesign code app, admin dashboard, and UI - #1867

Merged
smakosh merged 4 commits into
mainfrom
feat/redesign-admin-ui
Mar 22, 2026
Merged

smakosh merged 4 commits into
mainfrom
feat/redesign-admin-ui

Conversation

@smakosh

@smakosh smakosh commented Mar 22, 2026

Copy link
Copy Markdown
Member

Summary

  • Code app: Redesign landing page with 3x value messaging and terminal preview; redesign dashboard with usage meter, quick start, and improved layout
  • Admin dashboard: Add error type breakdown columns (client/gateway/upstream) to models and mappings tables, refactor history chart to use per-component data fetching, simplify model detail page
  • UI: Redesign integration cards with Dev Plans CTA banner, add model benchmarks component, align log API types with generated v1.d.ts, update landing hero and navbar
  • Cleanup: Remove deprecated Autohand and Codex CLI guides from docs and UI

Test plan

  • Verify code app landing page and dashboard render correctly
  • Verify admin models table shows client/gateway/upstream error columns
  • Verify admin model detail page history chart loads per-provider data
  • Verify UI integration cards page shows Dev Plans CTA
  • Verify model benchmarks display on model detail pages
  • Verify removed guides (Autohand, Codex CLI) no longer appear
  • Run pnpm build to confirm production builds pass

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Model benchmark panel: Arena leaderboard ranks and provider performance (TTFT, error rates) shown on model pages via a new benchmarks section and internal API.
  • UI Improvements

    • Dashboard: usage meter, redesigned API key UI, quick-start snippets.
    • Landing & pricing: expanded marketing layout, plans now display usage per tier.
    • Integrations: refreshed layout and CTA card.
  • Admin Enhancements

    • Admin tables now show client/gateway/upstream error counts and support sorting by them.

- Code: redesign landing page and dashboard with usage
  meter, quick start, and improved layout
- Admin: add error type breakdown (client/gateway/upstream),
  refactor history chart and model detail components
- UI: redesign integration cards with dev plans CTA,
  add model benchmarks, align log API types
- Remove deprecated Autohand and Codex CLI guides

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

coderabbitai Bot commented Mar 22, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 79c31dbe-519e-4f6c-9c94-186dad71f7bb

📥 Commits

Reviewing files that changed from the base of the PR and between 1303a1f and 583409c.

⛔ Files ignored due to path filters (4)
  • apps/code/src/lib/api/v1.d.ts is excluded by !**/v1.d.ts
  • apps/playground/src/lib/api/v1.d.ts is excluded by !**/v1.d.ts
  • apps/ui/src/lib/api/v1.d.ts is excluded by !**/v1.d.ts
  • ee/admin/src/lib/api/v1.d.ts is excluded by !**/v1.d.ts
📒 Files selected for processing (1)
  • apps/api/src/routes/admin.ts

Walkthrough

Adds cached Arena leaderboard fetching/matching, a new internal model benchmarks endpoint, UI components to display benchmarks and provider performance, dashboard and landing UI redesigns, and admin history/metrics refactors including three new per-model error-count metrics.

Changes

Cohort / File(s) Summary
Arena Benchmarks
apps/api/src/lib/arena-benchmarks.ts
New module: in-memory cached Arena leaderboard fetcher + HTML/JSON parsing, static fallback data, getArenaBenchmarks() and findArenaMatch() fuzzy-matching logic.
Internal Models API
apps/api/src/routes/internal-models.ts
New route GET /models/{modelId}/benchmarks returning provider counters and arena matches; integrates getArenaBenchmarks()/findArenaMatch().
Admin API / Metrics
apps/api/src/routes/admin.ts
Added clientErrorsCount, gatewayErrorsCount, upstreamErrorsCount aggregates to models and provider-mapping endpoints; removed /models/{modelId}/providers/history route.
Model Benchmarks UI
apps/ui/src/components/models/model-benchmarks.tsx, apps/ui/src/app/models/[name]/page.tsx
New client component fetching /internal/models/{id}/benchmarks, renders Arena rank badges and provider TTFT/error-rate breakdowns; integrated into model page.
Dashboard — Usage & API Key
apps/code/src/app/dashboard/DashboardClient.tsx, .../components/*, apps/code/src/app/dashboard/types.ts
Refactored dashboard: added UsageMeter, ApiKeySection, QuickStart; plan usage field added; updated plan cards and related components.
Landing & Navbar Data Flow
apps/code/src/app/page.tsx, apps/ui/src/components/landing/hero-rsc.tsx, .../hero.tsx, .../navbar.tsx
Landing page redesign; RSC now fetches models/providers and passes them to Hero/Navbar and ModelSearch.
Activity Logs — Types & Normalization
apps/ui/src/types/activity.ts, .../activity/*, apps/ui/src/components/activity/recent-logs.tsx
Switched log typings to OpenAPI paths types, added LogDetailData, and centralized log-to-UI conversion/date normalization.
Integrations & CTAs
apps/ui/src/components/integrations/integration-cards.tsx, apps/code/src/app/dashboard/components/DashboardIntegrations.tsx
Updated integrations list, added DevPlans CTA card, conditional link wrapping, and new Cursor integration.
Admin UI — History Refactor
ee/admin/src/components/history-chart.tsx, model-detail-client.tsx, model-provider-charts.tsx, ee/admin/src/lib/admin-history.ts, ee/admin/src/lib/types.ts
Removed externally-controlled history props; require per-chart fetchData; removed getModelProviderHistories() and its response type; changed default history window handling.
Admin UI — Error Columns
ee/admin/src/app/model-provider-mappings/page.tsx, ee/admin/src/components/models-table.tsx
Added three sortable numeric columns for client/gateway/upstream error counts and adjusted column spans/sort enums.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant UI as "Model Page UI"
participant API as "Internal Models API"
participant Bench as "Arena Benchmarks Module"
participant Arena as "External Arena Site"
UI->>API: GET /internal/models/{id}/benchmarks
API->>Bench: getArenaBenchmarks()
Bench->>Arena: fetch leaderboard pages (text, code)
Arena-->>Bench: HTML with NEXT_DATA/JSON
Bench-->>API: parsed arena entries (cached or fallback)
API-->>UI: { modelId, providers, arena } response

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • steebchen
  • rcogal
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: a comprehensive redesign across the code app, admin dashboard, and UI components. It is concise, clear, and directly reflects the primary objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/redesign-admin-ui

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ee/admin/src/components/history-chart.tsx (1)

113-137: ⚠️ Potential issue | 🟠 Major

Guard against stale responses from superseded window requests.

When loadData(window) is called with rapid window changes, async responses can complete out-of-order. If the user switches windows (e.g., 4h → 1h) before an older request finishes, the stale 4h response can overwrite the fresh 1h data and incorrectly set loading to false. Use an AbortController or request ID to cancel/ignore responses from superseded requests, ensuring only the latest window's data is applied to state.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ee/admin/src/components/history-chart.tsx` around lines 113 - 137, The
loadData handler can apply stale async responses when windows change; modify
loadData/useEffect to ignore superseded requests by sequencing them with a
per-call token (e.g., incrementing requestId or using an AbortController signal)
so only the latest request updates state. Generate a local request identifier
(or create an AbortController and pass its signal into fetchData), capture the
id/controller in the closure, and in the response path check that the id matches
(or the controller wasn’t aborted) before calling setData and setLoading; also
ensure previous requests are aborted or invalidated when internalWindow/window
changes (cleanup in the effect) so loading and data reflect only the newest
window.
🧹 Nitpick comments (8)
apps/code/src/app/dashboard/components/ActivePlanChangeTier.tsx (1)

49-51: Minor JSX spacing inconsistency.

The usage display on line 50 concatenates the ArrowRight icon directly with the text without proper spacing elements. Compare with InactivePlanChooser.tsx (lines 48-51) which uses separate <span> elements for consistent spacing.

💅 Proposed fix for consistent spacing
-							<div className="mb-4 flex items-center gap-1.5 text-xs text-muted-foreground">
-								<ArrowRight className="h-3 w-3" />${plan.usage} in usage
-							</div>
+							<div className="mb-4 flex items-center gap-1.5 text-xs text-muted-foreground">
+								<ArrowRight className="h-3 w-3" />
+								<span className="font-medium">${plan.usage}</span>
+								<span>in usage</span>
+							</div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/code/src/app/dashboard/components/ActivePlanChangeTier.tsx` around lines
49 - 51, The JSX layout in ActivePlanChangeTier (the ArrowRight icon next to the
usage text) lacks consistent spacing; update the render to mirror
InactivePlanChooser by separating the icon and the text into sibling elements
(e.g., keep <ArrowRight ... /> and move the "${plan.usage} in usage" into its
own <span> or element) so spacing and styling match other components; ensure you
reference the ArrowRight element and the plan.usage value when making the
change.
apps/code/src/app/dashboard/DashboardClient.tsx (2)

190-230: Same clipboard error handling consideration applies here.

The copySnippet function should also handle potential clipboard failures for consistency with other copy operations in the codebase.

🛡️ Proposed defensive handling
 	const copySnippet = async () => {
 		const snippet = `export ANTHROPIC_BASE_URL=https://api.llmgateway.io\nexport ANTHROPIC_AUTH_TOKEN=${apiKey}\nclaude`;
-		await navigator.clipboard.writeText(snippet);
-		toast.success("Snippet copied");
+		try {
+			await navigator.clipboard.writeText(snippet);
+			toast.success("Snippet copied");
+		} catch {
+			toast.error("Failed to copy");
+		}
 	};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/code/src/app/dashboard/DashboardClient.tsx` around lines 190 - 230, The
copySnippet function in QuickStart lacks clipboard error handling; wrap the
navigator.clipboard.writeText call in a try/catch inside QuickStart.copySnippet,
await the write inside the try, call toast.success on success and toast.error
(and optionally console.error the caught error) on failure so clipboard failures
are gracefully reported to the user; update the onClick handler to still call
copySnippet as before.

122-188: Consider handling clipboard API failures.

The copy function (line 125-128) doesn't handle potential clipboard API errors. While modern browsers widely support this API, it can fail in certain contexts (e.g., non-secure origins, iframe restrictions).

🛡️ Proposed defensive handling
 	const copy = async () => {
-		await navigator.clipboard.writeText(apiKey);
-		toast.success("Copied to clipboard");
+		try {
+			await navigator.clipboard.writeText(apiKey);
+			toast.success("Copied to clipboard");
+		} catch {
+			toast.error("Failed to copy");
+		}
 	};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/code/src/app/dashboard/DashboardClient.tsx` around lines 122 - 188, The
copy handler in ApiKeySection may throw if navigator.clipboard.writeText fails;
wrap the writeText call in a try/catch inside the copy function (the one defined
in ApiKeySection) and on success keep toast.success("Copied to clipboard"), on
failure call toast.error with a descriptive message and optionally implement a
DOM fallback (temporary textarea + select + document.execCommand('copy')) to
support non-secure contexts; ensure all branches are async/await safe and do not
leave temporary DOM elements behind.
apps/code/src/app/page.tsx (1)

23-63: Consider extracting shared plans data.

The plans array is duplicated between this file and DashboardClient.tsx (lines 42-65). While the structures differ slightly (this one includes features array), the core tier data (name, price, usage, tier, popular) is identical.

This could be extracted to a shared constant (e.g., in types.ts or a new constants.ts) to ensure pricing and usage values stay in sync. The landing page could extend the base data with the features array.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/code/src/app/page.tsx` around lines 23 - 63, Extract the duplicated core
plan data into a shared constant (e.g., basePlans) in a common module (types.ts
or constants.ts) and replace the local plans array here with an extended version
that imports basePlans and adds the page-specific features; update
DashboardClient.tsx to import the same basePlans instead of its duplicate so
name/price/usage/tier/popular stay in sync. Locate the existing "plans" array in
this file and the similar block in DashboardClient.tsx to perform the extraction
and ensure the landing-page code merges features onto the shared base objects
rather than redefining core fields.
apps/ui/src/app/dashboard/[orgId]/[projectId]/activity/[logId]/log-detail-client.tsx (1)

192-200: Consider type assertion safety.

The as Log cast on line 200 assumes the API response structure matches the database Log type after normalization. If the API response contains fields not in the db schema (or vice versa), this could cause subtle type mismatches.

The video-related field normalizations (lastVideoDownloadedAt, videoDownloadCount) are well-handled with proper Date conversion and nullish coalescing.

💡 Consider creating a dedicated UI log type

Instead of casting to Log, consider defining a UiLog type that explicitly declares all fields used in this component. This would make the type expectations explicit rather than relying on the cast.

// In a shared types file
type UiLog = Omit<Log, 'createdAt' | 'updatedAt' | 'lastVideoDownloadedAt'> & {
  createdAt: Date;
  updatedAt: Date;
  lastVideoDownloadedAt: Date | null;
  videoOutputCost?: number | string;
  // ... other API-specific fields
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/ui/src/app/dashboard/`[orgId]/[projectId]/activity/[logId]/log-detail-client.tsx
around lines 192 - 200, The current cast "as Log" on the normalized "log" object
is unsafe; replace the assertion with an explicit UI-specific type (e.g., UiLog)
and use that type for the normalized object instead of Log, updating the
normalization logic around
createdAt/updatedAt/lastVideoDownloadedAt/videoDownloadCount to produce values
matching UiLog's fields; create UiLog (or import it) to explicitly declare Date
vs null and any API-only fields and then type the "log" constant as UiLog to
avoid blind casting.
apps/ui/src/components/activity/recent-logs.tsx (1)

47-59: The as any casts indicate a type gap between API and db types.

The toUiLog function effectively normalizes API responses for UI consumption. The as any casts for toolChoice and customHeaders (lines 56-57) work around type mismatches between the OpenAPI schema and the db-derived Log type.

This approach functions correctly at runtime, but the type coercion could mask issues if the API schema changes.

💡 Consider defining explicit type mappings

If the API and db types for these fields are structurally compatible but nominally different, consider using mapped types or explicit field assignments to avoid as any:

 function toUiLog(log: ApiLog): Partial<Log> {
   return {
     ...log,
     createdAt: new Date(log.createdAt),
     updatedAt: new Date(log.updatedAt),
     lastVideoDownloadedAt: log.lastVideoDownloadedAt
       ? new Date(log.lastVideoDownloadedAt)
       : null,
     videoDownloadCount: log.videoDownloadCount ?? undefined,
-    toolChoice: log.toolChoice as any,
-    customHeaders: log.customHeaders as any,
+    toolChoice: log.toolChoice as Log['toolChoice'],
+    customHeaders: log.customHeaders as Log['customHeaders'],
   };
 }

This preserves the intent while providing slightly better type documentation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ui/src/components/activity/recent-logs.tsx` around lines 47 - 59, The
toUiLog function uses unsafe "as any" casts for toolChoice and customHeaders
which hides schema mismatches; instead, create explicit mapping/conversion logic
inside toUiLog that transforms ApiLog.toolChoice and ApiLog.customHeaders into
the UI Log types (e.g., map enum values or parse objects), or introduce small
adapter helpers (e.g., mapToolChoice(apiToolChoice) and
normalizeCustomHeaders(apiHeaders)) and return those typed values so you avoid
using "as any" while preserving runtime behavior.
apps/ui/src/components/integrations/integration-cards.tsx (1)

213-213: Avoid as any type assertion.

The as any cast bypasses type safety. If Next.js typed routes are enabled (typedRoutes in next.config), consider using the proper route type or a more specific cast.

♻️ Suggested fix

If typed routes are not strictly enforced for dynamic paths, you can use a typed route utility or cast to the expected type:

-							href={integration.href as any}
+							href={integration.href as `/guides/${string}`}

Alternatively, if the routes are statically known, define them as typed route literals in the integrations array.

As per coding guidelines: "Never use any or as any in TypeScript unless absolutely necessary."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ui/src/components/integrations/integration-cards.tsx` at line 213, The
use of "as any" on integration.href in integration-cards.tsx bypasses TypeScript
safety; replace it by giving integration.href a precise type (e.g., string |
UrlObject or the Next.js typed route type) in the integrations array/type
definition and pass that typed value directly to the Link/href prop (or, if
using Next.js typedRoutes, cast to the specific generated route type instead of
any). Locate the integrations definition and the Link usage referencing
integration.href and update the integration interface/type to the correct href
type, or convert integration.href to string with a safe cast (e.g., to string)
only if it is guaranteed to be one, then remove the "as any" assertion.
apps/api/src/routes/internal-models.ts (1)

287-303: Prefer the Drizzle query API for this read.

This new benchmark lookup is the one changed DB read in the file that drops down to select(...).innerJoin(...). Keeping it on the query API would align it with the rest of the route layer and the repository convention.

As per coding guidelines "For database reads in Drizzle ORM, use db().query.<table>.findMany() or db().query.<table>.findFirst()".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/api/src/routes/internal-models.ts` around lines 287 - 303, The current
DB read uses db.select(...).from(...).innerJoin(...) (creating mappings) which
deviates from our Drizzle query API convention; replace that block with the
Drizzle query API by calling db().query.modelProviderMapping.findMany (or
findFirst if appropriate) and include the provider relation (via the
`with`/relation option) so you select the same fields (providerId, providerName
from tables.provider.name, and all modelProviderMapping metrics like logsCount,
errorsCount, clientErrorsCount, gatewayErrorsCount, upstreamErrorsCount,
cachedCount, avgTimeToFirstToken). Ensure the resulting shape matches the
existing `mappings` usage and reference tables.modelProviderMapping and
tables.provider only to map column names if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/api/src/routes/admin.ts`:
- Line 3131: The handler for getModelDetail uses const window = query.window ??
"24h" but the request schema sets a default("4h"), making the "24h" fallback
unreachable; update the handler to use the same default as the schema (change
the fallback to "4h" or remove the fallback and rely on the schema) so the
variable resolution in getModelDetail/window matches the schema default and
aligns with getProviderHistory/getModelHistory.

In `@apps/api/src/routes/internal-models.ts`:
- Around line 304-309: The query filters only modelProviderMapping.status but
not the joined provider row; update the where clause that currently uses
and(eq(tables.modelProviderMapping.modelId, modelId),
eq(tables.modelProviderMapping.status, "active")) to also require the provider
row be active by adding a predicate like eq(tables.providers.status, "active")
(i.e., include the provider status check alongside modelProviderMapping.status)
so both the mapping and the provider are constrained to "active"; locate this
change near the existing use of tables.modelProviderMapping and ensure the
provider status column name (e.g., tables.providers.status or
tables.provider.status) matches the schema.

In `@apps/ui/src/components/models/all-models.tsx`:
- Around line 191-197: The check for model.output including "video" is invalid
because the Model.output type is ("text" | "image")[]; either add "video" to the
Model.output union in the Model definition (packages/models/src/models.ts) so
"video" is a valid value, or remove the dead branches that check
model?.output?.includes("video") (in
apps/ui/src/components/models/all-models.tsx — the capability push at the shown
diff, the related filter logic around line 749, and the getCapabilityIcons
function around lines 1227-1233); update all three sites consistently so the
code and the Model.output type remain in sync.

In `@apps/ui/src/components/models/model-benchmarks.tsx`:
- Around line 56-90: The component currently only checks isLoading and then
treats missing data as "no benchmarks", so API failures are indistinguishable
from empty results; update the useQuery call to also destructure isError and
error (and refetch) from useQuery, then add a branch before the empty-data check
that renders a distinct error state when isError is true: show an error message
including error.message and a retry action that calls refetch; keep the existing
hasProviderData/hasArenaData logic unchanged for the successful-empty case.

In `@ee/admin/src/components/model-detail-client.tsx`:
- Around line 112-114: The useEffect that calls loadStats(window) can allow
out-of-order responses to overwrite stats/providers and loading; modify
loadStats (or wrap the call in this effect) to accept and use an AbortController
or numeric request token: create a controller/token before calling loadStats,
pass it into loadStats (or attach it to the fetch inside loadStats),
cancel/abort the previous controller or increment the token on each effect run,
and inside loadStats ignore responses when the controller is aborted or the
token no longer matches; ensure you also set loading to true only for the active
request and only update stats/providers when the request is still valid.

---

Outside diff comments:
In `@ee/admin/src/components/history-chart.tsx`:
- Around line 113-137: The loadData handler can apply stale async responses when
windows change; modify loadData/useEffect to ignore superseded requests by
sequencing them with a per-call token (e.g., incrementing requestId or using an
AbortController signal) so only the latest request updates state. Generate a
local request identifier (or create an AbortController and pass its signal into
fetchData), capture the id/controller in the closure, and in the response path
check that the id matches (or the controller wasn’t aborted) before calling
setData and setLoading; also ensure previous requests are aborted or invalidated
when internalWindow/window changes (cleanup in the effect) so loading and data
reflect only the newest window.

---

Nitpick comments:
In `@apps/api/src/routes/internal-models.ts`:
- Around line 287-303: The current DB read uses
db.select(...).from(...).innerJoin(...) (creating mappings) which deviates from
our Drizzle query API convention; replace that block with the Drizzle query API
by calling db().query.modelProviderMapping.findMany (or findFirst if
appropriate) and include the provider relation (via the `with`/relation option)
so you select the same fields (providerId, providerName from
tables.provider.name, and all modelProviderMapping metrics like logsCount,
errorsCount, clientErrorsCount, gatewayErrorsCount, upstreamErrorsCount,
cachedCount, avgTimeToFirstToken). Ensure the resulting shape matches the
existing `mappings` usage and reference tables.modelProviderMapping and
tables.provider only to map column names if needed.

In `@apps/code/src/app/dashboard/components/ActivePlanChangeTier.tsx`:
- Around line 49-51: The JSX layout in ActivePlanChangeTier (the ArrowRight icon
next to the usage text) lacks consistent spacing; update the render to mirror
InactivePlanChooser by separating the icon and the text into sibling elements
(e.g., keep <ArrowRight ... /> and move the "${plan.usage} in usage" into its
own <span> or element) so spacing and styling match other components; ensure you
reference the ArrowRight element and the plan.usage value when making the
change.

In `@apps/code/src/app/dashboard/DashboardClient.tsx`:
- Around line 190-230: The copySnippet function in QuickStart lacks clipboard
error handling; wrap the navigator.clipboard.writeText call in a try/catch
inside QuickStart.copySnippet, await the write inside the try, call
toast.success on success and toast.error (and optionally console.error the
caught error) on failure so clipboard failures are gracefully reported to the
user; update the onClick handler to still call copySnippet as before.
- Around line 122-188: The copy handler in ApiKeySection may throw if
navigator.clipboard.writeText fails; wrap the writeText call in a try/catch
inside the copy function (the one defined in ApiKeySection) and on success keep
toast.success("Copied to clipboard"), on failure call toast.error with a
descriptive message and optionally implement a DOM fallback (temporary textarea
+ select + document.execCommand('copy')) to support non-secure contexts; ensure
all branches are async/await safe and do not leave temporary DOM elements
behind.

In `@apps/code/src/app/page.tsx`:
- Around line 23-63: Extract the duplicated core plan data into a shared
constant (e.g., basePlans) in a common module (types.ts or constants.ts) and
replace the local plans array here with an extended version that imports
basePlans and adds the page-specific features; update DashboardClient.tsx to
import the same basePlans instead of its duplicate so
name/price/usage/tier/popular stay in sync. Locate the existing "plans" array in
this file and the similar block in DashboardClient.tsx to perform the extraction
and ensure the landing-page code merges features onto the shared base objects
rather than redefining core fields.

In
`@apps/ui/src/app/dashboard/`[orgId]/[projectId]/activity/[logId]/log-detail-client.tsx:
- Around line 192-200: The current cast "as Log" on the normalized "log" object
is unsafe; replace the assertion with an explicit UI-specific type (e.g., UiLog)
and use that type for the normalized object instead of Log, updating the
normalization logic around
createdAt/updatedAt/lastVideoDownloadedAt/videoDownloadCount to produce values
matching UiLog's fields; create UiLog (or import it) to explicitly declare Date
vs null and any API-only fields and then type the "log" constant as UiLog to
avoid blind casting.

In `@apps/ui/src/components/activity/recent-logs.tsx`:
- Around line 47-59: The toUiLog function uses unsafe "as any" casts for
toolChoice and customHeaders which hides schema mismatches; instead, create
explicit mapping/conversion logic inside toUiLog that transforms
ApiLog.toolChoice and ApiLog.customHeaders into the UI Log types (e.g., map enum
values or parse objects), or introduce small adapter helpers (e.g.,
mapToolChoice(apiToolChoice) and normalizeCustomHeaders(apiHeaders)) and return
those typed values so you avoid using "as any" while preserving runtime
behavior.

In `@apps/ui/src/components/integrations/integration-cards.tsx`:
- Line 213: The use of "as any" on integration.href in integration-cards.tsx
bypasses TypeScript safety; replace it by giving integration.href a precise type
(e.g., string | UrlObject or the Next.js typed route type) in the integrations
array/type definition and pass that typed value directly to the Link/href prop
(or, if using Next.js typedRoutes, cast to the specific generated route type
instead of any). Locate the integrations definition and the Link usage
referencing integration.href and update the integration interface/type to the
correct href type, or convert integration.href to string with a safe cast (e.g.,
to string) only if it is guaranteed to be one, then remove the "as any"
assertion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ea1f7814-6985-4c53-b852-e92984463af8

📥 Commits

Reviewing files that changed from the base of the PR and between d8310a6 and 1c0c686.

⛔ Files ignored due to path filters (3)
  • apps/code/src/lib/api/v1.d.ts is excluded by !**/v1.d.ts
  • apps/ui/src/lib/api/v1.d.ts is excluded by !**/v1.d.ts
  • ee/admin/src/lib/api/v1.d.ts is excluded by !**/v1.d.ts
📒 Files selected for processing (36)
  • apps/api/src/lib/arena-benchmarks.ts
  • apps/api/src/routes/admin.ts
  • apps/api/src/routes/internal-models.ts
  • apps/code/src/app/dashboard/DashboardClient.tsx
  • apps/code/src/app/dashboard/components/ActivePlanChangeTier.tsx
  • apps/code/src/app/dashboard/components/DashboardIntegrations.tsx
  • apps/code/src/app/dashboard/components/DevPlanSettings.tsx
  • apps/code/src/app/dashboard/components/InactivePlanChooser.tsx
  • apps/code/src/app/dashboard/types.ts
  • apps/code/src/app/page.tsx
  • apps/docs/content/guides/autohand.mdx
  • apps/docs/content/guides/codex-cli.mdx
  • apps/docs/lib/custom-icons.tsx
  • apps/ui/src/app/dashboard/[orgId]/[projectId]/activity/[logId]/log-detail-client.tsx
  • apps/ui/src/app/dashboard/[orgId]/[projectId]/activity/[logId]/page.tsx
  • apps/ui/src/app/models/[name]/page.tsx
  • apps/ui/src/components/activity/recent-logs.tsx
  • apps/ui/src/components/dashboard/log-card.tsx
  • apps/ui/src/components/integrations/integration-cards.tsx
  • apps/ui/src/components/landing/hero-rsc.tsx
  • apps/ui/src/components/landing/hero.tsx
  • apps/ui/src/components/landing/navbar.tsx
  • apps/ui/src/components/models/all-models.tsx
  • apps/ui/src/components/models/model-benchmarks.tsx
  • apps/ui/src/content/guides/autohand.md
  • apps/ui/src/content/guides/codex-cli.md
  • apps/ui/src/types/activity.ts
  • ee/admin/src/app/model-provider-mappings/page.tsx
  • ee/admin/src/app/models/[modelId]/page.tsx
  • ee/admin/src/components/history-chart.tsx
  • ee/admin/src/components/model-detail-client.tsx
  • ee/admin/src/components/model-provider-charts.tsx
  • ee/admin/src/components/models-table.tsx
  • ee/admin/src/lib/admin-history.ts
  • ee/admin/src/lib/types.ts
  • packages/shared/src/components/integration-icons.tsx
💤 Files with no reviewable changes (8)
  • apps/ui/src/content/guides/autohand.md
  • ee/admin/src/lib/types.ts
  • apps/docs/content/guides/autohand.mdx
  • apps/docs/lib/custom-icons.tsx
  • apps/ui/src/content/guides/codex-cli.md
  • apps/docs/content/guides/codex-cli.mdx
  • packages/shared/src/components/integration-icons.tsx
  • ee/admin/src/lib/admin-history.ts

Comment thread apps/api/src/lib/arena-benchmarks.ts
Comment thread apps/api/src/routes/admin.ts Outdated
Comment thread apps/api/src/routes/internal-models.ts
Comment thread apps/ui/src/components/models/all-models.tsx Outdated
Comment thread apps/ui/src/components/models/model-benchmarks.tsx
Comment thread ee/admin/src/components/model-detail-client.tsx
@smakosh smakosh self-assigned this Mar 22, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/ui/src/components/integrations/integration-cards.tsx`:
- Around line 228-236: Replace the unsafe "as any" cast on the Link href by
giving integration.href a proper type that matches Next's typed routes or by
casting to the correct Route type; update the Integration interface/where
integration.href is created so it is typed as the Next Route (or string | Route
as appropriate) and then remove "as any" in the Link usage (i.e., change
href={integration.href as any} to href={integration.href} or
href={integration.href as Route}); locate the Link usage and the Integration
type/creator to ensure the types align and compile without using any.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3069a5e6-acb3-4640-9cb0-ec21ad152b9c

📥 Commits

Reviewing files that changed from the base of the PR and between 1c0c686 and 1303a1f.

📒 Files selected for processing (4)
  • apps/ui/src/app/dashboard/[orgId]/[projectId]/activity/[logId]/log-detail-client.tsx
  • apps/ui/src/components/activity/recent-logs.tsx
  • apps/ui/src/components/integrations/integration-cards.tsx
  • apps/ui/src/types/activity.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/ui/src/types/activity.ts
  • apps/ui/src/components/activity/recent-logs.tsx

Comment thread apps/ui/src/components/integrations/integration-cards.tsx
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@smakosh
smakosh added this pull request to the merge queue Mar 22, 2026
Merged via the queue into main with commit 23d72af Mar 22, 2026
8 checks passed
@smakosh
smakosh deleted the feat/redesign-admin-ui branch March 22, 2026 13:46
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.

2 participants