Refactor IndexedDB document persistence to reuse data structures of desktop persistence (#4020)

* Switch indexedDb document serialized struct from camelCase to snake_case

* Refactor and migrate old indexedDb format to the same shape as desktop persistence

* Avoid duplicate struct definitions in the desktop crate

* Refactor frontend message handling to consolidate auto-save document loading

* Code review

* Review

---------

Co-authored-by: Timon <me@timon.zip>
This commit is contained in:
Keavon Chambers
2026-04-15 02:29:23 -07:00
committed by GitHub
parent 79d778a535
commit 60f16d72a5
11 changed files with 345 additions and 295 deletions

View File

@@ -123,8 +123,7 @@ pub enum FrontendMessage {
document: String,
details: DocumentDetails,
},
TriggerLoadFirstAutoSaveDocument,
TriggerLoadRestAutoSaveDocuments,
TriggerLoadAutoSaveDocuments,
TriggerOpenLaunchDocuments,
TriggerLoadPreferences,
TriggerLoadWorkspaceLayout,

View File

@@ -15,12 +15,29 @@ pub struct OpenDocument {
pub struct DocumentDetails {
pub name: String,
pub path: Option<PathBuf>,
#[serde(rename = "isSaved")]
#[serde(alias = "isSaved")]
pub is_saved: bool,
#[serde(rename = "isAutoSaved")]
#[serde(alias = "isAutoSaved")]
pub is_auto_saved: bool,
}
#[cfg_attr(feature = "wasm", derive(tsify::Tsify), tsify(large_number_types_as_bigints))]
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct PersistedDocumentInfo {
pub id: DocumentId,
pub name: String,
#[serde(default)]
pub path: Option<PathBuf>,
pub is_saved: bool,
}
#[cfg_attr(feature = "wasm", derive(tsify::Tsify), tsify(large_number_types_as_bigints))]
#[derive(Clone, Debug, Default, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct PersistedState {
pub documents: Vec<PersistedDocumentInfo>,
pub current_document: Option<DocumentId>,
}
#[cfg_attr(feature = "wasm", derive(tsify::Tsify))]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum MouseCursorIcon {

View File

@@ -109,8 +109,11 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
// Before loading any documents, initially prepare the welcome screen buttons layout
responses.add(PortfolioMessage::RequestWelcomeScreenButtonsLayout);
// Tell frontend to load the current document
responses.add(FrontendMessage::TriggerLoadFirstAutoSaveDocument);
// Tell frontend to load persistent auto-saved documents (placed early so IndexedDB reads overlap with subsequent UI setup)
responses.add(FrontendMessage::TriggerLoadAutoSaveDocuments);
// Tell frontend to load documents passed in as launch arguments
responses.add(FrontendMessage::TriggerOpenLaunchDocuments);
// Display the menu bar at the top of the window
responses.add(MenuBarMessage::SendLayout);
@@ -118,11 +121,8 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
// Send the initial workspace panel layout to the frontend
responses.add(PortfolioMessage::UpdateWorkspacePanelLayout);
// Send the information for tooltips and categories for each node/input.
responses.add(FrontendMessage::SendUIMetadata {
node_descriptions: document_node_definitions::collect_node_descriptions(),
node_types: document_node_definitions::collect_node_types(),
});
// Request status bar info layout
responses.add(PortfolioMessage::RequestStatusBarInfoLayout);
// Send shortcuts for widgets created in the frontend which need shortcut tooltips
responses.add(FrontendMessage::SendShortcutFullscreen {
@@ -136,14 +136,11 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
shortcut: action_shortcut_manual!(Key::Shift, Key::MouseLeft),
});
// Request status bar info layout
responses.add(PortfolioMessage::RequestStatusBarInfoLayout);
// Tell frontend to finish loading persistent documents
responses.add(FrontendMessage::TriggerLoadRestAutoSaveDocuments);
// Tell frontend to load documented passed in as launch arguments
responses.add(FrontendMessage::TriggerOpenLaunchDocuments);
// Send the information for tooltips and categories for each node/input.
responses.add(FrontendMessage::SendUIMetadata {
node_descriptions: document_node_definitions::collect_node_descriptions(),
node_types: document_node_definitions::collect_node_types(),
});
}
PortfolioMessage::DocumentPassMessage { document_id, message } => {
if let Some(document) = self.documents.get_mut(&document_id) {