feat: redesign code app, admin dashboard, and UI - #1867
Conversation
- 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>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (4)
📒 Files selected for processing (1)
WalkthroughAdds 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
Sequence Diagram(s)mermaid Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 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 docstrings
🧪 Generate unit tests (beta)
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 |
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
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 | 🟠 MajorGuard 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 setloadingtofalse. 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
ArrowRighticon directly with the text without proper spacing elements. Compare withInactivePlanChooser.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
copySnippetfunction 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
copyfunction (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
plansarray is duplicated between this file andDashboardClient.tsx(lines 42-65). While the structures differ slightly (this one includesfeaturesarray), the core tier data (name,price,usage,tier,popular) is identical.This could be extracted to a shared constant (e.g., in
types.tsor a newconstants.ts) to ensure pricing and usage values stay in sync. The landing page could extend the base data with thefeaturesarray.🤖 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 Logcast on line 200 assumes the API response structure matches the databaseLogtype 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 aUiLogtype 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: Theas anycasts indicate a type gap between API and db types.The
toUiLogfunction effectively normalizes API responses for UI consumption. Theas anycasts fortoolChoiceandcustomHeaders(lines 56-57) work around type mismatches between the OpenAPI schema and the db-derivedLogtype.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: Avoidas anytype assertion.The
as anycast bypasses type safety. If Next.js typed routes are enabled (typedRoutesinnext.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
anyoras anyin 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()ordb().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
⛔ Files ignored due to path filters (3)
apps/code/src/lib/api/v1.d.tsis excluded by!**/v1.d.tsapps/ui/src/lib/api/v1.d.tsis excluded by!**/v1.d.tsee/admin/src/lib/api/v1.d.tsis excluded by!**/v1.d.ts
📒 Files selected for processing (36)
apps/api/src/lib/arena-benchmarks.tsapps/api/src/routes/admin.tsapps/api/src/routes/internal-models.tsapps/code/src/app/dashboard/DashboardClient.tsxapps/code/src/app/dashboard/components/ActivePlanChangeTier.tsxapps/code/src/app/dashboard/components/DashboardIntegrations.tsxapps/code/src/app/dashboard/components/DevPlanSettings.tsxapps/code/src/app/dashboard/components/InactivePlanChooser.tsxapps/code/src/app/dashboard/types.tsapps/code/src/app/page.tsxapps/docs/content/guides/autohand.mdxapps/docs/content/guides/codex-cli.mdxapps/docs/lib/custom-icons.tsxapps/ui/src/app/dashboard/[orgId]/[projectId]/activity/[logId]/log-detail-client.tsxapps/ui/src/app/dashboard/[orgId]/[projectId]/activity/[logId]/page.tsxapps/ui/src/app/models/[name]/page.tsxapps/ui/src/components/activity/recent-logs.tsxapps/ui/src/components/dashboard/log-card.tsxapps/ui/src/components/integrations/integration-cards.tsxapps/ui/src/components/landing/hero-rsc.tsxapps/ui/src/components/landing/hero.tsxapps/ui/src/components/landing/navbar.tsxapps/ui/src/components/models/all-models.tsxapps/ui/src/components/models/model-benchmarks.tsxapps/ui/src/content/guides/autohand.mdapps/ui/src/content/guides/codex-cli.mdapps/ui/src/types/activity.tsee/admin/src/app/model-provider-mappings/page.tsxee/admin/src/app/models/[modelId]/page.tsxee/admin/src/components/history-chart.tsxee/admin/src/components/model-detail-client.tsxee/admin/src/components/model-provider-charts.tsxee/admin/src/components/models-table.tsxee/admin/src/lib/admin-history.tsee/admin/src/lib/types.tspackages/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
There was a problem hiding this comment.
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
📒 Files selected for processing (4)
apps/ui/src/app/dashboard/[orgId]/[projectId]/activity/[logId]/log-detail-client.tsxapps/ui/src/components/activity/recent-logs.tsxapps/ui/src/components/integrations/integration-cards.tsxapps/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
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
Test plan
pnpm buildto confirm production builds pass🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
UI Improvements
Admin Enhancements