1import type { EnvironmentId, EnvironmentMachineKind } from "@t3tools/contracts";
2
3import type { SidebarProjectSnapshot } from "~/sidebarProjectGrouping";
4import { EnvironmentMachineIcon } from "./EnvironmentMachineIcon";
5import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip";
6
7/**
8 * Machine icon for a project picker row whose group has a member on another
9 * environment, with the environment names in a tooltip. Projects that only
10 * live on this device render nothing, the rule thread rows use for their
11 * machine icon. Callers
12 * render it only while the catalog spans environments (see
13 * projectGroupsSpanEnvironments), so single-machine users see no change.
14 */
15export function ProjectEnvironmentBadge(props: {
16 readonly group: Pick<SidebarProjectSnapshot, "memberProjects">;
17 readonly primaryEnvironmentId: EnvironmentId | null;
18 readonly machineByEnvironmentId: ReadonlyMap<EnvironmentId, EnvironmentMachineKind>;
19}) {
20 // Member order follows registration order and can differ between sessions,
21 // so sort by label to keep the icon and tooltip stable.
22 const remoteMembers = props.group.memberProjects
23 .filter((member) => member.environmentId !== props.primaryEnvironmentId)
24 .map((member) => ({ ...member, environmentLabel: member.environmentLabel ?? "Remote" }))
25 .sort((a, b) => a.environmentLabel.localeCompare(b.environmentLabel));
26 const first = remoteMembers[0];
27 if (!first) return null;
28 const labels = remoteMembers
29 .map((member) => member.environmentLabel)
30 .filter((label, index, all) => all.indexOf(label) === index)
31 .join(", ");
32 const alsoHere = remoteMembers.length < props.group.memberProjects.length;
33 const description = `${alsoHere ? "Also on" : "On"} ${labels}`;
34 return (
35 <Tooltip>
36 <TooltipTrigger
37 render={
38 <span
39 role="img"
40 aria-label={description}
41 className="ml-auto inline-flex shrink-0 items-center text-muted-foreground"
42 />
43 }
44 >
45 <EnvironmentMachineIcon
46 aria-hidden
47 kind={props.machineByEnvironmentId.get(first.environmentId) ?? "server"}
48 className="size-3.5"
49 />
50 </TooltipTrigger>
51 <TooltipPopup side="top">{description}</TooltipPopup>
52 </Tooltip>
53 );
54}