strapi-plugin-dynamic-zone-tools 1.0.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 (53) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/CONTRIBUTING.md +38 -0
  3. package/LICENSE +21 -0
  4. package/README.md +186 -0
  5. package/admin/custom.d.ts +2 -0
  6. package/admin/src/components/DynamicZoneComponentDuplicateInjector.tsx +604 -0
  7. package/admin/src/components/DynamicZoneEditViewExtensions.tsx +7 -0
  8. package/admin/src/components/DynamicZoneToolsPanel.tsx +1027 -0
  9. package/admin/src/components/FillFromRecord.tsx +36 -0
  10. package/admin/src/components/Initializer.tsx +19 -0
  11. package/admin/src/components/PluginIcon.tsx +5 -0
  12. package/admin/src/index.ts +61 -0
  13. package/admin/src/pages/App.tsx +15 -0
  14. package/admin/src/pages/HomePage.tsx +16 -0
  15. package/admin/src/pluginId.ts +1 -0
  16. package/admin/src/translations/en.json +51 -0
  17. package/admin/src/utils/createRowActionButton.ts +57 -0
  18. package/admin/src/utils/createRowActionMenu.ts +276 -0
  19. package/admin/src/utils/dynamicZoneClipboard.ts +134 -0
  20. package/admin/src/utils/dynamicZonePaths.ts +236 -0
  21. package/admin/src/utils/getTranslation.ts +5 -0
  22. package/admin/src/utils/prepareDynamicZoneData.ts +625 -0
  23. package/admin/src/utils/relationQueryParams.ts +19 -0
  24. package/admin/tsconfig.build.json +10 -0
  25. package/admin/tsconfig.json +12 -0
  26. package/dist/admin/en-Ce0ZP0MJ.js +54 -0
  27. package/dist/admin/en-DrSdJbJW.mjs +54 -0
  28. package/dist/admin/index.js +2161 -0
  29. package/dist/admin/index.mjs +2159 -0
  30. package/dist/admin/src/index.d.ts +12 -0
  31. package/dist/server/index.js +137 -0
  32. package/dist/server/index.mjs +137 -0
  33. package/dist/server/src/index.d.ts +55 -0
  34. package/package.json +112 -0
  35. package/server/src/bootstrap.ts +18 -0
  36. package/server/src/config/index.ts +4 -0
  37. package/server/src/content-types/index.ts +1 -0
  38. package/server/src/controllers/controller.ts +85 -0
  39. package/server/src/controllers/index.ts +5 -0
  40. package/server/src/destroy.ts +7 -0
  41. package/server/src/index.ts +30 -0
  42. package/server/src/middlewares/index.ts +1 -0
  43. package/server/src/policies/index.ts +1 -0
  44. package/server/src/register.ts +7 -0
  45. package/server/src/routes/admin-api.ts +18 -0
  46. package/server/src/routes/content-api.ts +1 -0
  47. package/server/src/routes/index.ts +15 -0
  48. package/server/src/services/index.ts +5 -0
  49. package/server/src/services/service.ts +9 -0
  50. package/server/tsconfig.build.json +10 -0
  51. package/server/tsconfig.json +11 -0
  52. package/strapi-admin.js +3 -0
  53. package/strapi-server.js +3 -0
@@ -0,0 +1,12 @@
1
+ declare const _default: {
2
+ register(app: any): void;
3
+ bootstrap(app: any): Promise<void>;
4
+ registerTrads(app: any): Promise<({
5
+ data: string;
6
+ locale: string;
7
+ } | {
8
+ data: {};
9
+ locale: string;
10
+ })[]>;
11
+ };
12
+ export default _default;
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const bootstrap = ({ strapi }) => {
4
+ const actions = [
5
+ {
6
+ section: "plugins",
7
+ displayName: "Fill Dynamic Zone",
8
+ uid: "fill",
9
+ pluginName: "dynamic-zone-tools"
10
+ }
11
+ ];
12
+ strapi.admin.services.permission.actionProvider.registerMany(actions);
13
+ };
14
+ const destroy = ({ strapi }) => {
15
+ };
16
+ const register = ({ strapi }) => {
17
+ };
18
+ const config = {
19
+ default: {},
20
+ validator() {
21
+ }
22
+ };
23
+ const contentTypes = {};
24
+ const MAX_POPULATE_DEPTH = 8;
25
+ const buildDeepPopulate = (strapi, uid, level = 1) => {
26
+ if (level > MAX_POPULATE_DEPTH) return true;
27
+ const model = strapi.getModel(uid);
28
+ if (!model) return true;
29
+ const populate = {};
30
+ for (const [name, attribute] of Object.entries(model.attributes)) {
31
+ switch (attribute.type) {
32
+ case "media":
33
+ populate[name] = true;
34
+ break;
35
+ case "relation":
36
+ if (attribute.target) populate[name] = true;
37
+ break;
38
+ case "component": {
39
+ const nested = buildDeepPopulate(strapi, attribute.component, level + 1);
40
+ populate[name] = nested === true || Object.keys(nested).length === 0 ? true : { populate: nested };
41
+ break;
42
+ }
43
+ case "dynamiczone": {
44
+ const on = {};
45
+ for (const componentUid of attribute.components ?? []) {
46
+ const nested = buildDeepPopulate(strapi, componentUid, level + 1);
47
+ on[componentUid] = nested === true || Object.keys(nested).length === 0 ? true : { populate: nested };
48
+ }
49
+ populate[name] = { on };
50
+ break;
51
+ }
52
+ }
53
+ }
54
+ return populate;
55
+ };
56
+ const controller = ({ strapi }) => ({
57
+ async getDynamicZoneData(ctx) {
58
+ const { contentType, id } = ctx.params;
59
+ const { locale, status } = ctx.query;
60
+ const model = strapi.getModel(contentType);
61
+ if (!model) {
62
+ return ctx.badRequest(`Unknown content type: ${contentType}`);
63
+ }
64
+ try {
65
+ const populate = buildDeepPopulate(strapi, contentType);
66
+ const hasDraftAndPublish = Boolean(model.options?.draftAndPublish);
67
+ const isLocalized = Boolean(model.pluginOptions?.i18n?.localized);
68
+ const document = await strapi.documents(contentType).findOne({
69
+ documentId: id,
70
+ populate: populate === true ? "*" : populate,
71
+ locale: isLocalized && locale ? locale : void 0,
72
+ status: hasDraftAndPublish ? status === "published" ? "published" : "draft" : void 0
73
+ });
74
+ if (!document) {
75
+ return ctx.notFound("Document not found");
76
+ }
77
+ return ctx.send({ data: document });
78
+ } catch (error) {
79
+ strapi.log.error("dynamic-zone-tools: failed to fetch source document", error);
80
+ return ctx.internalServerError("Failed to fetch dynamic zone data");
81
+ }
82
+ }
83
+ });
84
+ const controllers = {
85
+ controller
86
+ };
87
+ const middlewares = {};
88
+ const policies$1 = {};
89
+ const contentAPIRoutes = [];
90
+ const policies = [
91
+ "admin::isAuthenticatedAdmin",
92
+ {
93
+ name: "admin::hasPermissions",
94
+ config: {
95
+ actions: ["plugin::dynamic-zone-tools.fill"]
96
+ }
97
+ }
98
+ ];
99
+ const adminAPIRoutes = [
100
+ {
101
+ method: "GET",
102
+ path: "/source-document/:contentType/:id",
103
+ handler: "controller.getDynamicZoneData",
104
+ config: { policies }
105
+ }
106
+ ];
107
+ const routes = {
108
+ "content-api": {
109
+ type: "content-api",
110
+ routes: contentAPIRoutes
111
+ },
112
+ "admin": {
113
+ type: "admin",
114
+ routes: adminAPIRoutes
115
+ }
116
+ };
117
+ const service = ({ strapi }) => ({
118
+ getWelcomeMessage() {
119
+ return "Welcome to Strapi 🚀";
120
+ }
121
+ });
122
+ const services = {
123
+ service
124
+ };
125
+ const index = {
126
+ register,
127
+ bootstrap,
128
+ destroy,
129
+ config,
130
+ controllers,
131
+ routes,
132
+ services,
133
+ contentTypes,
134
+ policies: policies$1,
135
+ middlewares
136
+ };
137
+ exports.default = index;
@@ -0,0 +1,137 @@
1
+ const bootstrap = ({ strapi }) => {
2
+ const actions = [
3
+ {
4
+ section: "plugins",
5
+ displayName: "Fill Dynamic Zone",
6
+ uid: "fill",
7
+ pluginName: "dynamic-zone-tools"
8
+ }
9
+ ];
10
+ strapi.admin.services.permission.actionProvider.registerMany(actions);
11
+ };
12
+ const destroy = ({ strapi }) => {
13
+ };
14
+ const register = ({ strapi }) => {
15
+ };
16
+ const config = {
17
+ default: {},
18
+ validator() {
19
+ }
20
+ };
21
+ const contentTypes = {};
22
+ const MAX_POPULATE_DEPTH = 8;
23
+ const buildDeepPopulate = (strapi, uid, level = 1) => {
24
+ if (level > MAX_POPULATE_DEPTH) return true;
25
+ const model = strapi.getModel(uid);
26
+ if (!model) return true;
27
+ const populate = {};
28
+ for (const [name, attribute] of Object.entries(model.attributes)) {
29
+ switch (attribute.type) {
30
+ case "media":
31
+ populate[name] = true;
32
+ break;
33
+ case "relation":
34
+ if (attribute.target) populate[name] = true;
35
+ break;
36
+ case "component": {
37
+ const nested = buildDeepPopulate(strapi, attribute.component, level + 1);
38
+ populate[name] = nested === true || Object.keys(nested).length === 0 ? true : { populate: nested };
39
+ break;
40
+ }
41
+ case "dynamiczone": {
42
+ const on = {};
43
+ for (const componentUid of attribute.components ?? []) {
44
+ const nested = buildDeepPopulate(strapi, componentUid, level + 1);
45
+ on[componentUid] = nested === true || Object.keys(nested).length === 0 ? true : { populate: nested };
46
+ }
47
+ populate[name] = { on };
48
+ break;
49
+ }
50
+ }
51
+ }
52
+ return populate;
53
+ };
54
+ const controller = ({ strapi }) => ({
55
+ async getDynamicZoneData(ctx) {
56
+ const { contentType, id } = ctx.params;
57
+ const { locale, status } = ctx.query;
58
+ const model = strapi.getModel(contentType);
59
+ if (!model) {
60
+ return ctx.badRequest(`Unknown content type: ${contentType}`);
61
+ }
62
+ try {
63
+ const populate = buildDeepPopulate(strapi, contentType);
64
+ const hasDraftAndPublish = Boolean(model.options?.draftAndPublish);
65
+ const isLocalized = Boolean(model.pluginOptions?.i18n?.localized);
66
+ const document = await strapi.documents(contentType).findOne({
67
+ documentId: id,
68
+ populate: populate === true ? "*" : populate,
69
+ locale: isLocalized && locale ? locale : void 0,
70
+ status: hasDraftAndPublish ? status === "published" ? "published" : "draft" : void 0
71
+ });
72
+ if (!document) {
73
+ return ctx.notFound("Document not found");
74
+ }
75
+ return ctx.send({ data: document });
76
+ } catch (error) {
77
+ strapi.log.error("dynamic-zone-tools: failed to fetch source document", error);
78
+ return ctx.internalServerError("Failed to fetch dynamic zone data");
79
+ }
80
+ }
81
+ });
82
+ const controllers = {
83
+ controller
84
+ };
85
+ const middlewares = {};
86
+ const policies$1 = {};
87
+ const contentAPIRoutes = [];
88
+ const policies = [
89
+ "admin::isAuthenticatedAdmin",
90
+ {
91
+ name: "admin::hasPermissions",
92
+ config: {
93
+ actions: ["plugin::dynamic-zone-tools.fill"]
94
+ }
95
+ }
96
+ ];
97
+ const adminAPIRoutes = [
98
+ {
99
+ method: "GET",
100
+ path: "/source-document/:contentType/:id",
101
+ handler: "controller.getDynamicZoneData",
102
+ config: { policies }
103
+ }
104
+ ];
105
+ const routes = {
106
+ "content-api": {
107
+ type: "content-api",
108
+ routes: contentAPIRoutes
109
+ },
110
+ "admin": {
111
+ type: "admin",
112
+ routes: adminAPIRoutes
113
+ }
114
+ };
115
+ const service = ({ strapi }) => ({
116
+ getWelcomeMessage() {
117
+ return "Welcome to Strapi 🚀";
118
+ }
119
+ });
120
+ const services = {
121
+ service
122
+ };
123
+ const index = {
124
+ register,
125
+ bootstrap,
126
+ destroy,
127
+ config,
128
+ controllers,
129
+ routes,
130
+ services,
131
+ contentTypes,
132
+ policies: policies$1,
133
+ middlewares
134
+ };
135
+ export {
136
+ index as default
137
+ };
@@ -0,0 +1,55 @@
1
+ declare const _default: {
2
+ register: ({ strapi }: {
3
+ strapi: import('@strapi/types/dist/core').Strapi;
4
+ }) => void;
5
+ bootstrap: ({ strapi }: {
6
+ strapi: import('@strapi/types/dist/core').Strapi;
7
+ }) => void;
8
+ destroy: ({ strapi }: {
9
+ strapi: import('@strapi/types/dist/core').Strapi;
10
+ }) => void;
11
+ config: {
12
+ default: {};
13
+ validator(): void;
14
+ };
15
+ controllers: {
16
+ controller: ({ strapi }: {
17
+ strapi: import('@strapi/types/dist/core').Strapi;
18
+ }) => {
19
+ getDynamicZoneData(ctx: any): Promise<any>;
20
+ };
21
+ };
22
+ routes: {
23
+ 'content-api': {
24
+ type: string;
25
+ routes: any[];
26
+ };
27
+ admin: {
28
+ type: string;
29
+ routes: {
30
+ method: string;
31
+ path: string;
32
+ handler: string;
33
+ config: {
34
+ policies: (string | {
35
+ name: string;
36
+ config: {
37
+ actions: string[];
38
+ };
39
+ })[];
40
+ };
41
+ }[];
42
+ };
43
+ };
44
+ services: {
45
+ service: ({ strapi }: {
46
+ strapi: import('@strapi/types/dist/core').Strapi;
47
+ }) => {
48
+ getWelcomeMessage(): string;
49
+ };
50
+ };
51
+ contentTypes: {};
52
+ policies: {};
53
+ middlewares: {};
54
+ };
55
+ export default _default;
package/package.json ADDED
@@ -0,0 +1,112 @@
1
+ {
2
+ "name": "strapi-plugin-dynamic-zone-tools",
3
+ "description": "Dynamic zone productivity tools for Strapi 5: copy dynamic zones from other records and duplicate, copy, or insert individual component blocks.",
4
+ "license": "MIT",
5
+ "version": "1.0.0",
6
+ "keywords": [
7
+ "strapi",
8
+ "strapi5",
9
+ "strapi-plugin",
10
+ "plugin",
11
+ "dynamic-zone",
12
+ "dynamic-zones",
13
+ "content-manager",
14
+ "copy",
15
+ "duplicate",
16
+ "cms"
17
+ ],
18
+ "homepage": "https://github.com/dimitrisganotis/strapi-plugin-dynamic-zone-tools#readme",
19
+ "bugs": {
20
+ "url": "https://github.com/dimitrisganotis/strapi-plugin-dynamic-zone-tools/issues"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/dimitrisganotis/strapi-plugin-dynamic-zone-tools.git"
25
+ },
26
+ "author": {
27
+ "name": "Dimitris Ganotis",
28
+ "email": "hello@dganotis.dev",
29
+ "url": "https://www.dganotis.dev"
30
+ },
31
+ "type": "commonjs",
32
+ "strapi": {
33
+ "kind": "plugin",
34
+ "name": "dynamic-zone-tools",
35
+ "displayName": "Dynamic Zone Tools",
36
+ "description": "Copy dynamic zone content between records and duplicate, copy, or insert individual component blocks in Strapi 5."
37
+ },
38
+ "main": "./strapi-server.js",
39
+ "files": [
40
+ "admin/src",
41
+ "admin/custom.d.ts",
42
+ "admin/tsconfig.json",
43
+ "admin/tsconfig.build.json",
44
+ "server/src",
45
+ "server/tsconfig.json",
46
+ "server/tsconfig.build.json",
47
+ "dist",
48
+ "strapi-admin.js",
49
+ "strapi-server.js",
50
+ "package.json",
51
+ "README.md",
52
+ "CHANGELOG.md",
53
+ "CONTRIBUTING.md",
54
+ "LICENSE"
55
+ ],
56
+ "exports": {
57
+ "./strapi-admin": {
58
+ "types": "./dist/admin/src/index.d.ts",
59
+ "source": "./admin/src/index.ts",
60
+ "import": "./dist/admin/index.mjs",
61
+ "require": "./dist/admin/index.js",
62
+ "default": "./dist/admin/index.js"
63
+ },
64
+ "./strapi-server": {
65
+ "types": "./dist/server/src/index.d.ts",
66
+ "source": "./server/src/index.ts",
67
+ "import": "./dist/server/index.mjs",
68
+ "require": "./dist/server/index.js",
69
+ "default": "./dist/server/index.js"
70
+ },
71
+ "./package.json": "./package.json"
72
+ },
73
+ "scripts": {
74
+ "build": "strapi-plugin build",
75
+ "watch": "strapi-plugin watch",
76
+ "watch:link": "strapi-plugin watch:link",
77
+ "verify": "strapi-plugin verify",
78
+ "prepack": "npm run build",
79
+ "test:ts:front": "tsc -p admin/tsconfig.json --noEmit",
80
+ "test:ts:back": "tsc -p server/tsconfig.json --noEmit"
81
+ },
82
+ "dependencies": {
83
+ "fractional-indexing": "^3.2.0",
84
+ "react-intl": "^7.1.14"
85
+ },
86
+ "devDependencies": {
87
+ "@strapi/strapi": "^5.41.0",
88
+ "@strapi/sdk-plugin": "^5.3.2",
89
+ "prettier": "^3.7.4",
90
+ "react": "^18.3.1",
91
+ "react-dom": "^18.3.1",
92
+ "react-router-dom": "^6.30.2",
93
+ "styled-components": "^6.1.19",
94
+ "@types/react": "^18",
95
+ "@types/react-dom": "^18",
96
+ "@strapi/typescript-utils": "^5.41.0",
97
+ "typescript": "^5"
98
+ },
99
+ "peerDependencies": {
100
+ "@strapi/design-system": "^2.0.0",
101
+ "@strapi/icons": "^2.0.0",
102
+ "@strapi/strapi": "^5.41.0",
103
+ "react": "^18.0.0",
104
+ "react-dom": "^18.0.0",
105
+ "react-router-dom": "^6.0.0",
106
+ "styled-components": "^6.0.0"
107
+ },
108
+ "engines": {
109
+ "node": ">=18.0.0 <=22.x.x",
110
+ "npm": ">=6.0.0"
111
+ }
112
+ }
@@ -0,0 +1,18 @@
1
+ import type { Core } from '@strapi/strapi';
2
+
3
+ const bootstrap = ({ strapi }: { strapi: Core.Strapi }) => {
4
+ // Register permissions for the plugin
5
+ const actions = [
6
+ {
7
+ section: 'plugins',
8
+ displayName: 'Fill Dynamic Zone',
9
+ uid: 'fill',
10
+ pluginName: 'dynamic-zone-tools',
11
+ },
12
+ ];
13
+
14
+ // Register permissions immediately
15
+ strapi.admin.services.permission.actionProvider.registerMany(actions);
16
+ };
17
+
18
+ export default bootstrap;
@@ -0,0 +1,4 @@
1
+ export default {
2
+ default: {},
3
+ validator() {},
4
+ };
@@ -0,0 +1 @@
1
+ export default {};
@@ -0,0 +1,85 @@
1
+ import type { Core } from '@strapi/strapi';
2
+
3
+ const MAX_POPULATE_DEPTH = 8;
4
+
5
+ /**
6
+ * Builds a populate object that fully populates media, relations, components
7
+ * and dynamic zones (recursively). The content-manager admin endpoint only
8
+ * returns relation counts, which is why the tools need its own fetch.
9
+ */
10
+ const buildDeepPopulate = (strapi: Core.Strapi, uid: string, level = 1): Record<string, any> | true => {
11
+ if (level > MAX_POPULATE_DEPTH) return true;
12
+
13
+ const model = strapi.getModel(uid as any);
14
+ if (!model) return true;
15
+
16
+ const populate: Record<string, any> = {};
17
+
18
+ for (const [name, attribute] of Object.entries<any>(model.attributes)) {
19
+ switch (attribute.type) {
20
+ case 'media':
21
+ populate[name] = true;
22
+ break;
23
+ case 'relation':
24
+ // Polymorphic relations have no single target; skip them
25
+ if (attribute.target) populate[name] = true;
26
+ break;
27
+ case 'component': {
28
+ const nested = buildDeepPopulate(strapi, attribute.component, level + 1);
29
+ populate[name] = nested === true || Object.keys(nested).length === 0 ? true : { populate: nested };
30
+ break;
31
+ }
32
+ case 'dynamiczone': {
33
+ const on: Record<string, any> = {};
34
+ for (const componentUid of attribute.components ?? []) {
35
+ const nested = buildDeepPopulate(strapi, componentUid, level + 1);
36
+ on[componentUid] =
37
+ nested === true || Object.keys(nested).length === 0 ? true : { populate: nested };
38
+ }
39
+ populate[name] = { on };
40
+ break;
41
+ }
42
+ default:
43
+ break;
44
+ }
45
+ }
46
+
47
+ return populate;
48
+ };
49
+
50
+ const controller = ({ strapi }: { strapi: Core.Strapi }) => ({
51
+ async getDynamicZoneData(ctx) {
52
+ const { contentType, id } = ctx.params;
53
+ const { locale, status } = ctx.query;
54
+
55
+ const model = strapi.getModel(contentType);
56
+ if (!model) {
57
+ return ctx.badRequest(`Unknown content type: ${contentType}`);
58
+ }
59
+
60
+ try {
61
+ const populate = buildDeepPopulate(strapi, contentType);
62
+
63
+ const hasDraftAndPublish = Boolean((model.options as any)?.draftAndPublish);
64
+ const isLocalized = Boolean((model.pluginOptions as any)?.i18n?.localized);
65
+
66
+ const document = await strapi.documents(contentType).findOne({
67
+ documentId: id,
68
+ populate: populate === true ? '*' : populate,
69
+ locale: isLocalized && locale ? locale : undefined,
70
+ status: hasDraftAndPublish ? (status === 'published' ? 'published' : 'draft') : undefined,
71
+ });
72
+
73
+ if (!document) {
74
+ return ctx.notFound('Document not found');
75
+ }
76
+
77
+ return ctx.send({ data: document });
78
+ } catch (error) {
79
+ strapi.log.error('dynamic-zone-tools: failed to fetch source document', error);
80
+ return ctx.internalServerError('Failed to fetch dynamic zone data');
81
+ }
82
+ },
83
+ });
84
+
85
+ export default controller;
@@ -0,0 +1,5 @@
1
+ import controller from './controller';
2
+
3
+ export default {
4
+ controller,
5
+ };
@@ -0,0 +1,7 @@
1
+ import type { Core } from '@strapi/strapi';
2
+
3
+ const destroy = ({ strapi }: { strapi: Core.Strapi }) => {
4
+ // destroy phase
5
+ };
6
+
7
+ export default destroy;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Application methods
3
+ */
4
+ import bootstrap from './bootstrap';
5
+ import destroy from './destroy';
6
+ import register from './register';
7
+
8
+ /**
9
+ * Plugin server methods
10
+ */
11
+ import config from './config';
12
+ import contentTypes from './content-types';
13
+ import controllers from './controllers';
14
+ import middlewares from './middlewares';
15
+ import policies from './policies';
16
+ import routes from './routes';
17
+ import services from './services';
18
+
19
+ export default {
20
+ register,
21
+ bootstrap,
22
+ destroy,
23
+ config,
24
+ controllers,
25
+ routes,
26
+ services,
27
+ contentTypes,
28
+ policies,
29
+ middlewares,
30
+ };
@@ -0,0 +1 @@
1
+ export default {};
@@ -0,0 +1 @@
1
+ export default {};
@@ -0,0 +1,7 @@
1
+ import type { Core } from '@strapi/strapi';
2
+
3
+ const register = ({ strapi }: { strapi: Core.Strapi }) => {
4
+ // register phase
5
+ };
6
+
7
+ export default register;
@@ -0,0 +1,18 @@
1
+ const policies = [
2
+ 'admin::isAuthenticatedAdmin',
3
+ {
4
+ name: 'admin::hasPermissions',
5
+ config: {
6
+ actions: ['plugin::dynamic-zone-tools.fill'],
7
+ },
8
+ },
9
+ ];
10
+
11
+ export default [
12
+ {
13
+ method: 'GET',
14
+ path: '/source-document/:contentType/:id',
15
+ handler: 'controller.getDynamicZoneData',
16
+ config: { policies },
17
+ },
18
+ ];
@@ -0,0 +1 @@
1
+ export default [];
@@ -0,0 +1,15 @@
1
+ import contentAPIRoutes from './content-api';
2
+ import adminAPIRoutes from './admin-api';
3
+
4
+ const routes = {
5
+ 'content-api': {
6
+ type: 'content-api',
7
+ routes: contentAPIRoutes,
8
+ },
9
+ 'admin': {
10
+ type: 'admin',
11
+ routes: adminAPIRoutes,
12
+ },
13
+ };
14
+
15
+ export default routes;
@@ -0,0 +1,5 @@
1
+ import service from './service';
2
+
3
+ export default {
4
+ service,
5
+ };
@@ -0,0 +1,9 @@
1
+ import type { Core } from '@strapi/strapi';
2
+
3
+ const service = ({ strapi }: { strapi: Core.Strapi }) => ({
4
+ getWelcomeMessage() {
5
+ return 'Welcome to Strapi 🚀';
6
+ },
7
+ });
8
+
9
+ export default service;