-
Notifications
You must be signed in to change notification settings - Fork 50
Add the ability to copy an existing site #2107
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
base: trunk
Are you sure you want to change the base?
Changes from all commits
220e813
e7eaa46
53b4d26
f31765b
735b5e2
a7c4733
85c836d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import { MenuItem } from '@wordpress/components'; | ||
| import { __ } from '@wordpress/i18n'; | ||
| import { useI18n } from '@wordpress/react-i18n'; | ||
| import { useSiteDetails } from 'src/hooks/use-site-details'; | ||
| import { getIpcApi } from 'src/lib/get-ipc-api'; | ||
|
|
||
| type CopySiteProps = { | ||
| onClose: () => void; | ||
| }; | ||
|
|
||
| const CopySite = ( { onClose }: CopySiteProps ) => { | ||
| const { __ } = useI18n(); | ||
| const { selectedSite } = useSiteDetails(); | ||
|
|
||
| const isCopyDisabled = ! selectedSite; | ||
|
|
||
| return ( | ||
| <MenuItem | ||
| aria-disabled={ isCopyDisabled } | ||
| onClick={ () => { | ||
| if ( isCopyDisabled || ! selectedSite ) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unrelated to this PR, but I noticed the |
||
| return; | ||
| } | ||
| onClose(); | ||
| getIpcApi().triggerAddSiteCopy( selectedSite.id ); | ||
| } } | ||
| disabled={ isCopyDisabled } | ||
| > | ||
| { __( 'Copy site' ) } | ||
| </MenuItem> | ||
| ); | ||
| }; | ||
| export default CopySite; | ||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -34,6 +34,10 @@ interface SiteDetailsContext { | |||||||||||
| blueprint?: Blueprint, | ||||||||||||
| callback?: ( site: SiteDetails ) => Promise< void > | ||||||||||||
| ) => Promise< SiteDetails | void >; | ||||||||||||
| copySite: ( | ||||||||||||
| sourceId: string, | ||||||||||||
| config: Omit< CopySiteConfig, 'siteId' > | ||||||||||||
| ) => Promise< SiteDetails | void >; | ||||||||||||
| startServer: ( id: string ) => Promise< void >; | ||||||||||||
| stopServer: ( id: string ) => Promise< void >; | ||||||||||||
| stopAllRunningSites: () => Promise< void >; | ||||||||||||
|
|
@@ -55,6 +59,7 @@ const defaultContext: SiteDetailsContext = { | |||||||||||
| siteCreationMessages: {}, | ||||||||||||
| setSelectedSiteId: () => undefined, | ||||||||||||
| createSite: async () => undefined, | ||||||||||||
| copySite: async () => undefined, | ||||||||||||
| startServer: async () => undefined, | ||||||||||||
| stopServer: async () => undefined, | ||||||||||||
| stopAllRunningSites: async () => undefined, | ||||||||||||
|
|
@@ -186,6 +191,15 @@ export function SiteDetailsProvider( { children }: SiteDetailsProviderProps ) { | |||||||||||
| } | ||||||||||||
| } ); | ||||||||||||
|
|
||||||||||||
| useIpcListener( 'copySiteProgress', ( _, { siteId, message } ) => { | ||||||||||||
| if ( siteId && message ) { | ||||||||||||
| setSiteCreationMessages( ( prev ) => ( { | ||||||||||||
| ...prev, | ||||||||||||
| [ siteId ]: message, | ||||||||||||
| } ) ); | ||||||||||||
| } | ||||||||||||
| } ); | ||||||||||||
|
|
||||||||||||
| const toggleLoadingServerForSite = useCallback( ( siteId: string ) => { | ||||||||||||
| setLoadingServer( ( currentLoading ) => ( { | ||||||||||||
| ...currentLoading, | ||||||||||||
|
|
@@ -334,6 +348,95 @@ export function SiteDetailsProvider( { children }: SiteDetailsProviderProps ) { | |||||||||||
| [ selectedTab, setSelectedSiteId, setSelectedTab ] | ||||||||||||
| ); | ||||||||||||
|
|
||||||||||||
| const copySite = useCallback( | ||||||||||||
| async ( | ||||||||||||
| sourceId: string, | ||||||||||||
| config: Omit< CopySiteConfig, 'siteId' > | ||||||||||||
| ): Promise< SiteDetails | void > => { | ||||||||||||
| const tempSiteId = crypto.randomUUID(); | ||||||||||||
| setAddingSiteIds( ( prev ) => [ ...prev, tempSiteId ] ); | ||||||||||||
| setData( ( prevData ) => | ||||||||||||
| sortSites( [ | ||||||||||||
| ...prevData, | ||||||||||||
| { | ||||||||||||
| id: tempSiteId, | ||||||||||||
| name: config.newName, | ||||||||||||
| path: config.newPath, | ||||||||||||
| port: -1, | ||||||||||||
| running: false, | ||||||||||||
| isAddingSite: true, | ||||||||||||
| phpVersion: '', | ||||||||||||
| }, | ||||||||||||
| ] ) | ||||||||||||
| ); | ||||||||||||
| setSelectedSiteId( tempSiteId ); | ||||||||||||
|
|
||||||||||||
| let newSite: SiteDetails; | ||||||||||||
| try { | ||||||||||||
| newSite = await getIpcApi().copySite( sourceId, { | ||||||||||||
| ...config, | ||||||||||||
| siteId: tempSiteId, | ||||||||||||
| } ); | ||||||||||||
| if ( ! newSite ) { | ||||||||||||
| setTimeout( () => { | ||||||||||||
| setAddingSiteIds( ( prev ) => prev.filter( ( id ) => id !== tempSiteId ) ); | ||||||||||||
| setData( ( prevData ) => | ||||||||||||
| sortSites( prevData.filter( ( site ) => site.id !== tempSiteId ) ) | ||||||||||||
| ); | ||||||||||||
| }, 2000 ); | ||||||||||||
| return; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| setAddingSiteIds( ( prev ) => { | ||||||||||||
| prev.push( newSite.id ); | ||||||||||||
| return prev; | ||||||||||||
| } ); | ||||||||||||
|
Comment on lines
+390
to
+393
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
|
|
||||||||||||
| setSelectedSiteId( ( prevSelectedSiteId ) => { | ||||||||||||
| if ( prevSelectedSiteId === tempSiteId ) { | ||||||||||||
| if ( selectedTab !== 'overview' ) { | ||||||||||||
| setSelectedTab( 'overview' ); | ||||||||||||
| } | ||||||||||||
| return newSite.id; | ||||||||||||
| } | ||||||||||||
| return prevSelectedSiteId; | ||||||||||||
| } ); | ||||||||||||
|
|
||||||||||||
| setData( ( prevData ) => | ||||||||||||
| prevData.map( ( site ) => ( site.id === tempSiteId ? newSite : site ) ) | ||||||||||||
| ); | ||||||||||||
|
|
||||||||||||
| setSiteCreationMessages( ( prev ) => { | ||||||||||||
| const { [ newSite.id ]: _, ...rest } = prev; | ||||||||||||
| return rest; | ||||||||||||
| } ); | ||||||||||||
|
|
||||||||||||
| return newSite; | ||||||||||||
| } catch ( error ) { | ||||||||||||
| getIpcApi().showErrorMessageBox( { | ||||||||||||
| title: __( 'Failed to copy site' ), | ||||||||||||
| message: __( | ||||||||||||
| 'An error occurred while copying the site. Please try again. If this problem persists, please contact support.' | ||||||||||||
| ), | ||||||||||||
| error: simplifyErrorForDisplay( error ), | ||||||||||||
| showOpenLogs: true, | ||||||||||||
| } ); | ||||||||||||
|
|
||||||||||||
| setTimeout( () => { | ||||||||||||
| setAddingSiteIds( ( prev ) => prev.filter( ( id ) => id !== tempSiteId ) ); | ||||||||||||
| setData( ( prevData ) => | ||||||||||||
| sortSites( prevData.filter( ( site ) => site.id !== tempSiteId ) ) | ||||||||||||
| ); | ||||||||||||
| }, 2000 ); | ||||||||||||
| } finally { | ||||||||||||
| setAddingSiteIds( ( prev ) => | ||||||||||||
| prev.filter( ( id ) => id !== tempSiteId && id !== newSite?.id ) | ||||||||||||
| ); | ||||||||||||
| } | ||||||||||||
| }, | ||||||||||||
| [ selectedTab, setSelectedSiteId, setSelectedTab ] | ||||||||||||
| ); | ||||||||||||
|
|
||||||||||||
| const updateSite = useCallback( async ( site: SiteDetails ) => { | ||||||||||||
| await getIpcApi().updateSite( site ); | ||||||||||||
| const updatedSites = await getIpcApi().getSiteDetails(); | ||||||||||||
|
|
@@ -511,6 +614,7 @@ export function SiteDetailsProvider( { children }: SiteDetailsProviderProps ) { | |||||||||||
| data, | ||||||||||||
| setSelectedSiteId, | ||||||||||||
| createSite, | ||||||||||||
| copySite, | ||||||||||||
| updateSite, | ||||||||||||
| startServer, | ||||||||||||
| stopServer, | ||||||||||||
|
|
@@ -530,6 +634,7 @@ export function SiteDetailsProvider( { children }: SiteDetailsProviderProps ) { | |||||||||||
| data, | ||||||||||||
| setSelectedSiteId, | ||||||||||||
| createSite, | ||||||||||||
| copySite, | ||||||||||||
| updateSite, | ||||||||||||
| startServer, | ||||||||||||
| stopServer, | ||||||||||||
|
|
||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we move
CopySiteandDeleteSitetosrc/modules/site-settings.AFAIK these aren't being used anywhere else and
src/componentsshould be used for generic, reusable components.