This is an automated email from the ASF dual-hosted git repository. hsluoyz pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/casbin-gateway.git
commit 04985168cc407f101538ce9144733baba89a0c38 Author: Yang Luo <[email protected]> AuthorDate: Fri Sep 4 15:38:32 2026 +0800 refactor(agents): collapse card instances into one row of chips --- web/src/components/AgentInstances.tsx | 107 +++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 28 deletions(-) diff --git a/web/src/components/AgentInstances.tsx b/web/src/components/AgentInstances.tsx index 34836f5..87ea9a2 100644 --- a/web/src/components/AgentInstances.tsx +++ b/web/src/components/AgentInstances.tsx @@ -13,7 +13,17 @@ // limitations under the License. import * as React from "react"; -import {LogIn, Play, Plus, RefreshCw, Square, Trash2, UserPlus, Users} from "lucide-react"; +import { + LoaderCircle, + LogIn, + Play, + Plus, + RefreshCw, + Square, + Trash2, + UserPlus, + Users, +} from "lucide-react"; import i18next from "i18next"; import {accountLabel} from "@/components/AgentGridCard"; @@ -305,11 +315,62 @@ export function AgentInstances({agent, enabled = true}: {agent: Agent; enabled?: ); } +/** One copy as a chip: a dot for whether it runs, its name, and a click to flip that. */ +function InstanceChip({ + instance, + busy, + onToggle, +}: { + instance: AgentInstance; + busy: boolean; + onToggle: (instance: AgentInstance) => void; +}) { + const action = i18next.t(instance.running ? "agent:Stop" : "agent:Start"); + const name = instanceLabel(instance); + const blocked = !instance.running && !instance.canStart; + const who = instance.account ? instance.account.email || "" : ""; + + return ( + <SimpleTooltip + title={ + blocked + ? [name, instance.detail].filter(Boolean).join(" · ") + : [`${action} ${name}`, who].filter(Boolean).join(" · ") + } + > + <span> + <button + type="button" + disabled={blocked || busy} + aria-label={`${action}: ${name}`} + className={cn( + "bg-muted/50 hover:bg-muted flex max-w-[8rem] items-center gap-1 rounded-full border px-1.5 py-0.5 text-[11px] transition-colors disabled:opacity-50", + instance.running && "border-success/40", + )} + onClick={() => onToggle(instance)} + > + {busy ? ( + <LoaderCircle className="size-2.5 shrink-0 animate-spin" /> + ) : ( + <span + className={cn( + "size-1.5 shrink-0 rounded-full", + instance.running ? "bg-success" : "bg-muted-foreground/40", + )} + /> + )} + <span className="truncate">{name}</span> + </button> + </span> + </SimpleTooltip> + ); +} + /** - * The instances of one agent as a grid card shows them: an icon for the section, - * one line per copy with the account it is signed in to, and the control that - * starts or stops it. The card has no room for words about any of it, so the - * names live in the tooltips and the renaming on the detail page. + * The instances of one agent as a grid card shows them: one wrapping row of + * chips, each a copy that a click starts or stops. The card has no room for + * words about any of it, so the accounts live in the tooltips and the renaming + * on the detail page. */ export function AgentCardInstances({ agent, @@ -324,34 +385,24 @@ export function AgentCardInstances({ const instances = instancesOf(controls.instances, agent); return ( - <div className="space-y-1"> - <div className="flex items-center justify-between gap-2"> - <span className="text-muted-foreground flex items-center gap-1 text-[11px]"> + <div className="flex flex-wrap items-center gap-1"> + <SimpleTooltip title={i18next.t("agent:Instances hint")}> + <span className="text-muted-foreground mr-0.5 flex items-center gap-1 text-[11px]"> <Users className="size-3" /> - {i18next.t("agent:Instances")} - {instances.length > 0 ? ` · ${instances.length}` : null} + {instances.length > 0 ? instances.length : i18next.t("agent:Instances")} </span> - <AddInstanceButton agent={agent} controls={controls} compact /> - </div> + </SimpleTooltip> {instances.map(instance => ( - <div key={instance.name} className="flex items-center gap-2"> - <span - className={cn( - "size-1.5 shrink-0 rounded-full", - instance.running ? "bg-success" : "bg-muted-foreground/40", - )} - /> - <SimpleTooltip title={instance.account ? instance.account.email : instance.dataDir}> - <span className="min-w-0 flex-1 truncate text-[11px]">{instanceLabel(instance)}</span> - </SimpleTooltip> - <InstanceRunButton - instance={instance} - busy={controls.busyName === instance.name} - onToggle={controls.toggleRunning} - /> - </div> + <InstanceChip + key={instance.name} + instance={instance} + busy={controls.busyName === instance.name} + onToggle={controls.toggleRunning} + /> ))} + + <AddInstanceButton agent={agent} controls={controls} compact /> </div> ); } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
