mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
[a360b6e3] Redesign A2A page with conversation-first layout and agent identity (#401)
* [54b94e44] A2A page: filter controls + agent identity consistency (#387) (#392) * [54b94e44] feat(a2a): add filter bar and unify agent avatars + pulse across views Adds a status (active/all) + free-text search filter bar above the A2A switchboard/list content, backed by a shared a2a-filter-utils module so both A2ASwitchboard's pairs and A2AConversationList's conversations narrow identically. Extracts A2APairCard's pulse-flash state into a reusable usePulseFlash hook and exports its PairAvatar so the classic conversation list now renders the same two-participant avatar and emerald pulse-flash affordance the switchboard already had. * [54b94e44] docs(a2a): add comprehensive filtering and avatar documentation Documented the new A2A filter bar, filter utilities, pulse-flash hook, and conversation list API changes. Includes examples, testing guidance, and migration notes for the pulses prop requirement. --------- Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech> Co-authored-by: Frontend Documenter <fe-doc@roboco.tech> * [54417f0c] UX/UI: design A2A conversation-first layout and agent identity (#399) * [f612a5ab] Add conversation-first layout, agent identity, and live-stream affordance spec (#384) Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech> * [7ed2ef71] docs(ux_ui): add filter-control design spec for A2A conversations (#383) Co-authored-by: UX/UI Developer 2 <ux-dev-2@roboco.tech> --------- Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech> Co-authored-by: UX/UI Developer 2 <ux-dev-2@roboco.tech> * [f563bbc9] Implement conversation-first A2A layout, identity colors, connection states, transcript motion, and empty/error states (#423) (#427) * [f563bbc9] feat(a2a): conversation-first layout, team-color identity, connection states, transcript motion, empty/error states Implements docs/ux_ui/design/02-conversation-first-layout-agent-identity-live-stream.md: - xl:+ collapsible Context pane (identity cards, linked-task summary, no-task hint), persisted via the existing zustand ui-store - getAgentTeamColor + TEAM_COLOR_CLASSES in agent-utils.ts, applied to PairAvatar, the transcript row avatar, and the context pane - A2AConnectionBadge/A2AConnectionBanner rendering all four ConnectionState values distinctly with a motion-reduce-guarded pulsing dot and a dismissable reconnecting/disconnected strip - A2ATranscript: transform/opacity-only new-row entrance transition, scrolled-up "New messages" pill, split hasSelection/empty/error states with a scoped Retry - Unit tests for every new pure helper and component * [f563bbc9] docs(a2a): conversation-first layout, team-color identity, connection states, transcript motion, empty/error states Document the new conversation-first A2A layout features: - Agent team-color system (getAgentTeamColor, TEAM_COLOR_CLASSES) for six cell buckets - A2AContextPane component with identity cards, linked task summary, no-task hint - Connection state rendering (A2AConnectionBadge, A2AConnectionBanner) for all four ConnectionState values - Transcript entrance motion with transform/opacity-only transitions and prefers-reduced-motion guards - Split empty/error states (no selection, no messages, fetch error with scoped retry) - Page-level integration with xl:+ responsive grid layout Includes component API, usage examples, testing guidance, accessibility notes, and design rationale. --------- Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech> Co-authored-by: Frontend Documenter <fe-doc@roboco.tech> * [478f027c] Implement A2A conversations filter control per conversations-filter-control.md (#445) (#448) * [478f027c] feat(a2a): add multi-dimension Popover filter panel for A2A conversations Replace the free-text search + active/all toggle with the Popover-triggered filter control from conversations-filter-control.md: Agent multi-select checkboxes, a Task id-fragment input with a "No linked task" toggle, Status toggle buttons, and a date range, plus an active-filter chip row and Clear all. Filtering applies to both the switchboard (Agent only) and conversation list (all four dimensions) per the design doc's per-view rules. * [478f027c] docs(a2a): add comprehensive filter-control guide covering component API, filter dimensions, and per-view rules Documents A2AFilterBar component and filter utilities with: - Component API and props - All 4 filter dimensions (Agent, Task, Status, Date range) - Per-view rules (Switchboard vs List) - Usage examples and parent setup - Filter logic and match predicates - Testing guide and accessibility notes - Design notes on client-side filtering limitation - Links to related components and the design spec Helps developers understand, use, and maintain the A2A conversations filter control without needing to read the design doc or component source. --------- Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech> Co-authored-by: Frontend Documenter <fe-doc@roboco.tech> --------- Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech> Co-authored-by: Frontend Documenter <fe-doc@roboco.tech> Co-authored-by: UX/UI Developer 1 <ux-dev-1@roboco.tech> Co-authored-by: UX/UI Developer 2 <ux-dev-2@roboco.tech> Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech> Co-authored-by: Renn F <rennf93@users.noreply.github.com>
This commit is contained in:
co-authored by
Frontend Developer 1
Frontend Documenter
UX/UI Developer 1
UX/UI Developer 2
Frontend Developer 2
Renn F
parent
58354a364e
commit
6e57066bd6
@@ -3,8 +3,11 @@ import {
|
||||
resolveToSlug,
|
||||
getAgentDisplayName,
|
||||
getAgentInitials,
|
||||
getAgentTeamColor,
|
||||
isKnownAgent,
|
||||
registerAgentRoster,
|
||||
TEAM_COLOR_CLASSES,
|
||||
type AgentTeamColor,
|
||||
} from "@/lib/agent-utils";
|
||||
|
||||
// Canonical UUIDs from the backend roster (roboco/foundation/identity.py).
|
||||
@@ -87,3 +90,51 @@ describe("agent-utils existing roster (regression guard)", () => {
|
||||
expect(getAgentDisplayName(null)).toBe("Unassigned");
|
||||
});
|
||||
});
|
||||
|
||||
describe("getAgentTeamColor (design doc §2 — six buckets)", () => {
|
||||
it.each([
|
||||
["be-dev-1", "backend"],
|
||||
["be-pm", "backend"],
|
||||
["fe-dev-2", "frontend"],
|
||||
["fe-qa", "frontend"],
|
||||
["ux-dev-1", "ux_ui"],
|
||||
["ux-doc", "ux_ui"],
|
||||
["main-pm", "board"],
|
||||
["product-owner", "board"],
|
||||
["head-marketing", "board"],
|
||||
["auditor", "board"],
|
||||
["ceo", "ceo"],
|
||||
["CEO", "ceo"],
|
||||
["intake-1", "system"],
|
||||
["secretary-1", "system"],
|
||||
["pr-reviewer-1", "system"],
|
||||
] satisfies [string, AgentTeamColor][])(
|
||||
"buckets %s as %s",
|
||||
(slug, expected) => {
|
||||
expect(getAgentTeamColor(slug)).toBe(expected);
|
||||
},
|
||||
);
|
||||
|
||||
it("resolves a UUID to its team bucket via the slug map", () => {
|
||||
expect(getAgentTeamColor(BE_DEV_1_UUID)).toBe("backend");
|
||||
});
|
||||
|
||||
it("falls back to system for an unrecognized id, never throwing", () => {
|
||||
expect(getAgentTeamColor("some-unknown-agent")).toBe("system");
|
||||
expect(getAgentTeamColor(null)).toBe("system");
|
||||
});
|
||||
|
||||
it("gives every bucket a class string with no new color families beyond the six", () => {
|
||||
const buckets: AgentTeamColor[] = [
|
||||
"backend",
|
||||
"frontend",
|
||||
"ux_ui",
|
||||
"board",
|
||||
"ceo",
|
||||
"system",
|
||||
];
|
||||
for (const bucket of buckets) {
|
||||
expect(TEAM_COLOR_CLASSES[bucket]).toBeTruthy();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -229,3 +229,59 @@ export function isKnownAgent(agentId: string | null | undefined): boolean {
|
||||
if (!agentId) return false;
|
||||
return liveByKey.has(agentId) || agentId in AGENT_NAMES;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Team-color identity (design doc:
|
||||
// docs/ux_ui/design/02-conversation-first-layout-agent-identity-live-stream.md
|
||||
// §2). Color is scoped to the CELL an agent belongs to, not a per-agent hue —
|
||||
// legible at 22-agent scale and needs no new bucket when a cell grows.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export type AgentTeamColor =
|
||||
| "backend"
|
||||
| "frontend"
|
||||
| "ux_ui"
|
||||
| "board"
|
||||
| "ceo"
|
||||
| "system";
|
||||
|
||||
/** Every value here is an existing Tailwind color family already used
|
||||
* elsewhere in the codebase at the same `/15` bg + `/40` border weight
|
||||
* (`a2a-pair-card.tsx`'s pulse treatment) — no new tokens introduced. */
|
||||
export const TEAM_COLOR_CLASSES: Record<AgentTeamColor, string> = {
|
||||
backend: "bg-blue-500/15 border-blue-500/40 text-blue-700 dark:text-blue-400",
|
||||
frontend:
|
||||
"bg-violet-500/15 border-violet-500/40 text-violet-700 dark:text-violet-400",
|
||||
ux_ui:
|
||||
"bg-fuchsia-500/15 border-fuchsia-500/40 text-fuchsia-700 dark:text-fuchsia-400",
|
||||
board:
|
||||
"bg-amber-500/15 border-amber-500/40 text-amber-700 dark:text-amber-400",
|
||||
// The one human gets the app's own accent, not a team bucket.
|
||||
ceo: "bg-primary/15 border-primary/40 text-primary",
|
||||
system:
|
||||
"bg-slate-500/15 border-slate-500/40 text-slate-700 dark:text-slate-400",
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolve an agent id (slug or UUID) to its cell color bucket, derived from
|
||||
* the slug prefix. Unknown/unresolved slugs fall back to `system` — a color
|
||||
* layer is a scanning aid, never something that should throw on a stray id.
|
||||
*/
|
||||
export function getAgentTeamColor(
|
||||
agentId: string | null | undefined,
|
||||
): AgentTeamColor {
|
||||
const slug = resolveToSlug(agentId);
|
||||
if (slug === "ceo" || slug === "CEO") return "ceo";
|
||||
if (slug.startsWith("be-")) return "backend";
|
||||
if (slug.startsWith("fe-")) return "frontend";
|
||||
if (slug.startsWith("ux-")) return "ux_ui";
|
||||
if (
|
||||
slug === "main-pm" ||
|
||||
slug === "product-owner" ||
|
||||
slug === "head-marketing" ||
|
||||
slug === "auditor"
|
||||
) {
|
||||
return "board";
|
||||
}
|
||||
return "system";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user