Skip to content

feat(gui): Usage workspace view#442

Merged
Wibias merged 3 commits into
lidge-jun:devfrom
Wibias:codex/gui-usage-workspace
Jul 25, 2026
Merged

feat(gui): Usage workspace view#442
Wibias merged 3 commits into
lidge-jun:devfrom
Wibias:codex/gui-usage-workspace

Conversation

@Wibias

@Wibias Wibias commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Add a Usage workspace layout (section rail + main pane) matching Models/Subagents
  • Wire it to the global sidebar Classic/Workspace preference (no per-page toggle)
  • Stack via @container usage-workspace when the shell is narrow; keep mobile media query
  • Add usage.section.overview i18n (en/de/ja/ko/zh/ru) and focused GUI contract tests

Test plan

  • Open Usage in Classic — stacked panels unchanged
  • Switch sidebar to Workspace — rail sections + main pane
  • Navigate Overview / Models / Providers / Coverage
  • Models search still filters in workspace mode
  • Range/surface filters still reload data in both modes
  • Narrow window stacks rail above main (~720px container)
  • bun test ./gui/tests/usage-workspace.test.ts
  • bun run typecheck

Summary by CodeRabbit

  • New Features
    • Added a “workspace” layout for the Usage page with a left-rail section switcher (Overview, Models, Providers, Coverage) and responsive single-column behavior.
    • Usage now honors the current view mode, and workspace mode hides the Codex auth entry from the sidebar navigation.
    • Added the localized “Overview” label to the Usage UI across supported languages.
  • Bug Fixes
    • Improved Logs auto-refresh so silent polling no longer causes loading flicker or unnecessary state changes.

Add a section rail (Overview/Models/Providers/Coverage) driven by the sidebar Classic/Workspace preference, with container-query stacking and no per-page toggle.
@coderabbitai

This comment was marked as resolved.

@github-actions github-actions Bot added the enhancement New feature or request label Jul 25, 2026
Keep polling every 2s, but silent background fetches no longer toggle loading or insert a status row that shifts the table.
coderabbitai[bot]

This comment was marked as resolved.

Keep silent log polls from clearing errors or flashing empty/loading UI, restore Usage workspace headings and distinct landmark labels, mount the workspace shell while loading, and hide Codex Auth from the sidebar in workspace mode (Providers deep links stay).

@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: 1

🤖 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 `@gui/src/pages/Logs.tsx`:
- Around line 280-297: Update fetchLogs to maintain an AbortController for the
active request, aborting the previous request before starting each new call and
aborting it during the owning effect cleanup. Pass the signal to fetch, ignore
AbortError in the catch path, and ensure aborted or stale requests cannot update
logs, errors, or loading state.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: 4d1f2520-db3e-4a50-bf7b-3ea17729d276

📥 Commits

Reviewing files that changed from the base of the PR and between 545d9cd and df59b24.

📒 Files selected for processing (13)
  • gui/src/App.tsx
  • gui/src/i18n/de.ts
  • gui/src/i18n/en.ts
  • gui/src/i18n/ja.ts
  • gui/src/i18n/ko.ts
  • gui/src/i18n/ru.ts
  • gui/src/i18n/zh.ts
  • gui/src/pages/Logs.tsx
  • gui/src/pages/Usage.tsx
  • gui/src/styles-usage-workspace.css
  • gui/tests/logs-auto-refresh.test.tsx
  • gui/tests/usage-workspace.test.ts
  • gui/tests/workspace-sidebar-codex-auth.test.ts

Comment thread gui/src/pages/Logs.tsx
Comment on lines +280 to 297
const fetchLogs = useCallback(async (opts?: { silent?: boolean }) => {
const silent = opts?.silent === true;
// Silent polls must not clear an existing error or toggle loading — otherwise
// failures flicker between the error banner, empty state, and stale table.
if (!silent) setLoading(true);
try {
const res = await fetch(`${apiBase}/api/logs`);
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`.trim());
setLogs(await res.json());
setError(null);
} catch (cause) {
if (silent) return;
const detail = cause instanceof Error ? cause.message : "";
setError(detail ? `${t("logs.loadError")} ${detail}` : t("logs.loadError"));
} finally {
setLoading(false);
if (!silent) setLoading(false);
}
}, [apiBase, t]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

No cancellation/sequencing for polling fetch — stale response can overwrite fresher state.

fetchLogs fires a bare fetch(${apiBase}/api/logs) on every call (initial, retry, and every 2s silent poll) with no AbortController and no "latest request wins" guard. If two overlapping requests resolve out of order (e.g., a slow non-silent retry started at t=0 finishes after a silent poll fired at t=2000 already updated logs), the older response's setLogs/setError call will win and clobber the newer state. There's also no timeout, so a hung request leaves loading (and the disabled Retry button) stuck indefinitely, and repeated intervals can pile up in-flight requests against a slow backend.

Add an AbortController per call, abort the previous one before starting a new one (and on cleanup), and ignore AbortError in the catch:

🔧 Suggested fix
+  const fetchAbortRef = useRef<AbortController | null>(null);
   const fetchLogs = useCallback(async (opts?: { silent?: boolean }) => {
     const silent = opts?.silent === true;
+    fetchAbortRef.current?.abort();
+    const controller = new AbortController();
+    fetchAbortRef.current = controller;
     if (!silent) setLoading(true);
     try {
-      const res = await fetch(`${apiBase}/api/logs`);
+      const res = await fetch(`${apiBase}/api/logs`, { signal: controller.signal });
       if (!res.ok) throw new Error(`${res.status} ${res.statusText}`.trim());
       setLogs(await res.json());
       setError(null);
     } catch (cause) {
+      if (cause instanceof DOMException && cause.name === "AbortError") return;
       if (silent) return;
       const detail = cause instanceof Error ? cause.message : "";
       setError(detail ? `${t("logs.loadError")} ${detail}` : t("logs.loadError"));
     } finally {
       if (!silent) setLoading(false);
     }
   }, [apiBase, t]);

Also applies to: 299-305

🤖 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 `@gui/src/pages/Logs.tsx` around lines 280 - 297, Update fetchLogs to maintain
an AbortController for the active request, aborting the previous request before
starting each new call and aborting it during the owning effect cleanup. Pass
the signal to fetch, ignore AbortError in the catch path, and ensure aborted or
stale requests cannot update logs, errors, or loading state.

@Wibias
Wibias merged commit a904d8d into lidge-jun:dev Jul 25, 2026
11 checks passed
lidge-jun added a commit that referenced this pull request Jul 25, 2026
이 유닛의 최종 목표. 완료 기준 달성:
rg -n 'viewMode|ViewMode|classicToggle|workspaceToggle' gui/src -> 0건

- gui/src/view-mode.ts 삭제 (109줄): ViewMode 타입, 레거시 키 12개
  마이그레이션, providersHash 변환 헬퍼 전부
- App.tsx: 사이드바 토글 버튼과 7개 페이지의 viewMode prop 주입 제거
- 페이지 7개(Dashboard/Providers/Models/Subagents/Usage/ApiKeys/ClaudeCode)의
  Classic 분기 제거, Workspace를 유일 경로로 승격
  (Subagents는 반대 — WP1에서 Classic이 승격됐으므로 prop만 제거)
- 라우팅 3파일 정리: app-routing의 viewMode 결합, hash-routing의
  resolveProvidersHashChange, use-app-route-state의 상태/토글 전부
- i18n 6로케일 x 3키 = 18키 회수 (WP1의 60키와 합쳐 이 유닛 총 78키)
- 레거시 localStorage 키 12개 1회 삭제 (다음 릴리스에서 정리 함수도 제거)
- #providers/workspace 북마크는 passive replace로 #providers 리다이렉트

050 문서가 예측 못 한 것: 문서 작성 이후 머지된 PR #442/#444/#446이
Usage/ApiKeys/ClaudeCode에도 같은 분기를 추가했다. 범위가 4페이지에서
7페이지로 늘었다.

Classic 분기가 사라지며 드러난 죽은 코드 28건도 함께 제거했다 —
OAuthPanel/ProviderCardList import, 수동 코드 입력 흐름, 계정 모드
전환 함수 등 Classic 패널에서만 쓰이던 것들이다.

테스트: view-mode.test.ts / view-mode-remount.test.tsx 폐기.
providers-hash-history.test.tsx는 21케이스 중 토글 개념을 뺀
단일 해시 계약으로 재작성.

브라우저 검증: 사이드바 토글 부재, #providers/workspace -> #providers
리다이렉트, 낡은 localStorage 키 4종 자동 정리 확인.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant