Render each external object as a property row

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-06-23 00:35:05 +00:00
1 parent 4394fcd00d
commit f6ba07fe1c
2 files changed
+54 -27

No files matched your search

+25 -1
View File
@@ -1798,7 +1798,7 @@ describe("IssueProperties", () => {
act(() => root.unmount());
});
it("uses external object display metadata for the properties row label", async () => {
it("renders each external object as its own properties row using display metadata", async () => {
const root = renderProperties(container, {
issue: createIssue(),
childIssues: [],
@@ -1827,12 +1827,36 @@ describe("IssueProperties", () => {
sourceLabels: ["Description"],
},
},
{
mentionCount: 1,
sourceLabels: ["Comment"],
pill: {
providerKey: "github",
objectType: "issue",
displayKey: "Github Issue",
iconKey: "github",
statusCategory: "open",
statusIconKey: "circle-dot",
statusLabel: "Open",
liveness: "fresh",
displayTitle: "acme/web#12: Follow-up",
url: "https://github.com/acme/web/issues/12",
},
group: {
object: null,
mentions: [],
mentionCount: 1,
sourceLabels: ["Comment"],
},
},
],
});
await flush();
expect(container.textContent).toContain("Github Pull Request");
expect(container.textContent).toContain("Github Issue");
expect(container.textContent).toContain("Merged");
expect(container.textContent).toContain("Open");
expect(container.textContent).not.toContain("External objects");
const label = Array.from(container.querySelectorAll("span"))
.find((span) => span.textContent === "Github Pull Request");
+29 -26
View File
@@ -37,7 +37,12 @@ import { IssueReferencePill } from "./IssueReferencePill";
import { formatDate, formatDateTime, cn, projectUrl } from "../lib/utils";
import { ExternalObjectPill } from "./ExternalObjectPill";
import type { IssueExternalObjectGroup } from "../hooks/useIssueExternalObjects";
import { externalObjectIconForKey, externalObjectToneSeverity } from "../lib/external-objects";
import {
externalObjectIconForKey,
externalObjectProviderLabel,
externalObjectToneSeverity,
externalObjectTypeLabel,
} from "../lib/external-objects";
import { timeAgo } from "../lib/timeAgo";
import { Button } from "@/components/ui/button";
import { ToggleSwitch } from "@/components/ui/toggle-switch";
@@ -190,19 +195,11 @@ function sortExternalObjectGroups(groups: IssueExternalObjectGroup[]) {
});
}
function externalObjectRowLabel(groups: IssueExternalObjectGroup[] | undefined): React.ReactNode {
if (!groups || groups.length === 0) return "External objects";
const sorted = sortExternalObjectGroups(groups);
const primary = sorted[0]?.pill;
const displayKey = primary?.displayKey?.trim();
if (!primary || !displayKey) return "External objects";
const iconKey = primary.iconKey ?? null;
const allSameDisplay = sorted.every(({ pill }) =>
(pill.displayKey?.trim() ?? "") === displayKey && (pill.iconKey ?? null) === iconKey,
);
if (!allSameDisplay) return "External objects";
const Icon = externalObjectIconForKey(iconKey);
function externalObjectRowLabel(group: IssueExternalObjectGroup): React.ReactNode {
const { pill } = group;
const displayKey = pill.displayKey?.trim()
|| `${externalObjectProviderLabel(pill.providerKey)} ${externalObjectTypeLabel(pill.objectType)}`;
const Icon = externalObjectIconForKey(pill.iconKey);
return (
<span className="inline-flex min-w-0 items-center gap-1">
{Icon ? <Icon aria-hidden="true" className="h-3 w-3 shrink-0" /> : null}
@@ -2239,19 +2236,25 @@ export function IssueProperties({
<span className="h-4 w-24 animate-pulse rounded bg-muted/40" />
</PropertyRow>
) : externalObjects && externalObjects.length > 0 ? (
<PropertyRow label={externalObjectRowLabel(externalObjects)} labelClassName="w-32">
<div className="flex flex-wrap items-center gap-1.5">
{sortExternalObjectGroups(externalObjects)
.map(({ pill, mentionCount, sourceLabels, group }) => (
<ExternalObjectPill
<>
{sortExternalObjectGroups(externalObjects)
.map((externalObject) => {
const { pill, mentionCount, sourceLabels, group } = externalObject;
return (
<PropertyRow
key={group.object?.id ?? `${pill.providerKey}:${pill.objectType}:${pill.url ?? "anon"}`}
object={pill}
sourceCount={mentionCount}
sourceSummary={sourceLabels.join(", ")}
/>
))}
</div>
</PropertyRow>
label={externalObjectRowLabel(externalObject)}
labelClassName="w-32"
>
<ExternalObjectPill
object={pill}
sourceCount={mentionCount}
sourceSummary={sourceLabels.join(", ")}
/>
</PropertyRow>
);
})}
</>
) : null}
<PropertyPicker