@automattic/jetpack-shared-extension-utils 0.12.6 → 0.13.1

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 CHANGED
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.13.1] - 2023-11-14
9
+ ### Changed
10
+ - Updated package dependencies. [#34093]
11
+
12
+ ## [0.13.0] - 2023-11-13
13
+ ### Added
14
+ - Added a Redux store for Jetpack modules data. [#33397]
15
+
8
16
  ## [0.12.6] - 2023-11-08
9
17
  ### Fixed
10
18
  - Mobile: Fix a regression preventing correct block registration on mobile. [#33890]
@@ -280,6 +288,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
280
288
  ### Changed
281
289
  - Core: prepare utility for release
282
290
 
291
+ [0.13.1]: https://github.com/Automattic/jetpack-shared-extension-utils/compare/0.13.0...0.13.1
292
+ [0.13.0]: https://github.com/Automattic/jetpack-shared-extension-utils/compare/0.12.6...0.13.0
283
293
  [0.12.6]: https://github.com/Automattic/jetpack-shared-extension-utils/compare/0.12.5...0.12.6
284
294
  [0.12.5]: https://github.com/Automattic/jetpack-shared-extension-utils/compare/0.12.4...0.12.5
285
295
  [0.12.4]: https://github.com/Automattic/jetpack-shared-extension-utils/compare/0.12.3...0.12.4
package/README.md CHANGED
@@ -8,6 +8,64 @@ of the Jetpack plugin, so that plugins can share it. To begin with, we moving
8
8
  the code used by the Publicize editor extension, but the goal is to bring over
9
9
  all the shared code.
10
10
 
11
+ ## Fetching modules data from the store
12
+ The package relies on [controls](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/#controls)
13
+ and [resolvers](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/#resolvers)
14
+ to pull modules data from the API, and put it into the package's Redux store.
15
+
16
+ ### Basic Usage
17
+
18
+ In order to have all modules related data synced within different packages, let's use this Redux store as a source of truth, for both, getting and updating the data.
19
+
20
+
21
+ Use [`withSelect`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/#withselect), `withDispatch` higher-order component to pull the data or [`useSelect`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-data/#useselect) hook to pull the data from the store to pull directly in component. Example:
22
+
23
+
24
+ ```jsx
25
+ // Imports.
26
+ import { withSelect, withDispatch } from '@wordpress/data';
27
+ import { JETPACK_MODULES_STORE_ID } from '@automattic/jetpack-shared-extension-utils';
28
+
29
+ const SampleComponent = props => {
30
+ const { isModuleActive, isLoadingModules, isChangingStatus, updateJetpackModuleStatus } = props;
31
+
32
+ if ( isModuleActive ) {
33
+ return <div>Module is active</div>;
34
+ }
35
+
36
+ if ( isLoadingModules ) {
37
+ return <div>Loading modules...</div>;
38
+ }
39
+
40
+ if ( !isModuleActive ) {
41
+ return <button onClick={ () => updateJetpackModuleStatus( 'contact-form', true ) }>
42
+ Activate module
43
+ </button>;
44
+ }
45
+
46
+ return <div>Active contact form module</div>;
47
+ }
48
+
49
+ // We wrap `SampleComponent` into the composition of `withSelect` and `withDispatch` HOCs,
50
+ // which will pull the data from the store and pass as a parameter into the component.
51
+ // Jetpack modules will be pulled after first selection `isModuleActive`.
52
+ export default compose( [
53
+ withSelect( ( select, props ) => {
54
+ const { isModuleActive, areModulesLoading, areModulesUpdating } = select( 'jetpack-modules' );
55
+ return {
56
+ isModuleActive: isModuleActive( 'contact-form' ),
57
+ isLoadingModules: areModulesLoading(),
58
+ isChangingStatus: areModulesUpdating(),
59
+ };
60
+ } ),
61
+ withDispatch( dispatch => {
62
+ const { updateJetpackModuleStatus } = dispatch( 'jetpack-modules' );
63
+ return { updateJetpackModuleStatus };
64
+ } ),
65
+ ] )( ( SampleComponent ) );
66
+ ```
67
+
68
+
11
69
  ## How to install shared-extension-utils
12
70
 
13
71
  ### Installation From Git Repo
package/index.js CHANGED
@@ -18,3 +18,5 @@ export { default as useAnalytics } from './src/hooks/use-analytics';
18
18
  export { default as useModuleStatus } from './src/hooks/use-module-status';
19
19
  export { default as JetpackEditorPanelLogo } from './src/components/jetpack-editor-panel-logo';
20
20
  export { getBlockIconComponent, getBlockIconProp } from './src/get-block-icon-from-metadata';
21
+
22
+ export * from './src/modules-state';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/jetpack-shared-extension-utils",
3
- "version": "0.12.6",
3
+ "version": "0.13.1",
4
4
  "description": "Utility functions used by the block editor extensions",
5
5
  "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/shared-extension-utils/#readme",
6
6
  "bugs": {
@@ -18,14 +18,15 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "@automattic/jetpack-analytics": "^0.1.27",
21
- "@automattic/jetpack-components": "^0.44.4",
22
- "@automattic/jetpack-connection": "^0.30.5",
23
- "@wordpress/api-fetch": "6.41.0",
24
- "@wordpress/compose": "6.21.0",
25
- "@wordpress/element": "5.21.0",
26
- "@wordpress/i18n": "4.44.0",
27
- "@wordpress/plugins": "6.12.0",
28
- "@wordpress/url": "3.45.0",
21
+ "@automattic/jetpack-components": "^0.45.1",
22
+ "@automattic/jetpack-connection": "^0.30.7",
23
+ "@wordpress/api-fetch": "6.42.0",
24
+ "@wordpress/compose": "6.22.0",
25
+ "@wordpress/data": "9.15.0",
26
+ "@wordpress/element": "5.22.0",
27
+ "@wordpress/i18n": "4.45.0",
28
+ "@wordpress/plugins": "6.13.0",
29
+ "@wordpress/url": "3.46.0",
29
30
  "lodash": "4.17.21"
30
31
  },
31
32
  "devDependencies": {
@@ -42,7 +43,7 @@
42
43
  "@testing-library/react": "13.4.0",
43
44
  "@testing-library/user-event": "14.4.3",
44
45
  "@babel/plugin-transform-react-jsx": "7.22.15",
45
- "@wordpress/babel-plugin-import-jsx-pragma": "4.27.0"
46
+ "@wordpress/babel-plugin-import-jsx-pragma": "4.28.0"
46
47
  },
47
48
  "exports": {
48
49
  ".": "./index.js"
@@ -0,0 +1,96 @@
1
+ import { select } from '@wordpress/data';
2
+ import { isSimpleSite } from '../site-type-utils';
3
+ import {
4
+ fetchJetpackModules,
5
+ updateJetpackModuleStatus as updateJetpackModuleStatusControl,
6
+ } from './controls';
7
+ import { JETPACK_MODULES_STORE_ID } from '.';
8
+
9
+ export const SET_JETPACK_MODULES = 'SET_JETPACK_MODULES';
10
+
11
+ /**
12
+ * Yield actions to update module status
13
+ *
14
+ * @param {object} settings - Jetpack module settings.
15
+ * @param {string} settings.name - Jetpack module name.
16
+ * @param {boolean} settings.active - If the module is active or not.
17
+ * @yields {object} - an action object.
18
+ * @returns {object} - an action object.
19
+ */
20
+ export function* updateJetpackModuleStatus( settings ) {
21
+ try {
22
+ const originalData = select( JETPACK_MODULES_STORE_ID ).getJetpackModules();
23
+ yield setIsUpdating( true );
24
+ if ( originalData.data?.[ settings.name ]?.activated !== settings.active ) {
25
+ yield setJetpackModules( originalData );
26
+ }
27
+ yield updateJetpackModuleStatusControl( settings );
28
+ const data = yield fetchJetpackModules();
29
+ yield setJetpackModules( { data } );
30
+ return true;
31
+ } catch ( e ) {
32
+ const oldSettings = select( JETPACK_MODULES_STORE_ID ).getJetpackModules();
33
+ yield setJetpackModules( oldSettings );
34
+ return false;
35
+ } finally {
36
+ yield setIsUpdating( false );
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Yield actions to update module status
42
+ * @yields {object} - an action object.
43
+ * @returns {boolean} - if operation is successful or not.
44
+ */
45
+ export function* fetchModules() {
46
+ // We don't fetch modules for Simple Site and aknowledge that all modules are active
47
+ if ( isSimpleSite() ) {
48
+ return true;
49
+ }
50
+ try {
51
+ yield setIsLoading( true );
52
+ const data = yield fetchJetpackModules();
53
+ yield setJetpackModules( { data } );
54
+ return true;
55
+ } catch ( e ) {
56
+ const oldSettings = select( JETPACK_MODULES_STORE_ID ).getJetpackModules();
57
+ yield setJetpackModules( oldSettings );
58
+ return false;
59
+ } finally {
60
+ yield setIsLoading( false );
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Set modules as loading action
66
+ *
67
+ * @param {boolean} isLoading - If the modules are loading or not.
68
+ * @returns {object} - an action object.
69
+ */
70
+ function setIsLoading( isLoading ) {
71
+ return setJetpackModules( { isLoading } );
72
+ }
73
+
74
+ /**
75
+ * Set modules as updating action
76
+ *
77
+ * @param {boolean} isUpdating - If the modules are updating or not.
78
+ * @returns {object} - an action object.
79
+ */
80
+ function setIsUpdating( isUpdating ) {
81
+ return setJetpackModules( { isUpdating } );
82
+ }
83
+
84
+ /**
85
+ * Set Jetpack module action
86
+ *
87
+ * @param {object} options - Jetpack settings.
88
+ * @param {object} options.modules - Jetpack modules.
89
+ * @param {boolean} options.isLoading - If the modules are loading or not.
90
+ * @returns {object} - an action object.
91
+ */
92
+ export function setJetpackModules( options ) {
93
+ return { type: SET_JETPACK_MODULES, options };
94
+ }
95
+
96
+ export default { updateJetpackModuleStatus, setJetpackModules, fetchModules };
@@ -0,0 +1,48 @@
1
+ import apiFetch from '@wordpress/api-fetch';
2
+
3
+ export const FETCH_JETPACK_MODULES = 'FETCH_JETPACK_MODULES';
4
+ export const UPDATE_JETPACK_MODULE_STATUS = 'UPDATE_JETPACK_MODULE_STATUS';
5
+
6
+ /**
7
+ * fetchJetpackModules action
8
+ *
9
+ * @returns {object} - an action object.
10
+ */
11
+ export const fetchJetpackModules = () => {
12
+ return {
13
+ type: FETCH_JETPACK_MODULES,
14
+ };
15
+ };
16
+
17
+ /**
18
+ * Updating single module status action
19
+ *
20
+ * @param settings - Jetpack module settings.
21
+ * @param {string} settings.name - Jetpack module name.
22
+ * @param {boolean} settings.active - If the module is active or not.
23
+ */
24
+
25
+ export const updateJetpackModuleStatus = settings => {
26
+ return {
27
+ type: UPDATE_JETPACK_MODULE_STATUS,
28
+ settings,
29
+ };
30
+ };
31
+
32
+ export default {
33
+ [ FETCH_JETPACK_MODULES ]: function () {
34
+ return apiFetch( {
35
+ path: `/jetpack/v4/module/all`,
36
+ method: 'GET',
37
+ } );
38
+ },
39
+ [ UPDATE_JETPACK_MODULE_STATUS ]: function ( { settings } ) {
40
+ return apiFetch( {
41
+ path: `/jetpack/v4/module/${ settings.name }/active`,
42
+ method: 'POST',
43
+ data: {
44
+ active: settings.active,
45
+ },
46
+ } );
47
+ },
48
+ };
@@ -0,0 +1,17 @@
1
+ import { createReduxStore, register } from '@wordpress/data';
2
+ import actions from './actions';
3
+ import controls from './controls';
4
+ import reducer from './reducer';
5
+ import resolvers from './resolvers';
6
+ import selectors from './selectors';
7
+
8
+ export const JETPACK_MODULES_STORE_ID = 'jetpack-modules';
9
+
10
+ const store = createReduxStore( JETPACK_MODULES_STORE_ID, {
11
+ reducer,
12
+ actions,
13
+ controls,
14
+ resolvers,
15
+ selectors,
16
+ } );
17
+ register( store );
@@ -0,0 +1,18 @@
1
+ const defaultState = {
2
+ isLoading: false,
3
+ isUpdating: false,
4
+ data: {},
5
+ };
6
+
7
+ const setModulesData = ( state = defaultState, action ) => {
8
+ switch ( action.type ) {
9
+ case 'SET_JETPACK_MODULES':
10
+ return {
11
+ ...state,
12
+ ...action.options,
13
+ };
14
+ }
15
+ return state;
16
+ };
17
+
18
+ export default setModulesData;
@@ -0,0 +1,30 @@
1
+ import { setJetpackModules, fetchModules } from './actions';
2
+ import { fetchJetpackModules } from './controls';
3
+
4
+ /**
5
+ * Yield actions to get the Jetpack modules.
6
+ *
7
+ * @yields {object} - an action object.
8
+ * @returns {object} - an action object.
9
+ */
10
+ export function* getJetpackModules() {
11
+ try {
12
+ const data = yield fetchJetpackModules();
13
+ if ( data ) {
14
+ return setJetpackModules( { data } );
15
+ }
16
+ } catch ( e ) {
17
+ console.error( e ); // eslint-disable-line no-console
18
+ }
19
+ }
20
+
21
+ /**
22
+ * When requesting data on particular module
23
+ * we want to make sure to have the latest state
24
+ * @returns {boolean} - if action was completed successfully.
25
+ */
26
+ export function isModuleActive() {
27
+ return fetchModules();
28
+ }
29
+
30
+ export default { getJetpackModules, isModuleActive };
@@ -0,0 +1,13 @@
1
+ import { isSimpleSite } from '../site-type-utils';
2
+
3
+ const jetpackModulesSelectors = {
4
+ getJetpackModules: state => state.data,
5
+ // We consider simple sites to have all modules active
6
+ // TODO: we would remove this when wrapping logic with hooks
7
+ isModuleActive: ( state, moduleName ) =>
8
+ isSimpleSite() || ( state?.data?.[ moduleName ]?.activated ?? false ),
9
+ areModulesLoading: state => state.isLoading ?? false,
10
+ areModulesUpdating: state => state.isUpdating ?? false,
11
+ };
12
+
13
+ export default jetpackModulesSelectors;