strapi-plugin-navigation 2.0.4 → 2.0.7

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 (29) hide show
  1. package/README.md +2 -1
  2. package/admin/src/components/CollapseButton/index.js +31 -0
  3. package/admin/src/components/Item/ItemCardBadge/index.js +4 -4
  4. package/admin/src/components/Item/ItemCardHeader/Wrapper.js +0 -4
  5. package/admin/src/components/Item/ItemCardHeader/index.js +5 -4
  6. package/admin/src/components/Item/Wrapper.js +1 -1
  7. package/admin/src/components/Item/index.js +129 -66
  8. package/admin/src/components/NavigationItemList/Wrapper.js +1 -1
  9. package/admin/src/components/NavigationItemList/index.js +6 -0
  10. package/admin/src/components/Search/index.js +1 -1
  11. package/admin/src/pages/SettingsPage/index.js +95 -91
  12. package/admin/src/pages/View/components/NavigationItemForm/index.js +49 -30
  13. package/admin/src/pages/View/components/NavigationItemPopup/NavigationItemPopupHeader.js +3 -3
  14. package/admin/src/pages/View/index.js +81 -9
  15. package/admin/src/pages/View/utils/enums.js +1 -0
  16. package/admin/src/pages/View/utils/parsers.js +6 -3
  17. package/admin/src/translations/en.json +15 -3
  18. package/admin/src/utils/index.js +4 -2
  19. package/package.json +2 -3
  20. package/server/bootstrap.js +3 -22
  21. package/server/config/index.js +1 -0
  22. package/server/config.js +1 -0
  23. package/server/content-types/navigation-item/lifecycle.js +1 -0
  24. package/server/content-types/navigation-item/schema.json +7 -1
  25. package/server/graphql/types/content-types-name-fields.js +2 -2
  26. package/server/graphql/types/navigation-item.js +1 -1
  27. package/server/services/navigation.js +44 -19
  28. package/server/services/utils/functions.js +1 -1
  29. package/yarn-error.log +0 -5263
@@ -3,6 +3,8 @@
3
3
  "header.title": "Navigation",
4
4
  "header.description": "Define your portal navigation",
5
5
  "header.action.newItem": "New Item",
6
+ "header.action.collapseAll": "Collapse All",
7
+ "header.action.expandAll": "Expand All",
6
8
  "submit.cta.cancel": "Cancel",
7
9
  "submit.cta.save": "Save",
8
10
  "empty": "Your navigation is empty",
@@ -20,12 +22,14 @@
20
22
  "popup.item.form.externalPath.placeholder": "Link to the external source",
21
23
  "popup.item.form.externalPath.validation.type": "This value is not a proper url.",
22
24
  "popup.item.form.menuAttached.label": "Attach to menu",
23
- "popup.item.form.type.label": "Internal link",
25
+ "popup.item.form.type.label": "Navigation item type",
24
26
  "popup.item.form.type.internal.label": "Internal source",
25
27
  "popup.item.form.type.external.label": "External source",
28
+ "popup.item.form.type.wrapper.label": "Wrapper element",
26
29
  "popup.item.form.type.external.description": "Output path: {value}",
27
30
  "popup.item.form.audience.label": "Audience",
28
31
  "popup.item.form.audience.placeholder": "Select audience...",
32
+ "popup.item.form.audience.empty": "There are no more audiences",
29
33
  "popup.item.form.relatedSection.label": "Relation to",
30
34
  "popup.item.form.relatedType.label": "Content Type",
31
35
  "popup.item.form.relatedType.placeholder": "Select content type...",
@@ -43,6 +47,7 @@
43
47
  "notification.navigation.item.relation": "Entity relation does not exist!",
44
48
  "notification.navigation.item.relation.status.draft": "draft",
45
49
  "notification.navigation.item.relation.status.published": "published",
50
+ "pages.main.search.placeholder": "Type to start searching...",
46
51
  "pages.settings.general.title": "General settings",
47
52
  "pages.settings.additional.title": "Additional settings",
48
53
  "pages.settings.nameField.title": "Content types settings",
@@ -80,10 +85,17 @@
80
85
  "pages.settings.form.nameField.label": "Name fields",
81
86
  "pages.settings.form.nameField.placeholder": "Select at least one or leave empty to apply defaults",
82
87
  "pages.settings.form.nameField.hint": "If left empty name field is going to take following ordered fields: \"title\", \"subject\" and \"name\"",
88
+ "pages.settings.form.nameField.empty": "This content type doesn't have any string attributes",
89
+ "pages.settings.form.populate.label": "Fields to populate",
90
+ "pages.settings.form.populate.placeholder": "Select at least one or leave empty to disable populating relation fields",
91
+ "pages.settings.form.populate.hint": "Selected relation fields will be populated inside API responses",
92
+ "pages.settings.form.populate.empty": "This content type doesn't have any relation fields",
93
+ "pages.settings.form.contentTypesSettings.label": "Content types",
94
+ "pages.settings.form.contentTypesSettings.tooltip": "Custom configuration per content type",
83
95
  "components.navigationItem.action.newItem": "Add nested item",
84
96
  "components.navigationItem.badge.removed": "Removed",
85
- "components.navigationItem.badge.draft": "{type}: Draft",
86
- "components.navigationItem.badge.published": "{type}: Published",
97
+ "components.navigationItem.badge.draft": "Draft",
98
+ "components.navigationItem.badge.published": "Published",
87
99
  "components.confirmation.dialog.button.cancel": "Cancel",
88
100
  "components.confirmation.dialog.button.confirm": "Confirm",
89
101
  "components.confirmation.dialog.description": "Do you want to continue?",
@@ -3,7 +3,7 @@ import { isString } from 'lodash';
3
3
 
4
4
  import pluginId from '../pluginId';
5
5
 
6
- const getMessage = (input, defaultMessage = '', inPluginScope = true) => {
6
+ export const getMessage = (input, defaultMessage = '', inPluginScope = true) => {
7
7
  const { formatMessage } = useIntl();
8
8
  let formattedId = ''
9
9
  if (isString(input)) {
@@ -17,4 +17,6 @@ const getMessage = (input, defaultMessage = '', inPluginScope = true) => {
17
17
  }, input?.props || undefined)
18
18
  };
19
19
 
20
- export { getMessage };
20
+ export const ItemTypes = {
21
+ NAVIGATION_ITEM: 'navigationItem'
22
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strapi-plugin-navigation",
3
- "version": "2.0.4",
3
+ "version": "2.0.7",
4
4
  "description": "Strapi - Navigation plugin",
5
5
  "strapi": {
6
6
  "name": "navigation",
@@ -17,9 +17,8 @@
17
17
  "test:unit": "jest --verbose --coverage"
18
18
  },
19
19
  "dependencies": {
20
- "@strapi/utils": "^4.1.0",
20
+ "@strapi/utils": "^4.1.5",
21
21
  "uuid": "^8.3.0",
22
- "bad-words": "^3.0.3",
23
22
  "lodash": "^4.17.11",
24
23
  "react": "^16.9.0",
25
24
  "react-dom": "^16.9.0",
@@ -42,30 +42,11 @@ module.exports = async ({ strapi }) => {
42
42
  }
43
43
 
44
44
  // Initialize configuration
45
- const pluginStore = strapi.store({
46
- environment: '',
47
- type: 'plugin',
48
- name: 'navigation',
49
- });
50
-
51
- const config = await pluginStore.get({ key: 'config' });
52
- const pluginDefaultConfig = await strapi.plugin('navigation').config
53
- const defaultConfigValue = {
54
- additionalFields: pluginDefaultConfig('additionalFields'),
55
- contentTypes: pluginDefaultConfig('contentTypes'),
56
- contentTypesNameFields: pluginDefaultConfig('contentTypesNameFields'),
57
- allowedLevels: pluginDefaultConfig('allowedLevels'),
58
- gql: pluginDefaultConfig('gql'),
59
- }
60
-
61
- if (!config) {
62
- pluginStore.set({
63
- key: 'config', value: defaultConfigValue
64
- });
65
- }
45
+ const config = await strapi.plugin('navigation').service('navigation').setDefaultConfig()
66
46
 
47
+ // Initialize graphql configuration
67
48
  if (strapi.plugin('graphql')) {
68
49
  const graphqlConfiguration = require('./graphql')
69
- await graphqlConfiguration({ strapi, config: config || defaultConfigValue });
50
+ await graphqlConfiguration({ strapi, config });
70
51
  }
71
52
  };
@@ -3,6 +3,7 @@ module.exports = {
3
3
  additionalFields: [],
4
4
  contentTypes: [],
5
5
  contentTypesNameFields: {},
6
+ contentTypesPopulate: {},
6
7
  allowedLevels: 2
7
8
  }
8
9
  }
package/server/config.js CHANGED
@@ -3,6 +3,7 @@ module.exports = {
3
3
  additionalFields: [],
4
4
  contentTypes: [],
5
5
  contentTypesNameFields: {},
6
+ contentTypesPopulate: {},
6
7
  allowedLevels: 2
7
8
  }
8
9
  }
@@ -10,6 +10,7 @@ module.exports = {
10
10
  type: {
11
11
  INTERNAL: 'INTERNAL',
12
12
  EXTERNAL: 'EXTERNAL',
13
+ WRAPPER: 'WRAPPER',
13
14
  },
14
15
  additionalFields: {
15
16
  AUDIENCE: 'audience',
@@ -37,7 +37,8 @@
37
37
  "type": "enumeration",
38
38
  "enum": [
39
39
  "INTERNAL",
40
- "EXTERNAL"
40
+ "EXTERNAL",
41
+ "WRAPPER"
41
42
  ],
42
43
  "default": "INTERNAL",
43
44
  "configurable": false
@@ -65,6 +66,11 @@
65
66
  "default": 0,
66
67
  "configurable": false
67
68
  },
69
+ "collapsed": {
70
+ "type": "boolean",
71
+ "default": false,
72
+ "configurable": false
73
+ },
68
74
  "related": {
69
75
  "type": "relation",
70
76
  "relation": "oneToOne",
@@ -1,8 +1,8 @@
1
- module.exports = ({ nexus }) => nexus.objectType({
1
+ module.exports = ({ nexus, strapi }) => nexus.objectType({
2
2
  name: "ContentTypesNameFields",
3
3
  async definition(t) {
4
4
  t.nonNull.list.nonNull.string("default")
5
- const pluginStore = strapi.store({ type: 'plugin', name: 'navigation' });
5
+ const pluginStore = await strapi.plugin('navigation').service('navigation').getPluginStore();
6
6
  const config = await pluginStore.get({ key: 'config' });
7
7
  const contentTypesNameFields = config.contentTypesNameFields;
8
8
  Object.keys(contentTypesNameFields || {}).forEach(key => t.nonNull.list.string(key))
@@ -13,7 +13,7 @@ module.exports = ({ nexus }) =>
13
13
  t.int("parent")
14
14
  t.int("master")
15
15
  t.list.field("items", { type: 'NavigationItem' })
16
- t.list.field("related", { type: 'NavigationRelated' })
16
+ t.field("related", { type: 'NavigationRelated' })
17
17
  t.list.string("audience")
18
18
  // SQL
19
19
  t.string("created_at")
@@ -72,10 +72,11 @@ module.exports = ({ strapi }) => {
72
72
  // Get plugin config
73
73
  async config(viaSettingsPage = false) {
74
74
  const { audienceModel, service } = utilsFunctions.extractMeta(strapi.plugins);
75
- const pluginStore = await strapi.store({ type: 'plugin', name: 'navigation' });
75
+ const pluginStore = await strapi.plugin('navigation').service('navigation').getPluginStore()
76
76
  const config = await pluginStore.get({ key: 'config' });
77
77
  const additionalFields = config.additionalFields;
78
78
  const contentTypesNameFields = config.contentTypesNameFields;
79
+ const contentTypesPopulate = config.contentTypesPopulate;
79
80
  const allowedLevels = config.allowedLevels;
80
81
  const isGQLPluginEnabled = !isNil(strapi.plugin('graphql'));
81
82
 
@@ -86,6 +87,9 @@ module.exports = ({ strapi }) => {
86
87
  default: contentTypesNameFieldsDefaults,
87
88
  ...(isObject(contentTypesNameFields) ? contentTypesNameFields : {}),
88
89
  },
90
+ contentTypesPopulate: {
91
+ ...(isObject(contentTypesPopulate) ? contentTypesPopulate : {}),
92
+ },
89
93
  allowedLevels,
90
94
  additionalFields,
91
95
  isGQLPluginEnabled: viaSettingsPage ? isGQLPluginEnabled : undefined,
@@ -111,28 +115,42 @@ module.exports = ({ strapi }) => {
111
115
  },
112
116
 
113
117
  async updateConfig(newConfig) {
114
- const pluginStore = await strapi.store({ type: 'plugin', name: 'navigation' });
118
+ const pluginStore = await strapi.plugin('navigation').service('navigation').getPluginStore()
115
119
  await pluginStore.set({ key: 'config', value: newConfig });
116
120
  },
117
121
 
122
+ async getPluginStore() {
123
+ return await strapi.store({ type: 'plugin', name: 'navigation' });
124
+ },
125
+
126
+ async setDefaultConfig() {
127
+ const pluginStore = await strapi.plugin('navigation').service('navigation').getPluginStore()
128
+ const config = await pluginStore.get({ key: 'config' });
129
+ const pluginDefaultConfig = await strapi.plugin('navigation').config
130
+
131
+ // If new value gets introduced to the config it either is read from plugin store or from default plugin config
132
+ // This is fix for backwards compatibility and migration of config to newer version of the plugin
133
+ const defaultConfigValue = {
134
+ additionalFields: get(config, 'additionalFields', pluginDefaultConfig('additionalFields')),
135
+ contentTypes: get(config, 'contentTypes', pluginDefaultConfig('contentTypes')),
136
+ contentTypesNameFields: get(config, 'contentTypesNameFields', pluginDefaultConfig('contentTypesNameFields')),
137
+ contentTypesPopulate: get(config, 'contentTypesPopulate', pluginDefaultConfig('contentTypesPopulate')),
138
+ allowedLevels: get(config, 'allowedLevels', pluginDefaultConfig('allowedLevels')),
139
+ gql: get(config, 'gql', pluginDefaultConfig('gql')),
140
+ }
141
+ pluginStore.set({ key: 'config', value: defaultConfigValue });
142
+
143
+ return defaultConfigValue;
144
+ },
145
+
118
146
  async restoreConfig() {
119
- const pluginStore = await strapi.store({ type: 'plugin', name: 'navigation' });
120
- const defaultConfig = await strapi.plugin('navigation').config
121
-
122
- await pluginStore.delete({ key: 'config' })
123
- await pluginStore.set({
124
- key: 'config', value: {
125
- additionalFields: defaultConfig('additionalFields'),
126
- contentTypes: defaultConfig('contentTypes'),
127
- contentTypesNameFields: defaultConfig('contentTypesNameFields'),
128
- allowedLevels: defaultConfig('allowedLevels'),
129
- gql: defaultConfig('gql'),
130
- }
131
- });
147
+ const pluginStore = await strapi.plugin('navigation').service('navigation').getPluginStore()
148
+ await pluginStore.delete({ key: 'config' });
149
+ await strapi.plugin('navigation').service('navigation').setDefaultConfig();
132
150
  },
133
151
 
134
152
  async configContentTypes() {
135
- const pluginStore = strapi.store({ type: 'plugin', name: 'navigation' });
153
+ const pluginStore = await strapi.plugin('navigation').service('navigation').getPluginStore()
136
154
  const config = await pluginStore.get({ key: 'config' });
137
155
  const eligibleContentTypes =
138
156
  await Promise.all(
@@ -212,6 +230,8 @@ module.exports = ({ strapi }) => {
212
230
  },
213
231
 
214
232
  async getRelatedItems(entityItems) {
233
+ const pluginStore = await strapi.plugin('navigation').service('navigation').getPluginStore()
234
+ const config = await pluginStore.get({ key: 'config' });
215
235
  const relatedTypes = new Set(entityItems.flatMap((item) => get(item.related, 'related_type')));
216
236
  const groupedItems = Array.from(relatedTypes).filter((relatedType) => relatedType).reduce(
217
237
  (acc, relatedType) => Object.assign(acc, {
@@ -233,8 +253,9 @@ module.exports = ({ strapi }) => {
233
253
  .query(model)
234
254
  .findMany({
235
255
  where: {
236
- id: { $in: map(related, 'related_id') }
237
- }
256
+ id: { $in: map(related, 'related_id') },
257
+ },
258
+ populate: config.contentTypesPopulate[model] || []
238
259
  });
239
260
  return relationData
240
261
  .flatMap(_ =>
@@ -264,8 +285,12 @@ module.exports = ({ strapi }) => {
264
285
  },
265
286
 
266
287
  async getContentTypeItems(model) {
288
+ const pluginStore = await strapi.plugin('navigation').service('navigation').getPluginStore()
289
+ const config = await pluginStore.get({ key: 'config' });
267
290
  try {
268
- const contentTypeItems = await strapi.query(model).findMany()
291
+ const contentTypeItems = await strapi.query(model).findMany({
292
+ populate: config.contentTypesPopulate[model] || []
293
+ })
269
294
  return contentTypeItems;
270
295
  } catch (err) {
271
296
  return [];
@@ -213,7 +213,7 @@ module.exports = ({ strapi }) => {
213
213
  false;
214
214
  return item.type === itemType.INTERNAL ? isRelatedDefinedAndPublished : true;
215
215
  }
216
- return (item.type === itemType.EXTERNAL) || relatedItem;
216
+ return (item.type !== itemType.INTERNAL) || relatedItem;
217
217
  },
218
218
  };
219
219
  }