Skip to content

Commit 561253b

Browse files
Valentin Grünerclaude
andcommitted
refactor(webapp): let one registry name a standing
The same five standings carried three sets of words: the badge said "Nothing to report yet", the practice node on the detail page said "No occasion yet", and the ring legend said "No opportunity" — and the legend sits directly above the badge it disagreed with. `webapp/AGENTS.md` puts the rule plainly: nothing but the registry may hold words, a colour or an icon for an enum value. The legend and the nodes now read their words from the standing registry, which gains a `shortLabel` for the one place five entries share a row. The nodes keep their own glyph and colour, which the registry does not describe, and `UNMEASURED` stays with them because it is not a standing the server reports but the client's word for a practice it sent none for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MAQxdMw579siMh1wXKEEh4
1 parent 7f320bd commit 561253b

2 files changed

Lines changed: 42 additions & 43 deletions

File tree

webapp/src/components/profile/PracticeGroupStandingRing.tsx

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,38 @@
11
import type { PracticeStanding } from "@/api/types.gen";
2+
import { PRACTICE_GROUP_STANDING_BADGE } from "./practice-group-standing-presentation";
23

34
type Standing = PracticeStanding["standing"];
45

6+
/**
7+
* Ring order is worst-first, so the segment a reader should act on starts at twelve o'clock. The
8+
* words come from the standing registry rather than from here — the legend this feeds sits directly
9+
* above the badge that names the same value.
10+
*/
11+
const SEGMENT_ORDER: readonly Standing[] = [
12+
"DEVELOPING",
13+
"MIXED",
14+
"STRENGTH",
15+
"NOT_OBSERVED",
16+
"NO_OPPORTUNITY",
17+
];
18+
19+
const SEGMENT_COLORS: Record<Standing, string> = {
20+
DEVELOPING: "text-destructive",
21+
MIXED: "text-warning",
22+
STRENGTH: "text-success",
23+
NOT_OBSERVED: "text-muted-foreground/75",
24+
NO_OPPORTUNITY: "text-muted-foreground/45",
25+
};
26+
527
const SEGMENTS: ReadonlyArray<{
628
standing: Standing;
729
colorClass: string;
830
label: string;
9-
}> = [
10-
{ standing: "DEVELOPING", colorClass: "text-destructive", label: "Needs attention" },
11-
{ standing: "MIXED", colorClass: "text-warning", label: "Mixed" },
12-
{ standing: "STRENGTH", colorClass: "text-success", label: "Going well" },
13-
{ standing: "NOT_OBSERVED", colorClass: "text-muted-foreground/75", label: "Not observed" },
14-
{ standing: "NO_OPPORTUNITY", colorClass: "text-muted-foreground/45", label: "No opportunity" },
15-
];
31+
}> = SEGMENT_ORDER.map((standing) => ({
32+
standing,
33+
colorClass: SEGMENT_COLORS[standing],
34+
label: PRACTICE_GROUP_STANDING_BADGE[standing].shortLabel,
35+
}));
1636

1737
export const STANDING_LEGEND = SEGMENTS;
1838

Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,53 @@
1-
import {
2-
GitPullRequestIcon,
3-
IssueOpenedIcon,
4-
type Icon as OcticonComponent,
5-
} from "@primer/octicons-react";
6-
import type { FeedbackSourceCount, PracticeGroupStanding } from "@/api/types.gen";
7-
import { type BrandIcon, SlackIcon } from "@/components/icons/brand";
1+
import type { PracticeGroupStanding } from "@/api/types.gen";
82

93
export type PracticeGroupStandingKey = PracticeGroupStanding["standing"];
104

11-
const VERDICT_STANDINGS = ["DEVELOPING", "MIXED", "STRENGTH"] as const;
12-
13-
export function isVerdictStanding(standing: PracticeGroupStandingKey): boolean {
14-
return (VERDICT_STANDINGS as readonly string[]).includes(standing);
15-
}
16-
5+
/**
6+
* The one place a standing gets words and a colour. The badge, the ring legend and the practice
7+
* nodes on the detail page all read from here — they used to carry three spellings, and the legend
8+
* sat directly above a badge that disagreed with it.
9+
*
10+
* `shortLabel` is for the ring legend, where five entries share one row and the badge's full phrase
11+
* does not fit; it says the same thing in fewer words and is never a different word.
12+
*/
1713
export const PRACTICE_GROUP_STANDING_BADGE: Record<
1814
PracticeGroupStandingKey,
1915
{
2016
label: string;
17+
shortLabel: string;
2118
variant: "destructive" | "warning" | "success" | "outline";
22-
ringClass?: string;
2319
explanation: string;
2420
}
2521
> = {
2622
DEVELOPING: {
2723
label: "Needs attention",
24+
shortLabel: "Needs attention",
2825
variant: "destructive",
29-
ringClass: "ring-destructive/40 dark:ring-destructive/50",
3026
explanation: "Recent reviews raised problems in this group.",
3127
},
3228
MIXED: {
3329
label: "Mixed feedback",
30+
shortLabel: "Mixed",
3431
variant: "warning",
35-
ringClass: "ring-warning/40 dark:ring-warning/50",
3632
explanation: "Recent reviews found both strengths and problems here.",
3733
},
3834
STRENGTH: {
3935
label: "Going well",
36+
shortLabel: "Going well",
4037
variant: "success",
41-
ringClass: "ring-success/40 dark:ring-success/50",
4238
explanation: "Nothing needs your attention here right now.",
4339
},
4440
NOT_OBSERVED: {
4541
label: "Not observed yet",
42+
shortLabel: "Not observed",
4643
variant: "outline",
4744
explanation: "These practices have not been observed in your reviewed work yet.",
4845
},
4946
NO_OPPORTUNITY: {
5047
label: "Nothing to report yet",
48+
shortLabel: "Nothing to report",
5149
variant: "outline",
5250
explanation:
5351
"Your recent work was reviewed, but it either offered no opportunity for these practices or raised nothing worth mentioning.",
5452
},
5553
};
56-
57-
export const PRACTICE_GROUP_SOURCE_META: Partial<
58-
Record<
59-
FeedbackSourceCount["workKind"],
60-
{ Icon: OcticonComponent | BrandIcon; singular: string; plural: string }
61-
>
62-
> = {
63-
"scm.pull_request": {
64-
Icon: GitPullRequestIcon,
65-
singular: "pull request",
66-
plural: "pull requests",
67-
},
68-
"scm.issue": { Icon: IssueOpenedIcon, singular: "issue", plural: "issues" },
69-
"chat.conversation_thread": {
70-
Icon: SlackIcon,
71-
singular: "Slack conversation",
72-
plural: "Slack conversations",
73-
},
74-
};

0 commit comments

Comments
 (0)