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

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions apps/ui/src/components/create-site-form/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useConnector } from '@/data/core';
import { usePathValidator } from '@/data/queries/use-create-site-helpers';
import { useSites } from '@/data/queries/use-sites';
import { useWordPressVersions } from '@/data/queries/use-wordpress-versions';
import { useOffline } from '@/hooks/use-offline';
import { CreateSiteForm } from './index';
import type { CreateSiteFormValues } from './index';

Expand All @@ -31,10 +32,15 @@ vi.mock( '@/data/queries/use-wordpress-versions', () => ( {
useWordPressVersions: vi.fn(),
} ) );

vi.mock( '@/hooks/use-offline', () => ( {
useOffline: vi.fn(),
} ) );

const useConnectorMock = vi.mocked( useConnector, { partial: true } );
const usePathValidatorMock = vi.mocked( usePathValidator, { partial: true } );
const useSitesMock = vi.mocked( useSites, { partial: true } );
const useWordPressVersionsMock = vi.mocked( useWordPressVersions, { partial: true } );
const useOfflineMock = vi.mocked( useOffline );

function deferred< T >() {
let resolve!: ( value: T ) => void;
Expand Down Expand Up @@ -113,6 +119,7 @@ describe( 'CreateSiteForm', () => {
} );
useSitesMock.mockReturnValue( { data: [] } );
useWordPressVersionsMock.mockReturnValue( { data: undefined } );
useOfflineMock.mockReturnValue( false );
usePathValidatorMock.mockReturnValue( {
generateProposedPath: vi.fn( async ( name: string ) => ( {
path: `/sites/${ name }`,
Expand Down Expand Up @@ -437,6 +444,29 @@ describe( 'CreateSiteForm', () => {
expect( screen.getByLabelText( 'WordPress version' ).tagName ).toBe( 'SELECT' );
} );

it( 'locks the WordPress version to a disabled "latest" select while offline', async () => {
useOfflineMock.mockReturnValue( true );
renderForm( { name: 'Offline site', wpVersion: '6.7' } );
openAdvancedSettings();

const select = screen.getByLabelText( 'WordPress version' );
expect( select.tagName ).toBe( 'SELECT' );
expect( select ).toBeDisabled();
await waitFor( () => expect( select ).toHaveValue( DEFAULT_WORDPRESS_VERSION ) );

const trigger = select.closest( 'div[style*="pointer-events"]' )?.parentElement as HTMLElement;
fireEvent.mouseEnter( trigger );
fireEvent.mouseMove( trigger, { movementX: 1, movementY: 1 } );
// Tooltips use Base UI's default open delay, so wait long enough for the popup.
expect(
await screen.findByText(
'Changing WordPress version requires an internet connection.',
{},
{ timeout: 2000 }
)
).toBeVisible();
} );

it( 'supports an external submission gate', async () => {
renderForm( { name: 'Blocked site' }, vi.fn(), true );

Expand Down
25 changes: 16 additions & 9 deletions apps/ui/src/components/create-site-form/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { useConnector } from '@/data/core';
import { usePathValidator } from '@/data/queries/use-create-site-helpers';
import { useSites } from '@/data/queries/use-sites';
import { useWordPressVersions } from '@/data/queries/use-wordpress-versions';
import { useOffline } from '@/hooks/use-offline';
import styles from './style.module.css';
import type { SupportedPHPVersion } from '@studio/common/types/php-versions';
import type {
Expand Down Expand Up @@ -433,14 +434,18 @@ export function CreateSiteForm( {
}, [ defaults, initialValues ] );

const { data: wpVersions } = useWordPressVersions();
const isOffline = useOffline();
// While offline, "latest" is the only version installable without a
// download, so it's forced — same as the legacy version selector.
useEffect( () => {
if ( ! wpVersions?.length ) return;
setData( ( prev ) =>
wpVersions.some( ( version ) => version.value === prev.wpVersion )
? prev
: { ...prev, wpVersion: DEFAULT_WORDPRESS_VERSION }
);
}, [ wpVersions, data.wpVersion ] );
if ( ! isOffline && ! wpVersions?.length ) return;
setData( ( prev ) => {
const keep =
prev.wpVersion === DEFAULT_WORDPRESS_VERSION ||
( ! isOffline && !! wpVersions?.some( ( version ) => version.value === prev.wpVersion ) );
return keep ? prev : { ...prev, wpVersion: DEFAULT_WORDPRESS_VERSION };
} );
}, [ wpVersions, isOffline, data.wpVersion ] );

const fields = useMemo< Field< FormData >[] >(
() => [
Expand All @@ -461,7 +466,9 @@ export function CreateSiteForm( {
},
},
phpVersionField< FormData >(),
wpVersionField< FormData >( DEFAULT_WORDPRESS_VERSION, wpVersions ),
wpVersionField< FormData >( DEFAULT_WORDPRESS_VERSION, wpVersions, {
offline: isOffline,
} ),
adminUsernameField< FormData >(),
adminPasswordField< FormData >(),
adminEmailField< FormData >(),
Expand All @@ -475,7 +482,7 @@ export function CreateSiteForm( {
Edit: EnableHttpsControl,
},
],
[ existingDomainNames, wpVersions ]
[ existingDomainNames, isOffline, wpVersions ]
);

const basicForm = useMemo< Form >(
Expand Down
Loading