Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 81 additions & 18 deletions apps/server/src/services/tree.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import { note, NoteBuilder } from "../test/becca_mocking.js";
import {beforeEach, describe, expect, it, vi} from "vitest";
import {note, NoteBuilder} from "../test/becca_mocking.js";
import becca from "../becca/becca.js";
import BBranch from "../becca/entities/bbranch.js";
import BNote from "../becca/entities/bnote.js";
import tree from "./tree.js";
import cls from "./cls.js";
import { buildNote } from "../test/becca_easy_mocking.js";
import {buildNote} from "../test/becca_easy_mocking.js";

describe("Tree", () => {
let rootNote!: NoteBuilder;
Expand Down Expand Up @@ -48,6 +48,23 @@ describe("Tree", () => {
};
});
});
it("sorts notes by title (base case)", () => {

const note = buildNote({
children: [
{title: "1"},
{title: "2"},
{title: "3"},
],
"#sorted": "",
});
cls.init(() => {
tree.sortNotesIfNeeded(note.noteId);
});
const orderedTitles = note.children.map((child) => child.title);
expect(orderedTitles).toStrictEqual(["1", "2", "3"]);
}
)

it("custom sort order is idempotent", () => {
rootNote.label("sorted", "order");
Expand All @@ -56,13 +73,15 @@ describe("Tree", () => {
for (let i = 0; i <= 5; i++) {
rootNote.child(note(String(i)).label("order", String(i)));
}
rootNote.child(note("top").label("top"));
rootNote.child(note("bottom").label("bottom"));

// Add a few values which have no defined order.
for (let i = 6; i < 10; i++) {
rootNote.child(note(String(i)));
}

const expectedOrder = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ];
const expectedOrder = ["top", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "bottom"];

// Sort a few times to ensure that the resulting order is the same.
for (let i = 0; i < 5; i++) {
Expand All @@ -78,31 +97,31 @@ describe("Tree", () => {
it("pins to the top and bottom", () => {
const note = buildNote({
children: [
{ title: "bottom", "#bottom": "" },
{ title: "5" },
{ title: "3" },
{ title: "2" },
{ title: "1" },
{ title: "top", "#top": "" }
{title: "bottom", "#bottom": ""},
{title: "5"},
{title: "3"},
{title: "2"},
{title: "1"},
{title: "top", "#top": ""}
],
"#sorted": ""
});
cls.init(() => {
tree.sortNotesIfNeeded(note.noteId);
});
const orderedTitles = note.children.map((child) => child.title);
expect(orderedTitles).toStrictEqual([ "top", "1", "2", "3", "5", "bottom" ]);
expect(orderedTitles).toStrictEqual(["top", "1", "2", "3", "5", "bottom"]);
});

it("pins to the top and bottom in reverse order", () => {
const note = buildNote({
children: [
{ title: "bottom", "#bottom": "" },
{ title: "1" },
{ title: "2" },
{ title: "3" },
{ title: "5" },
{ title: "top", "#top": "" }
{title: "bottom", "#bottom": ""},
{title: "1"},
{title: "2"},
{title: "3"},
{title: "5"},
{title: "top", "#top": ""}
],
"#sorted": "",
"#sortDirection": "desc"
Expand All @@ -111,6 +130,50 @@ describe("Tree", () => {
tree.sortNotesIfNeeded(note.noteId);
});
const orderedTitles = note.children.map((child) => child.title);
expect(orderedTitles).toStrictEqual([ "top", "5", "3", "2", "1", "bottom" ]);
expect(orderedTitles).toStrictEqual(["top", "5", "3", "2", "1", "bottom"]);
});

it("keeps folder notes on top when #sortFolderFirst is set, but not above #top", () => {
const note = buildNote({
children: [
{title: "bottom", "#bottom": ""},
{title: "1"},
{title: "2"},
{title: "p1", children: [{title: "1.1"}, {title: "1.2"}]},
{title: "p2", children: [{title: "2.1"}, {title: "2.2"}]},
{title: "3"},
{title: "5"},
{title: "top", "#top": ""}
],
"#sorted": "",
"#sortFoldersFirst": ""
});
cls.init(() => {
tree.sortNotesIfNeeded(note.noteId);
});
const orderedTitles = note.children.map((child) => child.title);
expect(orderedTitles).toStrictEqual(["top", "p1", "p2", "1", "2", "3", "5", "bottom"]);
});

it("sorts notes accordingly when #sortNatural is set", () => {
const note = buildNote({
children: [
{title: "bottom", "#bottom": ""},
{title: "1"},
{title: "2"},
{title: "10"},
{title: "20"},
{title: "3"},
{title: "top", "#top": ""}
],
"#sorted": "",
"#sortNatural": ""
});
cls.init(() => {
tree.sortNotesIfNeeded(note.noteId);
});
const orderedTitles = note.children.map((child) => child.title);
expect(orderedTitles).toStrictEqual(["top", "1", "2", "3", "10", "20", "bottom"]);
}
)
});
19 changes: 10 additions & 9 deletions apps/server/src/services/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,6 @@ function sortNotes(parentNoteId: string, customSortBy: string = "title", reverse
}

notes.sort((a, b) => {
if (foldersFirst) {
const aHasChildren = a.hasChildren();
const bHasChildren = b.hasChildren();

if ((aHasChildren && !bHasChildren) || (!aHasChildren && bHasChildren)) {
// exactly one note of the two is a directory, so the sorting will be done based on this status
return aHasChildren ? -1 : 1;
}
}

function fetchValue(note: BNote, key: string) {
let rawValue: string | null;
Expand Down Expand Up @@ -154,6 +145,16 @@ function sortNotes(parentNoteId: string, customSortBy: string = "title", reverse
return compare(bottomBEl, bottomAEl) * (reverse ? -1 : 1);
}

if (foldersFirst) {
const aHasChildren = a.hasChildren();
const bHasChildren = b.hasChildren();

if ((aHasChildren && !bHasChildren) || (!aHasChildren && bHasChildren)) {
// exactly one note of the two is a directory, so the sorting will be done based on this status
return aHasChildren ? -1 : 1;
}
}

const customAEl = fetchValue(a, customSortBy) ?? fetchValue(a, "title") as string;
const customBEl = fetchValue(b, customSortBy) ?? fetchValue(b, "title") as string;

Expand Down