Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show error log if Playground fails to start #1336

Merged
merged 12 commits into from
May 7, 2024
10 changes: 5 additions & 5 deletions packages/php-wasm/logger/src/lib/handlers/log-to-memory.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { LogHandler } from '../log-handlers';
import { formatLogEntry, Log } from '../logger';

const prepareLogMessage = (message: any, ...args: any[]): string => {
return [
typeof message === 'object' ? JSON.stringify(message) : message,
...args.map((arg) => JSON.stringify(arg)),
].join(' ');
const prepareLogMessage = (logMessage: object): string => {
if (logMessage instanceof Error) {
return [logMessage.message, logMessage.stack].join('\n');
}
return JSON.stringify(logMessage, null, 2);
};

export const logs: string[] = [];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react';
import Modal from '../modal';
import { addCrashListener, logger } from '@php-wasm/logger';
import { logger } from '@php-wasm/logger';
import { Button, TextareaControl, TextControl } from '@wordpress/components';

import css from './style.module.css';
Expand All @@ -17,25 +17,10 @@ export function ErrorReportModal(props: { blueprint: Blueprint }) {
const [submitted, setSubmitted] = useState(false);
const [submitError, setSubmitError] = useState('');

function showModal() {
return activeModal === 'error-report';
}

useEffect(() => {
addCrashListener(logger, (e) => {
const error = e as CustomEvent;
if (error.detail?.source === 'php-wasm') {
setActiveModal('error-report');
}
});
}, [setActiveModal]);

useEffect(() => {
resetForm();
if (showModal()) {
setLogs(logger.getLogs().join('\n'));
setUrl(window.location.href);
}
setLogs(logger.getLogs().join('\n'));
setUrl(window.location.href);
}, [activeModal, setActiveModal, logs, setLogs]);

function resetForm() {
Expand Down Expand Up @@ -154,7 +139,7 @@ export function ErrorReportModal(props: { blueprint: Blueprint }) {
}

return (
<Modal isOpen={showModal()} onRequestClose={onClose}>
<Modal isOpen={true} onRequestClose={onClose}>
<header className={css.errorReportModalHeader}>
<h2>{getTitle()}</h2>
<p>{getContent()}</p>
Expand Down
14 changes: 4 additions & 10 deletions packages/playground/website/src/components/log-modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,14 @@ import css from './style.module.css';
import { usePlaygroundContext } from '../../playground-context';
import { TextControl } from '@wordpress/components';

export function LogModal() {
export function LogModal(props: { description?: JSX.Element; title?: string }) {
const { activeModal, setActiveModal } = usePlaygroundContext();
const [logs, setLogs] = useState<string[]>([]);
const [searchTerm, setSearchTerm] = useState('');

useEffect(getLogs, [activeModal]);

function showModal() {
return activeModal === 'log';
}

function getLogs() {
if (!showModal()) {
return;
}
setLogs(logger.getLogs());
}

Expand All @@ -47,9 +40,10 @@ export function LogModal() {
};

return (
<Modal isOpen={showModal()} onRequestClose={onClose} styles={styles}>
<Modal isOpen={true} onRequestClose={onClose} styles={styles}>
<header>
<h2>Logs</h2>
<h2>{props.title || 'Logs'}</h2>
{props.description}
<TextControl
title="Search"
placeholder="Search logs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@

.log-modal__log {
text-wrap: wrap;
word-wrap: break-word;
margin: 0.5rem 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Button } from '@wordpress/components';
import { LogModal } from '../log-modal';
import { useState } from '@wordpress/element';

import css from './style.module.css';

export const localStorageKey = 'playground-start-error-dont-show-again';

export function StartErrorModal() {
const [dontShowAgain, setDontShowAgain] = useState(
localStorage.getItem(localStorageKey) === 'true'
);

if (dontShowAgain) {
return null;
}

const dismiss = () => {
localStorage.setItem(localStorageKey, 'true');
setDontShowAgain(true);
};

const description = (
<>
<p>
Oops! There was a problem starting Playground. To figure out
what went wrong, please take a look at the error logs provided
below. If you see an "Invalid blueprint error," the logs will
point out the specific step causing the issue. You can then
double-check your blueprint. For more help, you can also{' '}
<a
href="https://wordpress.github.io/wordpress-playground/blueprints-api/troubleshoot-and-debug-blueprints"
target="_blank"
rel="noreferrer"
>
visit our documentation.
</a>{' '}
</p>
<Button
className={css.startErrorModalDismiss}
text="Don't show again"
onClick={dismiss}
variant="secondary"
isSmall={true}
/>
</>
);
return <LogModal title="Error" description={description} />;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.start-error-modal__dismiss {
margin-bottom: 1.33rem;
}
20 changes: 14 additions & 6 deletions packages/playground/website/src/lib/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { useEffect, useRef, useState } from 'react';
import { Blueprint, startPlaygroundWeb } from '@wp-playground/client';
import type { PlaygroundClient } from '@wp-playground/client';
import { getRemoteUrl } from './config';
import { usePlaygroundContext } from '../playground-context';
import { logger } from '@php-wasm/logger';

interface UsePlaygroundOptions {
blueprint?: Blueprint;
Expand All @@ -14,6 +16,7 @@ export function usePlayground({ blueprint, storage }: UsePlaygroundOptions) {
const [url, setUrl] = useState<string>();
const [playground, setPlayground] = useState<PlaygroundClient>();
const [awaitedIframe, setAwaitedIframe] = useState(false);
const { setActiveModal } = usePlaygroundContext();

useEffect(() => {
if (started.current) {
Expand Down Expand Up @@ -45,12 +48,17 @@ export function usePlayground({ blueprint, storage }: UsePlaygroundOptions) {
playgroundTmp = playground;
(window as any)['playground'] = playground;
},
}).finally(async () => {
if (playgroundTmp) {
playgroundTmp.onNavigation((url) => setUrl(url));
setPlayground(() => playgroundTmp);
}
});
})
.catch((error) => {
logger.error(error);
setActiveModal('start-error');
})
.finally(async () => {
if (playgroundTmp) {
playgroundTmp.onNavigation((url) => setUrl(url));
setPlayground(() => playgroundTmp);
}
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [iframe, awaitedIframe]);

Expand Down
50 changes: 44 additions & 6 deletions packages/playground/website/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,23 @@ import { acquireOAuthTokenIfNeeded } from './github/acquire-oauth-token-if-neede
import { GithubImportModal } from './github/github-import-form';
import { GithubExportMenuItem } from './components/toolbar-buttons/github-export-menu-item';
import { GithubExportModal } from './github/github-export-form';
import { useState } from 'react';
import { useState, useEffect, useRef } from 'react';
import {
ExportFormValues,
asPullRequestAction,
} from './github/github-export-form/form';
import { joinPaths } from '@php-wasm/util';
import { ActiveModal, PlaygroundContext } from './playground-context';
import { collectWindowErrors, logger } from '@php-wasm/logger';
import {
addCrashListener,
collectWindowErrors,
logger,
} from '@php-wasm/logger';
import { ErrorReportModal } from './components/error-report-modal';
import { asContentType } from './github/import-from-github';
import { GitHubOAuthGuardModal } from './github/github-oauth-guard';
import { LogModal } from './components/log-modal';
import { StartErrorModal } from './components/start-error-modal';

collectWindowErrors(logger);

Expand Down Expand Up @@ -88,8 +93,28 @@ if (currentConfiguration.wp === '6.3') {

acquireOAuthTokenIfNeeded();

function Modals({ activeModal }: { activeModal: ActiveModal }) {
// Use a ref to store the current modal to avoid re-rendering from resetting the modal state.
const currentModal = useRef<ActiveModal>(false);

if (currentModal.current === false || activeModal === false) {
currentModal.current = activeModal;
}

if (currentModal.current === 'log') {
return <LogModal />;
} else if (currentModal.current === 'error-report') {
return <ErrorReportModal blueprint={blueprint} />;
} else if (currentModal.current === 'start-error') {
return <StartErrorModal />;
}

return null;
}

function Main() {
const [activeModal, setActiveModal] = useState<ActiveModal | false>(false);
const [activeModal, setActiveModal] = useState<ActiveModal>(false);

const [githubExportFiles, setGithubExportFiles] = useState<any[]>();
const [githubExportValues, setGithubExportValues] = useState<
Partial<ExportFormValues>
Expand Down Expand Up @@ -129,12 +154,24 @@ function Main() {
return values;
});

useEffect(() => {
addCrashListener(logger, (e) => {
const error = e as CustomEvent;
if (error.detail?.source === 'php-wasm') {
setActiveModal('error-report');
}
});
}, []);

return (
<PlaygroundContext.Provider
value={{ storage, activeModal, setActiveModal }}
value={{
storage,
activeModal,
setActiveModal,
}}
>
<ErrorReportModal blueprint={blueprint} />
<LogModal />
<Modals activeModal={activeModal} />
<PlaygroundViewport
storage={storage}
displayMode={displayMode}
Expand Down Expand Up @@ -298,3 +335,4 @@ function resolveVersion<T>(
}
return version as T;
}

2 changes: 1 addition & 1 deletion packages/playground/website/src/playground-context.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createContext, useContext } from 'react';
import { StorageType } from './types';

export type ActiveModal = 'error-report' | 'log' | false;
export type ActiveModal = 'error-report' | 'log' | 'start-error' | false;

export const PlaygroundContext = createContext<{
storage: StorageType;
Expand Down
Loading