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:
@ -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
|
||||
|
||||
|
||||
@ -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],
|
||||
})
|
||||
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@ -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">
|
||||
|
||||
Reference in New Issue
Block a user