diff --git a/packages/edit-site/src/components/list/actions/index.js b/packages/edit-site/src/components/list/actions/index.js
new file mode 100644
index 0000000000000..016196fb57c10
--- /dev/null
+++ b/packages/edit-site/src/components/list/actions/index.js
@@ -0,0 +1,95 @@
+/**
+ * WordPress dependencies
+ */
+import { useDispatch } from '@wordpress/data';
+import { store as coreStore } from '@wordpress/core-data';
+import { __ } from '@wordpress/i18n';
+import { DropdownMenu, MenuGroup, MenuItem } from '@wordpress/components';
+import { moreVertical } from '@wordpress/icons';
+import { store as noticesStore } from '@wordpress/notices';
+
+/**
+ * Internal dependencies
+ */
+import { store as editSiteStore } from '../../../store';
+import isTemplateRemovable from '../../../utils/is-template-removable';
+import isTemplateRevertable from '../../../utils/is-template-revertable';
+import RenameMenuItem from './rename-menu-item';
+
+export default function Actions( { template } ) {
+ const { removeTemplate, revertTemplate } = useDispatch( editSiteStore );
+ const { saveEditedEntityRecord } = useDispatch( coreStore );
+ const { createSuccessNotice, createErrorNotice } = useDispatch(
+ noticesStore
+ );
+
+ const isRemovable = isTemplateRemovable( template );
+ const isRevertable = isTemplateRevertable( template );
+
+ if ( ! isRemovable && ! isRevertable ) {
+ return null;
+ }
+
+ async function revertAndSaveTemplate() {
+ try {
+ await revertTemplate( template, { allowUndo: false } );
+ await saveEditedEntityRecord(
+ 'postType',
+ template.type,
+ template.id
+ );
+
+ createSuccessNotice( __( 'Template reverted.' ), {
+ type: 'snackbar',
+ } );
+ } catch ( error ) {
+ const errorMessage =
+ error.message && error.code !== 'unknown_error'
+ ? error.message
+ : __( 'An error occurred while reverting the template.' );
+
+ createErrorNotice( errorMessage, { type: 'snackbar' } );
+ }
+ }
+
+ return (
+
+ { ( { onClose } ) => (
+
+ { isRemovable && (
+ <>
+
+
+ >
+ ) }
+ { isRevertable && (
+
+ ) }
+
+ ) }
+
+ );
+}
diff --git a/packages/edit-site/src/components/list/actions/rename-menu-item.js b/packages/edit-site/src/components/list/actions/rename-menu-item.js
new file mode 100644
index 0000000000000..6d6b98edbb661
--- /dev/null
+++ b/packages/edit-site/src/components/list/actions/rename-menu-item.js
@@ -0,0 +1,134 @@
+/**
+ * WordPress dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import { useState } from '@wordpress/element';
+import { useDispatch, useSelect } from '@wordpress/data';
+import {
+ Button,
+ Flex,
+ FlexItem,
+ MenuItem,
+ Modal,
+ TextControl,
+} from '@wordpress/components';
+import { store as coreStore } from '@wordpress/core-data';
+import { store as noticesStore } from '@wordpress/notices';
+
+export default function RenameMenuItem( { template, onClose } ) {
+ const [ title, setTitle ] = useState( () => template.title.rendered );
+ const [ isModalOpen, setIsModalOpen ] = useState( false );
+
+ const { getLastEntitySaveError } = useSelect( coreStore );
+ const { editEntityRecord, saveEditedEntityRecord } = useDispatch(
+ coreStore
+ );
+ const { createSuccessNotice, createErrorNotice } = useDispatch(
+ noticesStore
+ );
+
+ if ( ! template.is_custom ) {
+ return null;
+ }
+
+ async function onTemplateRename( event ) {
+ event.preventDefault();
+
+ try {
+ await editEntityRecord( 'postType', template.type, template.id, {
+ title,
+ } );
+
+ // Update state before saving rerenders the list.
+ setTitle( '' );
+ setIsModalOpen( false );
+ onClose();
+
+ // Persist edited entity.
+ await saveEditedEntityRecord(
+ 'postType',
+ template.type,
+ template.id
+ );
+
+ const lastError = getLastEntitySaveError(
+ 'postType',
+ template.type,
+ template.id
+ );
+
+ if ( lastError ) {
+ throw lastError;
+ }
+
+ createSuccessNotice( __( 'Template has been renamed.' ), {
+ type: 'snackbar',
+ } );
+ } catch ( error ) {
+ const errorMessage =
+ error.message && error.code !== 'unknown_error'
+ ? error.message
+ : __( 'An error occurred while renaming the template.' );
+
+ createErrorNotice( errorMessage, { type: 'snackbar' } );
+ }
+ }
+
+ return (
+ <>
+
+ { isModalOpen && (
+ {
+ setIsModalOpen( false );
+ } }
+ overlayClassName="edit-site-list__rename-modal"
+ >
+
+
+ ) }
+ >
+ );
+}
diff --git a/packages/edit-site/src/components/list/style.scss b/packages/edit-site/src/components/list/style.scss
index 92af509852969..575348c7f65ad 100644
--- a/packages/edit-site/src/components/list/style.scss
+++ b/packages/edit-site/src/components/list/style.scss
@@ -128,3 +128,29 @@
margin-left: $nav-sidebar-width;
}
}
+
+.edit-site-list__rename-modal {
+ .components-base-control {
+ @include break-medium() {
+ width: $grid-unit * 40;
+ }
+ }
+
+ .components-modal__header {
+ border-bottom: none;
+ }
+
+ .components-modal__content::before {
+ margin-bottom: $grid-unit-05;
+ }
+}
+
+.edit-site-list__rename-modal-actions {
+ margin-top: $grid-unit-15;
+}
+
+.edit-site-template__actions {
+ button:not(:last-child) {
+ margin-right: $grid-unit-10;
+ }
+}
diff --git a/packages/edit-site/src/components/list/table.js b/packages/edit-site/src/components/list/table.js
index ce243e157f0e4..148b6b460c0ff 100644
--- a/packages/edit-site/src/components/list/table.js
+++ b/packages/edit-site/src/components/list/table.js
@@ -1,98 +1,19 @@
/**
* WordPress dependencies
*/
-import { useSelect, useDispatch } from '@wordpress/data';
+import { useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
import { __, sprintf } from '@wordpress/i18n';
import {
VisuallyHidden,
- DropdownMenu,
- MenuGroup,
- MenuItem,
__experimentalHeading as Heading,
} from '@wordpress/components';
-import { moreVertical } from '@wordpress/icons';
import { addQueryArgs } from '@wordpress/url';
-import { store as noticesStore } from '@wordpress/notices';
/**
* Internal dependencies
*/
-import { store as editSiteStore } from '../../store';
-import isTemplateRemovable from '../../utils/is-template-removable';
-import isTemplateRevertable from '../../utils/is-template-revertable';
-
-function Actions( { template } ) {
- const { removeTemplate, revertTemplate } = useDispatch( editSiteStore );
- const { saveEditedEntityRecord } = useDispatch( coreStore );
- const { createSuccessNotice, createErrorNotice } = useDispatch(
- noticesStore
- );
-
- const isRemovable = isTemplateRemovable( template );
- const isRevertable = isTemplateRevertable( template );
-
- if ( ! isRemovable && ! isRevertable ) {
- return null;
- }
-
- async function revertAndSaveTemplate() {
- try {
- await revertTemplate( template, { allowUndo: false } );
- await saveEditedEntityRecord(
- 'postType',
- template.type,
- template.id
- );
-
- createSuccessNotice( __( 'Template reverted.' ), {
- type: 'snackbar',
- } );
- } catch ( error ) {
- const errorMessage =
- error.message && error.code !== 'unknown_error'
- ? error.message
- : __( 'An error occurred while reverting the template.' );
-
- createErrorNotice( errorMessage, { type: 'snackbar' } );
- }
- }
-
- return (
-
- { ( { onClose } ) => (
-
- { isRemovable && (
-
- ) }
- { isRevertable && (
-
- ) }
-
- ) }
-
- );
-}
+import Actions from './actions';
export default function Table( { templateType } ) {
const { templates, isLoading, postType } = useSelect(