diff --git a/skillmap/src/App.tsx b/skillmap/src/App.tsx index f91b9f8385b4..d39ee6efc5bc 100644 --- a/skillmap/src/App.tsx +++ b/skillmap/src/App.tsx @@ -30,7 +30,7 @@ import { InfoPanel } from './components/InfoPanel'; import { parseSkillMap } from './lib/skillMapParser'; import { parseHash, getMarkdownAsync, MarkdownSource, parseQuery, - setPageTitle, setPageSourceUrl, ParsedHash } from './lib/browserUtils'; + setPageTitle, setPageSourceUrl, ParsedHash, resolvePath } from './lib/browserUtils'; import { MakeCodeFrame } from './components/makecodeFrame'; import { getLocalUserStateAsync, getUserStateAsync, saveUserStateAsync } from './lib/workspaceProvider'; @@ -70,6 +70,7 @@ interface AppState { error?: string; cloudSyncCheckHasFinished: boolean; badgeSyncLock: boolean; + syncingLocalState?: boolean; } class AppImpl extends React.Component { @@ -234,8 +235,9 @@ class AppImpl extends React.Component { protected async cloudSyncCheckAsync() { const res = await this.ready(); if (!await authClient.loggedInAsync()) { - this.setState({cloudSyncCheckHasFinished: true}); + this.setState({cloudSyncCheckHasFinished: true, syncingLocalState: false}); } else { + this.setState({syncingLocalState: true}); const doCloudSyncCheckAsync = async () => { const state = store.getState(); const localUser = await getLocalUserStateAsync(); @@ -313,14 +315,14 @@ class AppImpl extends React.Component { action: "requestprojectcloudstatus", headerIds: getFlattenedHeaderIds(currentUser, state.pageSourceUrl) } as pxt.editor.EditorMessageRequestProjectCloudStatus); - this.setState({cloudSyncCheckHasFinished: true}); + this.setState({cloudSyncCheckHasFinished: true, syncingLocalState: false}); } // Timeout if cloud sync check doesn't complete in a reasonable timeframe. const TIMEOUT_MS = 10 * 1000; await Promise.race([ pxt.U.delay(TIMEOUT_MS).then(() => { if (!this.state.cloudSyncCheckHasFinished) - this.setState({cloudSyncCheckHasFinished: true}); + this.setState({cloudSyncCheckHasFinished: true, syncingLocalState: false}); }), doCloudSyncCheckAsync()]); } @@ -352,18 +354,22 @@ class AppImpl extends React.Component { render() { const { skillMaps, activityOpen, backgroundImageUrl, theme } = this.props; - const { error } = this.state; + const { error, syncingLocalState } = this.state; const maps = Object.keys(skillMaps).map((id: string) => skillMaps[id]); return (
-
- { error - ?
{error}
- : - } - { !error && } -
- + {syncingLocalState &&
+ {lf("MakeCode +
{lf("Saving to cloud...")}
+
} +
+ { error + ?
{error}
+ : + } + { !error && } +
+
); @@ -427,6 +433,11 @@ class AppImpl extends React.Component { } } + if ((!this.props.signedIn || (this.props.signedIn && this.state.cloudSyncCheckHasFinished)) + && this.state.syncingLocalState) { + this.setState({ syncingLocalState: false }); + } + await this.syncBadgesAsync(); } diff --git a/skillmap/src/components/makecodeFrame.tsx b/skillmap/src/components/makecodeFrame.tsx index bf6e4b737783..95c15e499efa 100644 --- a/skillmap/src/components/makecodeFrame.tsx +++ b/skillmap/src/components/makecodeFrame.tsx @@ -32,7 +32,7 @@ interface MakeCodeFrameProps { dispatchSetShareStatus: (headerId?: string, url?: string) => void; dispatchShowLoginPrompt: () => void; dispatchSetCloudStatus: (headerId: string, status: string) => void; - onFrameLoaded: (sendMessageAsync: (message: any) => Promise) => void; + onWorkspaceReady: (sendMessageAsync: (message: any) => Promise) => void; } type FrameState = "loading" | "no-project" | "opening-project" | "project-open" | "closing-project"; @@ -143,8 +143,6 @@ class MakeCodeFrameImpl extends React.Component this.sendMessageAsync(message)); } } @@ -165,6 +163,11 @@ class MakeCodeFrameImpl extends React.Component this.sendMessageAsync(message)); + } if (this.state.frameState === "loading") { this.setState({ frameState: "no-project" }); } @@ -182,7 +185,7 @@ class MakeCodeFrameImpl extends React.Component { const sendMessageCore = (message: any) => { message.response = true; @@ -195,14 +198,14 @@ class MakeCodeFrameImpl extends React.Component