Repository navigation
2.4 Saved Library and Folders
Relevant source files
The following files were used as context for generating this wiki page:
The VariantScope persistence layer manages the user's saved gene library, associated cached API responses, and a hierarchical folder organization system designed for desktop deployments. This subsystem guarantees that loaded genes can be inspected offline, sorted, analyzed for disk consumption, and organized into user-defined categories without mutating underlying raw data.
The library module (src/core/library.js) maintains a registry of all genes previously loaded and saved by the user. Each entry records metadata extracted from completed pipeline runs, allowing the home page and library views to render summaries instantly without triggering new network requests.
The library is stored under the 'library' key using the underlying caching abstraction src/core/library.js:7-19. The schema maps official gene symbols to a summary object structure containing query aliases, timestamps, partial-load flags, and summary statistics src/core/library.js:23-45.
Key functions driving library management include:
-
readAll()andwriteAll(): Read and write the library dictionary payload viacacheGetandcacheSetsrc/core/library.js:11-19. -
recordGene(result, typedSymbol, now): Appends or updates a gene entry upon successful load, merging any typed query aliases (groupFor(typedSymbol)) and tracking whether data sources failed (markingpartial: true) src/core/library.js:23-45. -
removeFromLibrary(symbol): Deletes an entry from the library index and returns it for cascading data cleanup src/core/library.js:53-61. -
sizeOfEntry(entry, saved): Calculates total byte consumption for a given entry by intersecting its group associations with disk or local storage metrics src/core/library.js:74-77. -
sortEntries(entries, key, sizes): Sorts library entries according to'recent','oldest','name', or'size'dimensions src/core/library.js:86-94.
graph TD
sub5["User Action / Pipeline Load"] --> rec["recordGene(result, typedSymbol)"]
rec --> read["readAll()"]
read --> cacheGet["cacheGet('library')"]
cacheGet --> merge["Merge Aliases & Freshness"]
merge --> writeAll["writeAll(all)"]
writeAll --> cacheSet["cacheSet('library', all, null)"]
style rec fill:none,stroke:#000,stroke-width:2px
style read fill:none,stroke:#000,stroke-width:2px
style writeAll fill:none,stroke:#000,stroke-width:2px
Sources: src/core/library.js:7-45, src/core/cache.js:1-1.
Desktop deployments support a nested folder structure for organizing saved genes on the home page. Folders are strictly logical labels; placing a gene in a folder alters its placement mapping rather than duplicating or moving physical gene records src/core/folders.js:1-5.
The folder state shape is defined as { folders: {id: {id, name, parent}}, placement: {SYMBOL: [folderId, ...]} } src/core/folders.js:3. Top-level folders have a parent value of null src/core/folders.js:4.
To maintain system stability and keep saved states lightweight, strict structural boundaries are enforced:
-
MAX_DEPTH = 6: Maximum nesting level (depth 1is top-level) src/core/folders.js:8. -
MAX_NAME = 40: Maximum characters allowed in a folder name src/core/folders.js:9. -
MAX_FOLDERS = 200: Total aggregate folder limit src/core/folders.js:10. -
ID_PATTERN = /^f[0-9a-f]{12}$/: UUID-derived identifier format generated vianewFolderId()src/core/folders.js:12-22.
The module src/core/folders.js exposes pure state transformation functions that return immutable copies of the state tree:
-
createFolder(state, name, parentId, newId): Validates name constraints, depth limits, and duplicates, then appends the new node src/core/folders.js:135-149. -
renameFolder(state, id, name): Validates uniqueness constraints within the target parent scope and updates the label src/core/folders.js:157-165. -
folderMoveError(state, id, toParent): Detects circular nesting paths, missing targets, or depth overflows prior to relocation src/core/folders.js:168-177. -
flatFolders(state, skip): Flattens the hierarchy into a depth-first traversal array ([{folder, depth, label}]) for pickers and dropdowns src/core/folders.js:102-119.
Storage persistence for folders is handled exclusively by src/core/folderStore.js, which reads and writes the folder state payload under the 'folders' cache key without an expiration TTL src/core/folderStore.js:1-17.
graph TD
sub2["folderStore.js & folders.js Mapping"] --> load["loadFolders()"]
load --> cacheGet["cacheGet('folders')"]
cacheGet --> sanitize["sanitizeFolders(data)"]
sanitize --> state["State Object: {folders, placement}"]
state --> pure1["createFolder(state, name, parentId)"]
state --> pure2["renameFolder(state, id, name)"]
state --> pure3["moveFolder(state, id, toParent)"]
pure1 --> save["saveFolders(newState)"]
pure2 --> save
pure3 --> save
save --> cacheSet["cacheSet('folders', newState, null)"]
style load fill:none,stroke:#000,stroke-width:2px
style sanitize fill:none,stroke:#000,stroke-width:2px
style pure1 fill:none,stroke:#000,stroke-width:2px
style save fill:none,stroke:#000,stroke-width:2px
Sources: src/core/folderStore.js:1-17, src/core/folders.js:14-177
The saved.js module bridges platform-specific storage mechanisms, decoupling the UI from whether data resides in browser localStorage or the Electron desktop disk cache src/core/saved.js:1-5.
-
listSaved(): Dispatches towindow.api.listCache()when running inside Electron, or falls back tocacheListGroups()in web environments, returning a list of objects detailing storage consumption per gene tag ([{group, bytes, entries}]) src/core/saved.js:7-9. -
deleteSaved(target): Invokeswindow.api.deleteCache(target)orcacheDeleteGroups(target)to purge specific gene groups or execute a complete storage wipe (target === 'all') src/core/saved.js:11-14.
graph TD
sub3["UI Invocation"] --> check["isElectron()"]
check -->|True| electronAPI["window.api.listCache() / deleteCache()"]
check -->|False| browserCache["cacheListGroups() / cacheDeleteGroups()"]
electronAPI --> disk["Electron Main Process Disk Cache"]
browserCache --> lstorage["Browser localStorage Cache"]
style check fill:none,stroke:#000,stroke-width:2px
style electronAPI fill:none,stroke:#000,stroke-width:2px
style browserCache fill:none,stroke:#000,stroke-width:2px
Sources: src/core/saved.js:1-15, src/core/http.js:1-1
Content imported from DeepWiki.