1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-07-16 00:14:34 +02:00

Desktop, Mobile: Fixes #10674: Fix sidebar performance regression with many nested notebooks (#10676)

This commit is contained in:
Henry Heino
2024-07-04 05:56:57 -07:00
committed by GitHub
parent f32fe63205
commit 320d0df60d
4 changed files with 106 additions and 47 deletions

View File

@ -1,39 +1,10 @@
import Folder from '../../models/Folder';
import BaseModel from '../../BaseModel';
import { FolderEntity, TagEntity, TagsWithNoteCountEntity } from '../../services/database/types';
import { getDisplayParentId, getTrashFolderId } from '../../services/trash';
import { getDisplayParentId } from '../../services/trash';
import { getCollator } from '../../models/utils/getCollator';
export type RenderFolderItem<T> = (folder: FolderEntity, hasChildren: boolean, depth: number)=> T;
export type RenderTagItem<T> = (tag: TagsWithNoteCountEntity)=> T;
function folderHasChildren_(folders: FolderEntity[], folderId: string) {
if (folderId === getTrashFolderId()) {
return !!folders.find(f => !!f.deleted_time);
}
for (let i = 0; i < folders.length; i++) {
const folder = folders[i];
const folderParentId = getDisplayParentId(folder, folders.find(f => f.id === folder.parent_id));
if (folderParentId === folderId) return true;
}
return false;
}
function folderIsCollapsed(folders: FolderEntity[], folderId: string, collapsedFolderIds: string[]) {
if (!collapsedFolderIds || !collapsedFolderIds.length) return false;
while (true) {
const folder: FolderEntity = BaseModel.byId(folders, folderId);
if (!folder) throw new Error(`No folder with id ${folder.id}`);
const folderParentId = getDisplayParentId(folder, folders.find(f => f.id === folder.parent_id));
if (!folderParentId) return false;
if (collapsedFolderIds.indexOf(folderParentId) >= 0) return true;
folderId = folderParentId;
}
}
interface FolderSelectedContext {
selectedFolderId: string;
notesParentType: string;
@ -48,21 +19,36 @@ type ItemsWithOrder<ItemType> = {
order: string[];
};
interface RenderFoldersProps {
interface FolderTree {
folders: FolderEntity[];
parentIdToChildren: Map<string, FolderEntity[]>;
idToItem: Map<string, FolderEntity>;
}
interface RenderFoldersProps {
folderTree: FolderTree;
collapsedFolderIds: string[];
}
function folderIsCollapsed(context: RenderFoldersProps, folderId: string) {
if (!context.collapsedFolderIds || !context.collapsedFolderIds.length) return false;
while (true) {
const folder = context.folderTree.idToItem.get(folderId);
const folderParentId = getDisplayParentId(folder, context.folderTree.idToItem.get(folder.parent_id));
if (!folderParentId) return false;
if (context.collapsedFolderIds.includes(folderParentId)) return true;
folderId = folderParentId;
}
}
function renderFoldersRecursive_<T>(props: RenderFoldersProps, renderItem: RenderFolderItem<T>, items: T[], parentId: string, depth: number, order: string[]): ItemsWithOrder<T> {
const folders = props.folders;
for (let i = 0; i < folders.length; i++) {
const folder = folders[i];
const folders = props.folderTree.parentIdToChildren.get(parentId ?? '') ?? [];
const parentIdToChildren = props.folderTree.parentIdToChildren;
for (const folder of folders) {
if (folderIsCollapsed(props, folder.id)) continue;
const folderParentId = getDisplayParentId(folder, props.folders.find(f => f.id === folder.parent_id));
if (!Folder.idsEqual(folderParentId, parentId)) continue;
if (folderIsCollapsed(props.folders, folder.id, props.collapsedFolderIds)) continue;
const hasChildren = folderHasChildren_(folders, folder.id);
const hasChildren = parentIdToChildren.has(folder.id);
order.push(folder.id);
items.push(renderItem(folder, hasChildren, depth));
if (hasChildren) {
@ -81,6 +67,24 @@ export const renderFolders = <T> (props: RenderFoldersProps, renderItem: RenderF
return renderFoldersRecursive_(props, renderItem, [], '', 0, []);
};
export const buildFolderTree = (folders: FolderEntity[]): FolderTree => {
const idToItem = new Map<string, FolderEntity>();
for (const folder of folders) {
idToItem.set(folder.id, folder);
}
const parentIdToChildren = new Map<string, FolderEntity[]>();
for (const folder of folders) {
const displayParentId = getDisplayParentId(folder, idToItem.get(folder.parent_id)) ?? '';
if (!parentIdToChildren.has(displayParentId)) {
parentIdToChildren.set(displayParentId, []);
}
parentIdToChildren.get(displayParentId).push(folder);
}
return { folders, parentIdToChildren, idToItem };
};
const sortTags = (tags: TagEntity[]) => {
tags = tags.slice();
const collator = getCollator();