|
import { createStore, del, get, set, update } from "idb-keyval"; |
|
import { get as getFromStore } from "svelte/store"; |
|
|
|
import { type Editor } from "@graphite/editor"; |
|
import { |
|
TriggerIndexedDbWriteDocument, |
|
TriggerIndexedDbRemoveDocument, |
|
TriggerSavePreferences, |
|
TriggerLoadPreferences, |
|
TriggerLoadFirstAutoSaveDocument, |
|
TriggerLoadRestAutoSaveDocuments, |
|
TriggerSaveActiveDocument, |
|
} from "@graphite/messages"; |
|
import { type PortfolioState } from "@graphite/state-providers/portfolio"; |
|
|
|
const graphiteStore = createStore("graphite", "store"); |
|
|
|
export function createPersistenceManager(editor: Editor, portfolio: PortfolioState) { |
|
|
|
|
|
async function storeDocumentOrder() { |
|
const documentOrder = getFromStore(portfolio).documents.map((doc) => String(doc.id)); |
|
await set("documents_tab_order", documentOrder, graphiteStore); |
|
} |
|
|
|
async function storeCurrentDocumentId(documentId: string) { |
|
await set("current_document_id", String(documentId), graphiteStore); |
|
} |
|
|
|
async function storeDocument(autoSaveDocument: TriggerIndexedDbWriteDocument) { |
|
await update<Record<string, TriggerIndexedDbWriteDocument>>( |
|
"documents", |
|
(old) => { |
|
const documents = old || {}; |
|
documents[autoSaveDocument.details.id] = autoSaveDocument; |
|
return documents; |
|
}, |
|
graphiteStore, |
|
); |
|
|
|
await storeDocumentOrder(); |
|
await storeCurrentDocumentId(autoSaveDocument.details.id); |
|
} |
|
|
|
async function removeDocument(id: string) { |
|
await update<Record<string, TriggerIndexedDbWriteDocument>>( |
|
"documents", |
|
(old) => { |
|
const documents = old || {}; |
|
delete documents[id]; |
|
return documents; |
|
}, |
|
graphiteStore, |
|
); |
|
|
|
await update<string[]>( |
|
"documents_tab_order", |
|
(old) => { |
|
const order = old || []; |
|
return order.filter((docId) => docId !== id); |
|
}, |
|
graphiteStore, |
|
); |
|
|
|
const documentCount = getFromStore(portfolio).documents.length; |
|
if (documentCount > 0) { |
|
const documentIndex = getFromStore(portfolio).activeDocumentIndex; |
|
const documentId = String(getFromStore(portfolio).documents[documentIndex].id); |
|
|
|
const tabOrder = (await get<string[]>("documents_tab_order", graphiteStore)) || []; |
|
if (tabOrder.includes(documentId)) { |
|
await storeCurrentDocumentId(documentId); |
|
} |
|
} else { |
|
await del("current_document_id", graphiteStore); |
|
} |
|
} |
|
|
|
async function loadFirstDocument() { |
|
const previouslySavedDocuments = await get<Record<string, TriggerIndexedDbWriteDocument>>("documents", graphiteStore); |
|
const documentOrder = await get<string[]>("documents_tab_order", graphiteStore); |
|
const currentDocumentId = await get<string>("current_document_id", graphiteStore); |
|
if (!previouslySavedDocuments || !documentOrder) return; |
|
|
|
const orderedSavedDocuments = documentOrder.flatMap((id) => (previouslySavedDocuments[id] ? [previouslySavedDocuments[id]] : [])); |
|
|
|
if (currentDocumentId && currentDocumentId in previouslySavedDocuments) { |
|
const doc = previouslySavedDocuments[currentDocumentId]; |
|
editor.handle.openAutoSavedDocument(BigInt(doc.details.id), doc.details.name, doc.details.isSaved, doc.document, false); |
|
editor.handle.selectDocument(BigInt(currentDocumentId)); |
|
} else { |
|
const len = orderedSavedDocuments.length; |
|
if (len > 0) { |
|
const doc = orderedSavedDocuments[len - 1]; |
|
editor.handle.openAutoSavedDocument(BigInt(doc.details.id), doc.details.name, doc.details.isSaved, doc.document, false); |
|
editor.handle.selectDocument(BigInt(doc.details.id)); |
|
} |
|
} |
|
} |
|
|
|
async function loadRestDocuments() { |
|
const previouslySavedDocuments = await get<Record<string, TriggerIndexedDbWriteDocument>>("documents", graphiteStore); |
|
const documentOrder = await get<string[]>("documents_tab_order", graphiteStore); |
|
const currentDocumentId = await get<string>("current_document_id", graphiteStore); |
|
if (!previouslySavedDocuments || !documentOrder) return; |
|
|
|
const orderedSavedDocuments = documentOrder.flatMap((id) => (previouslySavedDocuments[id] ? [previouslySavedDocuments[id]] : [])); |
|
|
|
if (currentDocumentId) { |
|
const currentIndex = orderedSavedDocuments.findIndex((doc) => doc.details.id === currentDocumentId); |
|
const beforeCurrentIndex = currentIndex - 1; |
|
const afterCurrentIndex = currentIndex + 1; |
|
|
|
for (let i = beforeCurrentIndex; i >= 0; i--) { |
|
const { document, details } = orderedSavedDocuments[i]; |
|
const { id, name, isSaved } = details; |
|
editor.handle.openAutoSavedDocument(BigInt(id), name, isSaved, document, true); |
|
} |
|
for (let i = afterCurrentIndex; i < orderedSavedDocuments.length; i++) { |
|
const { document, details } = orderedSavedDocuments[i]; |
|
const { id, name, isSaved } = details; |
|
editor.handle.openAutoSavedDocument(BigInt(id), name, isSaved, document, false); |
|
} |
|
|
|
editor.handle.selectDocument(BigInt(currentDocumentId)); |
|
} else { |
|
const length = orderedSavedDocuments.length; |
|
|
|
for (let i = length - 2; i >= 0; i--) { |
|
const { document, details } = orderedSavedDocuments[i]; |
|
const { id, name, isSaved } = details; |
|
editor.handle.openAutoSavedDocument(BigInt(id), name, isSaved, document, true); |
|
} |
|
|
|
if (length > 0) { |
|
const id = orderedSavedDocuments[length - 1].details.id; |
|
editor.handle.selectDocument(BigInt(id)); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
async function savePreferences(preferences: TriggerSavePreferences["preferences"]) { |
|
await set("preferences", preferences, graphiteStore); |
|
} |
|
|
|
async function loadPreferences() { |
|
const preferences = await get<Record<string, unknown>>("preferences", graphiteStore); |
|
if (!preferences) return; |
|
|
|
editor.handle.loadPreferences(JSON.stringify(preferences)); |
|
} |
|
|
|
|
|
|
|
|
|
editor.subscriptions.subscribeJsMessage(TriggerSavePreferences, async (preferences) => { |
|
await savePreferences(preferences.preferences); |
|
}); |
|
editor.subscriptions.subscribeJsMessage(TriggerLoadPreferences, async () => { |
|
await loadPreferences(); |
|
}); |
|
editor.subscriptions.subscribeJsMessage(TriggerIndexedDbWriteDocument, async (autoSaveDocument) => { |
|
await storeDocument(autoSaveDocument); |
|
}); |
|
editor.subscriptions.subscribeJsMessage(TriggerIndexedDbRemoveDocument, async (removeAutoSaveDocument) => { |
|
await removeDocument(removeAutoSaveDocument.documentId); |
|
}); |
|
editor.subscriptions.subscribeJsMessage(TriggerLoadFirstAutoSaveDocument, async () => { |
|
await loadFirstDocument(); |
|
}); |
|
editor.subscriptions.subscribeJsMessage(TriggerLoadRestAutoSaveDocuments, async () => { |
|
await loadRestDocuments(); |
|
}); |
|
editor.subscriptions.subscribeJsMessage(TriggerSaveActiveDocument, async (triggerSaveActiveDocument) => { |
|
const documentId = String(triggerSaveActiveDocument.documentId); |
|
const previouslySavedDocuments = await get<Record<string, TriggerIndexedDbWriteDocument>>("documents", graphiteStore); |
|
if (!previouslySavedDocuments) return; |
|
if (documentId in previouslySavedDocuments) { |
|
await storeCurrentDocumentId(documentId); |
|
} |
|
}); |
|
} |
|
|
|
export async function wipeDocuments() { |
|
await del("documents_tab_order", graphiteStore); |
|
await del("current_document_id", graphiteStore); |
|
await del("documents", graphiteStore); |
|
} |
|
|