[web] workspace/sandpack: also switch bundler URL when timeout
This commit is contained in:
parent
13ab5faf1a
commit
29e3419214
|
|
@ -8,6 +8,7 @@ import CodingPreferencesProvider from '~/components/global/CodingPreferencesProv
|
||||||
import { useColorSchemePreferences } from '~/components/global/color-scheme/ColorSchemePreferencesProvider';
|
import { useColorSchemePreferences } from '~/components/global/color-scheme/ColorSchemePreferencesProvider';
|
||||||
import type { ProjectsChallengeSolutionBundle } from '~/components/projects/challenges/types';
|
import type { ProjectsChallengeSolutionBundle } from '~/components/projects/challenges/types';
|
||||||
import SandpackObservability from '~/components/workspace/common/sandpack/SandpackObservability';
|
import SandpackObservability from '~/components/workspace/common/sandpack/SandpackObservability';
|
||||||
|
import { SandpackTimeout } from '~/components/workspace/common/sandpack/SandpackTimeout';
|
||||||
import { useSandpackBundlerURL } from '~/components/workspace/common/sandpack/useSandpackBundlerURL';
|
import { useSandpackBundlerURL } from '~/components/workspace/common/sandpack/useSandpackBundlerURL';
|
||||||
|
|
||||||
import ProjectsChallengeSolutionWorkspace from './ProjectsChallengeSolutionWorkspace';
|
import ProjectsChallengeSolutionWorkspace from './ProjectsChallengeSolutionWorkspace';
|
||||||
|
|
@ -20,7 +21,8 @@ const sandpackO11yInstance = 'projects.challenge_solution';
|
||||||
|
|
||||||
export default function ProjectsChallengeSolutionSection({ solution }: Props) {
|
export default function ProjectsChallengeSolutionSection({ solution }: Props) {
|
||||||
const { colorScheme } = useColorSchemePreferences();
|
const { colorScheme } = useColorSchemePreferences();
|
||||||
const bundlerURL = useSandpackBundlerURL(sandpackO11yInstance);
|
const [bundlerURL, changeToFallbackUrl] =
|
||||||
|
useSandpackBundlerURL(sandpackO11yInstance);
|
||||||
const { files, workspace } = solution;
|
const { files, workspace } = solution;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -49,6 +51,10 @@ export default function ProjectsChallengeSolutionSection({ solution }: Props) {
|
||||||
activeTabScrollIntoView={true}
|
activeTabScrollIntoView={true}
|
||||||
defaultFiles={files}
|
defaultFiles={files}
|
||||||
/>
|
/>
|
||||||
|
<SandpackTimeout
|
||||||
|
instance={sandpackO11yInstance}
|
||||||
|
onTimeout={changeToFallbackUrl}
|
||||||
|
/>
|
||||||
<SandpackObservability
|
<SandpackObservability
|
||||||
bundlerURL={bundlerURL}
|
bundlerURL={bundlerURL}
|
||||||
instance={sandpackO11yInstance}
|
instance={sandpackO11yInstance}
|
||||||
|
|
|
||||||
|
|
@ -73,20 +73,8 @@ export default function SandpackObservability({ bundlerURL, instance }: Props) {
|
||||||
const { status: sandpackStatus } = sandpack;
|
const { status: sandpackStatus } = sandpack;
|
||||||
const loadingStartedRef = useRef(false);
|
const loadingStartedRef = useRef(false);
|
||||||
const readySentRef = useRef(false);
|
const readySentRef = useRef(false);
|
||||||
const timeoutSentRef = useRef(false);
|
|
||||||
|
|
||||||
usePingSandpackBundler({ bundlerURL, instance });
|
usePingSandpackBundler({ bundlerURL, instance });
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (sandpackStatus === 'timeout' && !timeoutSentRef.current) {
|
|
||||||
logEvent('sandpack.timeout', {
|
|
||||||
instance,
|
|
||||||
namespace: 'workspace',
|
|
||||||
});
|
|
||||||
timeoutSentRef.current = true;
|
|
||||||
}
|
|
||||||
}, [instance, sandpackStatus]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (loadingStartedRef.current) {
|
if (loadingStartedRef.current) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { useSandpack } from '@codesandbox/sandpack-react';
|
||||||
|
import { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
import logEvent from '~/logging/logEvent';
|
||||||
|
|
||||||
|
type Props = Readonly<{
|
||||||
|
instance: string;
|
||||||
|
onTimeout: (instance: string) => void;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
export function SandpackTimeout({ instance, onTimeout }: Props) {
|
||||||
|
const timeoutSentRef = useRef(false);
|
||||||
|
|
||||||
|
const { sandpack } = useSandpack();
|
||||||
|
const { status: sandpackStatus } = sandpack;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (sandpackStatus === 'timeout' && !timeoutSentRef.current) {
|
||||||
|
onTimeout(instance);
|
||||||
|
logEvent('sandpack.timeout', {
|
||||||
|
instance,
|
||||||
|
namespace: 'workspace',
|
||||||
|
});
|
||||||
|
timeoutSentRef.current = true;
|
||||||
|
}
|
||||||
|
}, [instance, sandpackStatus, onTimeout]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ import { getErrorMessage } from '~/utils/getErrorMessage';
|
||||||
const defaultBundlerURL = 'https://bundler.greatfrontend.io';
|
const defaultBundlerURL = 'https://bundler.greatfrontend.io';
|
||||||
const fallbackBundlerURL = 'https://bundler.greatfrontend.com';
|
const fallbackBundlerURL = 'https://bundler.greatfrontend.com';
|
||||||
|
|
||||||
export function useSandpackBundlerURL(instance: string): string {
|
export function useSandpackBundlerURL(instance: string) {
|
||||||
const [url, setUrl] = useGreatStorageLocal(
|
const [url, setUrl] = useGreatStorageLocal(
|
||||||
'workspace:bundler-url', // Change the key if you want to reset the URL in local storage
|
'workspace:bundler-url', // Change the key if you want to reset the URL in local storage
|
||||||
defaultBundlerURL,
|
defaultBundlerURL,
|
||||||
|
|
@ -17,6 +17,20 @@ export function useSandpackBundlerURL(instance: string): string {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const changeToFallbackUrl = useCallback(
|
||||||
|
(reason: string) => {
|
||||||
|
setUrl(fallbackBundlerURL);
|
||||||
|
logEvent('sandpack.bundler_fallback', {
|
||||||
|
instance,
|
||||||
|
namespace: 'workspace',
|
||||||
|
online: navigator.onLine,
|
||||||
|
reason,
|
||||||
|
url: fallbackBundlerURL,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[instance, setUrl],
|
||||||
|
);
|
||||||
|
|
||||||
const pingBundlerURL = useCallback(async () => {
|
const pingBundlerURL = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(new URL('version.txt', url).toString());
|
const response = await fetch(new URL('version.txt', url).toString());
|
||||||
|
|
@ -33,6 +47,7 @@ export function useSandpackBundlerURL(instance: string): string {
|
||||||
instance,
|
instance,
|
||||||
namespace: 'workspace',
|
namespace: 'workspace',
|
||||||
online: navigator.onLine,
|
online: navigator.onLine,
|
||||||
|
reason: 'blocked',
|
||||||
stack: error instanceof Error ? error.stack : null,
|
stack: error instanceof Error ? error.stack : null,
|
||||||
url,
|
url,
|
||||||
});
|
});
|
||||||
|
|
@ -68,5 +83,5 @@ export function useSandpackBundlerURL(instance: string): string {
|
||||||
pingBundlerURL();
|
pingBundlerURL();
|
||||||
}, [url, pingBundlerURL]);
|
}, [url, pingBundlerURL]);
|
||||||
|
|
||||||
return url;
|
return [url, changeToFallbackUrl] as const;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import type {
|
||||||
QuestionJavaScript,
|
QuestionJavaScript,
|
||||||
QuestionMetadata,
|
QuestionMetadata,
|
||||||
} from '~/components/interviews/questions/common/QuestionsTypes';
|
} from '~/components/interviews/questions/common/QuestionsTypes';
|
||||||
|
import { SandpackTimeout } from '~/components/workspace/common/sandpack/SandpackTimeout';
|
||||||
import JavaScriptCodingWorkspace from '~/components/workspace/javascript/JavaScriptCodingWorkspace';
|
import JavaScriptCodingWorkspace from '~/components/workspace/javascript/JavaScriptCodingWorkspace';
|
||||||
import { loadLocalJavaScriptQuestionCode } from '~/components/workspace/javascript/JavaScriptCodingWorkspaceCodeStorage';
|
import { loadLocalJavaScriptQuestionCode } from '~/components/workspace/javascript/JavaScriptCodingWorkspaceCodeStorage';
|
||||||
|
|
||||||
|
|
@ -38,7 +39,8 @@ export default function JavaScriptCodingWorkspaceSection({
|
||||||
studyListKey,
|
studyListKey,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const { colorScheme } = useColorSchemePreferences();
|
const { colorScheme } = useColorSchemePreferences();
|
||||||
const bundlerURL = useSandpackBundlerURL(sandpackO11yInstance);
|
const [bundlerURL, changeToFallbackUrl] =
|
||||||
|
useSandpackBundlerURL(sandpackO11yInstance);
|
||||||
|
|
||||||
const { files, skeleton, workspace } = question;
|
const { files, skeleton, workspace } = question;
|
||||||
const loadedCode = loadLocalJavaScriptQuestionCode(
|
const loadedCode = loadLocalJavaScriptQuestionCode(
|
||||||
|
|
@ -98,6 +100,10 @@ export default function JavaScriptCodingWorkspaceSection({
|
||||||
workspace={workspace}
|
workspace={workspace}
|
||||||
onLanguageChange={onLanguageChange}
|
onLanguageChange={onLanguageChange}
|
||||||
/>
|
/>
|
||||||
|
<SandpackTimeout
|
||||||
|
instance={sandpackO11yInstance}
|
||||||
|
onTimeout={changeToFallbackUrl}
|
||||||
|
/>
|
||||||
<SandpackObservability
|
<SandpackObservability
|
||||||
bundlerURL={bundlerURL}
|
bundlerURL={bundlerURL}
|
||||||
instance={sandpackO11yInstance}
|
instance={sandpackO11yInstance}
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,12 @@ import {
|
||||||
questionUserInterfaceDescriptionPath,
|
questionUserInterfaceDescriptionPath,
|
||||||
questionUserInterfaceSolutionPath,
|
questionUserInterfaceSolutionPath,
|
||||||
} from '~/components/interviews/questions/content/user-interface/QuestionUserInterfaceRoutes';
|
} from '~/components/interviews/questions/content/user-interface/QuestionUserInterfaceRoutes';
|
||||||
|
import SandpackObservability from '~/components/workspace/common/sandpack/SandpackObservability';
|
||||||
|
import { SandpackTimeout } from '~/components/workspace/common/sandpack/SandpackTimeout';
|
||||||
import { useSandpackBundlerURL } from '~/components/workspace/common/sandpack/useSandpackBundlerURL';
|
import { useSandpackBundlerURL } from '~/components/workspace/common/sandpack/useSandpackBundlerURL';
|
||||||
|
|
||||||
import { useI18nRouter } from '~/next-i18nostic/src';
|
import { useI18nRouter } from '~/next-i18nostic/src';
|
||||||
|
|
||||||
import SandpackObservability from '../common/sandpack/SandpackObservability';
|
|
||||||
import UserInterfaceCodingWorkspace from './UserInterfaceCodingWorkspace';
|
import UserInterfaceCodingWorkspace from './UserInterfaceCodingWorkspace';
|
||||||
import { UserInterfaceCodingWorkspaceSavesContextProvider } from './UserInterfaceCodingWorkspaceSaveContext';
|
import { UserInterfaceCodingWorkspaceSavesContextProvider } from './UserInterfaceCodingWorkspaceSaveContext';
|
||||||
|
|
||||||
|
|
@ -44,7 +45,8 @@ export default function UserInterfaceCodingWorkspaceSavesPage({
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const router = useI18nRouter();
|
const router = useI18nRouter();
|
||||||
const { colorScheme } = useColorSchemePreferences();
|
const { colorScheme } = useColorSchemePreferences();
|
||||||
const bundlerURL = useSandpackBundlerURL(sandpackO11yInstance);
|
const [bundlerURL, changeToFallbackUrl] =
|
||||||
|
useSandpackBundlerURL(sandpackO11yInstance);
|
||||||
|
|
||||||
const { metadata, skeletonBundle } = question;
|
const { metadata, skeletonBundle } = question;
|
||||||
const { files: defaultFiles, workspace } = skeletonBundle;
|
const { files: defaultFiles, workspace } = skeletonBundle;
|
||||||
|
|
@ -106,6 +108,10 @@ export default function UserInterfaceCodingWorkspaceSavesPage({
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<SandpackTimeout
|
||||||
|
instance={sandpackO11yInstance}
|
||||||
|
onTimeout={changeToFallbackUrl}
|
||||||
|
/>
|
||||||
<SandpackObservability
|
<SandpackObservability
|
||||||
bundlerURL={bundlerURL}
|
bundlerURL={bundlerURL}
|
||||||
instance={sandpackO11yInstance}
|
instance={sandpackO11yInstance}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import type {
|
||||||
QuestionUserInterface,
|
QuestionUserInterface,
|
||||||
} from '~/components/interviews/questions/common/QuestionsTypes';
|
} from '~/components/interviews/questions/common/QuestionsTypes';
|
||||||
import type { QuestionUserInterfaceMode } from '~/components/interviews/questions/common/QuestionUserInterfacePath';
|
import type { QuestionUserInterfaceMode } from '~/components/interviews/questions/common/QuestionUserInterfacePath';
|
||||||
|
import { SandpackTimeout } from '~/components/workspace/common/sandpack/SandpackTimeout';
|
||||||
import { useSandpackBundlerURL } from '~/components/workspace/common/sandpack/useSandpackBundlerURL';
|
import { useSandpackBundlerURL } from '~/components/workspace/common/sandpack/useSandpackBundlerURL';
|
||||||
import UserInterfaceCodingWorkspace from '~/components/workspace/user-interface/UserInterfaceCodingWorkspace';
|
import UserInterfaceCodingWorkspace from '~/components/workspace/user-interface/UserInterfaceCodingWorkspace';
|
||||||
import { loadLocalUserInterfaceQuestionCode } from '~/components/workspace/user-interface/UserInterfaceCodingWorkspaceCodeStorage';
|
import { loadLocalUserInterfaceQuestionCode } from '~/components/workspace/user-interface/UserInterfaceCodingWorkspaceCodeStorage';
|
||||||
|
|
@ -44,7 +45,8 @@ export default function UserInterfaceCodingWorkspaceSection({
|
||||||
studyListKey,
|
studyListKey,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const { colorScheme } = useColorSchemePreferences();
|
const { colorScheme } = useColorSchemePreferences();
|
||||||
const bundlerURL = useSandpackBundlerURL(sandpackO11yInstance);
|
const [bundlerURL, changeToFallbackUrl] =
|
||||||
|
useSandpackBundlerURL(sandpackO11yInstance);
|
||||||
|
|
||||||
const loadedFiles = loadLocalUserInterfaceQuestionCode(
|
const loadedFiles = loadLocalUserInterfaceQuestionCode(
|
||||||
question,
|
question,
|
||||||
|
|
@ -105,6 +107,10 @@ export default function UserInterfaceCodingWorkspaceSection({
|
||||||
studyListKey={studyListKey}
|
studyListKey={studyListKey}
|
||||||
onFrameworkChange={onFrameworkChange}
|
onFrameworkChange={onFrameworkChange}
|
||||||
/>
|
/>
|
||||||
|
<SandpackTimeout
|
||||||
|
instance={sandpackO11yInstance}
|
||||||
|
onTimeout={changeToFallbackUrl}
|
||||||
|
/>
|
||||||
<SandpackObservability
|
<SandpackObservability
|
||||||
bundlerURL={bundlerURL}
|
bundlerURL={bundlerURL}
|
||||||
instance={sandpackO11yInstance}
|
instance={sandpackO11yInstance}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import { useIntl } from '~/components/intl';
|
||||||
import Anchor from '~/components/ui/Anchor';
|
import Anchor from '~/components/ui/Anchor';
|
||||||
import Banner from '~/components/ui/Banner';
|
import Banner from '~/components/ui/Banner';
|
||||||
import SandpackObservability from '~/components/workspace/common/sandpack/SandpackObservability';
|
import SandpackObservability from '~/components/workspace/common/sandpack/SandpackObservability';
|
||||||
|
import { SandpackTimeout } from '~/components/workspace/common/sandpack/SandpackTimeout';
|
||||||
import { useSandpackBundlerURL } from '~/components/workspace/common/sandpack/useSandpackBundlerURL';
|
import { useSandpackBundlerURL } from '~/components/workspace/common/sandpack/useSandpackBundlerURL';
|
||||||
|
|
||||||
import UserInterfaceCodingWorkspacePreview from './UserInterfaceCodingWorkspacePreview';
|
import UserInterfaceCodingWorkspacePreview from './UserInterfaceCodingWorkspacePreview';
|
||||||
|
|
@ -25,7 +26,8 @@ export default function UserInterfaceCodingWorkspaceSolutionPreviewTab({
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { colorScheme } = useColorSchemePreferences();
|
const { colorScheme } = useColorSchemePreferences();
|
||||||
const bundlerURL = useSandpackBundlerURL(sandpackO11yInstance);
|
const [bundlerURL, changeToFallbackUrl] =
|
||||||
|
useSandpackBundlerURL(sandpackO11yInstance);
|
||||||
const { dispatch, getTabById } =
|
const { dispatch, getTabById } =
|
||||||
useUserInterfaceCodingWorkspaceTilesContext();
|
useUserInterfaceCodingWorkspaceTilesContext();
|
||||||
|
|
||||||
|
|
@ -88,6 +90,10 @@ export default function UserInterfaceCodingWorkspaceSolutionPreviewTab({
|
||||||
}}
|
}}
|
||||||
theme={colorScheme === 'dark' ? 'dark' : undefined}>
|
theme={colorScheme === 'dark' ? 'dark' : undefined}>
|
||||||
<UserInterfaceCodingWorkspacePreview />
|
<UserInterfaceCodingWorkspacePreview />
|
||||||
|
<SandpackTimeout
|
||||||
|
instance={sandpackO11yInstance}
|
||||||
|
onTimeout={changeToFallbackUrl}
|
||||||
|
/>
|
||||||
<SandpackObservability
|
<SandpackObservability
|
||||||
bundlerURL={bundlerURL}
|
bundlerURL={bundlerURL}
|
||||||
instance={sandpackO11yInstance}
|
instance={sandpackO11yInstance}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue