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
28 changes: 2 additions & 26 deletions src/features/comparison/components/result-dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { InsightsList } from "./insights-list";
import { ScoreCard } from "@/components/cards";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import type { UserResult } from "@/features/developer";
import { getSignalMetricEntries, type UserResult } from "@/features/developer";
import { useTranslation } from "@/components/providers/language-provider";
import { formatComparisonToMarkdown } from "../format-comparison-to-markdown";
import type { CompareInsights, CompareWinner } from "../types";
Expand Down Expand Up @@ -274,31 +274,7 @@ export function ResultDashboard({
if (!user.signals) return null;

const signalEntries: Array<{ label: string; value: string | number }> = [
{ label: t("signals.reposAnalyzed"), value: user.signals.reposAnalyzed ?? "-" },
{
label: t("signals.pullRequestsAnalyzed"),
value: user.signals.pullRequestsAnalyzed ?? "-",
},
{ label: t("signals.mergedExternalPRs"), value: user.signals.mergedExternalPRs ?? "-" },
{ label: t("signals.ownRepoPRsIgnored"), value: user.signals.ownRepoPRsIgnored ?? "-" },
{ label: t("signals.unmergedPRsIgnored"), value: user.signals.unmergedPRsIgnored ?? "-" },
{
label: t("signals.uniqueExternalPRRepos"),
value: user.signals.uniqueExternalPRRepos ?? "-",
},
{ label: t("signals.issuesAnalyzed"), value: user.signals.issuesAnalyzed ?? "-" },
{
label: t("signals.externalIssuesCounted"),
value: user.signals.externalIssuesCounted ?? "-",
},
{
label: t("signals.discussionsAnalyzed"),
value: user.signals.discussionsAnalyzed ?? "-",
},
{
label: t("signals.externalDiscussionsCounted"),
value: user.signals.externalDiscussionsCounted ?? "-",
},
...getSignalMetricEntries(user.signals, t),
{
label: t("signals.reposWithLanguageData"),
value: user.signals.reposWithLanguageData ?? "-",
Expand Down
43 changes: 2 additions & 41 deletions src/features/developer/components/user-profile-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { useTranslation } from "@/components/providers/language-provider";
import { getCountryCode, detectCountry } from "@/lib/geo";
import countriesData from "@/data/countries.json";
import type { UserResult } from "../types";
import { getSignalMetricEntries } from "../signal-metrics";

type CountryInfo = {
slug: string;
Expand Down Expand Up @@ -121,47 +122,7 @@ export function UserProfileClient({ user, location, countryParam }: Props) {
const handleCopyLink = () => copy(window.location.href);

// Signal stats entries for transparency
const signalEntries = user.signals
? [
{ label: t("signals.reposAnalyzed"), value: user.signals.reposAnalyzed ?? "-" },
{
label: t("signals.pullRequestsAnalyzed"),
value: user.signals.pullRequestsAnalyzed ?? "-",
},
{
label: t("signals.mergedExternalPRs"),
value: user.signals.mergedExternalPRs ?? "-",
},
{
label: t("signals.ownRepoPRsIgnored"),
value: user.signals.ownRepoPRsIgnored ?? "-",
},
{
label: t("signals.unmergedPRsIgnored"),
value: user.signals.unmergedPRsIgnored ?? "-",
},
{
label: t("signals.uniqueExternalPRRepos"),
value: user.signals.uniqueExternalPRRepos ?? "-",
},
{
label: t("signals.issuesAnalyzed"),
value: user.signals.issuesAnalyzed ?? "-",
},
{
label: t("signals.externalIssuesCounted"),
value: user.signals.externalIssuesCounted ?? "-",
},
{
label: t("signals.discussionsAnalyzed"),
value: user.signals.discussionsAnalyzed ?? "-",
},
{
label: t("signals.externalDiscussionsCounted"),
value: user.signals.externalDiscussionsCounted ?? "-",
},
]
: [];
const signalEntries = getSignalMetricEntries(user.signals, t);

const totalRawSum = Math.max(
1,
Expand Down
1 change: 1 addition & 0 deletions src/features/developer/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./types";
export * from "./components";
export { getSignalMetricEntries } from "./signal-metrics";
27 changes: 27 additions & 0 deletions src/features/developer/signal-metrics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { I18nContextValue } from "@/lib/i18n";
import type { ScoringSignals } from "@/features/scoring";

const SIGNAL_METRICS = [
"reposAnalyzed",
"pullRequestsAnalyzed",
"mergedExternalPRs",
"ownRepoPRsIgnored",
"unmergedPRsIgnored",
"uniqueExternalPRRepos",
"issuesAnalyzed",
"externalIssuesCounted",
"discussionsAnalyzed",
"externalDiscussionsCounted",
] as const satisfies readonly (keyof ScoringSignals)[];

export function getSignalMetricEntries(
signals: ScoringSignals | undefined,
t: I18nContextValue["t"],
): Array<{ label: string; value: number | string }> {
if (!signals) return [];

return SIGNAL_METRICS.map((metric) => ({
label: t(`signals.${metric}`),
value: signals[metric] ?? "-",
}));
}
50 changes: 50 additions & 0 deletions src/features/developer/tests/signal-metrics.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { describe, expect, it } from "vitest";
import type { ScoringSignals } from "@/features/scoring";
import en from "@/locales/en.json";
import ar from "@/locales/ar.json";
import { getSignalMetricEntries } from "../signal-metrics";

const signals: ScoringSignals = {
reposAnalyzed: 0,
pullRequestsAnalyzed: 2,
mergedExternalPRs: 3,
ownRepoPRsIgnored: 4,
unmergedPRsIgnored: 5,
uniqueExternalPRRepos: 6,
issuesAnalyzed: 7,
externalIssuesCounted: 8,
discussionsAnalyzed: 9,
externalDiscussionsCounted: 10,
reposWithLanguageData: 11,
};

describe("getSignalMetricEntries", () => {
it.each([en, ar])("preserves metric order, zeroes and translated labels", (messages) => {
const entries = getSignalMetricEntries(signals, (key) => messages[key as keyof typeof en]);

expect(entries).toEqual([
{ label: messages["signals.reposAnalyzed"], value: 0 },
{ label: messages["signals.pullRequestsAnalyzed"], value: 2 },
{ label: messages["signals.mergedExternalPRs"], value: 3 },
{ label: messages["signals.ownRepoPRsIgnored"], value: 4 },
{ label: messages["signals.unmergedPRsIgnored"], value: 5 },
{ label: messages["signals.uniqueExternalPRRepos"], value: 6 },
{ label: messages["signals.issuesAnalyzed"], value: 7 },
{ label: messages["signals.externalIssuesCounted"], value: 8 },
{ label: messages["signals.discussionsAnalyzed"], value: 9 },
{ label: messages["signals.externalDiscussionsCounted"], value: 10 },
]);
});

it("returns no entries when signals are absent", () => {
expect(getSignalMetricEntries(undefined, (key) => key)).toEqual([]);
});

it("retains the fallback for incomplete cached signals without mutating input", () => {
const incomplete = Object.freeze({ reposAnalyzed: 0 }) as ScoringSignals;
const entries = getSignalMetricEntries(incomplete, (key) => key);
expect(entries[0].value).toBe(0);
expect(entries.slice(1).every((entry) => entry.value === "-")).toBe(true);
expect(incomplete).toEqual({ reposAnalyzed: 0 });
});
});
Loading