fix: hide official marks on org catalog rows (#3415)

* fix: hide official marks on org catalog rows

* style: format app shell selector

* revert: restore locked formatter output

* fix: preserve item badges on unverified orgs
This commit is contained in:
Patrick Erichsen
2026-08-05 12:30:15 -07:00
committed by GitHub
parent 109384dcb8
commit 5d6c9c6021
5 changed files with 177 additions and 14 deletions
+101
View File
@@ -262,6 +262,107 @@ describe("user profile route", () => {
expect(screen.queryByRole("searchbox", { name: /catalog search/i })).toBeNull();
});
it("hides official marks from skill rows on organization pages", async () => {
paginatedQueryMock.mockReturnValue({
loadMore: vi.fn(),
results: [
{
_id: "skills:gpu",
kind: "skill",
displayName: "GPU Helper",
summary: "GPU tasks",
topics: [],
icon: null,
href: "/nvidia/gpu-helper",
installs: 1,
stars: 0,
isOfficial: true,
updatedAt: 1,
},
],
status: "Exhausted",
});
const route = await loadRoute();
const Component = route.__config.component as ComponentType;
render(<Component />);
expect(screen.getByText("GPU Helper")).toBeTruthy();
expect(
within(screen.getByLabelText("Publisher catalog")).queryByLabelText("Official"),
).toBeNull();
});
it("keeps official marks on skill and plugin rows for unverified organizations", async () => {
const unverifiedPublisher = {
...publisher,
official: false,
stats: {
...publisher.stats,
skills: 1,
packages: 1,
},
};
loaderDataMock.mockReturnValue({ publisher: unverifiedPublisher });
queryMock.mockImplementation((_query, args: Record<string, unknown> | "skip") => {
if (args === "skip") return undefined;
if ("publisherHandle" in args) return { publisher: unverifiedPublisher, members: [] };
if ("kind" in args) return null;
return unverifiedPublisher;
});
paginatedQueryMock.mockImplementation((_query, args: Record<string, unknown>) => ({
loadMore: vi.fn(),
results:
args.kind === "plugin"
? [
{
_id: "packages:diagnostics",
kind: "plugin",
displayName: "Diagnostics",
summary: "Plugin diagnostics",
topics: [],
icon: null,
href: "/nvidia/plugins/diagnostics",
installs: 1,
stars: 0,
isOfficial: true,
updatedAt: 1,
},
]
: args.kind === "skill"
? [
{
_id: "skills:gpu",
kind: "skill",
displayName: "GPU Helper",
summary: "GPU tasks",
topics: [],
icon: null,
href: "/nvidia/gpu-helper",
installs: 1,
stars: 0,
isOfficial: true,
updatedAt: 1,
},
]
: [],
status: "Exhausted",
}));
const route = await loadRoute();
const Component = route.__config.component as ComponentType;
render(<Component />);
const catalog = screen.getByLabelText("Publisher catalog");
expect(within(catalog).getByText("GPU Helper")).toBeTruthy();
expect(within(catalog).getByLabelText("Official")).toBeTruthy();
fireEvent.click(screen.getByRole("button", { name: /plugins 1/i }));
expect(within(catalog).getByText("Diagnostics")).toBeTruthy();
expect(within(catalog).getByLabelText("Official")).toBeTruthy();
});
it("uses downloads sort for published catalog pages by default", async () => {
const route = await loadRoute();
const Component = route.__config.component as ComponentType;
+9 -3
View File
@@ -15,6 +15,7 @@ type PluginListItemProps = {
item: PackageListItem;
variant?: "list" | "card";
href?: string;
showOfficialBadge?: boolean;
};
const PLUGIN_CATEGORIES_BY_SLUG = new Map(
@@ -41,7 +42,12 @@ function getPluginCategories(item: PackageListItem) {
});
}
export function PluginListItem({ item, variant = "list", href }: PluginListItemProps) {
export function PluginListItem({
item,
variant = "list",
href,
showOfficialBadge = true,
}: PluginListItemProps) {
const downloads = formatCompactStat(item.stats?.downloads ?? 0);
const taxonomy = getPluginTaxonomyDisplay(item);
const categories = getPluginCategories(item);
@@ -76,7 +82,7 @@ export function PluginListItem({ item, variant = "list", href }: PluginListItemP
<span className="skill-card-owner">
{item.ownerHandle ? `@${item.ownerHandle}` : "community"}
</span>
{item.isOfficial ? <OfficialBadge /> : null}
{showOfficialBadge && item.isOfficial ? <OfficialBadge /> : null}
</span>
</div>
</div>
@@ -131,7 +137,7 @@ export function PluginListItem({ item, variant = "list", href }: PluginListItemP
<span className="skill-list-item-owner">@{item.ownerHandle}</span>
) : null}
</span>
{item.isOfficial ? <OfficialBadge /> : null}
{showOfficialBadge && item.isOfficial ? <OfficialBadge /> : null}
<CatalogTopicList topics={taxonomy.labels} limit={2} ariaLabel={taxonomy.ariaLabel} />
</div>
<p className="skill-list-item-summary">
+14
View File
@@ -102,6 +102,20 @@ describe("PublishedItemCard", () => {
expect(screen.queryByText("Official")).toBeNull();
});
it.each([baseSkill, basePlugin])(
"can hide the official mark from publisher catalog rows",
(item) => {
render(
<PublishedItemCard
item={{ ...item, icon: null, isOfficial: true }}
showOfficialBadge={false}
/>,
);
expect(screen.queryByLabelText("Official")).toBeNull();
},
);
it("does not add source-backed chrome to GitHub-backed skill rows", () => {
render(
<PublishedItemCard
+3 -1
View File
@@ -17,6 +17,7 @@ type SkillListItemProps = {
ownerHandle?: string | null;
owner?: PublicPublisher | null;
href?: string;
showOfficialBadge?: boolean;
};
export function SkillListItem({
@@ -24,6 +25,7 @@ export function SkillListItem({
ownerHandle,
owner,
href: hrefOverride,
showOfficialBadge = true,
}: SkillListItemProps) {
const handle = ownerHandle ?? owner?.handle ?? null;
const ownerSegment = handle?.trim() || String(skill.ownerPublisherId ?? skill.ownerUserId);
@@ -49,7 +51,7 @@ export function SkillListItem({
</span>
{handle ? <span className="skill-list-item-owner">@{handle}</span> : null}
</span>
{isOfficial ? <OfficialBadge /> : null}
{showOfficialBadge && isOfficial ? <OfficialBadge /> : null}
{badges
.filter((badge) => badge !== "Official")
.map((badge) => (
+50 -10
View File
@@ -741,6 +741,7 @@ export function PublisherProfilePage({
const hiddenOrgCount = Math.max(0, affiliations.length - VISIBLE_ORG_CHIPS);
const showOrganizations = publisher.kind === "user" && affiliations.length > 0;
const showMembers = publisher.kind === "org" && memberEntries.length > 0;
const showCatalogOfficialBadge = publisher.kind !== "org" || publisher.official !== true;
const publisherStatCards = buildPublisherStatCards(publisher);
const profileBio = publisher.bio?.trim() || DEFAULT_PUBLISHER_BIO;
@@ -918,6 +919,7 @@ export function PublisherProfilePage({
groups={catalogGroups}
selectedGroup={selectedCatalogGroup}
onSelectedGroupChange={setSelectedCatalogGroup}
showOfficialBadge={showCatalogOfficialBadge}
totalCount={catalogSearch.trim() ? undefined : catalogCount}
footer={
showCatalogLoadMore ? (
@@ -933,7 +935,10 @@ export function PublisherProfilePage({
/>
) : filteredItems.length > 0 ? (
<>
<PublisherCatalogItems items={filteredItems} />
<PublisherCatalogItems
items={filteredItems}
showOfficialBadge={showCatalogOfficialBadge}
/>
{showCatalogLoadMore ? (
<div className="publisher-profile-load-more">
<Button type="button" onClick={() => activeLoadMore(12)}>
@@ -1119,19 +1124,35 @@ export function shouldShowPublisherCatalogLoadMore({
);
}
function PublisherCatalogItems({ items }: { items: PublicPublisherCatalogItem[] }) {
function PublisherCatalogItems({
items,
showOfficialBadge = true,
}: {
items: PublicPublisherCatalogItem[];
showOfficialBadge?: boolean;
}) {
return (
<div className="browse-list-stack">
<div className="results-list">
{items.map((item) => (
<PublishedItemCard key={`${item.kind}:${item._id}`} item={item} />
<PublishedItemCard
key={`${item.kind}:${item._id}`}
item={item}
showOfficialBadge={showOfficialBadge}
/>
))}
</div>
</div>
);
}
function PublisherCatalogGroupSection({ group }: { group: PublisherCatalogGroup }) {
function PublisherCatalogGroupSection({
group,
showOfficialBadge,
}: {
group: PublisherCatalogGroup;
showOfficialBadge?: boolean;
}) {
return (
<section
className="publisher-profile-manifest-section"
@@ -1141,7 +1162,7 @@ function PublisherCatalogGroupSection({ group }: { group: PublisherCatalogGroup
<h3 id={`catalog-group-${group.key}`}>{group.title}</h3>
{group.description ? <p>{group.description}</p> : null}
</header>
<PublisherCatalogItems items={group.items} />
<PublisherCatalogItems items={group.items} showOfficialBadge={showOfficialBadge} />
</section>
);
}
@@ -1152,12 +1173,14 @@ export function PublisherGroupedCatalog({
onSelectedGroupChange,
footer,
totalCount,
showOfficialBadge,
}: {
groups: PublisherCatalogGroup[];
selectedGroup: string;
onSelectedGroupChange: (value: string) => void;
footer?: ReactNode;
totalCount?: number;
showOfficialBadge?: boolean;
}) {
const activeGroup =
selectedGroup === "all" ? null : (groups.find((group) => group.key === selectedGroup) ?? null);
@@ -1179,11 +1202,15 @@ export function PublisherGroupedCatalog({
{selectedGroup === "all" ? (
<div className="publisher-profile-catalog-sections">
{groups.map((group) => (
<PublisherCatalogGroupSection key={group.key} group={group} />
<PublisherCatalogGroupSection
key={group.key}
group={group}
showOfficialBadge={showOfficialBadge}
/>
))}
</div>
) : activeGroup ? (
<PublisherCatalogGroupSection group={activeGroup} />
<PublisherCatalogGroupSection group={activeGroup} showOfficialBadge={showOfficialBadge} />
) : null}
{footer}
</div>
@@ -1365,12 +1392,25 @@ function catalogItemToPackageListItem(item: PublicPublisherCatalogItem): Package
};
}
export function PublishedItemCard({ item }: { item: PublicPublisherCatalogItem }) {
export function PublishedItemCard({
item,
showOfficialBadge = true,
}: {
item: PublicPublisherCatalogItem;
showOfficialBadge?: boolean;
}) {
if (item.kind === "plugin") {
const plugin = catalogItemToPackageListItem(item);
return <PluginListItem item={plugin} variant="list" href={item.href} />;
return (
<PluginListItem
item={plugin}
variant="list"
href={item.href}
showOfficialBadge={showOfficialBadge}
/>
);
}
const skill = catalogItemToPublicSkill(item);
return <SkillListItem skill={skill} href={item.href} />;
return <SkillListItem skill={skill} href={item.href} showOfficialBadge={showOfficialBadge} />;
}