mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 02:06:43 +00:00
fix(ui): give roster rows their avatar-text gap and add presence mock fixtures (#111689)
* fix(ui): add avatar-text gap in roster menu and presence mock fixtures * refactor(ui): keep presence snapshot helper out of the connect auth hunk
This commit is contained in:
@@ -1128,6 +1128,13 @@ async function createChatPickerScenario(): Promise<ControlUiMockGatewayScenario>
|
||||
"sessions.files.set",
|
||||
],
|
||||
historyMessages: buildScrollableChatHistory(baseTime),
|
||||
// Lights up the footer facepile and who's-online roster; the email-only
|
||||
// entry keeps the roster's no-display-name row exercised.
|
||||
presenceUsers: [
|
||||
{ self: true, id: "presence-riley", name: "Riley", email: "riley@example.com" },
|
||||
{ id: "presence-colin", name: "Colin", email: "colin@example.com" },
|
||||
{ id: "presence-patricia", email: "patricia.erichsen@example.com" },
|
||||
],
|
||||
methodResponses: {
|
||||
...buildBackgroundTasksMock(baseTime),
|
||||
// config.set/config.apply are served statefully by the mock gateway
|
||||
|
||||
@@ -2009,7 +2009,7 @@ html.openclaw-native-macos
|
||||
Awesome's checkmark gutter and item metrics so title, avatars, and text
|
||||
share one left edge with the rest of the app's menus. */
|
||||
.presence-roster-menu__item {
|
||||
padding: 5px 8px;
|
||||
padding: 6px 8px;
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
@@ -2029,10 +2029,14 @@ html.openclaw-native-macos
|
||||
}
|
||||
|
||||
/* Roster avatars grow to two-line row scale. The circle clips via the child
|
||||
image/initials instead of the wrapper so the online badge can overflow. */
|
||||
image/initials instead of the wrapper so the online badge can overflow.
|
||||
The avatar-to-text gap lives here: Web Awesome's icon-slot margin targets
|
||||
the slotted openclaw-viewer-avatar host, which is display:contents and
|
||||
therefore generates no box for the margin to apply to. */
|
||||
.presence-roster-menu__item .viewer-avatar {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
margin-inline-end: 10px;
|
||||
overflow: visible;
|
||||
border: none;
|
||||
font-size: 10px;
|
||||
|
||||
@@ -66,6 +66,17 @@ export type ControlUiMockGatewayScenario = {
|
||||
methodResponses?: Record<string, unknown>;
|
||||
/** Replayed in-flight run snapshot served by chat.history and chat.startup. */
|
||||
inFlightRun?: { runId: string; text?: string; plan?: unknown } | null;
|
||||
/** Online users included in the connect snapshot's presence list. The entry
|
||||
* flagged `self` adopts the connecting client's instanceId so presence
|
||||
* surfaces (footer facepile, who's-online roster) resolve "you". */
|
||||
presenceUsers?: Array<{
|
||||
self?: boolean;
|
||||
id: string;
|
||||
name?: string;
|
||||
email?: string;
|
||||
avatarUrl?: string;
|
||||
watchedSessions?: string[];
|
||||
}>;
|
||||
/** Subscription-scoped Gateway events replayed on a fixed browser-side cycle. */
|
||||
repeatingSessionEvents?: {
|
||||
events: Array<{ event: "agent" | "session.tool"; payload: unknown }>;
|
||||
@@ -268,6 +279,7 @@ function normalizeScenario(
|
||||
historyMessages: scenario.historyMessages ?? [],
|
||||
methodResponses: scenario.methodResponses ?? {},
|
||||
inFlightRun: scenario.inFlightRun ?? null,
|
||||
presenceUsers: scenario.presenceUsers ?? [],
|
||||
models: scenario.models ?? [{ id: "gpt-5.5", name: "gpt-5.5", provider: "openai" }],
|
||||
repeatingSessionEvents: scenario.repeatingSessionEvents ?? { events: [] },
|
||||
sessionInfo: scenario.sessionInfo ?? null,
|
||||
@@ -583,6 +595,33 @@ function installControlUiMockGateway(input: {
|
||||
return { found: true, value: matchingCase.response };
|
||||
}
|
||||
|
||||
/** Presence slice of the connect snapshot. The self-flagged entry adopts the
|
||||
* connecting client's instanceId so presence surfaces resolve "you". */
|
||||
function presenceSnapshot(connectParams: unknown): { presence?: unknown[] } {
|
||||
if (scenario.presenceUsers.length === 0) {
|
||||
return {};
|
||||
}
|
||||
const client = isRecord(connectParams) ? connectParams.client : undefined;
|
||||
const selfInstanceId =
|
||||
isRecord(client) && typeof client.instanceId === "string"
|
||||
? client.instanceId
|
||||
: "e2e-self-instance";
|
||||
return {
|
||||
presence: scenario.presenceUsers.map((user, index) => ({
|
||||
instanceId: user.self ? selfInstanceId : `e2e-presence-${index}`,
|
||||
mode: "webchat",
|
||||
reason: "connect",
|
||||
user: {
|
||||
id: user.id,
|
||||
name: user.name ?? null,
|
||||
email: user.email ?? null,
|
||||
avatarUrl: user.avatarUrl ?? null,
|
||||
},
|
||||
watchedSessions: user.watchedSessions ?? [],
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
function recordSessionPatch(params: unknown): void {
|
||||
if (!isRecord(params) || typeof params.key !== "string") {
|
||||
return;
|
||||
@@ -809,6 +848,7 @@ function installControlUiMockGateway(input: {
|
||||
protocol: protocolVersion,
|
||||
server: { connId: "control-ui-e2e", version: "e2e" },
|
||||
snapshot: {
|
||||
...presenceSnapshot(params),
|
||||
sessionDefaults: {
|
||||
defaultAgentId: scenario.defaultAgentId,
|
||||
mainKey: "main",
|
||||
|
||||
Reference in New Issue
Block a user