Skip to content

Commit b567f0e

Browse files
committed
feat(shell): wire kb search into palette
1 parent 2989c8c commit b567f0e

8 files changed

Lines changed: 631 additions & 58 deletions

File tree

‎app/src/App.tsx‎

Lines changed: 62 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,37 @@ function MainShell() {
177177
setFocusNoteId(noteId);
178178
setPage("notes");
179179
};
180+
181+
// 批 3 T12(规格 §6.1「⌘K 命令入口用来替代现在手写的 `focus*` 参数跳转」):把这 10 个 `focus*`
182+
// 字段的**跨页跳转入口**收敛成具名函数 —— ⌘K 命令与页内回调从此走**同一实现**(此前同一段
183+
// 「setFocus…+setPage」在 2–4 处各写一遍)。⚠️ 边界(计划 Step 5 明写):**只收敛入口** ——
184+
// 状态机、字段类型、各页消费逻辑一个字节未动(删字段 / 改路由参数是批 5 的视图层重构)。
185+
// 入口映射:⌘K 侧能独立发起的是页面命令(9 个)· 建体系向导 · 检索结果(带 ID 的笔记深链);
186+
// 其余带 ID 的深链(会话/体系/复习组/工作台/对话)仍由**页内入口**发起 —— ID 只有页内有。
187+
const goSessions = (sessionId: number) => {
188+
setFocusSessionId(sessionId);
189+
setPage("sessions");
190+
};
191+
// REQ-260:带词高亮打开(引用卡片与 ⌘K 检索结果的**共同实现**)——与上面的普通打开是两条路:
192+
// 普通打开必须清带词态(审查 H1),带词打开双设 focusNoteSearch(key 递增让同笔记可重触发)
193+
const openNoteHighlight = (noteId: number, search: string) => {
194+
setFocusNoteId(noteId);
195+
setFocusNoteSearch({ noteId, search, key: Date.now() });
196+
setPage("notes");
197+
};
198+
const goSystem = (systemId: number) => { setFocusSystemId(systemId); setPage("knowledge"); };
199+
const goGroup = (groupId: number) => { setFocusGroupId(groupId); setPage("notes"); };
200+
// 组预选允许 null(NotesPage 的「复习全部」路径——收敛前那个内联箭头也是这么推出来的)
201+
const goReviewGroup = (groupId: number | null) => { setFocusReviewGroupId(groupId); setPage("review"); };
202+
const goChatSession = (chatId: number) => { setFocusChatId(chatId); setPage("chat"); };
203+
const goChatTask = (taskId: number) => { setFocusChatTaskId(taskId); setPage("chat"); };
204+
const goRefineWorkbench = (sessionId: number, taskId: number) => {
205+
setFocusSessionId(sessionId);
206+
setFocusRefineTaskId(taskId);
207+
setPage("sessions");
208+
};
209+
// 10 个 focus* 字段里**唯一无载荷**的入口(建体系向导不需要 ID)⇒ 它能由 ⌘K 独立发起
210+
const openSystemWizard = () => { setCreateSystemSignal((s) => s + 1); setPage("knowledge"); };
180211
// v0.13.7:跨页直达目标体系(组行徽标/结算简报 → 体系页自动选中)
181212
const [focusSystemId, setFocusSystemId] = useState<number | null>(null);
182213
// TD-2026-09-05-A:外部请求打开建体系向导(笔记页空体系引导 → 体系页向导)
@@ -361,12 +392,7 @@ function MainShell() {
361392
<main style={{ flex: 1, minHeight: 0, display: "flex" }}>
362393
<PageSlot show={page === "classroom"} mounted={mountedPages.has("classroom")}>
363394
{/* 2026-08 A4:融合完成直达会话(onOpenSessions 跳转 + focusSessionId 定位) */}
364-
<ClassroomPage
365-
onOpenSessions={(id) => {
366-
setFocusSessionId(id);
367-
setPage("sessions");
368-
}}
369-
/>
395+
<ClassroomPage onOpenSessions={goSessions} />
370396
</PageSlot>
371397
<PageSlot show={page === "sessions"} mounted={mountedPages.has("sessions")}>
372398
{/* v0.7.1:active 驱动列表刷新(display:none 挂载不刷新根治)+ 查看笔记跨页直达 */}
@@ -375,10 +401,8 @@ function MainShell() {
375401
// v0.16.1:工作台深链 / 精修启动 → AI 对话页(focus 消费后即清空)
376402
focusRefineTaskId={focusRefineTaskId}
377403
onFocusRefineTaskConsumed={() => setFocusRefineTaskId(null)}
378-
onRefineTaskStarted={(_sessionId, taskId) => {
379-
setFocusChatTaskId(taskId);
380-
setPage("chat");
381-
}}
404+
// 精修启动 → AI 对话页(T12:入口收敛为 goChatTask;sessionId 仍被忽略——与收敛前逐字一致)
405+
onRefineTaskStarted={(_sessionId, taskId) => goChatTask(taskId)}
382406
active={page === "sessions"}
383407
onOpenNote={(id) => openNotePlain(id)}
384408
/>
@@ -389,23 +413,11 @@ function MainShell() {
389413
focusNoteId={focusNoteId}
390414
focusNoteSearch={focusNoteSearch}
391415
focusGroupId={focusGroupId}
392-
// v0.20.10(批 5):ⓘ「复习本组」深链 → 复习页组预选
393-
onOpenReview={(groupId) => {
394-
setFocusReviewGroupId(groupId);
395-
setPage("review");
396-
}}
397-
onOpenSystem={(id) => {
398-
setFocusSystemId(id);
399-
setPage("knowledge");
400-
}}
401-
onCreateSystem={() => {
402-
setCreateSystemSignal((s) => s + 1);
403-
setPage("knowledge");
404-
}}
405-
onOpenSessions={(id) => {
406-
setFocusSessionId(id);
407-
setPage("sessions");
408-
}}
416+
// v0.20.10(批 5):ⓘ「复习本组」深链 → 复习页组预选(T12:入口收敛为 goReviewGroup)
417+
onOpenReview={goReviewGroup}
418+
onOpenSystem={goSystem}
419+
onCreateSystem={openSystemWizard}
420+
onOpenSessions={goSessions}
409421
/>
410422
</PageSlot>
411423
{/* v0.20.5:行动域页(保活挂载 + active 门控切回重载——TD-004 模式) */}
@@ -428,24 +440,17 @@ function MainShell() {
428440
AI 任务本页无感知;SessionsPage/ActionPage 同款 active 语义) */}
429441
<ChatPage
430442
active={page === "chat"}
431-
onOpenSessions={(id) => { setFocusSessionId(id); setPage("sessions"); }}
443+
onOpenSessions={goSessions}
432444
onOpenNote={(id) => { setFocusNoteId(id); setPage("notes"); }}
433-
onOpenNoteHighlight={(noteId, search) => {
434-
setFocusNoteId(noteId);
435-
setFocusNoteSearch({ noteId, search, key: Date.now() });
436-
setPage("notes");
437-
}} onOpenSettings={() => setPage("settings")}
445+
onOpenNoteHighlight={openNoteHighlight}
446+
onOpenSettings={() => setPage("settings")}
438447
// v0.16.1:任务进入对话页(会话页精修启动自动跳转);任务视图 → 工作台深链
439448
focusTaskId={focusChatTaskId}
440449
onFocusTaskConsumed={() => setFocusChatTaskId(null)}
441450
// REQ-274:对话面板「在对话页继续」直达会话(消费后清空)
442451
focusChatId={focusChatId}
443452
onFocusChatConsumed={() => setFocusChatId(null)}
444-
onOpenRefineWorkbench={(sessionId, taskId) => {
445-
setFocusSessionId(sessionId);
446-
setFocusRefineTaskId(taskId);
447-
setPage("sessions");
448-
}}
453+
onOpenRefineWorkbench={goRefineWorkbench}
449454
/>
450455
</PageSlot>
451456
<PageSlot show={page === "knowledge"} mounted={mountedPages.has("knowledge")}>
@@ -455,7 +460,7 @@ function MainShell() {
455460
focusSystemId={focusSystemId}
456461
createSystemSignal={createSystemSignal}
457462
onOpenNote={(id) => { setFocusNoteId(id); setPage("notes"); }}
458-
onOpenGroup={(id) => { setFocusGroupId(id); setPage("notes"); }}
463+
onOpenGroup={goGroup}
459464
/>
460465
</PageSlot>
461466
<PageSlot show={page === "goals"} mounted={mountedPages.has("goals")}>
@@ -504,10 +509,12 @@ function MainShell() {
504509
{aiToast.text}
505510
</div>
506511
)}
507-
{/* 批 3 T11:⌘K 命令面板(规格 §6.1)。它是**壳级覆盖层**,与 toast 一样挂在导航壳最外层、
512+
{/* 批 3 T11/T12:⌘K 命令面板(规格 §6.1)。它是**壳级覆盖层**,与 toast 一样挂在导航壳最外层、
508513
不是任何页面的子节点(切页不重挂、也不参与页面布局)。
509-
`onPick` 只收口两种动作 —— 页面级 `setPage`(key 仍经 `isPageKey` 运行期校验,
510-
回调实参不被信任)与打开对话面板;`focus*` 深链状态机原样不动(收敛是 T12)。
514+
`onPick` 收口三类动作(回调实参不被信任):页面级 `setPage`(key 仍经 `isPageKey` 运行期校验)·
515+
打开对话面板 · **T12 新增的两类** —— 检索结果(`kind:"hit"`:带载荷的深链入口,落到
516+
`focusNoteId` + `focusNoteSearch`,与引用卡片共用 `openNoteHighlight`)与无载荷的 `focus*`
517+
入口(`kind:"create-system"`)。`focus*` 状态机本身原样不动(收敛的只是入口,见 T12 报告)。
511518
Esc / 点遮罩 / 焦点都在组件内部(自足实现,见 `shell/CommandPalette.tsx` 文件头)。 */}
512519
<CommandPalette
513520
open={paletteOpen}
@@ -517,6 +524,14 @@ function MainShell() {
517524
setDockOpen(true);
518525
return;
519526
}
527+
if (pick.kind === "hit") {
528+
openNoteHighlight(pick.jump.noteId, pick.jump.search);
529+
return;
530+
}
531+
if (pick.kind === "create-system") {
532+
openSystemWizard();
533+
return;
534+
}
520535
if (isPageKey(pick.key)) setPage(pick.key);
521536
}}
522537
/>
@@ -529,15 +544,11 @@ function MainShell() {
529544
<AiConversationDock
530545
open={dockOpen}
531546
onClose={() => setDockOpen(false)}
532-
onOpenChat={(chatId) => { setFocusChatId(chatId); setPage("chat"); }}
533-
onOpenTaskInChat={(taskId) => { setFocusChatTaskId(taskId); setPage("chat"); }}
534-
onOpenSessions={(id) => { setFocusSessionId(id); setPage("sessions"); }}
535-
onOpenNote={(id) => openNotePlain(id)}
536-
onOpenRefineWorkbench={(sessionId, taskId) => {
537-
setFocusSessionId(sessionId);
538-
setFocusRefineTaskId(taskId);
539-
setPage("sessions");
540-
}}
547+
onOpenChat={goChatSession}
548+
onOpenTaskInChat={goChatTask}
549+
onOpenSessions={goSessions}
550+
onOpenNote={openNotePlain}
551+
onOpenRefineWorkbench={goRefineWorkbench}
541552
/>
542553
</Suspense>
543554
)}

‎app/src/shell/CommandPalette.css‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,12 @@
9191
font-size: 13px;
9292
color: var(--ed-ink-3, #6e6e68);
9393
}
94+
95+
/* 检索降级提示(批 3 T12):输入框与列表之间的一行灰字——「检索失败」与「没有命中」是两回事 */
96+
.ed-cmdk__note {
97+
flex: 0 0 auto;
98+
padding: 6px 16px;
99+
font-size: 12px;
100+
color: var(--ed-ink-3, #6e6e68);
101+
border-bottom: 1px solid var(--ed-border, #eae7e0);
102+
}

0 commit comments

Comments
 (0)