strapi-plugin-navigation 2.3.0-beta.0 → 2.3.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.
Files changed (81) hide show
  1. package/README.md +128 -31
  2. package/admin/src/components/AdditionalFieldInput/index.js +2 -2
  3. package/admin/src/components/AdditionalFieldInput/types.d.ts +4 -3
  4. package/admin/src/components/ConfirmationDialog/index.d.ts +10 -10
  5. package/admin/src/components/EmptyView/index.js +2 -0
  6. package/admin/src/components/Item/ItemCardHeader/icons.d.ts +1 -1
  7. package/admin/src/components/Item/ItemCardHeader/icons.js +2 -1
  8. package/admin/src/components/Item/ItemCardHeader/index.d.ts +1 -0
  9. package/admin/src/components/Item/ItemCardHeader/index.js +10 -8
  10. package/admin/src/components/Item/index.d.ts +15 -15
  11. package/admin/src/components/Item/index.js +10 -8
  12. package/admin/src/components/NavigationItemList/index.d.ts +13 -12
  13. package/admin/src/components/NavigationItemList/index.js +2 -2
  14. package/admin/src/hooks/useNavigationManager.d.ts +0 -1
  15. package/admin/src/index.d.ts +5 -7
  16. package/admin/src/index.js +12 -18
  17. package/admin/src/pages/DataManagerProvider/index.d.ts +1 -1
  18. package/admin/src/pages/DataManagerProvider/index.js +32 -5
  19. package/admin/src/pages/DataManagerProvider/reducer.d.ts +16 -16
  20. package/admin/src/pages/NoAccessPage/index.d.ts +3 -0
  21. package/admin/src/pages/NoAccessPage/index.js +31 -0
  22. package/admin/src/pages/SettingsPage/index.d.ts +0 -1
  23. package/admin/src/pages/SettingsPage/index.js +9 -0
  24. package/admin/src/pages/SettingsPage/types.d.ts +8 -8
  25. package/admin/src/pages/SettingsPage/utils/functions.d.ts +0 -2
  26. package/admin/src/pages/View/components/NavigationHeader/index.d.ts +2 -1
  27. package/admin/src/pages/View/components/NavigationHeader/index.js +19 -9
  28. package/admin/src/pages/View/components/NavigationItemForm/index.js +25 -19
  29. package/admin/src/pages/View/components/NavigationItemForm/types.d.ts +10 -9
  30. package/admin/src/pages/View/components/NavigationItemForm/utils/form.d.ts +6 -6
  31. package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupFooter.d.ts +12 -10
  32. package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupFooter.js +5 -1
  33. package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupHeader.d.ts +2 -1
  34. package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupHeader.js +6 -2
  35. package/admin/src/pages/View/components/NavigationItemPopup/index.d.ts +13 -12
  36. package/admin/src/pages/View/components/NavigationItemPopup/index.js +4 -3
  37. package/admin/src/pages/View/components/NavigationManager/AllNavigations/icons.d.ts +0 -1
  38. package/admin/src/pages/View/components/NavigationManager/AllNavigations/index.d.ts +0 -1
  39. package/admin/src/pages/View/components/NavigationManager/DeletionConfirm/index.d.ts +0 -1
  40. package/admin/src/pages/View/components/NavigationManager/ErrorDetails/index.d.ts +0 -1
  41. package/admin/src/pages/View/components/NavigationManager/Footer/index.d.ts +1 -1
  42. package/admin/src/pages/View/components/NavigationManager/Form/index.d.ts +0 -1
  43. package/admin/src/pages/View/components/NavigationManager/NavigationUpdate/index.d.ts +0 -1
  44. package/admin/src/pages/View/components/NavigationManager/NewNavigation/index.d.ts +0 -1
  45. package/admin/src/pages/View/components/NavigationManager/index.d.ts +0 -1
  46. package/admin/src/pages/View/components/NavigationManager/types.d.ts +3 -3
  47. package/admin/src/pages/View/index.d.ts +1 -1
  48. package/admin/src/pages/View/index.js +42 -25
  49. package/admin/src/permissions.d.ts +6 -2
  50. package/admin/src/permissions.js +1 -0
  51. package/admin/src/translations/ca.json +198 -0
  52. package/admin/src/translations/en.json +11 -1
  53. package/admin/src/translations/fr.json +3 -1
  54. package/admin/src/translations/index.d.ts +2 -0
  55. package/admin/src/translations/index.js +2 -0
  56. package/admin/src/utils/functions.d.ts +2 -2
  57. package/package.json +16 -14
  58. package/permissions.d.ts +1 -0
  59. package/permissions.js +1 -0
  60. package/server/bootstrap/index.js +6 -0
  61. package/server/config/setupStrategy.js +11 -0
  62. package/server/controllers/client.js +15 -0
  63. package/server/i18n/graphQLEnhancers.d.ts +1 -1
  64. package/server/i18n/navigationSetupStrategy.js +68 -40
  65. package/server/i18n/types.d.ts +11 -11
  66. package/server/i18n/utils.d.ts +2 -2
  67. package/server/routes/admin.js +99 -2
  68. package/server/routes/client.js +8 -0
  69. package/server/services/admin.js +114 -57
  70. package/server/services/client.js +17 -1
  71. package/server/services/common.js +31 -16
  72. package/server/utils/functions.d.ts +3 -1
  73. package/server/utils/functions.js +31 -2
  74. package/tsconfig.tsbuildinfo +1 -1
  75. package/types/config.d.ts +8 -8
  76. package/types/contentTypes.d.ts +20 -20
  77. package/types/controllers.d.ts +3 -2
  78. package/types/graphQL.d.ts +1 -1
  79. package/types/i18n.d.ts +2 -2
  80. package/types/services.d.ts +7 -3
  81. package/types/utils.d.ts +25 -20
package/README.md CHANGED
@@ -45,12 +45,16 @@ Strapi Navigation Plugin provides a website navigation / menu builder feature fo
45
45
  - [Plugin file](#in-v202-and-older--default-configuration-state-for-v203-and-newer)
46
46
  5. [🔧 GraphQL Configuration](#-gql-configuration)
47
47
  6. [🌍 i18n Internationalization](#-i18n-internationalization)
48
- 7. [🕸️ Public API specification](#%EF%B8%8F-public-api-specification)
48
+ 7. [👤 RBAC](#-rbac)
49
+ 8. [🔐 Authorization strategy](#-authorization-strategy)
50
+ 9. [🕸️ Public API specification](#%EF%B8%8F-public-api-specification)
49
51
  - [REST API](#rest-api)
50
52
  - [GraphQL API](#graphql-api)
51
- 8. [💬 FAQ](#-faq)
52
- 10. [🤝 Contributing](#-contributing)
53
- 11. [👨‍💻 Community support](#-community-support)
53
+ 10. [🔌 Extensions](#-extensions)
54
+ 11. [🧩 Examples](#-examples)
55
+ 12. [💬 FAQ](#-faq)
56
+ 13. [🤝 Contributing](#-contributing)
57
+ 14. [👨‍💻 Community support](#-community-support)
54
58
 
55
59
  ## ✨ Features
56
60
 
@@ -118,7 +122,7 @@ Complete installation requirements are exact same as for Strapi itself and can b
118
122
 
119
123
  **Supported Strapi versions**:
120
124
 
121
- - Strapi v4.2.0 (recently tested)
125
+ - Strapi v4.15.x (recently tested)
122
126
  - Strapi v4.x
123
127
 
124
128
  > 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).
@@ -163,6 +167,9 @@ Config for this plugin is stored as a part of the `config/plugins.js` or `config
163
167
  contentTypesNameFields: {
164
168
  'api::page.page': ['title']
165
169
  },
170
+ pathDefaultFields: {
171
+ 'api::page.page': ['slug']
172
+ },
166
173
  allowedLevels: 2,
167
174
  gql: {...},
168
175
  }
@@ -175,10 +182,10 @@ Config for this plugin is stored as a part of the `config/plugins.js` or `config
175
182
  - `allowedLevels` - Maximum level for which you're able to mark item as "Menu attached"
176
183
  - `contentTypes` - UIDs of related content types
177
184
  - `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`
185
+ - `pathDefaultFields` - The attribute to copy the default path from per content type. Syntax: `'api::<collection name>.<content type name>': ['url_slug', 'path']`
178
186
  - `gql` - If you're using GraphQL that's the right place to put all necessary settings. More **[ here ](#gql-configuration)**
179
187
  - `i18nEnabled` - should you want to manage multi-locale content via navigation set this value `Enabled`. More **[ here ](#i18n-internationalization)**
180
188
  - `cascadeMenuAttached` - If you don't want "Menu attached" to cascade on child items set this value `Disabled`.
181
- - `slugify` - allows to extend configuration of our "slugging" solution of choice. To learn more visit the [documentation](https://github.com/sindresorhus/slugify#api). It can be left unset since it's optional. **This option can only be handled by configuration in config file**.
182
189
 
183
190
  ### Properties
184
191
 
@@ -249,12 +256,35 @@ Of course if you know that `fr` version is present at id `2` you can just query
249
256
  If feature is enabled GQL render navigation query is expanded to handle `locale` param(it will work the same as regular requests). Checkout schema provided by GraphQL plugin.
250
257
 
251
258
  ## 👤 RBAC
252
- Plugin provides granular permissions based on Strapi RBAC functionality.
259
+ Plugin provides granular permissions based on **Strapi RBAC** functionality within the editorial interface &amp; **Admin API**. Those settings are editable via the _Setings_ -> _Administration Panel_ -> _Roles_.
253
260
 
254
- ### Mandatory permissions
255
261
  For any role different than **Super Admin**, to access the **Navigation panel** you must set following permissions:
262
+
263
+ ### Mandatory permissions
256
264
  - _Plugins_ -> _Navigation_ -> _Read_ - gives you the access to **Navigation Panel**
257
265
 
266
+ ### Other permissions
267
+ - _Plugins_ -> _Navigation_ -> _Update_ - with this permission user is able to change Navigation structure
268
+ - _Plugins_ -> _Navigation_ -> _Settings_ - special permission for users that should be able to change plugin settings
269
+
270
+ ## 🔐 Authorization strategy
271
+ Is applied for **Public API** both for REST and GraphQL. You can manage is by two different ways. Those settings are editable via the _Setings_ -> _Users &amp; Permissions Plugin_ -> _Roles_.
272
+
273
+ ## User based
274
+ - _Public_ - as per description it's default role for any not authenticated user. By enabling **Public API** of the plugin here you're making it **fully public**, without **any permissions check**.
275
+ - _Authenticated_ - as per description this is default role for Strapi Users. If you enable **Public API** here, for any call made you must use the User authentication token as `Bearer <token>`.
276
+
277
+ ## Token based
278
+ - _Full Access_ - gives full access to every Strapi Content API including our plugin endpoints as well.
279
+ - _Custom_ - granural access management to every Strapi Content API endpoints as well as plugin **Public API** - _(recomended approach)_
280
+
281
+ > _Note: Token usage &amp Read-Only tokens_
282
+ > If you're aiming to use token based approach, for every call you must provide proper token in headers as `Bearer <token>`.
283
+ >
284
+ > Important: As the Read-Only tokens are dedicated to support just `find` and `findAll` endpoints from Strapi Content API, they are not covering access to plugin **Public API** `render` and `renderChild` endpoints. We recommend to use the `Custom` token type for fully granural and secured approach instead of `Full Access` ones.
285
+ >
286
+ > Reference: [Strapi - API Tokens](https://docs.strapi.io/dev-docs/configurations/api-tokens#usage)
287
+
258
288
  ## Base Navigation Item model
259
289
 
260
290
  ### Flat
@@ -347,6 +377,73 @@ Plugin supports both **REST API** and **GraphQL API** exposed by Strapi.
347
377
  > Version `v2.0.13` introduced breaking change!
348
378
  > All responses have changed their structure. Related field will now be of type ContentType instead of Array\<ContentType\>
349
379
 
380
+ `GET <host>/api/navigation/?locale=<locale>&orderBy=<orderBy>&orderDirection=<orderDirection>`
381
+
382
+ NOTE: All params are optional
383
+
384
+ **Example URL**: `https://localhost:1337/api/navigation?locale=en`
385
+
386
+ **Example response body**
387
+
388
+ ```json
389
+ [
390
+ {
391
+ "id": 383,
392
+ "name": "Floor",
393
+ "slug": "floor-pl",
394
+ "visible": true,
395
+ "createdAt": "2023-09-29T12:45:54.399Z",
396
+ "updatedAt": "2023-09-29T13:44:08.702Z",
397
+ "localeCode": "pl"
398
+ },
399
+ {
400
+ "id": 384,
401
+ "name": "Floor",
402
+ "slug": "floor-fr",
403
+ "visible": true,
404
+ "createdAt": "2023-09-29T12:45:54.399Z",
405
+ "updatedAt": "2023-09-29T13:44:08.725Z",
406
+ "localeCode": "fr"
407
+ },
408
+ {
409
+ "id": 382,
410
+ "name": "Floor",
411
+ "slug": "floor",
412
+ "visible": true,
413
+ "createdAt": "2023-09-29T12:45:54.173Z",
414
+ "updatedAt": "2023-09-29T13:44:08.747Z",
415
+ "localeCode": "en"
416
+ },
417
+ {
418
+ "id": 374,
419
+ "name": "Main navigation",
420
+ "slug": "main-navigation-pl",
421
+ "visible": true,
422
+ "createdAt": "2023-09-29T12:22:30.373Z",
423
+ "updatedAt": "2023-09-29T13:44:08.631Z",
424
+ "localeCode": "pl"
425
+ },
426
+ {
427
+ "id": 375,
428
+ "name": "Main navigation",
429
+ "slug": "main-navigation-fr",
430
+ "visible": true,
431
+ "createdAt": "2023-09-29T12:22:30.373Z",
432
+ "updatedAt": "2023-09-29T13:44:08.658Z",
433
+ "localeCode": "fr"
434
+ },
435
+ {
436
+ "id": 373,
437
+ "name": "Main navigation",
438
+ "slug": "main-navigation",
439
+ "visible": true,
440
+ "createdAt": "2023-09-29T12:22:30.356Z",
441
+ "updatedAt": "2023-09-29T13:44:08.680Z",
442
+ "localeCode": "en"
443
+ }
444
+ ]
445
+ ```
446
+
350
447
  `GET <host>/api/navigation/render/<navigationIdOrSlug>?type=<type>`
351
448
 
352
449
  Return a rendered navigation structure depends on passed type (`TREE`, `RFR` or nothing to render as `FLAT`).
@@ -609,37 +706,16 @@ For collection types it will be read from content type's attribute name `templat
609
706
 
610
707
  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`.
611
708
 
612
- ## 🧩 Examples
613
-
614
- 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.
615
-
616
- ## 💬 FAQ
617
-
618
- ### GraphQL tricks
619
-
620
- **Q:** I would like to use GraphQL schemas but I'm not getting renderNavigation query or even proper types as Navigation, NavigationItem etc. What should I do?
621
-
622
- **A:** **A:** There is a one trick you might try. Strapi by default is ordering plugins by the way which takes `strapi-plugin-graphql` to initialize earlier than other plugins so types might not be injected. If you don't have it yet, please create `config/plugins.js` file and put there following lines (put `graphql` at the end):
623
-
624
- ```js
625
- module.exports = {
626
- 'navigation': { enabled: true },
627
- 'graphql': { enabled: true },
628
- };
629
- ```
630
-
631
- If you already got it, make sure that `navigation` plugin is inserted before `graphql`. That should do the job.
709
+ ## 🔌 Extensions
632
710
 
633
711
  ### Slug generation
634
712
 
635
- #### Customisation
636
-
637
713
  Slug generation is available as a controller and service. If you have custom requirements outside of what this plugin provides you can add your own logic with [plugins extensions](https://docs.strapi.io/developer-docs/latest/development/plugins-extension.html).
638
714
 
639
715
  For example:
640
716
 
641
717
  ```ts
642
- // path: ./src/index.js
718
+ // path: /admin/src/index.js
643
719
 
644
720
  module.exports = {
645
721
  // ...
@@ -657,6 +733,27 @@ module.exports = {
657
733
  };
658
734
  ```
659
735
 
736
+ ## 🧩 Examples
737
+
738
+ 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.
739
+
740
+ ## 💬 FAQ
741
+
742
+ ### GraphQL tricks
743
+
744
+ **Q:** I would like to use GraphQL schemas but I'm not getting renderNavigation query or even proper types as Navigation, NavigationItem etc. What should I do?
745
+
746
+ **A:** There is a one trick you might try. Strapi by default is ordering plugins by the way which takes `strapi-plugin-graphql` to initialize earlier than other plugins so types might not be injected. If you don't have it yet, please create `config/plugins.js` file and put there following lines (put `graphql` at the end):
747
+
748
+ ```js
749
+ module.exports = {
750
+ 'navigation': { enabled: true },
751
+ 'graphql': { enabled: true },
752
+ };
753
+ ```
754
+
755
+ If you already got it, make sure that `navigation` plugin is inserted before `graphql`. That should do the job.
756
+
660
757
  ## 🤝 Contributing
661
758
 
662
759
  <div>
@@ -36,14 +36,14 @@ const DEFAULT_STRING_VALUE = "";
36
36
  const handlerFactory = ({ field, prop, onChange }) => ({ target }) => {
37
37
  onChange(field.name, target[prop]);
38
38
  };
39
- const AdditionalFieldInput = ({ field, isLoading, onChange, value, error }) => {
39
+ const AdditionalFieldInput = ({ field, isLoading, onChange, value, disabled, error }) => {
40
40
  const toggleNotification = (0, helper_plugin_1.useNotification)();
41
41
  const { formatMessage } = (0, react_intl_1.useIntl)();
42
42
  const defaultInputProps = (0, react_1.useMemo)(() => ({
43
43
  id: field.name,
44
44
  name: field.name,
45
45
  label: field.label,
46
- disabled: isLoading,
46
+ disabled: isLoading || disabled,
47
47
  error: error && formatMessage(error),
48
48
  }), [field, isLoading, error]);
49
49
  const handleBoolean = (0, react_1.useMemo)(() => handlerFactory({ field, onChange, prop: "checked" }), [onChange, field]);
@@ -1,14 +1,15 @@
1
1
  import { MessageDescriptor } from "react-intl";
2
2
  import { NavigationItemCustomField } from "../../../../types";
3
- export declare type AdditionalFieldInputProps = {
3
+ export type AdditionalFieldInputProps = {
4
4
  field: NavigationItemCustomField;
5
5
  isLoading: boolean;
6
6
  onChange: (name: string, value: string) => void;
7
7
  value: string | boolean | string[] | null;
8
+ disabled: boolean;
8
9
  error: MessageDescriptor | null;
9
10
  };
10
- export declare type TargetProp = "value" | "checked";
11
- export declare type Input = {
11
+ export type TargetProp = "value" | "checked";
12
+ export type Input = {
12
13
  prop: TargetProp;
13
14
  } & Pick<AdditionalFieldInputProps, "onChange" | "field">;
14
15
  //# sourceMappingURL=types.d.ts.map
@@ -13,16 +13,16 @@ declare function ConfirmationDialog({ isVisible, isActionAsync, children, onConf
13
13
  }): JSX.Element;
14
14
  declare namespace ConfirmationDialog {
15
15
  namespace propTypes {
16
- const isVisible: PropTypes.Requireable<boolean>;
17
- const isActionAsync: PropTypes.Requireable<boolean>;
18
- const children: PropTypes.Requireable<any>;
19
- const header: PropTypes.Requireable<string>;
20
- const labelCancel: PropTypes.Requireable<string>;
21
- const labelConfirm: PropTypes.Requireable<string>;
22
- const iconConfirm: PropTypes.Requireable<object>;
23
- const onConfirm: PropTypes.Validator<(...args: any[]) => any>;
24
- const onCancel: PropTypes.Validator<(...args: any[]) => any>;
16
+ let isVisible: PropTypes.Requireable<boolean>;
17
+ let isActionAsync: PropTypes.Requireable<boolean>;
18
+ let children: PropTypes.Requireable<any>;
19
+ let header: PropTypes.Requireable<string>;
20
+ let labelCancel: PropTypes.Requireable<string>;
21
+ let labelConfirm: PropTypes.Requireable<string>;
22
+ let iconConfirm: PropTypes.Requireable<object>;
23
+ let onConfirm: PropTypes.Validator<(...args: any[]) => any>;
24
+ let onCancel: PropTypes.Validator<(...args: any[]) => any>;
25
25
  }
26
26
  }
27
- import PropTypes from "prop-types";
27
+ import PropTypes from 'prop-types';
28
28
  //# sourceMappingURL=index.d.ts.map
@@ -4,6 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const styled_components_1 = __importDefault(require("styled-components"));
7
+ const Box_1 = require("@strapi/design-system/Box");
8
+ const Button_1 = require("@strapi/design-system/Button");
7
9
  const EmptyView = styled_components_1.default.div `
8
10
  display: flex;
9
11
  flex-grow: 1;
@@ -1,5 +1,5 @@
1
- /// <reference types="react" />
2
1
  export declare const pencilIcon: JSX.Element;
3
2
  export declare const refreshIcon: JSX.Element;
4
3
  export declare const trashIcon: JSX.Element;
4
+ export declare const eyeIcon: JSX.Element;
5
5
  //# sourceMappingURL=icons.d.ts.map
@@ -3,10 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.trashIcon = exports.refreshIcon = exports.pencilIcon = void 0;
6
+ exports.eyeIcon = exports.trashIcon = exports.refreshIcon = exports.pencilIcon = void 0;
7
7
  const react_1 = __importDefault(require("react"));
8
8
  const icons_1 = require("@strapi/icons");
9
9
  exports.pencilIcon = react_1.default.createElement(icons_1.Pencil, null);
10
10
  exports.refreshIcon = react_1.default.createElement(icons_1.Refresh, null);
11
11
  exports.trashIcon = react_1.default.createElement(icons_1.Trash, null);
12
+ exports.eyeIcon = react_1.default.createElement(icons_1.Eye, null);
12
13
  //# sourceMappingURL=icons.js.map
@@ -5,6 +5,7 @@ interface IProps {
5
5
  path: string;
6
6
  icon: ToBeFixed;
7
7
  removed: boolean;
8
+ canUpdate: boolean;
8
9
  onItemRemove: VoidEffect;
9
10
  onItemEdit: VoidEffect;
10
11
  onItemRestore: VoidEffect;
@@ -14,18 +14,20 @@ const ItemCardBadge_1 = __importDefault(require("../ItemCardBadge"));
14
14
  const utils_1 = require("../../../utils");
15
15
  const icons_1 = require("./icons");
16
16
  const wrapperStyle = { zIndex: 2 };
17
- const ItemCardHeader = ({ title, path, icon, removed, onItemRemove, onItemEdit, onItemRestore, dragRef }) => (react_1.default.createElement(Wrapper_1.default, null,
17
+ const pathWrapperStyle = { maxWidth: "425px" };
18
+ const ItemCardHeader = ({ title, path, icon, removed, canUpdate, onItemRemove, onItemEdit, onItemRestore, dragRef }) => (react_1.default.createElement(Wrapper_1.default, null,
18
19
  react_1.default.createElement(Flex_1.Flex, { alignItems: "center" },
19
- react_1.default.createElement(DragButton_1.default, { ref: dragRef }),
20
+ canUpdate && (react_1.default.createElement(DragButton_1.default, { ref: dragRef })),
20
21
  react_1.default.createElement(Typography_1.Typography, { variant: "omega", fontWeight: "bold" }, title),
21
- react_1.default.createElement(Typography_1.Typography, { variant: "omega", fontWeight: "bold", textColor: 'neutral500' }, path),
22
- react_1.default.createElement(Icon_1.Icon, { as: icon })),
22
+ react_1.default.createElement(Typography_1.Typography, { variant: "omega", fontWeight: "bold", textColor: 'neutral500', ellipsis: true, style: pathWrapperStyle }, path),
23
+ react_1.default.createElement(Flex_1.Flex, null,
24
+ react_1.default.createElement(Icon_1.Icon, { as: icon }))),
23
25
  react_1.default.createElement(Flex_1.Flex, { alignItems: "center", style: wrapperStyle },
24
26
  removed &&
25
27
  (react_1.default.createElement(ItemCardBadge_1.default, { borderColor: "danger200", backgroundColor: "danger100", textColor: "danger600" }, (0, utils_1.getMessage)("components.navigationItem.badge.removed"))),
26
- react_1.default.createElement(IconButton_1.IconButton, { disabled: removed, onClick: onItemEdit, label: "Edit", icon: icons_1.pencilIcon }),
27
- removed ?
28
- react_1.default.createElement(IconButton_1.IconButton, { onClick: onItemRestore, label: "Restore", icon: icons_1.refreshIcon }) :
29
- react_1.default.createElement(IconButton_1.IconButton, { onClick: onItemRemove, label: "Remove", icon: icons_1.trashIcon }))));
28
+ react_1.default.createElement(IconButton_1.IconButton, { disabled: removed, onClick: onItemEdit, label: (0, utils_1.getMessage)(`components.navigationItem.action.${canUpdate ? 'edit' : 'view'}`, canUpdate ? 'Edit' : 'View'), icon: canUpdate ? icons_1.pencilIcon : icons_1.eyeIcon }),
29
+ canUpdate && (react_1.default.createElement(react_1.default.Fragment, null, removed ?
30
+ react_1.default.createElement(IconButton_1.IconButton, { onClick: onItemRestore, label: (0, utils_1.getMessage)('components.navigationItem.action.restore', "Restore"), icon: icons_1.refreshIcon }) :
31
+ react_1.default.createElement(IconButton_1.IconButton, { onClick: onItemRemove, label: (0, utils_1.getMessage)('components.navigationItem.action.remove', "Remove"), icon: icons_1.trashIcon }))))));
30
32
  exports.default = ItemCardHeader;
31
33
  //# sourceMappingURL=index.js.map
@@ -2,30 +2,30 @@ export default Item;
2
2
  declare function Item(props: any): JSX.Element;
3
3
  declare namespace Item {
4
4
  namespace propTypes {
5
- const item: PropTypes.Validator<PropTypes.InferProps<{
5
+ let item: PropTypes.Validator<NonNullable<PropTypes.InferProps<{
6
6
  title: PropTypes.Requireable<string>;
7
7
  type: PropTypes.Requireable<string>;
8
8
  uiRouterKey: PropTypes.Requireable<string>;
9
9
  path: PropTypes.Requireable<string>;
10
10
  externalPath: PropTypes.Requireable<string>;
11
- related: PropTypes.Requireable<string | number>;
11
+ related: PropTypes.Requireable<NonNullable<string | number | null | undefined>>;
12
12
  menuAttached: PropTypes.Requireable<boolean>;
13
13
  collapsed: PropTypes.Requireable<boolean>;
14
- }>>;
15
- const relatedRef: PropTypes.Requireable<object>;
16
- const level: PropTypes.Requireable<number>;
17
- const levelPath: PropTypes.Requireable<string>;
18
- const isParentAttachedToMenu: PropTypes.Requireable<boolean>;
19
- const onItemRestore: PropTypes.Validator<(...args: any[]) => any>;
20
- const onItemLevelAdd: PropTypes.Validator<(...args: any[]) => any>;
21
- const onItemRemove: PropTypes.Validator<(...args: any[]) => any>;
22
- const onItemReOrder: PropTypes.Validator<(...args: any[]) => any>;
23
- const onItemToggleCollapse: PropTypes.Validator<(...args: any[]) => any>;
24
- const config: PropTypes.Validator<PropTypes.InferProps<{
14
+ }>>>;
15
+ let relatedRef: PropTypes.Requireable<object>;
16
+ let level: PropTypes.Requireable<number>;
17
+ let levelPath: PropTypes.Requireable<string>;
18
+ let isParentAttachedToMenu: PropTypes.Requireable<boolean>;
19
+ let onItemRestore: PropTypes.Validator<(...args: any[]) => any>;
20
+ let onItemLevelAdd: PropTypes.Validator<(...args: any[]) => any>;
21
+ let onItemRemove: PropTypes.Validator<(...args: any[]) => any>;
22
+ let onItemReOrder: PropTypes.Validator<(...args: any[]) => any>;
23
+ let onItemToggleCollapse: PropTypes.Validator<(...args: any[]) => any>;
24
+ let config: PropTypes.Validator<NonNullable<PropTypes.InferProps<{
25
25
  contentTypes: PropTypes.Validator<any[]>;
26
26
  contentTypesNameFields: PropTypes.Validator<object>;
27
- }>>;
27
+ }>>>;
28
28
  }
29
29
  }
30
- import PropTypes from "prop-types";
30
+ import PropTypes from 'prop-types';
31
31
  //# sourceMappingURL=index.d.ts.map
@@ -46,7 +46,7 @@ const ItemCardRemovedOverlay_1 = require("./ItemCardRemovedOverlay");
46
46
  const utils_1 = require("../../utils");
47
47
  const CollapseButton_1 = __importDefault(require("../CollapseButton"));
48
48
  const Item = (props) => {
49
- const { item, isLast = false, level = 0, levelPath = '', allowedLevels, relatedRef, isParentAttachedToMenu, onItemLevelAdd, onItemRemove, onItemRestore, onItemEdit, onItemReOrder, onItemToggleCollapse, error, displayChildren, config = {}, } = props;
49
+ const { item, isLast = false, level = 0, levelPath = '', allowedLevels, relatedRef, isParentAttachedToMenu, onItemLevelAdd, onItemRemove, onItemRestore, onItemEdit, onItemReOrder, onItemToggleCollapse, error, displayChildren, config = {}, permissions = {}, } = props;
50
50
  const { viewId, title, type, path, removed, externalPath, menuAttached, collapsed, structureId, items = [], } = item;
51
51
  const { contentTypes = [], contentTypesNameFields } = config;
52
52
  const isExternal = type === utils_1.navigationItemType.EXTERNAL;
@@ -60,6 +60,7 @@ const Item = (props) => {
60
60
  const relatedItemLabel = !isExternal ? (0, parsers_1.extractRelatedItemLabel)(relatedRef, contentTypesNameFields, { contentTypes }) : '';
61
61
  const relatedTypeLabel = relatedRef?.labelSingular;
62
62
  const relatedBadgeColor = isPublished ? 'success' : 'secondary';
63
+ const { canUpdate } = permissions;
63
64
  const dragRef = (0, react_1.useRef)(null);
64
65
  const dropRef = (0, react_1.useRef)(null);
65
66
  const previewRef = (0, react_1.useRef)(null);
@@ -108,9 +109,10 @@ const Item = (props) => {
108
109
  const contentType = contentTypes.find(_ => _.uid === contentTypeUid) || {};
109
110
  const generatePreviewUrl = entity => {
110
111
  const { isSingle } = contentType;
111
- return `/content-manager/${isSingle ? 'singleType' : 'collectionType'}/${entity?.__collectionUid}${!isSingle ? '/' + entity?.id : ''}`;
112
+ const entityLocale = entity?.locale ? `?plugins[i18n][locale]=${entity?.locale}` : '';
113
+ return `/content-manager/${isSingle ? 'singleType' : 'collectionType'}/${entity?.__collectionUid}${!isSingle ? '/' + entity?.id : ''}${entityLocale}`;
112
114
  };
113
- const onNewItemClick = (0, react_1.useCallback)((event) => onItemLevelAdd(event, viewId, isNextMenuAllowedLevel, absolutePath, menuAttached, `${structureId}.${items.length}`), [viewId, isNextMenuAllowedLevel, absolutePath, menuAttached, structureId, items]);
115
+ const onNewItemClick = (0, react_1.useCallback)((event) => canUpdate && onItemLevelAdd(event, viewId, isNextMenuAllowedLevel, absolutePath, menuAttached, `${structureId}.${items.length}`), [viewId, isNextMenuAllowedLevel, absolutePath, menuAttached, structureId, items, canUpdate]);
114
116
  return (react_1.default.createElement(Wrapper_1.default, { level: level, isLast: isLast, style: { opacity: isDragging ? 0.2 : 1 }, ref: refs ? refs.dropRef : null },
115
117
  react_1.default.createElement(Card_1.Card, { style: { width: "728px", zIndex: 1, position: "relative", overflow: 'hidden' } },
116
118
  removed && (react_1.default.createElement(ItemCardRemovedOverlay_1.ItemCardRemovedOverlay, null)),
@@ -120,22 +122,22 @@ const Item = (props) => {
120
122
  ...item,
121
123
  isMenuAllowedLevel,
122
124
  isParentAttachedToMenu,
123
- }, levelPath, isParentAttachedToMenu), onItemRestore: () => onItemRestore(item), dragRef: refs.dragRef, removed: removed })),
125
+ }, levelPath, isParentAttachedToMenu), onItemRestore: () => onItemRestore(item), dragRef: refs.dragRef, removed: removed, canUpdate: canUpdate })),
124
126
  react_1.default.createElement(Divider_1.Divider, null),
125
127
  !isExternal && (react_1.default.createElement(Card_1.CardBody, { style: { padding: '8px' } },
126
128
  react_1.default.createElement(Flex_1.Flex, { style: { width: '100%' }, direction: "row", alignItems: "center", justifyContent: "space-between" },
127
129
  react_1.default.createElement(Flex_1.Flex, null,
128
130
  !(0, lodash_1.isEmpty)(item.items) && react_1.default.createElement(CollapseButton_1.default, { toggle: () => onItemToggleCollapse(item), collapsed: collapsed, itemsCount: item.items.length }),
129
- react_1.default.createElement(TextButton_1.TextButton, { disabled: removed, startIcon: react_1.default.createElement(icons_1.Plus, null), onClick: onNewItemClick },
130
- react_1.default.createElement(Typography_1.Typography, { variant: "pi", fontWeight: "bold", textColor: removed ? "neutral600" : "primary600" }, (0, utils_1.getMessage)("components.navigationItem.action.newItem")))),
131
+ canUpdate && (react_1.default.createElement(TextButton_1.TextButton, { disabled: removed, startIcon: react_1.default.createElement(icons_1.Plus, null), onClick: onNewItemClick },
132
+ react_1.default.createElement(Typography_1.Typography, { variant: "pi", fontWeight: "bold", textColor: removed ? "neutral600" : "primary600" }, (0, utils_1.getMessage)("components.navigationItem.action.newItem"))))),
131
133
  relatedItemLabel && (react_1.default.createElement(Flex_1.Flex, { justifyContent: 'center', alignItems: 'center' },
132
134
  isHandledByPublishFlow && (react_1.default.createElement(ItemCardBadge_1.default, { borderColor: `${relatedBadgeColor}200`, backgroundColor: `${relatedBadgeColor}100`, textColor: `${relatedBadgeColor}600`, className: "action", small: true }, (0, utils_1.getMessage)({ id: `components.navigationItem.badge.${isPublished ? 'published' : 'draft'}` }))),
133
135
  react_1.default.createElement(Typography_1.Typography, { variant: "omega", textColor: 'neutral600' },
134
136
  relatedTypeLabel,
135
137
  "\u00A0/\u00A0"),
136
138
  react_1.default.createElement(Typography_1.Typography, { variant: "omega", textColor: 'neutral800' }, relatedItemLabel),
137
- react_1.default.createElement(Link_1.Link, { to: `/content-manager/collectionType/${relatedRef?.__collectionUid}/${relatedRef?.id}`, endIcon: react_1.default.createElement(icons_1.ArrowRight, null) }, "\u00A0")))))))),
138
- hasChildren && !removed && !collapsed && react_1.default.createElement(NavigationItemList_1.default, { onItemLevelAdd: onItemLevelAdd, onItemRemove: onItemRemove, onItemEdit: onItemEdit, onItemRestore: onItemRestore, onItemReOrder: onItemReOrder, onItemToggleCollapse: onItemToggleCollapse, error: error, allowedLevels: allowedLevels, isParentAttachedToMenu: menuAttached, items: item.items, level: level + 1, levelPath: absolutePath, contentTypes: contentTypes, contentTypesNameFields: contentTypesNameFields })));
139
+ react_1.default.createElement(Link_1.Link, { to: generatePreviewUrl(relatedRef), endIcon: react_1.default.createElement(icons_1.ArrowRight, null) }, "\u00A0")))))))),
140
+ hasChildren && !removed && !collapsed && react_1.default.createElement(NavigationItemList_1.default, { onItemLevelAdd: onItemLevelAdd, onItemRemove: onItemRemove, onItemEdit: onItemEdit, onItemRestore: onItemRestore, onItemReOrder: onItemReOrder, onItemToggleCollapse: onItemToggleCollapse, error: error, allowedLevels: allowedLevels, isParentAttachedToMenu: menuAttached, items: item.items, level: level + 1, levelPath: absolutePath, contentTypes: contentTypes, contentTypesNameFields: contentTypesNameFields, permissions: permissions })));
139
141
  };
140
142
  Item.propTypes = {
141
143
  item: prop_types_1.default.shape({
@@ -1,5 +1,5 @@
1
1
  export default List;
2
- declare function List({ allowedLevels, error, isParentAttachedToMenu, items, level, levelPath, onItemEdit, onItemLevelAdd, onItemRemove, onItemRestore, onItemReOrder, onItemToggleCollapse, displayFlat, contentTypes, contentTypesNameFields, }: {
2
+ declare function List({ allowedLevels, error, isParentAttachedToMenu, items, level, levelPath, onItemEdit, onItemLevelAdd, onItemRemove, onItemRestore, onItemReOrder, onItemToggleCollapse, displayFlat, contentTypes, contentTypesNameFields, permissions, }: {
3
3
  allowedLevels: any;
4
4
  error: any;
5
5
  isParentAttachedToMenu?: boolean | undefined;
@@ -15,20 +15,21 @@ declare function List({ allowedLevels, error, isParentAttachedToMenu, items, lev
15
15
  displayFlat: any;
16
16
  contentTypes: any;
17
17
  contentTypesNameFields: any;
18
+ permissions: any;
18
19
  }): JSX.Element;
19
20
  declare namespace List {
20
21
  namespace propTypes {
21
- const allowedLevels: PropTypes.Requireable<number>;
22
- const isParentAttachedToMenu: PropTypes.Requireable<boolean>;
23
- const items: PropTypes.Requireable<any[]>;
24
- const level: PropTypes.Requireable<number>;
25
- const onItemLevelAdd: PropTypes.Validator<(...args: any[]) => any>;
26
- const onItemRemove: PropTypes.Validator<(...args: any[]) => any>;
27
- const onItemRestore: PropTypes.Validator<(...args: any[]) => any>;
28
- const onItemReOrder: PropTypes.Validator<(...args: any[]) => any>;
29
- const onItemToggleCollapse: PropTypes.Validator<(...args: any[]) => any>;
30
- const contentTypes: PropTypes.Validator<any[]>;
31
- const contentTypesNameFields: PropTypes.Validator<object>;
22
+ let allowedLevels: PropTypes.Requireable<number>;
23
+ let isParentAttachedToMenu: PropTypes.Requireable<boolean>;
24
+ let items: PropTypes.Requireable<any[]>;
25
+ let level: PropTypes.Requireable<number>;
26
+ let onItemLevelAdd: PropTypes.Validator<(...args: any[]) => any>;
27
+ let onItemRemove: PropTypes.Validator<(...args: any[]) => any>;
28
+ let onItemRestore: PropTypes.Validator<(...args: any[]) => any>;
29
+ let onItemReOrder: PropTypes.Validator<(...args: any[]) => any>;
30
+ let onItemToggleCollapse: PropTypes.Validator<(...args: any[]) => any>;
31
+ let contentTypes: PropTypes.Validator<any[]>;
32
+ let contentTypesNameFields: PropTypes.Validator<object>;
32
33
  }
33
34
  }
34
35
  import PropTypes from "prop-types";
@@ -7,12 +7,12 @@ const react_1 = __importDefault(require("react"));
7
7
  const prop_types_1 = __importDefault(require("prop-types"));
8
8
  const Item_1 = __importDefault(require("../Item"));
9
9
  const Wrapper_1 = __importDefault(require("./Wrapper"));
10
- const List = ({ allowedLevels, error, isParentAttachedToMenu = false, items, level = 0, levelPath = '', onItemEdit, onItemLevelAdd, onItemRemove, onItemRestore, onItemReOrder, onItemToggleCollapse, displayFlat, contentTypes, contentTypesNameFields, }) => (react_1.default.createElement(Wrapper_1.default, { level: level }, items.map((item, n) => {
10
+ const List = ({ allowedLevels, error, isParentAttachedToMenu = false, items, level = 0, levelPath = '', onItemEdit, onItemLevelAdd, onItemRemove, onItemRestore, onItemReOrder, onItemToggleCollapse, displayFlat, contentTypes, contentTypesNameFields, permissions, }) => (react_1.default.createElement(Wrapper_1.default, { level: level }, items.map((item, n) => {
11
11
  const { relatedRef, ...itemProps } = item;
12
12
  return (react_1.default.createElement(Item_1.default, { key: `list-item-${item.viewId || n}`, item: itemProps, isLast: n === items.length - 1, relatedRef: relatedRef, level: level, levelPath: levelPath, isParentAttachedToMenu: isParentAttachedToMenu, allowedLevels: allowedLevels, onItemRestore: onItemRestore, onItemLevelAdd: onItemLevelAdd, onItemRemove: onItemRemove, onItemEdit: onItemEdit, onItemReOrder: onItemReOrder, onItemToggleCollapse: onItemToggleCollapse, error: error, displayChildren: displayFlat, config: {
13
13
  contentTypes,
14
14
  contentTypesNameFields
15
- } }));
15
+ }, permissions: permissions }));
16
16
  })));
17
17
  List.propTypes = {
18
18
  allowedLevels: prop_types_1.default.number,
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  export declare const useNavigationManager: () => {
3
2
  navigationManagerModal: JSX.Element | null;
4
3
  openNavigationManagerModal: () => void;
@@ -1,14 +1,12 @@
1
1
  declare namespace _default {
2
2
  function register(app: any): void;
3
- function register(app: any): void;
4
- function bootstrap(): void;
5
3
  function bootstrap(): void;
6
4
  function registerTrads({ locales }: {
7
- locales: any;
8
- }): Promise<any[]>;
9
- function registerTrads({ locales }: {
10
- locales: any;
11
- }): Promise<any[]>;
5
+ locales?: any[] | undefined;
6
+ }): {
7
+ data: any;
8
+ locale: any;
9
+ }[];
12
10
  }
13
11
  export default _default;
14
12
  //# sourceMappingURL=index.d.ts.map
@@ -31,7 +31,8 @@ const package_json_1 = __importDefault(require("../../package.json"));
31
31
  const pluginId_1 = __importDefault(require("./pluginId"));
32
32
  const permissions_1 = __importDefault(require("./permissions"));
33
33
  const navigation_1 = __importDefault(require("./components/icons/navigation"));
34
- const translations_1 = require("./translations");
34
+ const translations_1 = __importStar(require("./translations"));
35
+ const lodash_1 = require("lodash");
35
36
  const name = package_json_1.default.strapi.name;
36
37
  exports.default = {
37
38
  register(app) {
@@ -50,7 +51,7 @@ exports.default = {
50
51
  const component = await Promise.resolve().then(() => __importStar(require('./pages/SettingsPage')));
51
52
  return component;
52
53
  },
53
- permissions: permissions_1.default.access,
54
+ permissions: permissions_1.default.settings,
54
55
  }
55
56
  ]);
56
57
  app.addMenuLink({
@@ -72,22 +73,15 @@ exports.default = {
72
73
  });
73
74
  },
74
75
  bootstrap() { },
75
- async registerTrads({ locales }) {
76
- const importedTrads = await Promise.all(locales.map(locale => {
77
- return Promise.resolve().then(() => __importStar(require(`./translations/${locale}.json`))).then(({ default: data }) => {
78
- return {
79
- data: (0, helper_plugin_1.prefixPluginTranslations)(data, pluginId_1.default),
80
- locale,
81
- };
82
- })
83
- .catch(() => {
84
- return {
85
- data: {},
86
- locale,
87
- };
88
- });
89
- }));
90
- return Promise.resolve(importedTrads);
76
+ registerTrads({ locales = [] }) {
77
+ return locales
78
+ .filter((locale) => Object.keys(translations_1.default).includes(locale))
79
+ .map((locale) => {
80
+ return {
81
+ data: (0, helper_plugin_1.prefixPluginTranslations)((0, lodash_1.get)(translations_1.default, locale, translations_1.default.en), pluginId_1.default, {}),
82
+ locale,
83
+ };
84
+ });
91
85
  },
92
86
  };
93
87
  //# sourceMappingURL=index.js.map
@@ -3,7 +3,7 @@ declare const _default: React.MemoExoticComponent<{
3
3
  children: any;
4
4
  }): JSX.Element;
5
5
  propTypes: {
6
- children: PropTypes.Validator<string | number | boolean | PropTypes.ReactElementLike | PropTypes.ReactNodeArray>;
6
+ children: PropTypes.Validator<NonNullable<PropTypes.ReactNodeLike>>;
7
7
  };
8
8
  }>;
9
9
  export default _default;