Skip to content

Commit 0c9a7c1

Browse files
committed
DataViews: Register the reset template and template part action like any third-party action
1 parent 3687874 commit 0c9a7c1

File tree

8 files changed

+159
-140
lines changed

8 files changed

+159
-140
lines changed

docs/reference-guides/data/data-core.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ _Parameters_
790790
- _kind_ `string`: Kind of the entity.
791791
- _name_ `string`: Name of the entity.
792792
- _recordId_ `Object`: ID of the record.
793-
- _options_ `Object`: Saving options.
793+
- _options_ `Object=`: Saving options.
794794

795795
### saveEntityRecord
796796

packages/core-data/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ _Parameters_
299299
- _kind_ `string`: Kind of the entity.
300300
- _name_ `string`: Name of the entity.
301301
- _recordId_ `Object`: ID of the record.
302-
- _options_ `Object`: Saving options.
302+
- _options_ `Object=`: Saving options.
303303

304304
### saveEntityRecord
305305

packages/core-data/src/actions.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -773,10 +773,10 @@ export const __experimentalBatch =
773773
/**
774774
* Action triggered to save an entity record's edits.
775775
*
776-
* @param {string} kind Kind of the entity.
777-
* @param {string} name Name of the entity.
778-
* @param {Object} recordId ID of the record.
779-
* @param {Object} options Saving options.
776+
* @param {string} kind Kind of the entity.
777+
* @param {string} name Name of the entity.
778+
* @param {Object} recordId ID of the record.
779+
* @param {Object=} options Saving options.
780780
*/
781781
export const saveEditedEntityRecord =
782782
( kind, name, recordId, options ) =>

packages/editor/src/components/post-actions/actions.js

Lines changed: 1 addition & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import {
3131
} from '../../store/constants';
3232
import { store as editorStore } from '../../store';
3333
import { unlock } from '../../lock-unlock';
34-
import isTemplateRevertable from '../../store/utils/is-template-revertable';
3534
import { exportPatternAsJSONAction } from './export-pattern-action';
3635
import { CreateTemplatePartModalContents } from '../create-template-part-modal';
3736

@@ -804,114 +803,6 @@ const useDuplicatePostAction = ( postType ) => {
804803
);
805804
};
806805

807-
const resetTemplateAction = {
808-
id: 'reset-template',
809-
label: __( 'Reset' ),
810-
isEligible: ( item ) => {
811-
return isTemplateRevertable( item );
812-
},
813-
icon: backup,
814-
supportsBulk: true,
815-
hideModalHeader: true,
816-
RenderModal: ( { items, closeModal, onActionPerformed } ) => {
817-
const [ isBusy, setIsBusy ] = useState( false );
818-
const { revertTemplate } = unlock( useDispatch( editorStore ) );
819-
const { saveEditedEntityRecord } = useDispatch( coreStore );
820-
const { createSuccessNotice, createErrorNotice } =
821-
useDispatch( noticesStore );
822-
const onConfirm = async () => {
823-
try {
824-
for ( const template of items ) {
825-
await revertTemplate( template, {
826-
allowUndo: false,
827-
} );
828-
await saveEditedEntityRecord(
829-
'postType',
830-
template.type,
831-
template.id
832-
);
833-
}
834-
createSuccessNotice(
835-
items.length > 1
836-
? sprintf(
837-
/* translators: The number of items. */
838-
__( '%s items reset.' ),
839-
items.length
840-
)
841-
: sprintf(
842-
/* translators: The template/part's name. */
843-
__( '"%s" reset.' ),
844-
decodeEntities( getItemTitle( items[ 0 ] ) )
845-
),
846-
{
847-
type: 'snackbar',
848-
id: 'revert-template-action',
849-
}
850-
);
851-
} catch ( error ) {
852-
let fallbackErrorMessage;
853-
if ( items[ 0 ].type === TEMPLATE_POST_TYPE ) {
854-
fallbackErrorMessage =
855-
items.length === 1
856-
? __(
857-
'An error occurred while reverting the template.'
858-
)
859-
: __(
860-
'An error occurred while reverting the templates.'
861-
);
862-
} else {
863-
fallbackErrorMessage =
864-
items.length === 1
865-
? __(
866-
'An error occurred while reverting the template part.'
867-
)
868-
: __(
869-
'An error occurred while reverting the template parts.'
870-
);
871-
}
872-
const errorMessage =
873-
error.message && error.code !== 'unknown_error'
874-
? error.message
875-
: fallbackErrorMessage;
876-
877-
createErrorNotice( errorMessage, { type: 'snackbar' } );
878-
}
879-
};
880-
return (
881-
<VStack spacing="5">
882-
<Text>
883-
{ __( 'Reset to default and clear all customizations?' ) }
884-
</Text>
885-
<HStack justify="right">
886-
<Button
887-
variant="tertiary"
888-
onClick={ closeModal }
889-
disabled={ isBusy }
890-
__experimentalIsFocusable
891-
>
892-
{ __( 'Cancel' ) }
893-
</Button>
894-
<Button
895-
variant="primary"
896-
onClick={ async () => {
897-
setIsBusy( true );
898-
await onConfirm( items );
899-
onActionPerformed?.( items );
900-
setIsBusy( false );
901-
closeModal();
902-
} }
903-
isBusy={ isBusy }
904-
disabled={ isBusy }
905-
__experimentalIsFocusable
906-
>
907-
{ __( 'Reset' ) }
908-
</Button>
909-
</HStack>
910-
</VStack>
911-
);
912-
},
913-
};
914-
915806
export const duplicatePatternAction = {
916807
id: 'duplicate-pattern',
917808
label: _x( 'Duplicate', 'action label' ),
@@ -1037,9 +928,7 @@ export function usePostActions( { postType, onActionPerformed, context } ) {
1037928
isPattern && userCanCreatePostType && duplicatePatternAction,
1038929
supportsTitle && renamePostActionForPostType,
1039930
isPattern && exportPatternAsJSONAction,
1040-
isTemplateOrTemplatePart
1041-
? resetTemplateAction
1042-
: restorePostActionForPostType,
931+
! isTemplateOrTemplatePart && restorePostActionForPostType,
1043932
! isTemplateOrTemplatePart &&
1044933
! isPattern &&
1045934
trashPostActionForPostType,

packages/editor/src/dataviews/actions/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { type StoreDescriptor, dispatch } from '@wordpress/data';
77
* Internal dependencies
88
*/
99
import deletePost from './delete-post';
10+
import resetPost from './reset-post';
11+
1012
// @ts-ignore
1113
import { store as editorStore } from '../../store';
1214
import { unlock } from '../../lock-unlock';
@@ -16,5 +18,6 @@ export default function registerDefaultActions() {
1618
dispatch( editorStore as StoreDescriptor )
1719
);
1820

21+
registerEntityAction( 'postType', '*', resetPost );
1922
registerEntityAction( 'postType', '*', deletePost );
2023
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/**
2+
* WordPress dependencies
3+
*/
4+
import { backup } from '@wordpress/icons';
5+
import { useDispatch } from '@wordpress/data';
6+
import { store as coreStore } from '@wordpress/core-data';
7+
import { __, _n, sprintf, _x } from '@wordpress/i18n';
8+
import { store as noticesStore } from '@wordpress/notices';
9+
import { useState } from '@wordpress/element';
10+
import {
11+
Button,
12+
__experimentalText as Text,
13+
__experimentalHStack as HStack,
14+
__experimentalVStack as VStack,
15+
} from '@wordpress/components';
16+
import type { Action } from '@wordpress/dataviews';
17+
import type { StoreDescriptor } from '@wordpress/data';
18+
19+
/**
20+
* Internal dependencies
21+
*/
22+
import { TEMPLATE_POST_TYPE, TEMPLATE_ORIGINS } from '../../store/constants';
23+
import { store as editorStore } from '../../store';
24+
import { unlock } from '../../lock-unlock';
25+
import type { Post, CoreDataError } from '../types';
26+
import { isTemplateOrTemplatePart, getItemTitle } from './utils';
27+
28+
const resetPost: Action< Post > = {
29+
id: 'reset-post',
30+
label: __( 'Reset' ),
31+
isEligible: ( item ) => {
32+
return (
33+
isTemplateOrTemplatePart( item ) &&
34+
item?.source === TEMPLATE_ORIGINS.custom &&
35+
item?.has_theme_file
36+
);
37+
},
38+
icon: backup,
39+
supportsBulk: true,
40+
hideModalHeader: true,
41+
RenderModal: ( { items, closeModal, onActionPerformed } ) => {
42+
const [ isBusy, setIsBusy ] = useState( false );
43+
const { revertTemplate } = unlock(
44+
useDispatch( editorStore as StoreDescriptor )
45+
);
46+
const { saveEditedEntityRecord } = useDispatch( coreStore );
47+
const { createSuccessNotice, createErrorNotice } =
48+
useDispatch( noticesStore );
49+
const onConfirm = async () => {
50+
try {
51+
for ( const template of items ) {
52+
await revertTemplate( template, {
53+
allowUndo: false,
54+
} );
55+
await saveEditedEntityRecord(
56+
'postType',
57+
template.type,
58+
template.id
59+
);
60+
}
61+
createSuccessNotice(
62+
items.length > 1
63+
? sprintf(
64+
/* translators: The number of items. */
65+
__( '%s items reset.' ),
66+
items.length
67+
)
68+
: sprintf(
69+
/* translators: The template/part's name. */
70+
__( '"%s" reset.' ),
71+
getItemTitle( items[ 0 ] )
72+
),
73+
{
74+
type: 'snackbar',
75+
id: 'revert-template-action',
76+
}
77+
);
78+
} catch ( error ) {
79+
let fallbackErrorMessage;
80+
if ( items[ 0 ].type === TEMPLATE_POST_TYPE ) {
81+
fallbackErrorMessage =
82+
items.length === 1
83+
? __(
84+
'An error occurred while reverting the template.'
85+
)
86+
: __(
87+
'An error occurred while reverting the templates.'
88+
);
89+
} else {
90+
fallbackErrorMessage =
91+
items.length === 1
92+
? __(
93+
'An error occurred while reverting the template part.'
94+
)
95+
: __(
96+
'An error occurred while reverting the template parts.'
97+
);
98+
}
99+
100+
const typedError = error as CoreDataError;
101+
const errorMessage =
102+
typedError.message && typedError.code !== 'unknown_error'
103+
? typedError.message
104+
: fallbackErrorMessage;
105+
106+
createErrorNotice( errorMessage, { type: 'snackbar' } );
107+
}
108+
};
109+
return (
110+
<VStack spacing="5">
111+
<Text>
112+
{ __( 'Reset to default and clear all customizations?' ) }
113+
</Text>
114+
<HStack justify="right">
115+
<Button
116+
variant="tertiary"
117+
onClick={ closeModal }
118+
disabled={ isBusy }
119+
__experimentalIsFocusable
120+
>
121+
{ __( 'Cancel' ) }
122+
</Button>
123+
<Button
124+
variant="primary"
125+
onClick={ async () => {
126+
setIsBusy( true );
127+
await onConfirm();
128+
onActionPerformed?.( items );
129+
setIsBusy( false );
130+
closeModal?.();
131+
} }
132+
isBusy={ isBusy }
133+
disabled={ isBusy }
134+
__experimentalIsFocusable
135+
>
136+
{ __( 'Reset' ) }
137+
</Button>
138+
</HStack>
139+
</VStack>
140+
);
141+
},
142+
};
143+
144+
export default resetPost;

packages/editor/src/dataviews/actions/utils.ts

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import { decodeEntities } from '@wordpress/html-entities';
77
* Internal dependencies
88
*/
99
import {
10-
TEMPLATE_ORIGINS,
1110
TEMPLATE_PART_POST_TYPE,
1211
TEMPLATE_POST_TYPE,
1312
} from '../../store/constants';
@@ -26,23 +25,3 @@ export function getItemTitle( item: Post ) {
2625
}
2726
return decodeEntities( item.title?.rendered || '' );
2827
}
29-
30-
/**
31-
* Check if a template is removable.
32-
*
33-
* @param template The template entity to check.
34-
* @return Whether the template is removable.
35-
*/
36-
export function isTemplateRemovable( template: TemplateOrTemplatePart ) {
37-
if ( ! template ) {
38-
return false;
39-
}
40-
// In patterns list page we map the templates parts to a different object
41-
// than the one returned from the endpoint. This is why we need to check for
42-
// two props whether is custom or has a theme file.
43-
return (
44-
[ template.source, template.source ].includes(
45-
TEMPLATE_ORIGINS.custom
46-
) && ! template.has_theme_file
47-
);
48-
}

packages/editor/src/dataviews/types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,15 @@ export interface BasePost {
1111
status?: PostStatus;
1212
title: string | { rendered: string };
1313
type: string;
14+
id: string | number;
1415
}
1516
export interface TemplateOrTemplatePart extends BasePost {
16-
type: 'template' | 'template-part';
17+
type: 'wp_template' | 'wp_template_part';
1718
source: string;
1819
has_theme_file: boolean;
1920
}
2021

2122
export type Post = TemplateOrTemplatePart | BasePost;
23+
24+
// Will be unnecessary after typescript 5.0 upgrade.
25+
export type CoreDataError = { message?: string; code?: string };

0 commit comments

Comments
 (0)