Make the document auto-save system initially restore the last-viewed tab before loading the rest (#2194)

* Fixes last tab being opened instead of last active tab

Fixes https://discord.com/channels/731730685944922173/881073965047636018/937518022548131891

* Defers node initialisation to SelectDocument message instead of load_document

* Fix warning regarding attempt to load closed document

* Defer loading resources and running nodes to selection time

* Make last active tab load before others

* Load last active saved document instead of last autosaved doc

* Fix failing tests

* Code review

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
mTvare
2025-01-25 06:41:47 +00:00
committed by GitHub
co-authored by Keavon Chambers
parent de36d4967d
commit 9954e49530
9 changed files with 153 additions and 32 deletions
+93 -8
View File
@@ -2,7 +2,15 @@ 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, TriggerLoadAutoSaveDocuments, TriggerLoadPreferences } from "@graphite/messages";
import {
TriggerIndexedDbWriteDocument,
TriggerIndexedDbRemoveDocument,
TriggerSavePreferences,
TriggerLoadPreferences,
TriggerLoadFirstAutoSaveDocument,
TriggerLoadRestAutoSaveDocuments,
TriggerSaveActiveDocument,
} from "@graphite/messages";
import { type PortfolioState } from "@graphite/state-providers/portfolio";
const graphiteStore = createStore("graphite", "store");
@@ -12,10 +20,13 @@ export function createPersistenceManager(editor: Editor, portfolio: PortfolioSta
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",
@@ -28,6 +39,7 @@ export function createPersistenceManager(editor: Editor, portfolio: PortfolioSta
);
await storeDocumentOrder();
await storeCurrentDocumentId(autoSaveDocument.details.id);
}
async function removeDocument(id: string) {
@@ -41,19 +53,80 @@ export function createPersistenceManager(editor: Editor, portfolio: PortfolioSta
graphiteStore,
);
const documentCount = getFromStore(portfolio).documents.length;
if (documentCount > 0) {
const documentIndex = getFromStore(portfolio).activeDocumentIndex;
const documentId = getFromStore(portfolio).documents[documentIndex].id;
await storeCurrentDocumentId(String(documentId));
} else {
await del("current_document_id", graphiteStore);
}
await storeDocumentOrder();
}
async function loadDocuments() {
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]] : []));
orderedSavedDocuments?.forEach(async (doc: TriggerIndexedDbWriteDocument) => {
editor.handle.openAutoSavedDocument(BigInt(doc.details.id), doc.details.name, doc.details.isSaved, doc.document);
});
if (currentDocumentId) {
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));
}
}
}
// PREFERENCES
@@ -84,12 +157,24 @@ export function createPersistenceManager(editor: Editor, portfolio: PortfolioSta
editor.subscriptions.subscribeJsMessage(TriggerIndexedDbRemoveDocument, async (removeAutoSaveDocument) => {
await removeDocument(removeAutoSaveDocument.documentId);
});
editor.subscriptions.subscribeJsMessage(TriggerLoadAutoSaveDocuments, async () => {
await loadDocuments();
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);
}
+11 -4
View File
@@ -768,7 +768,8 @@ export class UpdateMouseCursor extends JsMessage {
readonly cursor!: MouseCursorIcon;
}
export class TriggerLoadAutoSaveDocuments extends JsMessage {}
export class TriggerLoadFirstAutoSaveDocument extends JsMessage {}
export class TriggerLoadRestAutoSaveDocuments extends JsMessage {}
export class TriggerLoadPreferences extends JsMessage {}
@@ -807,6 +808,10 @@ export class TriggerSavePreferences extends JsMessage {
readonly preferences!: Record<string, unknown>;
}
export class TriggerSaveActiveDocument extends JsMessage {
readonly documentId!: bigint;
}
export class DocumentChanged extends JsMessage {}
export type DataBuffer = {
@@ -1574,10 +1579,12 @@ export const messageMakers: Record<string, MessageMaker> = {
TriggerImport,
TriggerIndexedDbRemoveDocument,
TriggerIndexedDbWriteDocument,
TriggerLoadAutoSaveDocuments,
TriggerLoadFirstAutoSaveDocument,
TriggerLoadPreferences,
TriggerLoadRestAutoSaveDocuments,
TriggerOpenDocument,
TriggerPaste,
TriggerSaveActiveDocument,
TriggerSavePreferences,
TriggerTextCommit,
TriggerTextCopy,
@@ -1597,14 +1604,14 @@ export const messageMakers: Record<string, MessageMaker> = {
UpdateDocumentModeLayout,
UpdateDocumentRulers,
UpdateDocumentScrollbars,
UpdateExportReorderIndex,
UpdateEyedropperSamplingState,
UpdateGraphFadeArtwork,
UpdateGraphViewOverlay,
UpdateImportReorderIndex,
UpdateImportsExports,
UpdateInputHints,
UpdateInSelectedNetwork,
UpdateExportReorderIndex,
UpdateImportReorderIndex,
UpdateLayersPanelControlBarLayout,
UpdateLayerWidths,
UpdateMenuBarLayout,