strapi-plugin-navigation 2.4.0 → 2.5.0

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 (43) hide show
  1. package/README.md +12 -1
  2. package/admin/src/pages/DataManagerProvider/actions.d.ts +2 -0
  3. package/admin/src/pages/DataManagerProvider/actions.js +3 -1
  4. package/admin/src/pages/DataManagerProvider/index.js +28 -0
  5. package/admin/src/pages/DataManagerProvider/reducer.js +8 -0
  6. package/admin/src/pages/SettingsPage/index.js +19 -7
  7. package/admin/src/pages/SettingsPage/types.d.ts +2 -1
  8. package/admin/src/pages/View/components/NavigationHeader/index.d.ts +2 -1
  9. package/admin/src/pages/View/components/NavigationHeader/index.js +5 -3
  10. package/admin/src/pages/View/components/NavigationManager/AllNavigations/icons.d.ts +1 -0
  11. package/admin/src/pages/View/components/NavigationManager/AllNavigations/icons.js +2 -1
  12. package/admin/src/pages/View/components/NavigationManager/AllNavigations/index.js +16 -4
  13. package/admin/src/pages/View/components/NavigationManager/PurgeCacheConfirm/index.d.ts +8 -0
  14. package/admin/src/pages/View/components/NavigationManager/PurgeCacheConfirm/index.js +34 -0
  15. package/admin/src/pages/View/components/NavigationManager/index.js +15 -2
  16. package/admin/src/pages/View/components/NavigationManager/types.d.ts +5 -1
  17. package/admin/src/pages/View/index.js +5 -2
  18. package/admin/src/translations/en.json +7 -0
  19. package/package.json +6 -6
  20. package/server/bootstrap/index.js +3 -0
  21. package/server/cache/index.d.ts +2 -0
  22. package/server/cache/index.js +18 -0
  23. package/server/cache/serviceEnhancers.d.ts +3 -0
  24. package/server/cache/serviceEnhancers.js +16 -0
  25. package/server/cache/setupStrategy.d.ts +3 -0
  26. package/server/cache/setupStrategy.js +38 -0
  27. package/server/cache/types.d.ts +11 -0
  28. package/server/cache/types.js +3 -0
  29. package/server/cache/utils.d.ts +11 -0
  30. package/server/cache/utils.js +19 -0
  31. package/server/config/index.js +1 -0
  32. package/server/config/setupStrategy.js +1 -0
  33. package/server/controllers/admin.js +18 -0
  34. package/server/i18n/navigationSetupStrategy.js +1 -1
  35. package/server/routes/admin.js +20 -0
  36. package/server/services/admin.js +42 -8
  37. package/server/utils/functions.d.ts +1 -1
  38. package/server/utils/functions.js +2 -2
  39. package/tsconfig.tsbuildinfo +1 -1
  40. package/types/bootstrap.d.ts +3 -0
  41. package/types/config.d.ts +1 -0
  42. package/types/controllers.d.ts +10 -0
  43. package/types/services.d.ts +7 -1
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addCacheConfigFields = void 0;
4
+ const utils_1 = require("./utils");
5
+ const addCacheConfigFields = async ({ previousConfig, strapi, }) => {
6
+ const { enabled, hasCachePlugin } = await (0, utils_1.getCacheStatus)({
7
+ strapi,
8
+ });
9
+ return {
10
+ ...previousConfig,
11
+ isCacheEnabled: enabled,
12
+ isCachePluginEnabled: hasCachePlugin,
13
+ };
14
+ };
15
+ exports.addCacheConfigFields = addCacheConfigFields;
16
+ //# sourceMappingURL=serviceEnhancers.js.map
@@ -0,0 +1,3 @@
1
+ import { IRestCacheSetupStrategy } from "../../types";
2
+ export declare const setupCacheStrategy: IRestCacheSetupStrategy;
3
+ //# sourceMappingURL=setupStrategy.d.ts.map
@@ -0,0 +1,38 @@
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
+ exports.setupCacheStrategy = void 0;
7
+ const router_1 = __importDefault(require("@koa/router"));
8
+ const client_1 = __importDefault(require("../routes/client"));
9
+ const utils_1 = require("./utils");
10
+ const setupCacheStrategy = async ({ strapi, }) => {
11
+ const { enabled, hasCachePlugin } = await (0, utils_1.getCacheStatus)({ strapi });
12
+ if (hasCachePlugin && enabled) {
13
+ const cachePlugin = strapi.plugin("rest-cache");
14
+ const createCacheMiddleware = cachePlugin?.middleware("recv");
15
+ if (!createCacheMiddleware) {
16
+ console.warn("Cache middleware not present in cache plugin. Stopping");
17
+ console.warn("Notify strapi-navigation-plugin-team");
18
+ return;
19
+ }
20
+ const pluginOption = strapi.config.get("plugin.rest-cache");
21
+ const router = new router_1.default();
22
+ const buildPathFrom = (route) => `/api/${route.info.pluginName}${route.path}`;
23
+ const buildFrom = (route) => ({
24
+ maxAge: pluginOption.strategy?.maxAge ?? 6 * 60 * 1000,
25
+ path: buildPathFrom(route),
26
+ method: "GET",
27
+ paramNames: ["idOrSlug", "childUIKey"],
28
+ keys: { useHeaders: [], useQueryParams: true },
29
+ hitpass: false,
30
+ });
31
+ client_1.default.routes.forEach((route) => {
32
+ router.get(buildPathFrom(route), createCacheMiddleware({ cacheRouteConfig: buildFrom(route) }, { strapi }));
33
+ });
34
+ strapi.server.router.use(router.routes());
35
+ }
36
+ };
37
+ exports.setupCacheStrategy = setupCacheStrategy;
38
+ //# sourceMappingURL=setupStrategy.js.map
@@ -0,0 +1,11 @@
1
+ import { IStrapi } from "strapi-typed";
2
+ export type AddCacheConfigFieldsInput<T> = {
3
+ previousConfig: T;
4
+ strapi: IStrapi;
5
+ viaSettingsPage?: boolean;
6
+ };
7
+ export type CacheConfigFields = {
8
+ isCacheEnabled: boolean;
9
+ isCachePluginEnabled: boolean;
10
+ };
11
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,11 @@
1
+ import { IStrapi } from "strapi-typed";
2
+ type GetCacheStatusInput = {
3
+ strapi: IStrapi;
4
+ };
5
+ type CacheStatus = {
6
+ hasCachePlugin: boolean;
7
+ enabled: boolean;
8
+ };
9
+ export declare const getCacheStatus: ({ strapi, }: GetCacheStatusInput) => Promise<CacheStatus>;
10
+ export {};
11
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCacheStatus = void 0;
4
+ const getCacheStatus = async ({ strapi, }) => {
5
+ const cachePlugin = strapi.plugin("rest-cache");
6
+ const hasCachePlugin = !!cachePlugin;
7
+ const pluginStore = strapi.store({
8
+ type: "plugin",
9
+ name: "navigation",
10
+ });
11
+ const config = await pluginStore.get({
12
+ key: "config",
13
+ });
14
+ return hasCachePlugin
15
+ ? { hasCachePlugin, enabled: config.isCacheEnabled }
16
+ : { hasCachePlugin, enabled: false };
17
+ };
18
+ exports.getCacheStatus = getCacheStatus;
19
+ //# sourceMappingURL=utils.js.map
@@ -29,6 +29,7 @@ const config = {
29
29
  pathDefaultFields: {},
30
30
  pruneObsoleteI18nNavigations: false,
31
31
  cascadeMenuAttached: true,
32
+ isCacheEnabled: false,
32
33
  },
33
34
  };
34
35
  exports.default = config;
@@ -25,6 +25,7 @@ const configSetupStrategy = async ({ strapi }) => {
25
25
  pruneObsoleteI18nNavigations: false,
26
26
  pathDefaultFields: getWithFallback("pathDefaultFields"),
27
27
  cascadeMenuAttached: getWithFallback("cascadeMenuAttached"),
28
+ isCacheEnabled: getWithFallback("isCacheEnabled"),
28
29
  };
29
30
  handleDeletedContentTypes(config, { strapi });
30
31
  (0, utils_1.validateAdditionalFields)(config.additionalFields);
@@ -6,6 +6,7 @@ const utils_2 = require("../utils");
6
6
  const utils_3 = require("../utils");
7
7
  const InvalidParamNavigationError_1 = require("../../utils/InvalidParamNavigationError");
8
8
  const NavigationError_1 = require("../../utils/NavigationError");
9
+ const utils_4 = require("../cache/utils");
9
10
  const adminControllers = {
10
11
  getAdminService() {
11
12
  return (0, utils_2.getPluginService)("admin");
@@ -137,6 +138,23 @@ const adminControllers = {
137
138
  throw error;
138
139
  }
139
140
  },
141
+ async purgeNavigationsCache() {
142
+ const mappedStrapi = strapi;
143
+ const { enabled } = await (0, utils_4.getCacheStatus)({ strapi: mappedStrapi });
144
+ if (!enabled) {
145
+ return { success: false };
146
+ }
147
+ return await this.getAdminService().purgeNavigationsCache();
148
+ },
149
+ async purgeNavigationCache(ctx) {
150
+ const { params: { id }, query: { clearLocalisations = 'false' } } = ctx;
151
+ const mappedStrapi = strapi;
152
+ const { enabled } = await (0, utils_4.getCacheStatus)({ strapi: mappedStrapi });
153
+ if (!enabled) {
154
+ return { success: false };
155
+ }
156
+ return await this.getAdminService().purgeNavigationCache(id, JSON.parse(clearLocalisations));
157
+ }
140
158
  };
141
159
  const assertCopyParams = (source, target) => {
142
160
  (0, types_1.assertIsNumber)(source, new InvalidParamNavigationError_1.InvalidParamNavigationError("Source's id is not a number"));
@@ -104,7 +104,7 @@ const i18nNavigationSetupStrategy = async ({ strapi, }) => {
104
104
  return getCurrentNavigations(strapi);
105
105
  };
106
106
  exports.i18nNavigationSetupStrategy = i18nNavigationSetupStrategy;
107
- const getCurrentNavigations = (strapi, ids) => strapi.plugin("navigation").service("admin").get(ids);
107
+ const getCurrentNavigations = (strapi, ids) => strapi.plugin("navigation").service("admin").get(ids, true);
108
108
  const createNavigation = ({ strapi, payload, populate, }) => strapi.query("plugin::navigation.navigation").create({
109
109
  data: {
110
110
  ...payload,
@@ -72,6 +72,26 @@ const routes = {
72
72
  }]
73
73
  }
74
74
  },
75
+ {
76
+ method: 'DELETE',
77
+ path: '/cache/purge/:id',
78
+ handler: 'admin.purgeNavigationCache',
79
+ config: {
80
+ policies: [
81
+ 'admin::isAuthenticatedAdmin'
82
+ ]
83
+ }
84
+ },
85
+ {
86
+ method: 'DELETE',
87
+ path: '/cache/purge',
88
+ handler: 'admin.purgeNavigationsCache',
89
+ config: {
90
+ policies: [
91
+ 'admin::isAuthenticatedAdmin'
92
+ ]
93
+ }
94
+ },
75
95
  {
76
96
  method: 'GET',
77
97
  path: '/slug',
@@ -5,6 +5,7 @@ const lodash_1 = require("lodash");
5
5
  const utils_2 = require("../utils");
6
6
  const i18n_1 = require("../i18n");
7
7
  const NavigationError_1 = require("../../utils/NavigationError");
8
+ const serviceEnhancers_1 = require("../cache/serviceEnhancers");
8
9
  const adminService = ({ strapi, }) => ({
9
10
  async config(viaSettingsPage = false) {
10
11
  const commonService = (0, utils_2.getPluginService)("common");
@@ -50,6 +51,7 @@ const adminService = ({ strapi, }) => ({
50
51
  viaSettingsPage,
51
52
  previousConfig: {},
52
53
  });
54
+ const cacheConfig = await (0, serviceEnhancers_1.addCacheConfigFields)({ strapi, previousConfig: {} });
53
55
  if (additionalFields.includes("audience")) {
54
56
  const audienceItems = await strapi
55
57
  .query(audienceModel.uid)
@@ -65,9 +67,10 @@ const adminService = ({ strapi, }) => ({
65
67
  ...result,
66
68
  ...extendedResult,
67
69
  ...i18nConfig,
70
+ ...cacheConfig,
68
71
  };
69
72
  },
70
- async get(ids) {
73
+ async get(ids, ignoreLocale = false) {
71
74
  const { masterModel } = (0, utils_2.getPluginModels)();
72
75
  const { enabled: i18nEnabled, locales } = await (0, i18n_1.getI18nStatus)({ strapi });
73
76
  const whereClause = {};
@@ -79,7 +82,7 @@ const adminService = ({ strapi, }) => ({
79
82
  populate: utils_2.DEFAULT_POPULATE,
80
83
  where: whereClause,
81
84
  });
82
- if (i18nEnabled) {
85
+ if (i18nEnabled && !ignoreLocale) {
83
86
  entities = entities.reduce((acc, entity) => {
84
87
  if (entity.localeCode && locales?.includes(entity.localeCode)) {
85
88
  acc.push({
@@ -126,11 +129,12 @@ const adminService = ({ strapi, }) => ({
126
129
  name,
127
130
  slug: await commonService.getSlug(name),
128
131
  visible,
132
+ localeCode: i18nEnabled && defaultLocale ? defaultLocale : null
129
133
  };
130
134
  const existingEntity = await strapi
131
135
  .query(masterModel.uid)
132
136
  .create({ data });
133
- const result = commonService
137
+ const result = await commonService
134
138
  .createBranch(payload.items, existingEntity, null, {})
135
139
  .then(() => adminService.getById(existingEntity.id))
136
140
  .then((newEntity) => {
@@ -207,19 +211,21 @@ const adminService = ({ strapi, }) => ({
207
211
  },
208
212
  async delete(id, auditLog) {
209
213
  const { masterModel, itemModel } = (0, utils_2.getPluginModels)();
210
- const adminService = (0, utils_2.getPluginService)("admin");
211
- const entity = await adminService.getById(id);
214
+ const entity = await this.getById(id);
212
215
  const { enabled: i18nEnabled } = await (0, i18n_1.getI18nStatus)({ strapi });
213
216
  const cleanNavigationItems = async (masterIds) => {
217
+ if (masterIds.length < 1) {
218
+ return;
219
+ }
214
220
  const navigationItems = await strapi.query(itemModel.uid).findMany({
215
221
  where: {
216
- $or: masterIds.map((id) => ({ master: id }))
222
+ $or: masterIds.map((id) => ({ master: id })),
217
223
  },
218
224
  limit: Number.MAX_SAFE_INTEGER,
219
225
  });
220
226
  await strapi.query(itemModel.uid).deleteMany({
221
227
  where: {
222
- $or: navigationItems.map(({ id }) => ({ id }))
228
+ id: navigationItems.map(({ id }) => (id)),
223
229
  },
224
230
  });
225
231
  };
@@ -248,7 +254,7 @@ const adminService = ({ strapi, }) => ({
248
254
  setImmediate(() => strapi.reload());
249
255
  },
250
256
  async restoreConfig() {
251
- const commonService = (0, utils_2.getPluginService)("common");
257
+ const commonService = (0, utils_2.getPluginService)("common", strapi);
252
258
  const pluginStore = await commonService.getPluginStore();
253
259
  await pluginStore.delete({ key: "config" });
254
260
  await commonService.setDefaultConfig();
@@ -306,6 +312,34 @@ const adminService = ({ strapi, }) => ({
306
312
  strapi,
307
313
  });
308
314
  },
315
+ async purgeNavigationCache(id, clearLocalisations) {
316
+ const entity = await this.getById(id);
317
+ const regexps = [];
318
+ const mapToRegExp = (id) => new RegExp(`/api/navigation/render/${id}`);
319
+ if (!entity) {
320
+ throw new utils_1.errors.NotFoundError("Navigation is not defined");
321
+ }
322
+ if (clearLocalisations) {
323
+ const { enabled: isI18nEnabled } = await (0, i18n_1.getI18nStatus)({ strapi });
324
+ if (isI18nEnabled) {
325
+ entity.localizations?.forEach((navigation) => {
326
+ regexps.push(mapToRegExp(navigation.id));
327
+ });
328
+ }
329
+ }
330
+ const restCachePlugin = strapi.plugin("rest-cache");
331
+ const cacheStore = restCachePlugin.service("cacheStore");
332
+ regexps.push(mapToRegExp(id));
333
+ await cacheStore.clearByRegexp(regexps);
334
+ return { success: true };
335
+ },
336
+ async purgeNavigationsCache() {
337
+ const restCachePlugin = strapi.plugin("rest-cache");
338
+ const cacheStore = restCachePlugin.service("cacheStore");
339
+ const regex = new RegExp("/api/navigation/render(.*)");
340
+ await cacheStore.clearByRegexp([regex]);
341
+ return { success: true };
342
+ }
309
343
  });
310
344
  exports.default = adminService;
311
345
  //# sourceMappingURL=admin.js.map
@@ -9,7 +9,7 @@ type TypeMap = {
9
9
  admin: IAdminService;
10
10
  common: ICommonService;
11
11
  };
12
- export declare function getPluginService<T extends NavigationServiceName>(name: T): T extends infer R extends NavigationServiceName ? TypeMap[R] : never;
12
+ export declare function getPluginService<T extends NavigationServiceName>(name: T, strapiInstance?: IStrapi): T extends infer R extends NavigationServiceName ? TypeMap[R] : never;
13
13
  export declare const errorHandler: (ctx: ToBeFixed) => (error: NavigationError | string) => any;
14
14
  export declare const getCustomFields: (additionalFields: NavigationItemAdditionalField[]) => NavigationItemCustomField[];
15
15
  export declare const parseParams: <TParams extends StringMap<string> = StringMap<string>, TResult extends StringMap<Primitive> = StringMap<Primitive>>(params: TParams) => TResult;
@@ -6,8 +6,8 @@ const types_1 = require("../../types");
6
6
  const NavigationError_1 = require("../../utils/NavigationError");
7
7
  const constant_1 = require("./constant");
8
8
  const UID_REGEX = /^(?<type>[a-z0-9-]+)\:{2}(?<api>[a-z0-9-]+)\.{1}(?<contentType>[a-z0-9-]+)$/i;
9
- function getPluginService(name) {
10
- return strapi.plugin("navigation").service(name);
9
+ function getPluginService(name, strapiInstance = strapi) {
10
+ return strapiInstance.plugin("navigation").service(name);
11
11
  }
12
12
  exports.getPluginService = getPluginService;
13
13
  const errorHandler = (ctx) => (error) => {