Accept a KiCad project drop so hierarchical sheets and the board upload in one step.
A single .kicad_sch was parsed in isolation, so child sheets looked like an empty netlist. Report 404s now surface the real API error instead of a generic fetch failure. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -41,6 +41,7 @@ import {
|
||||
} from "lucide-react";
|
||||
import { useOptionalUser } from "@/hooks/use-optional-auth";
|
||||
import { ImpedancePanel } from "@/components/project/impedance-panel";
|
||||
import { PcbUploadButton } from "@/components/project/pcb-upload";
|
||||
|
||||
export default function ProjectDetailPage({
|
||||
params,
|
||||
@@ -190,6 +191,11 @@ export default function ProjectDetailPage({
|
||||
<h1 className="text-lg font-semibold">{project.name}</h1>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{new Date(project.created).toLocaleDateString()}
|
||||
{project.hasPcb ? (
|
||||
<span className="ml-2">· PCB uploaded</span>
|
||||
) : (
|
||||
<span className="ml-2">· no PCB</span>
|
||||
)}
|
||||
{typeof project.totalCostUsd === "number" && project.totalCostUsd > 0 && (
|
||||
<span className="ml-2 font-mono tabular-nums text-foreground">
|
||||
${project.totalCostUsd.toFixed(4)}
|
||||
@@ -348,7 +354,11 @@ export default function ProjectDetailPage({
|
||||
)}
|
||||
|
||||
{tab === "impedance" && (
|
||||
<ImpedancePanel projectId={id} hasPcb={Boolean(project.hasPcb)} />
|
||||
<ImpedancePanel
|
||||
projectId={id}
|
||||
hasPcb={Boolean(project.hasPcb)}
|
||||
onPcbUploaded={reload}
|
||||
/>
|
||||
)}
|
||||
|
||||
{tab === "logs" && (
|
||||
@@ -357,6 +367,19 @@ export default function ProjectDetailPage({
|
||||
|
||||
{tab === "settings" && (
|
||||
<div className="space-y-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-sm">KiCad PCB</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-2">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{project.hasPcb
|
||||
? "A .kicad_pcb is on this project. Replace it here, then re-run the pipeline for layout and net Z0."
|
||||
: "No board yet. Schematic review does not need one. Layout checks and net Z0 do."}
|
||||
</p>
|
||||
<PcbUploadButton projectId={id} onUploaded={reload} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
<CollaboratorsSection projectId={id} />
|
||||
<SkippedComponentsSection skipped={project.skippedComponents} />
|
||||
<ReportVersionSection pinscopeVersion={project.pinscopeVersion} />
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
import { PipelineStepper } from "@/components/progress/pipeline-stepper";
|
||||
import { PausedRunBanner } from "@/components/billing/paused-run-banner";
|
||||
import { usePipelineProgress } from "@/hooks/use-pipeline-progress";
|
||||
import { cancelPipeline, fetchProject, resumePipeline, reprocessPipeline } from "@/lib/api";
|
||||
import { cancelPipeline, fetchProject, fetchReport, resumePipeline, reprocessPipeline } from "@/lib/api";
|
||||
import type { PauseCheckpoint } from "@/lib/types";
|
||||
import {
|
||||
AlertTriangle,
|
||||
@@ -107,14 +107,24 @@ export default function ProgressPage({
|
||||
}
|
||||
};
|
||||
|
||||
// Auto-navigate to report when pipeline completes successfully
|
||||
// Auto-navigate to report when pipeline completes and the file exists
|
||||
useEffect(() => {
|
||||
if (done && !error && !cancelled && !projectPaused) {
|
||||
const timer = setTimeout(() => {
|
||||
router.push(`/project/${id}/report`);
|
||||
}, 1500);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
if (!done || error || cancelled || projectPaused) return;
|
||||
let stopped = false;
|
||||
(async () => {
|
||||
for (let i = 0; i < 8; i++) {
|
||||
try {
|
||||
await fetchReport(id);
|
||||
if (!stopped) router.push(`/project/${id}/report`);
|
||||
return;
|
||||
} catch {
|
||||
await new Promise((r) => setTimeout(r, 500));
|
||||
}
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
stopped = true;
|
||||
};
|
||||
}, [done, error, cancelled, projectPaused, id, router]);
|
||||
|
||||
// Auto-navigate to dashboard when pipeline is cancelled
|
||||
|
||||
@@ -220,8 +220,18 @@ function ReportContent({ projectId }: { projectId: string }) {
|
||||
|
||||
if (error || !report || !graph) {
|
||||
return (
|
||||
<div className="p-6 max-w-5xl mx-auto w-full text-center py-12 text-sm text-muted-foreground">
|
||||
{error ?? "Report not found."}
|
||||
<div className="p-6 max-w-5xl mx-auto w-full text-center py-12 space-y-3">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{error ?? "Report not found."}
|
||||
</p>
|
||||
<p className="text-sm">
|
||||
<a
|
||||
href={`/project/${projectId}/progress`}
|
||||
className="text-blue-600 dark:text-blue-500 hover:underline"
|
||||
>
|
||||
Open pipeline progress
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user