Skip to content

Commit 35f1d18

Browse files
committed
fix(notes): 树组头组序随侧栏手排令牌重拉(批6 P2-10)
1 parent 4fe09e0 commit 35f1d18

3 files changed

Lines changed: 43 additions & 2 deletions

File tree

‎app/src/components/NoteListView.tree.test.tsx‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,36 @@ describe("NoteListView REQ-315 树视图排序/显式移动", () => {
212212
expect(idx("化妆")).toBeLessThan(idx("摄影"));
213213
});
214214

215+
it("refreshToken 变化 → 重拉组序行并重排树组头(侧栏手排/回自动后树面一致——审查 P2-10)", async () => {
216+
// 组序行由"侧栏操作"改写(useGroupOrders→onChanged→NotesPage refreshToken++);
217+
// 挂载单拉会残留旧序/已删序行——令牌变化须重拉 note_group_order_list
218+
let groupRows: [number, number][] = [[2, 1]]; // 编程=手动位(seq1)
219+
invokeMock.mockImplementation(async (cmd: string) => {
220+
switch (cmd) {
221+
case "note_order_list": return [];
222+
case "note_group_order_list": return groupRows;
223+
default: return null;
224+
}
225+
});
226+
const notes = [makeNote(1, "摄影笔记", 1), makeNote(2, "编程笔记", 2)];
227+
const { rerender } = render(
228+
<NoteListView notes={notes} groups={groups} groupFilter={null} refreshToken={0} {...baseProps} />,
229+
);
230+
await screen.findByTestId("note-tree-摄影");
231+
const headers = () => Array.from(document.querySelectorAll('[data-testid^="note-tree-"]'));
232+
const idx = (name: string) => headers().findIndex((h) => h.getAttribute("data-testid") === `note-tree-${name}`);
233+
// 手排 seq 在前:编程(2) → 摄影(1)
234+
expect(idx("编程")).toBeLessThan(idx("摄影"));
235+
// 侧栏「手排 ↺/回自动」清行 → 父层令牌 +1 → 树面重拉后回到输入序:摄影(1) → 编程(2)
236+
groupRows = [[1, 1]];
237+
rerender(<NoteListView notes={notes} groups={groups} groupFilter={null} refreshToken={1} {...baseProps} />);
238+
await waitFor(() => expect(idx("摄影")).toBeLessThan(idx("编程")));
239+
// 令牌触发重拉断言(mount 1 次 + token 变更 1 次)
240+
await waitFor(() => {
241+
expect(invokeMock.mock.calls.filter((c) => c[0] === "note_group_order_list").length).toBe(2);
242+
});
243+
});
244+
215245
it("平铺(搜索)态右键:不出现上移/下移(交互矩阵禁移动)", async () => {
216246
const notes = [makeNote(1, "拍了", 1), makeNote(2, "写了", 1)];
217247
render(<NoteListView notes={notes} groups={groups} groupFilter={null} {...baseProps} keyword="拍" />);

‎app/src/components/NoteListView.tsx‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ interface Props {
6666
/** REQ-316(批 7):移组触发空组自动清理 → 上抛组标题(父层 toast 留痕) */
6767
onCleanNotice?: (groupNames: string[]) => void;
6868
onCollapse?: () => void;
69+
/** 外部重载令牌(NotesPage refreshToken——侧栏手排/置顶/回自动经 onChanged
70+
* 递增;本组件据此重拉组序行与笔记序行,树组头与侧栏保持同序) */
71+
refreshToken?: number;
6972
}
7073

7174
/** scope 键(组/null=未分组) */
@@ -90,6 +93,7 @@ export default function NoteListView({
9093
noteColors, tagColors,
9194
onKeywordChange, onTagFilterChange, onSortModeChange, onSelect, onCreate, onRefresh, onOpenSession, onBatchDelete,
9295
onNotePinToggle, onNoteEdit, onNoteDelete, onNoteMoved, onCleanNotice, onCollapse,
96+
refreshToken = 0,
9397
}: Props) {
9498
const theme: ThemeMode = useMemo(
9599
() => (typeof window !== "undefined" && window.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light"),
@@ -147,7 +151,11 @@ export default function NoteListView({
147151
return () => window.removeEventListener("keydown", onKey);
148152
}, [batchMenu, contextMenu, selectionMode, selection.size, exitBatch]);
149153

150-
// 手动序装载(REQ-287:notes 行)+ REQ-315:组序行(树组头排序)
154+
// 手动序装载(REQ-287:notes 行)+ REQ-315:组序行(树组头排序)。
155+
// Why 依赖 refreshToken:侧栏上移/下移/回自动/手排↺(useGroupOrders→onChanged→
156+
// NotesPage refreshToken++)只经父层令牌通知——挂载单拉会在树面残留旧组序/
157+
// 复位后残留已删序行(审查 P2-10);与父层 refreshAll 同频重载,零去抖必要
158+
// (重载=读操作,量级毫秒级;本组件自持的保存路径 saveOrder 仍内联 loadOrders)
151159
const loadOrders = useCallback(() => {
152160
invoke<[string, number, number][]>("note_order_list")
153161
.then((rows) => {
@@ -162,7 +170,7 @@ export default function NoteListView({
162170
.then((rows) => setGroupOrderRows(new Map(rows.map(([gid, seq]) => [gid, seq]))))
163171
.catch((e) => console.warn("[notes] 组排序读取失败(自动排序兜底):", e));
164172
}, []);
165-
useEffect(() => { loadOrders(); }, [loadOrders]);
173+
useEffect(() => { loadOrders(); }, [loadOrders, refreshToken]);
166174

167175
const saveOrder = useCallback(async (scope: string, ids: number[]) => {
168176
await invoke("note_order_save", { scope, noteIds: ids });

‎app/src/pages/NotesPage.tsx‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,9 @@ export default function NotesPage({ focusNoteId, focusNoteSearch, focusGroupId,
514514
onNoteMoved={() => { refreshAll(); void handleNoteChanged(); }}
515515
onCleanNotice={notifyCleanNotice}
516516
onCollapse={() => listCol.setManualFolded(true)}
517+
// 批 6 审查 P2-10:侧栏手排/置顶/回自动(useGroupOrders→refreshAll)后
518+
// 重拉组序行——树组头与组侧栏同序(原挂载单拉,旧序/已删序行残留)
519+
refreshToken={refreshToken}
517520
/>
518521
)}
519522
<ColumnResizer onResize={listCol.resizeBy} onReset={listCol.resetWidth} />

0 commit comments

Comments
 (0)