Skip to content

feat: Add API errors admin page with real-time polling and Sentry integration - #813

Merged
otomatty merged 3 commits into
developfrom
claude/fix-issue-804-e1ZKX
May 4, 2026
Merged

feat: Add API errors admin page with real-time polling and Sentry integration#813
otomatty merged 3 commits into
developfrom
claude/fix-issue-804-e1ZKX

Conversation

@otomatty

@otomatty otomatty commented May 4, 2026

Copy link
Copy Markdown
Owner

概要

管理画面に API エラー一覧ページを追加し、Sentry から取得したエラーを可視化・管理できるようにしました。エラーの詳細表示、AI 解析結果の確認、ワークフロー状態(open/investigating/resolved/ignored)の更新が可能です。また、フロントエンド全体に Sentry エラーバウンダリーを導入し、未捕捉例外の自動報告を実装しました。

変更点

  • 管理画面エラー一覧ページ (admin/src/pages/errors/)

    • ErrorsContent.tsx: ステータス・重大度フィルター、テーブル表示、バッジ色分け
    • ErrorDetailDialog.tsx: AI 解析結果(要約・原因・修正方針・関連ファイル)の詳細表示とステータス更新
    • useApiErrors.ts: GET /api/admin/errors の定期ポーリング(30秒間隔、タブ非表示時スキップ)
    • useApiErrorActiveCount.ts: サイドバーバッジ用の軽量件数取得(active ステータスのみ)
    • index.tsx: コンテナコンポーネント(状態管理・API 呼び出し)
  • API クライアント (admin/src/api/admin.ts)

    • getApiErrors(): フィルター・ページネーション対応の一覧取得
    • getApiErrorById(): 単一エラー詳細取得
    • patchApiErrorStatus(): ワークフロー状態更新
    • 型定義: ApiErrorStatus, ApiErrorSeverity, ApiErrorRow, ApiErrorSuspectedFile
  • Sentry 統合

    • src/lib/sentry.ts / admin/src/lib/sentry.ts: SDK 初期化(DSN 未設定時は no-op)
    • ErrorBoundary コンポーネント(src/ / admin/src/): 未捕捉例外をキャッチして Sentry に報告
    • main.tsx 両方: ErrorBoundary でアプリをラップ
  • UI・ナビゲーション

    • admin/src/pages/Layout.tsx: サイドバーに「API エラー」メニュー追加、未対応件数バッジ表示
    • admin/src/App.tsx: /errors ルート追加
  • 多言語対応

    • admin/src/i18n/locales/{ja,en}/errors.json: エラー一覧・詳細画面の全文言
    • admin/src/i18n/locales/{ja,en}/nav.json: ナビゲーション文言追加
  • テスト・E2E

    • admin/src/pages/errors/ErrorsContent.test.tsx: UI レンダリング・フィルター動作
    • admin/src/components/ErrorBoundary.test.tsx: 例外キャッチ・Sentry 報告
    • admin/src/api/admin.test.ts: API クライアント関数
    • admin/e2e/errors-page.spec.ts: ページ全体の最小 E2E(モック API)
    • admin/playwright.config.ts: 管理画面専用 Playwright 設定
  • 環境変数・パッケージ

    • .env.example / admin/.env.example: `

https://claude.ai/code/session_01XDYFEoEyfjbSQK5KXXA7yK

Summary by CodeRabbit

  • New Features

    • Admin errors dashboard: list, filters (status/severity), detail modal, and status updates
    • Sidebar unread badge with unresolved error count
    • App-wide error boundaries with user-facing fallback UI
  • Monitoring

    • Sentry support wired into Web and Admin (configurable via env placeholders)
  • Tests

    • New E2E and unit tests for errors pages and error-boundary behavior
  • Documentation

    • Example env templates updated with Sentry DSN placeholders and notes

…/errors UI (#804)

Wires up `@sentry/react` for the frontend (`src/`) and admin (`admin/`) SPAs
with `Error Boundary` to forward unhandled exceptions, both gated on the
`VITE_SENTRY_DSN_WEB` / `VITE_ADMIN_SENTRY_DSN` env vars (no-op when blank).

Adds an admin `/errors` page (list + detail + status update) backed by the
existing `/api/admin/errors` endpoints, plus a sidebar badge that polls for
the count of active (`open` + `investigating`) errors. Phase 1 uses simple
polling at a 30s interval; realtime sync is deferred to a later phase.
@coderabbitai

coderabbitai Bot commented May 4, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e67e11ff-fcee-437b-aa2e-552a8a28b987

📥 Commits

Reviewing files that changed from the base of the PR and between d494581 and 0d96cf2.

📒 Files selected for processing (13)
  • admin/src/api/admin.ts
  • admin/src/components/ErrorBoundary.test.tsx
  • admin/src/components/ErrorBoundary.tsx
  • admin/src/i18n/locales/en/errors.json
  • admin/src/i18n/locales/en/nav.json
  • admin/src/i18n/locales/ja/errors.json
  • admin/src/i18n/locales/ja/nav.json
  • admin/src/lib/sentry.ts
  • admin/src/pages/errors/ErrorDetailDialog.tsx
  • admin/src/pages/errors/ErrorsContent.tsx
  • admin/src/pages/errors/useApiErrorActiveCount.ts
  • src/components/ErrorBoundary.tsx
  • src/lib/sentry.ts
✅ Files skipped from review due to trivial changes (4)
  • admin/src/i18n/locales/en/nav.json
  • admin/src/i18n/locales/ja/nav.json
  • admin/src/i18n/locales/en/errors.json
  • admin/src/pages/errors/ErrorDetailDialog.tsx
🚧 Files skipped from review as they are similar to previous changes (6)
  • admin/src/lib/sentry.ts
  • admin/src/components/ErrorBoundary.test.tsx
  • admin/src/pages/errors/ErrorsContent.tsx
  • src/components/ErrorBoundary.tsx
  • admin/src/i18n/locales/ja/errors.json
  • admin/src/components/ErrorBoundary.tsx

📝 Walkthrough

Walkthrough

Adds Sentry initialization and ErrorBoundary to web and admin frontends; implements an admin "API errors" feature including client APIs, polling hooks, list/detail UI with status updates, i18n, tests, Playwright E2E, layout wiring, and related config and dependency updates.

Changes

Error Tracking & Admin API Errors Feature

Layer / File(s) Summary
Configuration
.env.example, admin/.env.example
Documented per-surface Sentry DSN placeholders (VITE_SENTRY_DSN_WEB, VITE_ADMIN_SENTRY_DSN, SENTRY_DSN_API) and local no-op behavior.
Dependencies & Tooling
package.json, admin/package.json, admin/playwright.config.ts
Added @sentry/react to root and admin deps; added test:e2e script and admin Playwright config for E2E on port 30001.
Sentry Core & Reporting
src/lib/sentry.ts, admin/src/lib/sentry.ts
Added guarded initSentry() and captureException(error, context?) with exported CaptureExtras; re-exported Sentry.
Error Boundary Component
src/components/ErrorBoundary.tsx, admin/src/components/ErrorBoundary.tsx
Added class ErrorBoundary (getDerivedStateFromError, componentDidCatch, reset, optional fallback render-prop) that forwards exceptions to captureException.
App Integration
src/main.tsx, admin/src/main.tsx
Call initSentry() at startup and wrap app tree with ErrorBoundary before mount.
API Types & Clients
admin/src/api/admin.ts
Added ApiErrorStatus/ApiErrorSeverity/ApiErrorRow types and client functions getApiErrors(), getApiErrorById(), patchApiErrorStatus() with query/payload handling and error propagation.
Polling & Count Hooks
admin/src/pages/errors/useApiErrors.ts, admin/src/pages/errors/useApiErrorActiveCount.ts
Added useApiErrors (polling, visibility-aware, race-safe, refetch) and useApiErrorActiveCount (aggregates active error totals with polling and visibility handling).
Presentation Components
admin/src/pages/errors/ErrorsContent.tsx, admin/src/pages/errors/ErrorDetailDialog.tsx
Added ErrorsContent (filters, loading/empty/table, badges, actions) and ErrorDetailDialog (detail view, AI sections, suspected files, status select, save flow).
Container & Routing
admin/src/pages/errors/index.tsx, admin/src/App.tsx, admin/src/pages/Layout.tsx
Added Errors container component wiring hooks and mutations; wired /errors route; refactored Layout to typed NavItem with optional useBadgeCount and capped badge display.
Localization
admin/src/i18n/index.ts, admin/src/i18n/locales/en/errors.json, admin/src/i18n/locales/ja/errors.json, admin/src/i18n/locales/en/nav.json, admin/src/i18n/locales/ja/nav.json
Registered errors translation domain and added English/Japanese locale files; added unreadBadgeAriaLabel and errors nav label.
Tests & E2E
admin/src/api/admin.test.ts, admin/src/components/ErrorBoundary.test.tsx, admin/src/pages/errors/ErrorsContent.test.tsx, admin/e2e/errors-page.spec.ts
Unit tests for API client behavior, ErrorBoundary reporting/reset, ErrorsContent UI states; Playwright E2E spec that mocks auth and errors API and asserts heading and mocked row rendering.

Sequence Diagram(s)

sequenceDiagram
  participant Admin as Admin SPA
  participant API as Backend API
  participant Sentry as Sentry SDK

  Admin->>Admin: initSentry() (reads VITE_ADMIN_SENTRY_DSN)
  alt DSN set
    Admin->>Sentry: Sentry.init(...)
  end
  Admin->>API: GET /api/admin/errors (useApiErrors)
  API-->>Admin: { errors, total }
  Admin->>Admin: render ErrorsContent (badges, table)
  Admin->>API: PATCH /api/admin/errors/{id} (patchApiErrorStatus)
  API-->>Admin: { error: updatedRow }
  alt Uncaught render error
    Admin->>Sentry: captureException(error, { extra: { componentStack } })
    Admin-->>Admin: ErrorBoundary shows fallback UI
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

  • otomatty/zedi#811: Server-side api_errors table and handlers that correspond to the client APIs added here.
  • otomatty/zedi#812: Server admin error endpoints and Sentry webhook logic that the admin UI consumes.
  • otomatty/zedi#810: Related Sentry initialization and capture utilities across surfaces.

Poem

🐰 I peered at stacks and gave a hop,
DSNs aligned and errors stop,
Badges blink and lists unfurl,
Dialogs help the team unfurl—
A rabbit cheers for clearer ops!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature being added: an API errors admin page with polling and Sentry integration, matching the comprehensive changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 claude/fix-issue-804-e1ZKX

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request implements Sentry integration across the application and introduces a new API error management dashboard in the admin SPA. Key changes include the addition of a global ErrorBoundary component, Sentry initialization logic, and a dedicated Errors page that allows administrators to view detailed error reports and update their workflow status. The admin sidebar has also been updated with a dynamic badge to track active errors. Feedback was provided regarding a potential race condition in the useApiErrorActiveCount hook, where overlapping asynchronous requests might lead to inconsistent state updates if not properly tracked.

Comment on lines +19 to +37
const isMountedRef = useRef(true);

useEffect(() => {
isMountedRef.current = true;
let cancelled = false;

const fetchCount = async () => {
try {
const results = await Promise.all(
ACTIVE_API_ERROR_STATUSES.map((status) => getApiErrors({ status, limit: 1 })),
);
if (cancelled || !isMountedRef.current) return;
const total = results.reduce((sum, r) => sum + r.total, 0);
setCount(total);
} catch {
// バッジ取得失敗時は表示を更新しない(古い値を維持して誤った 0 表示を避ける)。
// Swallow errors to keep stale-but-correct count rather than flashing 0.
}
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

fetchCount 関数において、複数の非同期リクエストが並行して走った際のレースコンディションへの考慮が不足しています。例えば、ポーリングによる実行と visibilitychange による実行が重なった場合、古いリクエストの結果が新しい結果を上書きしてしまう可能性があります。useApiErrors.ts で実装されているように、useRef を用いて最新のリクエスト ID を追跡し、古いリクエストの結果を破棄する仕組みを導入することを推奨します。

  const isMountedRef = useRef(true);
  const latestRequestRef = useRef(0);

  useEffect(() => {
    isMountedRef.current = true;
    let cancelled = false;

    const fetchCount = async () => {
      const requestId = ++latestRequestRef.current;
      try {
        const results = await Promise.all(
          ACTIVE_API_ERROR_STATUSES.map((status) => getApiErrors({ status, limit: 1 })),
        );
        if (cancelled || !isMountedRef.current || requestId !== latestRequestRef.current) return;
        const total = results.reduce((sum, r) => sum + r.total, 0);
        setCount(total);
      } catch {
        // バッジ取得失敗時は表示を更新しない(古い値を維持して誤った 0 表示を避ける)。
        // Swallow errors to keep stale-but-correct count rather than flashing 0.
      }
    };

Polling ticks and visibilitychange callbacks can race. Track the latest
request id (mirroring `useApiErrors`) and discard stale responses so a
slow earlier fetch can't overwrite a fresher count.

Addresses gemini-code-assist review on PR #813.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
admin/src/pages/errors/useApiErrorActiveCount.ts (1)

25-32: ⚡ Quick win

Prevent older polls from overwriting newer counts.

fetchCount() can run concurrently from the interval and the visibilitychange refresh. A slower older request can resolve last and replace a fresher count.

Suggested sequencing guard
 export function useApiErrorActiveCount(): number {
   const [count, setCount] = useState(0);
   const isMountedRef = useRef(true);
+  const requestIdRef = useRef(0);

   useEffect(() => {
     isMountedRef.current = true;
     let cancelled = false;

     const fetchCount = async () => {
+      const requestId = ++requestIdRef.current;
       try {
         const results = await Promise.all(
           ACTIVE_API_ERROR_STATUSES.map((status) => getApiErrors({ status, limit: 1 })),
         );
-        if (cancelled || !isMountedRef.current) return;
+        if (cancelled || !isMountedRef.current || requestId !== requestIdRef.current) return;
         const total = results.reduce((sum, r) => sum + r.total, 0);
         setCount(total);
       } catch {

Also applies to: 39-48

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@admin/src/pages/errors/useApiErrorActiveCount.ts` around lines 25 - 32,
fetchCount can complete out-of-order and overwrite newer counts; add a
sequencing guard: maintain a fetch sequence counter ref (e.g., lastFetchIdRef)
and increment it at the start of fetchCount, capture the current id in a local
variable, and after awaiting the API calls check that the captured id ===
lastFetchIdRef.current (and that cancelled/isMountedRef checks still pass)
before computing total and calling setCount; apply the same pattern to the other
refresh path (the visibilitychange refresh) so only the latest fetch result
updates state.
src/components/ErrorBoundary.tsx (2)

1-35: LGTM!

Implementation is correct and mirrors the admin version. Both components are well-typed with comprehensive bilingual documentation.

Optional future consideration: These two ErrorBoundary implementations are nearly identical. Consider extracting to a shared UI package to reduce duplication.

Also applies to: 52-75

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ErrorBoundary.tsx` around lines 1 - 35, The ErrorBoundary
class is duplicated across admin and this component; refactor by extracting the
ErrorBoundary (the exported class ErrorBoundary with its props and state
interfaces and methods like static getDerivedStateFromError and any lifecycle
error handling) into a shared UI package/module and replace both local
implementations with imports from that shared module, keeping the same public
API (ErrorBoundaryProps, ErrorBoundaryState, fallback prop signature) so callers
need no changes.

38-50: ⚡ Quick win

Same recommendation: forward componentStack to Sentry.

As noted in the admin counterpart, passing info.componentStack to Sentry would improve error debugging.

♻️ Proposed enhancement
   componentDidCatch(error: Error, info: ErrorInfo): void {
     try {
-      captureException(error);
+      captureException(error, { extra: { componentStack: info.componentStack } });
     } catch {
       // 失敗時もフォールバック描画は継続する。
       // Continue rendering the fallback even if reporting fails.
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ErrorBoundary.tsx` around lines 38 - 50, The
ErrorBoundary.componentDidCatch currently calls captureException(error) without
passing the component stack; update componentDidCatch to forward
info.componentStack to the Sentry helper (captureException) so the component
stack is recorded—modify the call in componentDidCatch (and the captureException
helper signature if needed) to accept and forward the componentStack
(info.componentStack) to Sentry/SDK as event context or as the second argument.
admin/src/components/ErrorBoundary.tsx (1)

38-50: ⚡ Quick win

Consider forwarding componentStack to Sentry for richer debugging context.

The info.componentStack is available but not passed to captureException. Including it would help diagnose which component tree path led to the error.

♻️ Proposed enhancement to include component stack
   componentDidCatch(error: Error, info: ErrorInfo): void {
     try {
-      captureException(error);
+      captureException(error, { extra: { componentStack: info.componentStack } });
     } catch {
       // 失敗時もフォールバック描画は継続する。
       // Continue rendering the fallback even if reporting fails.
     }

Note: This requires updating captureException in @/lib/sentry to accept and forward options to the Sentry SDK.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@admin/src/components/ErrorBoundary.tsx` around lines 38 - 50, Forward the
component stack from ErrorBoundary to Sentry by updating componentDidCatch to
pass info.componentStack into captureException (in
ErrorBoundary.componentDidCatch) and then update the captureException helper in
"@/lib/sentry" to accept an options/metadata parameter and forward that to the
Sentry SDK (e.g., as extra or contexts) so the componentStack is sent; ensure
the try/catch behavior remains and include the componentStack only when present
to avoid breaking uninitialized/no-op behavior.
admin/src/pages/errors/ErrorDetailDialog.tsx (1)

21-21: 💤 Low value

Consider extracting STATUS_VALUES to a shared location.

This array is duplicated in both ErrorsContent.tsx and ErrorDetailDialog.tsx. Extracting to a shared constants file (e.g., @/api/admin.ts alongside the types) would ensure consistency.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@admin/src/pages/errors/ErrorDetailDialog.tsx` at line 21, STATUS_VALUES is
duplicated between ErrorDetailDialog.tsx and ErrorsContent.tsx; extract this
constant into a shared location (e.g., alongside ApiErrorStatus in
`@/api/admin.ts`) and import it from both components. Update ErrorDetailDialog.tsx
and ErrorsContent.tsx to remove the local const and import STATUS_VALUES from
the shared module, keeping the type ApiErrorStatus for the array to preserve
type safety.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@admin/src/i18n/locales/en/errors.json`:
- Line 37: The "occurrencesShort" translation always returns "{{count}}
occurrences" which yields "1 occurrences"; update the value to handle
pluralization for the singular case (e.g. use ICU plural syntax or the project's
i18n plural keys). Replace the value of the occurrencesShort key with a
plural-aware string such as "{{count, plural, one {# occurrence} other {#
occurrences}}}" or, if your system uses separate plural keys, add a singular key
(occurrencesShort_one: "{{count}} occurrence") and a plural key
(occurrencesShort_other: "{{count}} occurrences") and ensure the lookup uses
those keys.

In `@admin/src/i18n/locales/en/nav.json`:
- Line 5: Update the unreadBadgeAriaLabel value to be self-describing by
including what is unresolved (e.g. change the value of the
"unreadBadgeAriaLabel" key from "{{count}} unresolved" to something like
"{{count}} unresolved API errors" or another specific descriptor used in the UI)
so screen readers announce the item type along with the count.

---

Nitpick comments:
In `@admin/src/components/ErrorBoundary.tsx`:
- Around line 38-50: Forward the component stack from ErrorBoundary to Sentry by
updating componentDidCatch to pass info.componentStack into captureException (in
ErrorBoundary.componentDidCatch) and then update the captureException helper in
"@/lib/sentry" to accept an options/metadata parameter and forward that to the
Sentry SDK (e.g., as extra or contexts) so the componentStack is sent; ensure
the try/catch behavior remains and include the componentStack only when present
to avoid breaking uninitialized/no-op behavior.

In `@admin/src/pages/errors/ErrorDetailDialog.tsx`:
- Line 21: STATUS_VALUES is duplicated between ErrorDetailDialog.tsx and
ErrorsContent.tsx; extract this constant into a shared location (e.g., alongside
ApiErrorStatus in `@/api/admin.ts`) and import it from both components. Update
ErrorDetailDialog.tsx and ErrorsContent.tsx to remove the local const and import
STATUS_VALUES from the shared module, keeping the type ApiErrorStatus for the
array to preserve type safety.

In `@admin/src/pages/errors/useApiErrorActiveCount.ts`:
- Around line 25-32: fetchCount can complete out-of-order and overwrite newer
counts; add a sequencing guard: maintain a fetch sequence counter ref (e.g.,
lastFetchIdRef) and increment it at the start of fetchCount, capture the current
id in a local variable, and after awaiting the API calls check that the captured
id === lastFetchIdRef.current (and that cancelled/isMountedRef checks still
pass) before computing total and calling setCount; apply the same pattern to the
other refresh path (the visibilitychange refresh) so only the latest fetch
result updates state.

In `@src/components/ErrorBoundary.tsx`:
- Around line 1-35: The ErrorBoundary class is duplicated across admin and this
component; refactor by extracting the ErrorBoundary (the exported class
ErrorBoundary with its props and state interfaces and methods like static
getDerivedStateFromError and any lifecycle error handling) into a shared UI
package/module and replace both local implementations with imports from that
shared module, keeping the same public API (ErrorBoundaryProps,
ErrorBoundaryState, fallback prop signature) so callers need no changes.
- Around line 38-50: The ErrorBoundary.componentDidCatch currently calls
captureException(error) without passing the component stack; update
componentDidCatch to forward info.componentStack to the Sentry helper
(captureException) so the component stack is recorded—modify the call in
componentDidCatch (and the captureException helper signature if needed) to
accept and forward the componentStack (info.componentStack) to Sentry/SDK as
event context or as the second argument.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8e949e21-a6f5-435b-a1f2-14716483e224

📥 Commits

Reviewing files that changed from the base of the PR and between e351898 and 22ed976.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (28)
  • .env.example
  • admin/.env.example
  • admin/e2e/errors-page.spec.ts
  • admin/package.json
  • admin/playwright.config.ts
  • admin/src/App.tsx
  • admin/src/api/admin.test.ts
  • admin/src/api/admin.ts
  • admin/src/components/ErrorBoundary.test.tsx
  • admin/src/components/ErrorBoundary.tsx
  • admin/src/i18n/index.ts
  • admin/src/i18n/locales/en/errors.json
  • admin/src/i18n/locales/en/nav.json
  • admin/src/i18n/locales/ja/errors.json
  • admin/src/i18n/locales/ja/nav.json
  • admin/src/lib/sentry.ts
  • admin/src/main.tsx
  • admin/src/pages/Layout.tsx
  • admin/src/pages/errors/ErrorDetailDialog.tsx
  • admin/src/pages/errors/ErrorsContent.test.tsx
  • admin/src/pages/errors/ErrorsContent.tsx
  • admin/src/pages/errors/index.tsx
  • admin/src/pages/errors/useApiErrorActiveCount.ts
  • admin/src/pages/errors/useApiErrors.ts
  • package.json
  • src/components/ErrorBoundary.tsx
  • src/lib/sentry.ts
  • src/main.tsx

Comment thread admin/src/i18n/locales/en/errors.json Outdated
Comment thread admin/src/i18n/locales/en/nav.json Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@admin/src/pages/errors/useApiErrorActiveCount.ts`:
- Around line 15-16: The JSDoc for the hook useApiErrorActiveCount is incorrect
about failure behavior; instead of always falling back to 0 on fetch/auth errors
the implementation preserves the previous successful count (see the logic around
the block that retains previous count). Update the comment to state that the
hook returns the last known successful count on fetch/auth errors (and falls
back to 0 only if there was never a successful value), or alternatively change
the implementation to match the current doc—whichever contract you want to keep;
reference the hook name useApiErrorActiveCount and the code path that retains
previous count when editing.
- Around line 47-51: The initial unconditional call to fetchCount causes a fetch
even when the tab is hidden; modify the bootstrap logic in
useApiErrorActiveCount so that you only call fetchCount() immediately if
document is defined and document.hidden is false (i.e., guard the initial void
fetchCount() with the same "typeof document !== 'undefined' && !document.hidden"
check used inside the setInterval), leaving the interval and
API_ERRORS_POLL_INTERVAL_MS behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 05961ace-b8ab-4648-b90a-f7cdf06a6630

📥 Commits

Reviewing files that changed from the base of the PR and between 22ed976 and d494581.

📒 Files selected for processing (1)
  • admin/src/pages/errors/useApiErrorActiveCount.ts

Comment thread admin/src/pages/errors/useApiErrorActiveCount.ts Outdated
Comment thread admin/src/pages/errors/useApiErrorActiveCount.ts Outdated
- i18n: add `_one` / `_other` plural keys for `errors.detail.occurrencesShort`
  (was rendering "1 occurrences"). Pass `count` as a number so i18next plural
  resolution actually fires.
- i18n: make `nav.unreadBadgeAriaLabel` self-describing for screen readers
  ("{{count}} unresolved API errors").
- sentry: extend `captureException` with an optional `{ extra }` context and
  forward `componentStack` from both `ErrorBoundary` components so Sentry events
  capture the failing subtree.
- admin/src/api/admin.ts: expose `API_ERROR_STATUS_VALUES` and
  `API_ERROR_SEVERITY_VALUES` as the single source of truth; drop the local
  copies in `ErrorsContent` and `ErrorDetailDialog`.
- useApiErrorActiveCount: fix JSDoc to match actual behavior (preserves last
  successful count on errors), and guard the bootstrap fetch with the same
  visibility check as the polling tick so a hidden tab doesn't pay for the
  initial fan-out.

Skipped: extracting `ErrorBoundary` into a shared package — out of scope here.
@otomatty otomatty self-assigned this May 4, 2026
@otomatty
otomatty merged commit 5bb767e into develop May 4, 2026
17 checks passed
@otomatty
otomatty deleted the claude/fix-issue-804-e1ZKX branch May 4, 2026 21:24
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