strapi-plugin-navigation 2.0.8 → 2.0.11
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/admin/src/components/Item/index.js +15 -7
- package/admin/src/pages/DataManagerProvider/index.js +6 -6
- package/admin/src/pages/SettingsPage/index.js +6 -2
- package/admin/src/pages/SettingsPage/utils/functions.js +30 -0
- package/admin/src/pages/View/components/NavigationItemForm/index.js +13 -6
- package/admin/src/pages/View/utils/parsers.js +8 -5
- package/admin/src/translations/en.json +2 -2
- package/package.json +1 -1
- package/server/controllers/navigation.js +11 -3
- package/server/graphql/types/navigation-related.js +3 -1
- package/server/services/navigation.js +33 -39
- package/server/services/utils/constant.js +10 -1
- package/server/services/utils/functions.js +7 -1
|
@@ -55,7 +55,8 @@ const Item = (props) => {
|
|
|
55
55
|
const { contentTypes, contentTypesNameFields } = config;
|
|
56
56
|
const isExternal = type === navigationItemType.EXTERNAL;
|
|
57
57
|
const isWrapper = type === navigationItemType.WRAPPER;
|
|
58
|
-
const
|
|
58
|
+
const isHandledByPublishFlow = relatedRef && typeof relatedRef.publishedAt !== 'undefined';
|
|
59
|
+
const isPublished = isHandledByPublishFlow && relatedRef.publishedAt;
|
|
59
60
|
const isNextMenuAllowedLevel = isNumber(allowedLevels) ? level < (allowedLevels - 1) : true;
|
|
60
61
|
const isMenuAllowedLevel = isNumber(allowedLevels) ? level < allowedLevels : true;
|
|
61
62
|
const hasChildren = !isEmpty(item.items) && !isExternal && !displayChildren;
|
|
@@ -121,6 +122,13 @@ const Item = (props) => {
|
|
|
121
122
|
previewRef: dragPreview(previewRef),
|
|
122
123
|
}
|
|
123
124
|
|
|
125
|
+
const contentTypeUid = relatedRef?.__collectionUid;
|
|
126
|
+
const contentType = contentTypes.find(_ => _.uid === contentTypeUid) || {};
|
|
127
|
+
const generatePreviewUrl = entity => {
|
|
128
|
+
const { isSingle } = contentType;
|
|
129
|
+
return `/content-manager/${ isSingle ? 'singleType' : 'collectionType'}/${entity?.__collectionUid}${!isSingle ? '/' + entity?.id : ''}`
|
|
130
|
+
}
|
|
131
|
+
|
|
124
132
|
return (
|
|
125
133
|
<Wrapper level={level} isLast={isLast} style={{ opacity: isDragging ? 0.2 : 1 }} ref={refs ? refs.dropRef : null} >
|
|
126
134
|
<Card style={{ width: "728px", zIndex: 1, position: "relative", overflow: 'hidden' }}>
|
|
@@ -167,20 +175,20 @@ const Item = (props) => {
|
|
|
167
175
|
</Flex>
|
|
168
176
|
{relatedItemLabel && (
|
|
169
177
|
<Flex justifyContent='center' alignItems='center'>
|
|
170
|
-
<ItemCardBadge
|
|
178
|
+
{isHandledByPublishFlow && <ItemCardBadge
|
|
171
179
|
borderColor={`${relatedBadgeColor}200`}
|
|
172
180
|
backgroundColor={`${relatedBadgeColor}100`}
|
|
173
181
|
textColor={`${relatedBadgeColor}600`}
|
|
174
182
|
className="action"
|
|
175
183
|
small
|
|
176
184
|
>
|
|
177
|
-
{getMessage({id: `components.navigationItem.badge.${isPublished ? 'published' : 'draft'}`})}
|
|
178
|
-
</ItemCardBadge>
|
|
185
|
+
{getMessage({ id: `components.navigationItem.badge.${isPublished ? 'published' : 'draft'}` })}
|
|
186
|
+
</ItemCardBadge>}
|
|
179
187
|
<Typography variant="omega" textColor='neutral600'>{relatedTypeLabel} / </Typography>
|
|
180
188
|
<Typography variant="omega" textColor='neutral800'>{relatedItemLabel}</Typography>
|
|
181
|
-
|
|
182
|
-
to={
|
|
183
|
-
endIcon={<ArrowRight />}> </Link>
|
|
189
|
+
{ contentType?.visible && (<Link
|
|
190
|
+
to={generatePreviewUrl(relatedRef)}
|
|
191
|
+
endIcon={<ArrowRight />}> </Link>) }
|
|
184
192
|
</Flex>)
|
|
185
193
|
}
|
|
186
194
|
</Flex>
|
|
@@ -94,8 +94,8 @@ const DataManagerProvider = ({ children }) => {
|
|
|
94
94
|
} catch (err) {
|
|
95
95
|
console.error({ err });
|
|
96
96
|
toggleNotification({
|
|
97
|
-
type: '
|
|
98
|
-
message: { id: 'notification.error' },
|
|
97
|
+
type: 'warning',
|
|
98
|
+
message: { id: getTrad('notification.error') },
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
101
|
};
|
|
@@ -133,8 +133,8 @@ const DataManagerProvider = ({ children }) => {
|
|
|
133
133
|
} catch (err) {
|
|
134
134
|
console.error({ err });
|
|
135
135
|
toggleNotification({
|
|
136
|
-
type: '
|
|
137
|
-
message: { id: 'notification.error' },
|
|
136
|
+
type: 'warning',
|
|
137
|
+
message: { id: getTrad('notification.error') },
|
|
138
138
|
});
|
|
139
139
|
}
|
|
140
140
|
};
|
|
@@ -254,7 +254,7 @@ const DataManagerProvider = ({ children }) => {
|
|
|
254
254
|
|
|
255
255
|
if (err.response.payload.data && err.response.payload.data.errorTitles) {
|
|
256
256
|
return toggleNotification({
|
|
257
|
-
type: '
|
|
257
|
+
type: 'warning',
|
|
258
258
|
message: {
|
|
259
259
|
id: formatMessage(
|
|
260
260
|
getTrad('notification.navigation.error'),
|
|
@@ -264,7 +264,7 @@ const DataManagerProvider = ({ children }) => {
|
|
|
264
264
|
});
|
|
265
265
|
}
|
|
266
266
|
toggleNotification({
|
|
267
|
-
type: '
|
|
267
|
+
type: 'warning',
|
|
268
268
|
message: { id: getTrad('notification.error') },
|
|
269
269
|
});
|
|
270
270
|
}
|
|
@@ -31,6 +31,7 @@ import { navigationItemAdditionalFields } from '../View/utils/enums';
|
|
|
31
31
|
import ConfirmationDialog from '../../components/ConfirmationDialog';
|
|
32
32
|
import RestartAlert from '../../components/RestartAlert';
|
|
33
33
|
import { getMessage } from '../../utils';
|
|
34
|
+
import { isContentTypeEligible, resolveGlobalLikeId } from './utils/functions';
|
|
34
35
|
|
|
35
36
|
const SettingsPage = () => {
|
|
36
37
|
const { lockApp, unlockApp } = useOverlayBlocker();
|
|
@@ -56,7 +57,7 @@ const SettingsPage = () => {
|
|
|
56
57
|
additionalFields: audienceFieldChecked ? [navigationItemAdditionalFields.AUDIENCE] : [],
|
|
57
58
|
allowedLevels: allowedLevels,
|
|
58
59
|
gql: {
|
|
59
|
-
navigationItemRelated: selectedContentTypes.map(uid =>
|
|
60
|
+
navigationItemRelated: selectedContentTypes.map(uid => resolveGlobalLikeId(uid)),
|
|
60
61
|
}
|
|
61
62
|
});
|
|
62
63
|
|
|
@@ -108,7 +109,10 @@ const SettingsPage = () => {
|
|
|
108
109
|
)
|
|
109
110
|
}
|
|
110
111
|
|
|
111
|
-
const allContentTypes = !isLoading && Object.values(allContentTypesData).filter(
|
|
112
|
+
const allContentTypes = !isLoading && Object.values(allContentTypesData).filter(({ uid }) => isContentTypeEligible(uid, {
|
|
113
|
+
allowedContentTypes: navigationConfigData?.allowedContentTypes,
|
|
114
|
+
restrictedContentTypes: navigationConfigData?.restrictedContentTypes,
|
|
115
|
+
}));
|
|
112
116
|
const selectedContentTypes = navigationConfigData?.contentTypes.map(item => item.uid);
|
|
113
117
|
const audienceFieldChecked = navigationConfigData?.additionalFields.includes(navigationItemAdditionalFields.AUDIENCE);
|
|
114
118
|
const allowedLevels = navigationConfigData?.allowedLevels || 2;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { capitalize } = require("lodash");
|
|
4
|
+
|
|
5
|
+
const UID_REGEX = /^(?<type>[a-z0-9-]+)\:{2}(?<api>[a-z0-9-]+)\.{1}(?<contentType>[a-z0-9-]+)$/i;
|
|
6
|
+
|
|
7
|
+
const splitTypeUid = (uid = '') => {
|
|
8
|
+
return uid.split(UID_REGEX).filter((s) => s && s.length > 0);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
resolveGlobalLikeId(uid = '') {
|
|
13
|
+
const parse = (str) => str.split('-')
|
|
14
|
+
.map(_ => capitalize(_))
|
|
15
|
+
.join('');
|
|
16
|
+
|
|
17
|
+
const [type, scope, contentTypeName] = splitTypeUid(uid);
|
|
18
|
+
if (type === 'api') {
|
|
19
|
+
return parse(contentTypeName);
|
|
20
|
+
}
|
|
21
|
+
return `${parse(scope)}${parse(contentTypeName)}`;
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
isContentTypeEligible(uid = '', config = {}) {
|
|
25
|
+
const { allowedContentTypes = [], restrictedContentTypes = []} = config;
|
|
26
|
+
const isOneOfAllowedType = allowedContentTypes.filter(_ => uid.includes(_) || (uid === _)).length > 0;
|
|
27
|
+
const isNoneOfRestricted = restrictedContentTypes.filter(_ => uid.includes(_) || (uid === _)).length === 0;
|
|
28
|
+
return uid && isOneOfAllowedType && isNoneOfRestricted;
|
|
29
|
+
},
|
|
30
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useMemo, useState, useCallback } from 'react';
|
|
2
|
-
import { debounce, find, get, isEmpty, isEqual, isNil, isString } from 'lodash';
|
|
2
|
+
import { debounce, find, get, first, isEmpty, isEqual, isNil, isString } from 'lodash';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import { Formik } from 'formik'
|
|
5
5
|
import slugify from 'slugify';
|
|
@@ -75,9 +75,11 @@ const NavigationItemForm = ({
|
|
|
75
75
|
|
|
76
76
|
const sanitizePayload = (payload = {}) => {
|
|
77
77
|
const { onItemClick, onItemLevelAddClick, related, relatedType, menuAttached, type, ...purePayload } = payload;
|
|
78
|
-
const relatedId = related
|
|
78
|
+
const relatedId = related;
|
|
79
|
+
const singleRelatedItem = isSingleSelected ? first(contentTypeEntities) : undefined;
|
|
79
80
|
const relatedCollectionType = relatedType;
|
|
80
|
-
const title = payload.title
|
|
81
|
+
const title = payload.title;
|
|
82
|
+
|
|
81
83
|
return {
|
|
82
84
|
...purePayload,
|
|
83
85
|
title,
|
|
@@ -88,7 +90,8 @@ const NavigationItemForm = ({
|
|
|
88
90
|
related: type === navigationItemType.INTERNAL ? relatedId : undefined,
|
|
89
91
|
relatedType: type === navigationItemType.INTERNAL ? relatedCollectionType : undefined,
|
|
90
92
|
isSingle: isSingleSelected,
|
|
91
|
-
|
|
93
|
+
singleRelatedItem,
|
|
94
|
+
uiRouterKey: generateUiRouterKey(title, relatedId, relatedCollectionType),
|
|
92
95
|
};
|
|
93
96
|
};
|
|
94
97
|
|
|
@@ -134,6 +137,7 @@ const NavigationItemForm = ({
|
|
|
134
137
|
return undefined;
|
|
135
138
|
};
|
|
136
139
|
|
|
140
|
+
const initialRelatedTypeSelected = data?.relatedType?.value;
|
|
137
141
|
const relatedTypeSelectValue = form.relatedType;
|
|
138
142
|
const relatedSelectValue = form.related;
|
|
139
143
|
|
|
@@ -219,6 +223,9 @@ const NavigationItemForm = ({
|
|
|
219
223
|
() => contentTypes
|
|
220
224
|
.filter((contentType) => {
|
|
221
225
|
if (contentType.isSingle) {
|
|
226
|
+
if (relatedTypeSelectValue && [relatedTypeSelectValue, initialRelatedTypeSelected].includes(contentType.uid)) {
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
222
229
|
return !usedContentTypesData.some((_) => _.__collectionUid === contentType.uid && _.__collectionUid !== form.relatedType);
|
|
223
230
|
}
|
|
224
231
|
return true;
|
|
@@ -232,9 +239,9 @@ const NavigationItemForm = ({
|
|
|
232
239
|
}
|
|
233
240
|
},
|
|
234
241
|
value: get(item, 'uid'),
|
|
235
|
-
label:
|
|
242
|
+
label: get(item, 'label', get(item, 'name')),
|
|
236
243
|
})),
|
|
237
|
-
[contentTypes, usedContentTypesData],
|
|
244
|
+
[contentTypes, usedContentTypesData, relatedTypeSelectValue],
|
|
238
245
|
);
|
|
239
246
|
|
|
240
247
|
const thereAreNoMoreContentTypes = isEmpty(relatedSelectOptions) && !contentTypeSearchQuery;
|
|
@@ -89,10 +89,12 @@ const linkRelations = (item, config) => {
|
|
|
89
89
|
|
|
90
90
|
if (isSingle && relatedType) {
|
|
91
91
|
const relatedContentType = contentTypes.find(_ => relatedType === _.uid) || {};
|
|
92
|
+
const { singleRelatedItem = {} } = item;
|
|
92
93
|
return {
|
|
93
94
|
...item,
|
|
94
95
|
relatedType,
|
|
95
96
|
relatedRef: {
|
|
97
|
+
...singleRelatedItem,
|
|
96
98
|
...omit(relatedContentType, 'collectionName'),
|
|
97
99
|
isSingle,
|
|
98
100
|
__collectionUid: relatedContentType.uid,
|
|
@@ -122,7 +124,7 @@ const linkRelations = (item, config) => {
|
|
|
122
124
|
|
|
123
125
|
const shouldFindRelated = (isNumber(related) || isUuid(related) || isString(related)) && !relatedRef;
|
|
124
126
|
const shouldBuildRelated = !relatedRef || (relatedRef && (relatedRef.id !== relatedId));
|
|
125
|
-
|
|
127
|
+
|
|
126
128
|
if (shouldBuildRelated && !shouldFindRelated) {
|
|
127
129
|
const relatedContentType = find(contentTypes,
|
|
128
130
|
ct => ct.uid === relatedItem.__contentType, {});
|
|
@@ -295,9 +297,10 @@ export const isRelationPublished = ({ relatedRef, relatedType = {}, type, isColl
|
|
|
295
297
|
|
|
296
298
|
export const validateNavigationStructure = (items = []) =>
|
|
297
299
|
items.map(item =>
|
|
298
|
-
(
|
|
299
|
-
|
|
300
|
-
type: item.type
|
|
301
|
-
|
|
300
|
+
(
|
|
301
|
+
item.removed ||
|
|
302
|
+
isRelationCorrect({ related: item.related, type: item.type }) ||
|
|
303
|
+
(item.isSingle && isRelationCorrect({ related: item.relatedType, type: item.type }))
|
|
304
|
+
) &&
|
|
302
305
|
validateNavigationStructure(item.items)
|
|
303
306
|
).filter(item => !item).length === 0;
|
|
@@ -74,9 +74,9 @@
|
|
|
74
74
|
"pages.settings.notification.submit.error": "Config update has failed",
|
|
75
75
|
"pages.settings.notification.restore.error": "Config restore has failed",
|
|
76
76
|
"pages.settings.notification.restart.error": "Failed to restart your application. Try to do it manually.",
|
|
77
|
-
"pages.settings.form.contentTypes.label": "Enable for
|
|
77
|
+
"pages.settings.form.contentTypes.label": "Enable navigation for",
|
|
78
78
|
"pages.settings.form.contentTypes.placeholder": "eg. Pages, Posts",
|
|
79
|
-
"pages.settings.form.contentTypes.hint": "
|
|
79
|
+
"pages.settings.form.contentTypes.hint": "If none is selected, also none of the content types are enabled",
|
|
80
80
|
"pages.settings.form.allowedLevels.label": "Allowed levels",
|
|
81
81
|
"pages.settings.form.allowedLevels.placeholder": "eg. 2",
|
|
82
82
|
"pages.settings.form.allowedLevels.hint": "Maximum level for which you're able to mark item as \"Menu attached\"",
|
package/package.json
CHANGED
|
@@ -25,12 +25,20 @@ module.exports = ({strapi}) => ({
|
|
|
25
25
|
},
|
|
26
26
|
|
|
27
27
|
async updateConfig(ctx) {
|
|
28
|
-
|
|
28
|
+
try {
|
|
29
|
+
await getService().updateConfig(ctx.request.body);
|
|
30
|
+
} catch (e) {
|
|
31
|
+
errorHandler(ctx)(e);
|
|
32
|
+
}
|
|
29
33
|
return ctx.send({ status: 200 });
|
|
30
34
|
},
|
|
31
35
|
|
|
32
36
|
async restoreConfig(ctx) {
|
|
33
|
-
|
|
37
|
+
try {
|
|
38
|
+
await getService().restoreConfig();
|
|
39
|
+
} catch (e) {
|
|
40
|
+
errorHandler(ctx)(e);
|
|
41
|
+
}
|
|
34
42
|
return ctx.send({ status: 200 })
|
|
35
43
|
},
|
|
36
44
|
|
|
@@ -43,7 +51,7 @@ module.exports = ({strapi}) => ({
|
|
|
43
51
|
await getService().restart();
|
|
44
52
|
return ctx.send({ status: 200 });
|
|
45
53
|
} catch (e) {
|
|
46
|
-
errorHandler(ctx
|
|
54
|
+
errorHandler(ctx)(e);
|
|
47
55
|
}
|
|
48
56
|
},
|
|
49
57
|
|
|
@@ -8,7 +8,9 @@ module.exports = ({ strapi, nexus, config }) => {
|
|
|
8
8
|
definition(t) {
|
|
9
9
|
t.members(...related)
|
|
10
10
|
},
|
|
11
|
-
resolveType: (item) =>
|
|
11
|
+
resolveType: (item) => {
|
|
12
|
+
return strapi.contentTypes[item.__contentType]?.globalId
|
|
13
|
+
}
|
|
12
14
|
});
|
|
13
15
|
}
|
|
14
16
|
|
|
@@ -11,16 +11,14 @@ const {
|
|
|
11
11
|
toNumber,
|
|
12
12
|
isString,
|
|
13
13
|
first,
|
|
14
|
-
|
|
15
14
|
} = require('lodash');
|
|
16
15
|
const { validate: isUuid } = require('uuid');
|
|
17
16
|
const slugify = require('slugify');
|
|
18
|
-
const { KIND_TYPES } = require('./utils/constant');
|
|
17
|
+
const { KIND_TYPES, ALLOWED_CONTENT_TYPES, RESTRICTED_CONTENT_TYPES } = require('./utils/constant');
|
|
19
18
|
const utilsFunctionsFactory = require('./utils/functions');
|
|
20
19
|
const { renderType } = require('../content-types/navigation/lifecycle');
|
|
21
20
|
const { type: itemType, additionalFields: configAdditionalFields } = require('../content-types/navigation-item').lifecycle;
|
|
22
21
|
const { NotFoundError } = require('@strapi/utils').errors
|
|
23
|
-
const excludedContentTypes = ['strapi::'];
|
|
24
22
|
const contentTypesNameFieldsDefaults = ['title', 'subject', 'name'];
|
|
25
23
|
|
|
26
24
|
module.exports = ({ strapi }) => {
|
|
@@ -33,9 +31,7 @@ module.exports = ({ strapi }) => {
|
|
|
33
31
|
const entities = await strapi
|
|
34
32
|
.query(masterModel.uid)
|
|
35
33
|
.findMany({
|
|
36
|
-
|
|
37
|
-
limit: -1,
|
|
38
|
-
}
|
|
34
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
39
35
|
});
|
|
40
36
|
return entities;
|
|
41
37
|
},
|
|
@@ -52,9 +48,7 @@ module.exports = ({ strapi }) => {
|
|
|
52
48
|
where: {
|
|
53
49
|
master: id,
|
|
54
50
|
},
|
|
55
|
-
|
|
56
|
-
limit: -1,
|
|
57
|
-
},
|
|
51
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
58
52
|
sort: ['order:asc'],
|
|
59
53
|
populate: ['related', 'parent', 'audience']
|
|
60
54
|
});
|
|
@@ -71,8 +65,8 @@ module.exports = ({ strapi }) => {
|
|
|
71
65
|
|
|
72
66
|
// Get plugin config
|
|
73
67
|
async config(viaSettingsPage = false) {
|
|
74
|
-
const { audienceModel
|
|
75
|
-
const pluginStore = await
|
|
68
|
+
const { audienceModel } = utilsFunctions.extractMeta(strapi.plugins);
|
|
69
|
+
const pluginStore = await this.getPluginStore()
|
|
76
70
|
const config = await pluginStore.get({ key: 'config' });
|
|
77
71
|
const additionalFields = config.additionalFields;
|
|
78
72
|
const contentTypesNameFields = config.contentTypesNameFields;
|
|
@@ -80,9 +74,12 @@ module.exports = ({ strapi }) => {
|
|
|
80
74
|
const allowedLevels = config.allowedLevels;
|
|
81
75
|
const isGQLPluginEnabled = !isNil(strapi.plugin('graphql'));
|
|
82
76
|
|
|
83
|
-
let extendedResult = {
|
|
77
|
+
let extendedResult = {
|
|
78
|
+
allowedContentTypes: ALLOWED_CONTENT_TYPES,
|
|
79
|
+
restrictedContentTypes: RESTRICTED_CONTENT_TYPES,
|
|
80
|
+
};
|
|
84
81
|
const result = {
|
|
85
|
-
contentTypes: await
|
|
82
|
+
contentTypes: await this.configContentTypes(),
|
|
86
83
|
contentTypesNameFields: {
|
|
87
84
|
default: contentTypesNameFieldsDefaults,
|
|
88
85
|
...(isObject(contentTypesNameFields) ? contentTypesNameFields : {}),
|
|
@@ -99,9 +96,7 @@ module.exports = ({ strapi }) => {
|
|
|
99
96
|
const audienceItems = await strapi
|
|
100
97
|
.query(audienceModel.uid)
|
|
101
98
|
.findMany({
|
|
102
|
-
|
|
103
|
-
limit: -1,
|
|
104
|
-
}
|
|
99
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
105
100
|
});
|
|
106
101
|
extendedResult = {
|
|
107
102
|
...extendedResult,
|
|
@@ -115,7 +110,7 @@ module.exports = ({ strapi }) => {
|
|
|
115
110
|
},
|
|
116
111
|
|
|
117
112
|
async updateConfig(newConfig) {
|
|
118
|
-
const pluginStore = await
|
|
113
|
+
const pluginStore = await this.getPluginStore()
|
|
119
114
|
await pluginStore.set({ key: 'config', value: newConfig });
|
|
120
115
|
},
|
|
121
116
|
|
|
@@ -124,7 +119,7 @@ module.exports = ({ strapi }) => {
|
|
|
124
119
|
},
|
|
125
120
|
|
|
126
121
|
async setDefaultConfig() {
|
|
127
|
-
const pluginStore = await
|
|
122
|
+
const pluginStore = await this.getPluginStore()
|
|
128
123
|
const config = await pluginStore.get({ key: 'config' });
|
|
129
124
|
const pluginDefaultConfig = await strapi.plugin('navigation').config
|
|
130
125
|
|
|
@@ -133,10 +128,10 @@ module.exports = ({ strapi }) => {
|
|
|
133
128
|
const defaultConfigValue = {
|
|
134
129
|
additionalFields: get(config, 'additionalFields', pluginDefaultConfig('additionalFields')),
|
|
135
130
|
contentTypes: get(config, 'contentTypes', pluginDefaultConfig('contentTypes')),
|
|
136
|
-
contentTypesNameFields: get(config, 'contentTypesNameFields',
|
|
137
|
-
contentTypesPopulate: get(config, 'contentTypesPopulate',
|
|
138
|
-
allowedLevels: get(config, 'allowedLevels',
|
|
139
|
-
gql: get(config, 'gql',
|
|
131
|
+
contentTypesNameFields: get(config, 'contentTypesNameFields', pluginDefaultConfig('contentTypesNameFields')),
|
|
132
|
+
contentTypesPopulate: get(config, 'contentTypesPopulate', pluginDefaultConfig('contentTypesPopulate')),
|
|
133
|
+
allowedLevels: get(config, 'allowedLevels', pluginDefaultConfig('allowedLevels')),
|
|
134
|
+
gql: get(config, 'gql', pluginDefaultConfig('gql')),
|
|
140
135
|
}
|
|
141
136
|
pluginStore.set({ key: 'config', value: defaultConfigValue });
|
|
142
137
|
|
|
@@ -144,23 +139,20 @@ module.exports = ({ strapi }) => {
|
|
|
144
139
|
},
|
|
145
140
|
|
|
146
141
|
async restoreConfig() {
|
|
147
|
-
const pluginStore = await
|
|
142
|
+
const pluginStore = await this.getPluginStore()
|
|
148
143
|
await pluginStore.delete({ key: 'config' });
|
|
149
144
|
await strapi.plugin('navigation').service('navigation').setDefaultConfig();
|
|
150
145
|
},
|
|
151
146
|
|
|
152
147
|
async configContentTypes() {
|
|
153
|
-
const pluginStore = await
|
|
148
|
+
const pluginStore = await this.getPluginStore()
|
|
154
149
|
const config = await pluginStore.get({ key: 'config' });
|
|
155
150
|
const eligibleContentTypes =
|
|
156
151
|
await Promise.all(
|
|
157
152
|
config.contentTypes
|
|
158
|
-
.filter(contentType => !!strapi.contentTypes[contentType])
|
|
153
|
+
.filter(contentType => !!strapi.contentTypes[contentType] && utilsFunctions.isContentTypeEligible(contentType))
|
|
159
154
|
.map(
|
|
160
155
|
async (key) => {
|
|
161
|
-
if (find(excludedContentTypes, name => key.includes(name))) { // exclude internal content types
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
156
|
const item = strapi.contentTypes[key];
|
|
165
157
|
const { kind, options, uid } = item;
|
|
166
158
|
const { draftAndPublish } = options;
|
|
@@ -194,9 +186,10 @@ module.exports = ({ strapi }) => {
|
|
|
194
186
|
.map(({ key, available }) => {
|
|
195
187
|
const item = strapi.contentTypes[key];
|
|
196
188
|
const relatedField = (item.associations || []).find(_ => _.model === 'navigationitem');
|
|
197
|
-
const { uid, options, info, collectionName, modelName, apiName, plugin, kind } = item;
|
|
189
|
+
const { uid, options, info, collectionName, modelName, apiName, plugin, kind, pluginOptions } = item;
|
|
190
|
+
const { visible = true } = pluginOptions['content-manager'] || {};
|
|
198
191
|
const { name, description } = info;
|
|
199
|
-
const {
|
|
192
|
+
const { hidden, templateName } = options;
|
|
200
193
|
const findRouteConfig = find(get(strapi.api, `[${modelName}].config.routes`, []),
|
|
201
194
|
route => route.handler.includes('.find'));
|
|
202
195
|
const findRoutePath = findRouteConfig && findRouteConfig.path.split('/')[1];
|
|
@@ -221,12 +214,12 @@ module.exports = ({ strapi }) => {
|
|
|
221
214
|
labelSingular: utilsFunctions.singularize(labelSingular),
|
|
222
215
|
endpoint,
|
|
223
216
|
plugin,
|
|
224
|
-
available,
|
|
225
|
-
visible
|
|
217
|
+
available: available && !hidden,
|
|
218
|
+
visible,
|
|
226
219
|
templateName,
|
|
227
220
|
};
|
|
228
221
|
})
|
|
229
|
-
.filter((item) => item && item.
|
|
222
|
+
.filter((item) => item && item.available);
|
|
230
223
|
},
|
|
231
224
|
|
|
232
225
|
async getRelatedItems(entityItems) {
|
|
@@ -399,9 +392,7 @@ module.exports = ({ strapi }) => {
|
|
|
399
392
|
master: entity.id,
|
|
400
393
|
...itemCriteria,
|
|
401
394
|
},
|
|
402
|
-
|
|
403
|
-
limit: -1,
|
|
404
|
-
},
|
|
395
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
405
396
|
sort: ['order:asc'],
|
|
406
397
|
populate: ['related', 'audience', 'parent'],
|
|
407
398
|
});
|
|
@@ -428,6 +419,7 @@ module.exports = ({ strapi }) => {
|
|
|
428
419
|
id: item.id,
|
|
429
420
|
title: utilsFunctions.composeItemTitle(item, contentTypesNameFields, contentTypes),
|
|
430
421
|
menuAttached: item.menuAttached,
|
|
422
|
+
order: item.order,
|
|
431
423
|
path: isExternal ? item.externalPath : parentPath,
|
|
432
424
|
type: item.type,
|
|
433
425
|
uiRouterKey: item.uiRouterKey,
|
|
@@ -511,7 +503,10 @@ module.exports = ({ strapi }) => {
|
|
|
511
503
|
.filter(utilsFunctions.filterOutUnpublished)
|
|
512
504
|
.map(item => itemParser({
|
|
513
505
|
...item,
|
|
514
|
-
}, path, field))
|
|
506
|
+
}, path, field))
|
|
507
|
+
.sort((x, y) => {
|
|
508
|
+
return x.order - y.order;
|
|
509
|
+
});
|
|
515
510
|
},
|
|
516
511
|
|
|
517
512
|
renderRFR({ items, parent = null, parentNavItem = null, contentTypes = [] }) {
|
|
@@ -632,7 +627,7 @@ module.exports = ({ strapi }) => {
|
|
|
632
627
|
}
|
|
633
628
|
const navigationItem = await strapi
|
|
634
629
|
.query(itemModel.uid)
|
|
635
|
-
.create({ data });
|
|
630
|
+
.create({ data, populate: ['related', 'items'] });
|
|
636
631
|
return !isEmpty(item.items)
|
|
637
632
|
? service.createBranch(
|
|
638
633
|
item.items,
|
|
@@ -735,7 +730,6 @@ module.exports = ({ strapi }) => {
|
|
|
735
730
|
if (relatedItems) {
|
|
736
731
|
return Promise.all(relatedItems.map(async relatedItem => {
|
|
737
732
|
try {
|
|
738
|
-
|
|
739
733
|
const model = strapi.query('plugin::navigation.navigations-items-related');
|
|
740
734
|
const entity = await model
|
|
741
735
|
.findOne({
|
|
@@ -8,5 +8,14 @@ module.exports = {
|
|
|
8
8
|
|
|
9
9
|
MODEL_TYPES: {
|
|
10
10
|
CONTENT_TYPE: 'contentType'
|
|
11
|
-
}
|
|
11
|
+
},
|
|
12
|
+
ALLOWED_CONTENT_TYPES: [
|
|
13
|
+
'api::',
|
|
14
|
+
'plugin::'
|
|
15
|
+
],
|
|
16
|
+
RESTRICTED_CONTENT_TYPES: [
|
|
17
|
+
'plugin::users-permissions',
|
|
18
|
+
'plugin::i18n.locale',
|
|
19
|
+
'plugin::navigation',
|
|
20
|
+
],
|
|
12
21
|
};
|
|
@@ -13,7 +13,7 @@ const {
|
|
|
13
13
|
|
|
14
14
|
const { type: itemType } = require('../../content-types/navigation-item/lifecycle');
|
|
15
15
|
const { NavigationError } = require('../../../utils/NavigationError');
|
|
16
|
-
const { TEMPLATE_DEFAULT } = require('./constant');
|
|
16
|
+
const { TEMPLATE_DEFAULT, ALLOWED_CONTENT_TYPES, RESTRICTED_CONTENT_TYPES } = require('./constant');
|
|
17
17
|
|
|
18
18
|
module.exports = ({ strapi }) => {
|
|
19
19
|
return {
|
|
@@ -216,5 +216,11 @@ module.exports = ({ strapi }) => {
|
|
|
216
216
|
}
|
|
217
217
|
return (item.type !== itemType.INTERNAL) || relatedItem;
|
|
218
218
|
},
|
|
219
|
+
|
|
220
|
+
isContentTypeEligible(uid = '') {
|
|
221
|
+
const isOneOfAllowedType = ALLOWED_CONTENT_TYPES.filter(_ => uid.includes(_)).length > 0;
|
|
222
|
+
const isNoneOfRestricted = RESTRICTED_CONTENT_TYPES.filter(_ => uid.includes(_) || (uid === _)).length === 0;
|
|
223
|
+
return uid && isOneOfAllowedType && isNoneOfRestricted;
|
|
224
|
+
},
|
|
219
225
|
};
|
|
220
226
|
}
|