@griddo/ax 11.10.23 → 11.10.24

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 (58) hide show
  1. package/config/griddo-config/index.js +1 -0
  2. package/package.json +2 -2
  3. package/src/Style/index.tsx +10 -8
  4. package/src/__tests__/components/ConfigPanel/ConfigPanel.test.tsx +10 -8
  5. package/src/__tests__/components/ConfigPanel/Form/ConnectedField/PageConnectedField/PageConnectedField.test.tsx +86 -8
  6. package/src/__tests__/components/SideModal/SideModal.test.tsx +64 -0
  7. package/src/__tests__/hooks/useSchemas.test.tsx +224 -0
  8. package/src/__tests__/services/SchemasService.test.ts +135 -0
  9. package/src/api/schemas.tsx +11 -1
  10. package/src/components/ConfigPanel/GlobalPageForm/index.tsx +11 -17
  11. package/src/components/Fields/Wysiwyg/helpers.tsx +14 -4
  12. package/src/components/Loader/components/Dots.js +4 -5
  13. package/src/components/PageFinder/index.tsx +15 -9
  14. package/src/components/ResizePanel/index.tsx +13 -3
  15. package/src/components/ResizePanel/style.tsx +2 -9
  16. package/src/containers/App/actions.tsx +96 -24
  17. package/src/containers/App/constants.tsx +7 -0
  18. package/src/containers/App/interfaces.tsx +26 -8
  19. package/src/containers/App/reducer.tsx +24 -9
  20. package/src/containers/Sites/actions.tsx +49 -49
  21. package/src/forms/editor.tsx +4 -3
  22. package/src/helpers/index.tsx +76 -94
  23. package/src/helpers/schemas.tsx +144 -36
  24. package/src/helpers/structuredData.tsx +36 -7
  25. package/src/helpers/themes.tsx +26 -8
  26. package/src/hooks/index.tsx +5 -0
  27. package/src/hooks/useSchemas.ts +151 -0
  28. package/src/locales/en-US.ts +1 -0
  29. package/src/locales/es-ES.ts +1 -0
  30. package/src/modules/Analytics/GroupPanel/index.tsx +9 -6
  31. package/src/modules/Analytics/GroupPanel/utils.tsx +12 -28
  32. package/src/modules/Content/PageItem/index.tsx +33 -36
  33. package/src/modules/Content/index.tsx +34 -30
  34. package/src/modules/Content/utils.tsx +16 -12
  35. package/src/modules/Forms/FormEditor/index.tsx +13 -14
  36. package/src/modules/FramePreview/index.tsx +8 -8
  37. package/src/modules/GlobalEditor/index.tsx +57 -42
  38. package/src/modules/MediaGallery/ImageModal/index.tsx +15 -9
  39. package/src/modules/MediaGallery/ImageModal/style.tsx +16 -1
  40. package/src/modules/PublicPreview/index.tsx +4 -3
  41. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/index.tsx +4 -5
  42. package/src/modules/Settings/Globals/index.tsx +10 -11
  43. package/src/modules/Sites/index.tsx +13 -5
  44. package/src/modules/StructuredData/Form/index.tsx +25 -29
  45. package/src/modules/StructuredData/StructuredDataList/OptionTable/index.tsx +15 -6
  46. package/src/modules/StructuredData/StructuredDataList/index.tsx +22 -14
  47. package/src/modules/StructuredData/StructuredDataList/utils.tsx +12 -11
  48. package/src/schemas/index.tsx +5 -4
  49. package/src/schemas/pages/Page.ts +308 -0
  50. package/src/schemas/pages/index.ts +9 -0
  51. package/src/services/SchemasService.ts +240 -0
  52. package/src/services/index.ts +9 -0
  53. package/src/types/index.tsx +48 -39
  54. package/tsconfig.paths.json +1 -0
  55. package/src/schemas/pages/Page.tsx +0 -301
  56. package/src/schemas/pages/index.tsx +0 -5
  57. /package/src/schemas/pages/{FormPage.tsx → FormPage.ts} +0 -0
  58. /package/src/schemas/pages/{GlobalPage.tsx → GlobalPage.ts} +0 -0
@@ -26,7 +26,15 @@ import {
26
26
  import { sitesActions } from "@ax/containers/Sites";
27
27
  import { structuredDataActions } from "@ax/containers/StructuredData";
28
28
  import { getMaxColumns, updateColumns } from "@ax/helpers";
29
- import { useBulkSelection, useCategoryColors, useModal, usePermission, useToast, useWindowSize } from "@ax/hooks";
29
+ import {
30
+ useBulkSelection,
31
+ useCategoryColors,
32
+ useModal,
33
+ usePermission,
34
+ useSchemasUI,
35
+ useToast,
36
+ useWindowSize,
37
+ } from "@ax/hooks";
30
38
  import type {
31
39
  ICheck,
32
40
  IColumn,
@@ -53,7 +61,6 @@ import GlobalPageItem from "./GlobalPageItem";
53
61
  import { useFilterQuery, useSortedListStatus } from "./hooks";
54
62
  import OptionTable from "./OptionTable";
55
63
  import StructuredDataItem from "./StructuredDataItem";
56
- import * as S from "./style";
57
64
  import {
58
65
  filterByStatus,
59
66
  getAllLangPagesIds,
@@ -64,6 +71,8 @@ import {
64
71
  getSortedListStatus,
65
72
  } from "./utils";
66
73
 
74
+ import * as S from "./style";
75
+
67
76
  const StructuredDataList = (props: IProps): JSX.Element => {
68
77
  const {
69
78
  setHistoryPush,
@@ -160,7 +169,7 @@ const StructuredDataList = (props: IProps): JSX.Element => {
160
169
  const scope = currentSiteID ? "site" : "global";
161
170
 
162
171
  const isDataEditable = filter === "all-pages" || !currentStructuredData || currentStructuredData.editable;
163
- const isDataTranslatable = currentStructuredData && currentStructuredData.translate;
172
+ const isDataTranslatable = currentStructuredData?.translate;
164
173
  const isAllPages = filter === "all-pages";
165
174
  const isStructuredDataFromPage = !!currentStructuredData?.fromPage || isAllPages;
166
175
  const isDataExportable = currentStructuredData?.exportable || false;
@@ -171,10 +180,9 @@ const StructuredDataList = (props: IProps): JSX.Element => {
171
180
  const [windowWidth] = useWindowSize();
172
181
  const maxColumns = getMaxColumns(windowWidth, !isStructuredDataFromPage);
173
182
 
174
- const categoryColumns: ISchemaField[] =
175
- currentStructuredData && currentStructuredData.schema
176
- ? currentStructuredData.schema.fields.filter((field: ISchemaField) => field.showList)
177
- : [];
183
+ const categoryColumns: ISchemaField[] = currentStructuredData?.schema
184
+ ? currentStructuredData.schema.fields.filter((field: ISchemaField) => field.showList)
185
+ : [];
178
186
 
179
187
  const type = currentStructuredData ? currentStructuredData.id : "all";
180
188
  const columns = getColumns(categoryColumns, isStructuredDataFromPage, isAllPages, maxColumns.value);
@@ -216,6 +224,8 @@ const StructuredDataList = (props: IProps): JSX.Element => {
216
224
  [getParams, getStructuredDataContents],
217
225
  );
218
226
 
227
+ const { schemas } = useSchemasUI();
228
+
219
229
  const handleGetGlobalPages = async () => {
220
230
  const params: IGetGlobalPagesParams = getParams();
221
231
  params.filterStructuredData = isStructuredDataFromPage && !isAllPages && filter;
@@ -472,7 +482,7 @@ const StructuredDataList = (props: IProps): JSX.Element => {
472
482
  }
473
483
  : undefined;
474
484
 
475
- const currentDataColumnsState = currentStructuredData ? columnsState[structuredDataType] || [] : columnsState["all"];
485
+ const currentDataColumnsState = currentStructuredData ? columnsState[structuredDataType] || [] : columnsState.all;
476
486
 
477
487
  const TableHeader = (
478
488
  <BulkHeader
@@ -530,7 +540,7 @@ const StructuredDataList = (props: IProps): JSX.Element => {
530
540
 
531
541
  const options: { filters: IStructuredDataFilter[]; values: IStructuredDataValue[] } = {
532
542
  filters: getOptionFilters(structuredData),
533
- values: getOptionValues(structuredData),
543
+ values: getOptionValues(structuredData, schemas),
534
544
  };
535
545
 
536
546
  const notEditableText =
@@ -557,8 +567,7 @@ const StructuredDataList = (props: IProps): JSX.Element => {
557
567
  const selectedValue = getSelectedValue(options, filter);
558
568
 
559
569
  const mapCurrentDataContent = () =>
560
- currentDataContent &&
561
- currentDataContent.map((sData: IStructuredDataContent) => {
570
+ currentDataContent?.map((sData: IStructuredDataContent) => {
562
571
  const isItemSelected = isSelected(sData.id);
563
572
  return (
564
573
  <StructuredDataItem
@@ -583,8 +592,7 @@ const StructuredDataList = (props: IProps): JSX.Element => {
583
592
  });
584
593
 
585
594
  const mapGlobalPages = () =>
586
- currentSitePages &&
587
- currentSitePages.map((globalPage: IPage) => {
595
+ currentSitePages?.map((globalPage: IPage) => {
588
596
  const isItemSelected = isSelected(globalPage.id);
589
597
  const relatedStructuredData = structuredData.global.find(
590
598
  (data: IStructuredData) => data.id === globalPage.structuredData,
@@ -738,7 +746,7 @@ const mapStateToProps = (state: IRootState) => ({
738
746
  totalItems: state.sites.totalItems,
739
747
  lang: state.app.lang,
740
748
  globalLangs: state.app.globalLangs,
741
- currentSiteID: state.sites.currentSiteInfo && state.sites.currentSiteInfo.id,
749
+ currentSiteID: state.sites.currentSiteInfo?.id || null,
742
750
  activatedDataPacks: state.dataPacks.activated,
743
751
  isLoading: state.app.isLoading,
744
752
  template: state.pageEditor.template,
@@ -1,6 +1,7 @@
1
1
  import { pageStatus } from "@ax/containers/PageEditor/interfaces";
2
2
  import { arrayInsert } from "@ax/helpers";
3
3
  import type { IBulkSelectedItems } from "@ax/hooks";
4
+ import type { IUISchemas } from "@ax/services";
4
5
  import type {
5
6
  IColumn,
6
7
  IPage,
@@ -11,11 +12,6 @@ import type {
11
12
  IStructuredDataValue,
12
13
  } from "@ax/types";
13
14
 
14
- import { config } from "components";
15
-
16
- const schemas = config.schemas.ui;
17
- const { templates } = schemas;
18
-
19
15
  const getOptionFilters = (options: { global: IStructuredData[]; site: IStructuredData[] }): IStructuredDataFilter[] => {
20
16
  const pageOptions = options.global.filter((option: IStructuredData) => option.fromPage);
21
17
 
@@ -52,8 +48,14 @@ const mapStructuredOptions = (options: { global: IStructuredData[]; site: IStruc
52
48
  });
53
49
  };
54
50
 
55
- const getOptionValues = (options: { global: IStructuredData[]; site: IStructuredData[] }): IStructuredDataValue[] => {
51
+ const getOptionValues = (
52
+ options: { global: IStructuredData[]; site: IStructuredData[] },
53
+ schemas: IUISchemas | null,
54
+ ): IStructuredDataValue[] => {
56
55
  const templatesOptionsValues: IStructuredDataValue[] = [];
56
+ const { templates } = schemas || {};
57
+
58
+ if (!templates) return [];
57
59
 
58
60
  Object.keys(templates).forEach((schema: string) => {
59
61
  const currSchema = templates[schema];
@@ -67,7 +69,7 @@ const getOptionValues = (options: { global: IStructuredData[]; site: IStructured
67
69
  isDetailTemplate &&
68
70
  templatesOptionsValues.push({
69
71
  name: component,
70
- title: displayName,
72
+ title: displayName || "",
71
73
  type,
72
74
  value: component,
73
75
  });
@@ -143,6 +145,8 @@ const getAllLangPagesIds = (
143
145
  const selectedPages = currentSitePages.filter((page: IPage) => selectedItems.all.includes(page.id));
144
146
  langsPagesIds = selectedPages.reduce((ids: number[], page: IPage) => {
145
147
  const langsPageIds = page.pageLanguages.map((lang: IPageLanguage) => lang.pageId);
148
+
149
+ // biome-ignore lint/performance/noAccumulatingSpread: TODO: fix this
146
150
  return [...ids, ...langsPageIds];
147
151
  }, []);
148
152
  }
@@ -167,10 +171,7 @@ const getColumns = (
167
171
  }
168
172
 
169
173
  if (isStructuredDataFromPage) {
170
- defaultColumns = [
171
- { id: "site", title: "Site", show: isAllPages ? false : true, default: isAllPages ? false : true },
172
- ...defaultColumns,
173
- ];
174
+ defaultColumns = [{ id: "site", title: "Site", show: !isAllPages, default: !isAllPages }, ...defaultColumns];
174
175
  }
175
176
 
176
177
  if (isAllPages) {
@@ -1,7 +1,8 @@
1
- import pageSchemas from "./pages";
1
+ import getPageSchemas from "./pages";
2
2
 
3
- const fixedSchemas = {
4
- ...pageSchemas,
3
+ const getFixedSchemas = () => {
4
+ const pageSchemas = getPageSchemas();
5
+ return { ...pageSchemas };
5
6
  };
6
7
 
7
- export { fixedSchemas, pageSchemas };
8
+ export { getFixedSchemas, getPageSchemas };
@@ -0,0 +1,308 @@
1
+ import { schemasService } from "@ax/services";
2
+
3
+ const getThemes = () => {
4
+ if (!schemasService.isLoaded()) {
5
+ return [];
6
+ }
7
+ return schemasService.getSchemas().config.themes;
8
+ };
9
+
10
+ export default () => {
11
+ const themes = getThemes();
12
+
13
+ return {
14
+ schemaType: "page",
15
+ displayName: "Page",
16
+ component: "Page",
17
+ dataPacks: null,
18
+ configTabs: [
19
+ {
20
+ title: "content",
21
+ fields: [
22
+ {
23
+ title: "",
24
+ type: "TranslateButton",
25
+ key: "translate",
26
+ contentType: "page",
27
+ },
28
+ {
29
+ title: "Title",
30
+ type: "TextField",
31
+ key: "title",
32
+ autoComplete: "false",
33
+ },
34
+ {
35
+ title: "Template",
36
+ key: "template",
37
+ type: "template",
38
+ },
39
+ ],
40
+ },
41
+ {
42
+ title: "config",
43
+ fields: [
44
+ {
45
+ type: "UniqueCheck",
46
+ key: "isHome",
47
+ options: [
48
+ {
49
+ title: "Set as home",
50
+ },
51
+ ],
52
+ },
53
+ {
54
+ title: "Parent",
55
+ type: "AsyncSelect",
56
+ entity: "pages",
57
+ key: "parent",
58
+ options: { excludeDetailPages: true },
59
+ },
60
+ {
61
+ title: "Slug",
62
+ type: "TextField",
63
+ key: "slug",
64
+ },
65
+ {
66
+ title: "Template",
67
+ key: "template",
68
+ type: "template",
69
+ },
70
+ {
71
+ title: "Page Options",
72
+ type: "FieldGroup",
73
+ key: "pageOptions",
74
+ collapsed: false,
75
+ fields: [
76
+ {
77
+ title: "Theme",
78
+ type: "Select",
79
+ key: "theme",
80
+ options: themes,
81
+ helptext: "It affects the whole page: Header, Content, and footer.",
82
+ },
83
+ {
84
+ title: "Customize header and footer themes",
85
+ type: "ConditionalField",
86
+ key: "customizeThemes",
87
+ mandatory: true,
88
+ defaultValue: false,
89
+ options: [
90
+ {
91
+ value: true,
92
+ title: "Yes",
93
+ name: "Yes",
94
+ },
95
+ {
96
+ value: false,
97
+ title: "No",
98
+ name: "No",
99
+ },
100
+ ],
101
+ fields: [
102
+ {
103
+ title: "Header Theme",
104
+ type: "Select",
105
+ key: "headerTheme",
106
+ options: themes,
107
+ condition: true,
108
+ },
109
+ {
110
+ title: "Footer Theme",
111
+ type: "Select",
112
+ key: "footerTheme",
113
+ options: themes,
114
+ condition: true,
115
+ },
116
+ ],
117
+ },
118
+ ],
119
+ },
120
+ {
121
+ type: "IntegrationsField",
122
+ key: "integrations",
123
+ },
124
+ ],
125
+ },
126
+ {
127
+ title: "SEO & Analytics",
128
+ fields: [
129
+ {
130
+ title: "SEO Data",
131
+ type: "FieldGroup",
132
+ key: "seoData",
133
+ collapsed: true,
134
+ fields: [
135
+ {
136
+ title: "",
137
+ type: "SummaryButton",
138
+ key: "summary",
139
+ },
140
+ {
141
+ title: "Meta title",
142
+ type: "TextField",
143
+ key: "metaTitle",
144
+ },
145
+ {
146
+ title: "Meta description",
147
+ type: "TextArea",
148
+ key: "metaDescription",
149
+ },
150
+ {
151
+ title: "Keywords",
152
+ type: "TagsField",
153
+ key: "metaKeywords",
154
+ },
155
+ {
156
+ title: "Canonical URL",
157
+ type: "TextField",
158
+ key: "canonicalURL",
159
+ },
160
+ {
161
+ title: "Meta robots index",
162
+ type: "RadioGroup",
163
+ key: "isIndexed",
164
+ options: [
165
+ {
166
+ value: true,
167
+ title: "Index",
168
+ name: "index",
169
+ },
170
+ {
171
+ value: false,
172
+ title: "No index",
173
+ name: "noindex",
174
+ },
175
+ ],
176
+ },
177
+ {
178
+ title: "Meta robots follow",
179
+ type: "RadioGroup",
180
+ key: "follow",
181
+ options: [
182
+ {
183
+ value: true,
184
+ title: "Follow",
185
+ name: "follow",
186
+ },
187
+ {
188
+ value: false,
189
+ title: "No follow",
190
+ name: "nofollow",
191
+ },
192
+ ],
193
+ },
194
+ {
195
+ title: "Meta robots advanced",
196
+ type: "CheckGroup",
197
+ key: "metasAdvanced",
198
+ options: [
199
+ {
200
+ value: "noimageindex",
201
+ title: "No image index",
202
+ name: "noimage",
203
+ },
204
+ {
205
+ value: "nosnippet",
206
+ title: "No snippet",
207
+ name: "nosnippet",
208
+ },
209
+ {
210
+ value: "noodp",
211
+ title: "No ODP",
212
+ name: "noodp",
213
+ },
214
+ {
215
+ value: "noarchive",
216
+ title: "No archive",
217
+ name: "noarchive",
218
+ },
219
+ {
220
+ value: "noTranslate",
221
+ title: "No translate",
222
+ name: "noTranslate",
223
+ },
224
+ ],
225
+ },
226
+ ],
227
+ },
228
+ {
229
+ title: "GEO (LLMS)",
230
+ type: "FieldGroup",
231
+ key: "geo",
232
+ collapsed: true,
233
+ fields: [
234
+ {
235
+ type: "UniqueCheck",
236
+ key: "isLlmsEnabled",
237
+ options: [{ title: "Include this page in LLMs.txt" }],
238
+ description: "If enabled, this page will be listed in LLMs.txt for language models.",
239
+ },
240
+ ],
241
+ },
242
+ {
243
+ title: "Analytics Data Layer",
244
+ type: "FieldGroup",
245
+ key: "analytics",
246
+ collapsed: true,
247
+ fields: [
248
+ {
249
+ type: "AnalyticsField",
250
+ key: "dimensions",
251
+ collapsed: true,
252
+ },
253
+ ],
254
+ },
255
+ {
256
+ title: "Social Media",
257
+ type: "FieldGroup",
258
+ key: "socialShare",
259
+ collapsed: true,
260
+ fields: [
261
+ {
262
+ title: "Title",
263
+ type: "TextField",
264
+ key: "socialTitle",
265
+ },
266
+ {
267
+ title: "Description",
268
+ type: "TextField",
269
+ key: "socialDescription",
270
+ },
271
+ {
272
+ title: "Image",
273
+ type: "ImageField",
274
+ key: "socialImage",
275
+ },
276
+ ],
277
+ },
278
+ ],
279
+ },
280
+ ],
281
+ default: {
282
+ component: "Page",
283
+ isHome: false,
284
+ slug: "new-page",
285
+ title: "New Page",
286
+ headerConfig: "{}",
287
+ footerConfig: "{}",
288
+ liveStatus: { id: 1 },
289
+ template: {},
290
+ metaTitle: "",
291
+ metaDescription: "",
292
+ canonicalURL: "",
293
+ isIndexed: true,
294
+ follow: true,
295
+ metasAdvanced: "",
296
+ socialTitle: "",
297
+ socialDescription: "",
298
+ socialImage: {},
299
+ dimensions: {},
300
+ integrations: null,
301
+ theme: null,
302
+ customizeThemes: false,
303
+ headerTheme: null,
304
+ footerTheme: null,
305
+ isLlmsEnabled: true,
306
+ },
307
+ };
308
+ };
@@ -0,0 +1,9 @@
1
+ import FormPage from "./FormPage";
2
+ import GlobalPage from "./GlobalPage";
3
+ import getPageSchema from "./Page";
4
+
5
+ export default () => ({
6
+ Page: getPageSchema(),
7
+ GlobalPage,
8
+ FormPage,
9
+ });