strapi-plugin-navigation 1.0.3 → 1.1.2

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.
@@ -6,7 +6,7 @@ jobs:
6
6
  environment:
7
7
  CODECOV_TOKEN: a9097475-0b5b-481f-8733-7b84574d583e
8
8
  docker:
9
- - image: circleci/node:12.13.0
9
+ - image: circleci/node:14.17.2
10
10
  working_directory: ~/repo
11
11
  steps:
12
12
  - checkout
package/README.md CHANGED
@@ -55,7 +55,7 @@ Complete installation requirements are exact same as for Strapi itself and can b
55
55
 
56
56
  **Supported Strapi versions**:
57
57
 
58
- - Strapi v3.6.0 (recently tested)
58
+ - Strapi v3.6.8 (recently tested)
59
59
  - Strapi v3.x
60
60
 
61
61
  (This plugin may work with the older Strapi versions, but these are not tested nor officially supported at this time.)
@@ -73,40 +73,22 @@ Complete installation requirements are exact same as for Strapi itself and can b
73
73
 
74
74
  ## Content Type model relation to Navigation Item
75
75
 
76
- To enable Content Type to work with Navigation Item, you've to add following field to your model `*.settings.json`:
77
-
78
- ```
79
- "navigation": {
80
- "model": "navigationitem",
81
- "plugin": "navigation",
82
- "via": "related",
83
- "configurable": false,
84
- "hidden": true
85
- }
86
- ```
87
-
88
- inside the `attributes` section like in example below:
89
-
90
- ```
91
- "attributes": {
92
- ...,
93
- "navigation": {
94
- "model": "navigationitem",
95
- "plugin": "navigation",
96
- "via": "related",
97
- "configurable": false,
98
- "hidden": true
99
- },
100
- ...
101
- },
76
+ We can define in `config/plugins.js`
77
+ ```js
78
+ navigation: {
79
+ ...
80
+ relatedContentTypes: [
81
+ 'application::pages.pages'
82
+ ],
83
+ ...
84
+ },
102
85
  ```
103
86
 
104
87
  ## Configuration
105
- To setup the plugin properly we recommend to put following snippet as part of `config/custom.js` or `config/<env>/custom.js` file. If you've got already configurations for other plugins stores by this way, use just the `navigation` part within exising `plugins` item.
88
+ To setup the plugin properly we recommend to put following snippet as part of `config/plugins.js` or `config/<env>/plugins.js` file. If you've got already configurations for other plugins stores by this way, use just the `navigation` part within exising `plugins` item.
106
89
 
107
- ```
90
+ ```js
108
91
  ...
109
- plugins: {
110
92
  navigation: {
111
93
  additionalFields: ['audience'],
112
94
  allowedLevels: 2,
@@ -114,8 +96,8 @@ To setup the plugin properly we recommend to put following snippet as part of `c
114
96
  'blog_posts': ['altTitle'],
115
97
  'pages': ['title'],
116
98
  },
99
+ gql: { ... }
117
100
  },
118
- },
119
101
  ...
120
102
  ```
121
103
 
@@ -123,6 +105,34 @@ To setup the plugin properly we recommend to put following snippet as part of `c
123
105
  - `additionalFields` - Additional fields: 'audience', more in the future
124
106
  - `allowedLevels` - Maximum level for which your're able to mark item as "Menu attached"
125
107
  - `contentTypesNameFields` - Definition of content type title fields like `'content_type_name': ['field_name_1', 'field_name_2']`, if not set titles are pulled from fields like `['title', 'subject', 'name']`
108
+ - `gql` - If you're using GraphQL that's the right place to put all necessary settings. More **[ here ](#gql-configuration)**
109
+
110
+ ## GQL Configuration
111
+ To properly configure GQL to work with navigation you should provide `gql` prop which should contain union types which will be used for define GQL response format for your data while fetching:
112
+
113
+ ```gql
114
+ master: Int
115
+ items: [NavigationItem]
116
+ related: NavigationRelated
117
+ ```
118
+
119
+ as follows:
120
+
121
+ ```js
122
+ gql: {
123
+ navigationItemRelated: 'union NavigationRelated = <your GQL related entities>',
124
+ },
125
+ ```
126
+
127
+ for example:
128
+
129
+ ```js
130
+ gql: {
131
+ navigationItemRelated: 'union NavigationRelated = Pages | UploadFile',
132
+ },
133
+ ```
134
+ where `Pages` and `UploadFile` are your types to the **Content Types** you're referring by navigation items relations.
135
+
126
136
 
127
137
  ## Public API Navigation Item model
128
138
 
@@ -1,3 +1,4 @@
1
+ const {get} = require('lodash');
1
2
  function setupStrapi() {
2
3
  Object.defineProperty(global, 'strapi', {
3
4
  value: {
@@ -14,6 +15,9 @@ function setupStrapi() {
14
15
  },
15
16
  },
16
17
  },
18
+ get(path, defaultValue) {
19
+ return get(strapi, path, defaultValue);
20
+ },
17
21
  },
18
22
  api: {
19
23
  'home-page': {
@@ -40,13 +44,13 @@ function setupStrapi() {
40
44
  modelName: 'pages',
41
45
  associations: [{ model: 'navigationitem' }],
42
46
  },
43
- 'blog-post': {
47
+ 'application::blog-post.blog-post': {
44
48
  ...require('./blog-post.settings.json'),
45
49
  apiName: 'blog-posts',
46
50
  modelName: 'blog-posts',
47
51
  associations: [{ model: 'navigationitem' }],
48
52
  },
49
- 'my-homepage': {
53
+ 'application::my-homepages.my-homepage': {
50
54
  ...require('./my-homepage.settings.json'),
51
55
  apiName: 'my-homepage',
52
56
  modelName: 'my-homepage',
@@ -58,12 +62,12 @@ function setupStrapi() {
58
62
  modelName: 'home-page',
59
63
  associations: [{ model: 'navigationitem' }],
60
64
  },
61
- 'plugin-page': {
65
+ 'plugins::another-plugin.pages': {
62
66
  ...require('./another-plugin/pages.settings.json'),
63
67
  modelName: 'plugin-pages',
64
68
  associations: [{ model: 'navigationitem' }],
65
69
  },
66
- 'plugin-blog-post': {
70
+ 'plugins::another-plugin.blog-post': {
67
71
  ...require('./another-plugin/blog-post.settings.json'),
68
72
  modelName: 'plugin-blog-posts',
69
73
  associations: [{ model: 'navigationitem' }],
@@ -73,7 +77,15 @@ function setupStrapi() {
73
77
  navigation: {
74
78
  services: {
75
79
  navigation: jest.fn().mockImplementation(),
76
- }
80
+ },
81
+ relatedContentTypes: [
82
+ 'application::pages.pages',
83
+ 'application::blog-post.blog-post',
84
+ 'application::my-homepages.my-homepage',
85
+ 'application::page-homes.home-page',
86
+ 'plugins::another-plugin.pages',
87
+ 'plugins::another-plugin.blog-post'
88
+ ]
77
89
  },
78
90
  anotherPlugin: {
79
91
  models: {
@@ -29,7 +29,7 @@ export const form = {
29
29
  is: val => val === navigationItemType.EXTERNAL,
30
30
  then: yup.string()
31
31
  .required(translatedErrors.required)
32
- .matches(/(#.*)|(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})/, {
32
+ .matches(/(#.*)|(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,}|mailto:.+@(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])\.)+[^.\s]{2,})/, {
33
33
  excludeEmptyString: true,
34
34
  message: `${pluginId}.popup.item.form.externalPath.validation.type`,
35
35
  }),
@@ -1,5 +1,5 @@
1
1
  import { isUuid, uuid } from 'uuidv4';
2
- import { find, get, isArray, isEmpty, isNil, isNumber, isObject, isString, kebabCase, last, omit, orderBy } from 'lodash';
2
+ import { find, get, isArray, isEmpty, isNil, isNumber, isObject, isString, last, omit, orderBy } from 'lodash';
3
3
  import { navigationItemType } from './enums';
4
4
 
5
5
  export const transformItemToRESTPayload = (
@@ -46,8 +46,7 @@ export const transformItemToRESTPayload = (
46
46
  order,
47
47
  uiRouterKey,
48
48
  menuAttached,
49
- audience: audience.map((audienceItem) =>
50
- isObject(audienceItem) ? audienceItem.value : audienceItem,
49
+ audience: audience.map((audienceItem) => isObject(audienceItem) ? audienceItem.value || audienceItem.id : audienceItem,
51
50
  ),
52
51
  path: isExternal ? undefined : path,
53
52
  externalPath: isExternal ? externalPath : undefined,
@@ -65,7 +64,7 @@ export const transformItemToRESTPayload = (
65
64
  };
66
65
 
67
66
  export const transformToRESTPayload = (payload, config = {}) => {
68
- const { id, name, visible, items } = payload;
67
+ const { id, name, visible, items } = payload;
69
68
  return {
70
69
  id,
71
70
  name,
@@ -120,7 +119,7 @@ const linkRelations = (item, config) => {
120
119
  const shouldBuildRelated = !relatedRef || (relatedRef && (relatedRef.id !== relatedId));
121
120
  if (shouldBuildRelated && !shouldFindRelated) {
122
121
  const relatedContentType = find(contentTypes,
123
- ct => kebabCase(ct.contentTypeName) === kebabCase(relatedItem.__contentType), {});
122
+ ct => ct.uid === relatedItem.__contentType, {});
124
123
  const { uid, labelSingular, isSingle } = relatedContentType;
125
124
  relation = {
126
125
  related: relatedItem.id,
@@ -262,7 +261,7 @@ export const usedContentTypes = (items = []) => items.flatMap(
262
261
  if (item.relatedRef) {
263
262
  return [item.relatedRef, ...used];
264
263
  }
265
- return used;
264
+ return used;
266
265
  },
267
266
  );
268
267
 
@@ -284,11 +283,11 @@ export const isRelationPublished = ({ relatedRef, relatedType = {}, type, isColl
284
283
  return true;
285
284
  };
286
285
 
287
- export const validateNavigationStructure = (items = []) =>
288
- items.map(item =>
289
- (item.removed || isRelationCorrect({
290
- related: item.related,
286
+ export const validateNavigationStructure = (items = []) =>
287
+ items.map(item =>
288
+ (item.removed || isRelationCorrect({
289
+ related: item.related,
291
290
  type: item.type,
292
- })) &&
291
+ })) &&
293
292
  validateNavigationStructure(item.items)
294
- ).filter(item => !item).length === 0;
293
+ ).filter(item => !item).length === 0;
@@ -1,26 +1,112 @@
1
- const { isEmpty } = require("lodash");
1
+ const { isEmpty, get, last } = require('lodash');
2
+
3
+ const saveJSONParse = (value) => {
4
+ try {
5
+ return JSON.parse(value).map((_) => ({ ..._, id: _._id }));
6
+ } catch (e) {
7
+ return null;
8
+ }
9
+ };
10
+
11
+ const getDefaultConnectionName = (strapi) => strapi.config.get('database.defaultConnection');
12
+
13
+ const isMongo = (strapi) => {
14
+ const connectionName = getDefaultConnectionName(strapi);
15
+ return strapi.config.get(`database.connections.${connectionName}.connector`).includes('mongo');
16
+ };
17
+
18
+ const getNavigationMorphData = (strapi) => {
19
+ const connectionName = getDefaultConnectionName(strapi);
20
+ const { [connectionName]: knex } = strapi.connections;
21
+ return knex.schema.hasTable('navigations_items_morph').then((exist)=> exist ? knex('navigations_items_morph').select('*') : []);
22
+ };
23
+
24
+ const getNavigationItemsModel = (strapi) => strapi.query('navigationitem', 'navigation');
25
+
26
+ const getRelatedModel = (strapi) => strapi.query('navigations_items_related', 'navigation');
27
+
28
+ const createRelatedData = (relatedModel, navigationItemsModel, items) => ({
29
+ field,
30
+ order,
31
+ related_id,
32
+ related_type,
33
+ navigations_items_id,
34
+ }) => {
35
+ const item = items.find(item => item.id === navigations_items_id);
36
+ const modelUID = get(strapi.query(related_type), 'model.uid');
37
+ if (item && modelUID) {
38
+ const relatedData = {
39
+ field,
40
+ order,
41
+ related_id,
42
+ related_type: modelUID,
43
+ master: get(item.master, 'id', item.master),
44
+ };
45
+ return relatedModel.create(relatedData)
46
+ .then(
47
+ ({ id }) => navigationItemsModel.update({ id: navigations_items_id }, { related: id }),
48
+ );
49
+ }
50
+ return Promise.resolve();
51
+ };
52
+
53
+ const migrateNavigationItemsSQL = async (strapi) => {
54
+ const morphData = await getNavigationMorphData(strapi);
55
+ if (morphData.length) {
56
+ const relatedModel = getRelatedModel(strapi);
57
+ const navigationItemsModel = getNavigationItemsModel(strapi);
58
+ const items = await navigationItemsModel.find({});
59
+ await Promise.all(morphData.map(createRelatedData(relatedModel, navigationItemsModel, items)));
60
+ }
61
+ };
62
+
63
+ const migrateNavigationItemsMongo = async (strapi) => {
64
+ const navigationItemsModel = getNavigationItemsModel(strapi);
65
+ const connectionName = getDefaultConnectionName(strapi);
66
+ const models = strapi.connections[connectionName].models;
67
+ const items = (await models.NavigationNavigationitem.find({}))
68
+ // workaround to change type from object to int
69
+ .map(_ => ({ ..._.toObject(), related: last(saveJSONParse(get(_.errors, 'related.properties.value', null))) }))
70
+ .filter(_ => _.related);
71
+
72
+ if (items.length) {
73
+ await Promise.all(items.map(item => {
74
+ const data = {
75
+ related_id: item.related.ref,
76
+ related_type: models[item.related.kind].uid,
77
+ field: item.related.field,
78
+ order: 1,
79
+ master: item.master,
80
+ };
81
+ return getRelatedModel(strapi)
82
+ .create(data)
83
+ .then(result => navigationItemsModel.update({ id: item.id }, { related: [result.id] }));
84
+ }));
85
+
86
+ }
87
+ };
2
88
 
3
89
  module.exports = async () => {
4
90
  // Check if the plugin users-permissions is installed because the navigation needs it
5
- if (Object.keys(strapi.plugins).indexOf("users-permissions") === -1) {
91
+ if (Object.keys(strapi.plugins).indexOf('users-permissions') === -1) {
6
92
  throw new Error(
7
- "In order to make the navigation plugin work the users-permissions plugin is required",
93
+ 'In order to make the navigation plugin work the users-permissions plugin is required',
8
94
  );
9
95
  }
10
96
 
11
97
  // Add permissions
12
98
  const actions = [
13
99
  {
14
- section: "plugins",
15
- displayName: "Access the Navigation",
16
- uid: "read",
17
- pluginName: "navigation",
100
+ section: 'plugins',
101
+ displayName: 'Access the Navigation',
102
+ uid: 'read',
103
+ pluginName: 'navigation',
18
104
  },
19
105
  {
20
- section: "plugins",
21
- displayName: "Ability to change the Navigation",
22
- uid: "update",
23
- pluginName: "navigation",
106
+ section: 'plugins',
107
+ displayName: 'Ability to change the Navigation',
108
+ uid: 'update',
109
+ pluginName: 'navigation',
24
110
  },
25
111
  ];
26
112
 
@@ -36,6 +122,16 @@ module.exports = async () => {
36
122
  visible: true,
37
123
  });
38
124
  }
125
+ const relatedModel = getRelatedModel(global.strapi);
126
+ const isMigrated = !!(await relatedModel.count({}));
127
+ if (!isMigrated) {
128
+ const isMongoDB = isMongo(global.strapi);
129
+ if (isMongoDB) {
130
+ await migrateNavigationItemsMongo(global.strapi);
131
+ } else {
132
+ await migrateNavigationItemsSQL(global.strapi);
133
+ }
134
+ }
39
135
 
40
136
  const { actionProvider } = strapi.admin.services.permission;
41
137
  await actionProvider.registerMany(actions);
@@ -0,0 +1,204 @@
1
+ const NAVIGATION_DATE = `
2
+ # SQL
3
+ created_at: String
4
+ updated_at: String
5
+ # MONGO
6
+ createdAt: String
7
+ updatedAt: String
8
+ `;
9
+
10
+ const NAVIGATION_USER = `
11
+ # SQL
12
+ created_by: String
13
+ updated_by: String
14
+ # MONGO
15
+ createdBy: String
16
+ updatedBy: String
17
+ `;
18
+
19
+ const NAVIGATION = `
20
+ id: String!
21
+ name: String!
22
+ slug: String!
23
+ visible: Boolean!
24
+ `;
25
+
26
+ const getContentTypesNamesFields = () => {
27
+ const contentTypesNameFields = strapi.config.get('plugins.navigation.contentTypesNameFields');
28
+ return Object.keys(contentTypesNameFields || {}).map(key => `${key}: [String]!`).join('\n');
29
+ };
30
+
31
+ const getNavigationRelated = () => {
32
+ const related = strapi.config.get('plugins.navigation.gql.navigationItemRelated');
33
+ if (related) {
34
+ return related;
35
+ }
36
+ return `
37
+ type NavigationRelated {
38
+ id: Int
39
+ title: String
40
+ name: String
41
+ }
42
+ `;
43
+ };
44
+
45
+ module.exports = {
46
+ // language=GraphQL
47
+ definition: `
48
+ enum NavigationRenderType {
49
+ FLAT,
50
+ TREE,
51
+ RFR
52
+ }
53
+
54
+ ${getNavigationRelated()}
55
+
56
+
57
+ type NavigationItem {
58
+ id: Int!
59
+ title: String!
60
+ type: String!
61
+ path: String
62
+ externalPath: String
63
+ uiRouterKey: String!
64
+ menuAttached: Boolean!
65
+ order: Int!
66
+ parent: Int
67
+ master: Int
68
+ items: [NavigationItem]
69
+ related: NavigationRelated
70
+ audience: [String]
71
+ ${NAVIGATION_DATE}
72
+ ${NAVIGATION_USER}
73
+ }
74
+
75
+ type Navigation {
76
+ ${NAVIGATION}
77
+ }
78
+
79
+ type NavigationDetails {
80
+ ${NAVIGATION}
81
+ items: [NavigationItem]!
82
+ }
83
+
84
+
85
+ type ContentTypesNameFields {
86
+ default: [String!]!
87
+ ${getContentTypesNamesFields()}
88
+ }
89
+
90
+ type ContentTypes {
91
+ uid: String!
92
+ name: String!
93
+ isSingle: Boolean!
94
+ collectionName: String!
95
+ contentTypeName: String!
96
+ label: String!
97
+ relatedField: String!
98
+ labelSingular: String!
99
+ endpoint: String!
100
+ available: Boolean!
101
+ visible: Boolean!
102
+ }
103
+
104
+ type NavigationConfig {
105
+ allowedLevels: Int
106
+ availableAudience: [NavigationAudience]!
107
+ additionalFields: [String]!
108
+ contentTypesNameFields: ContentTypesNameFields
109
+ contentTypes: [ContentTypes]
110
+ }
111
+
112
+ input CreateNavigationRelated {
113
+ ref: String!
114
+ field: String!
115
+ refId: String!
116
+ }
117
+
118
+ input CreateNavigationItem {
119
+ title: String!
120
+ type: String!
121
+ path: String
122
+ externalPath: String
123
+ uiRouterKey: String!
124
+ menuAttached: Boolean!
125
+ order: Int!
126
+ parent: Int
127
+ master: Int
128
+ items: [CreateNavigationItem]
129
+ audience: [String]
130
+ related: CreateNavigationRelated
131
+ }
132
+
133
+ input CreateNavigation {
134
+ name: String!
135
+ items: [CreateNavigationItem]!
136
+ }
137
+ `,
138
+ query: `
139
+ renderNavigation(navigationIdOrSlug: String!, type: NavigationRenderType, menuOnly: Boolean): [NavigationItem]!
140
+ renderNavigationChild(id: String!, childUIKey: String!, type: NavigationRenderType, menuOnly: Boolean): [NavigationItem]!
141
+ getNavigation: [Navigation]!
142
+ configNavigation: NavigationConfig
143
+ getByIdNavigation(id: String!): NavigationItem
144
+ `,
145
+ type: {},
146
+ mutation: `
147
+ navigationCreate(newNavigation: CreateNavigation!): Navigation!
148
+ navigationUpdate(id: String!, navigation: CreateNavigation!): Navigation!
149
+ `,
150
+ resolver: {
151
+ Query: {
152
+ renderNavigation: {
153
+ resolverOf: 'plugins::navigation.navigation.render',
154
+ resolver(obj, options) {
155
+ const { navigationIdOrSlug, type, menuOnly } = options;
156
+ return strapi.plugins.navigation.services.navigation.render(navigationIdOrSlug, type, menuOnly);
157
+ },
158
+ },
159
+ renderNavigationChild: {
160
+ resolverOf: 'plugins::navigation.navigation.renderChild',
161
+ async resolver(obj, options) {
162
+ const { id, childUIKey, type, menuOnly } = options;
163
+ return strapi.plugins.navigation.services.navigation.renderChildren(id, childUIKey, type, menuOnly);
164
+ },
165
+ },
166
+ getNavigation: {
167
+ resolverOf: 'plugins::navigation.navigation.get',
168
+ resolver() {
169
+ return strapi.plugins.navigation.services.navigation.get();
170
+ },
171
+ },
172
+ configNavigation: {
173
+ resolverOf: 'plugins::navigation.navigation.config',
174
+ resolver() {
175
+ return strapi.plugins.navigation.services.navigation.config();
176
+ },
177
+ },
178
+ getByIdNavigation: {
179
+ resolverOf: 'plugins::navigation.navigation.getById',
180
+ async resolver(obj, options) {
181
+ const { id } = options;
182
+ return strapi.plugins.navigation.services.navigation.getById(id);
183
+ },
184
+ },
185
+ },
186
+ Mutation: {
187
+ navigationCreate: {
188
+ resolverOf: 'plugins::navigation.navigation.post',
189
+ resolver(obj, options) {
190
+ const { newNavigation } = options;
191
+ return strapi.plugins.navigation.services.navigation.post(newNavigation);
192
+ },
193
+ },
194
+ navigationUpdate: {
195
+ resolverOf: 'plugins::navigation.navigation.put',
196
+ resolver(obj, options) {
197
+ const { id, navigation } = options;
198
+ return strapi.plugins.navigation.services.navigation.put(id, navigation);
199
+ },
200
+ },
201
+ },
202
+ },
203
+ };
204
+
@@ -23,35 +23,33 @@ const errorHandler = (ctx) => (error) => {
23
23
  }
24
24
  throw error;
25
25
  };
26
+ const getService = () => strapi.plugins.navigation.services.navigation;
26
27
 
27
28
  module.exports = {
28
- getService() {
29
- return strapi.plugins.navigation.services.navigation;
30
- },
31
29
  /**
32
30
  * Default action.
33
31
  *
34
32
  * @return {Object}
35
33
  */
36
34
  async config() {
37
- return await this.getService().config();
35
+ return getService().config();
38
36
  },
39
37
 
40
38
  async get() {
41
- return await this.getService().get();
39
+ return getService().get();
42
40
  },
43
41
 
44
42
  async getById(ctx) {
45
43
  const { params } = ctx;
46
44
  const { id } = parseParams(params);
47
- return await this.getService().getById(id);
45
+ return getService().getById(id);
48
46
  },
49
47
 
50
48
  async render(ctx) {
51
49
  const { params, query = {} } = ctx;
52
50
  const { type, menu: menuOnly } = query;
53
51
  const { idOrSlug } = parseParams(params);
54
- return await this.getService().render(
52
+ return getService().render(
55
53
  idOrSlug,
56
54
  type,
57
55
  menuOnly,
@@ -61,7 +59,7 @@ module.exports = {
61
59
  const { params, query = {} } = ctx;
62
60
  const { type, menu: menuOnly } = query;
63
61
  const { idOrSlug, childUIKey } = parseParams(params);
64
- return await this.getService().renderChildren(
62
+ return getService().renderChildren(
65
63
  idOrSlug,
66
64
  childUIKey,
67
65
  type,
@@ -72,14 +70,14 @@ module.exports = {
72
70
  post(ctx) {
73
71
  const { auditLog } = ctx;
74
72
  const { body = {} } = ctx.request;
75
- return this.getService().post(body, auditLog);
73
+ return getService().post(body, auditLog);
76
74
  },
77
75
 
78
76
  put(ctx) {
79
77
  const { params, auditLog } = ctx;
80
78
  const { id } = parseParams(params);
81
79
  const { body = {} } = ctx.request;
82
- return this.getService().put(id, body, auditLog)
80
+ return getService().put(id, body, auditLog)
83
81
  .catch(errorHandler(ctx));
84
82
  },
85
83
  };
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "pluginOptions": {
12
12
  "content-manager": {
13
- "visible": false
13
+ "visible": true
14
14
  },
15
15
  "content-type-builder": {
16
16
  "visible": false