@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.
- package/.prettierignore +17 -0
- package/admin/src/api/collection-type.ts +110 -0
- package/admin/src/api/has-page-relation.ts +34 -0
- package/admin/src/api/page-type.ts +31 -0
- package/admin/src/api/template.ts +25 -0
- package/admin/src/components/Combobox/index.tsx +77 -0
- package/admin/src/components/Combobox/react-select-custom-styles.tsx +111 -0
- package/admin/src/components/Combobox/styles.ts +22 -0
- package/admin/src/components/ConfirmModal/index.tsx +90 -0
- package/admin/src/components/EditView/CollectionTypeSearch/index.tsx +118 -0
- package/admin/src/components/EditView/CollectionTypeSettings/CreatePageButton/index.tsx +95 -0
- package/admin/src/components/EditView/CollectionTypeSettings/CreatePageButton/styles.ts +26 -0
- package/admin/src/components/EditView/CollectionTypeSettings/index.tsx +53 -0
- package/admin/src/components/EditView/Details/index.tsx +47 -0
- package/admin/src/components/EditView/Details/styles.ts +51 -0
- package/admin/src/components/EditView/PageSettings/index.tsx +104 -0
- package/admin/src/components/EditView/Template/TemplateConfirmModal/index.tsx +36 -0
- package/admin/src/components/EditView/Template/TemplateSelect/index.tsx +64 -0
- package/admin/src/components/EditView/Template/TemplateSelect/use-template-modules.ts +30 -0
- package/admin/src/components/EditView/index.tsx +27 -0
- package/admin/src/components/EditView/page-type-select.tsx +30 -0
- package/admin/src/components/EditView/wrapper.tsx +35 -0
- package/admin/src/components/Initializer/index.tsx +24 -0
- package/admin/src/components/PageTypeFilter/index.tsx +17 -0
- package/admin/src/components/PageTypeFilter/page-type-filter.tsx +130 -0
- package/admin/src/components/PluginIcon/index.tsx +12 -0
- package/admin/src/constants.ts +1 -0
- package/admin/src/index.tsx +115 -0
- package/admin/src/pages/App/index.tsx +25 -0
- package/admin/src/pages/HomePage/index.tsx +19 -0
- package/admin/src/pluginId.ts +5 -0
- package/admin/src/redux/initialData.reducer.ts +0 -0
- package/admin/src/translations/en.json +6 -0
- package/admin/src/translations/nl.json +6 -0
- package/admin/src/utils/getRequestUrl.ts +11 -0
- package/admin/src/utils/getTrad.ts +5 -0
- package/admin/src/utils/hooks/useDebounce.ts +17 -0
- package/admin/src/utils/hooks/useGetLocaleFromUrl.ts +9 -0
- package/admin/src/utils/hooks/usePrevious.ts +12 -0
- package/admin/src/utils/sanitizeModules.ts +10 -0
- package/custom.d.ts +5 -0
- package/dist/package.json +1 -1
- package/dist/tsconfig.server.tsbuildinfo +1 -1
- package/package.json +1 -5
- package/server/bootstrap.ts +106 -0
- package/server/config/index.ts +4 -0
- package/server/content-types/index.ts +1 -0
- package/server/controllers/collection-types.ts +27 -0
- package/server/controllers/index.ts +9 -0
- package/server/controllers/page-type.ts +12 -0
- package/server/controllers/page.ts +20 -0
- package/server/destroy.ts +5 -0
- package/server/index.ts +23 -0
- package/server/middlewares/index.ts +1 -0
- package/server/policies/index.ts +1 -0
- package/server/register.ts +5 -0
- package/server/routes/index.ts +42 -0
- package/server/schema/page-end.json +97 -0
- package/server/schema/page-start.json +87 -0
- package/server/schema/page-type-end.json +49 -0
- package/server/schema/page-type-start.json +44 -0
- package/server/schema/template.json +35 -0
- package/server/services/builder.ts +121 -0
- package/server/services/collection-types.ts +49 -0
- package/server/services/index.ts +11 -0
- package/server/services/page-type.ts +22 -0
- package/server/services/page.ts +24 -0
- package/server/utils/graphql.ts +110 -0
- package/server/utils/reload-strapi-on-load.ts +13 -0
- package/shared/utils/constants.ts +4 -0
- package/shared/utils/sleep.ts +1 -0
- package/strapi-admin.js +3 -0
- package/strapi-server.js +3 -0
- package/tsconfig.json +20 -0
- 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 @@
|
|
|
1
|
+
export const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
package/strapi-admin.js
ADDED
package/strapi-server.js
ADDED
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
|
+
}
|