@wordpress/core-data 7.50.1-next.v.202607070741.0 → 7.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/build/actions.cjs +54 -1
- package/build/actions.cjs.map +3 -3
- package/build/components/entities-saved-states/entity-record-item.cjs +67 -0
- package/build/components/entities-saved-states/entity-record-item.cjs.map +7 -0
- package/build/components/entities-saved-states/entity-type-list.cjs +135 -0
- package/build/components/entities-saved-states/entity-type-list.cjs.map +7 -0
- package/build/components/entities-saved-states/hooks/use-is-dirty.cjs +97 -0
- package/build/components/entities-saved-states/hooks/use-is-dirty.cjs.map +7 -0
- package/build/components/entities-saved-states/index.cjs +215 -0
- package/build/components/entities-saved-states/index.cjs.map +7 -0
- package/build/entities.cjs +3 -1
- package/build/entities.cjs.map +2 -2
- package/build/private-actions.cjs +85 -0
- package/build/private-actions.cjs.map +3 -3
- package/build/private-apis.cjs +19 -0
- package/build/private-apis.cjs.map +3 -3
- package/build/utils/crdt.cjs +4 -2
- package/build/utils/crdt.cjs.map +2 -2
- package/build/utils/get-template-info.cjs +53 -0
- package/build/utils/get-template-info.cjs.map +7 -0
- package/build/utils/get-template-part-icon.cjs +43 -0
- package/build/utils/get-template-part-icon.cjs.map +7 -0
- package/build-module/actions.mjs +57 -1
- package/build-module/actions.mjs.map +2 -2
- package/build-module/components/entities-saved-states/entity-record-item.mjs +46 -0
- package/build-module/components/entities-saved-states/entity-record-item.mjs.map +7 -0
- package/build-module/components/entities-saved-states/entity-type-list.mjs +104 -0
- package/build-module/components/entities-saved-states/entity-type-list.mjs.map +7 -0
- package/build-module/components/entities-saved-states/hooks/use-is-dirty.mjs +72 -0
- package/build-module/components/entities-saved-states/hooks/use-is-dirty.mjs.map +7 -0
- package/build-module/components/entities-saved-states/index.mjs +187 -0
- package/build-module/components/entities-saved-states/index.mjs.map +7 -0
- package/build-module/entities.mjs +3 -1
- package/build-module/entities.mjs.map +2 -2
- package/build-module/private-actions.mjs +84 -0
- package/build-module/private-actions.mjs.map +2 -2
- package/build-module/private-apis.mjs +12 -0
- package/build-module/private-apis.mjs.map +2 -2
- package/build-module/utils/crdt.mjs +2 -1
- package/build-module/utils/crdt.mjs.map +2 -2
- package/build-module/utils/get-template-info.mjs +28 -0
- package/build-module/utils/get-template-info.mjs.map +7 -0
- package/build-module/utils/get-template-part-icon.mjs +24 -0
- package/build-module/utils/get-template-part-icon.mjs.map +7 -0
- package/build-types/actions.d.ts +3 -3
- package/build-types/actions.d.ts.map +1 -1
- package/build-types/awareness/base-awareness.d.ts +3 -0
- package/build-types/awareness/base-awareness.d.ts.map +1 -1
- package/build-types/awareness/post-editor-awareness.d.ts +7 -0
- package/build-types/awareness/post-editor-awareness.d.ts.map +1 -1
- package/build-types/batch/create-batch.d.ts +1 -1
- package/build-types/batch/create-batch.d.ts.map +1 -1
- package/build-types/components/entities-saved-states/entity-record-item.d.ts +6 -0
- package/build-types/components/entities-saved-states/entity-record-item.d.ts.map +1 -0
- package/build-types/components/entities-saved-states/entity-type-list.d.ts +6 -0
- package/build-types/components/entities-saved-states/entity-type-list.d.ts.map +1 -0
- package/build-types/components/entities-saved-states/hooks/use-is-dirty.d.ts +11 -0
- package/build-types/components/entities-saved-states/hooks/use-is-dirty.d.ts.map +1 -0
- package/build-types/components/entities-saved-states/index.d.ts +49 -0
- package/build-types/components/entities-saved-states/index.d.ts.map +1 -0
- package/build-types/entities.d.ts +2 -2
- package/build-types/entities.d.ts.map +1 -1
- package/build-types/entity-provider.d.ts +1 -1
- package/build-types/entity-provider.d.ts.map +1 -1
- package/build-types/entity-types/attachment.d.ts.map +1 -1
- package/build-types/entity-types/base-entity-records.d.ts.map +1 -1
- package/build-types/entity-types/base.d.ts.map +1 -1
- package/build-types/entity-types/comment.d.ts.map +1 -1
- package/build-types/entity-types/font-collection.d.ts.map +1 -1
- package/build-types/entity-types/font-family.d.ts.map +1 -1
- package/build-types/entity-types/global-styles-revision.d.ts.map +1 -1
- package/build-types/entity-types/icon.d.ts.map +1 -1
- package/build-types/entity-types/menu-location.d.ts.map +1 -1
- package/build-types/entity-types/nav-menu-item.d.ts.map +1 -1
- package/build-types/entity-types/nav-menu.d.ts.map +1 -1
- package/build-types/entity-types/page.d.ts.map +1 -1
- package/build-types/entity-types/plugin.d.ts.map +1 -1
- package/build-types/entity-types/post-revision.d.ts.map +1 -1
- package/build-types/entity-types/post-status.d.ts.map +1 -1
- package/build-types/entity-types/post.d.ts.map +1 -1
- package/build-types/entity-types/settings.d.ts.map +1 -1
- package/build-types/entity-types/sidebar.d.ts.map +1 -1
- package/build-types/entity-types/taxonomy.d.ts.map +1 -1
- package/build-types/entity-types/term.d.ts.map +1 -1
- package/build-types/entity-types/theme.d.ts.map +1 -1
- package/build-types/entity-types/type.d.ts.map +1 -1
- package/build-types/entity-types/user.d.ts.map +1 -1
- package/build-types/entity-types/widget-type.d.ts.map +1 -1
- package/build-types/entity-types/widget.d.ts.map +1 -1
- package/build-types/entity-types/wp-template-part.d.ts.map +1 -1
- package/build-types/entity-types/wp-template.d.ts.map +1 -1
- package/build-types/fetch/__experimental-fetch-url-data.d.ts +3 -0
- package/build-types/fetch/__experimental-fetch-url-data.d.ts.map +1 -1
- package/build-types/index.d.ts +17 -47
- package/build-types/index.d.ts.map +1 -1
- package/build-types/locks/actions.d.ts +1 -1
- package/build-types/locks/engine.d.ts +1 -1
- package/build-types/locks/utils.d.ts +1 -1
- package/build-types/locks/utils.d.ts.map +1 -1
- package/build-types/private-actions.d.ts +32 -1
- package/build-types/private-actions.d.ts.map +1 -1
- package/build-types/private-apis.d.ts +9 -0
- package/build-types/private-apis.d.ts.map +1 -1
- package/build-types/queried-data/actions.d.ts +1 -1
- package/build-types/queried-data/actions.d.ts.map +1 -1
- package/build-types/queried-data/get-query-parts.d.ts +21 -0
- package/build-types/queried-data/get-query-parts.d.ts.map +1 -1
- package/build-types/reducer.d.ts +3 -3
- package/build-types/reducer.d.ts.map +1 -1
- package/build-types/resolvers.d.ts +1 -1
- package/build-types/resolvers.d.ts.map +1 -1
- package/build-types/utils/crdt.d.ts +8 -0
- package/build-types/utils/crdt.d.ts.map +1 -1
- package/build-types/utils/get-template-info.d.ts +13 -0
- package/build-types/utils/get-template-info.d.ts.map +1 -0
- package/build-types/utils/get-template-part-icon.d.ts +9 -0
- package/build-types/utils/get-template-part-icon.d.ts.map +1 -0
- package/build-types/utils/log-entity-deprecation.d.ts +1 -1
- package/build-types/utils/log-entity-deprecation.d.ts.map +1 -1
- package/build-types/utils/on-sub-key.d.ts +4 -0
- package/build-types/utils/on-sub-key.d.ts.map +1 -0
- package/package.json +30 -25
- package/src/actions.js +92 -1
- package/src/components/entities-saved-states/entity-record-item.js +60 -0
- package/src/components/entities-saved-states/entity-type-list.js +130 -0
- package/src/components/entities-saved-states/hooks/use-is-dirty.js +101 -0
- package/src/components/entities-saved-states/index.js +242 -0
- package/src/components/entities-saved-states/style.scss +70 -0
- package/src/components/entities-saved-states/test/use-is-dirty.js +88 -0
- package/src/entities.js +3 -1
- package/src/private-actions.js +127 -0
- package/src/private-apis.ts +12 -0
- package/src/style.scss +1 -0
- package/src/test/actions.js +587 -0
- package/src/utils/crdt.ts +1 -1
- package/src/utils/get-template-info.js +52 -0
- package/src/utils/get-template-part-icon.js +30 -0
- package/src/utils/test/get-template-info.js +224 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/core-data",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.52.0",
|
|
4
4
|
"description": "Access to and manipulation of core WordPress entities.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -48,41 +48,46 @@
|
|
|
48
48
|
"build-module/index.mjs"
|
|
49
49
|
],
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@wordpress/api-fetch": "^7.
|
|
52
|
-
"@wordpress/block-editor": "^16.
|
|
53
|
-
"@wordpress/blocks": "^15.
|
|
54
|
-
"@wordpress/
|
|
55
|
-
"@wordpress/
|
|
56
|
-
"@wordpress/
|
|
57
|
-
"@wordpress/
|
|
58
|
-
"@wordpress/
|
|
59
|
-
"@wordpress/
|
|
60
|
-
"@wordpress/
|
|
61
|
-
"@wordpress/
|
|
62
|
-
"@wordpress/
|
|
63
|
-
"@wordpress/
|
|
64
|
-
"@wordpress/
|
|
65
|
-
"@wordpress/
|
|
66
|
-
"@wordpress/
|
|
51
|
+
"@wordpress/api-fetch": "^7.52.0",
|
|
52
|
+
"@wordpress/block-editor": "^16.1.0",
|
|
53
|
+
"@wordpress/blocks": "^15.25.0",
|
|
54
|
+
"@wordpress/components": "^38.0.0",
|
|
55
|
+
"@wordpress/compose": "^8.5.0",
|
|
56
|
+
"@wordpress/data": "^10.52.0",
|
|
57
|
+
"@wordpress/deprecated": "^4.52.0",
|
|
58
|
+
"@wordpress/element": "^8.4.0",
|
|
59
|
+
"@wordpress/global-styles-engine": "^1.19.0",
|
|
60
|
+
"@wordpress/html-entities": "^4.52.0",
|
|
61
|
+
"@wordpress/i18n": "^6.25.0",
|
|
62
|
+
"@wordpress/icons": "^15.3.0",
|
|
63
|
+
"@wordpress/is-shallow-equal": "^5.52.0",
|
|
64
|
+
"@wordpress/notices": "^5.52.0",
|
|
65
|
+
"@wordpress/private-apis": "^1.52.0",
|
|
66
|
+
"@wordpress/rich-text": "^7.52.0",
|
|
67
|
+
"@wordpress/sync": "^1.52.0",
|
|
68
|
+
"@wordpress/undo-manager": "^1.52.0",
|
|
69
|
+
"@wordpress/url": "^4.52.0",
|
|
70
|
+
"@wordpress/warning": "^3.52.0",
|
|
67
71
|
"change-case": "^4.1.2",
|
|
72
|
+
"clsx": "^2.1.1",
|
|
68
73
|
"equivalent-key-map": "^0.2.2",
|
|
69
74
|
"fast-deep-equal": "^3.1.3",
|
|
70
|
-
"memize": "^2.1.
|
|
75
|
+
"memize": "^2.1.1",
|
|
71
76
|
"uuid": "^14.0.0"
|
|
72
77
|
},
|
|
73
78
|
"devDependencies": {
|
|
74
|
-
"@jest/globals": "^30.
|
|
79
|
+
"@jest/globals": "^30.4.1",
|
|
75
80
|
"@testing-library/dom": "^10.4.1",
|
|
76
81
|
"@testing-library/react": "^16.3.2",
|
|
77
|
-
"@types/jest": "^
|
|
82
|
+
"@types/jest": "^30.0.0",
|
|
78
83
|
"@types/node": "^20.19.39",
|
|
79
|
-
"@wordpress/block-library": "^10.
|
|
84
|
+
"@wordpress/block-library": "^10.3.0",
|
|
80
85
|
"deep-freeze": "^0.0.1"
|
|
81
86
|
},
|
|
82
87
|
"peerDependencies": {
|
|
83
|
-
"@types/react": "^18
|
|
84
|
-
"react": "^18
|
|
85
|
-
"react-dom": "^18
|
|
88
|
+
"@types/react": "^18 || ^19",
|
|
89
|
+
"react": "^18 || ^19",
|
|
90
|
+
"react-dom": "^18 || ^19"
|
|
86
91
|
},
|
|
87
92
|
"peerDependenciesMeta": {
|
|
88
93
|
"@types/react": {
|
|
@@ -92,5 +97,5 @@
|
|
|
92
97
|
"publishConfig": {
|
|
93
98
|
"access": "public"
|
|
94
99
|
},
|
|
95
|
-
"gitHead": "
|
|
100
|
+
"gitHead": "7e8b17a983f9391d3ebc7717af2a1c9ed7efc7ab"
|
|
96
101
|
}
|
package/src/actions.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
+
import fastDeepEqual from 'fast-deep-equal/es6/index.js';
|
|
4
5
|
import { v4 as uuid } from 'uuid';
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -24,11 +25,71 @@ import {
|
|
|
24
25
|
getSyncManager,
|
|
25
26
|
} from './sync';
|
|
26
27
|
import logEntityDeprecation from './utils/log-entity-deprecation';
|
|
28
|
+
import {
|
|
29
|
+
getRawValue,
|
|
30
|
+
POST_META_KEY_FOR_CRDT_DOC_PERSISTENCE,
|
|
31
|
+
} from './utils/crdt';
|
|
27
32
|
|
|
28
33
|
function addTitleToAutoDraft( record ) {
|
|
29
34
|
return record.status === 'auto-draft' ? { ...record, title: '' } : record;
|
|
30
35
|
}
|
|
31
36
|
|
|
37
|
+
// Post meta is applied to the CRDT one subkey at a time, so compare the save
|
|
38
|
+
// response at the same granularity to avoid carrying stale sibling values.
|
|
39
|
+
function getServerMutatedMetaFields( updatedMeta, persistedMeta, syncedMeta ) {
|
|
40
|
+
const baseline = { ...persistedMeta, ...syncedMeta };
|
|
41
|
+
|
|
42
|
+
return Object.fromEntries(
|
|
43
|
+
Object.entries( updatedMeta ?? {} ).filter( ( [ key, value ] ) => {
|
|
44
|
+
if ( key === POST_META_KEY_FOR_CRDT_DOC_PERSISTENCE ) {
|
|
45
|
+
// The persisted CRDT snapshot may change on save and is
|
|
46
|
+
// intentionally excluded from CRDT meta synchronization, so it
|
|
47
|
+
// is not a server mutation.
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return ! fastDeepEqual( value, baseline[ key ] );
|
|
52
|
+
} )
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getServerMutatedFields(
|
|
57
|
+
updatedRecord,
|
|
58
|
+
persistedRecord,
|
|
59
|
+
syncedChanges
|
|
60
|
+
) {
|
|
61
|
+
return Object.fromEntries(
|
|
62
|
+
Object.entries( updatedRecord ).flatMap( ( [ key, value ] ) => {
|
|
63
|
+
if ( key === 'meta' ) {
|
|
64
|
+
const serverMutatedMeta = getServerMutatedMetaFields(
|
|
65
|
+
value,
|
|
66
|
+
persistedRecord.meta,
|
|
67
|
+
syncedChanges.meta
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
return Object.keys( serverMutatedMeta ).length
|
|
71
|
+
? [ [ key, serverMutatedMeta ] ]
|
|
72
|
+
: [];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const baseline =
|
|
76
|
+
key in syncedChanges
|
|
77
|
+
? syncedChanges[ key ]
|
|
78
|
+
: persistedRecord[ key ];
|
|
79
|
+
|
|
80
|
+
// The save response nests raw attributes as `{ raw, rendered }`
|
|
81
|
+
// while the baseline holds raw strings; compare raw values so the
|
|
82
|
+
// shape difference does not read as a server mutation.
|
|
83
|
+
const wasServerMutated = ! fastDeepEqual(
|
|
84
|
+
getRawValue( value ) ?? value,
|
|
85
|
+
getRawValue( baseline ) ?? baseline
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
return wasServerMutated ? [ [ key, value ] ] : [];
|
|
89
|
+
} )
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
32
93
|
/**
|
|
33
94
|
* Returns an action object used in signalling that authors have been received.
|
|
34
95
|
* Ignored from documentation as it's internal to the data store.
|
|
@@ -759,6 +820,23 @@ export const saveEntityRecord =
|
|
|
759
820
|
);
|
|
760
821
|
}
|
|
761
822
|
} else {
|
|
823
|
+
// `saveEntityRecord` can be called directly, bypassing
|
|
824
|
+
// `editEntityRecord`, so make sure its changes enter the
|
|
825
|
+
// CRDT before the persisted document is created below.
|
|
826
|
+
if (
|
|
827
|
+
entityConfig.syncConfig &&
|
|
828
|
+
! __unstableSkipSyncUpdate &&
|
|
829
|
+
! isNewRecord &&
|
|
830
|
+
persistedRecord
|
|
831
|
+
) {
|
|
832
|
+
getSyncManager()?.update(
|
|
833
|
+
`${ kind }/${ name }`,
|
|
834
|
+
recordId,
|
|
835
|
+
record,
|
|
836
|
+
LOCAL_UNDO_IGNORED_ORIGIN
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
|
|
762
840
|
let edits = record;
|
|
763
841
|
if ( entityConfig.__unstablePrePersist ) {
|
|
764
842
|
edits = {
|
|
@@ -783,12 +861,25 @@ export const saveEntityRecord =
|
|
|
783
861
|
edits
|
|
784
862
|
);
|
|
785
863
|
if ( entityConfig.syncConfig ) {
|
|
864
|
+
let syncChanges;
|
|
865
|
+
if ( __unstableSkipSyncUpdate ) {
|
|
866
|
+
syncChanges = {};
|
|
867
|
+
} else if ( isNewRecord || ! persistedRecord ) {
|
|
868
|
+
syncChanges = updatedRecord;
|
|
869
|
+
} else {
|
|
870
|
+
syncChanges = getServerMutatedFields(
|
|
871
|
+
updatedRecord,
|
|
872
|
+
persistedRecord,
|
|
873
|
+
record
|
|
874
|
+
);
|
|
875
|
+
}
|
|
876
|
+
|
|
786
877
|
// Use an untracked origin so that the save
|
|
787
878
|
// response does not create undo levels.
|
|
788
879
|
getSyncManager()?.update(
|
|
789
880
|
`${ kind }/${ name }`,
|
|
790
881
|
recordId,
|
|
791
|
-
|
|
882
|
+
syncChanges,
|
|
792
883
|
LOCAL_UNDO_IGNORED_ORIGIN,
|
|
793
884
|
{ isSave: true }
|
|
794
885
|
);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { CheckboxControl, PanelRow } from '@wordpress/components';
|
|
5
|
+
import { __ } from '@wordpress/i18n';
|
|
6
|
+
import { useSelect } from '@wordpress/data';
|
|
7
|
+
import { decodeEntities } from '@wordpress/html-entities';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Internal dependencies
|
|
11
|
+
*/
|
|
12
|
+
import { STORE_NAME } from '../../name';
|
|
13
|
+
import { getTemplateInfo } from '../../utils/get-template-info';
|
|
14
|
+
|
|
15
|
+
export default function EntityRecordItem( { record, checked, onChange } ) {
|
|
16
|
+
const { name, kind, title, key } = record;
|
|
17
|
+
|
|
18
|
+
// Handle templates that might use default descriptive titles.
|
|
19
|
+
const { entityRecordTitle } = useSelect(
|
|
20
|
+
( select ) => {
|
|
21
|
+
if ( 'postType' !== kind || 'wp_template' !== name ) {
|
|
22
|
+
return {
|
|
23
|
+
entityRecordTitle: title,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const template = select( STORE_NAME ).getEditedEntityRecord(
|
|
28
|
+
kind,
|
|
29
|
+
name,
|
|
30
|
+
key
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const { default_template_types: templateTypes = [] } =
|
|
34
|
+
select( STORE_NAME ).getCurrentTheme() ?? {};
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
entityRecordTitle: getTemplateInfo( {
|
|
38
|
+
template,
|
|
39
|
+
templateTypes,
|
|
40
|
+
} ).title,
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
[ name, kind, title, key ]
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<>
|
|
48
|
+
<PanelRow>
|
|
49
|
+
<CheckboxControl
|
|
50
|
+
label={
|
|
51
|
+
decodeEntities( entityRecordTitle ) || __( 'Untitled' )
|
|
52
|
+
}
|
|
53
|
+
checked={ checked }
|
|
54
|
+
onChange={ onChange }
|
|
55
|
+
className="entities-saved-states__change-control"
|
|
56
|
+
/>
|
|
57
|
+
</PanelRow>
|
|
58
|
+
</>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
|
+
import { useSelect } from '@wordpress/data';
|
|
6
|
+
import { PanelBody, PanelRow } from '@wordpress/components';
|
|
7
|
+
import { getGlobalStylesChanges } from '@wordpress/global-styles-engine';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Internal dependencies
|
|
11
|
+
*/
|
|
12
|
+
import EntityRecordItem from './entity-record-item';
|
|
13
|
+
import { STORE_NAME } from '../../name';
|
|
14
|
+
|
|
15
|
+
function getEntityDescription( entity, count ) {
|
|
16
|
+
switch ( entity ) {
|
|
17
|
+
case 'site':
|
|
18
|
+
return 1 === count
|
|
19
|
+
? __( 'This change will affect your whole site.' )
|
|
20
|
+
: __( 'These changes will affect your whole site.' );
|
|
21
|
+
case 'wp_template':
|
|
22
|
+
return __(
|
|
23
|
+
'This change will affect other parts of your site that use this template.'
|
|
24
|
+
);
|
|
25
|
+
case 'page':
|
|
26
|
+
case 'post':
|
|
27
|
+
return __( 'The following has been modified.' );
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function GlobalStylesDescription( { record } ) {
|
|
32
|
+
const { editedRecord, savedRecord } = useSelect(
|
|
33
|
+
( select ) => {
|
|
34
|
+
const { getEditedEntityRecord, getEntityRecord } =
|
|
35
|
+
select( STORE_NAME );
|
|
36
|
+
return {
|
|
37
|
+
editedRecord: getEditedEntityRecord(
|
|
38
|
+
record.kind,
|
|
39
|
+
record.name,
|
|
40
|
+
record.key
|
|
41
|
+
),
|
|
42
|
+
savedRecord: getEntityRecord(
|
|
43
|
+
record.kind,
|
|
44
|
+
record.name,
|
|
45
|
+
record.key
|
|
46
|
+
),
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
[ record.kind, record.name, record.key ]
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const globalStylesChanges = getGlobalStylesChanges(
|
|
53
|
+
editedRecord,
|
|
54
|
+
savedRecord,
|
|
55
|
+
{
|
|
56
|
+
maxResults: 10,
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
return globalStylesChanges.length ? (
|
|
60
|
+
<ul className="entities-saved-states__changes">
|
|
61
|
+
{ globalStylesChanges.map( ( change ) => (
|
|
62
|
+
<li key={ change }>{ change }</li>
|
|
63
|
+
) ) }
|
|
64
|
+
</ul>
|
|
65
|
+
) : null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function EntityDescription( { record, count } ) {
|
|
69
|
+
if ( 'globalStyles' === record?.name ) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
const description = getEntityDescription( record?.name, count );
|
|
73
|
+
return description ? <PanelRow>{ description }</PanelRow> : null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default function EntityTypeList( {
|
|
77
|
+
list,
|
|
78
|
+
unselectedEntities,
|
|
79
|
+
setUnselectedEntities,
|
|
80
|
+
} ) {
|
|
81
|
+
const count = list.length;
|
|
82
|
+
const firstRecord = list[ 0 ];
|
|
83
|
+
const entityConfig = useSelect(
|
|
84
|
+
( select ) =>
|
|
85
|
+
select( STORE_NAME ).getEntityConfig(
|
|
86
|
+
firstRecord.kind,
|
|
87
|
+
firstRecord.name
|
|
88
|
+
),
|
|
89
|
+
[ firstRecord.kind, firstRecord.name ]
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
let entityLabel = entityConfig.label;
|
|
93
|
+
if ( firstRecord?.name === 'wp_template_part' ) {
|
|
94
|
+
entityLabel =
|
|
95
|
+
1 === count ? __( 'Template Part' ) : __( 'Template Parts' );
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<PanelBody
|
|
100
|
+
title={ entityLabel }
|
|
101
|
+
initialOpen
|
|
102
|
+
className="entities-saved-states__panel-body"
|
|
103
|
+
>
|
|
104
|
+
<EntityDescription record={ firstRecord } count={ count } />
|
|
105
|
+
{ list.map( ( record ) => {
|
|
106
|
+
return (
|
|
107
|
+
<EntityRecordItem
|
|
108
|
+
key={ record.key || record.property }
|
|
109
|
+
record={ record }
|
|
110
|
+
checked={
|
|
111
|
+
! unselectedEntities.some(
|
|
112
|
+
( elt ) =>
|
|
113
|
+
elt.kind === record.kind &&
|
|
114
|
+
elt.name === record.name &&
|
|
115
|
+
elt.key === record.key &&
|
|
116
|
+
elt.property === record.property
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
onChange={ ( value ) =>
|
|
120
|
+
setUnselectedEntities( record, value )
|
|
121
|
+
}
|
|
122
|
+
/>
|
|
123
|
+
);
|
|
124
|
+
} ) }
|
|
125
|
+
{ 'globalStyles' === firstRecord?.name && (
|
|
126
|
+
<GlobalStylesDescription record={ firstRecord } />
|
|
127
|
+
) }
|
|
128
|
+
</PanelBody>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useSelect } from '@wordpress/data';
|
|
5
|
+
import { useMemo, useState } from '@wordpress/element';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Internal dependencies
|
|
9
|
+
*/
|
|
10
|
+
import { STORE_NAME } from '../../../name';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Custom hook that determines if any entities are dirty (edited) and provides a way to manage selected/unselected entities.
|
|
14
|
+
*
|
|
15
|
+
* @return {Object} An object containing the following properties:
|
|
16
|
+
* - dirtyEntityRecords: An array of dirty entity records.
|
|
17
|
+
* - isDirty: A boolean indicating if there are any dirty entity records.
|
|
18
|
+
* - setUnselectedEntities: A function to set the unselected entities.
|
|
19
|
+
* - unselectedEntities: An array of unselected entities.
|
|
20
|
+
*/
|
|
21
|
+
export const useIsDirty = () => {
|
|
22
|
+
const { editedEntities, siteEdits, siteEntityConfig } = useSelect(
|
|
23
|
+
( select ) => {
|
|
24
|
+
const {
|
|
25
|
+
__experimentalGetDirtyEntityRecords,
|
|
26
|
+
getEntityRecordEdits,
|
|
27
|
+
getEntityConfig,
|
|
28
|
+
} = select( STORE_NAME );
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
editedEntities: __experimentalGetDirtyEntityRecords(),
|
|
32
|
+
siteEdits: getEntityRecordEdits( 'root', 'site' ),
|
|
33
|
+
siteEntityConfig: getEntityConfig( 'root', 'site' ),
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
[]
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const dirtyEntityRecords = useMemo( () => {
|
|
40
|
+
// Remove site object and decouple into its edited pieces.
|
|
41
|
+
const editedEntitiesWithoutSite = editedEntities.filter(
|
|
42
|
+
( record ) => ! ( record.kind === 'root' && record.name === 'site' )
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const siteEntityLabels = siteEntityConfig?.meta?.labels ?? {};
|
|
46
|
+
const {
|
|
47
|
+
site_logo: siteLogoEdit,
|
|
48
|
+
site_icon: siteIconEdit,
|
|
49
|
+
...otherSiteEdits
|
|
50
|
+
} = siteEdits ?? {};
|
|
51
|
+
const orderedSiteProperties = [
|
|
52
|
+
siteLogoEdit !== undefined && 'site_logo',
|
|
53
|
+
siteIconEdit !== undefined && 'site_icon',
|
|
54
|
+
...Object.keys( otherSiteEdits ),
|
|
55
|
+
].filter( Boolean );
|
|
56
|
+
const editedSiteEntities = orderedSiteProperties.map(
|
|
57
|
+
( property ) => ( {
|
|
58
|
+
kind: 'root',
|
|
59
|
+
name: 'site',
|
|
60
|
+
title: siteEntityLabels[ property ] || property,
|
|
61
|
+
property,
|
|
62
|
+
} )
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
return [ ...editedEntitiesWithoutSite, ...editedSiteEntities ];
|
|
66
|
+
}, [ editedEntities, siteEdits, siteEntityConfig ] );
|
|
67
|
+
|
|
68
|
+
// Unchecked entities to be ignored by save function.
|
|
69
|
+
const [ unselectedEntities, _setUnselectedEntities ] = useState( [] );
|
|
70
|
+
|
|
71
|
+
const setUnselectedEntities = (
|
|
72
|
+
{ kind, name, key, property },
|
|
73
|
+
checked
|
|
74
|
+
) => {
|
|
75
|
+
if ( checked ) {
|
|
76
|
+
_setUnselectedEntities(
|
|
77
|
+
unselectedEntities.filter(
|
|
78
|
+
( elt ) =>
|
|
79
|
+
elt.kind !== kind ||
|
|
80
|
+
elt.name !== name ||
|
|
81
|
+
elt.key !== key ||
|
|
82
|
+
elt.property !== property
|
|
83
|
+
)
|
|
84
|
+
);
|
|
85
|
+
} else {
|
|
86
|
+
_setUnselectedEntities( [
|
|
87
|
+
...unselectedEntities,
|
|
88
|
+
{ kind, name, key, property },
|
|
89
|
+
] );
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const isDirty = dirtyEntityRecords.length - unselectedEntities.length > 0;
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
dirtyEntityRecords,
|
|
97
|
+
isDirty,
|
|
98
|
+
setUnselectedEntities,
|
|
99
|
+
unselectedEntities,
|
|
100
|
+
};
|
|
101
|
+
};
|