Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

[Bug][desktop] 顶栏会话菜单(标题右侧 ⌄)展开被一次 RPC 阻塞且无加载反馈,点击后表现为"没反应"

オープン
#519 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
45/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
typescript
領域
desktop, frontend

調査の方向性

The issue analyzes the shipped desktop bundle, but does not identify source files or tests, so first locate the session menu and fork menu hook in the repository. Trace how opening the top bar and sidebar menus waits for fork options, then check the existing loading state and tests. Done means the menu opens promptly, fork actions show a useful loading or failure state, and repeated clicks do not prevent it from opening.

索引モデルが issue の本文から書いたものです。

説明

desktop
Product or interface

Desktop app

Version

MiniMax Code Desktop 3.1.4.189 (macOS build)

Platform

macOS

OS version and architecture

macOS 26.3.1 (build 25D2128), arm64

Issue area

UI / UX

Desktop log upload ID (optional)

No response

Steps to reproduce
  1. 打开 MiniMax Code Desktop,进入任意一个本地会话(非云端会话)。
  2. 顶栏会话标题右侧有一个 ⌄ 箭头按钮(data-testid="chat-topbar-session-menu-trigger")。
  3. 点击该箭头。

观察两点:

  • 触发方式没有提示:鼠标悬浮在箭头上只会有一个浅灰背景和图标颜色变化,不会弹出菜单;必须点击才会展开。全程没有任何 tooltip / 文案说明这一点。
  • 点击后不是立即响应:点击和菜单真正出现之间,存在一段明显可感知的"空窗期"(空窗期长短取决于一次本地 RPC 的耗时)。本地 runtime 正在跑任务、刚启动尚未就绪、或会话尚未注册时,这个空窗期会被显著拉长,表现就是"点了没反应";连点几次反而更糟。
Expected and actual behavior

Expected: 点击箭头后菜单应立即展开(至多对"复制为新会话 / 新工作树"这两项显示加载态),且悬浮时有 tooltip 说明这是可点击的下拉菜单。

Actual:

  1. 打开动作被一次异步 RPC 整体阻塞。 菜单不是点击即开,而是要先等一次 GetSessionForkOptions RPC 返回后才展开;等待期间界面零反馈。
  2. 等待期没有任何加载/禁用/旋转等可见反馈,按钮只有 aria-label(zh:会话操作),没有 title、没有 tooltip、没有 aria-expanded,所以用户既不知道触发方式,也不知道系统是否已经收到点击。
  3. 重复点击会互相作废。 打开流程用了一个自增计数器做守卫,加载期间再次点击会让前一次待处理的"打开"失效,菜单要等最后一次请求返回才出现 —— 越点越慢,主观感受就是"按钮坏了"。
  4. UI 层没有超时与降级。 整个 gate 没有 Promise.race 超时兜底,本地 runtime 忙或未就绪时,点击可以长时间表现为完全无响应。
  5. Promise 链没有 .catch()。 目前底层 loadMenuOptions 内部吞掉了异常所以不会 reject,但一旦该调用链任一环抛出,就会变成 unhandled rejection,菜单永远不打开且没有任何报错提示。
  6. 可发现性缺失 + 目标语义冲突。 箭头命中区只有 30×30;而点击标题文字(data-testid="chat-topbar-title-button")触发的是内联重命名,不是菜单 —— 最显眼的入口做的是另一件事,真正的主菜单入口却没有任何指引。
Root cause analysis (analyzed from the shipped 3.1.4.189 bundle)

分析对象:/Applications/MiniMax Code.app/Contents/Resources/app.asar → out/_next/static/chunks/(桌面端 UI 未开源,以下为对已发布产物的静态分析)。

1) 触发方式是"点击",不是"悬浮"。

  • 顶栏触发按钮:chunks/75788.db1775b1813df733.js

    <Dropdown menu={nI} placement="bottomLeft" compact open={ts} onOpenChange={tL} ...>
      <button type="button"
              aria-label={t("chat_panel.session_menu_aria")}   // zh: 会话操作
              data-testid="chat-topbar-session-menu-trigger"
              className={eG(ts)}>
        <ChevronDown size={16} />
      </button>
    </Dropdown>
    
  • 共享 Dropdown 封装(webpack module 13376,位于 chunks/90321-e50007b0d4d62264.js):

    trigger: L = ["click"],        // 默认值
    ...
    <AntDropdown trigger={L} open={ei} onOpenChange={es} ... />   // trigger 原样透传给 antd
    

    顶栏调用处没有传 trigger,因此为 click-only。悬浮时的 hover:bg-bg_interaction_tertiary_hover 只是背景色反馈,不触发展开。

2) 为什么"点了没反应":打开被一次 fork 选项预取整体 gate 住。

顶栏容器(chunks/75788.db1775b1813df733.js):

const [ts, ti] = useState(false);        // ts = 菜单是否展开
const tr = useRef(0);                    // 请求序号
const tF = onMenuOpen;                   // fork 菜单预取

const tL = useCallback((open) => {
  const token = ++tr.current;
  if (!open) { ti(false); tF(false); return; }
  ti(false);                             // ① 先关掉
  tF(true).then(() => {                   // ② 等一次异步预取
    if (tr.current === token) ti(true);  // ③ 才真正展开
  });
}, [tF]);

tF 来自 fork 菜单 hook(webpack module 82610):

onMenuOpen: async (open) => {
  open && enabled && await forkMenuStore.getState().loadMenuOptions({ source, sessionId });
}

loadMenuOptions → service.getForkOptions() → thrift DesktopService.GetSessionForkOptions,
GET /minimax-desktop/api/v1/session/:id/fork/options(transport: "metadataOnly"),即一次到本地 runtime 的 RPC。

于是 "展开菜单"被绑死在"预取 fork 选项"上:本地 runtime 越慢,点击后菜单出现得越晚,慢到一定程度就是"完全没反应"。

3) 同一模式也存在于侧边栏会话菜单(chunks/app/(pages)/(mavis)/archon/page-f0f825d0d4c82846.js):

tc = (open) => {
  const token = ++eU.current;
  if (!open) { eO(false); eE(false); return; }
  eO(false); eW(false);
  eE(true).then(() => { if (eU.current === token) eO(true); });
};

两者共用同一个 fork-menu store,建议一并修复。

4) 其他相关事实

  • hook 已经暴露了 loading(以及 available / worktreeVisible),但顶栏完全没有使用 loading。
  • 该 gate 只在本地会话且会话支持 fork 时生效(enabled && isLocal(source) && !isRemote());云端会话会立即展开 —— 这也解释了为什么这个问题只在本地会话上稳定复现。
  • 箭头按钮尺寸为 size-[30px] min-h-[30px] min-w-[30px],展开态只切换 bg-bg_interaction_tertiary_selected / text-icon_default_primary;chevron 图标不会旋转,没有 aria-expanded。
Proposed fix

按优先级:

  1. 点击即展开,异步只补数据。 onOpenChange(true) 时立刻 ti(true);复制为新会话 / 新工作树 两项先以 loading 骨架呈现,GetSessionForkOptions 返回后再填充或启用。用户感知延迟降为 0。
  2. 给 RPC 加超时与降级。 Promise.race([rpc, timeout(1500~2000ms)]);超时按 canFork=false 降级(该项置灰),不再阻塞整个菜单。
  3. 补可见反馈与可发现性。
    • 触发器加 aria-expanded / aria-busy;pending 时显示 spinner 或让 chevron 旋转。
    • 加 tooltip(如"会话菜单")明确这是点击触发;悬浮时 chevron 可轻微位移/加深,给出"可点"的暗示。
    • 展开态让 chevron 旋转 180°,让开合状态一眼可辨。
  4. 修掉重复点击互相作废的竞态。 用 request-id + AbortController 取代自增计数器守卫:旧的请求取消,而不是仅仅被忽略,保证"最后一次点击一定打开"。
  5. 补 .catch()。 失败时 toast 提示,并且仍然打开菜单(其余菜单项不依赖 fork),避免静默失败。
  6. 统一修复侧边栏会话菜单,复用同一 hook 与同一套降级逻辑。
  7. (可选,产品决策) 让标题区域本身承载菜单(如点击标题 = 菜单、双击 = 重命名),或支持右键菜单,减少"标题是重命名、箭头才是菜单"的语义冲突。
Redacted error summary

No response

Screenshots

(附:顶栏标题与 ⌄ 按钮、以及展开后的会话菜单截图)


附:给维护者的简短结论

  • 触发方式:点击(不是悬浮)。module 13376 的 trigger 默认 ["click"],顶栏未覆盖。
  • "不灵敏"的根因:菜单展开被 loadMenuOptions()(一次到本地 runtime 的 thrift RPC)整体 gate 住,且 UI 层无超时、无 loading 反馈、无 catch,并带一个会让重复点击互相作废的计数器守卫。
  • 最小可行修复:先展开菜单 + fork 项 loading 态,再补超时降级与 .catch()。
主要言語
TypeScript
スター
2k
フォーク
259
平均マージ
11時間
マージ済み PR(30日)
81

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

MiniMax-AI/minimax-code のほかの issue

MiniMax-AI/minimax-code の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。