From af4fa762d33ba264c689bfb4a750b498c06e4e3e Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Wed, 4 Dec 2024 18:23:38 -0500
Subject: [PATCH 01/22] Add function to derive site name from slug
---
.../playground/website/src/lib/state/redux/slice-sites.ts | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/packages/playground/website/src/lib/state/redux/slice-sites.ts b/packages/playground/website/src/lib/state/redux/slice-sites.ts
index 2f47417a95..e159050038 100644
--- a/packages/playground/website/src/lib/state/redux/slice-sites.ts
+++ b/packages/playground/website/src/lib/state/redux/slice-sites.ts
@@ -98,6 +98,12 @@ export const getSitesLoadingState = (state: {
export function deriveSlugFromSiteName(name: string) {
return name.toLowerCase().replaceAll(' ', '-');
}
+export function deriveSiteNameFromSlug(slug: string) {
+ return slug
+ .replaceAll('-', ' ')
+ .replaceAll(/\b\w/g, (c) => c.toUpperCase())
+ .replaceAll(/WordPress/gi, 'WordPress');
+}
/**
* Updates the site metadata in the OPFS and in the redux state.
From 3910c15ae3e506a321818549063019f8f4db3dc9 Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Wed, 4 Dec 2024 18:25:23 -0500
Subject: [PATCH 02/22] Add modal to prompt user to save for site slugs without
a persisted site
---
.../website/src/components/layout/index.tsx | 72 ++++++++++---------
.../components/missing-site-modal/index.tsx | 62 ++++++++++++++++
2 files changed, 102 insertions(+), 32 deletions(-)
create mode 100644 packages/playground/website/src/components/missing-site-modal/index.tsx
diff --git a/packages/playground/website/src/components/layout/index.tsx b/packages/playground/website/src/components/layout/index.tsx
index 25a6ee3211..bdd9c23ef7 100644
--- a/packages/playground/website/src/components/layout/index.tsx
+++ b/packages/playground/website/src/components/layout/index.tsx
@@ -34,6 +34,7 @@ import {
} from '../../lib/state/redux/slice-ui';
import { ImportFormModal } from '../import-form-modal';
import { PreviewPRModal } from '../../github/preview-pr';
+import { MissingSiteModal } from '../missing-site-modal';
acquireOAuthTokenIfNeeded();
@@ -46,7 +47,8 @@ export const modalSlugs = {
GITHUB_EXPORT: 'github-export',
PREVIEW_PR_WP: 'preview-pr-wordpress',
PREVIEW_PR_GUTENBERG: 'preview-pr-gutenberg',
-}
+ MISSING_SITE_PROMPT: 'missing-site-prompt',
+};
const displayMode = getDisplayModeFromQuery();
function getDisplayModeFromQuery(): DisplayMode {
@@ -186,39 +188,45 @@ function Modals(blueprint: Blueprint) {
} else if (currentModal === modalSlugs.PREVIEW_PR_GUTENBERG) {
return ;
} else if (currentModal === modalSlugs.GITHUB_IMPORT) {
- return {
- setGithubExportValues({
- repoUrl: url,
- prNumber: pr?.toString(),
- toPathInRepo: path,
- prAction: pr ? 'update' : 'create',
+ return (
+ ;
+ urlInformation: { owner, repo, type, pr },
+ }) => {
+ setGithubExportValues({
+ repoUrl: url,
+ prNumber: pr?.toString(),
+ toPathInRepo: path,
+ prAction: pr ? 'update' : 'create',
+ contentType,
+ plugin: pluginOrThemeName,
+ theme: pluginOrThemeName,
+ });
+ setGithubExportFiles(files);
+ }}
+ />
+ );
} else if (currentModal === modalSlugs.GITHUB_EXPORT) {
- return {
- setGithubExportValues(formValues);
- setGithubExportFiles(undefined);
- }}
- />;
+ return (
+ {
+ setGithubExportValues(formValues);
+ setGithubExportFiles(undefined);
+ }}
+ />
+ );
+ } else if (currentModal === modalSlugs.MISSING_SITE_PROMPT) {
+ return ;
}
if (query.get('gh-ensure-auth') === 'yes') {
diff --git a/packages/playground/website/src/components/missing-site-modal/index.tsx b/packages/playground/website/src/components/missing-site-modal/index.tsx
new file mode 100644
index 0000000000..0c65083231
--- /dev/null
+++ b/packages/playground/website/src/components/missing-site-modal/index.tsx
@@ -0,0 +1,62 @@
+import { Button, Flex, FlexItem } from '@wordpress/components';
+import { Modal } from '../modal';
+import { SitePersistButton } from '../site-manager/site-persist-button';
+import {
+ useAppDispatch,
+ useAppSelector,
+ selectActiveSite,
+} from '../../lib/state/redux/store';
+import { setActiveModal } from '../../lib/state/redux/slice-ui';
+import { usePlaygroundClient } from '../../lib/use-playground-client';
+
+export function MissingSiteModal() {
+ const dispatch = useAppDispatch();
+ const closeModal = () => dispatch(setActiveModal(null));
+
+ const activeSite = useAppSelector((state) => selectActiveSite(state));
+ const playground = usePlaygroundClient(activeSite?.slug);
+
+ if (!activeSite) {
+ return null;
+ }
+ if (activeSite.metadata.storage !== 'none') {
+ return null;
+ }
+
+ // TODO: Improve language for this modal
+ return (
+
+
What do you want to do?
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
From 2c469686ca2d58d9437ffd262bd342b42ef4f2fc Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Wed, 4 Dec 2024 18:37:17 -0500
Subject: [PATCH 03/22] Prompt user to consider saving when site with specified
slug does not exist
---
.../ensure-playground-site-is-selected.tsx | 94 +++++++++++++------
1 file changed, 63 insertions(+), 31 deletions(-)
diff --git a/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx b/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
index 9d8cc32963..16d18d5b77 100644
--- a/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
+++ b/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
@@ -6,6 +6,7 @@ import {
siteListingLoaded,
selectSiteBySlug,
setTemporarySiteSpec,
+ deriveSiteNameFromSlug,
} from '../../lib/state/redux/slice-sites';
import {
selectActiveSite,
@@ -17,6 +18,8 @@ import { redirectTo } from '../../lib/state/url/router';
import { logger } from '@php-wasm/logger';
import { Blueprint } from '@wp-playground/blueprints';
import { usePrevious } from '../../lib/hooks/use-previous';
+import { modalSlugs } from '../layout';
+import { setActiveModal } from '../../lib/state/redux/slice-ui';
/**
* Ensures the redux store always has an activeSite value.
@@ -41,6 +44,8 @@ export function EnsurePlaygroundSiteIsSelected({
const requestedSiteObject = useAppSelector((state) =>
selectSiteBySlug(state, requestedSiteSlug!)
);
+ const promptIfSiteMissing =
+ url.searchParams.get('if-site-slug-missing') === 'prompt';
const prevUrl = usePrevious(url);
useEffect(() => {
@@ -72,14 +77,31 @@ export function EnsurePlaygroundSiteIsSelected({
if (requestedSiteSlug) {
// If the site does not exist, redirect to a new temporary site.
if (!requestedSiteObject) {
- // @TODO: Notification: 'The requested site was not found. Redirecting to a new temporary site.'
- logger.log(
- 'The requested site was not found. Redirecting to a new temporary site.'
- );
- const currentUrl = new URL(window.location.href);
- currentUrl.searchParams.delete('site-slug');
- redirectTo(currentUrl.toString());
- return;
+ if (promptIfSiteMissing) {
+ // @TODO: Notification: 'The requested site was not found. Redirecting to a new temporary site.'
+ logger.log(
+ 'The requested site was not found. Creating a new temporary site.'
+ );
+
+ await createNewTemporarySite(
+ dispatch,
+ requestedSiteSlug
+ );
+
+ dispatch(
+ setActiveModal(modalSlugs.MISSING_SITE_PROMPT)
+ );
+ return;
+ } else {
+ // @TODO: Notification: 'The requested site was not found. Redirecting to a new temporary site.'
+ logger.log(
+ 'The requested site was not found. Redirecting to a new temporary site.'
+ );
+ const currentUrl = new URL(window.location.href);
+ currentUrl.searchParams.delete('site-slug');
+ redirectTo(currentUrl.toString());
+ return;
+ }
}
dispatch(setActiveSite(requestedSiteSlug));
@@ -98,29 +120,7 @@ export function EnsurePlaygroundSiteIsSelected({
return;
}
- // If the site slug is missing, create a new temporary site.
- // Lean on the Query API parameters and the Blueprint API to
- // create the new site.
- const newUrl = new URL(window.location.href);
- let blueprint: Blueprint | undefined = undefined;
- try {
- blueprint = await resolveBlueprintFromURL(newUrl);
- } catch (e) {
- logger.error('Error resolving blueprint:', e);
- }
- // Create a new site otherwise
- const newSiteInfo = await dispatch(
- setTemporarySiteSpec({
- metadata: {
- originalBlueprint: blueprint,
- },
- originalUrlParams: {
- searchParams: parseSearchParams(newUrl.searchParams),
- hash: newUrl.hash,
- },
- })
- );
- dispatch(setActiveSite(newSiteInfo.slug));
+ await createNewTemporarySite(dispatch);
}
ensureSiteIsSelected();
@@ -138,3 +138,35 @@ function parseSearchParams(searchParams: URLSearchParams) {
}
return params;
}
+
+async function createNewTemporarySite(
+ dispatch: ReturnType,
+ requestedSiteSlug?: string
+) {
+ // If the site slug is missing, create a new temporary site.
+ // Lean on the Query API parameters and the Blueprint API to
+ // create the new site.
+ const newUrl = new URL(window.location.href);
+ let blueprint: Blueprint | undefined = undefined;
+ try {
+ blueprint = await resolveBlueprintFromURL(newUrl);
+ } catch (e) {
+ logger.error('Error resolving blueprint:', e);
+ }
+ // Create a new site otherwise
+ const newSiteInfo = await dispatch(
+ setTemporarySiteSpec({
+ metadata: {
+ originalBlueprint: blueprint,
+ name: requestedSiteSlug
+ ? deriveSiteNameFromSlug(requestedSiteSlug)
+ : undefined,
+ },
+ originalUrlParams: {
+ searchParams: parseSearchParams(newUrl.searchParams),
+ hash: newUrl.hash,
+ },
+ })
+ );
+ await dispatch(setActiveSite(newSiteInfo.slug));
+}
From bb554fa926628e438a92687e0239336fe75a8186 Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Wed, 4 Dec 2024 19:03:38 -0500
Subject: [PATCH 04/22] Multiple tweaks to prompt modal
---
.../components/missing-site-modal/index.tsx | 22 ++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/packages/playground/website/src/components/missing-site-modal/index.tsx b/packages/playground/website/src/components/missing-site-modal/index.tsx
index 0c65083231..0e62cdda18 100644
--- a/packages/playground/website/src/components/missing-site-modal/index.tsx
+++ b/packages/playground/website/src/components/missing-site-modal/index.tsx
@@ -8,13 +8,24 @@ import {
} from '../../lib/state/redux/store';
import { setActiveModal } from '../../lib/state/redux/slice-ui';
import { usePlaygroundClient } from '../../lib/use-playground-client';
+import { useState } from 'react';
export function MissingSiteModal() {
const dispatch = useAppDispatch();
const closeModal = () => dispatch(setActiveModal(null));
const activeSite = useAppSelector((state) => selectActiveSite(state));
- const playground = usePlaygroundClient(activeSite?.slug);
+ const playgroundClient = usePlaygroundClient(activeSite?.slug);
+
+ const [playgroundReady, setPlaygroundReady] = useState<
+ boolean | Promise
+ >(false);
+
+ if (playgroundClient && playgroundReady === false) {
+ const promiseToBeReady = playgroundClient.isReady();
+ setPlaygroundReady(promiseToBeReady);
+ promiseToBeReady.then(() => setPlaygroundReady(true));
+ }
if (!activeSite) {
return null;
@@ -32,27 +43,28 @@ export function MissingSiteModal() {
onRequestClose={closeModal}
>
What do you want to do?
-
+
From bbb99d5b10c91f83050658f52995ae652a322f10 Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Wed, 4 Dec 2024 20:36:50 -0500
Subject: [PATCH 05/22] Fix wait until playground ready
---
.../components/missing-site-modal/index.tsx | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/packages/playground/website/src/components/missing-site-modal/index.tsx b/packages/playground/website/src/components/missing-site-modal/index.tsx
index 0e62cdda18..f2795d3a0c 100644
--- a/packages/playground/website/src/components/missing-site-modal/index.tsx
+++ b/packages/playground/website/src/components/missing-site-modal/index.tsx
@@ -8,7 +8,7 @@ import {
} from '../../lib/state/redux/store';
import { setActiveModal } from '../../lib/state/redux/slice-ui';
import { usePlaygroundClient } from '../../lib/use-playground-client';
-import { useState } from 'react';
+import { useEffect, useState } from 'react';
export function MissingSiteModal() {
const dispatch = useAppDispatch();
@@ -17,16 +17,12 @@ export function MissingSiteModal() {
const activeSite = useAppSelector((state) => selectActiveSite(state));
const playgroundClient = usePlaygroundClient(activeSite?.slug);
- const [playgroundReady, setPlaygroundReady] = useState<
- boolean | Promise
- >(false);
-
- if (playgroundClient && playgroundReady === false) {
- const promiseToBeReady = playgroundClient.isReady();
- setPlaygroundReady(promiseToBeReady);
- promiseToBeReady.then(() => setPlaygroundReady(true));
- }
-
+ const [playgroundReady, setPlaygroundReady] = useState(false);
+ useEffect(() => {
+ if (playgroundClient) {
+ playgroundClient.isReady().then(() => setPlaygroundReady(true));
+ }
+ }, [playgroundClient]);
if (!activeSite) {
return null;
}
From 95e891d42501619b9db50811bb823328946db61c Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Wed, 4 Dec 2024 21:16:38 -0500
Subject: [PATCH 06/22] Add TODO
---
.../ensure-playground-site-is-selected.tsx | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx b/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
index 16d18d5b77..3acba76a7e 100644
--- a/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
+++ b/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
@@ -88,6 +88,7 @@ export function EnsurePlaygroundSiteIsSelected({
requestedSiteSlug
);
+ // TODO: Wait for Playground to load before showing the modal which would otherwise obscure the progress indicator
dispatch(
setActiveModal(modalSlugs.MISSING_SITE_PROMPT)
);
From d70b1a2d7bcbcb51e21cc39ac4a0099cf06fc404 Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Wed, 4 Dec 2024 21:18:43 -0500
Subject: [PATCH 07/22] Improve modal text
---
.../src/components/missing-site-modal/index.tsx | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/packages/playground/website/src/components/missing-site-modal/index.tsx b/packages/playground/website/src/components/missing-site-modal/index.tsx
index f2795d3a0c..a51f50302d 100644
--- a/packages/playground/website/src/components/missing-site-modal/index.tsx
+++ b/packages/playground/website/src/components/missing-site-modal/index.tsx
@@ -35,10 +35,16 @@ export function MissingSiteModal() {
-
What do you want to do?
+
+ WordPress Playground tried to load a Playground that does not
+ exist, so we loaded a temporary Playground instead. Your changes
+ will be lost on page refresh.
+
+
Would you like to save this Playground to browser storage?
From d12cffbd0a77e7b9e4bca1e01aaf318d860e1ef5 Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Wed, 4 Dec 2024 22:22:47 -0500
Subject: [PATCH 08/22] Adjust name of query param
---
.../ensure-playground-site-is-selected.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx b/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
index 3acba76a7e..f115d413da 100644
--- a/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
+++ b/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
@@ -45,7 +45,7 @@ export function EnsurePlaygroundSiteIsSelected({
selectSiteBySlug(state, requestedSiteSlug!)
);
const promptIfSiteMissing =
- url.searchParams.get('if-site-slug-missing') === 'prompt';
+ url.searchParams.get('if-stored-site-missing') === 'prompt';
const prevUrl = usePrevious(url);
useEffect(() => {
From 7eb79008ea6e9d66caf64ef79dd168f49b1c4751 Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Wed, 4 Dec 2024 22:23:14 -0500
Subject: [PATCH 09/22] Avoid modal being accidentally dismissed without making
a choice
---
.../website/src/components/missing-site-modal/index.tsx | 3 +++
1 file changed, 3 insertions(+)
diff --git a/packages/playground/website/src/components/missing-site-modal/index.tsx b/packages/playground/website/src/components/missing-site-modal/index.tsx
index a51f50302d..5c3f296f58 100644
--- a/packages/playground/website/src/components/missing-site-modal/index.tsx
+++ b/packages/playground/website/src/components/missing-site-modal/index.tsx
@@ -23,6 +23,7 @@ export function MissingSiteModal() {
playgroundClient.isReady().then(() => setPlaygroundReady(true));
}
}, [playgroundClient]);
+
if (!activeSite) {
return null;
}
@@ -37,6 +38,8 @@ export function MissingSiteModal() {
contentLabel="This is a dialog window which overlays the main content of the
page. It offers the user a choice between using a temporary Playground
and a persistent Playground that is saved to browser storage."
+ isDismissible={false}
+ shouldCloseOnClickOutside={false}
onRequestClose={closeModal}
>
From 0986c6b7bef1987bdfa7e2e2e58a23189578a689 Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Wed, 4 Dec 2024 23:34:42 -0500
Subject: [PATCH 10/22] Try to improve modal language
---
.../website/src/components/missing-site-modal/index.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/playground/website/src/components/missing-site-modal/index.tsx b/packages/playground/website/src/components/missing-site-modal/index.tsx
index 5c3f296f58..985fb394b8 100644
--- a/packages/playground/website/src/components/missing-site-modal/index.tsx
+++ b/packages/playground/website/src/components/missing-site-modal/index.tsx
@@ -44,8 +44,8 @@ export function MissingSiteModal() {
>
WordPress Playground tried to load a Playground that does not
- exist, so we loaded a temporary Playground instead. Your changes
- will be lost on page refresh.
+ exist, so we loaded a temporary Playground instead. Any changes
+ to temporary Playgrounds are lost on page refresh.
Would you like to save this Playground to browser storage?
From b148c5643a6ce80d0d4c865e37a14655da11d44e Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Wed, 4 Dec 2024 23:43:18 -0500
Subject: [PATCH 11/22] Display modal after Playground loads
---
.../ensure-playground-site-is-selected.tsx | 33 +++++++++++++++----
1 file changed, 27 insertions(+), 6 deletions(-)
diff --git a/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx b/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
index f115d413da..b72a64b256 100644
--- a/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
+++ b/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
@@ -1,4 +1,4 @@
-import { useEffect } from 'react';
+import { useEffect, useState } from 'react';
import { resolveBlueprintFromURL } from '../../lib/state/url/resolve-blueprint-from-url';
import { useCurrentUrl } from '../../lib/state/url/router-hooks';
import { opfsSiteStorage } from '../../lib/state/opfs/opfs-site-storage';
@@ -20,6 +20,7 @@ import { Blueprint } from '@wp-playground/blueprints';
import { usePrevious } from '../../lib/hooks/use-previous';
import { modalSlugs } from '../layout';
import { setActiveModal } from '../../lib/state/redux/slice-ui';
+import { selectClientBySiteSlug } from '../../lib/state/redux/slice-clients';
/**
* Ensures the redux store always has an activeSite value.
@@ -44,6 +45,14 @@ export function EnsurePlaygroundSiteIsSelected({
const requestedSiteObject = useAppSelector((state) =>
selectSiteBySlug(state, requestedSiteSlug!)
);
+ const requestedClientInfo = useAppSelector(
+ (state) =>
+ requestedSiteSlug &&
+ selectClientBySiteSlug(state, requestedSiteSlug)
+ );
+ const [needMissingSitePromptForSlug, setNeedMissingSitePromptForSlug] =
+ useState(false);
+
const promptIfSiteMissing =
url.searchParams.get('if-stored-site-missing') === 'prompt';
const prevUrl = usePrevious(url);
@@ -87,11 +96,7 @@ export function EnsurePlaygroundSiteIsSelected({
dispatch,
requestedSiteSlug
);
-
- // TODO: Wait for Playground to load before showing the modal which would otherwise obscure the progress indicator
- dispatch(
- setActiveModal(modalSlugs.MISSING_SITE_PROMPT)
- );
+ setNeedMissingSitePromptForSlug(requestedSiteSlug);
return;
} else {
// @TODO: Notification: 'The requested site was not found. Redirecting to a new temporary site.'
@@ -128,6 +133,22 @@ export function EnsurePlaygroundSiteIsSelected({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [url.href, requestedSiteSlug, siteListingStatus]);
+ useEffect(() => {
+ if (
+ needMissingSitePromptForSlug &&
+ needMissingSitePromptForSlug === requestedSiteSlug &&
+ requestedClientInfo
+ ) {
+ dispatch(setActiveModal(modalSlugs.MISSING_SITE_PROMPT));
+ setNeedMissingSitePromptForSlug(false);
+ }
+ }, [
+ needMissingSitePromptForSlug,
+ requestedSiteSlug,
+ requestedClientInfo,
+ dispatch,
+ ]);
+
return children;
}
From 3e03aa51663974199e460fee4d8f7706c819464b Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Wed, 4 Dec 2024 23:58:17 -0500
Subject: [PATCH 12/22] Disable use-temp button when saving to OPFS
---
.../components/missing-site-modal/index.tsx | 22 +++++++++----------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/packages/playground/website/src/components/missing-site-modal/index.tsx b/packages/playground/website/src/components/missing-site-modal/index.tsx
index 985fb394b8..e1620b88df 100644
--- a/packages/playground/website/src/components/missing-site-modal/index.tsx
+++ b/packages/playground/website/src/components/missing-site-modal/index.tsx
@@ -7,22 +7,18 @@ import {
selectActiveSite,
} from '../../lib/state/redux/store';
import { setActiveModal } from '../../lib/state/redux/slice-ui';
-import { usePlaygroundClient } from '../../lib/use-playground-client';
-import { useEffect, useState } from 'react';
+import { selectClientInfoBySiteSlug } from '../../lib/state/redux/slice-clients';
export function MissingSiteModal() {
const dispatch = useAppDispatch();
const closeModal = () => dispatch(setActiveModal(null));
const activeSite = useAppSelector((state) => selectActiveSite(state));
- const playgroundClient = usePlaygroundClient(activeSite?.slug);
-
- const [playgroundReady, setPlaygroundReady] = useState(false);
- useEffect(() => {
- if (playgroundClient) {
- playgroundClient.isReady().then(() => setPlaygroundReady(true));
- }
- }, [playgroundClient]);
+ const clientInfo = useAppSelector(
+ (state) =>
+ activeSite?.slug &&
+ selectClientInfoBySiteSlug(state, activeSite?.slug)
+ );
if (!activeSite) {
return null;
@@ -52,7 +48,10 @@ export function MissingSiteModal() {
Would you like to save this Playground to browser storage?
- WordPress Playground tried to load a Playground that does not
- exist, so we loaded a temporary Playground instead. Any changes
- to temporary Playgrounds are lost on page refresh.
+ The {activeSite.metadata.name} Playground does not exist, so we
+ loaded a temporary Playground instead.
+
+
+ If you want to preserve your changes, you can save the
+ Playground to browser storage.
-
Would you like to save this Playground to browser storage?
Date: Thu, 5 Dec 2024 16:21:51 +0100
Subject: [PATCH 15/22] Update
packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
Co-authored-by: Bero
---
.../ensure-playground-site-is-selected.tsx | 1 -
1 file changed, 1 deletion(-)
diff --git a/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx b/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
index b72a64b256..a4f4a5594d 100644
--- a/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
+++ b/packages/playground/website/src/components/ensure-playground-site/ensure-playground-site-is-selected.tsx
@@ -87,7 +87,6 @@ export function EnsurePlaygroundSiteIsSelected({
// If the site does not exist, redirect to a new temporary site.
if (!requestedSiteObject) {
if (promptIfSiteMissing) {
- // @TODO: Notification: 'The requested site was not found. Redirecting to a new temporary site.'
logger.log(
'The requested site was not found. Creating a new temporary site.'
);
From c8dc49b899c6d1056e4364157a6e9ed2a79e440e Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Thu, 5 Dec 2024 10:25:33 -0500
Subject: [PATCH 16/22] Prefer row orientation for buttons to follow Modal
style recommendations
---
.../components/missing-site-modal/index.tsx | 35 +++++++++++++------
1 file changed, 24 insertions(+), 11 deletions(-)
diff --git a/packages/playground/website/src/components/missing-site-modal/index.tsx b/packages/playground/website/src/components/missing-site-modal/index.tsx
index 518830275a..417de1f97b 100644
--- a/packages/playground/website/src/components/missing-site-modal/index.tsx
+++ b/packages/playground/website/src/components/missing-site-modal/index.tsx
@@ -46,7 +46,30 @@ export function MissingSiteModal() {
If you want to preserve your changes, you can save the
Playground to browser storage.
-
+ {/* Note: We are using row-reverse direction so the secondary
+ button can display first in row orientation and last when
+ wrapping to vertical orientation.
+
+ This matches Modal style recommendations here:
+ https://github.com/WordPress/gutenberg/tree/1418350eb5a1f15e109fc96af385bdd029fc7304/packages/components/src/modal#side-by-side-buttons-recommended
+ */}
+
+
+
+
+ Save Playground to browser storage
+
+
+
-
-
-
- Save Playground to browser storage
-
-
-
);
From 651c1d55841c418d8674c256d5ba19cd84307931 Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Thu, 5 Dec 2024 11:48:24 -0500
Subject: [PATCH 17/22] Allow PersistSiteButton to save to single storage type
---
.../site-persist-button/index.tsx | 24 +++++++++++++++++--
.../lib/state/redux/persist-temporary-site.ts | 3 ++-
2 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/packages/playground/website/src/components/site-manager/site-persist-button/index.tsx b/packages/playground/website/src/components/site-manager/site-persist-button/index.tsx
index 611b27bede..865704ca3d 100644
--- a/packages/playground/website/src/components/site-manager/site-persist-button/index.tsx
+++ b/packages/playground/website/src/components/site-manager/site-persist-button/index.tsx
@@ -11,13 +11,16 @@ import { persistTemporarySite } from '../../../lib/state/redux/persist-temporary
import { selectClientInfoBySiteSlug } from '../../../lib/state/redux/slice-clients';
import { useLocalFsAvailability } from '../../../lib/hooks/use-local-fs-availability';
import { isOpfsAvailable } from '../../../lib/state/opfs/opfs-site-storage';
+import { SiteStorageType } from '../../../lib/site-metadata';
export function SitePersistButton({
siteSlug,
children,
+ storage = null,
}: {
siteSlug: string;
children: React.ReactNode;
+ storage?: Extract | null;
}) {
const clientInfo = useAppSelector((state) =>
selectClientInfoBySiteSlug(state, siteSlug)
@@ -26,8 +29,19 @@ export function SitePersistButton({
const dispatch = useAppDispatch();
if (!clientInfo?.opfsSync || clientInfo.opfsSync?.status === 'error') {
- return (
- <>
+ let button = null;
+ if (storage) {
+ button = (
+
There has been an error. Please try again.
diff --git a/packages/playground/website/src/lib/state/redux/persist-temporary-site.ts b/packages/playground/website/src/lib/state/redux/persist-temporary-site.ts
index 26560346d4..ece5fa16d4 100644
--- a/packages/playground/website/src/lib/state/redux/persist-temporary-site.ts
+++ b/packages/playground/website/src/lib/state/redux/persist-temporary-site.ts
@@ -14,10 +14,11 @@ import {
updateSiteMetadata,
} from './slice-sites';
import { PlaygroundRoute, redirectTo } from '../url/router';
+import { SiteStorageType } from '../../site-metadata';
export function persistTemporarySite(
siteSlug: string,
- storageType: 'opfs' | 'local-fs'
+ storageType: Extract
) {
// @TODO: Handle errors
return async (
From 621ddd5ad54d9ca11678d7050dd93dc5f072fb62 Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Thu, 5 Dec 2024 11:50:04 -0500
Subject: [PATCH 18/22] Only save to OPFS
---
.../website/src/components/missing-site-modal/index.tsx | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/packages/playground/website/src/components/missing-site-modal/index.tsx b/packages/playground/website/src/components/missing-site-modal/index.tsx
index 417de1f97b..8e10a693fe 100644
--- a/packages/playground/website/src/components/missing-site-modal/index.tsx
+++ b/packages/playground/website/src/components/missing-site-modal/index.tsx
@@ -61,7 +61,10 @@ export function MissingSiteModal() {
justify="flex-start"
>
-
+
Date: Thu, 5 Dec 2024 11:52:44 -0500
Subject: [PATCH 19/22] Remove redundant ARIA label
---
.../website/src/components/missing-site-modal/index.tsx | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/packages/playground/website/src/components/missing-site-modal/index.tsx b/packages/playground/website/src/components/missing-site-modal/index.tsx
index 8e10a693fe..a4151157fd 100644
--- a/packages/playground/website/src/components/missing-site-modal/index.tsx
+++ b/packages/playground/website/src/components/missing-site-modal/index.tsx
@@ -65,10 +65,7 @@ export function MissingSiteModal() {
siteSlug={activeSite.slug}
storage="opfs"
>
-
+
Save Playground to browser storage
From 04552852f7aec0defd2a29687162ae8cff8e06b0 Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Thu, 5 Dec 2024 12:01:21 -0500
Subject: [PATCH 20/22] Increase space between buttons
---
.../website/src/components/missing-site-modal/index.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/playground/website/src/components/missing-site-modal/index.tsx b/packages/playground/website/src/components/missing-site-modal/index.tsx
index a4151157fd..f140e0c105 100644
--- a/packages/playground/website/src/components/missing-site-modal/index.tsx
+++ b/packages/playground/website/src/components/missing-site-modal/index.tsx
@@ -55,7 +55,7 @@ export function MissingSiteModal() {
*/}
Date: Thu, 5 Dec 2024 12:02:27 -0500
Subject: [PATCH 21/22] Make Playground name visually distinguished from
surrounding modal text
---
.../website/src/components/missing-site-modal/index.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/playground/website/src/components/missing-site-modal/index.tsx b/packages/playground/website/src/components/missing-site-modal/index.tsx
index f140e0c105..af7b57ff02 100644
--- a/packages/playground/website/src/components/missing-site-modal/index.tsx
+++ b/packages/playground/website/src/components/missing-site-modal/index.tsx
@@ -39,8 +39,8 @@ export function MissingSiteModal() {
onRequestClose={closeModal}
>
- The {activeSite.metadata.name} Playground does not exist, so we
- loaded a temporary Playground instead.
+ The {activeSite.metadata.name} Playground does not exist,
+ so we loaded a temporary Playground instead.
If you want to preserve your changes, you can save the
From fb168727328fcc4fe2037186ef112d728dd8c492 Mon Sep 17 00:00:00 2001
From: Brandon Payton
Date: Thu, 5 Dec 2024 12:13:51 -0500
Subject: [PATCH 22/22] Document if-stored-site-missing query param
---
.../developers/06-apis/query-api/01-index.md | 39 ++++++++++---------
1 file changed, 20 insertions(+), 19 deletions(-)
diff --git a/packages/docs/site/docs/developers/06-apis/query-api/01-index.md b/packages/docs/site/docs/developers/06-apis/query-api/01-index.md
index 911afa26fe..fd2170e0e3 100644
--- a/packages/docs/site/docs/developers/06-apis/query-api/01-index.md
+++ b/packages/docs/site/docs/developers/06-apis/query-api/01-index.md
@@ -21,25 +21,26 @@ You can go ahead and try it out. The Playground will automatically install the t
## Available options
-| Option | Default Value | Description |
-| --------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `php` | `8.0` | Loads the specified PHP version. Accepts `7.0`, `7.1`, `7.2`, `7.3`, `7.4`, `8.0`, `8.1`, `8.2`, `8.3`, or `latest`. |
-| `wp` | `latest` | Loads the specified WordPress version. Accepts the last three major WordPress versions. As of June 1, 2024, that's `6.3`, `6.4`, or `6.5`. You can also use the generic values `latest`, `nightly`, or `beta`. |
-| `blueprint-url` | | The URL of the Blueprint that will be used to configure this Playground instance. |
-| `networking` | `no` | Enables or disables the networking support for Playground. Accepts `yes` or `no`. |
-| `plugin` | | Installs the specified plugin. Use the plugin name from the WordPress Plugins Directory URL. For example, if the URL is `https://wordpress.org/plugins/wp-lazy-loading/`, the plugin name would be `wp-lazy-loading`. You can pre-install multiple plugins by saying `plugin=coblocks&plugin=wp-lazy-loading&…`. Installing a plugin automatically logs the user in as an admin. |
-| `theme` | | Installs the specified theme. Use the theme name from the WordPress Themes Directory URL. For example, if the URL is `https://wordpress.org/themes/disco/`, the theme name would be `disco`. Installing a theme automatically logs the user in as an admin. |
-| `url` | `/wp-admin/` | Load the specified initial WordPress page in this Playground instance. |
-| `mode` | `browser-full-screen` | Determines how the WordPress instance is displayed. Either wrapped in a browser UI or full width as a seamless experience. Accepts `browser-full-screen`, or `seamless`. |
-| `lazy` | | Defer loading the Playground assets until someone clicks on the "Run" button. Does not accept any values. If `lazy` is added as a URL parameter, loading will be deferred. |
-| `login` | `yes` | Log the user in as an admin. Accepts `yes` or `no`. |
-| `multisite` | `no` | Enables the WordPress multisite mode. Accepts `yes` or `no`. |
-| `import-site` | | Imports site files and database from a ZIP file specified by a URL. |
-| `import-wxr` | | Imports site content from a WXR file specified by a URL. It uses the WordPress Importer plugin, so the default admin user must be logged in. |
-| `site-slug` | | Selects which site to load from browser storage. |
-| `language` | `en_US` | Sets the locale for the WordPress instance. This must be used in combination with `networking=yes` otherwise WordPress won't be able to download translations. |
-| `core-pr` | | Installs a specific https://github.com/WordPress/wordpress-develop core PR. Accepts the PR number. For example, `core-pr=6883`. |
-| `gutenberg-pr` | | Installs a specific https://github.com/WordPress/gutenberg PR. Accepts the PR number. For example, `gutenberg-pr=65337`. |
+| Option | Default Value | Description |
+| ------------------------ | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `php` | `8.0` | Loads the specified PHP version. Accepts `7.0`, `7.1`, `7.2`, `7.3`, `7.4`, `8.0`, `8.1`, `8.2`, `8.3`, or `latest`. |
+| `wp` | `latest` | Loads the specified WordPress version. Accepts the last three major WordPress versions. As of June 1, 2024, that's `6.3`, `6.4`, or `6.5`. You can also use the generic values `latest`, `nightly`, or `beta`. |
+| `blueprint-url` | | The URL of the Blueprint that will be used to configure this Playground instance. |
+| `networking` | `no` | Enables or disables the networking support for Playground. Accepts `yes` or `no`. |
+| `plugin` | | Installs the specified plugin. Use the plugin name from the WordPress Plugins Directory URL. For example, if the URL is `https://wordpress.org/plugins/wp-lazy-loading/`, the plugin name would be `wp-lazy-loading`. You can pre-install multiple plugins by saying `plugin=coblocks&plugin=wp-lazy-loading&…`. Installing a plugin automatically logs the user in as an admin. |
+| `theme` | | Installs the specified theme. Use the theme name from the WordPress Themes Directory URL. For example, if the URL is `https://wordpress.org/themes/disco/`, the theme name would be `disco`. Installing a theme automatically logs the user in as an admin. |
+| `url` | `/wp-admin/` | Load the specified initial WordPress page in this Playground instance. |
+| `mode` | `browser-full-screen` | Determines how the WordPress instance is displayed. Either wrapped in a browser UI or full width as a seamless experience. Accepts `browser-full-screen`, or `seamless`. |
+| `lazy` | | Defer loading the Playground assets until someone clicks on the "Run" button. Does not accept any values. If `lazy` is added as a URL parameter, loading will be deferred. |
+| `login` | `yes` | Log the user in as an admin. Accepts `yes` or `no`. |
+| `multisite` | `no` | Enables the WordPress multisite mode. Accepts `yes` or `no`. |
+| `import-site` | | Imports site files and database from a ZIP file specified by a URL. |
+| `import-wxr` | | Imports site content from a WXR file specified by a URL. It uses the WordPress Importer plugin, so the default admin user must be logged in. |
+| `site-slug` | | Selects which site to load from browser storage. |
+| `language` | `en_US` | Sets the locale for the WordPress instance. This must be used in combination with `networking=yes` otherwise WordPress won't be able to download translations. |
+| `core-pr` | | Installs a specific https://github.com/WordPress/wordpress-develop core PR. Accepts the PR number. For example, `core-pr=6883`. |
+| `gutenberg-pr` | | Installs a specific https://github.com/WordPress/gutenberg PR. Accepts the PR number. For example, `gutenberg-pr=65337`. |
+| `if-stored-site-missing` | | Indicates how to handle the scenario where the `site-slug` parameter identifies a site that does not exist. Use `if-stored-site-missing=prompt` to indicate that the user should be asked whether they would like to save a new site with the specified `site-slug`. |
For example, the following code embeds a Playground with a preinstalled Gutenberg plugin and opens the post editor: