fix(W4-A #18): keep main nav visible when entering /admin/*#186
Merged
Conversation
`/admin/*` previously mounted under its own `AdminLayout` which rendered a
full 224px sidebar + 48px header in place of the AppShell. Entering Admin
therefore unmounted Dashboard / Projects / Scans / Approvals / Policies /
Integrations from the sidebar — users hit a dead-end where they couldn't
return to the rest of the portal without typing a URL.
Restructure the route table so `/admin/*` nests inside the AppShell route:
- `router.tsx`: move the entire admin Route group under the same `/`
AppShell parent. The AppShell sidebar already renders an "Administration"
section for super-admins (lines 188-199), so admin nav remains reachable
alongside the main nav at all times.
- `AdminLayout.tsx`: strip the now-redundant chrome (sidebar / header /
logout button / signed-in-as line). Reduced to the existence-hide guard
(returns `AdminNotFound` for non-super-admins) wrapping `<Outlet />`.
The `data-testid="admin-layout"` marker is preserved for harness compat.
- `AdminLayout.test.tsx`: drop assertions on the removed chrome
(`admin-sidebar`, `admin-nav-*`, `admin-logout`); retain the three guard
scenarios (super-admin / developer / no-user).
- `en/admin.json`, `ko/admin.json`: remove the unused `admin.layout.{title,
signed_in_as}` keys (no other call sites).
- `docs/plan-w4-ui-ia-overhaul.md`: new plan doc — single source of truth
for W4-A through W4-D.
- `docs/post-ga-execution-tracker.md`: mark W4-A "PR 대기".
Gates: typecheck clean · lint 0 errors · vitest 930 pass · i18n:check OK.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
haksungjang
added a commit
that referenced
this pull request
May 26, 2026
…/ license split (#187) Lands the three shared primitives that W4-B (#16 + #17 + #19) will consume. No callers wired yet — keeps this PR small and reviewable, and lets W4-B's diff stay focused on the per-tab UX changes. Primitives ---------- 1. `SortableColumnHeader` (`src/components/ui/sortable-column-header.tsx`) - 3-state click cycle: unset → asc → desc → unset. - Exposes `aria-sort` ("none"/"ascending"/"descending") and a `data-sort-order` attribute mirroring the same state for tests. - Replaces the existing "Sort by ▼ + Order ▼" toolbar pair. State stays in the caller (no internal `useState`), so URL params keep flowing through `useSearchParams` as today. - `nextSortState(column, current)` helper exported for reducer / URL normalization use. 2. Chart `onSegmentClick` prop (Severity + License distribution charts) - Optional `onSegmentClick?: (key) => void`. When provided, both the stacked-bar segment and the matching legend row become `<button>`s and forward the bucket key to the callback (Overview will use this for `?tab=vulnerabilities&severity=critical` style deep-links). - Backwards-compatible: when omitted, the segments + legend keep rendering as the original `<div>` / `<li>` elements with identical class names and test IDs. Buckets with `count === 0` stay non-interactive even when a callback is set. 3. `LicenseColumnCell` (`src/features/projects/components/`) - Single render primitive that surfaces both the SPDX identifier (`MIT`, `Apache-2.0`, …) and the policy category badge in a stacked layout — required so Allowed-MIT vs Allowed-Apache-2.0 are distinguishable in tables. W4-B will swap this into ComponentsTab and VulnerabilitiesTab. - Exposes `data-license-spdx` + `data-license-category` for filter plumbing and Playwright assertions. i18n ---- - `common.json` (EN/KO): new `sort.aria_{ascending,descending,unsorted}` keys for the SortableColumnHeader `aria-label`. - `project_detail.json` (EN/KO): new `components.license.unknown_dash` ("—") used by LicenseColumnCell when the SPDX field is null. Gates ----- - typecheck clean - lint 0 errors (+1 react-refresh warning on the new helper export, matching the project-wide pattern — 22 pre-existing instances) - vitest 951 pass (+21 new: 12 SortableColumnHeader, 3 LicenseColumnCell, 5 chart interaction, +1 absorbed; +12 + 3 + 5 + 1 = 21 incremental) - i18n:check OK Tracker ------- The `docs/post-ga-execution-tracker.md` W4 section was introduced in PR #186 (W4-A), which is still open. A tiny doc-only follow-up will mark "W4-B-prep ✅" once W4-A merges and the W4 lines land on main. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
haksungjang
added a commit
that referenced
this pull request
May 26, 2026
…bilities UX overhaul (#188) * feat(W4-B-prep): shared primitives for chart deep-link / column sort / license split Lands the three shared primitives that W4-B (#16 + #17 + #19) will consume. No callers wired yet — keeps this PR small and reviewable, and lets W4-B's diff stay focused on the per-tab UX changes. Primitives ---------- 1. `SortableColumnHeader` (`src/components/ui/sortable-column-header.tsx`) - 3-state click cycle: unset → asc → desc → unset. - Exposes `aria-sort` ("none"/"ascending"/"descending") and a `data-sort-order` attribute mirroring the same state for tests. - Replaces the existing "Sort by ▼ + Order ▼" toolbar pair. State stays in the caller (no internal `useState`), so URL params keep flowing through `useSearchParams` as today. - `nextSortState(column, current)` helper exported for reducer / URL normalization use. 2. Chart `onSegmentClick` prop (Severity + License distribution charts) - Optional `onSegmentClick?: (key) => void`. When provided, both the stacked-bar segment and the matching legend row become `<button>`s and forward the bucket key to the callback (Overview will use this for `?tab=vulnerabilities&severity=critical` style deep-links). - Backwards-compatible: when omitted, the segments + legend keep rendering as the original `<div>` / `<li>` elements with identical class names and test IDs. Buckets with `count === 0` stay non-interactive even when a callback is set. 3. `LicenseColumnCell` (`src/features/projects/components/`) - Single render primitive that surfaces both the SPDX identifier (`MIT`, `Apache-2.0`, …) and the policy category badge in a stacked layout — required so Allowed-MIT vs Allowed-Apache-2.0 are distinguishable in tables. W4-B will swap this into ComponentsTab and VulnerabilitiesTab. - Exposes `data-license-spdx` + `data-license-category` for filter plumbing and Playwright assertions. i18n ---- - `common.json` (EN/KO): new `sort.aria_{ascending,descending,unsorted}` keys for the SortableColumnHeader `aria-label`. - `project_detail.json` (EN/KO): new `components.license.unknown_dash` ("—") used by LicenseColumnCell when the SPDX field is null. Gates ----- - typecheck clean - lint 0 errors (+1 react-refresh warning on the new helper export, matching the project-wide pattern — 22 pre-existing instances) - vitest 951 pass (+21 new: 12 SortableColumnHeader, 3 LicenseColumnCell, 5 chart interaction, +1 absorbed; +12 + 3 + 5 + 1 = 21 incremental) - i18n:check OK Tracker ------- The `docs/post-ga-execution-tracker.md` W4 section was introduced in PR #186 (W4-A), which is still open. A tiny doc-only follow-up will mark "W4-B-prep ✅" once W4-A merges and the W4 lines land on main. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(W4-B #16/#17/#19): Overview chart deep-link + Components/Vulnerabilities UX overhaul W4-B-prep (PR #187, commit 07a8c9f) shipped three shared primitives — SortableColumnHeader, LicenseColumnCell, and the chart onSegmentClick prop — without wiring them. This PR consumes them across the three tabs the user identified in #16/#17/#19. #16 — Overview tab - Drop the Risk Score card (the header's RiskGauge already surfaces the score). The #35 Surface B "vuln data unavailable" alert survives as a standalone amber banner at the top of the tab so 0 CVEs is never silently misread as "safe". - Severity + License charts become deep-links: clicking a segment writes ?tab=vulnerabilities&severity=<key> or ?tab=licenses&license_category= <key>. The PDF setTab helper already preserves severity / license_ category when entering those tabs (PDP lines 196-218), so the link lands on the filtered list. - Recent Scans row click branches on status: succeeded / failed / cancelled → onJumpToComponents (pin snapshot + jump to Components — final results are the actionable view) queued / running → onSelectScan (re-open progress drawer) #17 — Components tab - License column replaced with LicenseColumnCell (SPDX above, policy category badge below). Two Allowed components are now distinguishable at a glance. - Severity + License MultiSelect drops removed from ComponentsToolbar. The Overview chart deep-links populate the URL params; the new ActiveFilterChips row above the table surfaces each selected value as a removable chip so the filter stays visible. - Sort + Order <select> drops removed. SortableColumnHeader on the Name / License / Severity headers cycles unset → asc → desc → unset. URL ?sort= / ?order= already mirrored the state. #19 — Vulnerabilities tab - License column uses LicenseColumnCell (BE list schema has no `license` SPDX field yet — we render the dash above the category badge so the visual matches Components without inventing data. SPDX surfacing is a follow-up that needs a BE schema bump). - Severity / License / Sort / Order toolbar controls removed; replaced by ActiveFilterChips + SortableColumnHeader on Severity / CVSS / EPSS / Reachability / Status. Column order tightened to CVE / Severity / CVSS / EPSS / Reachability / License / Title / Affected / Status — Discovered moved to the drawer to reduce horizontal scroll on a 13" laptop. - Component@Version column NOT added: VulnerabilityListItem (BE) only exposes affected_component_count, no name/version. Follow-up requires BE schema bump. i18n: 6 new keys (active_filters.*) added in EN + KO. 13 stale toolbar keys (severity_label / license_label / sort_label / sort_by_* / order_label / order_*) removed from EN + KO. i18n:check green. Gates: typecheck clean · lint 0 errors · vitest 958 passing (OverviewTab 11, ComponentsTab 16, VulnerabilitiesTab 44 — 11 net new) · i18n:check OK. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
haksungjang
added a commit
that referenced
this pull request
May 26, 2026
Session of 2026-05-26→27: six PRs merged sequentially — - #186 W4-A (admin layout) - #187 W4-B-prep (3 primitives) - #188 W4-B (Overview/Components/Vulnerabilities UX) - #189 W4-C (IA reorganize 11→8 tabs) - #190 W4-D (npm lockfile fallback for TYPE/USAGE) - #191 follow-up (Vulnerability list-schema bump) Wave 4 work bundle now closed. Next session reverts to user-feedback intake mode; operational verification steps for #190 + #191 documented in the handoff for the orchestrator to run on the next demo seed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
/admin/*이 자체AdminLayout(독자 sidebar + header)으로 마운트되어 Admin 진입 시 일반 메뉴(Dashboard / Projects / Scans / Approvals / Policies / Integrations)가 사라지는 P0 버그 수정./admin/*를AppShell하위로 nest. AppShell sidebar는 이미 super-admin에게 "Administration" 섹션을 표시하므로(L188-199) 일반 메뉴와 admin 메뉴가 항상 공존.AdminLayout을 super-admin 가드 +<Outlet />로 축소(자체 chrome 제거).data-testid="admin-layout"은 harness 호환을 위해 유지.Why
사용자 핸즈온(2026-05-26) #18 — super-admin이 Admin 진입 후 일반 portal로 못 돌아오는 dead-end. 사용자 기대: "사이드바는 항상 일반 메뉴 + admin 섹션 동시 표시".
Changes
apps/frontend/src/router.tsx: 전체 admin Route 그룹을/AppShell 부모 안으로 이동.apps/frontend/src/features/admin/AdminLayout.tsx: chrome(sidebar/header/logout/signed-in-as) 삭제. 가드만 유지.apps/frontend/tests/unit/features/admin/AdminLayout.test.tsx: 제거된 chrome 어서션 삭제(admin-sidebar/admin-nav-*/admin-logout). 가드 3 시나리오(super-admin / developer / no-user) 유지.apps/frontend/src/locales/{en,ko}/admin.json: 미사용admin.layout.{title, signed_in_as}키 제거.docs/plan-w4-ui-ia-overhaul.md: 신규 W4-A~W4-D 단일 진실 계획 문서.docs/post-ga-execution-tracker.md: W4-A "PR 대기" 표시 + 변경 요지 기록.Behavior
/admin/users진입 시 사이드바에 Dashboard / Projects / Scans / Approvals / Policies / Integrations + Administration 섹션(Users / Teams / DT / Scans / Disk / Audit / Health) 모두 표시. 일반 portal로 한 클릭 복귀 가능.AdminNotFound렌더, URL 보존).Test plan
npm run typecheckcleannpm run lint0 errors (23 pre-existing warnings)npx vitest run930 tests pass (admin layout unit 3 tests 포함)npm run i18n:checkOK (EN/KO 동기)/admin/users진입 → 사이드바에 Dashboard 등 일반 메뉴 표시 확인/admin/users직접 접근 시 404 확인🤖 Generated with Claude Code