mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-10-03 11:21:31 +08:00
Merge remote-tracking branch 'origin/develop' into feature/better_sidebar
This commit is contained in:
commit
74b78e7a2c
12
dump-db/package-lock.json
generated
12
dump-db/package-lock.json
generated
@ -464,9 +464,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/better-sqlite3": {
|
"node_modules/better-sqlite3": {
|
||||||
"version": "11.8.0",
|
"version": "11.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.8.1.tgz",
|
||||||
"integrity": "sha512-aKv9s2dir7bsEX5RIjL9HHWB9uQ+f6Vch5B4qmeAOop4Y9OYHX+PNKLr+mpv6+d8L/ZYh4l7H8zPuVMbWkVMLw==",
|
"integrity": "sha512-9BxNaBkblMjhJW8sMRZxnxVTRgbRmssZW0Oxc1MPBTfiR+WW21e2Mk4qu8CzrcZb1LwPCnFsfDEzq+SNcBU8eg==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bindings": "^1.5.0",
|
"bindings": "^1.5.0",
|
||||||
@ -1516,9 +1516,9 @@
|
|||||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
|
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
|
||||||
},
|
},
|
||||||
"better-sqlite3": {
|
"better-sqlite3": {
|
||||||
"version": "11.8.0",
|
"version": "11.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.8.1.tgz",
|
||||||
"integrity": "sha512-aKv9s2dir7bsEX5RIjL9HHWB9uQ+f6Vch5B4qmeAOop4Y9OYHX+PNKLr+mpv6+d8L/ZYh4l7H8zPuVMbWkVMLw==",
|
"integrity": "sha512-9BxNaBkblMjhJW8sMRZxnxVTRgbRmssZW0Oxc1MPBTfiR+WW21e2Mk4qu8CzrcZb1LwPCnFsfDEzq+SNcBU8eg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bindings": "^1.5.0",
|
"bindings": "^1.5.0",
|
||||||
"prebuild-install": "^7.1.1"
|
"prebuild-install": "^7.1.1"
|
||||||
|
31
package-lock.json
generated
31
package-lock.json
generated
@ -16,12 +16,12 @@
|
|||||||
"@mermaid-js/layout-elk": "0.1.7",
|
"@mermaid-js/layout-elk": "0.1.7",
|
||||||
"@mind-elixir/node-menu": "1.0.3",
|
"@mind-elixir/node-menu": "1.0.3",
|
||||||
"@triliumnext/express-partial-content": "1.0.1",
|
"@triliumnext/express-partial-content": "1.0.1",
|
||||||
"@types/react-dom": "18.3.1",
|
"@types/react-dom": "18.3.5",
|
||||||
"archiver": "7.0.1",
|
"archiver": "7.0.1",
|
||||||
"async-mutex": "0.5.0",
|
"async-mutex": "0.5.0",
|
||||||
"autocomplete.js": "0.38.1",
|
"autocomplete.js": "0.38.1",
|
||||||
"axios": "1.7.9",
|
"axios": "1.7.9",
|
||||||
"better-sqlite3": "11.8.0",
|
"better-sqlite3": "11.8.1",
|
||||||
"bootstrap": "5.3.3",
|
"bootstrap": "5.3.3",
|
||||||
"boxicons": "2.1.4",
|
"boxicons": "2.1.4",
|
||||||
"cheerio": "1.0.0",
|
"cheerio": "1.0.0",
|
||||||
@ -134,7 +134,7 @@
|
|||||||
"@types/mime-types": "2.1.4",
|
"@types/mime-types": "2.1.4",
|
||||||
"@types/multer": "1.4.12",
|
"@types/multer": "1.4.12",
|
||||||
"@types/node": "22.10.7",
|
"@types/node": "22.10.7",
|
||||||
"@types/react": "18.3.1",
|
"@types/react": "18.3.18",
|
||||||
"@types/safe-compare": "1.1.2",
|
"@types/safe-compare": "1.1.2",
|
||||||
"@types/sanitize-html": "2.13.0",
|
"@types/sanitize-html": "2.13.0",
|
||||||
"@types/sax": "1.2.7",
|
"@types/sax": "1.2.7",
|
||||||
@ -3918,6 +3918,7 @@
|
|||||||
"version": "15.7.14",
|
"version": "15.7.14",
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz",
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz",
|
||||||
"integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==",
|
"integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/qs": {
|
"node_modules/@types/qs": {
|
||||||
@ -3935,9 +3936,10 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/react": {
|
"node_modules/@types/react": {
|
||||||
"version": "18.3.1",
|
"version": "18.3.18",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz",
|
||||||
"integrity": "sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==",
|
"integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/prop-types": "*",
|
"@types/prop-types": "*",
|
||||||
@ -3945,12 +3947,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/react-dom": {
|
"node_modules/@types/react-dom": {
|
||||||
"version": "18.3.1",
|
"version": "18.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.5.tgz",
|
||||||
"integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==",
|
"integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "*"
|
"@types/react": "^18.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/readdir-glob": {
|
"node_modules/@types/readdir-glob": {
|
||||||
@ -5140,9 +5142,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/better-sqlite3": {
|
"node_modules/better-sqlite3": {
|
||||||
"version": "11.8.0",
|
"version": "11.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.8.1.tgz",
|
||||||
"integrity": "sha512-aKv9s2dir7bsEX5RIjL9HHWB9uQ+f6Vch5B4qmeAOop4Y9OYHX+PNKLr+mpv6+d8L/ZYh4l7H8zPuVMbWkVMLw==",
|
"integrity": "sha512-9BxNaBkblMjhJW8sMRZxnxVTRgbRmssZW0Oxc1MPBTfiR+WW21e2Mk4qu8CzrcZb1LwPCnFsfDEzq+SNcBU8eg==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -6683,6 +6685,7 @@
|
|||||||
"version": "3.1.3",
|
"version": "3.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/cytoscape": {
|
"node_modules/cytoscape": {
|
||||||
|
@ -61,12 +61,12 @@
|
|||||||
"@mermaid-js/layout-elk": "0.1.7",
|
"@mermaid-js/layout-elk": "0.1.7",
|
||||||
"@mind-elixir/node-menu": "1.0.3",
|
"@mind-elixir/node-menu": "1.0.3",
|
||||||
"@triliumnext/express-partial-content": "1.0.1",
|
"@triliumnext/express-partial-content": "1.0.1",
|
||||||
"@types/react-dom": "18.3.1",
|
"@types/react-dom": "18.3.5",
|
||||||
"archiver": "7.0.1",
|
"archiver": "7.0.1",
|
||||||
"async-mutex": "0.5.0",
|
"async-mutex": "0.5.0",
|
||||||
"autocomplete.js": "0.38.1",
|
"autocomplete.js": "0.38.1",
|
||||||
"axios": "1.7.9",
|
"axios": "1.7.9",
|
||||||
"better-sqlite3": "11.8.0",
|
"better-sqlite3": "11.8.1",
|
||||||
"bootstrap": "5.3.3",
|
"bootstrap": "5.3.3",
|
||||||
"boxicons": "2.1.4",
|
"boxicons": "2.1.4",
|
||||||
"cheerio": "1.0.0",
|
"cheerio": "1.0.0",
|
||||||
@ -176,7 +176,7 @@
|
|||||||
"@types/mime-types": "2.1.4",
|
"@types/mime-types": "2.1.4",
|
||||||
"@types/multer": "1.4.12",
|
"@types/multer": "1.4.12",
|
||||||
"@types/node": "22.10.7",
|
"@types/node": "22.10.7",
|
||||||
"@types/react": "18.3.1",
|
"@types/react": "18.3.18",
|
||||||
"@types/safe-compare": "1.1.2",
|
"@types/safe-compare": "1.1.2",
|
||||||
"@types/sanitize-html": "2.13.0",
|
"@types/sanitize-html": "2.13.0",
|
||||||
"@types/sax": "1.2.7",
|
"@types/sax": "1.2.7",
|
||||||
|
@ -27,7 +27,7 @@ export default class FBlob {
|
|||||||
/**
|
/**
|
||||||
* @throws Error in case of invalid JSON
|
* @throws Error in case of invalid JSON
|
||||||
*/
|
*/
|
||||||
getJsonContent(): unknown {
|
getJsonContent<T>(): T | null {
|
||||||
if (!this.content || !this.content.trim()) {
|
if (!this.content || !this.content.trim()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import TypeWidget from "./type_widget.js";
|
import TypeWidget from "./type_widget.js";
|
||||||
import utils from "../../services/utils.js";
|
import utils from "../../services/utils.js";
|
||||||
import MindElixir, { type MindElixirCtor } from "mind-elixir";
|
import type { MindElixirCtor } from "mind-elixir";
|
||||||
import nodeMenu from "@mind-elixir/node-menu";
|
import nodeMenu from "@mind-elixir/node-menu";
|
||||||
import type FNote from "../../entities/fnote.js";
|
import type FNote from "../../entities/fnote.js";
|
||||||
import type { EventData } from "../../components/app_context.js";
|
import type { EventData } from "../../components/app_context.js";
|
||||||
@ -141,11 +141,16 @@ const TPL = `
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
interface MindmapModel {
|
||||||
|
direction: number;
|
||||||
|
}
|
||||||
|
|
||||||
export default class MindMapWidget extends TypeWidget {
|
export default class MindMapWidget extends TypeWidget {
|
||||||
|
|
||||||
private $content!: JQuery<HTMLElement>;
|
private $content!: JQuery<HTMLElement>;
|
||||||
private triggeredByUserOperation?: boolean;
|
private triggeredByUserOperation?: boolean;
|
||||||
private mind?: ReturnType<MindElixirCtor["new"]>;
|
private mind?: ReturnType<MindElixirCtor["new"]>;
|
||||||
|
private MindElixir: any; // TODO: Fix type
|
||||||
|
|
||||||
static getType() {
|
static getType() {
|
||||||
return "mindMap";
|
return "mindMap";
|
||||||
@ -170,6 +175,11 @@ export default class MindMapWidget extends TypeWidget {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Save the mind map if the user changes the layout direction.
|
||||||
|
this.$content.on("click", ".mind-elixir-toolbar.lt", () => {
|
||||||
|
this.spacedUpdate.scheduleUpdate();
|
||||||
|
});
|
||||||
|
|
||||||
super.doRender();
|
super.doRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +189,6 @@ export default class MindMapWidget extends TypeWidget {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#initLibrary();
|
|
||||||
await this.#loadData(note);
|
await this.#loadData(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,23 +198,27 @@ export default class MindMapWidget extends TypeWidget {
|
|||||||
|
|
||||||
async #loadData(note: FNote) {
|
async #loadData(note: FNote) {
|
||||||
const blob = await note.getBlob();
|
const blob = await note.getBlob();
|
||||||
const content = blob?.getJsonContent() || MindElixir.new(NEW_TOPIC_NAME);
|
const content = blob?.getJsonContent<MindmapModel>();
|
||||||
|
|
||||||
if (this.mind) {
|
if (!this.mind) {
|
||||||
this.mind.refresh(content);
|
await this.#initLibrary(content?.direction);
|
||||||
this.mind.toCenter();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.mind.refresh(content ?? this.MindElixir.new(NEW_TOPIC_NAME));
|
||||||
|
this.mind.toCenter();
|
||||||
}
|
}
|
||||||
|
|
||||||
#initLibrary() {
|
async #initLibrary(direction?: number) {
|
||||||
const mind = new MindElixir({
|
this.MindElixir = (await import("mind-elixir")).default;
|
||||||
|
|
||||||
|
const mind = new this.MindElixir({
|
||||||
el: this.$content[0],
|
el: this.$content[0],
|
||||||
direction: MindElixir.LEFT
|
direction: direction ?? this.MindElixir.LEFT
|
||||||
});
|
});
|
||||||
mind.install(nodeMenu);
|
mind.install(nodeMenu);
|
||||||
|
|
||||||
this.mind = mind;
|
this.mind = mind;
|
||||||
mind.init(MindElixir.new(NEW_TOPIC_NAME));
|
mind.init(this.MindElixir.new(NEW_TOPIC_NAME));
|
||||||
// TODO: See why the typeof mindmap is not correct.
|
// TODO: See why the typeof mindmap is not correct.
|
||||||
mind.bus.addListener("operation", (operation: { name: string }) => {
|
mind.bus.addListener("operation", (operation: { name: string }) => {
|
||||||
this.triggeredByUserOperation = true;
|
this.triggeredByUserOperation = true;
|
||||||
|
@ -61,27 +61,28 @@ describe("data_dir.ts unit tests", async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
describe("#getPlatformAppDataDir()", () => {
|
describe("#getPlatformAppDataDir()", () => {
|
||||||
type TestCaseGetPlatformAppDataDir = [description: string, fnValue: Parameters<typeof getPlatformAppDataDir>, expectedValueFn: (val: ReturnType<typeof getPlatformAppDataDir>) => boolean];
|
type TestCaseGetPlatformAppDataDir = [description: string, fnValue: Parameters<typeof getPlatformAppDataDir>, expectedValue: string | null, osHomedirMockValue: string | null];
|
||||||
|
|
||||||
const testCases: TestCaseGetPlatformAppDataDir[] = [
|
const testCases: TestCaseGetPlatformAppDataDir[] = [
|
||||||
["w/ unsupported OS it should return 'null'", ["aix", undefined], (val) => val === null],
|
["w/ unsupported OS it should return 'null'", ["aix", undefined], null, null],
|
||||||
|
|
||||||
["w/ win32 and no APPDATA set it should return 'null'", ["win32", undefined], (val) => val === null],
|
["w/ win32 and no APPDATA set it should return 'null'", ["win32", undefined], null, null],
|
||||||
|
|
||||||
["w/ win32 and set APPDATA it should return set 'APPDATA'", ["win32", "AppData"], (val) => val === "AppData"],
|
["w/ win32 and set APPDATA it should return set 'APPDATA'", ["win32", "AppData"], "AppData", null],
|
||||||
|
|
||||||
["w/ linux it should return '/.local/share'", ["linux", undefined], (val) => val !== null && val.endsWith("/.local/share")],
|
["w/ linux it should return '~/.local/share'", ["linux", undefined], "/home/mock/.local/share", "/home/mock"],
|
||||||
|
|
||||||
["w/ linux and wrongly set APPDATA it should ignore APPDATA and return /.local/share", ["linux", "FakeAppData"], (val) => val !== null && val.endsWith("/.local/share")],
|
["w/ linux and wrongly set APPDATA it should ignore APPDATA and return '~/.local/share'", ["linux", "FakeAppData"], "/home/mock/.local/share", "/home/mock"],
|
||||||
|
|
||||||
["w/ darwin it should return /Library/Application Support", ["darwin", undefined], (val) => val !== null && val.endsWith("/Library/Application Support")]
|
["w/ darwin it should return '~/Library/Application Support'", ["darwin", undefined], "/Users/mock/Library/Application Support", "/Users/mock"]
|
||||||
];
|
];
|
||||||
|
|
||||||
testCases.forEach((testCase) => {
|
testCases.forEach((testCase) => {
|
||||||
const [testDescription, value, isExpected] = testCase;
|
const [testDescription, fnValues, expected, osHomedirMockValue] = testCase;
|
||||||
return it(testDescription, () => {
|
return it(testDescription, () => {
|
||||||
const actual = getPlatformAppDataDir(...value);
|
mockFn.osHomedirMock.mockReturnValue(osHomedirMockValue);
|
||||||
const result = isExpected(actual);
|
const actual = getPlatformAppDataDir(...fnValues);
|
||||||
expect(result).toBeTruthy();
|
expect(actual).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user