fix: 사이트 검사 3가지 UI 이슈 수정

1. SSE page_complete 이벤트 필드명 score→overall_score 불일치 수정
   (진행 페이지에서 각 페이지별 점수가 표시되지 않던 버그)
2. 진행 페이지 재방문 시 완료된 검사는 결과 대시보드로 자동 리다이렉트
3. 카테고리 상세(이슈 목록)를 인라인으로 표시하여 트리 사이드바 유지
   (이전: 별도 페이지로 이동하여 트리가 사라지는 문제)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jungwoo choi
2026-02-13 17:37:14 +09:00
parent 3e224d221a
commit c440f1c332
4 changed files with 116 additions and 15 deletions

View File

@ -22,7 +22,7 @@ class Settings(BaseSettings):
MAX_HTML_SIZE: int = 10485760 # 10MB
# Site inspection
SITE_MAX_PAGES: int = 20
SITE_MAX_PAGES: int = 500
SITE_MAX_DEPTH: int = 2
SITE_CONCURRENCY: int = 2

View File

@ -61,8 +61,9 @@ class SiteInspectionService:
"""
settings = get_settings()
# Clamp to server-side limits
max_pages = min(max_pages, settings.SITE_MAX_PAGES)
# Clamp to server-side limits (0 = unlimited, don't clamp)
if max_pages > 0:
max_pages = min(max_pages, settings.SITE_MAX_PAGES)
max_depth = min(max_depth, settings.SITE_MAX_DEPTH)
site_inspection_id = str(uuid.uuid4())
@ -507,7 +508,7 @@ class SiteInspectionService:
"page_url": page_url,
"page_index": page_index,
"inspection_id": inspection_id,
"score": overall_score,
"overall_score": overall_score,
"grade": grade,
})
@ -553,7 +554,7 @@ class SiteInspectionService:
"page_url": page_url,
"page_index": page_index,
"inspection_id": None,
"score": 0,
"overall_score": 0,
"grade": "F",
"error": str(e)[:200],
})

View File

@ -1,21 +1,22 @@
"use client";
import { use, useState, useCallback } from "react";
import { useRouter } from "next/navigation";
import { useSiteInspectionResult, useInspectionResult } from "@/lib/queries";
import { useSiteInspectionResult, useInspectionResult, useInspectionIssues } from "@/lib/queries";
import { PageTree } from "@/components/site-inspection/PageTree";
import { AggregateScorePanel } from "@/components/site-inspection/AggregateScorePanel";
import { OverallScoreGauge } from "@/components/dashboard/OverallScoreGauge";
import { CategoryScoreCard } from "@/components/dashboard/CategoryScoreCard";
import { IssueSummaryBar } from "@/components/dashboard/IssueSummaryBar";
import { InspectionMeta } from "@/components/dashboard/InspectionMeta";
import { FilterBar } from "@/components/issues/FilterBar";
import { IssueList } from "@/components/issues/IssueList";
import { LoadingSpinner } from "@/components/common/LoadingSpinner";
import { ErrorState } from "@/components/common/ErrorState";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { CATEGORY_LABELS, CATEGORY_KEYS } from "@/lib/constants";
import { ApiError } from "@/lib/api";
import { Clock, Menu, X } from "lucide-react";
import { Clock, Menu, X, ArrowLeft } from "lucide-react";
import type { CategoryKey } from "@/types/inspection";
export default function SiteInspectionResultPage({
@ -158,7 +159,7 @@ export default function SiteInspectionResultPage({
/**
* 개별 페이지 대시보드 컴포넌트.
* 기존 inspection 결과 컴포넌트들을 재사용하여 특정 페이지의 검사 결과를 표시한다.
* 카테고리 클릭 시 이슈 목록을 인라인으로 표시하여 트리 사이드바를 유지한다.
*/
function PageDashboard({
inspectionId,
@ -167,7 +168,11 @@ function PageDashboard({
inspectionId: string;
pageUrl: string;
}) {
const router = useRouter();
// 이슈 보기 모드 상태
const [issueView, setIssueView] = useState<{
showing: boolean;
initialCategory: string;
}>({ showing: false, initialCategory: "all" });
const {
data: result,
@ -179,14 +184,25 @@ function PageDashboard({
const handleCategoryClick = useCallback(
(category: CategoryKey) => {
router.push(`/inspections/${inspectionId}/issues?category=${category}`);
setIssueView({ showing: true, initialCategory: category });
},
[inspectionId, router]
[]
);
const handleViewIssues = useCallback(() => {
router.push(`/inspections/${inspectionId}/issues`);
}, [inspectionId, router]);
setIssueView({ showing: true, initialCategory: "all" });
}, []);
const handleBackToDashboard = useCallback(() => {
setIssueView({ showing: false, initialCategory: "all" });
}, []);
// inspectionId 변경 시 이슈 뷰 초기화
const [prevId, setPrevId] = useState(inspectionId);
if (inspectionId !== prevId) {
setPrevId(inspectionId);
setIssueView({ showing: false, initialCategory: "all" });
}
if (isLoading) {
return <LoadingSpinner message="페이지 검사 결과를 불러오는 중..." />;
@ -205,6 +221,17 @@ function PageDashboard({
);
}
// 이슈 목록 인라인 보기
if (issueView.showing) {
return (
<InlineIssueView
inspectionId={inspectionId}
initialCategory={issueView.initialCategory}
onBack={handleBackToDashboard}
/>
);
}
return (
<div>
{/* 페이지 URL 표시 */}
@ -281,3 +308,64 @@ function PageDashboard({
</div>
);
}
/**
* 이슈 목록 인라인 뷰.
* 사이트 검사 결과 페이지 내에서 이슈를 표시하여 트리 사이드바를 유지한다.
*/
function InlineIssueView({
inspectionId,
initialCategory,
onBack,
}: {
inspectionId: string;
initialCategory: string;
onBack: () => void;
}) {
const [selectedCategory, setSelectedCategory] = useState(initialCategory);
const [selectedSeverity, setSelectedSeverity] = useState("all");
const { data, isLoading, isError, refetch } = useInspectionIssues(
inspectionId,
selectedCategory === "all" ? undefined : selectedCategory,
selectedSeverity === "all" ? undefined : selectedSeverity
);
return (
<div>
{/* 뒤로가기 */}
<div className="mb-4">
<Button variant="ghost" size="sm" onClick={onBack}>
<ArrowLeft className="h-4 w-4" />
</Button>
</div>
<h2 className="text-xl font-bold mb-4"> </h2>
{/* 필터 */}
<div className="mb-6">
<FilterBar
selectedCategory={selectedCategory}
selectedSeverity={selectedSeverity}
onCategoryChange={setSelectedCategory}
onSeverityChange={setSelectedSeverity}
/>
</div>
{/* 이슈 목록 */}
{isError ? (
<ErrorState
message="이슈 목록을 불러올 수 없습니다"
onRetry={() => refetch()}
/>
) : (
<IssueList
issues={data?.issues}
isLoading={isLoading}
total={data?.total || 0}
/>
)}
</div>
);
}

View File

@ -1,6 +1,8 @@
"use client";
import { use } from "react";
import { use, useEffect } from "react";
import { useRouter } from "next/navigation";
import { useSiteInspectionResult } from "@/lib/queries";
import { SiteCrawlProgress } from "@/components/site-inspection/SiteCrawlProgress";
export default function SiteInspectionProgressPage({
@ -9,6 +11,16 @@ export default function SiteInspectionProgressPage({
params: Promise<{ id: string }>;
}) {
const { id } = use(params);
const router = useRouter();
// 이미 완료된 검사인 경우 결과 페이지로 리다이렉트
const { data: siteResult } = useSiteInspectionResult(id);
useEffect(() => {
if (siteResult?.status === "completed" || siteResult?.status === "error") {
router.replace(`/site-inspections/${id}`);
}
}, [siteResult?.status, id, router]);
return (
<div className="container mx-auto px-4 py-8">