strapi-plugin-navigation 2.0.0-beta.1 → 2.0.0-beta.5

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.
Files changed (36) hide show
  1. package/README.md +62 -104
  2. package/admin/src/components/Item/ItemCardHeader/index.js +2 -2
  3. package/admin/src/components/Item/index.js +3 -1
  4. package/admin/src/components/NavigationItemList/index.js +2 -0
  5. package/admin/src/components/Search/index.js +49 -0
  6. package/admin/src/pages/DataManagerProvider/index.js +6 -9
  7. package/admin/src/pages/DataManagerProvider/reducer.js +58 -69
  8. package/admin/src/pages/View/index.js +16 -4
  9. package/admin/src/pages/View/utils/parsers.js +1 -1
  10. package/admin/src/pluginId.js +2 -2
  11. package/package.json +7 -3
  12. package/server/config/index.js +8 -0
  13. package/server/controllers/navigation.js +21 -0
  14. package/server/graphql/index.js +23 -0
  15. package/server/graphql/queries/index.js +17 -0
  16. package/server/graphql/queries/render-navigation-child.js +16 -0
  17. package/server/graphql/queries/render-navigation.js +15 -0
  18. package/server/graphql/resolvers-config.js +4 -0
  19. package/server/graphql/types/content-types-name-fields.js +8 -0
  20. package/server/graphql/types/content-types.js +16 -0
  21. package/server/graphql/types/create-navigation-item.js +17 -0
  22. package/server/graphql/types/create-navigation-related.js +8 -0
  23. package/server/graphql/types/create-navigation.js +7 -0
  24. package/server/graphql/types/index.js +15 -0
  25. package/server/graphql/types/navigation-config.js +9 -0
  26. package/server/graphql/types/navigation-details.js +10 -0
  27. package/server/graphql/types/navigation-item.js +29 -0
  28. package/server/graphql/types/navigation-related.js +23 -0
  29. package/server/graphql/types/navigation-render-type.js +4 -0
  30. package/server/graphql/types/navigation.js +9 -0
  31. package/server/register.js +5 -0
  32. package/server/routes/client.js +21 -0
  33. package/server/routes/index.js +2 -1
  34. package/server/services/navigation.js +272 -6
  35. package/server/services/utils/functions.js +84 -2
  36. package/strapi-server.js +3 -1
package/README.md CHANGED
@@ -1,34 +1,45 @@
1
- # Strapi v4 - Navigation plugin - BETA
2
-
3
- <p align="center">
1
+ <div align="center">
2
+ <h1>Strapi v4 - Navigation plugin - BETA</h1>
3
+ <p>Create consumable navigation with a simple and straigthforward visual builder.</p>
4
4
  <a href="https://www.npmjs.org/package/strapi-plugin-navigation">
5
- <img src="https://img.shields.io/npm/v/strapi-plugin-navigation/latest.svg" alt="NPM Version" />
5
+ <img src="https://img.shields.io/github/package-json/v/VirtusLab-Open-Source/strapi-plugin-navigation/feat%252Fstrapi-v4-support?label=npm" alt="NPM Version" />
6
6
  </a>
7
7
  <a href="https://www.npmjs.org/package/strapi-plugin-navigation">
8
8
  <img src="https://img.shields.io/npm/dm/strapi-plugin-navigation.svg" alt="Monthly download on NPM" />
9
9
  </a>
10
10
  <a href="https://circleci.com/gh/VirtusLab/strapi-plugin-navigation">
11
- <img src="https://circleci.com/gh/VirtusLab/strapi-plugin-navigation.svg?style=shield" alt="CircleCI" />
11
+ <img src="https://circleci.com/gh/VirtusLab-Open-Source/strapi-plugin-navigation/tree/feat%2Fstrapi-v4-support.svg?style=shield" alt="CircleCI" />
12
12
  </a>
13
13
  <a href="https://codecov.io/gh/VirtusLab/strapi-plugin-navigation">
14
- <img src="https://codecov.io/gh/VirtusLab/strapi-plugin-navigation/coverage.svg?branch=master" alt="codecov.io" />
14
+ <img src="https://codecov.io/gh/VirtusLab/strapi-plugin-navigation/coverage.svg?branch=feat%2Fstrapi-v4-support" alt="codecov.io" />
15
15
  </a>
16
- </p>
16
+ </div>
17
+
18
+ ---
17
19
 
18
- A plugin for [Strapi Headless CMS](https://github.com/strapi/strapi) that provides navigation / menu builder feature with their possibility to control the audience and different output structure renderers:
20
+ Strapi Navigation Plugin provides a website navigation / menu builder feature for [Strapi Headless CMS](https://github.com/strapi/strapi) admin panel. Navigation has the possibility to control the audience and can be consumed by the website with different output structure renderers:
19
21
 
20
22
  - Flat
21
23
  - Tree (nested)
22
24
  - RFR (ready for handling by Redux First Router)
23
25
 
24
- ### Versions
26
+ ## ✨ Features
27
+
28
+ - **Navigation Public API:** Simple and ready for use API endpoint for consuming the navigation structure you've created
29
+ - **Visual builder:** Elegant and easy to use visual builder
30
+ - **Any Content Type relation:** Navigation can by linked to any of your Content Types by default. Simply, you're controlling it and also limiting available content types by configuration props
31
+ - **Customizable:** Possibility to customize the options like: available Content Types, Maximum level for "attach to menu", Additional fields (audience)
32
+ - **[Audit log](https://github.com/VirtusLab/strapi-molecules/tree/master/packages/strapi-plugin-audit-log):** integration with Strapi Molecules Audit Log plugin that provides changes track record
33
+
34
+
35
+ ## ⚙️ Versions
25
36
 
26
37
  - **Stable** - [v1.1.2](https://github.com/VirtusLab-Open-Source/strapi-plugin-navigation)
27
38
  - **Beta** - v4 support - [v2.0.0-beta.x](https://github.com/VirtusLab-Open-Source/strapi-plugin-navigation/tree/feat/strapi-v4-support)
28
39
 
29
- ### ⏳ Installation
40
+ ## ⏳ Installation
30
41
 
31
- (Use **yarn** to install this plugin within your Strapi project (recommended). [Install yarn with these docs](https://yarnpkg.com/lang/en/docs/install/).)
42
+ It's recommended to use **yarn** to install this plugin within your Strapi project. [You can install yarn with these docs](https://yarnpkg.com/lang/en/docs/install/).
32
43
 
33
44
  ```bash
34
45
  yarn add strapi-plugin-navigation@latest
@@ -49,87 +60,53 @@ yarn develop --watch-admin
49
60
 
50
61
  The **UI Navigation** plugin should appear in the **Plugins** section of Strapi sidebar after you run app again.
51
62
 
52
-
53
63
  Enjoy 🎉
54
64
 
55
- ### 🖐 Requirements
65
+ ## 🖐 Requirements
56
66
 
57
- Complete installation requirements are exact same as for Strapi itself and can be found in the documentation under <a href="https://strapi.io/documentation/v3.x/installation/cli.html#step-1-make-sure-requirements-are-met">Installation Requirements</a>.
67
+ Complete installation requirements are exact same as for Strapi itself and can be found in the documentation under <a href="https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/installation/cli.html#preparing-the-installation">Installation Requirements</a>.
58
68
 
59
69
  **Supported Strapi versions**:
60
70
 
61
- - Strapi v4.0.2 (recently tested)
62
-
63
- (This plugin is not working with v3.x and not may work with the older Strapi v4 versions, but these are not tested nor officially supported at this time.)
64
-
65
- **We recommend always using the latest version of Strapi to start your new projects**.
66
-
67
- ## Features
68
-
69
- - **Navigation Public API:** Simple and ready for use API endpoint for getting the navigation structure you've created
70
- - **Visual builder:** Elegant and easy to use visual builder
71
- - **Any Content Type relation:** Navigation can by linked to any of your Content Types by default. Simply, you're controlling it and also limiting available content types by configuration props
72
- - **Customizable:** Possibility to customize the options like: available Content Types, Maximum level for "attach to menu", Additional fields (audience)
73
- - **[Audit log](https://github.com/VirtusLab/strapi-molecules/tree/master/packages/strapi-plugin-audit-log):** integration with Strapi Molecules Audit Log plugin that provides changes track record
74
-
75
-
76
- ## Content Type model relation to Navigation Item
77
-
78
- To enable Content Type to work with Navigation Item, you've to add following field to your model `*.settings.json`:
71
+ - Strapi v4.0.5 (recently tested)
72
+ - Strapi v4.x
79
73
 
80
- ```
81
- "navigation": {
82
- "model": "navigationitem",
83
- "plugin": "navigation",
84
- "via": "related",
85
- "configurable": false,
86
- "hidden": true
87
- }
88
- ```
74
+ _This plugin is not working with v3.x._
89
75
 
90
- inside the `attributes` section like in example below:
76
+ It may or may not work with the older Strapi v4 versions, these are not tested nor officially supported at this time.
91
77
 
92
- ```
93
- "attributes": {
94
- ...,
95
- "navigation": {
96
- "model": "navigationitem",
97
- "plugin": "navigation",
98
- "via": "related",
99
- "configurable": false,
100
- "hidden": true
101
- },
102
- ...
103
- },
104
- ```
78
+ **We recommend always using the latest version of Strapi to start your new projects**.
105
79
 
106
- ## Configuration
107
- To setup the plugin properly we recommend to put following snippet as part of `config/custom.js` or `config/<env>/custom.js` file. If you've got already configurations for other plugins stores by this way, use just the `navigation` part within exising `plugins` item.
80
+ ## 🔧 Configuration
81
+ Config for this plugin is stored as a part of `config/plugins.js` or `config/<env>/plugins.js` file. You can use following snippet to make sure that the config structure is correct. If you've got already configurations for other plugins stores by this way, you can use the `navigation` along with them.
108
82
 
109
83
  ```js
110
- ...
111
- plugins: {
112
- navigation: {
113
- additionalFields: ['audience'],
114
- allowedLevels: 2,
115
- contentTypesNameFields: {
116
- 'blog_posts': ['altTitle'],
117
- 'pages': ['title'],
118
- },
119
- gql: { ... }
120
- },
121
- },
122
- ...
84
+ module.exports = ({ env }) => ({
85
+ // ...
86
+ navigation: {
87
+ enabled: true,
88
+ config: {
89
+ additionalFields: ['audience'],
90
+ contentTypes: ['api::page.page'],
91
+ contentTypesNameFields: {
92
+ 'api::page.page': ['title']
93
+ },
94
+ allowedLevels: 2,
95
+ gql: {...},
96
+ }
97
+ }
98
+ });
123
99
  ```
124
100
 
125
101
  ### Properties
126
102
  - `additionalFields` - Additional fields: 'audience', more in the future
127
103
  - `allowedLevels` - Maximum level for which your're able to mark item as "Menu attached"
128
- - `contentTypesNameFields` - Definition of content type title fields like `'content_type_name': ['field_name_1', 'field_name_2']`, if not set titles are pulled from fields like `['title', 'subject', 'name']`
104
+ - `contentTypes` - UIDs of related content types
105
+ - `contentTypesNameFields` - Definition of content type title fields like `'api::<collection name>.<content type name>': ['field_name_1', 'field_name_2']`, if not set titles are pulled from fields like `['title', 'subject', 'name']`. **TIP** - Proper content type uid you can find in the URL of Content Manager where you're managing relevant entities like: `admin/content-manager/collectionType/< THE UID HERE >?page=1&pageSize=10&sort=Title:ASC&plugins[i18n][locale]=en`
129
106
  - `gql` - If you're using GraphQL that's the right place to put all necessary settings. More **[ here ](#gql-configuration)**
130
107
 
131
108
  ## GQL Configuration
132
- To properly configure GQL to work with navigation you should provide `gql` prop which should contain union types which will be used for define GQL response format for your data while fetching:
109
+ Using navigation with GraphQL requires both plugins to be installed and working. You can find instalation guide for GraphQL plugin **[here](https://docs.strapi.io/developer-docs/latest/plugins/graphql.html#graphql)**. To properly configure GQL to work with navigation you should provide `gql` prop. This should contain union types that will be used to define GQL response format for your data while fetching:
133
110
 
134
111
  ```gql
135
112
  master: Int
@@ -137,11 +114,11 @@ items: [NavigationItem]
137
114
  related: NavigationRelated
138
115
  ```
139
116
 
140
- as follows:
117
+ This prop should look as follows:
141
118
 
142
119
  ```js
143
120
  gql: {
144
- navigationItemRelated: 'union NavigationRelated = <your GQL related entities>',
121
+ navigationItemRelated: ['<your GQL related content types>'],
145
122
  },
146
123
  ```
147
124
 
@@ -149,10 +126,10 @@ for example:
149
126
 
150
127
  ```js
151
128
  gql: {
152
- navigationItemRelated: 'union NavigationRelated = Pages | UploadFile',
129
+ navigationItemRelated: ['Page', 'UploadFile'],
153
130
  },
154
131
  ```
155
- where `Pages` and `UploadFile` are your types to the **Content Types** you're referring by navigation items relations.
132
+ where `Page` and `UploadFile` are your type names for the **Content Types** you're referring by navigation items relations.
156
133
 
157
134
 
158
135
  ## Public API Navigation Item model
@@ -225,13 +202,13 @@ where `Pages` and `UploadFile` are your types to the **Content Types** you're re
225
202
 
226
203
  ### Render
227
204
 
228
- `GET <host>/navigation/render/<idOrSlug>?type=<type>`
205
+ `GET <host>/api/navigation/render/<idOrSlug>?type=<type>`
229
206
 
230
207
  Return a rendered navigation structure depends on passed type (`tree`, `rfr` or nothing to render as `flat/raw`).
231
208
 
232
209
  *Note: The ID of navigation by default is `1`, that's for future extensions and multi-navigation feature.*
233
210
 
234
- **Example URL**: `https://localhost:1337/navigation/render/1`
211
+ **Example URL**: `https://localhost:1337/api/navigation/render/1`
235
212
 
236
213
  **Example response body**
237
214
 
@@ -260,7 +237,7 @@ Return a rendered navigation structure depends on passed type (`tree`, `rfr` or
260
237
  ]
261
238
  ```
262
239
 
263
- **Example URL**: `https://localhost:1337/navigation/render/1?type=tree`
240
+ **Example URL**: `https://localhost:1337/api/navigation/render/1?type=tree`
264
241
 
265
242
  **Example response body**
266
243
 
@@ -296,7 +273,7 @@ Return a rendered navigation structure depends on passed type (`tree`, `rfr` or
296
273
  ]
297
274
  ```
298
275
 
299
- **Example URL**: `https://localhost:1337/navigation/render/1?type=rfr`
276
+ **Example URL**: `https://localhost:1337/api/navigation/render/1?type=rfr`
300
277
 
301
278
  **Example response body**
302
279
 
@@ -387,30 +364,11 @@ For collection types it will be read from content type's attribute name `templat
387
364
 
388
365
  For single types a global name of this content type will be used as a template name or it can be set manually with an option named `templateName`.
389
366
 
390
- ## Audit log
391
- If you would like to use the [Strapi Molecules Audit Log](https://github.com/VirtusLab/strapi-molecules/tree/master/packages/strapi-plugin-audit-log) plugin you've to first install and then add in you `config/middleware.js` following section enable it:
392
- ```js
393
- {
394
- 'audit-log': {
395
- enabled: true,
396
- exclude: [],
397
- map: [
398
- {
399
- pluginName: 'navigation',
400
- serviceName: 'navigation',
401
- Class: Navigation,
402
- },
403
- ]
404
- }
405
- }
406
- ```
407
- As a last step you've to provide the Navigation class to let Audit Log use it. To not provide external & hard dependencies we've added the example of class code in the `examples/audit-log-integration.js` .
408
-
409
- ## Examples
367
+ ## 🧩 Examples
410
368
 
411
369
  Live example of plugin usage can be found in the [VirtusLab Strapi Examples](https://github.com/VirtusLab/strapi-examples/tree/master/strapi-plugin-navigation) repository.
412
370
 
413
- ## Q&A
371
+ ## 💬 Q&A
414
372
 
415
373
  ### Content Types
416
374
 
@@ -418,11 +376,11 @@ Live example of plugin usage can be found in the [VirtusLab Strapi Examples](htt
418
376
 
419
377
  **A:** As an authors of the plugin we're not supporting any editing of mentioned content types via built-in Strapi Content Manager. Plugin delivers highly customized & extended functionality which might be covered only by dedicated editor UI accessible via **Plugins Section > UI Navigation**. Only issues that has been recognized there, are in the scope of support we've providing.
420
378
 
421
- ## Contributing
379
+ ## 🤝 Contributing
422
380
 
423
381
  Feel free to fork and make a Pull Request to this plugin project. All the input is warmly welcome!
424
382
 
425
- ## Community support
383
+ ## 👨‍💻 Community support
426
384
 
427
385
  For general help using Strapi, please refer to [the official Strapi documentation](https://strapi.io/documentation/). For additional help, you can use one of these channels to ask a question:
428
386
 
@@ -430,6 +388,6 @@ For general help using Strapi, please refer to [the official Strapi documentatio
430
388
  - [Slack - VirtusLab Open Source](https://virtuslab-oss.slack.com) We're present on a public channel #strapi-molecules
431
389
  - [GitHub](https://github.com/VirtusLab/strapi-plugin-navigation/issues) (Bug reports, Contributions, Questions and Discussions)
432
390
 
433
- ## License
391
+ ## 📝 License
434
392
 
435
393
  [MIT License](LICENSE.md) Copyright (c) 2021 [VirtusLab Sp. z o.o.](https://virtuslab.com/) &amp; [Strapi Solutions](https://strapi.io/).
@@ -12,7 +12,7 @@ import Wrapper from './Wrapper';
12
12
  import ItemCardBadge from '../ItemCardBadge';
13
13
  import { getTrad } from "../../../translations";
14
14
 
15
- const ItemCardHeader = ({ title, path, icon, removed, isPublished, onItemRemove, onItemEdit, onItemRestore }) => {
15
+ const ItemCardHeader = ({ title, path, icon, removed, isExternal, isPublished, onItemRemove, onItemEdit, onItemRestore }) => {
16
16
  const badgeColor = isPublished ? 'success' : 'secondary';
17
17
  const { formatMessage } = useIntl();
18
18
 
@@ -36,7 +36,7 @@ const ItemCardHeader = ({ title, path, icon, removed, isPublished, onItemRemove,
36
36
  >
37
37
  {formatMessage(getTrad("navigation.item.badge.removed"))}
38
38
  </ItemCardBadge>
39
- : <ItemCardBadge
39
+ : !isExternal && <ItemCardBadge
40
40
  borderColor={`${badgeColor}200`}
41
41
  backgroundColor={`${badgeColor}100`}
42
42
  textColor={`${badgeColor}600`}
@@ -31,6 +31,7 @@ const Item = (props) => {
31
31
  onItemRestore,
32
32
  onItemEdit,
33
33
  error,
34
+ displayChildren,
34
35
  } = props;
35
36
 
36
37
  const {
@@ -48,7 +49,7 @@ const Item = (props) => {
48
49
  const isPublished = relatedRef && relatedRef?.publishedAt;
49
50
  const isNextMenuAllowedLevel = isNumber(allowedLevels) ? level < (allowedLevels - 1) : true;
50
51
  const isMenuAllowedLevel = isNumber(allowedLevels) ? level < allowedLevels : true;
51
- const hasChildren = !isEmpty(item.items) && !isExternal;
52
+ const hasChildren = !isEmpty(item.items) && !isExternal && !displayChildren;
52
53
  const absolutePath = isExternal ? undefined : `${levelPath === '/' ? '' : levelPath}/${path === '/' ? '' : path}`;
53
54
 
54
55
  return (
@@ -60,6 +61,7 @@ const Item = (props) => {
60
61
  path={isExternal ? externalPath : absolutePath}
61
62
  icon={isExternal ? <EarthIcon /> : <LinkIcon />}
62
63
  isPublished={isPublished}
64
+ isExternal={isExternal}
63
65
  onItemRemove={() => onItemRemove(item)}
64
66
  onItemEdit={() => onItemEdit({
65
67
  ...item,
@@ -15,6 +15,7 @@ const List = ({
15
15
  onItemLevelAdd,
16
16
  onItemRemove,
17
17
  onItemRestore,
18
+ displayFlat,
18
19
  }) => (
19
20
  <Wrapper level={level}>
20
21
  {items.map((item, n) => {
@@ -34,6 +35,7 @@ const List = ({
34
35
  onItemRemove={onItemRemove}
35
36
  onItemEdit={onItemEdit}
36
37
  error={error}
38
+ displayChildren={displayFlat}
37
39
  />
38
40
  );
39
41
  })}
@@ -0,0 +1,49 @@
1
+ import React, { useRef, useState, useEffect } from 'react';
2
+ import { useIntl } from 'react-intl';
3
+ import { IconButton } from '@strapi/design-system/IconButton';
4
+ import { Searchbar, SearchForm } from '@strapi/design-system/Searchbar';
5
+ import SearchIcon from "@strapi/icons/Search";
6
+ import { getTradId } from '../../translations';
7
+
8
+ const Search = ({ value, setValue }) => {
9
+ const [isOpen, setIsOpen] = useState(!!value);
10
+ const wrapperRef = useRef(null);
11
+ const { formatMessage } = useIntl();
12
+
13
+ useEffect(() => {
14
+ if (isOpen) {
15
+ setTimeout(() => {
16
+ wrapperRef.current.querySelector('input').focus();
17
+ }, 0);
18
+ }
19
+ }, [isOpen]);
20
+
21
+ if (isOpen) {
22
+ return (
23
+ <div ref={wrapperRef}>
24
+ <SearchForm>
25
+ <Searchbar
26
+ name="searchbar"
27
+ onClear={() => setValue('')}
28
+ value={value}
29
+ size="S"
30
+ onChange={(e) => setValue(e.target.value)}
31
+ clearLabel="Clearing the search"
32
+ placeholder={formatMessage({
33
+ id: getTradId('popup.item.form.audience.placeholder'),
34
+ defaultMessage: 'Type to start searching...',
35
+ })}
36
+ >
37
+ Search for navigation items
38
+ </Searchbar>
39
+ </SearchForm>
40
+ </div>
41
+ );
42
+ } else {
43
+ return (
44
+ <IconButton icon={<SearchIcon />} onClick={() => setIsOpen(!isOpen)} />
45
+ );
46
+ }
47
+ }
48
+
49
+ export default Search;
@@ -8,7 +8,6 @@ import {
8
8
  LoadingIndicatorPage,
9
9
  useNotification,
10
10
  useAppInfos,
11
- useStrapiApp,
12
11
  } from "@strapi/helper-plugin";
13
12
  import DataManagerContext from "../../contexts/DataManagerContext";
14
13
  import getTrad from "../../utils/getTrad";
@@ -39,7 +38,7 @@ const DataManagerProvider = ({ children }) => {
39
38
  const toggleNotification = useNotification();
40
39
  const { autoReload } = useAppInfos();
41
40
  const { formatMessage } = useIntl();
42
-
41
+
43
42
  const {
44
43
  items,
45
44
  config,
@@ -54,10 +53,8 @@ const DataManagerProvider = ({ children }) => {
54
53
  isLoadingForAdditionalDataToBeSet,
55
54
  isLoadingForSubmit,
56
55
  error
57
- } = reducerState.toJS();
56
+ } = reducerState;
58
57
  const { pathname } = useLocation();
59
- const { getPlugin } = useStrapiApp();
60
- const { apis } = getPlugin(pluginId);
61
58
  const formatMessageRef = useRef();
62
59
  formatMessageRef.current = formatMessage;
63
60
 
@@ -164,7 +161,7 @@ const DataManagerProvider = ({ children }) => {
164
161
  }
165
162
  }, [autoReload]);
166
163
 
167
- const getContentTypeItems = async ({ modelUID, query }, plugin = "") => {
164
+ const getContentTypeItems = async ({ modelUID, query }) => {
168
165
  dispatch({
169
166
  type: GET_CONTENT_TYPE_ITEMS,
170
167
  });
@@ -174,7 +171,7 @@ const DataManagerProvider = ({ children }) => {
174
171
  if (query) {
175
172
  queryParams.append('_q', query);
176
173
  }
177
-
174
+
178
175
  const contentTypeItems = await request(`${url}?${queryParams.toString()}`, {
179
176
  method: "GET",
180
177
  signal,
@@ -229,7 +226,7 @@ const DataManagerProvider = ({ children }) => {
229
226
  dispatch({
230
227
  type: SUBMIT_NAVIGATION,
231
228
  });
232
-
229
+
233
230
  const nagivationId = payload.id ? `/${payload.id}` : "";
234
231
  const method = payload.id ? "PUT" : "POST";
235
232
  const navigation = await request(`/${pluginId}${nagivationId}`, {
@@ -309,4 +306,4 @@ DataManagerProvider.propTypes = {
309
306
  children: PropTypes.node.isRequired,
310
307
  };
311
308
 
312
- export default memo(DataManagerProvider);
309
+ export default memo(DataManagerProvider);
@@ -1,4 +1,5 @@
1
- import { fromJS } from "immutable";
1
+ import produce from 'immer';
2
+
2
3
  import {
3
4
  GET_LIST_DATA,
4
5
  GET_LIST_DATA_SUCCEEDED,
@@ -18,7 +19,7 @@ import {
18
19
  SUBMIT_NAVIGATION_ERROR,
19
20
  } from './actions';
20
21
 
21
- const initialState = fromJS({
22
+ const initialState = {
22
23
  items: [],
23
24
  activeItem: undefined,
24
25
  changedActiveItem: undefined,
@@ -31,106 +32,94 @@ const initialState = fromJS({
31
32
  isLoadingForAdditionalDataToBeSet: false,
32
33
  isLoadingForSubmit: false,
33
34
  error: undefined,
34
- });
35
+ };
35
36
 
36
- const reducer = (state, action) => {
37
+ const reducer = (state, action) => produce(state, draftState => {
37
38
  switch (action.type) {
38
39
  case GET_CONFIG: {
39
- return state
40
- .update("isLoadingForAdditionalDataToBeSet", () => true)
41
- .removeIn("config");
40
+ draftState.isLoadingForDetailsDataToBeSet = true;
41
+ draftState.config = {};
42
+ break;
42
43
  }
43
44
  case GET_CONFIG_SUCCEEDED: {
44
- return state
45
- .update("isLoadingForAdditionalDataToBeSet", () => false)
46
- .update("config", () => fromJS(action.config));
45
+ draftState.isLoadingForDetailsDataToBeSet = false;
46
+ draftState.config = action.config;
47
+ break;
47
48
  }
48
49
  case GET_LIST_DATA: {
49
- return state
50
- .removeIn("items")
51
- .update("isLoadingForDataToBeSet", () => true);
50
+ draftState.items = [];
51
+ draftState.isLoadingForDataToBeSet = true;
52
+ break;
52
53
  }
53
54
  case GET_LIST_DATA_SUCCEEDED: {
54
- return state
55
- .update("items", () => fromJS(action.items))
56
- .update("isLoading", () => false)
57
- .update("isLoadingForDataToBeSet", () => false);
55
+ draftState.items = action.items;
56
+ draftState.isLoading = false;
57
+ draftState.isLoadingForDataToBeSet = false;
58
+ break;
58
59
  }
59
60
  case GET_NAVIGATION_DATA: {
60
- return state
61
- .removeIn("activeItem")
62
- .removeIn("changedActiveItem")
63
- .update("isLoadingForDetailsDataToBeSet", () => true);
61
+ draftState.activeItem = undefined;
62
+ draftState.changedActiveItem = undefined;
63
+ draftState.isLoadingForDetailsDataToBeSet = true;
64
+ break;
64
65
  }
65
66
  case GET_NAVIGATION_DATA_SUCCEEDED: {
66
- const { activeItem = {} } = action;
67
- return state
68
- .update("activeItem", () => fromJS(activeItem))
69
- .update("changedActiveItem", () => fromJS(activeItem))
70
- .update("isLoadingForDetailsDataToBeSet", () => false);
67
+ const activeItem = action.activeItem || {};
68
+ draftState.activeItem = activeItem;
69
+ draftState.changedActiveItem = activeItem;
70
+ draftState.isLoadingForDetailsDataToBeSet = false;
71
+ break;
71
72
  }
72
73
  case CHANGE_NAVIGATION_DATA: {
73
- return state
74
- .update("changedActiveItem", () => action.changedActiveItem)
75
- .update("navigationPopupOpened", () =>
76
- action.forceClosePopups ? false : state.navigationPopupOpened,
77
- )
78
- .update("navigationItemPopupOpened", () =>
79
- action.forceClosePopups ? false : state.navigationItemPopupOpened,
80
- );
81
- }
82
- case RESET_NAVIGATION_DATA: {
83
- const { activeItem = {} } = action;
84
- return state.update("changedActiveItem", () => activeItem);
74
+ draftState.changedActiveItem = action.changedActiveItem;
75
+ draftState.navigationPopupOpened = action.forceClosePopups ? false : state.navigationPopupOpened;
76
+ draftState.navigationItemPopupOpened = action.forceClosePopups ? false : state.navigationItemPopupOpened;
77
+ break;
78
+ }
79
+ case RESET_NAVIGATION_DATA : {
80
+ draftState.changedActiveItem = action.activeItem || {};
81
+ break;
85
82
  }
86
83
  case GET_CONTENT_TYPE_ITEMS: {
87
- return state.update("isLoadingForAdditionalDataToBeSet", () => true);
84
+ draftState.isLoadingForAdditionalDataToBeSet = true;
85
+ break;
88
86
  }
89
87
  case GET_CONTENT_TYPE_ITEMS_SUCCEEDED: {
90
- return state
91
- .update("isLoadingForAdditionalDataToBeSet", () => false)
92
- .updateIn(["config", "contentTypeItems"], () =>
93
- fromJS(action.contentTypeItems),
94
- );
88
+ draftState.isLoadingForAdditionalDataToBeSet = false;
89
+ draftState.config.contentTypeItems = action.contentTypeItems;
90
+ break;
95
91
  }
96
92
  case CHANGE_NAVIGATION_POPUP_VISIBILITY: {
97
- return state.update(
98
- "navigationPopupOpened",
99
- () => action.navigationPopupOpened,
100
- );
93
+ draftState.navigationPopupOpened = action.navigationPopupOpened;
94
+ break;
101
95
  }
102
96
  case CHANGE_NAVIGATION_ITEM_POPUP_VISIBILITY: {
103
- return state.update(
104
- "navigationItemPopupOpened",
105
- () => action.navigationItemPopupOpened,
106
- );
97
+ draftState.navigationItemPopupOpened = action.navigationItemPopupOpened;
98
+ break;
107
99
  }
108
100
  case SUBMIT_NAVIGATION: {
109
- return state
110
- .update('isLoadingForSubmit', () => true)
111
- .update('error', () => undefined);
101
+ draftState.isLoadingForSubmit = true;
102
+ draftState.error = undefined;
103
+ break;
112
104
  }
113
105
  case SUBMIT_NAVIGATION_SUCCEEDED: {
114
- const { navigation = {} } = action;
115
- return state
116
- .update("activeItem", () => fromJS(navigation))
117
- .update("changedActiveItem", () => fromJS(navigation))
118
- .update(
119
- 'isLoadingForSubmit',
120
- () => false,
121
- );
106
+ draftState.activeItem = action.navigation || {};
107
+ draftState.changedActiveItem = action.navigation || {};
108
+ draftState.isLoadingForSubmit = false;
109
+ break;
122
110
  }
123
111
  case SUBMIT_NAVIGATION_ERROR: {
124
- return state
125
- .update('isLoadingForSubmit', () => false)
126
- .update('error', () => action.error);
112
+ draftState.isLoadingForSubmit = false;
113
+ draftState.error = action.error;
114
+ break;
127
115
  }
128
- case RELOAD_PLUGIN:
116
+ case RELOAD_PLUGIN: {
129
117
  return initialState;
118
+ }
130
119
  default:
131
- return state;
120
+ return draftState;
132
121
  }
133
- };
122
+ });
134
123
 
135
124
  export default reducer;
136
125
  export { initialState };