strapi-plugin-navigation 2.0.0-rc.1 → 2.0.3

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 (50) hide show
  1. package/README.md +55 -8
  2. package/__mocks__/pages.settings.json +25 -0
  3. package/__mocks__/strapi.js +207 -0
  4. package/admin/src/components/ConfirmationDialog/index.js +56 -0
  5. package/admin/src/components/Item/ItemCardBadge/index.js +2 -1
  6. package/admin/src/components/Item/ItemCardHeader/index.js +8 -13
  7. package/admin/src/components/Item/index.js +10 -13
  8. package/admin/src/components/RestartAlert/index.js +8 -0
  9. package/admin/src/components/Search/index.js +21 -23
  10. package/admin/src/hooks/useAllContentTypes.js +13 -0
  11. package/admin/src/hooks/useNavigationConfig.js +58 -0
  12. package/admin/src/index.js +24 -1
  13. package/admin/src/pages/SettingsPage/index.js +311 -0
  14. package/admin/src/pages/View/components/NavigationHeader/index.js +39 -23
  15. package/admin/src/pages/View/components/NavigationItemForm/index.js +49 -9
  16. package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupFooter.js +3 -6
  17. package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupHeader.js +3 -7
  18. package/admin/src/pages/View/components/NavigationItemPopup/index.js +3 -5
  19. package/admin/src/pages/View/index.js +29 -20
  20. package/admin/src/pages/View/utils/parsers.js +7 -3
  21. package/admin/src/translations/en.json +52 -10
  22. package/admin/src/translations/fr.json +4 -4
  23. package/admin/src/utils/api.js +51 -0
  24. package/admin/src/utils/index.js +20 -0
  25. package/package.json +7 -6
  26. package/server/bootstrap.js +30 -1
  27. package/server/content-types/navigation/schema.json +45 -0
  28. package/server/content-types/navigation-item/schema.json +1 -1
  29. package/server/controllers/navigation.js +30 -5
  30. package/server/graphql/index.js +3 -4
  31. package/server/graphql/queries/render-navigation.js +4 -3
  32. package/server/graphql/types/content-types-name-fields.js +4 -2
  33. package/server/graphql/types/navigation-related.js +2 -2
  34. package/server/routes/admin.js +24 -1
  35. package/server/services/__tests__/functions.test.js +48 -0
  36. package/server/services/__tests__/navigation.test.js +84 -77
  37. package/server/services/navigation.js +58 -18
  38. package/server/services/utils/functions.js +45 -12
  39. package/strapi-server.js +0 -2
  40. package/yarn-error.log +5263 -0
  41. package/.circleci/config.yml +0 -48
  42. package/.eslintrc +0 -35
  43. package/.github/pull_request_template.md +0 -13
  44. package/.github/stale.yml +0 -15
  45. package/.nvmrc +0 -1
  46. package/codecov.yml +0 -3
  47. package/public/assets/logo.png +0 -0
  48. package/public/assets/preview.png +0 -0
  49. package/server/content-types/navigation/schema.js +0 -45
  50. package/server/register.js +0 -5
package/README.md CHANGED
@@ -1,7 +1,9 @@
1
- <div align="center">
1
+ <div align="center" width="150px">
2
2
  <img style="width: 150px; height: auto;" src="public/assets/logo.png" alt="Logo - Strapi Navigation plugin" />
3
+ </div>
4
+ <div align="center">
3
5
  <h1>Strapi v4 - Navigation plugin</h1>
4
- <p>Create consumable navigation with a simple and straighthforward visual builder</p>
6
+ <p>Create consumable navigation with a simple and straightforward visual builder</p>
5
7
  <a href="https://www.npmjs.org/package/strapi-plugin-navigation">
6
8
  <img alt="GitHub package.json version" src="https://img.shields.io/github/package-json/v/VirtusLab-Open-Source/strapi-plugin-navigation?label=npm&logo=npm">
7
9
  </a>
@@ -14,6 +16,12 @@
14
16
  <a href="https://codecov.io/gh/VirtusLab/strapi-plugin-navigation">
15
17
  <img src="https://codecov.io/gh/VirtusLab/strapi-plugin-navigation/coverage.svg?branch=master" alt="codecov.io" />
16
18
  </a>
19
+ <a href="https://sharing.clickup.com/tl/xhcmx-43/strapiv-4-navigation-roadmap">
20
+ <img src="https://img.shields.io/website?down_message=roadmap&label=product&up_message=roadmap&url=https%3A%2F%2Fsharing.clickup.com%2Ftl%2Fxhcmx-43%2Fstrapiv-4-navigation-roadmap" />
21
+ </a>
22
+ <a href="https://sharing.clickup.com/b/6-169004201-2/strapiv-4-navigation-board">
23
+ <img src="https://img.shields.io/website?down_message=board&label=product&up_color=blue&up_message=board&url=https%3A%2F%2Fsharing.clickup.com%2Fb%2F6-169004201-2%2Fstrapiv-4-navigation-board" />
24
+ </a>
17
25
  </div>
18
26
 
19
27
  ---
@@ -33,10 +41,10 @@ Strapi Navigation Plugin provides a website navigation / menu builder feature fo
33
41
  - **Navigation Public API:** Simple and ready for use API endpoint for consuming the navigation structure you've created
34
42
  - **Visual builder:** Elegant and easy to use visual builder
35
43
  - **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
44
+ - **Multiple navigations:** Create as many Navigation containers as you want, setup them and use in the consumer application
36
45
  - **Customizable:** Possibility to customize the options like: available Content Types, Maximum level for "attach to menu", Additional fields (audience)
37
46
  - **[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
38
47
 
39
-
40
48
  ## ⚙️ Versions
41
49
 
42
50
  - **Strapi v4** - (current) - [v2.x](https://github.com/VirtusLab-Open-Source/strapi-plugin-navigation)
@@ -73,7 +81,7 @@ Complete installation requirements are exact same as for Strapi itself and can b
73
81
 
74
82
  **Supported Strapi versions**:
75
83
 
76
- - Strapi v4.0.5 (recently tested)
84
+ - Strapi v4.1.0 (recently tested)
77
85
  - Strapi v4.x
78
86
 
79
87
  > This plugin is designed for **Strapi v4** and is not working with v3.x. To get version for **Strapi v3** install version [v1.x](https://github.com/VirtusLab-Open-Source/strapi-plugin-navigation/tree/strapi-v3).
@@ -81,7 +89,20 @@ Complete installation requirements are exact same as for Strapi itself and can b
81
89
  **We recommend always using the latest version of Strapi to start your new projects**.
82
90
 
83
91
  ## 🔧 Configuration
84
- 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.
92
+
93
+ ### In `v2.0.3` and newer
94
+
95
+ Version `2.0.3` introduces the intuitive **Settings** page which you can easily access via `Strapi Settings -> Section: Navigation Plugin -> Configuration`. On the dedicated page, you will be able to set up all crucial properties which drive the plugin and customize each individual collection for which **Navigation plugin** should be enabled.
96
+
97
+ > *Note*
98
+ > The default configuration for your plugin is fetched from `config/plugins.js` or, if the file is not there, directly from the plugin itself. If you would like to customize the default state to which you might revert, please follow the next section.
99
+
100
+ ### In `v2.0.2` and older + default configuration state for `v2.0.3` and newer
101
+
102
+ Config for this plugin is stored as a part of the `config/plugins.js` or `config/<env>/plugins.js` file. You can use the 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.
103
+
104
+ > *Note v2.0.3 and newer only*
105
+ > Changing this file will not automatically change plugin configuration. To synchronize plugin's config with plugins.js file, it is necessary to restore configuration through the settings page
85
106
 
86
107
  ```js
87
108
  module.exports = ({ env }) => ({
@@ -103,13 +124,16 @@ Config for this plugin is stored as a part of `config/plugins.js` or `config/<en
103
124
 
104
125
  ### Properties
105
126
  - `additionalFields` - Additional fields: 'audience', more in the future
106
- - `allowedLevels` - Maximum level for which your're able to mark item as "Menu attached"
127
+ - `allowedLevels` - Maximum level for which you're able to mark item as "Menu attached"
107
128
  - `contentTypes` - UIDs of related content types
108
129
  - `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`
109
130
  - `gql` - If you're using GraphQL that's the right place to put all necessary settings. More **[ here ](#gql-configuration)**
110
131
 
111
132
  ## 🔧 GQL Configuration
112
- 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
+ Using navigation with GraphQL requires both plugins to be installed and working. You can find installation 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:
134
+
135
+ > **Important!**
136
+ > If you're using `config/plugins.js` to configure your plugins , please put `navigation` property before `graphql`. Otherwise types are not going to be properly added to GraphQL Schema. That's because of dynamic types which base on plugin configuration which are added on `bootstrap` stage, not `register`. This is not valid if you're using `graphql` plugin without any custom configuration, so most of cases in real.
113
137
 
114
138
  ```gql
115
139
  master: Int
@@ -209,6 +233,20 @@ For any role different than **Super Admin**, to access the **Navigation panel**
209
233
 
210
234
  ## 🕸️ Public API specification
211
235
 
236
+ ### Query Params
237
+
238
+ - `type` - Enum value representing structure type of returned navigation
239
+
240
+ **Example URL**: `https://localhost:1337/api/navigation/render/1?type=FLAT`
241
+
242
+ - `menu` - Boolean value for querying only navigation items that are attached to menu should be rendered eg.
243
+
244
+ **Example URL**: `https://localhost:1337/api/navigation/render/1?menu=true`
245
+
246
+ - `path` - String value for querying navigation items by its path
247
+
248
+ **Example URL**: `https://localhost:1337/api/navigation/render/1?path=/home/about-us`
249
+
212
250
  ### Render
213
251
 
214
252
  `GET <host>/api/navigation/render/<idOrSlug>?type=<type>`
@@ -387,13 +425,22 @@ Live example of plugin usage can be found in the [VirtusLab Strapi Examples](htt
387
425
 
388
426
  ## 🤝 Contributing
389
427
 
428
+ <div>
429
+ <a href="https://sharing.clickup.com/tl/xhcmx-43/strapiv-4-navigation-roadmap">
430
+ <img src="https://img.shields.io/website?down_message=roadmap&label=product&up_message=roadmap&url=https%3A%2F%2Fsharing.clickup.com%2Ftl%2Fxhcmx-43%2Fstrapiv-4-navigation-roadmap" />
431
+ </a>
432
+ <a href="https://sharing.clickup.com/b/6-169004201-2/strapiv-4-navigation-board">
433
+ <img src="https://img.shields.io/website?down_message=board&label=product&up_color=blue&up_message=board&url=https%3A%2F%2Fsharing.clickup.com%2Fb%2F6-169004201-2%2Fstrapiv-4-navigation-board" />
434
+ </a>
435
+ </div>
436
+
390
437
  Feel free to fork and make a Pull Request to this plugin project. All the input is warmly welcome!
391
438
 
392
439
  ## 👨‍💻 Community support
393
440
 
394
441
  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:
395
442
 
396
- - [Slack](http://slack.strapi.io) We're present on official Strapi slack workspace. Look for @cyp3r and DM.
443
+ - [Discord](https://discord.strapi.io/) We're present on official Strapi Discord workspace. Find us by `[VirtusLab]` prefix and DM.
397
444
  - [Slack - VirtusLab Open Source](https://virtuslab-oss.slack.com) We're present on a public channel #strapi-molecules
398
445
  - [GitHub](https://github.com/VirtusLab/strapi-plugin-navigation/issues) (Bug reports, Contributions, Questions and Discussions)
399
446
  - [E-mail](mailto:strapi@virtuslab.com) - we will respond back as soon as possible
@@ -0,0 +1,25 @@
1
+ {
2
+ "kind": "collectionType",
3
+ "collectionName": "pages",
4
+ "info": {
5
+ "singularName": "page",
6
+ "pluralName": "pages",
7
+ "displayName": "Page",
8
+ "name": "page"
9
+ },
10
+ "options": {
11
+ "increments": true,
12
+ "timestamps": true,
13
+ "searchable": true,
14
+ "previewable": true,
15
+ "draftAndPublish": false
16
+ },
17
+ "pluginOptions": {},
18
+ "attributes": {
19
+ "title": {
20
+ "type": "string",
21
+ "required": true
22
+ }
23
+ }
24
+ }
25
+
@@ -0,0 +1,207 @@
1
+ const { isMatch } = require('lodash');
2
+
3
+ const masterModelMock = {
4
+ findOne: () => ({
5
+ id: 1,
6
+ name: "Main navigation",
7
+ slug: "main-navigation",
8
+ visible: true,
9
+ createdAt: "2021-12-30T14:05:50.276Z",
10
+ updatedAt: "2021-12-30T14:05:50.276Z",
11
+ }),
12
+ findMany: () => [{
13
+ id: 1,
14
+ name: "Main navigation",
15
+ slug: "main-navigation",
16
+ visible: true,
17
+ createdAt: "2021-12-30T14:05:50.276Z",
18
+ updatedAt: "2021-12-30T14:05:50.276Z",
19
+ }],
20
+ };
21
+
22
+ const itemModelMock = {
23
+ findOne: async () => ({
24
+ id: 1,
25
+ title: "home",
26
+ type: "INTERNAL",
27
+ path: "home1",
28
+ externalPath: null,
29
+ uiRouterKey: "home",
30
+ menuAttached: true,
31
+ order: 1,
32
+ createdAt: "2021-12-31T10:04:54.812Z",
33
+ updatedAt: "2022-01-14T13:36:29.430Z",
34
+ related: {
35
+ id: 1,
36
+ related_id: "1",
37
+ related_type: "api::pages.pages",
38
+ field: "navigation",
39
+ order: 1,
40
+ master: "3",
41
+ createdAt: "2021-12-31T10:04:54.800Z",
42
+ updatedAt: "2021-12-31T10:04:54.800Z",
43
+ navigationItemId: 56,
44
+ },
45
+ parent: null,
46
+ }),
47
+ findMany: async ({ where }) => [{
48
+ id: 1,
49
+ title: "home",
50
+ type: "INTERNAL",
51
+ path: "home",
52
+ externalPath: null,
53
+ uiRouterKey: "home",
54
+ menuAttached: true,
55
+ order: 1,
56
+ createdAt: "2021-12-31T10:04:54.812Z",
57
+ updatedAt: "2022-01-14T13:36:29.430Z",
58
+ master: 1,
59
+ related: {
60
+ id: 1,
61
+ related_id: "1",
62
+ related_type: "api::pages.pages",
63
+ field: "navigation",
64
+ order: 1,
65
+ master: "3",
66
+ createdAt: "2021-12-31T10:04:54.800Z",
67
+ updatedAt: "2021-12-31T10:04:54.800Z",
68
+ navigationItemId: 56,
69
+ },
70
+ parent: null,
71
+ }, {
72
+ id: 2,
73
+ title: "side",
74
+ type: "INTERNAL",
75
+ path: "side",
76
+ externalPath: null,
77
+ uiRouterKey: "side",
78
+ menuAttached: false,
79
+ order: 1,
80
+ createdAt: "2021-12-31T10:04:54.824Z",
81
+ updatedAt: "2021-12-31T12:47:20.508Z",
82
+ master: 1,
83
+ related: {
84
+ id: 2,
85
+ related_id: "2",
86
+ related_type: "api::pages.pages",
87
+ field: "navigation",
88
+ order: 1,
89
+ master: "3",
90
+ createdAt: "2021-12-31T10:04:54.823Z",
91
+ updatedAt: "2021-12-31T10:04:54.823Z",
92
+ navigationItemId: 57,
93
+ },
94
+ parent: {
95
+ id: 1,
96
+ title: "home",
97
+ type: "INTERNAL",
98
+ path: "home1",
99
+ externalPath: null,
100
+ uiRouterKey: "home",
101
+ menuAttached: true,
102
+ order: 1,
103
+ createdAt: "2021-12-31T10:04:54.812Z",
104
+ updatedAt: "2022-01-14T13:36:29.430Z",
105
+ },
106
+ }].filter(item => isMatch(item, where)),
107
+ };
108
+
109
+ const pageModelMock = {
110
+ findOne: async ({ where }) => ({
111
+ "id": 1,
112
+ "attributes": {
113
+ "title": "Page nr 1",
114
+ "createdAt": "2022-01-19T08:22:31.244Z",
115
+ "updatedAt": "2022-01-19T08:22:31.244Z",
116
+ "publishedAt": null
117
+ }
118
+ }),
119
+ findMany: async ({ where }) => [{
120
+ "id": 1,
121
+ "attributes": {
122
+ "title": "Page nr 1",
123
+ "createdAt": "2022-01-19T08:22:31.244Z",
124
+ "updatedAt": "2022-01-19T08:22:31.244Z",
125
+ "publishedAt": null
126
+ }
127
+ }, {
128
+ "id": 2,
129
+ "attributes": {
130
+ "title": "Page nr 2",
131
+ "createdAt": "2022-01-19T08:22:50.821Z",
132
+ "updatedAt": "2022-01-19T08:22:50.821Z",
133
+ "publishedAt": null
134
+ }
135
+ }]
136
+
137
+ };
138
+
139
+ const plugins = (strapi) => ({
140
+ navigation: {
141
+ get services() { return require('../server/services') },
142
+ service: (key) => (require('../server/services'))[key]({ strapi }),
143
+ get contentTypes() { return require('../server/content-types') },
144
+ contentType: (key) => preparePluginContentType(require('../server/content-types')[key].schema, 'navigation'),
145
+ config: (key) => ({
146
+ ...require('../server/config').default,
147
+ contentTypes: ['api::pages.pages'],
148
+ })[key],
149
+ }
150
+ });
151
+
152
+ const contentTypes = {
153
+ 'api::pages.pages': {
154
+ ...require('./pages.settings.json'),
155
+ uid: 'api::pages.pages',
156
+ modelName: 'page',
157
+ },
158
+ };
159
+
160
+ const preparePluginContentType = (schema, plugin) => {
161
+ const { name } = schema.info;
162
+
163
+ return {
164
+ ...schema,
165
+ uid: `plugin::${plugin}.${name}`,
166
+ modelName: name,
167
+ }
168
+ }
169
+
170
+ const strapiFactory = (plugins, contentTypes) => ({
171
+ get plugins() { return plugins(strapi) },
172
+ plugin: (name) => plugins(strapi)[name],
173
+ get contentTypes() { return contentTypes },
174
+ contentType: (key) => contentTypes[key],
175
+ query: (model) => {
176
+ switch (model) {
177
+ case 'plugin::navigation.navigation':
178
+ return masterModelMock;
179
+ case 'plugin::navigation.navigation-item':
180
+ return itemModelMock;
181
+ case 'api::pages.pages':
182
+ return pageModelMock;
183
+ default:
184
+ return {
185
+ findOne: () => ({}),
186
+ findMany: () => [],
187
+ }
188
+ }
189
+ },
190
+ store: ({ type, name }) => {
191
+ if (type === 'plugin' && name === 'navigation') {
192
+ return {
193
+ get: ({ key }) => key === 'config' ? {
194
+ ...require('../server/config').default,
195
+ contentTypes: ['api::pages.pages']
196
+ } : null,
197
+ set: () => null,
198
+ }
199
+ }
200
+ }
201
+ });
202
+
203
+ const setupStrapi = () => {
204
+ Object.defineProperty(global, 'strapi', { value: strapiFactory(plugins, contentTypes) });
205
+ }
206
+
207
+ module.exports = { setupStrapi };
@@ -0,0 +1,56 @@
1
+ /**
2
+ *
3
+ * Entity Details
4
+ *
5
+ */
6
+
7
+ import React from 'react';
8
+ import PropTypes from 'prop-types';
9
+ import { Button } from '@strapi/design-system/Button';
10
+ import { Dialog, DialogBody, DialogFooter } from '@strapi/design-system/Dialog';
11
+ import { Flex } from '@strapi/design-system/Flex';
12
+ import { Stack } from '@strapi/design-system/Stack';
13
+ import { Typography } from '@strapi/design-system/Typography';
14
+ import { ExclamationMarkCircle, Check } from '@strapi/icons';
15
+ import { getMessage } from '../../utils';
16
+
17
+ const ConfirmationDialog = ({
18
+ isVisible = false,
19
+ isActionAsync = false,
20
+ children,
21
+ onConfirm,
22
+ onCancel,
23
+ header,
24
+ labelCancel,
25
+ labelConfirm,
26
+ iconConfirm
27
+ }) => (
28
+ <Dialog onClose={onCancel} title={header || getMessage('components.confirmation.dialog.header', 'Confirmation')} isOpen={isVisible}>
29
+ <DialogBody icon={<ExclamationMarkCircle />}>
30
+ <Stack size={2}>
31
+ <Flex justifyContent="center">
32
+ <Typography id="dialog-confirm-description">{children || getMessage('components.confirmation.dialog.description')}</Typography>
33
+ </Flex>
34
+ </Stack>
35
+ </DialogBody>
36
+ <DialogFooter startAction={<Button onClick={onCancel} variant="tertiary" disabled={isActionAsync}>
37
+ {labelCancel || getMessage('components.confirmation.dialog.button.cancel', 'Cancel')}
38
+ </Button>} endAction={<Button onClick={onConfirm} variant="danger-light" startIcon={iconConfirm || <Check />} disabled={isActionAsync}>
39
+ {labelConfirm || getMessage('components.confirmation.dialog.button.confirm', 'Confirm')}
40
+ </Button>} />
41
+ </Dialog>
42
+ );
43
+
44
+ ConfirmationDialog.propTypes = {
45
+ isVisible: PropTypes.bool,
46
+ isActionAsync: PropTypes.bool,
47
+ children: PropTypes.string.isRequired,
48
+ header: PropTypes.string,
49
+ labelCancel: PropTypes.string,
50
+ labelConfirm: PropTypes.string,
51
+ iconConfirm: PropTypes.object,
52
+ onConfirm: PropTypes.func.isRequired,
53
+ onCancel: PropTypes.func.isRequired,
54
+ };
55
+
56
+ export default ConfirmationDialog;
@@ -5,7 +5,8 @@ const ItemCardBadge = styled(Badge)`
5
5
  border: 1px solid ${({ theme, borderColor }) => theme.colors[borderColor]};
6
6
 
7
7
  ${ props => props.small && `
8
- padding: 0 4px;
8
+ padding: ${props.theme.spaces[1]};
9
+ margin: 0px ${props.theme.spaces[3]};
9
10
  vertical-align: middle;
10
11
 
11
12
  cursor: default;
@@ -1,25 +1,20 @@
1
1
  import React from 'react';
2
- import { useIntl } from 'react-intl';
3
2
 
4
3
  import { Flex } from '@strapi/design-system/Flex';
5
4
  import { IconButton } from '@strapi/design-system/IconButton';
6
5
  import { Typography } from '@strapi/design-system/Typography';
7
- import PencilIcon from '@strapi/icons/Pencil';
8
- import TrashIcon from '@strapi/icons/Trash';
9
- import RefreshIcon from '@strapi/icons/Refresh';
6
+ import { Icon } from '@strapi/design-system/Icon';
7
+ import { Pencil, Trash, Refresh } from '@strapi/icons/';
10
8
 
11
9
  import Wrapper from './Wrapper';
12
10
  import ItemCardBadge from '../ItemCardBadge';
13
- import { getTrad } from "../../../translations";
11
+ import { getMessage } from '../../../utils';
14
12
 
15
13
  const ItemCardHeader = ({ title, path, icon, removed, onItemRemove, onItemEdit, onItemRestore }) => {
16
-
17
- const { formatMessage } = useIntl();
18
-
19
14
  return (
20
15
  <Wrapper>
21
16
  <Flex alignItems="center">
22
- {icon}
17
+ <Icon as={icon} />
23
18
  <Typography variant="omega" fontWeight="bold">
24
19
  {title}
25
20
  </Typography>
@@ -34,14 +29,14 @@ const ItemCardHeader = ({ title, path, icon, removed, onItemRemove, onItemEdit,
34
29
  backgroundColor={`danger100`}
35
30
  textColor={`danger600`}
36
31
  >
37
- {formatMessage(getTrad("navigation.item.badge.removed"))}
32
+ {getMessage("components.navigationItem.badge.removed")}
38
33
  </ItemCardBadge>)
39
34
  }
40
35
 
41
- <IconButton disabled={removed} onClick={onItemEdit} label="Edit" icon={<PencilIcon />} />
36
+ <IconButton disabled={removed} onClick={onItemEdit} label="Edit" icon={<Pencil />} />
42
37
  {removed ?
43
- <IconButton onClick={onItemRestore} label="Restore" icon={<RefreshIcon />} /> :
44
- <IconButton onClick={onItemRemove} label="Remove" icon={<TrashIcon />} />
38
+ <IconButton onClick={onItemRestore} label="Restore" icon={<Refresh />} /> :
39
+ <IconButton onClick={onItemRemove} label="Remove" icon={<Trash />} />
45
40
  }
46
41
  </Flex>
47
42
  </Wrapper>
@@ -1,7 +1,6 @@
1
1
  import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
- import { isEmpty, isNumber, get } from 'lodash';
4
- import { useIntl } from "react-intl";
3
+ import { isEmpty, isNumber } from 'lodash';
5
4
 
6
5
  import { Box } from '@strapi/design-system/Box';
7
6
  import { Card, CardBody } from '@strapi/design-system/Card';
@@ -10,17 +9,16 @@ import { Flex } from '@strapi/design-system/Flex';
10
9
  import { Link } from '@strapi/design-system/Link';
11
10
  import { TextButton } from '@strapi/design-system/TextButton';
12
11
  import { Typography } from '@strapi/design-system/Typography';
13
-
14
12
  import { ArrowRight, Link as LinkIcon, Earth, Plus } from '@strapi/icons';
15
13
 
16
14
  import { navigationItemType } from '../../pages/View/utils/enums';
17
15
  import ItemCardHeader from './ItemCardHeader';
18
16
  import List from '../NavigationItemList';
19
17
  import Wrapper from './Wrapper';
20
- import { getTrad } from '../../translations';
21
18
  import { extractRelatedItemLabel } from '../../pages/View/utils/parsers';
22
19
  import ItemCardBadge from './ItemCardBadge';
23
20
  import { ItemCardRemovedOverlay } from './ItemCardRemovedOverlay';
21
+ import { getMessage } from '../../utils';
24
22
 
25
23
  const Item = (props) => {
26
24
  const {
@@ -50,7 +48,6 @@ const Item = (props) => {
50
48
  menuAttached,
51
49
  } = item;
52
50
 
53
- const { formatMessage } = useIntl();
54
51
  const { contentTypes, contentTypesNameFields } = config;
55
52
  const isExternal = type === navigationItemType.EXTERNAL;
56
53
  const isPublished = relatedRef && relatedRef?.publishedAt;
@@ -71,7 +68,7 @@ const Item = (props) => {
71
68
  <ItemCardHeader
72
69
  title={title}
73
70
  path={isExternal ? externalPath : absolutePath}
74
- icon={isExternal ? <Earth /> : <LinkIcon />}
71
+ icon={isExternal ? Earth : LinkIcon }
75
72
  onItemRemove={() => onItemRemove({
76
73
  ...item,
77
74
  relatedRef,
@@ -97,21 +94,22 @@ const Item = (props) => {
97
94
  onClick={(e) => onItemLevelAdd(e, viewId, isNextMenuAllowedLevel, absolutePath, menuAttached)}
98
95
  >
99
96
  <Typography variant="pi" fontWeight="bold" textColor={removed ? "neutral600" : "primary600"}>
100
- {formatMessage(getTrad("navigation.item.action.newItem"))}
97
+ {getMessage("components.navigationItem.action.newItem")}
101
98
  </Typography>
102
99
  </TextButton>
103
100
  { relatedItemLabel && (<Box>
104
101
  <ItemCardBadge
105
- style={{ marginRight: 4 }}
106
102
  borderColor={`${relatedBadgeColor}200`}
107
103
  backgroundColor={`${relatedBadgeColor}100`}
108
104
  textColor={`${relatedBadgeColor}600`}
109
105
  className="action"
110
106
  small
111
107
  >
112
- {formatMessage(getTrad(`navigation.item.badge.${isPublished ? 'published' : 'draft'}`), {
113
- type: relatedTypeLabel
114
- })}
108
+ {getMessage({
109
+ id: `components.navigationItem.badge.${isPublished ? 'published' : 'draft'}`, props: {
110
+ type: relatedTypeLabel
111
+ }
112
+ })}
115
113
  </ItemCardBadge>
116
114
  <Typography variant="pi" fontWeight="bold" textColor="neutral600">
117
115
  { relatedItemLabel }
@@ -131,7 +129,7 @@ const Item = (props) => {
131
129
  onItemRestore={onItemRestore}
132
130
  error={error}
133
131
  allowedLevels={allowedLevels}
134
- isParentAttachedToMenu={true}
132
+ isParentAttachedToMenu={menuAttached}
135
133
  items={item.items}
136
134
  level={level + 1}
137
135
  levelPath={absolutePath}
@@ -151,7 +149,6 @@ Item.propTypes = {
151
149
  uiRouterKey: PropTypes.string,
152
150
  path: PropTypes.string,
153
151
  externalPath: PropTypes.string,
154
- audience: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.number])),
155
152
  related: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
156
153
  menuAttached: PropTypes.bool
157
154
  }).isRequired,
@@ -0,0 +1,8 @@
1
+ import styled from 'styled-components';
2
+ import { Alert } from '@strapi/design-system/Alert';
3
+
4
+ export default styled(Alert)`
5
+ [role="status"] {
6
+ flex-direction: column;
7
+ }
8
+ `
@@ -1,7 +1,7 @@
1
1
  import React, { useRef, useState, useEffect } from 'react';
2
2
  import { useIntl } from 'react-intl';
3
3
  import { IconButton } from '@strapi/design-system/IconButton';
4
- import { Searchbar, SearchForm } from '@strapi/design-system/Searchbar';
4
+ import { Searchbar } from '@strapi/design-system/Searchbar';
5
5
  import SearchIcon from "@strapi/icons/Search";
6
6
  import { getTradId } from '../../translations';
7
7
 
@@ -11,32 +11,30 @@ const Search = ({ value, setValue }) => {
11
11
  const { formatMessage } = useIntl();
12
12
 
13
13
  useEffect(() => {
14
- if (isOpen) {
15
- setTimeout(() => {
16
- wrapperRef.current.querySelector('input').focus();
17
- }, 0);
18
- }
14
+ if (isOpen) {
15
+ setTimeout(() => {
16
+ wrapperRef.current.querySelector('input').focus();
17
+ }, 0);
18
+ }
19
19
  }, [isOpen]);
20
-
20
+
21
21
  if (isOpen) {
22
22
  return (
23
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>
24
+ <Searchbar
25
+ name="searchbar"
26
+ onClear={() => { setValue(''); setIsOpen(false); }}
27
+ value={value}
28
+ size="S"
29
+ onChange={(e) => setValue(e.target.value)}
30
+ clearLabel="Clearing the search"
31
+ placeholder={formatMessage({
32
+ id: getTradId('popup.item.form.audience.placeholder'),
33
+ defaultMessage: 'Type to start searching...',
34
+ })}
35
+ >
36
+ Search for navigation items
37
+ </Searchbar>
40
38
  </div>
41
39
  );
42
40
  } else {
@@ -0,0 +1,13 @@
1
+ import { useQuery } from 'react-query';
2
+ import { useNotification } from '@strapi/helper-plugin';
3
+ import { fetchAllContentTypes } from '../utils/api';
4
+
5
+ const useAllContentTypes = () => {
6
+ const toggleNotification = useNotification();
7
+ const { isLoading, data } = useQuery('contentTypes', () =>
8
+ fetchAllContentTypes(toggleNotification)
9
+ );
10
+ return { data, isLoading, };
11
+ };
12
+
13
+ export default useAllContentTypes;