mirror of https://github.com/openclaw/openclaw.git
fix(ui): session dropdown shows label instead of key (#45130)
Merged via squash.
Prepared head SHA: 0255e3971b
Co-authored-by: luzhidong <15848762+luzhidong@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
This commit is contained in:
parent
64e6df7eea
commit
40c81e9cd3
|
|
@ -12,6 +12,7 @@ Docs: https://docs.openclaw.ai
|
|||
### Fixes
|
||||
|
||||
- Z.AI/onboarding: detect a working default model even for explicit `zai-coding-*` endpoint choices, so Coding Plan setup can keep the selected endpoint while defaulting to `glm-5` when available or `glm-4.7` as fallback. (#45969)
|
||||
- Control UI/chat sessions: show human-readable labels in the grouped session dropdown again, keep unique scoped fallbacks when metadata is missing, and disambiguate duplicate labels only when needed. (#45130) thanks @luzhidong.
|
||||
|
||||
## 2026.3.13
|
||||
|
||||
|
|
|
|||
|
|
@ -575,6 +575,7 @@ export function isCronSessionKey(key: string): boolean {
|
|||
type SessionOptionEntry = {
|
||||
key: string;
|
||||
label: string;
|
||||
scopeLabel: string;
|
||||
title: string;
|
||||
};
|
||||
|
||||
|
|
@ -625,10 +626,12 @@ export function resolveSessionOptionGroups(
|
|||
resolveAgentGroupLabel(state, parsed.agentId),
|
||||
)
|
||||
: ensureGroup("other", "Other Sessions");
|
||||
const scopeLabel = parsed?.rest?.trim() || key;
|
||||
const label = resolveSessionScopedOptionLabel(key, row, parsed?.rest);
|
||||
group.options.push({
|
||||
key,
|
||||
label,
|
||||
scopeLabel,
|
||||
title: key,
|
||||
});
|
||||
};
|
||||
|
|
@ -643,6 +646,19 @@ export function resolveSessionOptionGroups(
|
|||
addOption(row.key);
|
||||
}
|
||||
addOption(sessionKey);
|
||||
|
||||
for (const group of groups.values()) {
|
||||
const counts = new Map<string, number>();
|
||||
for (const option of group.options) {
|
||||
counts.set(option.label, (counts.get(option.label) ?? 0) + 1);
|
||||
}
|
||||
for (const option of group.options) {
|
||||
if ((counts.get(option.label) ?? 0) > 1 && option.scopeLabel !== option.label) {
|
||||
option.label = `${option.label} · ${option.scopeLabel}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(groups.values());
|
||||
}
|
||||
|
||||
|
|
@ -673,18 +689,14 @@ function resolveSessionScopedOptionLabel(
|
|||
if (!row) {
|
||||
return base;
|
||||
}
|
||||
const displayName =
|
||||
typeof row.displayName === "string" && row.displayName.trim().length > 0
|
||||
? row.displayName.trim()
|
||||
: null;
|
||||
const label = typeof row.label === "string" ? row.label.trim() : "";
|
||||
const showDisplayName = Boolean(
|
||||
displayName && displayName !== key && displayName !== label && displayName !== base,
|
||||
);
|
||||
if (!showDisplayName) {
|
||||
return base;
|
||||
|
||||
const label = row.label?.trim() || "";
|
||||
const displayName = row.displayName?.trim() || "";
|
||||
if ((label && label !== key) || (displayName && displayName !== key)) {
|
||||
return resolveSessionDisplayName(key, row);
|
||||
}
|
||||
return `${base} · ${displayName}`;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
type ThemeOption = { id: ThemeName; label: string; icon: string };
|
||||
|
|
|
|||
|
|
@ -647,4 +647,124 @@ describe("chat view", () => {
|
|||
expect(rerendered?.value).toBe("gpt-5-mini");
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it("prefers the session label over displayName in the grouped chat session selector", () => {
|
||||
const { state } = createChatHeaderState({ omitSessionFromList: true });
|
||||
state.sessionKey = "agent:main:subagent:4f2146de-887b-4176-9abe-91140082959b";
|
||||
state.settings.sessionKey = state.sessionKey;
|
||||
state.sessionsResult = {
|
||||
ts: 0,
|
||||
path: "",
|
||||
count: 1,
|
||||
defaults: { model: "gpt-5", contextTokens: null },
|
||||
sessions: [
|
||||
{
|
||||
key: state.sessionKey,
|
||||
kind: "direct",
|
||||
updatedAt: null,
|
||||
label: "cron-config-check",
|
||||
displayName: "webchat:g-agent-main-subagent-4f2146de-887b-4176-9abe-91140082959b",
|
||||
},
|
||||
],
|
||||
};
|
||||
const container = document.createElement("div");
|
||||
render(renderChatSessionSelect(state), container);
|
||||
|
||||
const [sessionSelect] = Array.from(container.querySelectorAll<HTMLSelectElement>("select"));
|
||||
const labels = Array.from(sessionSelect?.querySelectorAll("option") ?? []).map((option) =>
|
||||
option.textContent?.trim(),
|
||||
);
|
||||
|
||||
expect(labels).toContain("Subagent: cron-config-check");
|
||||
expect(labels).not.toContain(state.sessionKey);
|
||||
expect(labels).not.toContain(
|
||||
"subagent:4f2146de-887b-4176-9abe-91140082959b · webchat:g-agent-main-subagent-4f2146de-887b-4176-9abe-91140082959b",
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps a unique scoped fallback when the current grouped session is missing from sessions.list", () => {
|
||||
const { state } = createChatHeaderState({ omitSessionFromList: true });
|
||||
state.sessionKey = "agent:main:subagent:4f2146de-887b-4176-9abe-91140082959b";
|
||||
state.settings.sessionKey = state.sessionKey;
|
||||
const container = document.createElement("div");
|
||||
render(renderChatSessionSelect(state), container);
|
||||
|
||||
const [sessionSelect] = Array.from(container.querySelectorAll<HTMLSelectElement>("select"));
|
||||
const labels = Array.from(sessionSelect?.querySelectorAll("option") ?? []).map((option) =>
|
||||
option.textContent?.trim(),
|
||||
);
|
||||
|
||||
expect(labels).toContain("subagent:4f2146de-887b-4176-9abe-91140082959b");
|
||||
expect(labels).not.toContain("Subagent:");
|
||||
});
|
||||
|
||||
it("keeps a unique scoped fallback when a grouped session row has no label or displayName", () => {
|
||||
const { state } = createChatHeaderState({ omitSessionFromList: true });
|
||||
state.sessionKey = "agent:main:subagent:4f2146de-887b-4176-9abe-91140082959b";
|
||||
state.settings.sessionKey = state.sessionKey;
|
||||
state.sessionsResult = {
|
||||
ts: 0,
|
||||
path: "",
|
||||
count: 1,
|
||||
defaults: { model: "gpt-5", contextTokens: null },
|
||||
sessions: [
|
||||
{
|
||||
key: state.sessionKey,
|
||||
kind: "direct",
|
||||
updatedAt: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
const container = document.createElement("div");
|
||||
render(renderChatSessionSelect(state), container);
|
||||
|
||||
const [sessionSelect] = Array.from(container.querySelectorAll<HTMLSelectElement>("select"));
|
||||
const labels = Array.from(sessionSelect?.querySelectorAll("option") ?? []).map((option) =>
|
||||
option.textContent?.trim(),
|
||||
);
|
||||
|
||||
expect(labels).toContain("subagent:4f2146de-887b-4176-9abe-91140082959b");
|
||||
expect(labels).not.toContain("Subagent:");
|
||||
});
|
||||
|
||||
it("disambiguates duplicate grouped labels with the scoped key suffix", () => {
|
||||
const { state } = createChatHeaderState({ omitSessionFromList: true });
|
||||
state.sessionKey = "agent:main:subagent:4f2146de-887b-4176-9abe-91140082959b";
|
||||
state.settings.sessionKey = state.sessionKey;
|
||||
state.sessionsResult = {
|
||||
ts: 0,
|
||||
path: "",
|
||||
count: 2,
|
||||
defaults: { model: "gpt-5", contextTokens: null },
|
||||
sessions: [
|
||||
{
|
||||
key: "agent:main:subagent:4f2146de-887b-4176-9abe-91140082959b",
|
||||
kind: "direct",
|
||||
updatedAt: null,
|
||||
label: "cron-config-check",
|
||||
},
|
||||
{
|
||||
key: "agent:main:subagent:6fb8b84b-c31f-410f-b7df-1553c82e43c9",
|
||||
kind: "direct",
|
||||
updatedAt: null,
|
||||
label: "cron-config-check",
|
||||
},
|
||||
],
|
||||
};
|
||||
const container = document.createElement("div");
|
||||
render(renderChatSessionSelect(state), container);
|
||||
|
||||
const [sessionSelect] = Array.from(container.querySelectorAll<HTMLSelectElement>("select"));
|
||||
const labels = Array.from(sessionSelect?.querySelectorAll("option") ?? []).map((option) =>
|
||||
option.textContent?.trim(),
|
||||
);
|
||||
|
||||
expect(labels).toContain(
|
||||
"Subagent: cron-config-check · subagent:4f2146de-887b-4176-9abe-91140082959b",
|
||||
);
|
||||
expect(labels).toContain(
|
||||
"Subagent: cron-config-check · subagent:6fb8b84b-c31f-410f-b7df-1553c82e43c9",
|
||||
);
|
||||
expect(labels).not.toContain("Subagent: cron-config-check");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue