Refactor persistent data storage code and add button to wipe data on crash (#827)

* Organize persistence.ts

* Switch to simpler promise handling

* Switch document list storage from localStorage to IndexedDB

* Track document auto-save status to avoid re-auto-saving unnecessarily

* Add button to clear storage on crash

* Bump document version and test file

* Switch to IDB-Keyval instead of raw IDB transactions
This commit is contained in:
Keavon Chambers
2022-11-02 15:19:04 -07:00
parent 73233169b2
commit 9d56e86203
16 changed files with 183 additions and 187 deletions

File diff suppressed because one or more lines are too long

View File

@@ -74,7 +74,7 @@ pub const DEFAULT_FONT_FAMILY: &str = "Merriweather";
pub const DEFAULT_FONT_STYLE: &str = "Normal (400)";
// Document
pub const GRAPHITE_DOCUMENT_VERSION: &str = "0.0.14"; // Remember to save a simple document and replace the test file `graphite-test-document.graphite`
pub const GRAPHITE_DOCUMENT_VERSION: &str = "0.0.15"; // Remember to save a simple document and replace the test file `graphite-test-document.graphite`
pub const DEFAULT_DOCUMENT_NAME: &str = "Untitled Document";
pub const FILE_SAVE_SUFFIX: &str = ".graphite";

View File

@@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize};
#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)]
pub struct FrontendDocumentDetails {
#[serde(rename = "isAutoSaved")]
pub is_auto_saved: bool,
#[serde(rename = "isSaved")]
pub is_saved: bool,
pub name: String,

View File

@@ -37,6 +37,7 @@ use serde::{Deserialize, Serialize};
pub struct DocumentMessageHandler {
pub graphene_document: GrapheneDocument,
pub saved_document_identifier: u64,
pub auto_saved_document_identifier: u64,
pub name: String,
pub version: String,
@@ -68,6 +69,7 @@ impl Default for DocumentMessageHandler {
Self {
graphene_document: GrapheneDocument::default(),
saved_document_identifier: 0,
auto_saved_document_identifier: 0,
name: String::from("Untitled Document"),
version: GRAPHITE_DOCUMENT_VERSION.to_string(),
@@ -1354,10 +1356,22 @@ impl DocumentMessageHandler {
.unwrap_or(0)
}
pub fn is_auto_saved(&self) -> bool {
self.current_identifier() == self.auto_saved_document_identifier
}
pub fn is_saved(&self) -> bool {
self.current_identifier() == self.saved_document_identifier
}
pub fn set_auto_save_state(&mut self, is_saved: bool) {
if is_saved {
self.auto_saved_document_identifier = self.current_identifier();
} else {
self.auto_saved_document_identifier = generate_uuid();
}
}
pub fn set_save_state(&mut self, is_saved: bool) {
if is_saved {
self.saved_document_identifier = self.current_identifier();

View File

@@ -92,6 +92,7 @@ pub enum PortfolioMessage {
OpenDocumentFileWithId {
document_id: u64,
document_name: String,
document_is_auto_saved: bool,
document_is_saved: bool,
document_serialized_content: String,
},

View File

@@ -49,6 +49,9 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
}
PortfolioMessage::AutoSaveActiveDocument => {
if let Some(document_id) = self.active_document_id {
if let Some(document) = self.active_document_mut() {
document.set_auto_save_state(true);
}
responses.push_back(PortfolioMessage::AutoSaveDocument { document_id }.into());
}
}
@@ -58,6 +61,7 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
FrontendMessage::TriggerIndexedDbWriteDocument {
document: document.serialize_document(),
details: FrontendDocumentDetails {
is_auto_saved: document.is_auto_saved(),
is_saved: document.is_saved(),
id: document_id,
name: document.name.clone(),
@@ -93,24 +97,15 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
if self.document_ids.is_empty() {
self.active_document_id = None;
} else if Some(document_id) == self.active_document_id {
if document_index == self.document_ids.len() {
} else if self.active_document_id.is_some() {
let document_id = if document_index == self.document_ids.len() {
// If we closed the last document take the one previous (same as last)
responses.push_back(
PortfolioMessage::SelectDocument {
document_id: *self.document_ids.last().unwrap(),
}
.into(),
);
*self.document_ids.last().unwrap()
} else {
// Move to the next tab
responses.push_back(
PortfolioMessage::SelectDocument {
document_id: self.document_ids[document_index],
}
.into(),
);
}
self.document_ids[document_index]
};
responses.push_back(PortfolioMessage::SelectDocument { document_id }.into());
}
// Send the new list of document tab names
@@ -282,6 +277,7 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
PortfolioMessage::OpenDocumentFileWithId {
document_id: generate_uuid(),
document_name,
document_is_auto_saved: false,
document_is_saved: true,
document_serialized_content,
}
@@ -291,12 +287,14 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
PortfolioMessage::OpenDocumentFileWithId {
document_id,
document_name,
document_is_auto_saved,
document_is_saved,
document_serialized_content,
} => {
let document = DocumentMessageHandler::with_name_and_content(document_name, document_serialized_content);
match document {
Ok(mut document) => {
document.set_auto_save_state(document_is_auto_saved);
document.set_save_state(document_is_saved);
self.load_document(document, document_id, responses);
}
@@ -417,10 +415,10 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
}
PortfolioMessage::SelectDocument { document_id } => {
if let Some(document) = self.active_document() {
if !document.is_saved() {
// Safe to unwrap since we know that there is an active document
if !document.is_auto_saved() {
responses.push_back(
PortfolioMessage::AutoSaveDocument {
// Safe to unwrap since we know that there is an active document
document_id: self.active_document_id.unwrap(),
}
.into(),
@@ -472,10 +470,11 @@ impl MessageHandler<PortfolioMessage, (&InputPreprocessorMessageHandler, &Prefer
.document_ids
.iter()
.filter_map(|id| {
self.documents.get(id).map(|doc| FrontendDocumentDetails {
is_saved: doc.is_saved(),
self.documents.get(id).map(|document| FrontendDocumentDetails {
is_auto_saved: document.is_auto_saved(),
is_saved: document.is_saved(),
id: *id,
name: doc.name.clone(),
name: document.name.clone(),
})
})
.collect::<Vec<_>>();