import { useDeferredValue, useMemo, useState } from "react"; import { useQuery } from "@tanstack/react-query"; import { Link } from "react-router-dom"; import { listOperations } from "../../entities/operation/api"; import { PageSection } from "../../shared/ui/page-section"; export function OperationListPage() { const [searchTerm, setSearchTerm] = useState(""); const deferredSearchTerm = useDeferredValue(searchTerm); const operationsQuery = useQuery({ queryKey: ["operations"], queryFn: listOperations, }); const filteredItems = useMemo(() => { const items = operationsQuery.data?.items ?? []; const normalizedSearchTerm = deferredSearchTerm.trim().toLowerCase(); if (!normalizedSearchTerm) { return items; } return items.filter((item) => `${item.name} ${item.display_name} ${item.protocol} ${item.status}` .toLowerCase() .includes(normalizedSearchTerm), ); }, [deferredSearchTerm, operationsQuery.data?.items]); const metrics = useMemo(() => { const items = operationsQuery.data?.items ?? []; return { total: items.length, published: items.filter((item) => item.status === "published").length, drafts: items.filter((item) => item.status === "draft").length, protocols: Array.from(new Set(items.map((item) => item.protocol))).length, }; }, [operationsQuery.data?.items]); return (
Catalog health
Published and draft operations share one operator surface and one MCP publication path.
Fetching the current registry snapshot from the admin backend.
Adjust the search term or create a new contract for REST, GraphQL or unary gRPC.
Create operation{item.name}