@griddo/ax 1.67.10 → 1.68.2

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 (121) hide show
  1. package/config/jest/componentsMock.js +1528 -27
  2. package/package.json +2 -2
  3. package/src/__mocks__/reducers/app.tsx +10 -0
  4. package/src/__mocks__/reducers/sites.tsx +10 -0
  5. package/src/__tests__/{AnalyticsField.test.tsx → components/Fields/AnalyticsField/AnalyticsField.test.tsx} +5 -5
  6. package/src/__tests__/{PageAnalytics.test.tsx → components/Fields/AnalyticsField/PageAnalytics/PageAnalytics.test.tsx} +2 -2
  7. package/src/__tests__/{StructuredDataAnalytics.test.tsx → components/Fields/AnalyticsField/StructuredDataAnalytics/StructuredDataAnalytics.test.tsx} +2 -2
  8. package/src/__tests__/{ArrayFieldGroup.test.tsx → components/Fields/ArrayFieldGroup/ArrayFieldGroup.test.tsx} +2 -2
  9. package/src/__tests__/{AsyncCheckGroup.test.tsx → components/Fields/AsyncCheckGroup/AsyncCheckGroup.test.tsx} +2 -2
  10. package/src/__tests__/{AsyncSelect.test.tsx → components/Fields/AsyncSelect/AsyncSelect.test.tsx} +2 -2
  11. package/src/__tests__/{CheckField.test.tsx → components/Fields/CheckField/CheckField.test.tsx} +2 -2
  12. package/src/__tests__/{CheckGroup.test.tsx → components/Fields/CheckGroup/CheckGroup.test.tsx} +2 -2
  13. package/src/__tests__/components/Fields/ColorPicker/ColorPicker.test.tsx +195 -0
  14. package/src/__tests__/components/Fields/ComponentArray/ComponentArray.test.tsx +184 -0
  15. package/src/__tests__/components/Fields/ComponentArray/MixableComponentArray/MixableComponentArray.test.tsx +315 -0
  16. package/src/__tests__/components/Fields/ComponentArray/MixableComponentArray/PasteModuleButton/PasteModuleButton.test.tsx +95 -0
  17. package/src/__tests__/components/Fields/ComponentArray/SameComponentArray/SameComponentArray.test.tsx +225 -0
  18. package/src/__tests__/{FieldGroup.test.tsx → components/Fields/FieldGroup/FieldGroup.test.tsx} +2 -2
  19. package/src/__tests__/components/Fields/FieldsDivider/FieldsDivider.test.tsx +24 -0
  20. package/src/__tests__/components/Fields/FileField/FileField.test.tsx +135 -0
  21. package/src/__tests__/{HeadingField.test.tsx → components/Fields/HeadingField/HeadingField.test.tsx} +2 -2
  22. package/src/__tests__/components/Fields/HiddenField/HiddenField.test.tsx +76 -0
  23. package/src/__tests__/components/Fields/MultiCheckSelect/MultiCheckSelect.test.tsx +70 -0
  24. package/src/__tests__/components/Fields/NoteField/NoteField.test.tsx +67 -0
  25. package/src/__tests__/components/Fields/NumberField/NumberField.test.tsx +109 -0
  26. package/src/__tests__/components/Fields/RadioField/RadioField.test.tsx +106 -0
  27. package/src/__tests__/components/Fields/RichText/RichText.test.tsx +52 -0
  28. package/src/__tests__/components/Fields/Select/Select.test.tsx +75 -0
  29. package/src/__tests__/components/Fields/SliderField/SliderField.test.tsx +82 -0
  30. package/src/__tests__/{TagField.test.tsx → components/Fields/TagField/TagField.test.tsx} +2 -2
  31. package/src/__tests__/{TextArea.test.tsx → components/Fields/TextArea/TextArea.test.tsx} +2 -2
  32. package/src/__tests__/{TextField.test.tsx → components/Fields/TextField/TextField.test.tsx} +2 -2
  33. package/src/__tests__/components/Fields/ToggleField/ToggleField.test.tsx +100 -0
  34. package/src/__tests__/{UniqueCheck.test.tsx → components/Fields/UniqueCheck/UniqueCheck.test.tsx} +2 -2
  35. package/src/__tests__/components/Fields/UrlField/UrlField.test.tsx +446 -0
  36. package/src/__tests__/components/Fields/UrlField/mockedAxios.ts +2214 -0
  37. package/src/__tests__/components/Fields/VisualUniqueSelection/ImageSelection/ImageSelection.test.tsx +99 -0
  38. package/src/__tests__/components/Fields/VisualUniqueSelection/ScrollableSelection/ScrollableSelection.test.tsx +176 -0
  39. package/src/__tests__/components/Fields/VisualUniqueSelection/VisualUniqueSelection.test.tsx +78 -0
  40. package/src/components/ActionMenu/index.tsx +1 -0
  41. package/src/components/Browser/index.tsx +39 -47
  42. package/src/components/Browser/style.tsx +15 -15
  43. package/src/components/BrowserContent/index.tsx +78 -0
  44. package/src/components/ConfigPanel/Form/ConnectedField/NavConnectedField/index.tsx +3 -5
  45. package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/index.tsx +2 -6
  46. package/src/components/ConfigPanel/Header/index.tsx +28 -11
  47. package/src/components/ConfigPanel/index.tsx +2 -2
  48. package/src/components/ErrorCenter/index.tsx +11 -4
  49. package/src/components/Fields/ArrayFieldGroup/index.tsx +4 -2
  50. package/src/components/Fields/ArrayFieldGroup/style.tsx +7 -0
  51. package/src/components/Fields/AsyncCheckGroup/index.tsx +1 -1
  52. package/src/components/Fields/CheckField/index.tsx +1 -1
  53. package/src/components/Fields/ColorPicker/Picker/index.tsx +9 -3
  54. package/src/components/Fields/ColorPicker/index.tsx +4 -9
  55. package/src/components/Fields/ComponentArray/MixableComponentArray/PasteModuleButton/index.tsx +2 -1
  56. package/src/components/Fields/ComponentArray/MixableComponentArray/index.tsx +27 -22
  57. package/src/components/Fields/ComponentArray/MixableComponentArray/style.tsx +3 -38
  58. package/src/components/Fields/ComponentArray/SameComponentArray/index.tsx +3 -2
  59. package/src/components/Fields/ComponentArray/SameComponentArray/style.tsx +1 -28
  60. package/src/components/Fields/ComponentArray/helpers.tsx +1 -1
  61. package/src/components/Fields/ComponentContainer/index.tsx +3 -1
  62. package/src/components/Fields/FileField/FileDragAndDrop/index.tsx +1 -1
  63. package/src/components/Fields/FileField/FileDragAndDrop/style.tsx +2 -3
  64. package/src/components/Fields/FileField/index.tsx +6 -6
  65. package/src/components/Fields/HiddenField/index.tsx +3 -3
  66. package/src/components/Fields/MultiCheckSelect/index.tsx +8 -27
  67. package/src/components/Fields/NoteField/index.tsx +3 -3
  68. package/src/components/Fields/NumberField/index.tsx +6 -3
  69. package/src/components/Fields/RadioField/index.tsx +10 -2
  70. package/src/components/Fields/ReferenceField/index.tsx +8 -1
  71. package/src/components/Fields/ReferenceField/style.tsx +5 -0
  72. package/src/components/Fields/RichText/index.tsx +1 -1
  73. package/src/components/Fields/SliderField/index.tsx +11 -7
  74. package/src/components/Fields/ToggleField/index.tsx +12 -3
  75. package/src/components/Fields/UrlField/PageFinder/SelectionListItem/index.tsx +1 -1
  76. package/src/components/Fields/UrlField/index.tsx +6 -4
  77. package/src/components/Fields/UrlField/style.tsx +4 -2
  78. package/src/components/Fields/VisualOption/index.tsx +10 -2
  79. package/src/components/Fields/VisualUniqueSelection/ImageSelection/index.tsx +2 -2
  80. package/src/components/Fields/VisualUniqueSelection/ScrollableSelection/index.tsx +4 -3
  81. package/src/components/Fields/VisualUniqueSelection/ScrollableSelection/style.tsx +1 -1
  82. package/src/components/Fields/VisualUniqueSelection/index.tsx +3 -3
  83. package/src/components/FieldsBehavior/index.tsx +4 -4
  84. package/src/components/FieldsBehavior/style.tsx +5 -12
  85. package/src/components/FloatingMenu/index.tsx +8 -4
  86. package/src/components/Loader/index.tsx +12 -8
  87. package/src/components/MainWrapper/AppBar/index.tsx +1 -0
  88. package/src/components/MainWrapper/index.tsx +1 -0
  89. package/src/components/Toast/index.tsx +1 -1
  90. package/src/components/Tooltip/index.tsx +1 -1
  91. package/src/components/index.tsx +2 -0
  92. package/src/containers/App/actions.tsx +3 -7
  93. package/src/containers/PageEditor/actions.tsx +36 -5
  94. package/src/forms/editor.tsx +35 -1
  95. package/src/forms/fields.tsx +6 -2
  96. package/src/forms/index.tsx +2 -0
  97. package/src/forms/validators.tsx +29 -8
  98. package/src/guards/error/index.tsx +1 -1
  99. package/src/helpers/containerEvaluations.tsx +32 -4
  100. package/src/helpers/index.tsx +2 -0
  101. package/src/helpers/structuredData.tsx +2 -2
  102. package/src/hooks/forms.tsx +1 -28
  103. package/src/hooks/index.tsx +1 -2
  104. package/src/modules/FramePreview/index.tsx +70 -36
  105. package/src/modules/FramePreview/style.tsx +3 -0
  106. package/src/modules/GlobalEditor/PageBrowser/index.tsx +2 -7
  107. package/src/modules/GlobalEditor/index.tsx +8 -6
  108. package/src/modules/GlobalEditor/style.tsx +1 -1
  109. package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/DefaultsBrowser/index.tsx +0 -4
  110. package/src/modules/Navigation/Defaults/DefaultsEditor/index.tsx +3 -2
  111. package/src/modules/PageEditor/PageBrowser/index.tsx +1 -4
  112. package/src/modules/PageEditor/index.tsx +6 -6
  113. package/src/modules/PublicPreview/index.tsx +17 -34
  114. package/src/modules/PublicPreview/style.tsx +0 -2
  115. package/src/modules/Settings/ContentTypes/DataPacks/Config/Form/TemplateConfig/TemplateEditor/Editor/TemplateBrowser/index.tsx +0 -4
  116. package/src/modules/Sites/index.tsx +1 -1
  117. package/src/modules/StructuredData/Form/ConnectedField/index.tsx +1 -1
  118. package/src/modules/StructuredData/Form/index.tsx +3 -1
  119. package/src/modules/StructuredData/StructuredDataList/index.tsx +1 -0
  120. package/src/schemas/pages/GlobalPage.tsx +1 -0
  121. package/src/types/index.tsx +1 -0
@@ -7,9 +7,9 @@ const NoteField = (props: INoteFieldProps): JSX.Element => {
7
7
  const { title, text } = value;
8
8
 
9
9
  return (
10
- <S.Wrapper className={className}>
11
- {title && <S.Title>{title}</S.Title>}
12
- <S.Text>{text}</S.Text>
10
+ <S.Wrapper className={className} data-testid="noteFieldWrapper">
11
+ {title && <S.Title data-testid="title">{title}</S.Title>}
12
+ <S.Text>{text}</S.Text>
13
13
  </S.Wrapper>
14
14
  );
15
15
  };
@@ -13,6 +13,7 @@ const NumberField = (props: INumberFieldProps): JSX.Element => {
13
13
  useEffect(() => {
14
14
  setInputValue(strValue);
15
15
  }, [strValue]);
16
+
16
17
  const setValue = (value: string, eventType: string) => {
17
18
  const floatValue = parseFloat(value);
18
19
  setInputValue(value);
@@ -45,6 +46,7 @@ const NumberField = (props: INumberFieldProps): JSX.Element => {
45
46
  setValue(e.target.value, e.type);
46
47
  handleValidation && handleValidation(e.target.value, validators);
47
48
  };
49
+
48
50
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
49
51
  setValue(e.target.value, e.type);
50
52
  error && handleValidation && handleValidation(e.target.value, validators);
@@ -54,7 +56,7 @@ const NumberField = (props: INumberFieldProps): JSX.Element => {
54
56
  const decreaseValue = () => handleClick("ArrowDown");
55
57
 
56
58
  return (
57
- <S.FieldWrapper error={error}>
59
+ <S.FieldWrapper error={error} data-testid="conditional-field-wrapper">
58
60
  <S.Input
59
61
  type="number"
60
62
  value={inputValue}
@@ -65,12 +67,13 @@ const NumberField = (props: INumberFieldProps): JSX.Element => {
65
67
  min={minValue}
66
68
  max={maxValue}
67
69
  disabled={disabled}
70
+ data-testid="input"
68
71
  />
69
72
  <S.QuantityNav error={error} disabled={disabled}>
70
- <S.ArrowUp onClick={increaseValue}>
73
+ <S.ArrowUp onClick={increaseValue} data-testid="arrow-up">
71
74
  <Icon name="UpArrow" />
72
75
  </S.ArrowUp>
73
- <S.ArrowDown onClick={decreaseValue}>
76
+ <S.ArrowDown onClick={decreaseValue} data-testid="arrow-down">
74
77
  <Icon name="DownArrow" />
75
78
  </S.ArrowDown>
76
79
  </S.QuantityNav>
@@ -12,10 +12,18 @@ const RadioField = (props: IRadioFieldProps): JSX.Element => {
12
12
  };
13
13
 
14
14
  return (
15
- <S.Wrapper>
15
+ <S.Wrapper data-testid="radio-field-wrapper">
16
16
  <S.Label>
17
17
  {title}
18
- <S.Input type="radio" name={name} value={value} checked={checked} disabled={disabled} onChange={handleChange} />
18
+ <S.Input
19
+ type="radio"
20
+ name={name}
21
+ value={value}
22
+ checked={checked}
23
+ disabled={disabled}
24
+ onChange={handleChange}
25
+ data-testid="radio-field-input"
26
+ />
19
27
  <S.CheckMark checked={checked} error={error} />
20
28
  </S.Label>
21
29
  </S.Wrapper>
@@ -32,6 +32,7 @@ const ReferenceField = (props: IProps) => {
32
32
  maxItems,
33
33
  resetValidation,
34
34
  handleValidation,
35
+ mandatory,
35
36
  } = props;
36
37
 
37
38
  const { isOpen, toggleModal } = useModal();
@@ -178,9 +179,14 @@ const ReferenceField = (props: IProps) => {
178
179
 
179
180
  const manualItems = !isAuto && value && Array.isArray(value.fixed) ? value.fixed.length : 0;
180
181
 
182
+ const Asterisk = () => (mandatory ? <S.Asterisk>*</S.Asterisk> : null);
183
+
181
184
  return (
182
185
  <S.Wrapper>
183
- <S.Label>Elements</S.Label>
186
+ <S.Label>
187
+ Elements
188
+ <Asterisk />
189
+ </S.Label>
184
190
  <S.ModeWrapper>
185
191
  {!singleMode && (
186
192
  <Select
@@ -224,6 +230,7 @@ interface IProps {
224
230
  maxItems?: number;
225
231
  resetValidation?: () => void;
226
232
  handleValidation?: (value: string, validators?: Record<string, unknown>) => void;
233
+ mandatory: boolean;
227
234
  }
228
235
 
229
236
  const mapStateToProps = (state: IRootState) => ({
@@ -11,6 +11,10 @@ const Label = styled.div`
11
11
  border-bottom: 1px solid ${(p) => p.theme.color.uiLine};
12
12
  `;
13
13
 
14
+ const Asterisk = styled.span`
15
+ color: ${(p) => p.theme.color.error};
16
+ `;
17
+
14
18
  const ActionWrapper = styled.div`
15
19
  position: absolute;
16
20
  right: 0;
@@ -53,6 +57,7 @@ const SingleModeText = styled.span`
53
57
  `;
54
58
 
55
59
  export {
60
+ Asterisk,
56
61
  Wrapper,
57
62
  Label,
58
63
  ActionWrapper,
@@ -89,7 +89,7 @@ const RichText = (props: IRichTextProps): JSX.Element => {
89
89
  };
90
90
 
91
91
  return (
92
- <S.EditorWrapper error={error} disabled={disabled}>
92
+ <S.EditorWrapper error={error} disabled={disabled} data-testid="rich-text-wrapper">
93
93
  <Editor
94
94
  editorState={editorState}
95
95
  toolbarClassName="richTextToolbar"
@@ -9,7 +9,7 @@ const SliderField = (props: ITextFieldProps): JSX.Element => {
9
9
  const val = typeof value === "undefined" ? defaultValue : value;
10
10
 
11
11
  useEffect(() => {
12
- onChange(Number(val));
12
+ onChange(Number(val));
13
13
  // eslint-disable-next-line react-hooks/exhaustive-deps
14
14
  }, []);
15
15
 
@@ -17,22 +17,26 @@ const SliderField = (props: ITextFieldProps): JSX.Element => {
17
17
  if (bubbleRef.current) {
18
18
  bubbleRef.current.style.left = setBubbleLeft();
19
19
  }
20
- });
20
+ }, [bubbleRef]);
21
21
 
22
22
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
23
23
  const newValue = e.target.value;
24
24
  onChange(Number(newValue));
25
25
  };
26
-
26
+
27
27
  const setBubbleLeft = () => {
28
28
  const half = Number(((val - min) * 100) / (max - min));
29
29
  return `calc(${half}% + (${8 - half * 0.16}px))`;
30
- }
30
+ };
31
31
 
32
32
  return (
33
- <S.Slider>
34
- <S.Bubble ref={bubbleRef}>{prefix && `${prefix} `}{val}{suffix && ` ${suffix}`}</S.Bubble>
35
- <S.Input value={value} min={min} max={max} step={step} onChange={handleChange} />
33
+ <S.Slider data-testid="sliderComponent">
34
+ <S.Bubble data-testid="bubbleComponent" ref={bubbleRef}>
35
+ {prefix && `${prefix} `}
36
+ {val}
37
+ {suffix && ` ${suffix}`}
38
+ </S.Bubble>
39
+ <S.Input data-testid="inputComponent" value={value} min={min} max={max} step={step} onChange={handleChange} />
36
40
  </S.Slider>
37
41
  );
38
42
  };
@@ -13,9 +13,18 @@ const ToggleField = (props: IToggleFieldProps): JSX.Element => {
13
13
  };
14
14
 
15
15
  return (
16
- <S.Wrapper>
17
- <S.Input id="toggle" type="checkbox" name={name} value={value || false} checked={checked} disabled={disabled} onChange={handleChange}/>
18
- <S.Label htmlFor="toggle"/>
16
+ <S.Wrapper data-testid="toggle-field-wrapper">
17
+ <S.Input
18
+ id="toggle"
19
+ type="checkbox"
20
+ name={name}
21
+ value={value || false}
22
+ checked={checked}
23
+ disabled={disabled}
24
+ onChange={handleChange}
25
+ data-testid="toggle-field-input"
26
+ />
27
+ <S.Label htmlFor="toggle" />
19
28
  </S.Wrapper>
20
29
  );
21
30
  };
@@ -13,7 +13,7 @@ const SelectionListItem = (props: ISelectionListItemProps): JSX.Element => {
13
13
  const pageType = type || "Page";
14
14
 
15
15
  return (
16
- <S.ListItem onClick={handleOnClick}>
16
+ <S.ListItem onClick={handleOnClick} data-testid="selection-list-item">
17
17
  <S.Header>
18
18
  <S.Type>{pageType}</S.Type>
19
19
  <S.Date>{getFormattedDateWithTimezone(date, "d MMM Y")}</S.Date>
@@ -129,7 +129,9 @@ const UrlField = (props: IUrlFieldProps): JSX.Element => {
129
129
  if (pageID) {
130
130
  field = (
131
131
  <S.PageSelectedWrapper>
132
- <S.PageField onClick={handleOnClick}>{internalPageName && `- ${internalPageName} -`}</S.PageField>
132
+ <S.PageField onClick={handleOnClick} data-testid="page-field">
133
+ {internalPageName && `- ${internalPageName} -`}
134
+ </S.PageField>
133
135
  <S.IconWrapper>
134
136
  <IconAction icon="unlink" onClick={handleReset} disabled={disabled} />
135
137
  </S.IconWrapper>
@@ -162,7 +164,7 @@ const UrlField = (props: IUrlFieldProps): JSX.Element => {
162
164
  ];
163
165
 
164
166
  return (
165
- <>
167
+ <S.UrlFieldWrapper data-testid="url-field-wrapper">
166
168
  {field}
167
169
  {value && value.linkTo && isTabsVisible && (
168
170
  <S.AnchorWrapper>
@@ -217,11 +219,11 @@ const UrlField = (props: IUrlFieldProps): JSX.Element => {
217
219
  >
218
220
  <PageFinder onClick={handleSetPage} isOpen={isOpen} />
219
221
  </FloatingPanel>
220
- </>
222
+ </S.UrlFieldWrapper>
221
223
  );
222
224
  };
223
225
 
224
- interface IUrlFieldProps {
226
+ export interface IUrlFieldProps {
225
227
  value: IUrlField | null;
226
228
  title: string;
227
229
  onChange: (value: IUrlField | null) => void;
@@ -1,5 +1,7 @@
1
1
  import styled from "styled-components";
2
2
 
3
+ const UrlFieldWrapper = styled.div``;
4
+
3
5
  const PageSelectedWrapper = styled.div`
4
6
  display: flex;
5
7
  box-shadow: ${(p) => p.theme.shadow.shadowS};
@@ -33,7 +35,7 @@ const IconWrapper = styled.div`
33
35
  transform: translate(-50%, -50%);
34
36
  svg {
35
37
  width: ${(p) => p.theme.spacing.m};
36
- height: ${(p) => p.theme.spacing.m}};
38
+ height: ${(p) => p.theme.spacing.m};
37
39
  }
38
40
  }
39
41
  `;
@@ -52,4 +54,4 @@ const AnchorWrapper = styled.div`
52
54
  margin-top: ${(p) => p.theme.spacing.s};
53
55
  `;
54
56
 
55
- export { PageSelectedWrapper, PageField, IconWrapper, AdvancedWrapper, AnchorWrapper };
57
+ export { PageSelectedWrapper, PageField, IconWrapper, AdvancedWrapper, AnchorWrapper, UrlFieldWrapper };
@@ -9,9 +9,17 @@ const VisualOption = ({ value, onChange, name, label, checked, img, disabled }:
9
9
 
10
10
  return (
11
11
  <S.Label>
12
- <S.RadioButton type="radio" name={name} value={value} checked={checked} onChange={handleChange} disabled={disabled}/>
12
+ <S.RadioButton
13
+ data-testid="radioButtons"
14
+ type="radio"
15
+ name={name}
16
+ value={value}
17
+ checked={checked}
18
+ onChange={handleChange}
19
+ disabled={disabled}
20
+ />
13
21
  <S.ImageWrapper active={checked} disabled={disabled}>
14
- <S.Image src={img}/>
22
+ <S.Image src={img} />
15
23
  </S.ImageWrapper>
16
24
  </S.Label>
17
25
  );
@@ -13,7 +13,7 @@ const ImageSelection = (props: IImageSelectionProps): JSX.Element => {
13
13
  const handleChange = (newValue: string) => onChange(newValue);
14
14
 
15
15
  return (
16
- <S.Wrapper columns={columns}>
16
+ <S.Wrapper columns={columns} data-testid="imageSelectionComponent">
17
17
  {mappedOptions.map((option: any, index: number) => (
18
18
  <VisualOption
19
19
  value={option.value}
@@ -30,7 +30,7 @@ const ImageSelection = (props: IImageSelectionProps): JSX.Element => {
30
30
  );
31
31
  };
32
32
 
33
- interface IImageSelectionProps {
33
+ export interface IImageSelectionProps {
34
34
  value: string;
35
35
  title: string;
36
36
  onChange: (value: string) => void;
@@ -39,7 +39,7 @@ const ScrollableSelection = (props: IScrollableSelectionProps): JSX.Element => {
39
39
  }, [carouselRef, columns]);
40
40
 
41
41
  return (
42
- <S.Wrapper>
42
+ <S.Wrapper data-testid="scrollableSelectionComponent">
43
43
  <S.Carousel ref={carouselRef}>
44
44
  {mappedOptions.map((option: IScrollableUniqueSelectionFieldOptionsProps, index: number) => (
45
45
  <S.CarouselItem width={carouselItemWidth} columns={columns} key={index}>
@@ -62,7 +62,7 @@ const ScrollableSelection = (props: IScrollableSelectionProps): JSX.Element => {
62
62
  </S.MoveButton>
63
63
  <S.DotGroup>
64
64
  {[...Array(slides)].map((_, i) => (
65
- <S.Dot selected={i === carouselIndex} key={i}></S.Dot>
65
+ <S.Dot data-testid="dotSelected" selected={i === carouselIndex} key={i}></S.Dot>
66
66
  ))}
67
67
  </S.DotGroup>
68
68
  <S.MoveButton>
@@ -74,7 +74,7 @@ const ScrollableSelection = (props: IScrollableSelectionProps): JSX.Element => {
74
74
  );
75
75
  };
76
76
 
77
- interface IScrollableSelectionProps {
77
+ export interface IScrollableSelectionProps {
78
78
  value: string;
79
79
  title: string;
80
80
  onChange: (value: string) => void;
@@ -87,6 +87,7 @@ interface IScrollableSelectionProps {
87
87
  selectedContent: any;
88
88
  reference?: string;
89
89
  theme: string;
90
+ elementUniqueSelection: boolean;
90
91
  }
91
92
 
92
93
  interface IScrollableUniqueSelectionFieldOptionsProps {
@@ -45,7 +45,7 @@ export const Dot = styled.div<{ selected: boolean }>`
45
45
  background-color: ${(p) => (p.selected ? p.theme.color.uiSiteMenu : p.theme.color.uiLine)};
46
46
  `;
47
47
 
48
- export const MoveButton = styled.button`
48
+ export const MoveButton = styled.div`
49
49
  background-color: transparent;
50
50
  border: 0;
51
51
  `;
@@ -1,9 +1,9 @@
1
1
  import React from "react";
2
2
 
3
- import ImageSelection from "./ImageSelection";
4
- import ScrollableSelection from "./ScrollableSelection";
3
+ import ImageSelection, { IImageSelectionProps } from "./ImageSelection";
4
+ import ScrollableSelection, { IScrollableSelectionProps } from "./ScrollableSelection";
5
5
 
6
- const VisualUniqueSelection = (props: any): JSX.Element => {
6
+ const VisualUniqueSelection = (props: IImageSelectionProps & IScrollableSelectionProps): JSX.Element => {
7
7
  const { elementUniqueSelection = false } = props;
8
8
  const Component = elementUniqueSelection ? ScrollableSelection : ImageSelection;
9
9
 
@@ -40,7 +40,7 @@ const FieldsBehavior = (props: any): JSX.Element => {
40
40
  // eslint-disable-next-line react-hooks/exhaustive-deps
41
41
  }, [editorID, error]);
42
42
 
43
- const helpTextWrapper = message ? <S.HelpText>{message}</S.HelpText> : "";
43
+ const helpTextWrapper = message ? <S.HelpText error={errorField}>{message}</S.HelpText> : "";
44
44
  const isComponentArray = fieldType === "ComponentArray";
45
45
  const isComponentContainer = fieldType === "ComponentContainer";
46
46
  const hasMultipleOptions: boolean = whiteList && whiteList.length > 1;
@@ -79,8 +79,8 @@ const FieldsBehavior = (props: any): JSX.Element => {
79
79
  };
80
80
 
81
81
  return (
82
- <S.Wrapper error={errorField} className={wrapperClass} showTitle={showTitle} id={objKey}>
83
- <S.Content data-testid="contentWrapper" error={errorField}>
82
+ <S.Wrapper className={wrapperClass} showTitle={showTitle} id={objKey}>
83
+ <S.Content error={errorField} data-testid="contentWrapper">
84
84
  <Field
85
85
  {...props}
86
86
  showAdvanced={showAdvanced}
@@ -91,7 +91,7 @@ const FieldsBehavior = (props: any): JSX.Element => {
91
91
  </S.Content>
92
92
  <S.Header className="fieldHeader">
93
93
  {showTitle && (
94
- <S.Label htmlFor={name}>
94
+ <S.Label htmlFor={name} error={errorField}>
95
95
  {title} <Asterisk />
96
96
  </S.Label>
97
97
  )}
@@ -1,8 +1,8 @@
1
1
  import styled from "styled-components";
2
2
 
3
- export const Label = styled.label`
3
+ export const Label = styled.label<{ error: boolean | undefined }>`
4
4
  ${(p) => p.theme.textStyle?.fieldLabel};
5
- color: ${(p) => p.theme.color?.textMediumEmphasis};
5
+ color: ${(p) => (p.error === true ? p.theme.color?.error : p.theme.color?.textMediumEmphasis)};
6
6
  display: block;
7
7
  margin-bottom: ${(p) => p.theme.spacing?.xs};
8
8
  `;
@@ -11,9 +11,9 @@ export const Asterisk = styled.span`
11
11
  color: ${(p) => p.theme.color?.error};
12
12
  `;
13
13
 
14
- export const HelpText = styled.div`
14
+ export const HelpText = styled.div<{ error: boolean | undefined }>`
15
15
  ${(p) => p.theme.textStyle.uiXS};
16
- color: ${(p) => p.theme.color?.textMediumEmphasis};
16
+ color: ${(p) => (p.error === true ? p.theme.color?.error : p.theme.color?.textMediumEmphasis)};
17
17
  `;
18
18
 
19
19
  export const Header = styled.div`
@@ -30,19 +30,12 @@ export const Icons = styled.div`
30
30
  display: flex;
31
31
  `;
32
32
 
33
- export const Wrapper = styled.div<{ error: boolean | undefined; showTitle: boolean | undefined }>`
33
+ export const Wrapper = styled.div<{ showTitle: boolean | undefined }>`
34
34
  position: relative;
35
35
  margin-bottom: ${(p) => p.theme.spacing?.m};
36
36
  padding-top: ${(p) => (p.showTitle ? p.theme.spacing?.m : 0)};
37
37
  width: 100%;
38
38
 
39
- ${HelpText} {
40
- color: ${(p) => (p.error === true ? p.theme.color?.error : p.theme.color?.textMediumEmphasis)};
41
- }
42
- ${Label} {
43
- color: ${(p) => (p.error === true ? p.theme.color?.error : p.theme.color?.textMediumEmphasis)};
44
- }
45
-
46
39
  &:hover > .fieldHeader ${Icons} {
47
40
  opacity: 1;
48
41
  }
@@ -57,15 +57,19 @@ const FloatingMenu = (props: IProps) => {
57
57
  useHandleClickOutside(isOpen, handleClickOutside);
58
58
 
59
59
  return (
60
- <S.Wrapper ref={wrapper} onClick={handleClick} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
60
+ <S.Wrapper
61
+ ref={wrapper}
62
+ onClick={handleClick}
63
+ onMouseEnter={handleMouseEnter}
64
+ onMouseLeave={handleMouseLeave}
65
+ data-testid="floating-menu"
66
+ >
61
67
  <S.ButtonWrapper ref={button}>
62
68
  <Button />
63
69
  </S.ButtonWrapper>
64
70
  {isOpen && (
65
71
  <S.MenuWrapper isInAppBar={isInAppBar} ref={menuOptions} position={position} offset={offset}>
66
- <S.Menu>
67
- {children}
68
- </S.Menu>
72
+ <S.Menu>{children}</S.Menu>
69
73
  </S.MenuWrapper>
70
74
  )}
71
75
  </S.Wrapper>
@@ -1,9 +1,11 @@
1
1
  import React from "react";
2
2
 
3
- const images = require.context("./components", true);
4
- const imagePath = (name: string) => images(name);
3
+ import Circle from "./components/Circle";
4
+ import Dots from "./components/Dots";
5
5
 
6
- const Loader = (props: IProps) => {
6
+ const components: Record<string, () => JSX.Element> = { Circle, Dots };
7
+
8
+ const Loader = (props: IProps): JSX.Element => {
7
9
  const name = props.name
8
10
  .replace(".svg", "")
9
11
  .split("-")
@@ -11,12 +13,14 @@ const Loader = (props: IProps) => {
11
13
  .join("");
12
14
 
13
15
  const { size = "70" } = props;
16
+ const elementProps = {
17
+ height: size,
18
+ width: size,
19
+ viewBox: "0 0 100 100",
20
+ };
14
21
 
15
- const Svg = imagePath(`./${name}`).default;
16
- return (
17
- <Svg height={size} width={size} viewBox="0 0 100 100" />
18
- );
19
- }
22
+ return React.createElement(components[name], elementProps);
23
+ };
20
24
 
21
25
  interface IStateProps {
22
26
  name: string;
@@ -275,6 +275,7 @@ interface IAppBarProps {
275
275
  errors?: IErrorItem[];
276
276
  errorActions?: {
277
277
  goToError(editorID: number, tab: string, template: boolean): void;
278
+ goToPackage(): void;
278
279
  };
279
280
  isFromEditor?: boolean;
280
281
  pageStatusActions?: any[];
@@ -47,6 +47,7 @@ interface IWrapperProps {
47
47
  errors?: IErrorItem[];
48
48
  errorActions?: {
49
49
  goToError(editorID: number, tab: string, template: boolean): void;
50
+ goToPackage(): void;
50
51
  };
51
52
  pageStatusActions?: any[];
52
53
  }
@@ -25,7 +25,7 @@ const Toast = (props: IProps) => {
25
25
 
26
26
  return createPortal(
27
27
  <S.Wrapper ref={toast}>
28
- <S.Text>{message}</S.Text>
28
+ <S.Text data-testid="toastMessage">{message}</S.Text>
29
29
  <S.Buttons>
30
30
  {action &&
31
31
  <Button type="button" buttonStyle="lineInverse" onClick={action}>
@@ -78,7 +78,7 @@ const Tooltip = (props: IProps): JSX.Element => {
78
78
  if (!content) return children;
79
79
 
80
80
  return (
81
- <S.Tooltip onMouseEnter={showTip} onMouseLeave={hideTip} onMouseDown={handleClick}>
81
+ <S.Tooltip data-testid="tooltipComponent" onMouseEnter={showTip} onMouseLeave={hideTip} onMouseDown={handleClick}>
82
82
  <div ref={childrenRef}>{children}</div>
83
83
  <S.Tip
84
84
  active={active}
@@ -47,6 +47,7 @@ import ActionMenu from "./ActionMenu";
47
47
  import Avatar from "./Avatar";
48
48
  import Breadcrumb from "./Breadcrumb";
49
49
  import Browser from "./Browser";
50
+ import BrowserContent from "./BrowserContent";
50
51
  import BulkSelectionOptions from "./BulkSelectionOptions";
51
52
  import Button from "./Button";
52
53
  import CategoryCell from "./CategoryCell";
@@ -140,6 +141,7 @@ export {
140
141
  Avatar,
141
142
  Breadcrumb,
142
143
  Browser,
144
+ BrowserContent,
143
145
  BulkSelectionOptions,
144
146
  Button,
145
147
  CategoryCell,
@@ -99,14 +99,10 @@ function resetError(): ISetErrorAction {
99
99
 
100
100
  function handleError(response: any): (dispatch: Dispatch) => Promise<void> {
101
101
  return async (dispatch) => {
102
- const {
103
- data: { code, message },
104
- btnText,
105
- actionsBelow,
106
- } = response;
102
+ const { data, btnText, actionsBelow, text } = response;
107
103
  const error = {
108
- code,
109
- text: message,
104
+ code: data?.code,
105
+ text: data?.message || text,
110
106
  btnText,
111
107
  actionsBelow,
112
108
  };
@@ -29,6 +29,7 @@ import {
29
29
  checkH1content,
30
30
  parseValidationErrors,
31
31
  findPackagesActivationErrors,
32
+ checkMaxModules,
32
33
  } from "@ax/forms";
33
34
  import { appActions } from "@ax/containers/App";
34
35
  import { navigationActions } from "@ax/containers/Navigation";
@@ -100,6 +101,15 @@ const { getSiteDefaults, getDefaults } = navigationActions;
100
101
  // FIXME: CHECK EDITOR CONTENT STRUCTURE (editorContent.editorContent)
101
102
 
102
103
  function setEditorContent(editorContent: IPage | Record<string, unknown>): ISetEditorContent {
104
+ const iframe = document.querySelector("iframe");
105
+ iframe?.contentWindow?.postMessage(
106
+ {
107
+ type: "content-update",
108
+ message: editorContent,
109
+ },
110
+ "*"
111
+ );
112
+
103
113
  return { type: SET_EDITOR_CONTENT, payload: { editorContent } };
104
114
  }
105
115
 
@@ -654,6 +664,13 @@ function addModule(
654
664
  ): (dispatch: Dispatch, getState: any) => void {
655
665
  return (dispatch, getState) => {
656
666
  const { editorContent, sections, editorID } = getStateValues(getState);
667
+
668
+ const { isMaxModules, errorMessage } = checkMaxModules(editorContent, type);
669
+ if (isMaxModules) {
670
+ handleError({ text: errorMessage })(dispatch);
671
+ return;
672
+ }
673
+
657
674
  const componentModule = {
658
675
  editorID,
659
676
  type,
@@ -763,6 +780,13 @@ function duplicateModule(editorID: number, key?: string): (dispatch: Dispatch, g
763
780
 
764
781
  const updatedSections: any = [...sections];
765
782
  const { element: originalItem, parent, grandParent } = findByEditorID(updatedSections, editorID);
783
+
784
+ const { isMaxModules, errorMessage } = checkMaxModules(editorContent, originalItem.component);
785
+ if (isMaxModules) {
786
+ handleError({ text: errorMessage })(dispatch);
787
+ return;
788
+ }
789
+
766
790
  const parentModule = Array.isArray(parent) ? grandParent : parent;
767
791
 
768
792
  const parentKey = key ? key : getParentKey(parentModule, editorID);
@@ -814,6 +838,15 @@ function pasteModule(editorID: number): (dispatch: Dispatch, getState: any) => P
814
838
 
815
839
  const { sections, editorContent } = getStateValues(getState);
816
840
 
841
+ const { isMaxModules, errorMessage } = checkMaxModules(editorContent, moduleCopy.element.component);
842
+ if (isMaxModules && errorMessage) {
843
+ const error: INotification = {
844
+ type: "error",
845
+ text: errorMessage,
846
+ };
847
+ return { error };
848
+ }
849
+
817
850
  const updatedSections: any = [...sections];
818
851
  const { element: originalElement } = findByEditorID(updatedSections, editorID);
819
852
 
@@ -1069,7 +1102,7 @@ function getTemplateConfig(template: string): (dispatch: Dispatch, getState: any
1069
1102
  };
1070
1103
  }
1071
1104
 
1072
- function validatePage(publish?: boolean, browserRef?: any): (dispatch: Dispatch, getState: any) => Promise<boolean> {
1105
+ function validatePage(publish?: boolean): (dispatch: Dispatch, getState: any) => Promise<boolean> {
1073
1106
  return async (dispatch, getState) => {
1074
1107
  try {
1075
1108
  const { editorContent } = getStateValues(getState);
@@ -1104,10 +1137,8 @@ function validatePage(publish?: boolean, browserRef?: any): (dispatch: Dispatch,
1104
1137
  errors = packagesActivationErrors ? [...errors, packagesActivationErrors] : errors;
1105
1138
 
1106
1139
  let warnings: IErrorItem[] = [];
1107
- if (browserRef && browserRef.current) {
1108
- const h1Warning = checkH1content(browserRef.current);
1109
- warnings = h1Warning ? [...warnings, h1Warning] : warnings;
1110
- }
1140
+ const h1Warning = checkH1content();
1141
+ warnings = h1Warning ? [...warnings, h1Warning] : warnings;
1111
1142
 
1112
1143
  const allErrors = [...errors, ...warnings];
1113
1144