@webbio/strapi-plugin-page-builder 0.0.12 → 0.0.13

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 (75) hide show
  1. package/.prettierignore +17 -0
  2. package/admin/src/api/collection-type.ts +110 -0
  3. package/admin/src/api/has-page-relation.ts +34 -0
  4. package/admin/src/api/page-type.ts +31 -0
  5. package/admin/src/api/template.ts +25 -0
  6. package/admin/src/components/Combobox/index.tsx +77 -0
  7. package/admin/src/components/Combobox/react-select-custom-styles.tsx +111 -0
  8. package/admin/src/components/Combobox/styles.ts +22 -0
  9. package/admin/src/components/ConfirmModal/index.tsx +90 -0
  10. package/admin/src/components/EditView/CollectionTypeSearch/index.tsx +118 -0
  11. package/admin/src/components/EditView/CollectionTypeSettings/CreatePageButton/index.tsx +95 -0
  12. package/admin/src/components/EditView/CollectionTypeSettings/CreatePageButton/styles.ts +26 -0
  13. package/admin/src/components/EditView/CollectionTypeSettings/index.tsx +53 -0
  14. package/admin/src/components/EditView/Details/index.tsx +47 -0
  15. package/admin/src/components/EditView/Details/styles.ts +51 -0
  16. package/admin/src/components/EditView/PageSettings/index.tsx +104 -0
  17. package/admin/src/components/EditView/Template/TemplateConfirmModal/index.tsx +36 -0
  18. package/admin/src/components/EditView/Template/TemplateSelect/index.tsx +64 -0
  19. package/admin/src/components/EditView/Template/TemplateSelect/use-template-modules.ts +30 -0
  20. package/admin/src/components/EditView/index.tsx +27 -0
  21. package/admin/src/components/EditView/page-type-select.tsx +30 -0
  22. package/admin/src/components/EditView/wrapper.tsx +35 -0
  23. package/admin/src/components/Initializer/index.tsx +24 -0
  24. package/admin/src/components/PageTypeFilter/index.tsx +17 -0
  25. package/admin/src/components/PageTypeFilter/page-type-filter.tsx +130 -0
  26. package/admin/src/components/PluginIcon/index.tsx +12 -0
  27. package/admin/src/constants.ts +1 -0
  28. package/admin/src/index.tsx +115 -0
  29. package/admin/src/pages/App/index.tsx +25 -0
  30. package/admin/src/pages/HomePage/index.tsx +19 -0
  31. package/admin/src/pluginId.ts +5 -0
  32. package/admin/src/redux/initialData.reducer.ts +0 -0
  33. package/admin/src/translations/en.json +6 -0
  34. package/admin/src/translations/nl.json +6 -0
  35. package/admin/src/utils/getRequestUrl.ts +11 -0
  36. package/admin/src/utils/getTrad.ts +5 -0
  37. package/admin/src/utils/hooks/useDebounce.ts +17 -0
  38. package/admin/src/utils/hooks/useGetLocaleFromUrl.ts +9 -0
  39. package/admin/src/utils/hooks/usePrevious.ts +12 -0
  40. package/admin/src/utils/sanitizeModules.ts +10 -0
  41. package/custom.d.ts +5 -0
  42. package/dist/package.json +1 -1
  43. package/dist/tsconfig.server.tsbuildinfo +1 -1
  44. package/package.json +1 -5
  45. package/server/bootstrap.ts +106 -0
  46. package/server/config/index.ts +4 -0
  47. package/server/content-types/index.ts +1 -0
  48. package/server/controllers/collection-types.ts +27 -0
  49. package/server/controllers/index.ts +9 -0
  50. package/server/controllers/page-type.ts +12 -0
  51. package/server/controllers/page.ts +20 -0
  52. package/server/destroy.ts +5 -0
  53. package/server/index.ts +23 -0
  54. package/server/middlewares/index.ts +1 -0
  55. package/server/policies/index.ts +1 -0
  56. package/server/register.ts +5 -0
  57. package/server/routes/index.ts +42 -0
  58. package/server/schema/page-end.json +97 -0
  59. package/server/schema/page-start.json +87 -0
  60. package/server/schema/page-type-end.json +49 -0
  61. package/server/schema/page-type-start.json +44 -0
  62. package/server/schema/template.json +35 -0
  63. package/server/services/builder.ts +121 -0
  64. package/server/services/collection-types.ts +49 -0
  65. package/server/services/index.ts +11 -0
  66. package/server/services/page-type.ts +22 -0
  67. package/server/services/page.ts +24 -0
  68. package/server/utils/graphql.ts +110 -0
  69. package/server/utils/reload-strapi-on-load.ts +13 -0
  70. package/shared/utils/constants.ts +4 -0
  71. package/shared/utils/sleep.ts +1 -0
  72. package/strapi-admin.js +3 -0
  73. package/strapi-server.js +3 -0
  74. package/tsconfig.json +20 -0
  75. package/tsconfig.server.json +25 -0
@@ -0,0 +1,121 @@
1
+ import partition from 'lodash/partition';
2
+
3
+ import { Service } from '@strapi/strapi/lib/types/core/common';
4
+
5
+ import pageStart from '../schema/page-start.json';
6
+ import pageEnd from '../schema/page-end.json';
7
+ import pluginId from '../../admin/src/pluginId';
8
+ import { PAGE_UID, TEMPLATE_UID, PAGE_TYPE_UID } from '../../shared/utils/constants';
9
+ import { reloadStrapiOnLoad } from '../utils/reload-strapi-on-load';
10
+ import pageTypeStart from '../schema/page-type-start.json';
11
+ import pageTypeEnd from '../schema/page-type-end.json';
12
+ import template from '../schema/template.json';
13
+
14
+ const UIDS = [TEMPLATE_UID, PAGE_TYPE_UID, PAGE_UID];
15
+
16
+ export default {
17
+ async buildContentTypes() {
18
+ this.listenToCreatedContentTypes();
19
+
20
+ await this.createContentTypes();
21
+
22
+ await this.updateContentTypes();
23
+ },
24
+ listenToCreatedContentTypes() {
25
+ strapi.eventHub.on('content-type.create', async (e) => {
26
+ if (e.contentType.uid === PAGE_UID) {
27
+ reloadStrapiOnLoad();
28
+ }
29
+ });
30
+ },
31
+
32
+ async createContentTypes() {
33
+ const newContentTypes = UIDS.filter((c) => !Boolean(strapi.contentType(c))).map(
34
+ (c) => this.getContentType(c)?.create
35
+ );
36
+
37
+ await this.synchronizeContentTypes(newContentTypes);
38
+ },
39
+ async updateContentTypes() {
40
+ const updateContentTypes = UIDS.filter((c) => Boolean(strapi.contentType(c))).map(
41
+ (c) => this.getContentType(c).update
42
+ );
43
+
44
+ await this.synchronizeContentTypes(updateContentTypes);
45
+ },
46
+ async synchronizeContentTypes(contentTypes: { uid: string; contentType: Record<string, any> }[]) {
47
+ const ctb = strapi.service('plugin::content-type-builder.content-types') as Service;
48
+
49
+ const [oldTypes, newTypes] = partition(contentTypes, (c) => Boolean(strapi.contentType(c.uid)));
50
+
51
+ if (newTypes.length > 0) {
52
+ console.log(
53
+ '[Plugin Page Builder]: Creating content types',
54
+ newTypes.map((x) => x.uid)
55
+ );
56
+ }
57
+
58
+ if (oldTypes.length > 0) {
59
+ console.log(
60
+ '[Plugin Page Builder]: Updating content types',
61
+ oldTypes.map((x) => x.uid)
62
+ );
63
+ }
64
+
65
+ if ((newTypes || []).length > 0) {
66
+ await ctb.createContentTypes(newTypes.map((c) => ({ contentType: c.contentType, components: [] })));
67
+ }
68
+
69
+ if ((oldTypes || []).length > 0) {
70
+ for (const oldType of oldTypes) {
71
+ await ctb.editContentType(oldType.uid, { contentType: oldType.contentType, components: [] });
72
+ }
73
+ }
74
+ },
75
+ getContentType(uid: string) {
76
+ const contentTypes = {
77
+ [PAGE_UID]: {
78
+ create: this.getPageContentType(true),
79
+ update: this.getPageContentType()
80
+ },
81
+ [PAGE_TYPE_UID]: {
82
+ create: this.getPageTypeContentType(true),
83
+ update: this.getPageTypeContentType()
84
+ },
85
+ [TEMPLATE_UID]: {
86
+ create: this.getTemplateContentType(),
87
+ update: this.getTemplateContentType()
88
+ }
89
+ };
90
+
91
+ return contentTypes?.[uid];
92
+ },
93
+ getPageContentType(create?: boolean) {
94
+ const page = create ? pageStart : pageEnd;
95
+ const contentType = this.addModulesToCollectionType(page);
96
+
97
+ return { uid: PAGE_UID, contentType };
98
+ },
99
+ getPageTypeContentType(create?: boolean) {
100
+ const pageType = create ? pageTypeStart : pageTypeEnd;
101
+ const contentType = this.addModulesToCollectionType(pageType);
102
+
103
+ return { uid: PAGE_TYPE_UID, contentType };
104
+ },
105
+ getTemplateContentType() {
106
+ const contentType = this.addModulesToCollectionType(template);
107
+
108
+ return { uid: TEMPLATE_UID, contentType };
109
+ },
110
+ addModulesToCollectionType(collectionType: Record<string, any>) {
111
+ const components = this.getConfigModuleComponents();
112
+
113
+ return {
114
+ ...collectionType,
115
+ attributes: { ...collectionType.attributes, modules: { ...collectionType.attributes.modules, components } }
116
+ };
117
+ },
118
+ getConfigModuleComponents() {
119
+ return (strapi.config.get(`plugin.${pluginId}`)?.modules || []).filter(Boolean);
120
+ }
121
+ };
@@ -0,0 +1,49 @@
1
+ import { Strapi } from '@strapi/strapi';
2
+ import uniqBy from 'lodash/uniqBy';
3
+
4
+ import { IGetTranslationPageLinks } from '../controllers/collection-types';
5
+
6
+ export default {
7
+ async hasPageRelation(uid: string): Promise<{ hasPageRelation: boolean }> {
8
+ const contentType = strapi.contentTypes?.[uid];
9
+
10
+ return {
11
+ hasPageRelation: Boolean(
12
+ contentType?.attributes?.page && contentType?.attributes?.page?.morphBy === 'collectionTypeData'
13
+ )
14
+ };
15
+ },
16
+ async getTranslationPageLinks(uid: string, ids: string[]) {
17
+ try {
18
+ const entities = await (strapi as Strapi).entityService.findMany(uid, {
19
+ filters: {
20
+ id: { $in: ids }
21
+ },
22
+ populate: {
23
+ page: {
24
+ populate: {
25
+ localizations: true
26
+ }
27
+ }
28
+ }
29
+ });
30
+
31
+ let pages: IGetTranslationPageLinks[] = [];
32
+
33
+ // Get all pages linked to the entity
34
+ entities?.forEach((x: any) => {
35
+ x?.page?.forEach((p: any) => {
36
+ pages.push({ id: p.id, locale: p.locale });
37
+
38
+ p.localizations.forEach((l: any) => {
39
+ pages.push({ id: l.id, locale: l.locale });
40
+ });
41
+ });
42
+ });
43
+
44
+ return uniqBy(pages, 'id');
45
+ } catch {
46
+ return [];
47
+ }
48
+ }
49
+ };
@@ -0,0 +1,11 @@
1
+ import page from './page';
2
+ import builder from './builder';
3
+ import pageType from './page-type';
4
+ import collectionTypes from './collection-types';
5
+
6
+ export default {
7
+ page,
8
+ builder,
9
+ 'page-type': pageType,
10
+ 'collection-types': collectionTypes
11
+ };
@@ -0,0 +1,22 @@
1
+ export default {
2
+ async findOneByUid(uid: string) {
3
+ const result = await strapi.entityService.findMany('api::page-type.page-type', {
4
+ populate: {
5
+ template: {
6
+ populate: {
7
+ modules: true
8
+ }
9
+ }
10
+ },
11
+ filters: {
12
+ uid
13
+ }
14
+ });
15
+
16
+ if (result.length > 0) {
17
+ return result[0];
18
+ } else {
19
+ return null;
20
+ }
21
+ }
22
+ };
@@ -0,0 +1,24 @@
1
+ import { PAGE_UID } from '../../shared/utils/constants';
2
+
3
+ export default {
4
+ async getPage(id: string) {
5
+ // @ts-ignore
6
+ const page = await strapi.db.query(PAGE_UID).findOne({
7
+ // @ts-ignore
8
+ select: 'id',
9
+ populate: {
10
+ // @ts-ignore
11
+ collectionTypeData: true,
12
+ pageType: true
13
+ },
14
+ where: {
15
+ id
16
+ }
17
+ });
18
+
19
+ return {
20
+ pageType: page.pageType,
21
+ collectionTypeData: page.collectionTypeData?.[0] ?? null
22
+ };
23
+ }
24
+ };
@@ -0,0 +1,110 @@
1
+ import { Strapi } from '@strapi/strapi';
2
+ import { PAGE_UID } from '../../shared/utils/constants';
3
+
4
+ const findPageByPath = (strapi: Strapi) => {
5
+ const typeDefs = `
6
+ type Query {
7
+ findPageByPath(path: String, locale: I18NLocaleCode): PageEntityResponse
8
+ }
9
+ `;
10
+
11
+ const resolvers = (strapi: Strapi) => {
12
+ const { transformArgs } = strapi.plugin('graphql').service('builders').utils;
13
+ const { toEntityResponse, toEntityResponseCollection } = strapi.plugin('graphql').service('format').returnTypes;
14
+
15
+ return {
16
+ Query: {
17
+ findPageByPath: {
18
+ resolve: async (parent: any, args: Record<string, any>, ctx: any) => {
19
+ const contentType = strapi.getModel(PAGE_UID);
20
+ const transformedArgs = transformArgs(args, { contentType });
21
+
22
+ const queryResult = await strapi.entityService.findMany(contentType.uid, {
23
+ filters: {
24
+ path: {
25
+ $eq: transformedArgs.path
26
+ }
27
+ },
28
+ locale: transformedArgs.locale
29
+ });
30
+
31
+ const result = queryResult?.[0];
32
+ return toEntityResponse(result, { args: transformedArgs, resourceUID: contentType.uid });
33
+ }
34
+ }
35
+ }
36
+ };
37
+ };
38
+
39
+ const resolversConfig = {
40
+ 'Query.findPageByPath': {
41
+ auth: false
42
+ }
43
+ };
44
+
45
+ return {
46
+ typeDefs,
47
+ resolvers: resolvers(strapi),
48
+ resolversConfig
49
+ };
50
+ };
51
+
52
+ const findPagePaths = (strapi: Strapi) => {
53
+ const typeDefs = `
54
+ type PageByPath {
55
+ id: Int!
56
+ path: String!
57
+ title: String!
58
+ locale: String!
59
+ pageType: ENUM_PAGE_PAGETYPE
60
+ updatedAt: DateTime!
61
+ publishedAt: DateTime!
62
+ }
63
+
64
+ type Query {
65
+ findPagePaths(locale: String, pageType: String = "all"): [PageByPath]
66
+ }
67
+ `;
68
+
69
+ const resolvers = (strapi: Strapi) => {
70
+ const { transformArgs } = strapi.plugin('graphql').service('builders').utils;
71
+
72
+ return {
73
+ Query: {
74
+ findPagePaths: {
75
+ resolve: async (parent: any, args: Record<string, any>, ctx: any) => {
76
+ const contentType = strapi.getModel(PAGE_UID);
77
+ const transformedArgs = transformArgs(args, { contentType });
78
+
79
+ const queryResult = await strapi.entityService.findMany(contentType.uid, {
80
+ populate: '*',
81
+ locale: transformedArgs.locale
82
+ });
83
+
84
+ const result = queryResult.filter((page) => page?.path);
85
+
86
+ return result;
87
+ }
88
+ }
89
+ }
90
+ };
91
+ };
92
+
93
+ const resolversConfig = {
94
+ 'Query.findPagePaths': {
95
+ auth: false
96
+ }
97
+ };
98
+
99
+ return {
100
+ typeDefs,
101
+ resolvers: resolvers(strapi),
102
+ resolversConfig
103
+ };
104
+ };
105
+
106
+ export const registerGraphQLResolvers = (strapi: Strapi) => {
107
+ const extensionService = strapi.plugin('graphql').service('extension');
108
+ extensionService.use(findPageByPath(strapi));
109
+ extensionService.use(findPagePaths(strapi));
110
+ };
@@ -0,0 +1,13 @@
1
+ const reloadStrapiOnLoad = () => {
2
+ console.log('[Plugin Page Builder]: Checking if strapi is loaded', strapi.isLoaded);
3
+
4
+ if (strapi.isLoaded) {
5
+ strapi.reload();
6
+
7
+ return;
8
+ }
9
+
10
+ setTimeout(reloadStrapiOnLoad, 1000);
11
+ };
12
+
13
+ export { reloadStrapiOnLoad };
@@ -0,0 +1,4 @@
1
+ export const PAGE_UID = 'api::page.page';
2
+ export const TEMPLATE_UID = 'api::template.template';
3
+ export const PAGE_TYPE_UID = 'api::page-type.page-type';
4
+ export const PAGE_TYPE_PAGE = 'page';
@@ -0,0 +1 @@
1
+ export const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+
3
+ module.exports = require('./admin/src').default;
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+
3
+ module.exports = require('./dist/server');
package/tsconfig.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "extends": "@strapi/typescript-utils/tsconfigs/admin",
3
+
4
+ "compilerOptions": {
5
+ "target": "ESNext",
6
+ "strict": true
7
+ },
8
+
9
+ "include": ["admin", "custom.d.ts"],
10
+
11
+ "exclude": [
12
+ "node_modules/",
13
+ "dist/",
14
+
15
+ // Do not include server files in the server compilation
16
+ "server/",
17
+ // Do not include test files
18
+ "**/*.test.ts"
19
+ ]
20
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "extends": "@strapi/typescript-utils/tsconfigs/server",
3
+
4
+ "compilerOptions": {
5
+ "outDir": "dist",
6
+ "rootDir": "."
7
+ },
8
+
9
+ "include": [
10
+ // Include the root directory
11
+ "server",
12
+ // Force the JSON files in the src folder to be included
13
+ "server/**/*.json"
14
+ ],
15
+
16
+ "exclude": [
17
+ "node_modules/",
18
+ "dist/",
19
+
20
+ // Do not include admin files in the server compilation
21
+ "admin/",
22
+ // Do not include test files
23
+ "**/*.test.ts"
24
+ ]
25
+ }