fix: clarify paginated plugin count (#2393)

* fix: clarify paginated plugin count

* fix: correct shown-count pluralization

Agent-Logs-Url: https://github.com/openclaw/clawhub/sessions/32575bd4-9dc7-4b8f-9536-bdc96f008783

Co-authored-by: BunsDev <68980965+BunsDev@users.noreply.github.com>
This commit is contained in:
Val Alexander
2026-05-31 01:00:02 -05:00
committed by GitHub
co-authored by BunsDev
parent 05d5fc1151
commit 9fc2da4dc4
2 changed files with 49 additions and 2 deletions
+31
View File
@@ -346,6 +346,9 @@ describe("plugins route", () => {
render(<Component />);
expect(screen.getByRole("heading", { name: "Plugins 1+" })).toBeTruthy();
expect(screen.getByText("1+ results")).toBeTruthy();
fireEvent.click(screen.getByRole("button", { name: "Next page" }));
expect(navigateMock).toHaveBeenCalled();
@@ -357,6 +360,34 @@ describe("plugins route", () => {
});
});
it("uses singular shown text on non-first browse pages", async () => {
searchMock = { cursor: "cursor:current" };
loaderDataMock = {
items: [
{
name: "demo-plugin",
displayName: "Demo Plugin",
family: "code-plugin",
channel: "community",
isOfficial: false,
executesCode: true,
createdAt: 1,
updatedAt: 1,
},
],
nextCursor: "cursor:next",
rateLimited: false,
retryAfterSeconds: null,
};
const route = await loadRoute();
const Component = route.__config.component as ComponentType;
render(<Component />);
expect(screen.getByRole("heading", { name: "Plugins 1 shown" })).toBeTruthy();
expect(screen.getByText("1 result shown")).toBeTruthy();
});
it("renders a title count and switches to grid view", async () => {
loaderDataMock = {
items: [
+18 -2
View File
@@ -94,6 +94,18 @@ function sortPluginSearchItems(items: PackageListItem[], sort: PluginSort) {
return sorted;
}
function formatPluginHeadingCount(count: number, hasNextPage: boolean, hasPreviousPage: boolean) {
if (hasPreviousPage) return `${count} shown`;
if (hasNextPage) return `${count}+`;
return String(count);
}
function formatPluginResultsCount(count: number, hasNextPage: boolean, hasPreviousPage: boolean) {
if (hasPreviousPage) return `${count} result${count === 1 ? "" : "s"} shown`;
if (hasNextPage) return `${count}+ results`;
return `${count} result${count === 1 ? "" : "s"}`;
}
export const Route = createFileRoute("/plugins/")({
pendingComponent: PluginsIndexPending,
validateSearch: (search): PluginSearchState => ({
@@ -273,6 +285,10 @@ function PluginsIndex() {
() => (hasQuery ? sortPluginSearchItems(items, activeSort as PluginSort) : items),
[activeSort, hasQuery, items],
);
const hasPreviousPage = Boolean(!hasQuery && search.cursor);
const hasNextPage = Boolean(!hasQuery && nextCursor);
const headingCount = formatPluginHeadingCount(visibleItems.length, hasNextPage, hasPreviousPage);
const resultsCount = formatPluginResultsCount(visibleItems.length, hasNextPage, hasPreviousPage);
const sortOptions = useMemo(() => {
if (hasQuery) {
@@ -419,7 +435,7 @@ function PluginsIndex() {
Filters
</button>
<h1 className="browse-title">
Plugins <span className="browse-count">{visibleItems.length}</span>
Plugins <span className="browse-count">{headingCount}</span>
</h1>
</div>
<form className="browse-page-search" onSubmit={handleSearch}>
@@ -448,7 +464,7 @@ function PluginsIndex() {
<div className="browse-results">
<div className="browse-results-toolbar">
<span className="browse-results-count">
{visibleItems.length} result{visibleItems.length !== 1 ? "s" : ""}
{resultsCount}
{hasQuery ||
search.category ||
search.official ||