From 0c8b93f3e4fd0dff09ffdee674b9f48c87fad186 Mon Sep 17 00:00:00 2001 From: yenthefromghent Date: Mon, 18 May 2026 16:53:15 +0200 Subject: [PATCH 1/4] core: Added VirtualLazyFolder --- .../features/virtual-drive/folder/index.ts | 3 +- .../virtual-drive/folder/virtualLazyFolder.ts | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 packages/core/src/features/virtual-drive/folder/virtualLazyFolder.ts diff --git a/packages/core/src/features/virtual-drive/folder/index.ts b/packages/core/src/features/virtual-drive/folder/index.ts index a70c8df5b..326d4586f 100644 --- a/packages/core/src/features/virtual-drive/folder/index.ts +++ b/packages/core/src/features/virtual-drive/folder/index.ts @@ -1,2 +1,3 @@ export * from "./virtualFolder"; -export * from "./virtualFolderLink"; \ No newline at end of file +export * from "./virtualFolderLink"; +export * from "./virtualLazyFolder"; \ No newline at end of file diff --git a/packages/core/src/features/virtual-drive/folder/virtualLazyFolder.ts b/packages/core/src/features/virtual-drive/folder/virtualLazyFolder.ts new file mode 100644 index 000000000..99bcb91c7 --- /dev/null +++ b/packages/core/src/features/virtual-drive/folder/virtualLazyFolder.ts @@ -0,0 +1,40 @@ +import { VirtualBase, VirtualBaseEvents } from "../virtualBase"; +import { VirtualFile } from "../file"; +import { VirtualFolder } from "./virtualFolder"; + +export class VirtualLazyFolder extends VirtualFolder { + private hasPopulated = false; + + constructor(name: string, type?: number) { + super(name, type); + } + + /** + * Override this method to populate the folder with files and sub-folders. + * Called once, the first time the folder's contents are requested. + */ + onPopulate(): Promise { + return Promise.resolve(); + } + + private triggerPopulate() { + if (this.hasPopulated) + return; + + this.hasPopulated = true; + + this.onPopulate().then(() => { + this.emit(VirtualBase.UPDATE_EVENT); + }); + } + + getFiles(showHidden = false): VirtualFile[] { + this.triggerPopulate(); + return super.getFiles(showHidden); + } + + getSubFolders(showHidden = false): VirtualFolder[] { + this.triggerPopulate(); + return super.getSubFolders(showHidden); + } +} \ No newline at end of file From 6b8de67f97ca0c6ac770659275673084483d537e Mon Sep 17 00:00:00 2001 From: yenthefromghent Date: Wed, 20 May 2026 10:52:09 +0200 Subject: [PATCH 2/4] feat: Async version for getFiles() and getSubFolders() --- .../virtual-drive/folder/virtualFolder.ts | 14 ++++++++++++++ .../virtual-drive/folder/virtualLazyFolder.ts | 19 +++++++++++-------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/packages/core/src/features/virtual-drive/folder/virtualFolder.ts b/packages/core/src/features/virtual-drive/folder/virtualFolder.ts index ba87caa19..691ac98f8 100644 --- a/packages/core/src/features/virtual-drive/folder/virtualFolder.ts +++ b/packages/core/src/features/virtual-drive/folder/virtualFolder.ts @@ -370,6 +370,10 @@ export class VirtualFolder exte this.confirmChanges(); } + async loadContent(): Promise { + return Promise.resolve() + } + /** * Returns all files inside this folder. * @param showHidden - Whether to include hidden files. @@ -383,6 +387,11 @@ export class VirtualFolder exte ); } + async getFilesAsync(showHidden = false): Promise { + await this.loadContent(); + return this.getFiles(showHidden); + } + /** * Returns all sub-folders inside this folder. * @param showHidden - Whether to include hidden folders. @@ -396,6 +405,11 @@ export class VirtualFolder exte ); } + async getSubFoldersAsync(showHidden = false): Promise { + await this.loadContent(); + return this.getSubFolders(showHidden); + } + /** * Returns the amount of files and sub-folders inside this folder. * @param includeHidden - Whether to include hidden files and folders in the count. diff --git a/packages/core/src/features/virtual-drive/folder/virtualLazyFolder.ts b/packages/core/src/features/virtual-drive/folder/virtualLazyFolder.ts index 99bcb91c7..de96461ce 100644 --- a/packages/core/src/features/virtual-drive/folder/virtualLazyFolder.ts +++ b/packages/core/src/features/virtual-drive/folder/virtualLazyFolder.ts @@ -4,6 +4,7 @@ import { VirtualFolder } from "./virtualFolder"; export class VirtualLazyFolder extends VirtualFolder { private hasPopulated = false; + private content: Promise = Promise.resolve() constructor(name: string, type?: number) { super(name, type); @@ -17,24 +18,26 @@ export class VirtualLazyFolder return Promise.resolve(); } - private triggerPopulate() { - if (this.hasPopulated) - return; + async loadContent(): Promise { + if (this.hasPopulated) { + return this.content + } - this.hasPopulated = true; - - this.onPopulate().then(() => { + this.hasPopulated = true + this.content = this.onPopulate().then(() => { this.emit(VirtualBase.UPDATE_EVENT); }); + + return this.content } getFiles(showHidden = false): VirtualFile[] { - this.triggerPopulate(); + this.loadContent(); return super.getFiles(showHidden); } getSubFolders(showHidden = false): VirtualFolder[] { - this.triggerPopulate(); + this.loadContent(); return super.getSubFolders(showHidden); } } \ No newline at end of file From bc194e31499bd768e57ec319d1d0be91e193791c Mon Sep 17 00:00:00 2001 From: yenthefromghent Date: Wed, 20 May 2026 11:51:07 +0200 Subject: [PATCH 3/4] bugfix: fixed loadContent() always returning new promise --- .../core/src/features/virtual-drive/folder/virtualLazyFolder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/features/virtual-drive/folder/virtualLazyFolder.ts b/packages/core/src/features/virtual-drive/folder/virtualLazyFolder.ts index de96461ce..852320241 100644 --- a/packages/core/src/features/virtual-drive/folder/virtualLazyFolder.ts +++ b/packages/core/src/features/virtual-drive/folder/virtualLazyFolder.ts @@ -18,7 +18,7 @@ export class VirtualLazyFolder return Promise.resolve(); } - async loadContent(): Promise { + loadContent(): Promise { if (this.hasPopulated) { return this.content } From cd392bc95224373337f8cceac5ef2cb2532551c2 Mon Sep 17 00:00:00 2001 From: yenthefromghent Date: Wed, 20 May 2026 11:51:23 +0200 Subject: [PATCH 4/4] test: Added test for VirtualLazyFolder --- .../virtual-drive/virtualDrive.utils.ts | 26 +++++++++++++++- .../virtual-drive/virtualLazyFolder.test.ts | 30 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 packages/core/test/features/virtual-drive/virtualLazyFolder.test.ts diff --git a/packages/core/test/features/virtual-drive/virtualDrive.utils.ts b/packages/core/test/features/virtual-drive/virtualDrive.utils.ts index 208ddbdc9..e1c1c5f16 100644 --- a/packages/core/test/features/virtual-drive/virtualDrive.utils.ts +++ b/packages/core/test/features/virtual-drive/virtualDrive.utils.ts @@ -1,4 +1,4 @@ -import { SystemManager, VirtualBase, VirtualFile, VirtualFolder, VirtualRoot } from "../../../src/features"; +import { SystemManager, VirtualBase, VirtualFile, VirtualFolder, VirtualRoot, VirtualLazyFolder } from "../../../src/features"; export class MockVirtualFile extends VirtualFile { @@ -31,4 +31,28 @@ export class MockVirtualRoot extends VirtualRoot { this.init(); } +} + +export class MockVirtualLazyFolder extends VirtualLazyFolder { + private resolve!: () => void; + readonly populated: Promise; + private onPopulateCallback: (Folder: MockVirtualLazyFolder) => void + + constructor(name: string, onPopulateCallback: (Folder: MockVirtualLazyFolder) => void = () => {}) { + super(name); + this.onPopulateCallback = onPopulateCallback + this.populated = new Promise((resolve) => { + this.resolve = resolve; + }); + } + + override onPopulate(): Promise { + return this.populated.then(() =>{ + this.onPopulateCallback(this) + }) + } + + completePopulation() { + this.resolve(); + } } \ No newline at end of file diff --git a/packages/core/test/features/virtual-drive/virtualLazyFolder.test.ts b/packages/core/test/features/virtual-drive/virtualLazyFolder.test.ts new file mode 100644 index 000000000..800ab2cbb --- /dev/null +++ b/packages/core/test/features/virtual-drive/virtualLazyFolder.test.ts @@ -0,0 +1,30 @@ +import { test as base, expect } from "vitest"; +import { extend } from "@prozilla-os/dev-tools"; +import { VirtualLazyFolder } from "../../../dist/main"; +import { MockVirtualFile, MockVirtualLazyFolder } from "./virtualDrive.utils"; +import { beforeEach } from "vitest"; + +const test = extend(base) + +let mockVirtualLazyFolder: MockVirtualLazyFolder; + +beforeEach(() => { + mockVirtualLazyFolder = new MockVirtualLazyFolder("foo", (f) => { + f.addFile(new MockVirtualFile("test", "txt")); + }); +}); + +test("getFilesAsync()", async () => { + const mockFilesPromise = mockVirtualLazyFolder.getFilesAsync(); + expect(mockVirtualLazyFolder.getFiles()).toStrictEqual([]); + + mockVirtualLazyFolder.completePopulation(); + const mockFiles = await mockFilesPromise; + expect(mockFiles).toHaveLength(1) +}); + +test("onPopulate", async () => { + const mockPromise1 = mockVirtualLazyFolder.loadContent() + const mockPromise2 = mockVirtualLazyFolder.loadContent() + expect(mockPromise1).toBe(mockPromise2); +}); \ No newline at end of file