mirror of
https://github.com/OpenHands/OpenHands.git
synced 2026-10-07 13:38:55 +08:00
fix: truncate long conversation title on mobile to keep tab toggle visible (#867)
* fix(skills): save disabled_skills when settings has no prior disabled_skills field
The hydration effect in SkillsSettingsScreen only set hasHydratedInitialSettings=true
when settings?.disabled_skills was truthy. When no skills had ever been disabled,
the server omits the field entirely (undefined), so the condition was always false:
if (settings?.disabled_skills) { ... } // skipped when field is absent
Because settings?.disabled_skills is undefined both before *and* after settings
load, the dependency array [settings?.disabled_skills] never changed value on
load either, so the effect never ran a second time. hasHydratedInitialSettings
stayed false, and the save effect's early-return guard blocked every toggle.
Fix by gating on settingsLoading instead and defaulting the missing field with
?? []. Also add a localStorage stub for Node.js 25+ which ships a built-in
localStorage that is non-functional without --localstorage-file, breaking the
zustand persist middleware in the test environment.
Co-authored-by: openhands <openhands@all-hands.dev>
* fix(tests): use mockResolvedValue(true) for saveSettings spy
saveSettings returns Promise<boolean>, not Promise<void>, so
mockResolvedValue(undefined) caused TS2345 type errors in CI.
Co-authored-by: openhands <openhands@all-hands.dev>
* fix(skills): persist disabled_skills to localStorage for local backend
The local agent-server has no concept of disabled_skills and its
PATCH /api/settings strips the field before sending. As a result,
toggling a skill off appeared to work in the UI but was never
persisted -- the value was silently discarded on every save and
page refresh reverted the toggle.
Fix by mirroring the existing app-preferences pattern:
- saveSettings (local path): call writeStoredDisabledSkills before
stripping the field from the PATCH payload.
- transformApiResponse: call readStoredDisabledSkills and overlay it
onto the partial Settings returned from the API, so every getSettings
call (cached or fresh) surfaces the stored value.
Export DISABLED_SKILLS_STORAGE_KEY so tests can reference the key
without duplicating the string literal.
Co-authored-by: openhands <openhands@all-hands.dev>
* fix: truncate long conversation title on mobile to keep tab toggle visible
When a conversation title was long enough it would overflow and hide the
RightPanelToggle button (the tab toggle) in the top-right of the mobile
header. Fixed by:
- Adding `min-w-0` to the left-side flex container in
ConversationNameWithStatus so it can shrink and the toggle stays in view
- Adding `shrink-0` to the status dot wrapper so it never collapses
- Adding `min-w-0` to ConversationName's root div (flex item) to allow
it to shrink within the parent
- Removing `w-fit max-w-fit` from the title div (both prevented
`truncate` from ever activating) so the title now properly truncates
with an ellipsis when too long
- Adding `shrink-0` to the ellipsis-button wrapper so it is always
accessible regardless of title length
Fixes #848
Co-authored-by: openhands <openhands@all-hands.dev>
---------
Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
committed by
GitHub
co-authored by
openhands
parent
a00ebe44f3
commit
082cbc2ddb
@@ -59,8 +59,8 @@ export function ConversationNameWithStatus() {
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<div className="flex items-center">
|
||||
<div className="group relative">
|
||||
<div className="flex items-center min-w-0">
|
||||
<div className="group relative shrink-0">
|
||||
<DebugStackframeDot
|
||||
className="ml-[3.5px] w-6 h-6 cursor-pointer"
|
||||
color={statusColor}
|
||||
|
||||
@@ -134,7 +134,7 @@ export function ConversationName() {
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="flex items-center gap-2 h-[22px] text-base font-normal text-left pl-0 lg:pl-1"
|
||||
className="flex items-center gap-2 h-[22px] text-base font-normal text-left pl-0 lg:pl-1 min-w-0"
|
||||
data-testid="conversation-name"
|
||||
>
|
||||
{titleMode === "edit" ? (
|
||||
@@ -150,7 +150,7 @@ export function ConversationName() {
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
className="text-white leading-5 w-fit max-w-fit truncate"
|
||||
className="text-white leading-5 truncate"
|
||||
data-testid="conversation-name-title"
|
||||
onDoubleClick={handleDoubleClick}
|
||||
title={conversation.title || ""}
|
||||
@@ -160,7 +160,10 @@ export function ConversationName() {
|
||||
)}
|
||||
|
||||
{titleMode !== "edit" && (
|
||||
<div ref={ellipsisAnchorRef} className="relative flex items-center">
|
||||
<div
|
||||
ref={ellipsisAnchorRef}
|
||||
className="relative flex items-center shrink-0"
|
||||
>
|
||||
<EllipsisButton onClick={handleEllipsisClick} />
|
||||
{contextMenuOpen && (
|
||||
<ConversationNameContextMenu
|
||||
|
||||
Reference in New Issue
Block a user