Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions apps/cli/commands/site/set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export interface SetCommandOptions {
adminEmail?: string;
debugLog?: boolean;
debugDisplay?: boolean;
phpmyadmin?: boolean;
}

export async function runCommand( sitePath: string, options: SetCommandOptions ): Promise< void > {
Expand All @@ -68,6 +69,7 @@ export async function runCommand( sitePath: string, options: SetCommandOptions )
adminPassword,
debugLog,
debugDisplay,
phpmyadmin,
} = options;
let { adminEmail } = options;

Expand All @@ -82,11 +84,12 @@ export async function runCommand( sitePath: string, options: SetCommandOptions )
adminPassword === undefined &&
adminEmail === undefined &&
debugLog === undefined &&
debugDisplay === undefined
debugDisplay === undefined &&
phpmyadmin === undefined
) {
throw new LoggerError(
__(
'At least one option (--name, --domain, --https, --php, --wp, --xdebug, --admin-username, --admin-password, --admin-email, --debug-log, --debug-display) is required.'
'At least one option (--name, --domain, --https, --php, --wp, --xdebug, --admin-username, --admin-password, --admin-email, --debug-log, --debug-display, --phpmyadmin) is required.'
)
);
}
Expand Down Expand Up @@ -171,6 +174,7 @@ export async function runCommand( sitePath: string, options: SetCommandOptions )
const debugLogChanged = debugLog !== undefined && debugLog !== site.enableDebugLog;
const debugDisplayChanged =
debugDisplay !== undefined && debugDisplay !== site.enableDebugDisplay;
const phpmyadminChanged = phpmyadmin !== undefined && phpmyadmin !== site.enablePhpMyAdmin;

const hasChanges =
nameChanged ||
Expand All @@ -181,7 +185,8 @@ export async function runCommand( sitePath: string, options: SetCommandOptions )
xdebugChanged ||
credentialsChanged ||
debugLogChanged ||
debugDisplayChanged;
debugDisplayChanged ||
phpmyadminChanged;
if ( ! hasChanges ) {
throw new LoggerError(
__( 'No changes to apply. The site already has the specified settings.' )
Expand All @@ -197,6 +202,7 @@ export async function runCommand( sitePath: string, options: SetCommandOptions )
credentialsChanged,
debugLogChanged,
debugDisplayChanged,
phpmyadminChanged,
} );
const oldDomain = site.customDomain;

Expand Down Expand Up @@ -238,6 +244,9 @@ export async function runCommand( sitePath: string, options: SetCommandOptions )
if ( debugDisplayChanged ) {
foundSite.enableDebugDisplay = debugDisplay;
}
if ( phpmyadminChanged ) {
foundSite.enablePhpMyAdmin = phpmyadmin;
}

await saveAppdata( appdata );
site = foundSite;
Expand Down Expand Up @@ -392,6 +401,10 @@ export const registerCommand = ( yargs: StudioArgv ) => {
.option( 'debug-display', {
type: 'boolean',
description: __( 'Enable WP_DEBUG_DISPLAY' ),
} )
.option( 'phpmyadmin', {
type: 'boolean',
description: __( 'Enable phpMyAdmin' ),
} );
},
handler: async ( argv ) => {
Expand All @@ -408,6 +421,7 @@ export const registerCommand = ( yargs: StudioArgv ) => {
adminEmail: argv.adminEmail,
debugLog: argv.debugLog,
debugDisplay: argv.debugDisplay,
phpmyadmin: argv.phpmyadmin,
} );
} catch ( error ) {
if ( error instanceof LoggerError ) {
Expand Down
2 changes: 1 addition & 1 deletion apps/cli/commands/site/tests/set.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ describe( 'CLI: studio site set', () => {
describe( 'Validation', () => {
it( 'should throw when no options provided', async () => {
await expect( runCommand( testSitePath, {} ) ).rejects.toThrow(
'At least one option (--name, --domain, --https, --php, --wp, --xdebug, --admin-username, --admin-password, --admin-email, --debug-log, --debug-display) is required.'
'At least one option (--name, --domain, --https, --php, --wp, --xdebug, --admin-username, --admin-password, --admin-email, --debug-log, --debug-display, --phpmyadmin) is required.'
);
} );

Expand Down
1 change: 1 addition & 0 deletions apps/cli/lib/types/wordpress-server-ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const serverConfig = z.object( {
enableXdebug: z.boolean().optional(),
enableDebugLog: z.boolean().optional(),
enableDebugDisplay: z.boolean().optional(),
enablePhpMyAdmin: z.boolean().optional(),
blueprint: z
.object( {
contents: z.any(), // Blueprint type is complex, allow any for now
Expand Down
8 changes: 8 additions & 0 deletions apps/cli/lib/wordpress-server-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ export async function startWordPressServer(
serverConfig.enableDebugDisplay = true;
}

if ( site.enablePhpMyAdmin ) {
serverConfig.enablePhpMyAdmin = true;
}

const processDesc = await startProcess( processName, wordPressServerChildPath );
await waitForReadyMessage( processDesc.pmId );
await sendMessage(
Expand Down Expand Up @@ -366,6 +370,10 @@ export async function runBlueprint(
serverConfig.enableDebugDisplay = true;
}

if ( site.enablePhpMyAdmin ) {
serverConfig.enablePhpMyAdmin = true;
}

const processDesc = await startProcess( processName, wordPressServerChildPath );
try {
await waitForReadyMessage( processDesc.pmId );
Expand Down
29 changes: 29 additions & 0 deletions apps/cli/patches/@wp-playground+cli+3.1.12.patch

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions apps/cli/patches/@wp-playground+tools+3.1.12.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
diff --git a/node_modules/@wp-playground/tools/DbiMysqli-CmlcCdDi.js b/node_modules/@wp-playground/tools/DbiMysqli-CmlcCdDi.js
index f17cbe9..a8ac6d7 100644
--- a/node_modules/@wp-playground/tools/DbiMysqli-CmlcCdDi.js
+++ b/node_modules/@wp-playground/tools/DbiMysqli-CmlcCdDi.js
@@ -23,7 +23,7 @@ use WP_SQLite_Connection;
use WP_SQLite_Driver;

// Load the SQLite driver.
-require_once '/internal/shared/sqlite-database-integration/wp-pdo-mysql-on-sqlite.php';
+require_once '/wordpress/wp-content/mu-plugins/sqlite-database-integration/wp-pdo-mysql-on-sqlite.php';

// Supress the following phpMyAdmin warning:
// "The mysqlnd extension is missing. Please check your PHP configuration."
5 changes: 5 additions & 0 deletions apps/cli/wordpress-server-child.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,11 @@ async function getBaseRunCLIArgs(
args.xdebug = true;
}

if ( config.enablePhpMyAdmin ) {
logToConsole( 'Enabling phpMyAdmin support' );
args.phpmyadmin = true;
}

return args;
}

Expand Down
22 changes: 22 additions & 0 deletions apps/studio/src/components/content-tab-overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
archive,
code,
desktop,
grid,
pencil,
layout,
navigation,
Expand All @@ -17,6 +18,7 @@ import { useI18n } from '@wordpress/react-i18n';
import { useState } from 'react';
import { ArrowIcon } from 'src/components/arrow-icon';
import { ButtonsSection, ButtonsSectionProps } from 'src/components/buttons-section';
import { useOffline } from 'src/hooks/use-offline';
import { useSiteDetails } from 'src/hooks/use-site-details';
import { useThemeDetails } from 'src/hooks/use-theme-details';
import { isWindows } from 'src/lib/app-globals';
Expand Down Expand Up @@ -134,6 +136,9 @@ function CustomizeSection( {
function ShortcutsSection( { selectedSite }: Pick< ContentTabOverviewProps, 'selectedSite' > ) {
const { data: editor } = useGetUserEditorQuery();
const { data: terminal } = useGetUserTerminalQuery();
const { startServer, loadingServer } = useSiteDetails();
const isOffline = useOffline();
const isServerLoading = loadingServer[ selectedSite.id ];

const buttonsArray: ButtonsSectionProps[ 'buttonsArray' ] = [
{
Expand Down Expand Up @@ -176,6 +181,23 @@ function ShortcutsSection( { selectedSite }: Pick< ContentTabOverviewProps, 'sel
}
},
} );

buttonsArray.push( {
label: __( 'phpMyAdmin' ),
className: 'text-nowrap',
icon: grid,
disabled: ! selectedSite.enablePhpMyAdmin || isServerLoading || isOffline,
onClick: async () => {
if ( ! selectedSite.running ) {
await startServer( selectedSite );
}
getIpcApi().openSiteURL(
selectedSite.id,
'/phpmyadmin/index.php?route=/database/structure&db=wordpress'
);
},
} );

return <ButtonsSection buttonsArray={ buttonsArray } title={ __( 'Open in…' ) } />;
}

Expand Down
3 changes: 3 additions & 0 deletions apps/studio/src/components/content-tab-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ export function ContentTabSettings( { selectedSite }: ContentTabSettingsProps )
<SettingsRow label={ __( 'Debug display' ) }>
<span>{ selectedSite.enableDebugDisplay ? __( 'Enabled' ) : __( 'Disabled' ) }</span>
</SettingsRow>
<SettingsRow label={ __( 'phpMyAdmin' ) }>
<span>{ selectedSite.enablePhpMyAdmin ? __( 'Enabled' ) : __( 'Disabled' ) }</span>
</SettingsRow>

<tr>
<th colSpan={ 2 } className="pb-4 ltr:text-left rtl:text-right">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ describe( 'ContentTabSettings', () => {
).toHaveTextContent( 'localhost:8881' );
expect( screen.getByText( 'HTTPS' ) ).toBeVisible();
expect( screen.getByText( 'Xdebug' ) ).toBeVisible();
// HTTPS, Xdebug, Debug log, and Debug display show "Disabled"
expect( screen.getAllByText( 'Disabled' ) ).toHaveLength( 4 );
// HTTPS, Xdebug, Debug log, Debug display, and phpMyAdmin show "Disabled"
expect( screen.getAllByText( 'Disabled' ) ).toHaveLength( 5 );
expect( screen.getByRole( 'button', { name: 'Copy local path to clipboard' } ) ).toBeVisible();
expect( screen.getByText( '7.7.7' ) ).toBeVisible();
expect(
Expand Down
4 changes: 4 additions & 0 deletions apps/studio/src/ipc-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,10 @@ export async function updateSite(
options.debugDisplay = updatedSite.enableDebugDisplay ?? false;
}

if ( updatedSite.enablePhpMyAdmin !== currentSite.enablePhpMyAdmin ) {
options.phpmyadmin = updatedSite.enablePhpMyAdmin ?? false;
}

const hasCliChanges = Object.keys( options ).length > 2;

if ( hasCliChanges ) {
Expand Down
1 change: 1 addition & 0 deletions apps/studio/src/ipc-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ interface StoppedSiteDetails {
enableXdebug?: boolean;
enableDebugLog?: boolean;
enableDebugDisplay?: boolean;
enablePhpMyAdmin?: boolean;
sortOrder?: number;
}

Expand Down
5 changes: 5 additions & 0 deletions apps/studio/src/modules/cli/lib/cli-site-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface EditSiteOptions {
adminEmail?: string;
debugLog?: boolean;
debugDisplay?: boolean;
phpmyadmin?: boolean;
}

export async function editSiteViaCli( options: EditSiteOptions ): Promise< void > {
Expand Down Expand Up @@ -104,5 +105,9 @@ function buildCliArgs( options: EditSiteOptions ): string[] {
args.push( options.debugDisplay ? '--debug-display' : '--no-debug-display' );
}

if ( options.phpmyadmin !== undefined ) {
args.push( options.phpmyadmin ? '--phpmyadmin' : '--no-phpmyadmin' );
}

return args;
}
57 changes: 55 additions & 2 deletions apps/studio/src/modules/site-settings/edit-site-details.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { DEFAULT_PHP_VERSION, DEFAULT_WORDPRESS_VERSION } from '@studio/common/constants';
import {
DEFAULT_ENABLE_PHPMYADMIN,
DEFAULT_PHP_VERSION,
DEFAULT_WORDPRESS_VERSION,
} from '@studio/common/constants';
import {
generateCustomDomainFromSiteName,
getDomainNameValidationError,
Expand All @@ -20,10 +24,12 @@ import Button from 'src/components/button';
import { ErrorInformation } from 'src/components/error-information';
import { LearnMoreLink, LearnHowLink } from 'src/components/learn-more';
import Modal from 'src/components/modal';
import offlineIcon from 'src/components/offline-icon';
import PasswordControl from 'src/components/password-control';
import TextControlComponent from 'src/components/text-control';
import { Tooltip } from 'src/components/tooltip';
import { WPVersionSelector } from 'src/components/wp-version-selector';
import { useOffline } from 'src/hooks/use-offline';
import { useSiteDetails } from 'src/hooks/use-site-details';
import { cx } from 'src/lib/cx';
import { getIpcApi } from 'src/lib/get-ipc-api';
Expand All @@ -37,6 +43,7 @@ type EditSiteDetailsProps = {
const EditSiteDetails = ( { currentWpVersion, onSave }: EditSiteDetailsProps ) => {
const { __ } = useI18n();
const { updateSite, selectedSite, isEditModalOpen, setIsEditModalOpen } = useSiteDetails();
const isOffline = useOffline();
const [ errorUpdatingWpVersion, setErrorUpdatingWpVersion ] = useState< string | null >( null );
const [ isEditingSite, setIsEditingSite ] = useState( false );
const [ needsRestart, setNeedsRestart ] = useState( false );
Expand All @@ -45,6 +52,9 @@ const EditSiteDetails = ( { currentWpVersion, onSave }: EditSiteDetailsProps ) =
const [ enableDebugDisplay, setEnableDebugDisplay ] = useState(
selectedSite?.enableDebugDisplay ?? false
);
const [ enablePhpMyAdmin, setEnablePhpMyAdmin ] = useState(
selectedSite?.enablePhpMyAdmin ?? DEFAULT_ENABLE_PHPMYADMIN
);
const [ xdebugEnabledSite, setXdebugEnabledSite ] = useState< SiteDetails | null >( null );
const [ adminUsername, setAdminUsername ] = useState( selectedSite?.adminUsername ?? 'admin' );
const [ adminPassword, setAdminPassword ] = useState(
Expand Down Expand Up @@ -146,7 +156,8 @@ const EditSiteDetails = ( { currentWpVersion, onSave }: EditSiteDetailsProps ) =
( decodePassword( selectedSite.adminPassword ?? '' ) || 'password' ) === adminPassword &&
( selectedSite.adminEmail || 'admin@localhost.com' ) === adminEmail &&
!! selectedSite.enableDebugLog === enableDebugLog &&
!! selectedSite.enableDebugDisplay === enableDebugDisplay;
!! selectedSite.enableDebugDisplay === enableDebugDisplay &&
( selectedSite.enablePhpMyAdmin ?? DEFAULT_ENABLE_PHPMYADMIN ) === enablePhpMyAdmin;
const hasValidationErrors =
! selectedSite ||
! siteName.trim() ||
Expand All @@ -173,6 +184,7 @@ const EditSiteDetails = ( { currentWpVersion, onSave }: EditSiteDetailsProps ) =
setAdminEmail( selectedSite.adminEmail || 'admin@localhost.com' );
setEnableDebugLog( selectedSite.enableDebugLog ?? false );
setEnableDebugDisplay( selectedSite.enableDebugDisplay ?? false );
setEnablePhpMyAdmin( selectedSite.enablePhpMyAdmin ?? DEFAULT_ENABLE_PHPMYADMIN );
}, [ selectedSite, getEffectiveWpVersion ] );

const onSiteEdit = async ( event: FormEvent ) => {
Expand All @@ -189,6 +201,8 @@ const EditSiteDetails = ( { currentWpVersion, onSave }: EditSiteDetailsProps ) =
const hasDebugLogChanged = enableDebugLog !== ( selectedSite.enableDebugLog ?? false );
const hasDebugDisplayChanged =
enableDebugDisplay !== ( selectedSite.enableDebugDisplay ?? false );
const hasPhpMyAdminChanged =
enablePhpMyAdmin !== ( selectedSite.enablePhpMyAdmin ?? DEFAULT_ENABLE_PHPMYADMIN );
const hasDomainChanged =
Boolean( selectedSite.customDomain ) !== useCustomDomain ||
( useCustomDomain && customDomain !== selectedSite.customDomain );
Expand All @@ -210,6 +224,7 @@ const EditSiteDetails = ( { currentWpVersion, onSave }: EditSiteDetailsProps ) =
credentialsChanged: hasCredentialsChanged,
debugLogChanged: hasDebugLogChanged,
debugDisplayChanged: hasDebugDisplayChanged,
phpmyadminChanged: hasPhpMyAdminChanged,
} );
setNeedsRestart( needsRestart );

Expand All @@ -235,6 +250,7 @@ const EditSiteDetails = ( { currentWpVersion, onSave }: EditSiteDetailsProps ) =
adminEmail,
enableDebugLog,
enableDebugDisplay,
enablePhpMyAdmin,
},
hasWpVersionChanged ? selectedWpVersion : undefined
);
Expand Down Expand Up @@ -589,6 +605,43 @@ const EditSiteDetails = ( { currentWpVersion, onSave }: EditSiteDetailsProps ) =
) }
</div>
</div>

<div
className={ cx(
'flex flex-col gap-2 mt-4',
isEditingSite || isOffline ? 'opacity-50 cursor-not-allowed' : ''
) }
>
<Tooltip
disabled={ ! isOffline }
text={ __( 'Enabling phpMyAdmin requires an internet connection.' ) }
icon={ offlineIcon }
placement="top-start"
>
<div className="flex items-center gap-2">
<input
type="checkbox"
id="enable-phpmyadmin"
checked={ enablePhpMyAdmin }
onChange={ ( e ) => setEnablePhpMyAdmin( e.target.checked ) }
disabled={ isEditingSite || isOffline }
/>
<label
htmlFor="enable-phpmyadmin"
className={ cx(
isEditingSite || isOffline ? 'cursor-not-allowed' : ''
) }
>
{ __( 'Enable phpMyAdmin' ) }
</label>
</div>
</Tooltip>
<div className="text-a8c-gray-50 text-xs mt-1">
{ __(
'Access phpMyAdmin to browse and manage your site database. Requires internet to download.'
) }
</div>
</div>
</>
) }
</div>
Expand Down
Loading
Loading