feat: link group names to group page in agents limit settings (#24212)

This commit is contained in:
Kayla はな
2026-04-14 12:22:14 -06:00
committed by GitHub
parent 20b953a99d
commit 214351ebe1
4 changed files with 80 additions and 51 deletions
@@ -415,6 +415,7 @@ export const AgentSettingsSpendPageView: FC<
<GroupLimitsSection
hideHeader
groupOverrides={groupOverrides}
groupOrganizationNames={groupCtrl.groupOrganizationNames}
showGroupForm={groupCtrl.showGroupForm}
onShowGroupFormChange={
groupCtrl.handleShowGroupFormChange
@@ -72,6 +72,11 @@ const meta: Meta<typeof GroupLimitsSection> = {
component: GroupLimitsSection,
args: {
groupOverrides: mockGroupOverrides,
groupOrganizationNames: {
"group-1": "acme",
"group-2": "acme",
"group-4": "acme",
},
showGroupForm: false,
onShowGroupFormChange: fn(),
selectedGroup: null,
@@ -1,7 +1,8 @@
import { Check } from "lucide-react";
import { type FC, useId, useState } from "react";
import { Link } from "react-router";
import { getErrorMessage } from "#/api/errors";
import type { Group } from "#/api/typesGenerated";
import type { ChatUsageLimitGroupOverride, Group } from "#/api/typesGenerated";
import { Autocomplete } from "#/components/Autocomplete/Autocomplete";
import { AvatarData } from "#/components/Avatar/AvatarData";
import { Button } from "#/components/Button/Button";
@@ -26,14 +27,9 @@ import { SectionHeader } from "../SectionHeader";
interface GroupLimitsSectionProps {
hideHeader?: boolean;
groupOverrides: ReadonlyArray<{
group_id: string;
group_display_name: string;
group_name: string;
group_avatar_url: string;
member_count: number;
spend_limit_micros: number | null;
}>;
groupOverrides: readonly ChatUsageLimitGroupOverride[];
/** Maps group_id → organization_name for building links to the group page. */
groupOrganizationNames?: Record<string, string>;
showGroupForm: boolean;
onShowGroupFormChange: (show: boolean) => void;
selectedGroup: Group | null;
@@ -65,6 +61,7 @@ interface GroupLimitsSectionProps {
export const GroupLimitsSection: FC<GroupLimitsSectionProps> = ({
hideHeader,
groupOverrides,
groupOrganizationNames,
showGroupForm,
onShowGroupFormChange,
selectedGroup,
@@ -111,48 +108,68 @@ export const GroupLimitsSection: FC<GroupLimitsSectionProps> = ({
</TableRow>
</TableHeader>
<TableBody>
{groupOverrides.map((override) => (
<TableRow key={override.group_id}>
<TableCell>
<AvatarData
title={override.group_display_name || override.group_name}
subtitle={override.group_name}
src={override.group_avatar_url}
imgFallbackText={override.group_name}
/>
</TableCell>
<TableCell>{override.member_count}</TableCell>
<TableCell>
{override.spend_limit_micros !== null
? formatCostMicros(override.spend_limit_micros)
: "Unlimited"}
</TableCell>
<TableCell>
<div className="flex gap-2">
<Button
variant="outline"
size="sm"
type="button"
onClick={() => onEditGroupOverride(override)}
disabled={deletePending || upsertPending}
>
Edit
</Button>
<Button
variant="outline"
size="sm"
type="button"
onClick={() =>
setPendingDeleteGroupId(override.group_id)
}
disabled={deletePending || upsertPending || isEditing}
>
Delete
</Button>
</div>
</TableCell>
</TableRow>
))}
{groupOverrides.map((override) => {
const orgName = groupOrganizationNames?.[override.group_id];
const groupLink = orgName
? `/organizations/${orgName}/groups/${override.group_name}`
: undefined;
const avatar = (
<AvatarData
title={override.group_display_name || override.group_name}
subtitle={override.group_name}
src={override.group_avatar_url}
imgFallbackText={override.group_name}
/>
);
return (
<TableRow key={override.group_id}>
<TableCell>
{groupLink ? (
<Link
to={groupLink}
className="flex rounded-md no-underline text-inherit -m-1.5 p-1.5 transition-colors hover:bg-surface-secondary"
>
{avatar}
</Link>
) : (
avatar
)}
</TableCell>
<TableCell>{override.member_count}</TableCell>
<TableCell>
{override.spend_limit_micros !== null
? formatCostMicros(override.spend_limit_micros)
: "Unlimited"}
</TableCell>
<TableCell>
<div className="flex gap-2">
<Button
variant="outline"
size="sm"
type="button"
onClick={() => onEditGroupOverride(override)}
disabled={deletePending || upsertPending}
>
Edit
</Button>
<Button
variant="outline"
size="sm"
type="button"
onClick={() =>
setPendingDeleteGroupId(override.group_id)
}
disabled={deletePending || upsertPending || isEditing}
>
Delete
</Button>
</div>
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
) : (
@@ -37,6 +37,7 @@ type GroupOverrideChildProps = {
existingGroupIds: Set<string>;
availableGroups: Group[];
groupAutocompleteNoOptionsText: string;
groupOrganizationNames: Record<string, string>;
};
interface GroupOverrideControllerProps {
@@ -67,6 +68,10 @@ export const GroupOverrideController: FC<GroupOverrideControllerProps> = ({
// Derived values.
const existingGroupIds = new Set(groupOverrides.map((g) => g.group_id));
const availableGroups = groups.filter((g) => !existingGroupIds.has(g.id));
const groupOrganizationNames: Record<string, string> = {};
for (const g of groups) {
groupOrganizationNames[g.id] = g.organization_name;
}
const groupAutocompleteNoOptionsText = isLoadingGroups
? "Loading groups..."
: groups.length === 0
@@ -137,5 +142,6 @@ export const GroupOverrideController: FC<GroupOverrideControllerProps> = ({
existingGroupIds,
availableGroups,
groupAutocompleteNoOptionsText,
groupOrganizationNames,
});
};