strapi-plugin-navigation 2.2.3 → 2.2.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.
- package/README.md +35 -6
- package/admin/src/components/AdditionalFieldInput/index.js +2 -2
- package/admin/src/components/AdditionalFieldInput/types.d.ts +1 -0
- package/admin/src/components/Item/ItemCardHeader/icons.d.ts +1 -1
- package/admin/src/components/Item/ItemCardHeader/icons.js +2 -1
- package/admin/src/components/Item/ItemCardHeader/index.d.ts +1 -0
- package/admin/src/components/Item/ItemCardHeader/index.js +10 -8
- package/admin/src/components/Item/index.js +7 -6
- package/admin/src/components/NavigationItemList/index.d.ts +2 -1
- package/admin/src/components/NavigationItemList/index.js +2 -2
- package/admin/src/hooks/useNavigationManager.d.ts +0 -1
- package/admin/src/index.js +1 -1
- package/admin/src/pages/DataManagerProvider/index.js +2 -0
- package/admin/src/pages/DataManagerProvider/reducer.d.ts +1 -1
- package/admin/src/pages/NoAccessPage/index.d.ts +3 -0
- package/admin/src/pages/NoAccessPage/index.js +31 -0
- package/admin/src/pages/SettingsPage/index.d.ts +0 -1
- package/admin/src/pages/SettingsPage/index.js +9 -0
- package/admin/src/pages/SettingsPage/types.d.ts +1 -1
- package/admin/src/pages/View/components/NavigationHeader/index.d.ts +2 -1
- package/admin/src/pages/View/components/NavigationHeader/index.js +9 -8
- package/admin/src/pages/View/components/NavigationItemForm/index.js +36 -24
- package/admin/src/pages/View/components/NavigationItemForm/types.d.ts +8 -1
- package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupFooter.d.ts +4 -2
- package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupFooter.js +5 -1
- package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupHeader.d.ts +2 -1
- package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupHeader.js +6 -2
- package/admin/src/pages/View/components/NavigationItemPopup/index.d.ts +4 -1
- package/admin/src/pages/View/components/NavigationItemPopup/index.js +5 -3
- package/admin/src/pages/View/components/NavigationManager/AllNavigations/icons.d.ts +0 -1
- package/admin/src/pages/View/components/NavigationManager/AllNavigations/index.d.ts +0 -1
- package/admin/src/pages/View/components/NavigationManager/DeletionConfirm/index.d.ts +0 -1
- package/admin/src/pages/View/components/NavigationManager/ErrorDetails/index.d.ts +0 -1
- package/admin/src/pages/View/components/NavigationManager/Form/index.d.ts +0 -1
- package/admin/src/pages/View/components/NavigationManager/NavigationUpdate/index.d.ts +0 -1
- package/admin/src/pages/View/components/NavigationManager/NewNavigation/index.d.ts +0 -1
- package/admin/src/pages/View/components/NavigationManager/index.d.ts +0 -1
- package/admin/src/pages/View/index.js +40 -20
- package/admin/src/permissions.d.ts +4 -0
- package/admin/src/permissions.js +1 -0
- package/admin/src/translations/en.json +8 -0
- package/package.json +2 -2
- package/permissions.d.ts +1 -0
- package/permissions.js +1 -0
- package/server/bootstrap/index.js +6 -0
- package/server/config/index.js +0 -1
- package/server/config/setupStrategy.js +0 -9
- package/server/content-types/index.d.ts +2 -0
- package/server/content-types/navigation/index.d.ts +1 -0
- package/server/content-types/navigation/schema.d.ts +1 -0
- package/server/content-types/navigation/schema.js +2 -1
- package/server/content-types/navigation-item/index.d.ts +1 -0
- package/server/content-types/navigation-item/schema.d.ts +1 -0
- package/server/content-types/navigation-item/schema.js +2 -1
- package/server/controllers/admin.js +13 -0
- package/server/index.d.ts +2 -0
- package/server/routes/admin.js +10 -0
- package/server/services/admin.js +2 -10
- package/server/services/client.js +10 -14
- package/server/services/common.js +27 -1
- package/strapi-server.d.ts +2 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/types/config.d.ts +0 -1
- package/types/controllers.d.ts +5 -0
- package/types/services.d.ts +1 -0
- package/types/utils.d.ts +5 -0
package/README.md
CHANGED
|
@@ -118,7 +118,7 @@ Complete installation requirements are exact same as for Strapi itself and can b
|
|
|
118
118
|
|
|
119
119
|
**Supported Strapi versions**:
|
|
120
120
|
|
|
121
|
-
- Strapi v4.
|
|
121
|
+
- Strapi v4.9.0 (recently tested)
|
|
122
122
|
- Strapi v4.x
|
|
123
123
|
|
|
124
124
|
> 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).
|
|
@@ -149,6 +149,9 @@ Config for this plugin is stored as a part of the `config/plugins.js` or `config
|
|
|
149
149
|
> *Note v2.0.3 and newer only*
|
|
150
150
|
> 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
|
|
151
151
|
|
|
152
|
+
> *Note for newer than v2.2.0*
|
|
153
|
+
> `slugify` as been removed. **THIS A BREAKING CHANGE**
|
|
154
|
+
|
|
152
155
|
```js
|
|
153
156
|
module.exports = ({ env }) => ({
|
|
154
157
|
// ...
|
|
@@ -160,13 +163,11 @@ Config for this plugin is stored as a part of the `config/plugins.js` or `config
|
|
|
160
163
|
contentTypesNameFields: {
|
|
161
164
|
'api::page.page': ['title']
|
|
162
165
|
},
|
|
166
|
+
pathDefaultFields: {
|
|
167
|
+
'api::page.page': ['slug']
|
|
168
|
+
},
|
|
163
169
|
allowedLevels: 2,
|
|
164
170
|
gql: {...},
|
|
165
|
-
slugify: {
|
|
166
|
-
customReplacements: [
|
|
167
|
-
["🤔", "thinking"],
|
|
168
|
-
],
|
|
169
|
-
}
|
|
170
171
|
}
|
|
171
172
|
}
|
|
172
173
|
});
|
|
@@ -177,6 +178,7 @@ Config for this plugin is stored as a part of the `config/plugins.js` or `config
|
|
|
177
178
|
- `allowedLevels` - Maximum level for which you're able to mark item as "Menu attached"
|
|
178
179
|
- `contentTypes` - UIDs of related content types
|
|
179
180
|
- `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`
|
|
181
|
+
- `pathDefaultFields` - The attribute to copy the default path from per content type. Syntax: `'api::<collection name>.<content type name>': ['url_slug', 'path']`
|
|
180
182
|
- `gql` - If you're using GraphQL that's the right place to put all necessary settings. More **[ here ](#gql-configuration)**
|
|
181
183
|
- `i18nEnabled` - should you want to manage multi-locale content via navigation set this value `Enabled`. More **[ here ](#i18n-internationalization)**
|
|
182
184
|
- `cascadeMenuAttached` - If you don't want "Menu attached" to cascade on child items set this value `Disabled`.
|
|
@@ -632,6 +634,33 @@ module.exports = {
|
|
|
632
634
|
|
|
633
635
|
If you already got it, make sure that `navigation` plugin is inserted before `graphql`. That should do the job.
|
|
634
636
|
|
|
637
|
+
### Slug generation
|
|
638
|
+
|
|
639
|
+
#### Customisation
|
|
640
|
+
|
|
641
|
+
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).
|
|
642
|
+
|
|
643
|
+
For example:
|
|
644
|
+
|
|
645
|
+
```ts
|
|
646
|
+
// path: ./src/index.js
|
|
647
|
+
|
|
648
|
+
module.exports = {
|
|
649
|
+
// ...
|
|
650
|
+
bootstrap({ strapi }) {
|
|
651
|
+
const navigationCommonService = strapi.plugin("navigation").service("common");
|
|
652
|
+
const originalGetSlug = navigationCommonService.getSlug;
|
|
653
|
+
const preprocess = (q) => {
|
|
654
|
+
return q + "suffix";
|
|
655
|
+
};
|
|
656
|
+
|
|
657
|
+
navigationCommonService.getSlug = (query) => {
|
|
658
|
+
return originalGetSlug(preprocess(query));
|
|
659
|
+
};
|
|
660
|
+
},
|
|
661
|
+
};
|
|
662
|
+
```
|
|
663
|
+
|
|
635
664
|
## 🤝 Contributing
|
|
636
665
|
|
|
637
666
|
<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]);
|
|
@@ -5,6 +5,7 @@ export declare type AdditionalFieldInputProps = {
|
|
|
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
11
|
export declare type TargetProp = "value" | "checked";
|
|
@@ -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
|
|
@@ -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
|
|
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(
|
|
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:
|
|
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
|
|
@@ -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);
|
|
@@ -110,7 +111,7 @@ const Item = (props) => {
|
|
|
110
111
|
const { isSingle } = contentType;
|
|
111
112
|
return `/content-manager/${isSingle ? 'singleType' : 'collectionType'}/${entity?.__collectionUid}${!isSingle ? '/' + entity?.id : ''}`;
|
|
112
113
|
};
|
|
113
|
-
const onNewItemClick = (0, react_1.useCallback)((event) => onItemLevelAdd(event, viewId, isNextMenuAllowedLevel, absolutePath, menuAttached, `${structureId}.${items.length}`), [viewId, isNextMenuAllowedLevel, absolutePath, menuAttached, structureId, items]);
|
|
114
|
+
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
115
|
return (react_1.default.createElement(Wrapper_1.default, { level: level, isLast: isLast, style: { opacity: isDragging ? 0.2 : 1 }, ref: refs ? refs.dropRef : null },
|
|
115
116
|
react_1.default.createElement(Card_1.Card, { style: { width: "728px", zIndex: 1, position: "relative", overflow: 'hidden' } },
|
|
116
117
|
removed && (react_1.default.createElement(ItemCardRemovedOverlay_1.ItemCardRemovedOverlay, null)),
|
|
@@ -120,14 +121,14 @@ const Item = (props) => {
|
|
|
120
121
|
...item,
|
|
121
122
|
isMenuAllowedLevel,
|
|
122
123
|
isParentAttachedToMenu,
|
|
123
|
-
}, levelPath, isParentAttachedToMenu), onItemRestore: () => onItemRestore(item), dragRef: refs.dragRef, removed: removed })),
|
|
124
|
+
}, levelPath, isParentAttachedToMenu), onItemRestore: () => onItemRestore(item), dragRef: refs.dragRef, removed: removed, canUpdate: canUpdate })),
|
|
124
125
|
react_1.default.createElement(Divider_1.Divider, null),
|
|
125
126
|
!isExternal && (react_1.default.createElement(Card_1.CardBody, { style: { padding: '8px' } },
|
|
126
127
|
react_1.default.createElement(Flex_1.Flex, { style: { width: '100%' }, direction: "row", alignItems: "center", justifyContent: "space-between" },
|
|
127
128
|
react_1.default.createElement(Flex_1.Flex, null,
|
|
128
129
|
!(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")))),
|
|
130
|
+
canUpdate && (react_1.default.createElement(TextButton_1.TextButton, { disabled: removed, startIcon: react_1.default.createElement(icons_1.Plus, null), onClick: onNewItemClick },
|
|
131
|
+
react_1.default.createElement(Typography_1.Typography, { variant: "pi", fontWeight: "bold", textColor: removed ? "neutral600" : "primary600" }, (0, utils_1.getMessage)("components.navigationItem.action.newItem"))))),
|
|
131
132
|
relatedItemLabel && (react_1.default.createElement(Flex_1.Flex, { justifyContent: 'center', alignItems: 'center' },
|
|
132
133
|
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
134
|
react_1.default.createElement(Typography_1.Typography, { variant: "omega", textColor: 'neutral600' },
|
|
@@ -135,7 +136,7 @@ const Item = (props) => {
|
|
|
135
136
|
"\u00A0/\u00A0"),
|
|
136
137
|
react_1.default.createElement(Typography_1.Typography, { variant: "omega", textColor: 'neutral800' }, relatedItemLabel),
|
|
137
138
|
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
|
+
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
140
|
};
|
|
140
141
|
Item.propTypes = {
|
|
141
142
|
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,6 +15,7 @@ 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 {
|
|
@@ -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,
|
package/admin/src/index.js
CHANGED
|
@@ -50,7 +50,7 @@ exports.default = {
|
|
|
50
50
|
const component = await Promise.resolve().then(() => __importStar(require('./pages/SettingsPage')));
|
|
51
51
|
return component;
|
|
52
52
|
},
|
|
53
|
-
permissions: permissions_1.default.
|
|
53
|
+
permissions: permissions_1.default.settings,
|
|
54
54
|
}
|
|
55
55
|
]);
|
|
56
56
|
app.addMenuLink({
|
|
@@ -287,6 +287,7 @@ const DataManagerProvider = ({ children }) => {
|
|
|
287
287
|
method: "DELETE",
|
|
288
288
|
signal,
|
|
289
289
|
});
|
|
290
|
+
const slugify = (query) => (0, helper_plugin_1.request)(`/${pluginId_1.default}/slug?q=${query}`, { method: "GET", signal });
|
|
290
291
|
const hardReset = () => getDataRef.current();
|
|
291
292
|
return (react_1.default.createElement(DataManagerContext_1.default.Provider, { value: {
|
|
292
293
|
items: passedActiveItems,
|
|
@@ -316,6 +317,7 @@ const DataManagerProvider = ({ children }) => {
|
|
|
316
317
|
readNavigationItemFromLocale,
|
|
317
318
|
handleNavigationsDeletion,
|
|
318
319
|
hardReset,
|
|
320
|
+
slugify,
|
|
319
321
|
} }, isLoading ? react_1.default.createElement(helper_plugin_1.LoadingIndicatorPage, null) : children));
|
|
320
322
|
};
|
|
321
323
|
DataManagerProvider.propTypes = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export default reducer;
|
|
2
|
-
declare function reducer(state: any, action: any): any
|
|
2
|
+
declare function reducer(state: any, action: any): (base?: ((draftState: any) => any) | undefined, ...args: unknown[]) => ((draftState: any) => any) | Promise<(draftState: any) => any>;
|
|
3
3
|
export namespace initialState {
|
|
4
4
|
const items: never[];
|
|
5
5
|
const activeItem: undefined;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const react_1 = __importDefault(require("react"));
|
|
7
|
+
const helper_plugin_1 = require("@strapi/helper-plugin");
|
|
8
|
+
const Main_1 = require("@strapi/design-system/Main");
|
|
9
|
+
const Layout_1 = require("@strapi/design-system/Layout");
|
|
10
|
+
const EmptyStateLayout_1 = require("@strapi/design-system/EmptyStateLayout");
|
|
11
|
+
const icons_1 = require("@strapi/icons");
|
|
12
|
+
const react_intl_1 = require("react-intl");
|
|
13
|
+
const NoAcccessPage = () => {
|
|
14
|
+
const { formatMessage } = (0, react_intl_1.useIntl)();
|
|
15
|
+
(0, helper_plugin_1.useFocusWhenNavigate)();
|
|
16
|
+
return (react_1.default.createElement(Main_1.Main, { labelledBy: "title" },
|
|
17
|
+
react_1.default.createElement(Layout_1.HeaderLayout, { id: "title", title: formatMessage({
|
|
18
|
+
id: 'page.auth.noAccess',
|
|
19
|
+
defaultMessage: 'No access',
|
|
20
|
+
}) }),
|
|
21
|
+
react_1.default.createElement(Layout_1.ContentLayout, null,
|
|
22
|
+
react_1.default.createElement(EmptyStateLayout_1.EmptyStateLayout, { action: react_1.default.createElement(helper_plugin_1.LinkButton, { variant: "secondary", endIcon: react_1.default.createElement(icons_1.ArrowRight, null), to: "/" }, formatMessage({
|
|
23
|
+
id: 'components.notAccessPage.back',
|
|
24
|
+
defaultMessage: 'Back to homepage',
|
|
25
|
+
})), content: formatMessage({
|
|
26
|
+
id: 'page.auth.not.allowed',
|
|
27
|
+
defaultMessage: "Oops! It seems like You do not have access to this page...",
|
|
28
|
+
}), hasRadius: true, icon: react_1.default.createElement(icons_1.EmptyPictures, { width: "10rem" }), shadow: "tableShadow" }))));
|
|
29
|
+
};
|
|
30
|
+
exports.default = NoAcccessPage;
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -55,6 +55,8 @@ const styles_1 = require("../../components/Alert/styles");
|
|
|
55
55
|
const DisableI18nModal_1 = require("./components/DisableI18nModal");
|
|
56
56
|
const CustomFieldModal_1 = __importDefault(require("./components/CustomFieldModal"));
|
|
57
57
|
const CustomFieldTable_1 = __importDefault(require("./components/CustomFieldTable"));
|
|
58
|
+
const permissions_2 = __importDefault(require("../../permissions"));
|
|
59
|
+
const NoAccessPage_1 = __importDefault(require("../NoAccessPage"));
|
|
58
60
|
const RESTART_NOT_REQUIRED = { required: false };
|
|
59
61
|
const RESTART_REQUIRED = { required: true, reasons: [] };
|
|
60
62
|
const RELATION_ATTRIBUTE_TYPES = ['relation', 'media', 'component'];
|
|
@@ -77,6 +79,10 @@ const SettingsPage = () => {
|
|
|
77
79
|
const [contentTypeExpanded, setContentTypeExpanded] = (0, react_1.useState)(undefined);
|
|
78
80
|
const { data: navigationConfigData, isLoading: isConfigLoading, error: configErr, submitMutation, restoreMutation, restartMutation } = (0, useNavigationConfig_1.default)();
|
|
79
81
|
const { data: allContentTypesData, isLoading: isContentTypesLoading, error: contentTypesErr } = (0, useAllContentTypes_1.default)();
|
|
82
|
+
const viewPermissions = (0, react_1.useMemo)(() => ({
|
|
83
|
+
settings: permissions_2.default.settings
|
|
84
|
+
}), []);
|
|
85
|
+
const { isLoading: isLoadingForPermissions, allowedActions: { canManageSettings, }, } = (0, helper_plugin_1.useRBAC)(viewPermissions);
|
|
80
86
|
const isLoading = isConfigLoading || isContentTypesLoading;
|
|
81
87
|
const isError = configErr || contentTypesErr;
|
|
82
88
|
const configContentTypes = navigationConfigData?.contentTypes || [];
|
|
@@ -198,6 +204,9 @@ const SettingsPage = () => {
|
|
|
198
204
|
const filteredFields = customFields.filter(f => f.name !== field.name);
|
|
199
205
|
setCustomFields([...filteredFields, updatedField]);
|
|
200
206
|
};
|
|
207
|
+
if (!(isLoadingForPermissions || canManageSettings)) {
|
|
208
|
+
return (react_1.default.createElement(NoAccessPage_1.default, null));
|
|
209
|
+
}
|
|
201
210
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
202
211
|
react_1.default.createElement(helper_plugin_1.SettingsPageTitle, { name: (0, utils_2.getMessage)('Settings.email.plugin.title', 'Configuration') }),
|
|
203
212
|
react_1.default.createElement(Main_1.Main, { labelledBy: "title" },
|
|
@@ -19,7 +19,7 @@ export declare type StrapiContentTypeSchema = StrapiContentTypeFullSchema & {
|
|
|
19
19
|
export declare type PreparePayload = (payload: {
|
|
20
20
|
form: RawPayload;
|
|
21
21
|
pruneObsoleteI18nNavigations: boolean;
|
|
22
|
-
}) =>
|
|
22
|
+
}) => NavigationPluginConfig;
|
|
23
23
|
export declare type OnSave = Effect<RawPayload>;
|
|
24
24
|
export declare type OnPopupClose = Effect<boolean>;
|
|
25
25
|
export declare type HandleSetContentTypeExpanded = Effect<string | undefined>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export default NavigationHeader;
|
|
2
|
-
declare function NavigationHeader({ activeNavigation, availableNavigations, structureHasErrors, structureHasChanged, handleChangeSelection, handleLocalizationSelection, handleSave, config, }: {
|
|
2
|
+
declare function NavigationHeader({ activeNavigation, availableNavigations, structureHasErrors, structureHasChanged, handleChangeSelection, handleLocalizationSelection, handleSave, config, permissions, }: {
|
|
3
3
|
activeNavigation: any;
|
|
4
4
|
availableNavigations: any;
|
|
5
5
|
structureHasErrors: any;
|
|
@@ -8,5 +8,6 @@ declare function NavigationHeader({ activeNavigation, availableNavigations, stru
|
|
|
8
8
|
handleLocalizationSelection: any;
|
|
9
9
|
handleSave: any;
|
|
10
10
|
config: any;
|
|
11
|
+
permissions?: {} | undefined;
|
|
11
12
|
}): JSX.Element;
|
|
12
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -46,7 +46,7 @@ const pickDefaultLocaleNavigation = ({ activeNavigation, config }) => config.i18
|
|
|
46
46
|
: activeNavigation?.localizations.find(({ localeCode }) => localeCode === config.defaultLocale)
|
|
47
47
|
: null
|
|
48
48
|
: activeNavigation;
|
|
49
|
-
const NavigationHeader = ({ activeNavigation, availableNavigations, structureHasErrors, structureHasChanged, handleChangeSelection, handleLocalizationSelection, handleSave, config, }) => {
|
|
49
|
+
const NavigationHeader = ({ activeNavigation, availableNavigations, structureHasErrors, structureHasChanged, handleChangeSelection, handleLocalizationSelection, handleSave, config, permissions = {}, }) => {
|
|
50
50
|
const { formatMessage } = (0, react_intl_1.useIntl)();
|
|
51
51
|
const allLocaleVersions = (0, react_1.useMemo)(() => activeNavigation?.localizations.length && config.i18nEnabled
|
|
52
52
|
? (0, lodash_1.uniqBy)([activeNavigation, ...(activeNavigation.localizations ?? [])].sort((a, b) => a.localeCode.localeCompare(b.localeCode)), 'id')
|
|
@@ -54,21 +54,22 @@ const NavigationHeader = ({ activeNavigation, availableNavigations, structureHas
|
|
|
54
54
|
const hasLocalizations = config.i18nEnabled && allLocaleVersions.length;
|
|
55
55
|
const passedActiveNavigation = pickDefaultLocaleNavigation({ activeNavigation, config });
|
|
56
56
|
const { closeNavigationManagerModal, openNavigationManagerModal, navigationManagerModal } = (0, useNavigationManager_1.useNavigationManager)();
|
|
57
|
+
const { canUpdate } = permissions;
|
|
57
58
|
return (react_1.default.createElement(Layout_1.HeaderLayout, { primaryAction: react_1.default.createElement(Stack_1.Stack, { horizontal: true, size: 2 },
|
|
58
|
-
react_1.default.createElement(Box_1.Box, {
|
|
59
|
+
react_1.default.createElement(Box_1.Box, { marginRight: "8px" },
|
|
59
60
|
react_1.default.createElement(Grid_1.Grid, { gap: 4 },
|
|
60
61
|
!hasLocalizations ? (react_1.default.createElement(Grid_1.GridItem, { col: 2 })) : null,
|
|
61
|
-
react_1.default.createElement(Grid_1.GridItem, { col: 3 },
|
|
62
|
-
react_1.default.createElement(Button_1.Button, { onClick: openNavigationManagerModal, startIcon: null, type: "button", variant: "secondary", fullWidth: true, size: "S" }, formatMessage((0, translations_1.getTrad)('header.action.manage')))),
|
|
63
|
-
react_1.default.createElement(Grid_1.GridItem, { col: 4 },
|
|
62
|
+
canUpdate && (react_1.default.createElement(Grid_1.GridItem, { col: 3 },
|
|
63
|
+
react_1.default.createElement(Button_1.Button, { onClick: openNavigationManagerModal, startIcon: null, type: "button", variant: "secondary", fullWidth: true, size: "S" }, formatMessage((0, translations_1.getTrad)('header.action.manage'))))),
|
|
64
|
+
react_1.default.createElement(Grid_1.GridItem, { col: canUpdate ? 4 : 10 },
|
|
64
65
|
react_1.default.createElement(Select_1.Select, { type: "select", placeholder: "Change navigation", name: "navigationSelect", onChange: handleChangeSelection, value: passedActiveNavigation?.id, size: "S", style: null }, availableNavigations.map(({ id, name }) => react_1.default.createElement(Select_1.Option, { key: id, value: id }, name)))),
|
|
65
66
|
hasLocalizations
|
|
66
67
|
? react_1.default.createElement(Grid_1.GridItem, { col: 2 },
|
|
67
68
|
react_1.default.createElement(Select_1.Select, { type: "select", placeholder: formatMessage((0, translations_1.getTrad)('pages.main.header.localization.select.placeholder')), name: "navigationLocalizationSelect", onChange: handleLocalizationSelection, value: activeNavigation?.id, size: "S" }, allLocaleVersions.map(({ id, localeCode }) => react_1.default.createElement(Select_1.Option, { key: id, value: id }, localeCode))))
|
|
68
69
|
: null,
|
|
69
|
-
react_1.default.createElement(Grid_1.GridItem, { col: 3 },
|
|
70
|
-
react_1.default.createElement(Button_1.Button, { onClick: handleSave, startIcon: submitIcon, disabled: structureHasErrors || !structureHasChanged, type: "submit", fullWidth: true, size: "S" }, formatMessage((0, translations_1.getTrad)('submit.cta.save')))))),
|
|
71
|
-
navigationManagerModal), title: formatMessage({
|
|
70
|
+
canUpdate && (react_1.default.createElement(Grid_1.GridItem, { col: 3 },
|
|
71
|
+
react_1.default.createElement(Button_1.Button, { onClick: handleSave, startIcon: submitIcon, disabled: structureHasErrors || !structureHasChanged, type: "submit", fullWidth: true, size: "S" }, formatMessage((0, translations_1.getTrad)('submit.cta.save'))))))),
|
|
72
|
+
canUpdate && navigationManagerModal), title: formatMessage({
|
|
72
73
|
id: (0, translations_1.getTrad)('header.title'),
|
|
73
74
|
defaultMessage: 'UI Navigation',
|
|
74
75
|
}), subtitle: formatMessage({
|
|
@@ -28,7 +28,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
const react_1 = __importStar(require("react"));
|
|
30
30
|
const lodash_1 = require("lodash");
|
|
31
|
-
const
|
|
31
|
+
const fp_1 = require("lodash/fp");
|
|
32
32
|
const formik_1 = require("formik");
|
|
33
33
|
const ModalLayout_1 = require("@strapi/design-system/ModalLayout");
|
|
34
34
|
const Select_1 = require("@strapi/design-system/Select");
|
|
@@ -44,17 +44,17 @@ const translations_1 = require("../../../../translations");
|
|
|
44
44
|
const types_1 = require("../../../../../../types");
|
|
45
45
|
const AdditionalFieldInput_1 = __importDefault(require("../../../../components/AdditionalFieldInput"));
|
|
46
46
|
const utils_2 = require("../../../../utils");
|
|
47
|
-
const appendLabelPublicationStatusFallback =
|
|
48
|
-
const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading, inputsPrefix, data, contentTypes = [], contentTypeEntities = [], usedContentTypeEntities = [], availableAudience = [], additionalFields = [], contentTypesNameFields = {}, onSubmit, onCancel, getContentTypeEntities, usedContentTypesData, appendLabelPublicationStatus = appendLabelPublicationStatusFallback, locale, readNavigationItemFromLocale, }) => {
|
|
47
|
+
const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading, inputsPrefix, data, contentTypes = [], contentTypeEntities = [], usedContentTypeEntities = [], availableAudience = [], additionalFields = [], contentTypesNameFields = {}, onSubmit, onCancel, getContentTypeEntities, usedContentTypesData, appendLabelPublicationStatus = appendLabelPublicationStatusFallback, locale, readNavigationItemFromLocale, slugify, permissions = {}, }) => {
|
|
49
48
|
const [isLoading, setIsLoading] = (0, react_1.useState)(isPreloading);
|
|
50
49
|
const [hasBeenInitialized, setInitializedState] = (0, react_1.useState)(false);
|
|
51
50
|
const [hasChanged, setChangedState] = (0, react_1.useState)(false);
|
|
52
51
|
const [contentTypeSearchQuery, setContentTypeSearchQuery] = (0, react_1.useState)(undefined);
|
|
53
52
|
const [contentTypeSearchInputValue, setContentTypeSearchInputValue] = (0, react_1.useState)(undefined);
|
|
53
|
+
const { canUpdate } = permissions;
|
|
54
54
|
const formik = (0, formik_1.useFormik)({
|
|
55
55
|
initialValues: formDefinition.defaultValues,
|
|
56
|
-
onSubmit: (payload) => onSubmit(sanitizePayload(payload, data)),
|
|
57
|
-
validate: (values) => (0, form_1.checkFormValidity)(sanitizePayload(values, {}), formDefinition.schemaFactory(isSingleSelected, additionalFields)),
|
|
56
|
+
onSubmit: loadingAware(async (payload) => onSubmit(await sanitizePayload(slugify, payload, data)), setIsLoading),
|
|
57
|
+
validate: loadingAware(async (values) => (0, form_1.checkFormValidity)(await sanitizePayload(slugify, values, {}), formDefinition.schemaFactory(isSingleSelected, additionalFields)), setIsLoading),
|
|
58
58
|
validateOnChange: false,
|
|
59
59
|
});
|
|
60
60
|
const initialRelatedTypeSelected = (0, lodash_1.get)(data, 'relatedType.value');
|
|
@@ -120,7 +120,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
120
120
|
}, contentTypesNameFields, { contentTypes });
|
|
121
121
|
}
|
|
122
122
|
}, [contentTypeEntities, contentTypesNameFields, contentTypes]);
|
|
123
|
-
const sanitizePayload = (payload, data) => {
|
|
123
|
+
const sanitizePayload = async (slugify, payload, data) => {
|
|
124
124
|
const { related, relatedType, menuAttached, type, ...purePayload } = payload;
|
|
125
125
|
const relatedId = related;
|
|
126
126
|
const singleRelatedItem = isSingleSelected ? (0, lodash_1.first)(contentTypeEntities) : undefined;
|
|
@@ -128,6 +128,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
128
128
|
const title = !!payload.title?.trim()
|
|
129
129
|
? payload.title
|
|
130
130
|
: getDefaultTitle(related, relatedType, isSingleSelected);
|
|
131
|
+
const uiRouterKey = await generateUiRouterKey(slugify, title, relatedId, relatedCollectionType);
|
|
131
132
|
return {
|
|
132
133
|
...data,
|
|
133
134
|
...purePayload,
|
|
@@ -140,7 +141,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
140
141
|
relatedType: type === utils_1.navigationItemType.INTERNAL ? relatedCollectionType : undefined,
|
|
141
142
|
isSingle: isSingleSelected,
|
|
142
143
|
singleRelatedItem,
|
|
143
|
-
uiRouterKey
|
|
144
|
+
uiRouterKey,
|
|
144
145
|
};
|
|
145
146
|
};
|
|
146
147
|
const onChange = ({ name, value }) => {
|
|
@@ -183,17 +184,16 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
183
184
|
value,
|
|
184
185
|
});
|
|
185
186
|
};
|
|
186
|
-
const generateUiRouterKey = (title, related, relatedType) => {
|
|
187
|
-
const { slugify: customSlugifyConfig } = config;
|
|
187
|
+
const generateUiRouterKey = async (slugify, title, related, relatedType) => {
|
|
188
188
|
if (title) {
|
|
189
|
-
return (0, lodash_1.isString)(title) && !(0, lodash_1.isEmpty)(title) ? (0,
|
|
189
|
+
return (0, lodash_1.isString)(title) && !(0, lodash_1.isEmpty)(title) ? await slugify(title).then((0, fp_1.prop)("slug")) : undefined;
|
|
190
190
|
}
|
|
191
191
|
else if (related) {
|
|
192
192
|
const relationTitle = (0, parsers_1.extractRelatedItemLabel)({
|
|
193
193
|
...contentTypeEntities.find(_ => _.id === related),
|
|
194
194
|
__collectionUid: relatedType
|
|
195
195
|
}, contentTypesNameFields, { contentTypes });
|
|
196
|
-
return (0, lodash_1.isString)(relationTitle) && !(0, lodash_1.isEmpty)(relationTitle) ? (0,
|
|
196
|
+
return (0, lodash_1.isString)(relationTitle) && !(0, lodash_1.isEmpty)(relationTitle) ? await slugify(relationTitle).then((0, fp_1.prop)("slug")) : undefined;
|
|
197
197
|
}
|
|
198
198
|
return undefined;
|
|
199
199
|
};
|
|
@@ -236,7 +236,7 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
236
236
|
}), item => item.metadatas.intlLabel.id);
|
|
237
237
|
const isExternal = formik.values.type === utils_1.navigationItemType.EXTERNAL;
|
|
238
238
|
const pathSourceName = isExternal ? 'externalPath' : 'path';
|
|
239
|
-
const submitDisabled = (formik.values.type === utils_1.navigationItemType.INTERNAL && !isSingleSelected && (0, lodash_1.isNil)(formik.values.related));
|
|
239
|
+
const submitDisabled = (formik.values.type === utils_1.navigationItemType.INTERNAL && !isSingleSelected && (0, lodash_1.isNil)(formik.values.related)) || isLoading;
|
|
240
240
|
const debouncedSearch = (0, react_1.useCallback)((0, lodash_1.debounce)(nextValue => setContentTypeSearchQuery(nextValue), 500), []);
|
|
241
241
|
const debounceContentTypeSearchQuery = (value) => {
|
|
242
242
|
setContentTypeSearchInputValue(value);
|
|
@@ -381,20 +381,20 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
381
381
|
react_1.default.createElement(ModalLayout_1.ModalBody, null,
|
|
382
382
|
react_1.default.createElement(Grid_1.Grid, { gap: 5 },
|
|
383
383
|
react_1.default.createElement(Grid_1.GridItem, { key: "title", col: 12 },
|
|
384
|
-
react_1.default.createElement(helper_plugin_1.GenericInput, { autoFocused: true, intlLabel: (0, translations_1.getTrad)('popup.item.form.title.label', 'Title'), name: "title", placeholder: (0, translations_1.getTrad)("e.g. Blog", 'e.g. Blog'), description: (0, translations_1.getTrad)('popup.item.form.title.placeholder', 'e.g. Blog'), type: "text", error: formik.errors.title, onChange: ({ target: { name, value } }) => onChange({ name, value }), value: formik.values.title })),
|
|
384
|
+
react_1.default.createElement(helper_plugin_1.GenericInput, { autoFocused: true, intlLabel: (0, translations_1.getTrad)('popup.item.form.title.label', 'Title'), name: "title", placeholder: (0, translations_1.getTrad)("e.g. Blog", 'e.g. Blog'), description: (0, translations_1.getTrad)('popup.item.form.title.placeholder', 'e.g. Blog'), type: "text", disabled: !canUpdate, error: formik.errors.title, onChange: ({ target: { name, value } }) => onChange({ name, value }), value: formik.values.title })),
|
|
385
385
|
react_1.default.createElement(Grid_1.GridItem, { key: "type", col: 4, lg: 12 },
|
|
386
|
-
react_1.default.createElement(helper_plugin_1.GenericInput, { intlLabel: (0, translations_1.getTrad)('popup.item.form.type.label', 'Internal link'), name: "type", options: navigationItemTypeOptions, type: "select", error: formik.errors.type, onChange: ({ target: { name, value } }) => onChange({ name, value }), value: formik.values.type })),
|
|
386
|
+
react_1.default.createElement(helper_plugin_1.GenericInput, { intlLabel: (0, translations_1.getTrad)('popup.item.form.type.label', 'Internal link'), name: "type", options: navigationItemTypeOptions, type: "select", disabled: !canUpdate, error: formik.errors.type, onChange: ({ target: { name, value } }) => onChange({ name, value }), value: formik.values.type })),
|
|
387
387
|
react_1.default.createElement(Grid_1.GridItem, { key: "menuAttached", col: 4, lg: 12 },
|
|
388
|
-
react_1.default.createElement(helper_plugin_1.GenericInput, { intlLabel: (0, translations_1.getTrad)('popup.item.form.menuAttached.label', 'MenuAttached'), name: "menuAttached", type: "bool", error: formik.errors.menuAttached, onChange: ({ target: { name, value } }) => onChange({ name, value }), value: formik.values.menuAttached, disabled: config.cascadeMenuAttached ? !(data.isMenuAllowedLevel && data.parentAttachedToMenu) : false })),
|
|
388
|
+
react_1.default.createElement(helper_plugin_1.GenericInput, { intlLabel: (0, translations_1.getTrad)('popup.item.form.menuAttached.label', 'MenuAttached'), name: "menuAttached", type: "bool", error: formik.errors.menuAttached, onChange: ({ target: { name, value } }) => onChange({ name, value }), value: formik.values.menuAttached, disabled: !canUpdate || (config.cascadeMenuAttached ? !(data.isMenuAllowedLevel && data.parentAttachedToMenu) : false) })),
|
|
389
389
|
react_1.default.createElement(Grid_1.GridItem, { key: "path", col: 12 },
|
|
390
|
-
react_1.default.createElement(helper_plugin_1.GenericInput, { intlLabel: (0, translations_1.getTrad)(`popup.item.form.${pathSourceName}.label`, 'Path'), name: pathSourceName, placeholder: (0, translations_1.getTrad)(`popup.item.form.${pathSourceName}.placeholder`, 'e.g. Blog'), type: "text", error: formik.errors[pathSourceName], onChange: ({ target: { name, value } }) => onChange({ name, value }), value: formik.values[pathSourceName], description: generatePreviewPath() })),
|
|
390
|
+
react_1.default.createElement(helper_plugin_1.GenericInput, { intlLabel: (0, translations_1.getTrad)(`popup.item.form.${pathSourceName}.label`, 'Path'), name: pathSourceName, placeholder: (0, translations_1.getTrad)(`popup.item.form.${pathSourceName}.placeholder`, 'e.g. Blog'), type: "text", disabled: !canUpdate, error: formik.errors[pathSourceName], onChange: ({ target: { name, value } }) => onChange({ name, value }), value: formik.values[pathSourceName], description: generatePreviewPath() })),
|
|
391
391
|
formik.values.type === utils_1.navigationItemType.INTERNAL && (react_1.default.createElement(react_1.default.Fragment, null,
|
|
392
392
|
react_1.default.createElement(Grid_1.GridItem, { col: 6, lg: 12 },
|
|
393
|
-
react_1.default.createElement(helper_plugin_1.GenericInput, { type: "select", intlLabel: (0, translations_1.getTrad)('popup.item.form.relatedType.label', 'Related Type'), placeholder: (0, translations_1.getTrad)('popup.item.form.relatedType.placeholder', 'Related Type'), name: "relatedType", error: formik.errors.relatedType, onChange: onChangeRelatedType, options: relatedTypeSelectOptions, value: formik.values.relatedType, disabled: isLoading || (0, lodash_1.isEmpty)(relatedTypeSelectOptions), description: !isLoading && (0, lodash_1.isEmpty)(relatedTypeSelectOptions)
|
|
393
|
+
react_1.default.createElement(helper_plugin_1.GenericInput, { type: "select", intlLabel: (0, translations_1.getTrad)('popup.item.form.relatedType.label', 'Related Type'), placeholder: (0, translations_1.getTrad)('popup.item.form.relatedType.placeholder', 'Related Type'), name: "relatedType", error: formik.errors.relatedType, onChange: onChangeRelatedType, options: relatedTypeSelectOptions, value: formik.values.relatedType, disabled: isLoading || (0, lodash_1.isEmpty)(relatedTypeSelectOptions) || !canUpdate, description: !isLoading && (0, lodash_1.isEmpty)(relatedTypeSelectOptions)
|
|
394
394
|
? (0, translations_1.getTrad)('popup.item.form.relatedType.empty', 'There are no more content types')
|
|
395
395
|
: undefined })),
|
|
396
396
|
formik.values.relatedType && !isSingleSelected && (react_1.default.createElement(Grid_1.GridItem, { col: 6, lg: 12 },
|
|
397
|
-
react_1.default.createElement(helper_plugin_1.GenericInput, { type: "select", intlLabel: (0, translations_1.getTrad)('popup.item.form.related.label', 'Related'), placeholder: (0, translations_1.getTrad)('popup.item.form.related.label', 'Related'), name: "related", error: formik.errors.related, onChange: ({ target: { name, value } }) => onChange({ name, value }), onInputChange: debounceContentTypeSearchQuery, inputValue: contentTypeSearchInputValue, options: relatedSelectOptions, value: formik.values.related, disabled: isLoading || thereAreNoMoreContentTypes, description: !isLoading && thereAreNoMoreContentTypes
|
|
397
|
+
react_1.default.createElement(helper_plugin_1.GenericInput, { type: "select", intlLabel: (0, translations_1.getTrad)('popup.item.form.related.label', 'Related'), placeholder: (0, translations_1.getTrad)('popup.item.form.related.label', 'Related'), name: "related", error: formik.errors.related, onChange: ({ target: { name, value } }) => onChange({ name, value }), onInputChange: debounceContentTypeSearchQuery, inputValue: contentTypeSearchInputValue, options: relatedSelectOptions, value: formik.values.related, disabled: isLoading || thereAreNoMoreContentTypes || !canUpdate, description: !isLoading && thereAreNoMoreContentTypes
|
|
398
398
|
? {
|
|
399
399
|
id: (0, translations_1.getTradId)('popup.item.form.related.empty'),
|
|
400
400
|
defaultMessage: 'There are no more entities',
|
|
@@ -406,19 +406,31 @@ const NavigationItemForm = ({ config, availableLocale, isLoading: isPreloading,
|
|
|
406
406
|
return (react_1.default.createElement(Grid_1.GridItem, { key: "audience", col: 6, lg: 12 },
|
|
407
407
|
react_1.default.createElement(Select_1.Select, { id: "audience", placeholder: (0, utils_2.getMessage)('popup.item.form.audience.placeholder'), label: (0, utils_2.getMessage)('popup.item.form.audience.label'), onChange: onAudienceChange, value: formik.values.audience, hint: !isLoading && (0, lodash_1.isEmpty)(audienceOptions)
|
|
408
408
|
? (0, utils_2.getMessage)('popup.item.form.audience.empty', 'There are no more audiences')
|
|
409
|
-
: undefined, multi: true, withTags: true, disabled: (0, lodash_1.isEmpty)(audienceOptions) }, audienceOptions.map(({ value, label }) => react_1.default.createElement(Select_1.Option, { key: value, value: value }, label)))));
|
|
409
|
+
: undefined, multi: true, withTags: true, disabled: (0, lodash_1.isEmpty)(audienceOptions) || !canUpdate }, audienceOptions.map(({ value, label }) => react_1.default.createElement(Select_1.Option, { key: value, value: value }, label)))));
|
|
410
410
|
}
|
|
411
411
|
else {
|
|
412
412
|
return (react_1.default.createElement(Grid_1.GridItem, { key: additionalField.name, col: 6, lg: 12 },
|
|
413
|
-
react_1.default.createElement(AdditionalFieldInput_1.default, { field: additionalField, isLoading: isLoading, onChange: onAdditionalFieldChange, value: (0, lodash_1.get)(formik.values, `additionalFields.${additionalField.name}`, null), error: (0, lodash_1.get)(formik.errors, `additionalFields.${additionalField.name}`, null) })));
|
|
413
|
+
react_1.default.createElement(AdditionalFieldInput_1.default, { field: additionalField, isLoading: isLoading, onChange: onAdditionalFieldChange, value: (0, lodash_1.get)(formik.values, `additionalFields.${additionalField.name}`, null), disabled: !canUpdate, error: (0, lodash_1.get)(formik.errors, `additionalFields.${additionalField.name}`, null) })));
|
|
414
414
|
}
|
|
415
415
|
})),
|
|
416
416
|
isI18nBootstrapAvailable ? (react_1.default.createElement(Grid_1.Grid, { gap: 5, paddingTop: 5 },
|
|
417
417
|
react_1.default.createElement(Grid_1.GridItem, { col: 6, lg: 12 },
|
|
418
|
-
react_1.default.createElement(helper_plugin_1.GenericInput, { ...itemCopyProps, type: "select", name: itemLocaleCopyField, error: (0, lodash_1.get)(formik.errors, itemLocaleCopyField), onChange: onChangeLocaleCopy, options: availableLocaleOptions, value: itemLocaleCopyValue, disabled: isLoading })),
|
|
419
|
-
react_1.default.createElement(Grid_1.GridItem, { col: 6, lg: 12, paddingTop: 6 },
|
|
420
|
-
react_1.default.createElement(Button_1.Button, { variant: "tertiary", onClick: onCopyFromLocale, disabled: isLoading || !itemLocaleCopyValue }, (0, utils_2.getMessage)('popup.item.form.i18n.locale.button'))))) : null)),
|
|
421
|
-
react_1.default.createElement(NavigationItemPopupFooter_1.NavigationItemPopupFooter, { handleSubmit: formik.handleSubmit, handleCancel: onCancel, submitDisabled: submitDisabled })));
|
|
418
|
+
react_1.default.createElement(helper_plugin_1.GenericInput, { ...itemCopyProps, type: "select", name: itemLocaleCopyField, error: (0, lodash_1.get)(formik.errors, itemLocaleCopyField), onChange: onChangeLocaleCopy, options: availableLocaleOptions, value: itemLocaleCopyValue, disabled: isLoading || !canUpdate })),
|
|
419
|
+
canUpdate && (react_1.default.createElement(Grid_1.GridItem, { col: 6, lg: 12, paddingTop: 6 },
|
|
420
|
+
react_1.default.createElement(Button_1.Button, { variant: "tertiary", onClick: onCopyFromLocale, disabled: isLoading || !itemLocaleCopyValue }, (0, utils_2.getMessage)('popup.item.form.i18n.locale.button')))))) : null)),
|
|
421
|
+
react_1.default.createElement(NavigationItemPopupFooter_1.NavigationItemPopupFooter, { handleSubmit: formik.handleSubmit, handleCancel: onCancel, submitDisabled: submitDisabled, canUpdate: canUpdate })));
|
|
422
|
+
};
|
|
423
|
+
const appendLabelPublicationStatusFallback = () => "";
|
|
424
|
+
const loadingAware = (action, isLoading) => async (input) => {
|
|
425
|
+
try {
|
|
426
|
+
isLoading(true);
|
|
427
|
+
return await action(input);
|
|
428
|
+
}
|
|
429
|
+
catch (_) {
|
|
430
|
+
}
|
|
431
|
+
finally {
|
|
432
|
+
isLoading(false);
|
|
433
|
+
}
|
|
422
434
|
};
|
|
423
435
|
exports.default = NavigationItemForm;
|
|
424
436
|
//# sourceMappingURL=index.js.map
|