diff --git a/pxteditor/history.ts b/pxteditor/history.ts index 7a0da9d74d5..e51f2df77a7 100644 --- a/pxteditor/history.ts +++ b/pxteditor/history.ts @@ -375,6 +375,51 @@ namespace pxt.workspace { toWrite[pxt.HISTORY_FILE] = JSON.stringify(history); } + export function pushSnapshotOnHistory(text: ScriptText, currentTime: number) { + let history: pxt.workspace.HistoryFile; + + if (text[pxt.HISTORY_FILE]) { + history = pxt.workspace.parseHistoryFile(text[pxt.HISTORY_FILE]); + } + else { + history = { + entries: [], + snapshots: [], + shares: [] + }; + } + + history.snapshots.push(takeSnapshot(text, currentTime)); + + text[pxt.HISTORY_FILE] = JSON.stringify(history); + } + + export function updateShareHistory(text: ScriptText, currentTime: number, shares: PublishVersion[]) { + let history: pxt.workspace.HistoryFile; + + if (text[pxt.HISTORY_FILE]) { + history = pxt.workspace.parseHistoryFile(text[pxt.HISTORY_FILE]); + } + else { + history = { + entries: [], + snapshots: [], + shares: [] + }; + } + + for (const share of shares) { + if (!history.shares.some(s => s.id === share.id)) { + history.shares.push({ + id: share.id, + timestamp: currentTime, + }); + } + } + + text[pxt.HISTORY_FILE] = JSON.stringify(history); + } + function takeSnapshot(text: ScriptText, time: number) { return { timestamp: time, diff --git a/webapp/src/dialogs.tsx b/webapp/src/dialogs.tsx index 23c8b1d092d..ba26a1c6a6b 100644 --- a/webapp/src/dialogs.tsx +++ b/webapp/src/dialogs.tsx @@ -872,6 +872,7 @@ export async function showTurnBackTimeDialogAsync(header: pxt.workspace.Header, header.targetVersion = editorVersion; + await workspace.saveSnapshotAsync(header.id); await workspace.saveAsync(header, text); reloadHeader(); } diff --git a/webapp/src/workspace.ts b/webapp/src/workspace.ts index 57ee453c84d..6824a0abe59 100644 --- a/webapp/src/workspace.ts +++ b/webapp/src/workspace.ts @@ -306,6 +306,49 @@ export async function getTextAsync(id: string, getSavedText = false): Promise { + await enqueueHistoryOperationAsync( + id, + text => { + pxt.workspace.pushSnapshotOnHistory(text, Date.now()) + } + ); +} + +export async function updateShareHistoryAsync(id: string): Promise { + await enqueueHistoryOperationAsync( + id, + (text, header) => { + pxt.workspace.updateShareHistory(text, Date.now(), header.pubVersions || []) + } + ); +} + +async function enqueueHistoryOperationAsync(id: string, op: (text: ScriptText, header: Header) => void) { + await maybeSyncHeadersAsync(); + + const e = lookup(id); + + if (!e) return; + + await headerQ.enqueue(id, async () => { + const saved = await impl.getAsync(e.header); + + const h = saved.header; + + op(saved.text, h); + + const ver = await impl.setAsync(h, saved.version, saved.text); + e.version = ver; + + data.invalidate("text:" + h.id); + data.invalidate("pkg-git-status:" + h.id); + data.invalidateHeader("header", h); + + refreshHeadersSession(); + }); +} + export interface ScriptMeta { description: string; blocksWidth?: number; @@ -343,46 +386,48 @@ function getScriptRequest(h: Header, text: ScriptText, meta: ScriptMeta, screens } // https://github.com/Microsoft/pxt-backend/blob/master/docs/sharing.md#anonymous-publishing -export function anonymousPublishAsync(h: Header, text: ScriptText, meta: ScriptMeta, screenshotUri?: string) { +export async function anonymousPublishAsync(h: Header, text: ScriptText, meta: ScriptMeta, screenshotUri?: string) { checkHeaderSession(h); const saveId = {} h.saveId = saveId const scrReq = getScriptRequest(h, text, meta, screenshotUri) + pxt.debug(`publishing script; ${scrReq.text.length} bytes`) - return Cloud.privatePostAsync("scripts", scrReq, /* forceLiveEndpoint */ true) - .then((inf: Cloud.JsonScript) => { - if (!h.pubVersions) h.pubVersions = []; - h.pubVersions.push({ id: inf.id, type: "snapshot" }); - if (inf.shortid) inf.id = inf.shortid; - h.pubId = inf.shortid - h.pubCurrent = h.saveId === saveId - h.meta = inf.meta; - pxt.debug(`published; id /${h.pubId}`) - return saveAsync(h) - .then(() => inf) - }) + const inf = await Cloud.privatePostAsync("scripts", scrReq, /* forceLiveEndpoint */ true) as Cloud.JsonScript; + if (!h.pubVersions) h.pubVersions = []; + h.pubVersions.push({ id: inf.id, type: "snapshot" }); + if (inf.shortid) inf.id = inf.shortid; + h.pubId = inf.shortid + h.pubCurrent = h.saveId === saveId + h.meta = inf.meta; + pxt.debug(`published; id /${h.pubId}`) + + await saveAsync(h); + await updateShareHistoryAsync(h.id); + return inf; } -export function persistentPublishAsync(h: Header, text: ScriptText, meta: ScriptMeta, screenshotUri?: string) { +export async function persistentPublishAsync(h: Header, text: ScriptText, meta: ScriptMeta, screenshotUri?: string) { checkHeaderSession(h); const saveId = {} h.saveId = saveId const scrReq = getScriptRequest(h, text, meta, screenshotUri) pxt.debug(`publishing script; ${scrReq.text.length} bytes`) - return cloud.shareAsync(h.id, scrReq) - .then((resp: { shareID: string, scr: cloud.SharedCloudProject }) => { - const { shareID, scr: script } = resp; - if (!h.pubVersions) h.pubVersions = []; - h.pubVersions.push({ id: script.id, type: "permalink" }); - h.pubId = shareID - h.pubCurrent = h.saveId === saveId - h.pubPermalink = shareID; - h.meta = script.meta; - pxt.debug(`published; id /${h.pubId}`) - return saveAsync(h).then(() => h) - }) + + const { shareID, scr: script } = await cloud.shareAsync(h.id, scrReq); + if (!h.pubVersions) h.pubVersions = []; + h.pubVersions.push({ id: script.id, type: "permalink" }); + h.pubId = shareID + h.pubCurrent = h.saveId === saveId + h.pubPermalink = shareID; + h.meta = script.meta; + pxt.debug(`published; id /${h.pubId}`) + await saveAsync(h); + await updateShareHistoryAsync(h.id); + + return h; } function fixupVersionAsync(e: File) {