Skip to content

Commit

Permalink
Create new page (WordPress#50565)
Browse files Browse the repository at this point in the history
* create new page

* remove pages nesting

* add redirectAfterSave to add page modal

* reset redirectAfterSave

* adjust copy of new page to show draft

* redirect after adding page

* create page modal use local state

* fix import add page

* add page use onClose and remove setPage

* cleaning up add page

* removed value and used placeholder for add page

* add page modal translations

* e2e test new page modal

* move setting current canvas

* removed unnecessary help text

* Revert "move setting current canvas"

This reverts commit 79d1116.

* update add new page placeholder

* auto focus add new page input

Co-authored-by: Ramon <ramonjd@users.noreply.github.com>

* add no title placeholder

---------

Co-authored-by: Ramon <ramonjd@users.noreply.github.com>
  • Loading branch information
2 people authored and sethrubenstein committed Jul 13, 2023
1 parent e393252 commit 0a9c3c5
Show file tree
Hide file tree
Showing 3 changed files with 254 additions and 83 deletions.
105 changes: 105 additions & 0 deletions packages/edit-site/src/components/add-new-page/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/**
* External dependencies
*/
import { kebabCase } from 'lodash';

/**
* WordPress dependencies
*/
import {
Button,
Modal,
__experimentalHStack as HStack,
__experimentalVStack as VStack,
TextControl,
} from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import { useDispatch } from '@wordpress/data';
import { useState } from '@wordpress/element';
import { store as coreStore } from '@wordpress/core-data';
import { store as noticesStore } from '@wordpress/notices';

export default function AddNewPageModal( { onSave, onClose } ) {
const [ isCreatingPage, setIsCreatingPage ] = useState( false );
const [ title, setTitle ] = useState( '' );

const { saveEntityRecord } = useDispatch( coreStore );
const { createErrorNotice, createSuccessNotice } =
useDispatch( noticesStore );

async function createPage( event ) {
event.preventDefault();

if ( isCreatingPage ) {
return;
}
setIsCreatingPage( true );
try {
const newPage = await saveEntityRecord(
'postType',
'page',
{
status: 'draft',
title,
slug: kebabCase( title || __( 'No title' ) ),
},
{ throwOnError: true }
);

onSave( newPage );

createSuccessNotice(
sprintf(
// translators: %s: Title of the created template e.g: "Category".
__( '"%s" successfully created.' ),
newPage.title?.rendered || title
),
{
type: 'snackbar',
}
);
} catch ( error ) {
const errorMessage =
error.message && error.code !== 'unknown_error'
? error.message
: __( 'An error occurred while creating the page.' );

createErrorNotice( errorMessage, {
type: 'snackbar',
} );
} finally {
setIsCreatingPage( false );
}
}

return (
<Modal title={ __( 'Draft a new page' ) } onRequestClose={ onClose }>
<form onSubmit={ createPage }>
<VStack spacing={ 3 }>
<TextControl
/* eslint-disable jsx-a11y/no-autofocus */
autoFocus
/* eslint-enable jsx-a11y/no-autofocus */
label={ __( 'Page title' ) }
onChange={ setTitle }
placeholder={ __( 'No title' ) }
value={ title }
/>
<HStack spacing={ 2 } justify="end">
<Button variant="tertiary" onClick={ onClose }>
{ __( 'Cancel' ) }
</Button>
<Button
variant="primary"
type="submit"
isBusy={ isCreatingPage }
aria-disabled={ isCreatingPage }
>
{ __( 'Create draft' ) }
</Button>
</HStack>
</VStack>
</form>
</Modal>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import {
__experimentalTruncate as Truncate,
__experimentalVStack as VStack,
} from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { useEntityRecords, store as coreStore } from '@wordpress/core-data';
import { decodeEntities } from '@wordpress/html-entities';
import { layout, page, home, loop } from '@wordpress/icons';
import { privateApis as routerPrivateApis } from '@wordpress/router';
import { layout, page, home, loop, plus } from '@wordpress/icons';
import { useSelect } from '@wordpress/data';

/**
Expand All @@ -19,6 +21,11 @@ import { useSelect } from '@wordpress/data';
import SidebarNavigationScreen from '../sidebar-navigation-screen';
import { useLink } from '../routes/link';
import SidebarNavigationItem from '../sidebar-navigation-item';
import SidebarButton from '../sidebar-button';
import AddNewPageModal from '../add-new-page';
import { unlock } from '../../private-apis';

const { useHistory } = unlock( routerPrivateApis );

const PageItem = ( { postType = 'page', postId, ...props } ) => {
const linkInfo = useLink( {
Expand Down Expand Up @@ -85,98 +92,127 @@ export default function SidebarNavigationScreenPages() {
reorderedPages.splice( 1, 0, ...blogPage );
}

const [ showAddPage, setShowAddPage ] = useState( false );

const history = useHistory();

const handleNewPage = ( { type, id } ) => {
// Navigate to the created template editor.
history.push( {
postId: id,
postType: type,
canvas: 'edit',
} );
setShowAddPage( false );
};

return (
<SidebarNavigationScreen
title={ __( 'Pages' ) }
description={ __( 'Browse and edit pages on your site.' ) }
content={
<>
{ ( isLoadingPages || isLoadingTemplates ) && (
<ItemGroup>
<Item>{ __( 'Loading pages' ) }</Item>
</ItemGroup>
) }
{ ! ( isLoadingPages || isLoadingTemplates ) && (
<ItemGroup>
{ ! pagesAndTemplates?.length && (
<Item>{ __( 'No page found' ) }</Item>
) }
{ isHomePageBlog && homeTemplate && (
<PageItem
postType="wp_template"
postId={ homeTemplate.id }
key={ homeTemplate.id }
icon={ home }
withChevron
>
<Truncate numberOfLines={ 1 }>
{ decodeEntities(
homeTemplate.title?.rendered ||
__( '(no title)' )
) }
</Truncate>
</PageItem>
) }
{ reorderedPages?.map( ( item ) => {
let itemIcon;
switch ( item.id ) {
case frontPage:
itemIcon = home;
break;
case postsPage:
itemIcon = loop;
break;
default:
itemIcon = page;
}
return (
<PageItem
postId={ item.id }
key={ item.id }
icon={ itemIcon }
withChevron
>
<Truncate numberOfLines={ 1 }>
{ decodeEntities(
item?.title?.rendered ||
__( '(no title)' )
) }
</Truncate>
</PageItem>
);
} ) }
<VStack className="edit-site-sidebar-navigation-screen__sticky-section">
{ dynamicPageTemplates?.map( ( item ) => (
<>
{ showAddPage && (
<AddNewPageModal
onSave={ handleNewPage }
onClose={ () => setShowAddPage( false ) }
/>
) }
<SidebarNavigationScreen
title={ __( 'Pages' ) }
description={ __( 'Browse and edit pages on your site.' ) }
actions={
<SidebarButton
icon={ plus }
label={ __( 'Draft a new page' ) }
onClick={ () => setShowAddPage( true ) }
/>
}
content={
<>
{ ( isLoadingPages || isLoadingTemplates ) && (
<ItemGroup>
<Item>{ __( 'Loading pages' ) }</Item>
</ItemGroup>
) }
{ ! ( isLoadingPages || isLoadingTemplates ) && (
<ItemGroup>
{ ! pagesAndTemplates?.length && (
<Item>{ __( 'No page found' ) }</Item>
) }
{ isHomePageBlog && homeTemplate && (
<PageItem
postType="wp_template"
postId={ item.id }
key={ item.id }
icon={ layout }
postId={ homeTemplate.id }
key={ homeTemplate.id }
icon={ home }
withChevron
>
<Truncate numberOfLines={ 1 }>
{ decodeEntities(
item.title?.rendered ||
homeTemplate.title?.rendered ||
__( '(no title)' )
) }
</Truncate>
</PageItem>
) ) }
<SidebarNavigationItem
className="edit-site-sidebar-navigation-screen-pages__see-all"
href="edit.php?post_type=page"
onClick={ () => {
document.location =
'edit.php?post_type=page';
} }
>
{ __( 'Manage all pages' ) }
</SidebarNavigationItem>
</VStack>
</ItemGroup>
) }
</>
}
/>
) }
{ reorderedPages?.map( ( item ) => {
let itemIcon;
switch ( item.id ) {
case frontPage:
itemIcon = home;
break;
case postsPage:
itemIcon = loop;
break;
default:
itemIcon = page;
}
return (
<PageItem
postId={ item.id }
key={ item.id }
icon={ itemIcon }
withChevron
>
<Truncate numberOfLines={ 1 }>
{ decodeEntities(
item?.title?.rendered ||
__( '(no title)' )
) }
</Truncate>
</PageItem>
);
} ) }
<VStack className="edit-site-sidebar-navigation-screen__sticky-section">
{ dynamicPageTemplates?.map( ( item ) => (
<PageItem
postType="wp_template"
postId={ item.id }
key={ item.id }
icon={ layout }
withChevron
>
<Truncate numberOfLines={ 1 }>
{ decodeEntities(
item.title?.rendered ||
__( '(no title)' )
) }
</Truncate>
</PageItem>
) ) }
<SidebarNavigationItem
className="edit-site-sidebar-navigation-screen-pages__see-all"
href="edit.php?post_type=page"
onClick={ () => {
document.location =
'edit.php?post_type=page';
} }
>
{ __( 'Manage all pages' ) }
</SidebarNavigationItem>
</VStack>
</ItemGroup>
) }
</>
}
/>
</>
);
}
30 changes: 30 additions & 0 deletions test/e2e/specs/site-editor/pages.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* WordPress dependencies
*/
const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' );

test.describe( 'Pages', () => {
test.beforeAll( async ( { requestUtils } ) => {
await requestUtils.activateTheme( 'emptytheme' );
} );
test( 'Create a new page', async ( { admin, page } ) => {
const pageName = 'demo';
await admin.visitSiteEditor();
await page.getByRole( 'button', { name: 'Pages' } ).click();
await page.getByRole( 'button', { name: 'Draft a new page' } ).click();
// Fill the page title and submit.
const newPageDialog = page.locator(
'role=dialog[name="Draft a new page"i]'
);
const pageTitleInput = newPageDialog.locator(
'role=textbox[name="Page title"i]'
);
await pageTitleInput.fill( pageName );
await page.keyboard.press( 'Enter' );
await expect(
page.locator(
`role=button[name="Dismiss this notice"i] >> text="${ pageName }" successfully created.`
)
).toBeVisible();
} );
} );

0 comments on commit 0a9c3c5

Please sign in to comment.