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

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 +59 -0
  29. package/admin/src/middlewares/index.tsx +37 -0
  30. package/admin/src/pluginId.ts +5 -0
  31. package/admin/src/translations/en.json +6 -0
  32. package/admin/src/translations/nl.json +6 -0
  33. package/admin/src/utils/getRequestUrl.ts +11 -0
  34. package/admin/src/utils/getTrad.ts +5 -0
  35. package/admin/src/utils/hooks/useDebounce.ts +17 -0
  36. package/admin/src/utils/hooks/useGetLocaleFromUrl.ts +9 -0
  37. package/admin/src/utils/hooks/usePrevious.ts +12 -0
  38. package/admin/src/utils/sanitizeModules.ts +10 -0
  39. package/custom.d.ts +5 -0
  40. package/dist/package.json +1 -1
  41. package/dist/server/services/builder.js +14 -5
  42. package/dist/tsconfig.server.tsbuildinfo +1 -1
  43. package/package.json +1 -5
  44. package/server/bootstrap.ts +106 -0
  45. package/server/config/index.ts +4 -0
  46. package/server/content-types/index.ts +1 -0
  47. package/server/controllers/collection-types.ts +27 -0
  48. package/server/controllers/index.ts +9 -0
  49. package/server/controllers/page-type.ts +12 -0
  50. package/server/controllers/page.ts +20 -0
  51. package/server/destroy.ts +5 -0
  52. package/server/index.ts +23 -0
  53. package/server/middlewares/index.ts +1 -0
  54. package/server/policies/index.ts +1 -0
  55. package/server/register.ts +5 -0
  56. package/server/routes/index.ts +42 -0
  57. package/server/schema/page-end.json +97 -0
  58. package/server/schema/page-start.json +87 -0
  59. package/server/schema/page-type-end.json +49 -0
  60. package/server/schema/page-type-start.json +44 -0
  61. package/server/schema/template.json +35 -0
  62. package/server/services/builder.ts +134 -0
  63. package/server/services/collection-types.ts +49 -0
  64. package/server/services/index.ts +11 -0
  65. package/server/services/page-type.ts +22 -0
  66. package/server/services/page.ts +24 -0
  67. package/server/utils/graphql.ts +110 -0
  68. package/server/utils/reload-strapi-on-load.ts +13 -0
  69. package/shared/utils/constants.ts +4 -0
  70. package/shared/utils/sleep.ts +1 -0
  71. package/strapi-admin.js +3 -0
  72. package/strapi-server.js +3 -0
  73. package/tsconfig.json +20 -0
  74. package/tsconfig.server.json +25 -0
  75. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,130 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import set from 'lodash/set';
3
+
4
+ import { SingleSelectOption, SingleSelect } from '@strapi/design-system';
5
+ import { useQueryParams } from '@strapi/helper-plugin';
6
+
7
+ import { useGetPageTypes } from '../../api/page-type';
8
+ import { PAGE_TYPE_NO_FILTER } from '../../constants';
9
+ import { PAGE_TYPE_PAGE } from '../../../../shared/utils/constants';
10
+
11
+ const PageTypeFilter = () => {
12
+ const [{ query }, setQuery] = useQueryParams();
13
+ const { data: pageTypes } = useGetPageTypes({});
14
+ const initialPageTypeUid = getInitialPageType(query, pageTypes);
15
+ const [selectedPageTypeUid, setSelectedPageTypeUid] = useState(initialPageTypeUid);
16
+
17
+ const removeFilters = () => {
18
+ const newAndFilters = query.filters?.$and?.filter(
19
+ (x?: Record<string, any>) => Object.keys(x || {})?.[0] !== 'pageType'
20
+ );
21
+ const filters = { ...query.filters, $and: newAndFilters };
22
+
23
+ if (newAndFilters && newAndFilters.length === 0) {
24
+ delete filters.$and;
25
+ }
26
+
27
+ setQuery({
28
+ page: 1,
29
+ filters
30
+ });
31
+ };
32
+
33
+ const handleFilterChange = (filters: Record<string, any>) => {
34
+ const currentFilters = query.filters?.$and ? query.filters : { ...query.filters, $and: [] }; // Make sure $and exists.
35
+ const pageTypeFilterIndex = currentFilters.$and.findIndex(
36
+ (x?: Record<string, any>) => Object.keys(x || {})?.[0] === 'pageType'
37
+ );
38
+
39
+ if (pageTypeFilterIndex > -1) {
40
+ set(currentFilters, `$and[${pageTypeFilterIndex}]`, filters); // If the pageType filter already exists, replace it
41
+ } else {
42
+ currentFilters.$and.push(filters);
43
+ }
44
+
45
+ setQuery({
46
+ page: 1,
47
+ filters: currentFilters
48
+ });
49
+ };
50
+
51
+ const handleSelect = (value: string) => {
52
+ setSelectedPageTypeUid(value);
53
+
54
+ if (value === 'all') {
55
+ removeFilters();
56
+ return;
57
+ }
58
+
59
+ if (value === PAGE_TYPE_PAGE) {
60
+ handleFilterChange(nullPageTypeQueryFilter);
61
+ return;
62
+ }
63
+
64
+ handleFilterChange(getPageTypeQueryFilter(value));
65
+ };
66
+
67
+ useEffect(() => {
68
+ setSelectedPageTypeUid(getInitialPageType(query, pageTypes));
69
+ }, [pageTypes]);
70
+
71
+ useEffect(() => {
72
+ if (!query?.filters) {
73
+ setSelectedPageTypeUid(null);
74
+ }
75
+ }, [query]);
76
+
77
+ return (
78
+ <SingleSelect placeholder="Select page type" onChange={handleSelect} size="S" value={selectedPageTypeUid}>
79
+ <SingleSelectOption key={PAGE_TYPE_NO_FILTER} value={PAGE_TYPE_NO_FILTER}>
80
+ All Pagetypes
81
+ </SingleSelectOption>
82
+ <SingleSelectOption key={PAGE_TYPE_PAGE} value={PAGE_TYPE_PAGE}>
83
+ Page
84
+ </SingleSelectOption>
85
+ {pageTypes?.map((pageType) => (
86
+ <SingleSelectOption key={pageType.uid} value={pageType.uid}>
87
+ {pageType.title || pageType.uid}
88
+ </SingleSelectOption>
89
+ ))}
90
+ </SingleSelect>
91
+ );
92
+ };
93
+
94
+ export { PageTypeFilter };
95
+
96
+ const getPageTypeQueryFilter = (pageType: string) => ({
97
+ pageType: {
98
+ uid: {
99
+ $eq: pageType
100
+ }
101
+ }
102
+ });
103
+
104
+ const nullPageTypeQueryFilter = {
105
+ pageType: {
106
+ uid: {
107
+ $null: true
108
+ }
109
+ }
110
+ };
111
+
112
+ const getInitialPageType = (query: any, pageTypes: any) => {
113
+ const pageTypeFromQuery = query?.filters?.$and?.find(
114
+ (x?: Record<string, any>) => Object.keys(x || {})?.[0] === 'pageType'
115
+ )?.pageType;
116
+
117
+ if (pageTypeFromQuery?.uid?.$null === 'true') {
118
+ return PAGE_TYPE_PAGE;
119
+ }
120
+
121
+ if (pageTypeFromQuery?.uid?.$eq) {
122
+ const matchingPageType = pageTypes?.find((pageType: any) => pageType?.uid === pageTypeFromQuery.uid.$eq);
123
+
124
+ if (matchingPageType) {
125
+ return matchingPageType.uid;
126
+ }
127
+ }
128
+
129
+ return PAGE_TYPE_NO_FILTER;
130
+ };
@@ -0,0 +1,12 @@
1
+ /**
2
+ *
3
+ * PluginIcon
4
+ *
5
+ */
6
+
7
+ import React from 'react';
8
+ import { Puzzle } from '@strapi/icons';
9
+
10
+ const PluginIcon = () => <Puzzle />;
11
+
12
+ export default PluginIcon;
@@ -0,0 +1 @@
1
+ export const PAGE_TYPE_NO_FILTER = 'all';
@@ -0,0 +1,59 @@
1
+ import { prefixPluginTranslations } from '@strapi/helper-plugin';
2
+
3
+ import pluginPkg from '../../package.json';
4
+ import pluginId from './pluginId';
5
+ import Initializer from './components/Initializer';
6
+ import PageTypeFilter from './components/PageTypeFilter';
7
+ import { EditView } from './components/EditView';
8
+ import middlewares from './middlewares';
9
+
10
+ const name = pluginPkg.strapi.name;
11
+
12
+ export default {
13
+ register(app: any) {
14
+ app.addMiddlewares(middlewares);
15
+ const plugin = {
16
+ id: pluginId,
17
+ initializer: Initializer,
18
+ isReady: false,
19
+ name
20
+ };
21
+
22
+ app.registerPlugin(plugin);
23
+ },
24
+
25
+ bootstrap(app: any) {
26
+ app.injectContentManagerComponent('editView', 'right-links', {
27
+ name: 'collection-type-picker',
28
+ Component: EditView
29
+ });
30
+ app.injectContentManagerComponent('listView', 'actions', {
31
+ name: 'page-type-filter',
32
+ Component: PageTypeFilter
33
+ });
34
+ },
35
+
36
+ async registerTrads(app: any) {
37
+ const { locales } = app;
38
+
39
+ const importedTrads = await Promise.all(
40
+ (locales as string[]).map((locale) => {
41
+ return import(`./translations/${locale}.json`)
42
+ .then(({ default: data }) => {
43
+ return {
44
+ data: prefixPluginTranslations(data, pluginId),
45
+ locale
46
+ };
47
+ })
48
+ .catch(() => {
49
+ return {
50
+ data: {},
51
+ locale
52
+ };
53
+ });
54
+ })
55
+ );
56
+
57
+ return Promise.resolve(importedTrads);
58
+ }
59
+ };
@@ -0,0 +1,37 @@
1
+ import { getFetchClient } from '@strapi/helper-plugin';
2
+
3
+ import { PAGE_UID } from '../../../shared/utils/constants';
4
+ import getRequestUrl from '../utils/getRequestUrl';
5
+
6
+ const middleware =
7
+ () =>
8
+ ({ getState }: any) =>
9
+ (next: any) =>
10
+ async (action: any) => {
11
+ // If data is being fetched or after a save
12
+ if (
13
+ action.type === 'ContentManager/CrudReducer/GET_DATA_SUCCEEDED' ||
14
+ action.type === 'ContentManager/CrudReducer/SUBMIT_SUCCEEDED'
15
+ ) {
16
+ const store = getState();
17
+ const layoutSlice = store['content-manager_editViewLayoutManager'];
18
+ const uid = layoutSlice.currentLayout.contentType.uid;
19
+
20
+ if (uid !== PAGE_UID) {
21
+ return next(action);
22
+ }
23
+
24
+ const { get } = await getFetchClient();
25
+ const { data: pageData } = await get(`${getRequestUrl('page')}/${action.data.id}`);
26
+
27
+ action.data.collectionTypeTitle = pageData?.collectionTypeData?.title;
28
+ action.data.collectionTypeId = pageData?.collectionTypeData?.id;
29
+ action.data.initialPageType = pageData?.pageType ? pageData.pageType : undefined;
30
+
31
+ return next(action);
32
+ }
33
+ return next(action);
34
+ };
35
+
36
+ const middlewares = [middleware];
37
+ export default middlewares;
@@ -0,0 +1,5 @@
1
+ import pluginPkg from '../../package.json';
2
+
3
+ const pluginId = pluginPkg.strapi.name;
4
+
5
+ export default pluginId;
@@ -0,0 +1,6 @@
1
+ {
2
+ "template.confirmModal.title": "Replace all page modules",
3
+ "template.confirmModal.body": "You are about to replace all modules on this page. Are you sure you want to continue?",
4
+ "template.confirmModal.buttons.cancel": "No, cancel",
5
+ "template.confirmModal.buttons.submit": "Yes, replace all"
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "template.confirmModal.title": "Pagina modules vervangen",
3
+ "template.confirmModal.body": "Weet je zeker dat je alle modules op deze pagina wilt vervangen?",
4
+ "template.confirmModal.buttons.cancel": "Nee, annuleer",
5
+ "template.confirmModal.buttons.submit": "Ja, vervang modules"
6
+ }
@@ -0,0 +1,11 @@
1
+ import pluginId from '../pluginId';
2
+
3
+ const getRequestUrl = (path: string) => {
4
+ if (path.startsWith('/')) {
5
+ return `/${pluginId}${path}`;
6
+ }
7
+
8
+ return `/${pluginId}/${path}`;
9
+ };
10
+
11
+ export default getRequestUrl;
@@ -0,0 +1,5 @@
1
+ import pluginId from '../pluginId';
2
+
3
+ const getTrad = (id: string) => `${pluginId}.${id}`;
4
+
5
+ export default getTrad;
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+
3
+ export function useDebounce<T>(value: T, delay: number): T {
4
+ const [debouncedValue, setDebouncedValue] = React.useState(value);
5
+
6
+ React.useEffect(() => {
7
+ const handler = setTimeout(() => {
8
+ setDebouncedValue(value);
9
+ }, delay);
10
+
11
+ return () => {
12
+ clearTimeout(handler);
13
+ };
14
+ }, [value, delay]);
15
+
16
+ return debouncedValue;
17
+ }
@@ -0,0 +1,9 @@
1
+ import { useQueryParams } from '@strapi/helper-plugin';
2
+
3
+ const useGetLocaleFromUrl = () => {
4
+ const [{ query }] = useQueryParams();
5
+
6
+ return query?.plugins?.i18n?.locale;
7
+ };
8
+
9
+ export { useGetLocaleFromUrl };
@@ -0,0 +1,12 @@
1
+ import { useRef, useEffect } from 'react';
2
+
3
+ // Hook
4
+ export const usePrevious = <T>(value: T): T | null => {
5
+ const ref: React.MutableRefObject<T | null> = useRef(null);
6
+
7
+ useEffect(() => {
8
+ ref.current = value;
9
+ }, [value]);
10
+
11
+ return ref.current;
12
+ };
@@ -0,0 +1,10 @@
1
+ export const sanitizeModules = (modules: Record<string, any>[]) => {
2
+ return modules?.map((module, idx) => {
3
+ delete module.id;
4
+
5
+ return {
6
+ ...module,
7
+ __temp_key__: idx
8
+ };
9
+ });
10
+ };
package/custom.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ declare module '@strapi/design-system/*';
2
+ declare module '@strapi/design-system';
3
+ declare module '@strapi/icons';
4
+ declare module '@strapi/icons/*';
5
+ declare module '@strapi/helper-plugin';
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webbio/strapi-plugin-page-builder",
3
- "version": "0.0.5",
3
+ "version": "0.0.14",
4
4
  "description": "This is the description of the plugin.",
5
5
  "scripts": {
6
6
  "develop": "tsc -p tsconfig.server.json -w",
@@ -71,23 +71,32 @@ exports.default = {
71
71
  },
72
72
  getPageContentType(create) {
73
73
  const page = create ? page_start_json_1.default : page_end_json_1.default;
74
- const contentType = this.addModulesToCollectionType(page);
74
+ const contentType = this.mergeCollectionTypeWithModules(page, constants_1.PAGE_UID);
75
75
  return { uid: constants_1.PAGE_UID, contentType };
76
76
  },
77
77
  getPageTypeContentType(create) {
78
78
  const pageType = create ? page_type_start_json_1.default : page_type_end_json_1.default;
79
- const contentType = this.addModulesToCollectionType(pageType);
79
+ const contentType = this.mergeCollectionTypeWithModules(pageType, constants_1.PAGE_TYPE_UID);
80
80
  return { uid: constants_1.PAGE_TYPE_UID, contentType };
81
81
  },
82
82
  getTemplateContentType() {
83
- const contentType = this.addModulesToCollectionType(template_json_1.default);
83
+ const contentType = this.mergeCollectionTypeWithModules(template_json_1.default, constants_1.TEMPLATE_UID);
84
84
  return { uid: constants_1.TEMPLATE_UID, contentType };
85
85
  },
86
- addModulesToCollectionType(collectionType) {
86
+ mergeCollectionTypeWithModules(collectionType, uid) {
87
+ const { pluginOptions: oldPluginOptions, __schema__: { attributes: oldAttributes } } = strapi.contentType(constants_1.PAGE_UID) || {};
87
88
  const components = this.getConfigModuleComponents();
88
89
  return {
89
90
  ...collectionType,
90
- attributes: { ...collectionType.attributes, modules: { ...collectionType.attributes.modules, components } }
91
+ pluginOptions: {
92
+ ...oldPluginOptions,
93
+ ...collectionType === null || collectionType === void 0 ? void 0 : collectionType.pluginOptions
94
+ },
95
+ attributes: {
96
+ ...oldAttributes,
97
+ ...collectionType.attributes,
98
+ modules: { ...collectionType.attributes.modules, components }
99
+ }
91
100
  };
92
101
  },
93
102
  getConfigModuleComponents() {