Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ const ComponentMarkup = ({
owned,
published_by: publishedBy,
} = component;
const componentIdentifier = publishedBy
? `Published by ${publishedBy}`
: digest
? `Digest ${digest}`
: undefined;

const displayName = useMemo(
() => name ?? getComponentName({ spec, url }),
Expand Down Expand Up @@ -267,14 +272,14 @@ const ComponentMarkup = ({
>
{displayName}
</Text>
{publishedBy && (
{componentIdentifier && (
<Text
size="xs"
tone="subdued"
className="min-w-0 truncate"
title={`Published by ${publishedBy}`}
title={componentIdentifier}
>
Published by {publishedBy}
{componentIdentifier}
</Text>
)}
{matchExplanation && (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { render, screen } from "@testing-library/react";
import type { ReactNode } from "react";
import { describe, expect, it, vi } from "vitest";

import type { SearchResult } from "@/types/componentLibrary";
import { ComponentSearchFilter } from "@/utils/constants";

import SearchResults from "./SearchResults";

vi.mock("@/components/shared/Dialogs", () => ({
ComponentDetailsDialog: () => <button type="button">Details</button>,
}));

vi.mock("@/components/shared/FavoriteComponentToggle", () => ({
ComponentFavoriteToggle: () => <button type="button">Favorite</button>,
}));

vi.mock(
"@/components/shared/ManageComponent/hooks/useOutdatedComponents",
() => ({
useOutdatedComponents: () => ({ data: [] }),
}),
);

vi.mock("@/components/shared/Settings/useFlags", () => ({
useFlagValue: () => false,
}));

vi.mock("@/providers/ComponentLibraryProvider/ForcedSearchProvider", () => ({
useForcedSearchContext: () => ({
currentSearchFilter: {
searchTerm: "scrape",
filters: [ComponentSearchFilter.NAME],
},
}),
}));

vi.mock("../../NodesOverlay/NodesOverlayProvider", () => ({
useNodesOverlay: () => ({
notifyNode: vi.fn(),
getNodeIdsByDigest: vi.fn(() => []),
fitNodeIntoView: vi.fn(),
}),
}));

vi.mock("./ComponentHoverPopover", () => ({
ComponentHoverPopover: ({ children }: { children: ReactNode }) => (
<>{children}</>
),
}));

describe("SearchResults", () => {
it("shows publisher metadata for v1 component search results", () => {
const searchResult: SearchResult = {
components: {
standard: [
{
digest: "published-digest",
name: "Scrape V2",
published_by: "pipeline-components@shopify.com",
},
],
user: [],
used: [],
},
};

render(
<SearchResults searchResult={searchResult} onFiltersChange={vi.fn()} />,
);

expect(screen.getByText("Scrape V2")).toBeInTheDocument();
expect(
screen.getByText("Published by pipeline-components@shopify.com"),
).toBeInTheDocument();
});

it("shows digest metadata when a v1 component search result has no publisher", () => {
const searchResult: SearchResult = {
components: {
standard: [
{
digest: "sha256:abc123",
name: "Upload to GCS",
},
],
user: [],
used: [],
},
};

render(
<SearchResults searchResult={searchResult} onFiltersChange={vi.fn()} />,
);

expect(screen.getByText("Upload to GCS")).toBeInTheDocument();
expect(screen.getByText("Digest sha256:abc123")).toBeInTheDocument();
});
});
39 changes: 36 additions & 3 deletions src/routes/Dashboard/DashboardComponentsV2View.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ const routeMocks = vi.hoisted(() => {
return {
standard: makeComponent("standard-digest", "Standard component"),
registered: makeComponent("registered-digest", "Registered component"),
published: {
...makeComponent("published-digest", "Published component"),
published_by: "pipeline-components@shopify.com",
},
user: makeComponent("user-digest", "User component"),
extraStandardComponents: [] as ComponentReference[],
navigate: vi.fn(),
Expand Down Expand Up @@ -81,7 +85,7 @@ vi.mock("@tanstack/react-query", () => ({
}

if (key === "component-search-v2" && queryKey[1] === "published") {
return { data: [], isLoading: false };
return { data: [routeMocks.published], isLoading: false };
}

if (
Expand All @@ -108,6 +112,7 @@ vi.mock("@tanstack/react-query", () => ({
data: [
routeMocks.standard,
routeMocks.registered,
routeMocks.published,
routeMocks.user,
...routeMocks.extraStandardComponents,
],
Expand Down Expand Up @@ -536,13 +541,13 @@ describe("DashboardComponentsV2View", () => {

expect(
screen.getByText(
"Showing 100 of 108 components in selected sources. Start typing to search.",
"Showing 100 of 109 components in selected sources. Start typing to search.",
),
).toBeInTheDocument();
expect(screen.getByText("Browse component 099")).toBeInTheDocument();
expect(screen.queryByText("Browse component 100")).not.toBeInTheDocument();

fireEvent.click(screen.getByRole("button", { name: "Show 8 more" }));
fireEvent.click(screen.getByRole("button", { name: "Show 9 more" }));

await waitFor(() => {
expect(screen.getByText("Browse component 104")).toBeInTheDocument();
Expand Down Expand Up @@ -635,6 +640,34 @@ describe("DashboardComponentsV2View", () => {
});
});

it("shows publisher on published component result cards", async () => {
render(<DashboardComponentsV2View />);

fireEvent.change(screen.getByLabelText("Search components"), {
target: { value: "published" },
});

await waitFor(() => {
expect(screen.getByText("Published component")).toBeInTheDocument();
});
expect(
screen.getByText("Published by pipeline-components@shopify.com"),
).toBeInTheDocument();
});

it("keeps publisher visible in compact selected-result rows", async () => {
routeMocks.search = { component: "published-digest", q: "published" };

render(<DashboardComponentsV2View />);

await waitFor(() => {
expect(screen.getByText("Published component")).toBeInTheDocument();
});
expect(
screen.getByText("Published by pipeline-components@shopify.com"),
).toBeInTheDocument();
});

it("explains why lexical component results matched", async () => {
render(<DashboardComponentsV2View />);

Expand Down
11 changes: 8 additions & 3 deletions src/routes/Dashboard/DashboardComponentsV2View.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -372,9 +372,14 @@ const ComponentCard = ({
</Badge>
)}
</InlineStack>
{publishedBy && !isDetailOpen && (
<Text size="xs" tone="subdued">
by {publishedBy}
{publishedBy && (
<Text
size="xs"
tone="subdued"
className={cn(isDetailOpen ? "pl-6" : undefined)}
title={`Published by ${publishedBy}`}
>
Published by {publishedBy}
</Text>
)}
{matchSummary && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ vi.mock(
ComponentMarkup: ({
component,
matchedFields,
source,
}: {
component: { name?: string };
matchedFields?: string[];
source?: { label: string };
}) => (
<li>
{component.name}
{matchedFields && <span>matched {matchedFields.join(",")}</span>}
{source && <span>source {source.label}</span>}
</li>
),
IONodeSidebarItem: () => <li>IO node</li>,
Expand Down Expand Up @@ -109,6 +112,25 @@ describe("ComponentSearchResults", () => {
expect(onSuggestedSearch).toHaveBeenCalledWith("csv");
});

it("passes source metadata through for result display", () => {
const results: ComponentSearchV2Result[] = [
{
reference: {
digest: "digest",
name: "Load CSV",
published_by: "pipeline-components@shopify.com",
},
source: { kind: "published", id: "published", label: "Published" },
},
];

render(
<ComponentSearchResults {...baseProps} query="csv" results={results} />,
);

expect(screen.getByText("source Published")).toBeInTheDocument();
});

it("passes matched fields through for result explanations", () => {
const results: ComponentSearchV2Result[] = [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ export function ComponentSearchResults({
matchedFields={result.matchedFields}
rerankScore={result.rerankScore}
rerankReason={result.rerankReason}
source={result.source}
/>
))}
</BlockStack>
Expand Down
Loading