import { useEffect, useRef, useState } from "react"; import { useLocation, useNavigate, useParams, useSearchParams } from "react-router-dom"; import { LuPencil, LuPlus, LuTrash2 } from "react-icons/lu"; import { errorMessage } from "../api/client.js"; import { useDeleteSecret, useOwners, useSecrets } from "../api/hooks.js"; import { ConfirmDialog } from "../components/ConfirmDialog.jsx"; import { FormSelect } from "../components/FormControls.jsx"; import { SecretEditorModal } from "../components/SecretEditorModal.jsx"; import { useRouteDrivenModal } from "../hooks/useRouteDrivenModal.js"; import { formatTime } from "../lib/format.jsx"; export function SecretsPage() { const navigate = useNavigate(); const location = useLocation(); const { owner: routeOwner, name: routeName } = useParams(); const [params] = useSearchParams(); const isNewRoute = /\/secrets\/new\/?$/.test(location.pathname); const isEditRoute = Boolean(routeOwner && routeName); const { data: owners = [] } = useOwners(); const [ownerFilter, setOwnerFilter] = useState( () => routeOwner || params.get("owner") || "", ); const { data: secrets = [], isLoading } = useSecrets(ownerFilter || undefined); const del = useDeleteSecret(); const [confirmDelete, setConfirmDelete] = useState(null); const [highlightName, setHighlightName] = useState(() => routeName || ""); const highlightRef = useRef(null); const listPath = ownerFilter ? `/secrets?owner=${encodeURIComponent(ownerFilter)}` : "/secrets"; const { editor, closeEditor } = useRouteDrivenModal({ isNewRoute, isEditRoute, listPath, newRouteKey: () => `new:${params.get("owner") || ""}:${params.get("name") || ""}`, canOpenNew: () => Boolean(params.get("owner") || ownerFilter || owners.length > 0), onBeforeOpenNew: () => { if (params.get("owner")) setOwnerFilter(params.get("owner")); }, buildNewEditor: () => { const owner = params.get("owner") || ownerFilter || owners[0] || "default"; return { mode: "add", initial: { owner, name: params.get("name") || "" }, }; }, editRouteKey: () => `edit:${routeOwner}/${routeName}`, canOpenEdit: () => { if (ownerFilter !== routeOwner) { setOwnerFilter(routeOwner); return false; } return true; }, onOpenEdit: () => setHighlightName(routeName), buildEditEditor: () => ({ mode: "replace", initial: { owner: routeOwner, name: routeName }, }), newDeps: [params, owners, ownerFilter], editDeps: [routeOwner, routeName, ownerFilter], }); useEffect(() => { if (!highlightName || isLoading) return; highlightRef.current?.scrollIntoView({ block: "nearest", behavior: "smooth" }); }, [highlightName, isLoading, secrets]); return (

Secrets

{ setOwnerFilter(e.target.value); setHighlightName(""); navigate( e.target.value ? `/secrets?owner=${encodeURIComponent(e.target.value)}` : "/secrets", { replace: true }, ); }} > {owners.map((o) => ( ))}
{isLoading ? ( ) : secrets.length === 0 ? (

No secrets yet.

) : (
{secrets.map((s) => { const highlighted = highlightName && s.name === highlightName && (!ownerFilter || s.owner === ownerFilter); return ( ); })}
Owner Name Updated
{s.owner} {s.name} {formatTime(s.updated_at)}
)} {editor ? ( { setHighlightName(saved?.name || editor.initial.name); }} /> ) : null} setConfirmDelete(null)} onConfirm={() => del.mutate(confirmDelete.id, { onSuccess: () => setConfirmDelete(null) }) } />
); }