diff --git a/packages/playground/website/src/components/layout/index.tsx b/packages/playground/website/src/components/layout/index.tsx index 5affcceebc..19a08dbc5d 100644 --- a/packages/playground/website/src/components/layout/index.tsx +++ b/packages/playground/website/src/components/layout/index.tsx @@ -32,6 +32,7 @@ import { import { ImportFormModal } from '../import-form-modal'; import { PreviewPRModal } from '../../github/preview-pr'; import { MissingSiteModal } from '../missing-site-modal'; +import { RenameSiteModal } from '../rename-site-modal'; acquireOAuthTokenIfNeeded(); @@ -45,6 +46,7 @@ export const modalSlugs = { PREVIEW_PR_WP: 'preview-pr-wordpress', PREVIEW_PR_GUTENBERG: 'preview-pr-gutenberg', MISSING_SITE_PROMPT: 'missing-site-prompt', + RENAME_SITE: 'rename-site', }; const displayMode = getDisplayModeFromQuery(); @@ -222,6 +224,8 @@ function Modals(blueprint: BlueprintDeclaration) { }} /> ); + } else if (currentModal === modalSlugs.RENAME_SITE) { + return ; } else if (currentModal === modalSlugs.MISSING_SITE_PROMPT) { return ; } diff --git a/packages/playground/website/src/components/modal/modal-buttons.tsx b/packages/playground/website/src/components/modal/modal-buttons.tsx index c9bbb0d9de..62e0033672 100644 --- a/packages/playground/website/src/components/modal/modal-buttons.tsx +++ b/packages/playground/website/src/components/modal/modal-buttons.tsx @@ -9,15 +9,17 @@ interface ModalButtonsProps { onCancel?: () => void; onSubmit?: (e: any) => void; } -export default function ModalButtons({ submitText = 'Submit', areDisabled = false, areBusy, onCancel, onSubmit }: ModalButtonsProps) { +export default function ModalButtons({ + submitText = 'Submit', + areDisabled = false, + areBusy, + onCancel, + onSubmit, +}: ModalButtonsProps) { return ( - + - ) + ); } diff --git a/packages/playground/website/src/components/rename-site-modal/index.tsx b/packages/playground/website/src/components/rename-site-modal/index.tsx new file mode 100644 index 0000000000..76d4c3f9a1 --- /dev/null +++ b/packages/playground/website/src/components/rename-site-modal/index.tsx @@ -0,0 +1,55 @@ +import { useDispatch } from 'react-redux'; +import SiteNameForm from '../site-name-form'; +import { Modal } from '../modal'; +import { setActiveModal } from '../../lib/state/redux/slice-ui'; +import type { PlaygroundDispatch } from '../../lib/state/redux/store'; +import { useActiveSite } from '../../lib/state/redux/store'; +import { updateSiteMetadata } from '../../lib/state/redux/slice-sites'; +import { useState } from 'react'; + +export const RenameSiteModal = () => { + const dispatch: PlaygroundDispatch = useDispatch(); + const [isUpdating, setIsUpdating] = useState(false); + + const activeSite = useActiveSite(); + + const closeModal = () => { + dispatch(setActiveModal(null)); + }; + + async function handleSubmit(newName: string) { + if (!activeSite || !activeSite.slug) { + return null; + } + setIsUpdating(true); + await dispatch( + updateSiteMetadata({ + slug: activeSite.slug, + changes: { + name: newName, + }, + }) + ); + setIsUpdating(false); + closeModal(); + } + + return ( + + + + ); +}; diff --git a/packages/playground/website/src/components/save-site-modal/index.tsx b/packages/playground/website/src/components/save-site-modal/index.tsx new file mode 100644 index 0000000000..6e8effc097 --- /dev/null +++ b/packages/playground/website/src/components/save-site-modal/index.tsx @@ -0,0 +1,62 @@ +import { useDispatch } from 'react-redux'; +import SiteNameForm from '../site-name-form'; +import { Modal } from '../modal'; +import type { PlaygroundDispatch } from '../../lib/state/redux/store'; +import { useActiveSite } from '../../lib/state/redux/store'; +import { updateSiteMetadata } from '../../lib/state/redux/slice-sites'; +import { useState } from 'react'; +import type { SiteStorageType } from '../../lib/site-metadata'; +import { persistTemporarySite } from '../../lib/state/redux/persist-temporary-site'; + +interface SaveSiteModalProps { + storageType: Extract; + onClose: () => void; +} + +export const SaveSiteModal = ({ storageType, onClose }: SaveSiteModalProps) => { + const dispatch: PlaygroundDispatch = useDispatch(); + const [isSaving, setIsSaving] = useState(false); + + const activeSite = useActiveSite(); + + const closeModal = () => { + onClose(); + }; + + async function handleSubmit(newName: string) { + if (!activeSite || !activeSite.slug) { + return null; + } + setIsSaving(true); + await dispatch( + updateSiteMetadata({ + slug: activeSite.slug, + changes: { + name: newName, + }, + }) + ); + await dispatch(persistTemporarySite(activeSite.slug, storageType)); + setIsSaving(false); + closeModal(); + } + + return ( + + + + ); +}; diff --git a/packages/playground/website/src/components/site-manager/site-info-panel/index.tsx b/packages/playground/website/src/components/site-manager/site-info-panel/index.tsx index 72a3fccb60..2c6b526e3e 100644 --- a/packages/playground/website/src/components/site-manager/site-info-panel/index.tsx +++ b/packages/playground/website/src/components/site-manager/site-info-panel/index.tsx @@ -18,6 +18,7 @@ import { usePlaygroundClientInfo } from '../../../lib/use-playground-client'; import { OfflineNotice } from '../../offline-notice'; import { DownloadAsZipMenuItem } from '../../toolbar-buttons/download-as-zip'; import { GithubExportMenuItem } from '../../toolbar-buttons/github-export-menu-item'; +import { RenameMenuItem } from '../../toolbar-buttons/rename-menu-item'; import { ReportError } from '../../toolbar-buttons/report-error'; import { TemporarySiteNotice } from '../temporary-site-notice'; import type { SiteInfo } from '../../../lib/state/redux/slice-sites'; @@ -222,6 +223,9 @@ export function SiteInfoPanel({ <> {!isTemporary && ( + | null; + storage?: PersistedSiteStorageType | null; }) { + const [selectedStorageType, setSelectedStorageType] = + useState(null); const clientInfo = useAppSelector((state) => selectClientInfoBySiteSlug(state, siteSlug) ); const localFsAvailability = useLocalFsAvailability(clientInfo?.client); - const dispatch = useAppDispatch(); + + const persistSiteClick = (storageType: PersistedSiteStorageType) => { + setSelectedStorageType(storageType); + }; + + if (selectedStorageType) { + return ( + setSelectedStorageType(null)} + /> + ); + } if (!clientInfo?.opfsSync || clientInfo.opfsSync?.status === 'error') { let button = null; if (storage) { button = ( -
- dispatch(persistTemporarySite(siteSlug, storage)) - } - > - {children} -
+
persistSiteClick(storage)}>{children}
); } else { button = ( - dispatch(persistTemporarySite(siteSlug, 'opfs')) - } + onClick={() => persistSiteClick('opfs')} > Save in this browser @@ -62,9 +69,7 @@ export function SitePersistButton({ - dispatch(persistTemporarySite(siteSlug, 'local-fs')) - } + onClick={() => persistSiteClick('local-fs')} > Save in a local directory diff --git a/packages/playground/website/src/components/site-name-form/index.tsx b/packages/playground/website/src/components/site-name-form/index.tsx new file mode 100644 index 0000000000..ffb28e4e6a --- /dev/null +++ b/packages/playground/website/src/components/site-name-form/index.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { useState } from 'react'; +import ModalButtons from '../modal/modal-buttons'; +import { TextControl } from '@wordpress/components'; + +interface SiteNameFormProps { + onClose: () => void; + onSubmit: (newName: string) => void; + isBusy: boolean; + siteName: string; + autoFocusNameInput?: boolean; +} + +export default function SiteNameForm({ + onClose, + onSubmit, + isBusy, + siteName, + autoFocusNameInput = false, +}: SiteNameFormProps) { + const [newName, setNewName] = useState(siteName); + + function submitOnEnter(e: React.KeyboardEvent) { + if (e.key === 'Enter') { + onSubmit(newName); + } + } + + return ( + <> + + + onSubmit(newName)} + submitText="Save" + areBusy={isBusy} + /> + + ); +} diff --git a/packages/playground/website/src/components/toolbar-buttons/rename-menu-item.tsx b/packages/playground/website/src/components/toolbar-buttons/rename-menu-item.tsx new file mode 100644 index 0000000000..3ba1e26ff3 --- /dev/null +++ b/packages/playground/website/src/components/toolbar-buttons/rename-menu-item.tsx @@ -0,0 +1,25 @@ +import { MenuItem } from '@wordpress/components'; +import { setActiveModal } from '../../lib/state/redux/slice-ui'; +import type { PlaygroundDispatch } from '../../lib/state/redux/store'; +import { useDispatch } from 'react-redux'; +import { modalSlugs } from '../layout'; + +interface Props { + onClose: () => void; + disabled?: boolean; +} +export function RenameMenuItem({ onClose, disabled }: Props) { + const dispatch: PlaygroundDispatch = useDispatch(); + return ( + { + dispatch(setActiveModal(modalSlugs.RENAME_SITE)); + onClose(); + }} + > + Rename + + ); +} diff --git a/packages/playground/website/src/lib/site-metadata.ts b/packages/playground/website/src/lib/site-metadata.ts index f0f179739a..d5629b3817 100644 --- a/packages/playground/website/src/lib/site-metadata.ts +++ b/packages/playground/website/src/lib/site-metadata.ts @@ -27,6 +27,10 @@ import { resolveBlueprintFromURL } from './state/url/resolve-blueprint-from-url' */ export const SiteStorageTypes = ['opfs', 'local-fs', 'none'] as const; export type SiteStorageType = (typeof SiteStorageTypes)[number]; +export type PersistedSiteStorageType = Extract< + SiteStorageType, + 'opfs' | 'local-fs' +>; /** * The site logo data. diff --git a/packages/playground/wordpress-builds/src/sqlite-database-integration/get-sqlite-driver-module-details.ts b/packages/playground/wordpress-builds/src/sqlite-database-integration/get-sqlite-driver-module-details.ts index 0cda6d0408..a185569ef5 100644 --- a/packages/playground/wordpress-builds/src/sqlite-database-integration/get-sqlite-driver-module-details.ts +++ b/packages/playground/wordpress-builds/src/sqlite-database-integration/get-sqlite-driver-module-details.ts @@ -19,7 +19,6 @@ export function getSqliteDriverModuleDetails( url: string; } { switch (version) { - case 'develop': /** @ts-ignore */ return { diff --git a/packages/playground/wordpress-builds/src/sqlite-database-integration/sqlite-database-integration-versions.json b/packages/playground/wordpress-builds/src/sqlite-database-integration/sqlite-database-integration-versions.json index 5ad5ea82d3..ae1c3ffcc9 100644 --- a/packages/playground/wordpress-builds/src/sqlite-database-integration/sqlite-database-integration-versions.json +++ b/packages/playground/wordpress-builds/src/sqlite-database-integration/sqlite-database-integration-versions.json @@ -1,4 +1,4 @@ { - "develop": "develop", - "v2.1.16": "v2.1.16" -} \ No newline at end of file + "develop": "develop", + "v2.1.16": "v2.1.16" +}