20260623 optimize rpki explorer ui interactions

This commit is contained in:
2026-06-23 15:47:50 +08:00
parent 4f41fbe04e
commit 574e40a4d4
16 changed files with 1483 additions and 297 deletions

View File

@@ -1,9 +1,13 @@
import { Activity, Braces, Database, FileSearch, GitBranch, Home, PackageOpen, ShieldCheck } from "lucide-react";
import type { LucideIcon } from "lucide-react";
import { useState } from "react";
import { Shell } from "../components/layout/Shell";
import { ObjectDetailPage } from "../features/object-detail/ObjectDetailPage";
import { OverviewPage } from "../features/overview/OverviewPage";
import { RepositoriesPage } from "../features/repositories/RepositoriesPage";
import { createRepositoryBrowserState } from "../features/repositories/repositoryBrowserState";
type ViewId = "overview" | "repositories" | "publication-points" | "objects" | "validation" | "exports" | "runs" | "api";
const navigationItems = [
{ id: "overview", label: "Overview", icon: Home },
@@ -14,22 +18,86 @@ const navigationItems = [
{ id: "exports", label: "Exports", icon: PackageOpen },
{ id: "runs", label: "Runs", icon: Activity },
{ id: "api", label: "API", icon: FileSearch }
];
] satisfies Array<{ id: ViewId; label: string; icon: LucideIcon }>;
const comingSoonCopy: Record<Exclude<ViewId, "overview" | "repositories" | "objects">, { title: string; description: string; alternative: string }> = {
"publication-points": {
title: "Publication Points",
description: "Dedicated publication point analytics are not implemented yet.",
alternative: "Use Repositories to drill down from repository to publication point and object rows."
},
validation: {
title: "Validation",
description: "A dedicated validation investigation workspace is planned but not available in this MVP.",
alternative: "Use Overview for reason summaries and Object Detail for per-object validation evidence."
},
exports: {
title: "Exports",
description: "A standalone export job browser is planned but not available yet.",
alternative: "Use Object Detail to trigger object or publication point export workflows."
},
runs: {
title: "Runs",
description: "Historical run navigation is not implemented in the current Explorer UI.",
alternative: "The current view always uses the latest indexed run from query service."
},
api: {
title: "API",
description: "The API reference page is planned but not implemented yet.",
alternative: "Use the project README and query service endpoints while the UI reference page is pending."
}
};
export function App() {
const [activeView, setActiveView] = useState("overview");
const [activeView, setActiveView] = useState<ViewId>("overview");
const [selectedObjectInstanceId, setSelectedObjectInstanceId] = useState<string | null>(null);
const [repositoryBrowserState, setRepositoryBrowserState] = useState(createRepositoryBrowserState);
const openObject = (objectInstanceId: string) => {
setSelectedObjectInstanceId(objectInstanceId);
setActiveView("objects");
};
const renderActiveView = () => {
if (activeView === "objects") {
return <ObjectDetailPage initialObjectInstanceId={selectedObjectInstanceId} />;
}
if (activeView === "repositories") {
return (
<RepositoriesPage
browserState={repositoryBrowserState}
onBrowserStateChange={setRepositoryBrowserState}
onOpenObject={openObject}
/>
);
}
if (activeView === "overview") {
return <OverviewPage />;
}
return <ComingSoonPage {...comingSoonCopy[activeView]} />;
};
return (
<Shell activeView={activeView} navigationItems={navigationItems} onNavigate={setActiveView}>
{activeView === "objects" ? <ObjectDetailPage initialObjectInstanceId={selectedObjectInstanceId} /> : null}
{activeView === "repositories" ? <RepositoriesPage onOpenObject={openObject} /> : null}
{activeView !== "objects" && activeView !== "repositories" ? <OverviewPage /> : null}
{renderActiveView()}
</Shell>
);
}
function ComingSoonPage({ title, description, alternative }: { title: string; description: string; alternative: string }) {
return (
<section className="page-stack" aria-labelledby="coming-soon-heading">
<div className="hero-dashboard compact-hero coming-soon-panel">
<div>
<p className="eyebrow">Planned workspace</p>
<h2 id="coming-soon-heading">{title}</h2>
<p>{description}</p>
</div>
<div className="hero-status muted-status">
<strong>Coming soon</strong>
<span>{alternative}</span>
</div>
</div>
</section>
);
}