@griddo/ax 1.72.11 → 1.73.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 (76) hide show
  1. package/package.json +2 -2
  2. package/scripts/griddo-sync-schemas.js +1 -1
  3. package/src/__tests__/components/ErrorCenter/ErrorCenter.test.tsx +186 -0
  4. package/src/__tests__/components/Flag/Flag.test.tsx +60 -0
  5. package/src/__tests__/components/FloatingMenu/FloatingMenu.test.tsx +712 -0
  6. package/src/__tests__/components/FloatingPanel/FloatingPanel.test.tsx +149 -0
  7. package/src/__tests__/components/GuardModal/GuardModal.test.tsx +31 -0
  8. package/src/__tests__/components/Icon/Icon.test.tsx +76 -0
  9. package/src/__tests__/components/IconAction/IconAction.test.tsx +91 -0
  10. package/src/__tests__/components/Notification/Notification.test.tsx +206 -0
  11. package/src/__tests__/components/Notification/SubNotification/Subnotification.test.tsx +46 -0
  12. package/src/__tests__/components/ReorderArrows/ReorderArrows.test.tsx +96 -0
  13. package/src/__tests__/components/ResizePanel/ResizePanel.test.tsx +200 -0
  14. package/src/__tests__/components/SearchField/SearchField.test.tsx +375 -0
  15. package/src/api/analytics.tsx +4 -4
  16. package/src/components/ActionMenu/style.tsx +1 -0
  17. package/src/components/ConfigPanel/Form/ConnectedField/NavConnectedField/index.tsx +1 -1
  18. package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/Field/index.tsx +2 -1
  19. package/src/components/ConfigPanel/Form/index.tsx +22 -1
  20. package/src/components/ConfigPanel/Form/style.tsx +19 -0
  21. package/src/components/ConfigPanel/GlobalPageForm/index.tsx +22 -3
  22. package/src/components/ConfigPanel/GlobalPageForm/style.tsx +18 -2
  23. package/src/components/ConfigPanel/NavigationForm/Field/index.tsx +25 -13
  24. package/src/components/ConfigPanel/index.tsx +8 -0
  25. package/src/components/ErrorCenter/index.tsx +8 -4
  26. package/src/components/Fields/DateField/DatePickerInput/index.tsx +30 -8
  27. package/src/components/Fields/DateField/index.tsx +8 -2
  28. package/src/components/Fields/Select/index.tsx +1 -0
  29. package/src/components/Flag/index.tsx +13 -11
  30. package/src/components/FloatingMenu/index.tsx +23 -7
  31. package/src/components/FloatingMenu/style.tsx +1 -0
  32. package/src/components/FloatingPanel/index.tsx +9 -3
  33. package/src/components/GuardModal/index.tsx +3 -3
  34. package/src/components/Icon/index.tsx +2 -1
  35. package/src/components/IconAction/index.tsx +3 -3
  36. package/src/components/MainWrapper/AppBar/index.tsx +3 -1
  37. package/src/components/MainWrapper/AppBar/style.tsx +3 -0
  38. package/src/components/MenuItem/index.tsx +1 -1
  39. package/src/components/Modal/index.tsx +1 -1
  40. package/src/components/Notification/SubNotification/index.tsx +33 -0
  41. package/src/components/Notification/SubNotification/style.tsx +49 -0
  42. package/src/components/Notification/index.tsx +31 -17
  43. package/src/components/Notification/style.tsx +33 -8
  44. package/src/components/ReorderArrows/index.tsx +3 -3
  45. package/src/components/ResizePanel/ResizeHandle/index.tsx +29 -38
  46. package/src/components/ResizePanel/index.tsx +13 -15
  47. package/src/components/SearchField/index.tsx +9 -8
  48. package/src/containers/Analytics/actions.tsx +14 -4
  49. package/src/containers/App/actions.tsx +18 -6
  50. package/src/containers/App/reducer.tsx +1 -0
  51. package/src/containers/Domains/actions.tsx +8 -1
  52. package/src/containers/Navigation/Defaults/actions.tsx +16 -2
  53. package/src/containers/PageEditor/actions.tsx +82 -6
  54. package/src/containers/PageEditor/utils.tsx +28 -10
  55. package/src/containers/Redirects/actions.tsx +16 -2
  56. package/src/containers/Sites/actions.tsx +80 -3
  57. package/src/containers/StructuredData/actions.tsx +24 -3
  58. package/src/containers/Users/actions.tsx +8 -1
  59. package/src/forms/errors.tsx +1 -0
  60. package/src/forms/fields.tsx +6 -3
  61. package/src/forms/validators.tsx +14 -4
  62. package/src/guards/error/index.tsx +17 -21
  63. package/src/helpers/dates.tsx +2 -0
  64. package/src/helpers/index.tsx +2 -0
  65. package/src/hooks/modals.tsx +4 -4
  66. package/src/modules/Content/OptionTable/index.tsx +20 -7
  67. package/src/modules/Content/index.tsx +4 -7
  68. package/src/modules/Content/utils.tsx +18 -13
  69. package/src/modules/FramePreview/index.tsx +39 -12
  70. package/src/modules/GlobalEditor/index.tsx +17 -20
  71. package/src/modules/Navigation/Menus/List/Table/index.tsx +2 -2
  72. package/src/modules/PageEditor/Editor/index.tsx +13 -0
  73. package/src/modules/PageEditor/index.tsx +17 -20
  74. package/src/modules/Redirects/RedirectItem/index.tsx +17 -3
  75. package/src/modules/Settings/ContentTypes/DataPacks/Item/index.tsx +1 -1
  76. package/src/modules/StructuredData/Form/index.tsx +10 -13
@@ -0,0 +1,200 @@
1
+ import React, { useRef } from "react";
2
+
3
+ import { ThemeProvider } from "styled-components";
4
+ import { render, cleanup, screen, fireEvent } from "@testing-library/react";
5
+ import { parseTheme } from "@ax/helpers";
6
+ import "@testing-library/jest-dom";
7
+
8
+ import ResizePanel, { IResizePanelProps } from "@ax/components/ResizePanel";
9
+ import globalTheme from "@ax/themes/theme.json";
10
+
11
+ afterEach(cleanup);
12
+
13
+ jest.mock("react", () => {
14
+ const originReact = jest.requireActual("react");
15
+ const mUseRef = jest.fn();
16
+ return {
17
+ ...originReact,
18
+ useRef: mUseRef,
19
+ };
20
+ });
21
+
22
+ const useMockRef = useRef as jest.MockedFunction<typeof useRef>;
23
+
24
+ describe("ResizePanel component rendering", () => {
25
+ it("should render the component with 2 panels", () => {
26
+ const defaultProps: IResizePanelProps = {
27
+ leftPanel: <div>Left Panel</div>,
28
+ rightPanel: <div>Right Panel</div>,
29
+ };
30
+
31
+ const rightPanelRef = { current: {} };
32
+ useMockRef.mockReturnValue(rightPanelRef);
33
+
34
+ render(
35
+ <ThemeProvider theme={parseTheme(globalTheme)}>
36
+ <ResizePanel {...defaultProps} />
37
+ </ThemeProvider>
38
+ );
39
+
40
+ const leftPanel = screen.getByTestId("left-panel-fixed");
41
+ expect(leftPanel).toBeTruthy();
42
+ const rightPanel = screen.getByTestId("right-panel");
43
+ expect(rightPanel).toBeTruthy();
44
+ });
45
+
46
+ it("should render the component with 2 panels if left if not fixed", () => {
47
+ const defaultProps: IResizePanelProps = {
48
+ leftPanel: <div>Left Panel</div>,
49
+ rightPanel: <div>Right Panel</div>,
50
+ fixed: false,
51
+ };
52
+
53
+ const rightPanelRef = { current: {} };
54
+ useMockRef.mockReturnValueOnce(rightPanelRef);
55
+
56
+ render(
57
+ <ThemeProvider theme={parseTheme(globalTheme)}>
58
+ <ResizePanel {...defaultProps} />
59
+ </ThemeProvider>
60
+ );
61
+
62
+ const leftPanel = screen.getByTestId("left-panel");
63
+ expect(leftPanel).toBeTruthy();
64
+ const rightPanel = screen.getByTestId("right-panel");
65
+ expect(rightPanel).toBeTruthy();
66
+ });
67
+ });
68
+
69
+ describe("ResizePanel mouse events", () => {
70
+ it("fixed panel changes position on scroll", () => {
71
+ const defaultProps: IResizePanelProps = {
72
+ leftPanel: <div>Left Panel</div>,
73
+ rightPanel: <div>Right Panel</div>,
74
+ fixed: true,
75
+ };
76
+
77
+ const scroll = 100;
78
+
79
+ const rightPanelRef = { current: {} };
80
+ Object.defineProperty(rightPanelRef, "current", {
81
+ set(_current) {
82
+ if (_current) {
83
+ jest.spyOn(_current, "offsetWidth", "get").mockReturnValueOnce(350);
84
+ }
85
+ this._current = _current;
86
+ },
87
+ get() {
88
+ return this._current;
89
+ },
90
+ });
91
+ useMockRef.mockReturnValue(rightPanelRef);
92
+
93
+ render(
94
+ <ThemeProvider theme={parseTheme(globalTheme)}>
95
+ <ResizePanel {...defaultProps} />
96
+ </ThemeProvider>
97
+ );
98
+
99
+ const fixedPanel = screen.getByTestId("fixed-panel");
100
+ expect(fixedPanel).toBeTruthy();
101
+
102
+ fireEvent.scroll(window, { target: { scrollX: scroll } });
103
+ const leftPosition = getComputedStyle(fixedPanel).left;
104
+
105
+ expect(leftPosition).toBe(`calc(24px - ${scroll}px)`);
106
+ });
107
+
108
+ it("right panel should change width if handle moves past its width", () => {
109
+ const defaultProps: IResizePanelProps = {
110
+ leftPanel: <div>Left Panel</div>,
111
+ rightPanel: <div>Right Panel</div>,
112
+ fixed: true,
113
+ };
114
+
115
+ const windowWidth = 1440;
116
+ const mousePositionX = 1000;
117
+
118
+ const rightPanelRef = { current: {} };
119
+
120
+ Object.defineProperty(document.body, "offsetWidth", { value: windowWidth });
121
+
122
+ Object.defineProperty(rightPanelRef, "current", {
123
+ set(_current) {
124
+ if (_current) {
125
+ jest.spyOn(_current, "offsetWidth", "get").mockReturnValueOnce(345);
126
+ }
127
+ this._current = _current;
128
+ },
129
+ get() {
130
+ return this._current;
131
+ },
132
+ });
133
+
134
+ useMockRef.mockReturnValue(rightPanelRef);
135
+
136
+ render(
137
+ <ThemeProvider theme={parseTheme(globalTheme)}>
138
+ <ResizePanel {...defaultProps} />
139
+ </ThemeProvider>
140
+ );
141
+
142
+ const rightPanel = screen.getByTestId("right-panel");
143
+ expect(rightPanel).toBeTruthy();
144
+
145
+ const handler = screen.getByTestId("handler");
146
+ expect(handler).toBeTruthy();
147
+
148
+ fireEvent.mouseDown(handler);
149
+ fireEvent.mouseMove(handler, { clientX: mousePositionX, clientY: 100 });
150
+ fireEvent.mouseUp(handler);
151
+
152
+ const width = getComputedStyle(rightPanel).width;
153
+ expect(width).toBe(`${windowWidth - mousePositionX}px`);
154
+ });
155
+
156
+ it("right panel shouldn't change width if handle not moves past its width", () => {
157
+ const defaultProps: IResizePanelProps = {
158
+ leftPanel: <div>Left Panel</div>,
159
+ rightPanel: <div>Right Panel</div>,
160
+ fixed: true,
161
+ };
162
+
163
+ const rightPanelRef = { current: {} };
164
+
165
+ Object.defineProperty(document.body, "offsetWidth", { value: 1440 });
166
+
167
+ Object.defineProperty(rightPanelRef, "current", {
168
+ set(_current) {
169
+ if (_current) {
170
+ jest.spyOn(_current, "offsetWidth", "get").mockReturnValueOnce(345);
171
+ }
172
+ this._current = _current;
173
+ },
174
+ get() {
175
+ return this._current;
176
+ },
177
+ });
178
+
179
+ useMockRef.mockReturnValue(rightPanelRef);
180
+
181
+ render(
182
+ <ThemeProvider theme={parseTheme(globalTheme)}>
183
+ <ResizePanel {...defaultProps} />
184
+ </ThemeProvider>
185
+ );
186
+
187
+ const rightPanel = screen.getByTestId("right-panel");
188
+ expect(rightPanel).toBeTruthy();
189
+
190
+ const handler = screen.getByTestId("handler");
191
+ expect(handler).toBeTruthy();
192
+
193
+ fireEvent.mouseDown(handler);
194
+ fireEvent.mouseMove(handler, { clientX: 1200, clientY: 100 });
195
+ fireEvent.mouseUp(handler);
196
+
197
+ const width = getComputedStyle(rightPanel).width;
198
+ expect(width).toBe("345px");
199
+ });
200
+ });
@@ -0,0 +1,375 @@
1
+ import * as React from "react";
2
+
3
+ import { ThemeProvider } from "styled-components";
4
+ import { render, cleanup, screen, fireEvent, act } from "@testing-library/react";
5
+ import { parseTheme } from "@ax/helpers";
6
+ import "@testing-library/jest-dom";
7
+ import userEvent from "@testing-library/user-event";
8
+
9
+ import SearchField, { ISearchFieldProps } from "@ax/components/SearchField";
10
+ import globalTheme from "@ax/themes/theme.json";
11
+
12
+ afterEach(cleanup);
13
+
14
+ describe("Search field component rendering", () => {
15
+ it("should render the component opened", () => {
16
+ const onChangeMock = jest.fn();
17
+ const defaultProps: ISearchFieldProps = {
18
+ onChange: onChangeMock,
19
+ };
20
+
21
+ render(
22
+ <ThemeProvider theme={parseTheme(globalTheme)}>
23
+ <SearchField {...defaultProps} />
24
+ </ThemeProvider>
25
+ );
26
+
27
+ const searchField = screen.getByTestId("search-field-wrapper");
28
+ const iconSearchWrapper = screen.queryByTestId("icon-search-wrapper");
29
+ const fieldWrapper = screen.getByTestId("field-wrapper");
30
+
31
+ expect(searchField).toBeTruthy();
32
+ expect(iconSearchWrapper).toBeFalsy();
33
+ expect(fieldWrapper).toBeTruthy();
34
+ });
35
+
36
+ it("should render the component opened with placeholder", () => {
37
+ const onChangeMock = jest.fn();
38
+ const defaultProps: ISearchFieldProps = {
39
+ onChange: onChangeMock,
40
+ placeholder: "Search",
41
+ };
42
+
43
+ render(
44
+ <ThemeProvider theme={parseTheme(globalTheme)}>
45
+ <SearchField {...defaultProps} />
46
+ </ThemeProvider>
47
+ );
48
+
49
+ const searchField = screen.getByTestId("search-field-wrapper");
50
+ const iconSearchWrapper = screen.queryByTestId("icon-search-wrapper");
51
+ const fieldWrapper = screen.getByTestId("field-wrapper");
52
+ const placeholderText = screen.queryByPlaceholderText(/Search/i);
53
+
54
+ expect(searchField).toBeTruthy();
55
+ expect(iconSearchWrapper).toBeFalsy();
56
+ expect(fieldWrapper).toBeTruthy();
57
+ expect(placeholderText).toBeTruthy();
58
+ });
59
+
60
+ it("should render the component closed", () => {
61
+ const onChangeMock = jest.fn();
62
+ const defaultProps: ISearchFieldProps = {
63
+ onChange: onChangeMock,
64
+ closeOnInactive: true,
65
+ };
66
+
67
+ render(
68
+ <ThemeProvider theme={parseTheme(globalTheme)}>
69
+ <SearchField {...defaultProps} />
70
+ </ThemeProvider>
71
+ );
72
+
73
+ const searchField = screen.getByTestId("search-field-wrapper");
74
+ const iconSearchWrapper = screen.getByTestId("icon-search-wrapper");
75
+ const fieldWrapper = screen.queryByTestId("field-wrapper");
76
+
77
+ expect(searchField).toBeTruthy();
78
+ expect(iconSearchWrapper).toBeTruthy();
79
+ expect(fieldWrapper).toBeFalsy();
80
+ });
81
+
82
+ it("should render the component disabled", () => {
83
+ const onChangeMock = jest.fn();
84
+ const defaultProps: ISearchFieldProps = {
85
+ onChange: onChangeMock,
86
+ closeOnInactive: false,
87
+ disabled: true,
88
+ };
89
+
90
+ render(
91
+ <ThemeProvider theme={parseTheme(globalTheme)}>
92
+ <SearchField {...defaultProps} />
93
+ </ThemeProvider>
94
+ );
95
+
96
+ const input = screen.getByTestId("search-input");
97
+ expect(input).toBeDisabled();
98
+ });
99
+ });
100
+
101
+ describe("Search field filters", () => {
102
+ it("should render the component with search filters", () => {
103
+ const onChangeMock = jest.fn();
104
+
105
+ const searchFilters = [
106
+ { value: "filterby", label: "Filter by" },
107
+ { value: "from", label: "Old URL" },
108
+ { value: "to", label: "New URL" },
109
+ ];
110
+
111
+ const defaultProps: ISearchFieldProps = {
112
+ onChange: onChangeMock,
113
+ searchFilters,
114
+ };
115
+
116
+ render(
117
+ <ThemeProvider theme={parseTheme(globalTheme)}>
118
+ <SearchField {...defaultProps} />
119
+ </ThemeProvider>
120
+ );
121
+
122
+ const searchField = screen.getByTestId("search-field-wrapper");
123
+ const iconSearchWrapper = screen.queryByTestId("icon-search-wrapper");
124
+ const fieldWrapper = screen.getByTestId("field-wrapper");
125
+ const filterWrapper = screen.queryByTestId("filter-wrapper");
126
+
127
+ expect(searchField).toBeTruthy();
128
+ expect(iconSearchWrapper).toBeFalsy();
129
+ expect(fieldWrapper).toBeTruthy();
130
+ expect(filterWrapper).toBeTruthy();
131
+ });
132
+
133
+ it("should call onFilterChange when selecting option", async () => {
134
+ const onChangeMock = jest.fn();
135
+ const onFilterChangeMock = jest.fn();
136
+
137
+ const searchFilters = [
138
+ { value: "filterby", label: "Filter by" },
139
+ { value: "from", label: "Old URL" },
140
+ { value: "to", label: "New URL" },
141
+ ];
142
+
143
+ const defaultProps: ISearchFieldProps = {
144
+ onChange: onChangeMock,
145
+ searchFilters,
146
+ onFilterChange: onFilterChangeMock,
147
+ };
148
+
149
+ render(
150
+ <ThemeProvider theme={parseTheme(globalTheme)}>
151
+ <SearchField {...defaultProps} />
152
+ </ThemeProvider>
153
+ );
154
+
155
+ const filterWrapper = screen.queryByTestId("filter-wrapper");
156
+ expect(filterWrapper).toBeTruthy();
157
+
158
+ await act(async () => userEvent.click(screen.getByLabelText("filterSelect")));
159
+
160
+ const selectedItem = screen.getByText("Old URL");
161
+ await act(async () => userEvent.click(selectedItem));
162
+
163
+ expect(onFilterChangeMock).toBeCalledTimes(1);
164
+ expect(screen.getByText("Old URL")).toBeInTheDocument();
165
+ });
166
+ });
167
+
168
+ describe("search field events", () => {
169
+ it("should open on icon search click and show field and close icon", () => {
170
+ const onChangeMock = jest.fn();
171
+ const defaultProps: ISearchFieldProps = {
172
+ onChange: onChangeMock,
173
+ closeOnInactive: true,
174
+ };
175
+
176
+ const { rerender } = render(
177
+ <ThemeProvider theme={parseTheme(globalTheme)}>
178
+ <SearchField {...defaultProps} />
179
+ </ThemeProvider>
180
+ );
181
+
182
+ const searchField = screen.getByTestId("search-field-wrapper");
183
+ const iconSearchWrapper = screen.queryByTestId("icon-search-wrapper");
184
+ const fieldWrapper = screen.queryByTestId("field-wrapper");
185
+
186
+ expect(searchField).toBeTruthy();
187
+ expect(iconSearchWrapper).toBeTruthy();
188
+ expect(fieldWrapper).toBeFalsy();
189
+
190
+ fireEvent.click(screen.getByTestId("icon-search-wrapper"));
191
+
192
+ rerender(
193
+ <ThemeProvider theme={parseTheme(globalTheme)}>
194
+ <SearchField {...defaultProps} />
195
+ </ThemeProvider>
196
+ );
197
+
198
+ const iconSearchWrapper2 = screen.queryByTestId("icon-search-wrapper");
199
+ const iconCloseWrapper = screen.queryByTestId("icon-close-wrapper");
200
+ const fieldWrapper2 = screen.queryByTestId("field-wrapper");
201
+ expect(fieldWrapper2).toBeTruthy();
202
+ expect(iconSearchWrapper2).toBeFalsy();
203
+ expect(iconCloseWrapper).toBeTruthy();
204
+ });
205
+
206
+ it("should close and clear on close icon click and hide field and search icon if closeOnActive", () => {
207
+ const onChangeMock = jest.fn();
208
+ const defaultProps: ISearchFieldProps = {
209
+ onChange: onChangeMock,
210
+ closeOnInactive: true,
211
+ };
212
+
213
+ const { rerender } = render(
214
+ <ThemeProvider theme={parseTheme(globalTheme)}>
215
+ <SearchField {...defaultProps} />
216
+ </ThemeProvider>
217
+ );
218
+
219
+ const iconSearchWrapper = screen.getByTestId("icon-search-wrapper");
220
+ expect(iconSearchWrapper).toBeTruthy();
221
+ fireEvent.click(iconSearchWrapper);
222
+
223
+ rerender(
224
+ <ThemeProvider theme={parseTheme(globalTheme)}>
225
+ <SearchField {...defaultProps} />
226
+ </ThemeProvider>
227
+ );
228
+
229
+ const iconCloseWrapper = screen.getByTestId("icon-close-wrapper");
230
+ expect(iconCloseWrapper).toBeTruthy();
231
+ fireEvent.click(iconCloseWrapper);
232
+
233
+ rerender(
234
+ <ThemeProvider theme={parseTheme(globalTheme)}>
235
+ <SearchField {...defaultProps} />
236
+ </ThemeProvider>
237
+ );
238
+
239
+ const iconSearchWrapper2 = screen.queryByTestId("icon-search-wrapper");
240
+ const iconCloseWrapper2 = screen.queryByTestId("icon-close-wrapper");
241
+ const fieldWrapper = screen.queryByTestId("field-wrapper");
242
+ expect(fieldWrapper).toBeFalsy();
243
+ expect(iconSearchWrapper2).toBeTruthy();
244
+ expect(iconCloseWrapper2).toBeFalsy();
245
+ expect(onChangeMock).toBeCalledTimes(1);
246
+ });
247
+
248
+ it("should clear and not close on close icon click if not closeOnActive and input is not empty", () => {
249
+ const onChangeMock = jest.fn();
250
+ const defaultProps: ISearchFieldProps = {
251
+ onChange: onChangeMock,
252
+ closeOnInactive: false,
253
+ };
254
+
255
+ const { rerender } = render(
256
+ <ThemeProvider theme={parseTheme(globalTheme)}>
257
+ <SearchField {...defaultProps} />
258
+ </ThemeProvider>
259
+ );
260
+
261
+ const input = screen.getByTestId("search-input");
262
+ fireEvent.change(input, { target: { value: "prueba" } });
263
+ const iconCloseWrapper = screen.getByTestId("icon-close-wrapper");
264
+ expect(iconCloseWrapper).toBeTruthy();
265
+ fireEvent.click(iconCloseWrapper);
266
+
267
+ rerender(
268
+ <ThemeProvider theme={parseTheme(globalTheme)}>
269
+ <SearchField {...defaultProps} />
270
+ </ThemeProvider>
271
+ );
272
+
273
+ const iconSearchWrapper = screen.queryByTestId("icon-search-wrapper-2");
274
+ const iconCloseWrapper2 = screen.queryByTestId("icon-close-wrapper");
275
+ const fieldWrapper = screen.queryByTestId("field-wrapper");
276
+ expect(fieldWrapper).toBeTruthy();
277
+ expect(iconSearchWrapper).toBeTruthy();
278
+ expect(iconCloseWrapper2).toBeFalsy();
279
+ expect(onChangeMock).toBeCalledTimes(1);
280
+ });
281
+
282
+ it("show press enter on input type", () => {
283
+ const onChangeMock = jest.fn();
284
+ const defaultProps: ISearchFieldProps = {
285
+ onChange: onChangeMock,
286
+ closeOnInactive: true,
287
+ searchOnEnter: true,
288
+ };
289
+
290
+ const { rerender } = render(
291
+ <ThemeProvider theme={parseTheme(globalTheme)}>
292
+ <SearchField {...defaultProps} />
293
+ </ThemeProvider>
294
+ );
295
+
296
+ const iconSearchWrapper = screen.getByTestId("icon-search-wrapper");
297
+ expect(iconSearchWrapper).toBeTruthy();
298
+ fireEvent.click(iconSearchWrapper);
299
+
300
+ rerender(
301
+ <ThemeProvider theme={parseTheme(globalTheme)}>
302
+ <SearchField {...defaultProps} />
303
+ </ThemeProvider>
304
+ );
305
+
306
+ const fieldWrapper = screen.getByTestId("field-wrapper");
307
+ const input = screen.getByTestId("search-input");
308
+ expect(fieldWrapper).toBeTruthy();
309
+ fireEvent.change(input, { target: { value: "prueba" } });
310
+ expect(screen.queryByText("Press ENTER")).toBeTruthy();
311
+ });
312
+
313
+ it("should call onchange on input type", () => {
314
+ const onChangeMock = jest.fn();
315
+ const defaultProps: ISearchFieldProps = {
316
+ onChange: onChangeMock,
317
+ closeOnInactive: true,
318
+ searchOnEnter: false,
319
+ };
320
+
321
+ const { rerender } = render(
322
+ <ThemeProvider theme={parseTheme(globalTheme)}>
323
+ <SearchField {...defaultProps} />
324
+ </ThemeProvider>
325
+ );
326
+
327
+ const iconSearchWrapper = screen.getByTestId("icon-search-wrapper");
328
+ expect(iconSearchWrapper).toBeTruthy();
329
+ fireEvent.click(iconSearchWrapper);
330
+
331
+ rerender(
332
+ <ThemeProvider theme={parseTheme(globalTheme)}>
333
+ <SearchField {...defaultProps} />
334
+ </ThemeProvider>
335
+ );
336
+
337
+ const fieldWrapper = screen.getByTestId("field-wrapper");
338
+ const input = screen.getByTestId("search-input");
339
+ expect(fieldWrapper).toBeTruthy();
340
+ fireEvent.keyDown(input, { key: "A", code: "KeyA" });
341
+ expect(onChangeMock).toBeCalledTimes(1);
342
+ });
343
+
344
+ it("should call onchange on key enter", () => {
345
+ const onChangeMock = jest.fn();
346
+ const defaultProps: ISearchFieldProps = {
347
+ onChange: onChangeMock,
348
+ closeOnInactive: true,
349
+ searchOnEnter: true,
350
+ };
351
+
352
+ const { rerender } = render(
353
+ <ThemeProvider theme={parseTheme(globalTheme)}>
354
+ <SearchField {...defaultProps} />
355
+ </ThemeProvider>
356
+ );
357
+
358
+ const iconSearchWrapper = screen.getByTestId("icon-search-wrapper");
359
+ expect(iconSearchWrapper).toBeTruthy();
360
+ fireEvent.click(iconSearchWrapper);
361
+
362
+ rerender(
363
+ <ThemeProvider theme={parseTheme(globalTheme)}>
364
+ <SearchField {...defaultProps} />
365
+ </ThemeProvider>
366
+ );
367
+
368
+ const fieldWrapper = screen.getByTestId("field-wrapper");
369
+ const input = screen.getByTestId("search-input");
370
+ expect(fieldWrapper).toBeTruthy();
371
+ fireEvent.change(input, { target: { value: "prueba" } });
372
+ fireEvent.keyDown(input, { key: "Enter", code: "Enter", charCode: 13 });
373
+ expect(onChangeMock).toBeCalledTimes(1);
374
+ });
375
+ });
@@ -6,22 +6,22 @@ import { IServiceConfig, sendRequest } from "./utils";
6
6
  const SERVICES: { [key: string]: IServiceConfig } = {
7
7
  GET_ANALYTICS: {
8
8
  ...template,
9
- endpoint: ["/site/", "/analytics"],
9
+ endpoint: ["/site/", "/metrics"],
10
10
  method: "GET",
11
11
  },
12
12
  UPDATE_SCRIPT_CODE: {
13
13
  ...template,
14
- endpoint: ["/site/", "/analytics/script"],
14
+ endpoint: ["/site/", "/metrics/code"],
15
15
  method: "PUT",
16
16
  },
17
17
  CREATE_DIMENSIONS: {
18
18
  ...template,
19
- endpoint: ["/analytics/dimensions/site/", "/bulk"],
19
+ endpoint: ["/metrics/dimensions/site/", "/bulk"],
20
20
  method: "POST",
21
21
  },
22
22
  CREATE_DIMENSIONS_GROUPS: {
23
23
  ...template,
24
- endpoint: ["/analytics/groups/site/", "/bulk"],
24
+ endpoint: ["/metrics/groups/site/", "/bulk"],
25
25
  method: "POST",
26
26
  },
27
27
  };
@@ -45,6 +45,7 @@ export const ActionItem = styled.li<{ disabled?: boolean; color?: boolean }>`
45
45
  pointer-events: ${(p) => (p.disabled ? "none" : "auto")};
46
46
  text-align: left;
47
47
  white-space: nowrap;
48
+ cursor: pointer;
48
49
 
49
50
  &:focus {
50
51
  background: ${(p) => (p.disabled ? "transparent" : p.theme.color.overlayFocusPrimary)};
@@ -55,7 +55,7 @@ const NavConnectedField = (props: any) => {
55
55
 
56
56
  if (isConditional) {
57
57
  const innerActions = { ...actions, updateValue, goTo };
58
- innerFields = getInnerFields(field.fields, innerActions, selectedContent, isTemplateActivated, theme);
58
+ innerFields = getInnerFields(field.fields, innerActions, selectedContent, isTemplateActivated, theme, site);
59
59
  }
60
60
 
61
61
  return (
@@ -46,8 +46,9 @@ const Field = (props: IProps): JSX.Element => {
46
46
  selectedContent,
47
47
  isTemplateActivated,
48
48
  theme,
49
+ site,
49
50
  errors,
50
- deleteError
51
+ deleteError,
51
52
  );
52
53
  }
53
54
 
@@ -5,8 +5,11 @@ import { Tabs } from "@ax/components";
5
5
 
6
6
  import ConnectedField from "./ConnectedField";
7
7
 
8
+ import * as S from "./style";
9
+
8
10
  export const Form = (props: IProps): JSX.Element => {
9
- const { schema, selectedTab, setSelectedTab, actions, isPage, isGlobal, theme, setHistoryPush } = props;
11
+ const { schema, selectedTab, setSelectedTab, actions, isPage, isGlobal, theme, setHistoryPush, header, footer } =
12
+ props;
10
13
  const tabContent = schema.configTabs.find((tab: ISchemaTab) => tab.title === selectedTab);
11
14
  const setTab = (tab: string) => setSelectedTab(tab);
12
15
 
@@ -53,9 +56,25 @@ export const Form = (props: IProps): JSX.Element => {
53
56
 
54
57
  const tabs = getTabs();
55
58
 
59
+ const handleRestoreHeader = () =>
60
+ actions.restorePageNavigationAction && actions.restorePageNavigationAction("header");
61
+
62
+ const handleRestoreFooter = () =>
63
+ actions.restorePageNavigationAction && actions.restorePageNavigationAction("footer");
64
+
56
65
  return (
57
66
  <section>
58
67
  <Tabs tabs={tabs} active={selectedTab} setSelectedTab={setTab} />
68
+ {selectedTab === "content" && !isGlobal && header === 0 && (
69
+ <S.FieldWrapper>
70
+ This page doesn&apos;t have a header. Click <S.Link onClick={handleRestoreHeader}>here</S.Link> to restore it.
71
+ </S.FieldWrapper>
72
+ )}
73
+ {selectedTab === "content" && !isGlobal && footer === 0 && (
74
+ <S.FieldWrapper>
75
+ This page doesn&apos;t have a footer. Click <S.Link onClick={handleRestoreFooter}>here</S.Link> to restore it.
76
+ </S.FieldWrapper>
77
+ )}
59
78
  {tabContent && tabContent.fields.map((field: ISchemaField) => generateFields(field))}
60
79
  </section>
61
80
  );
@@ -71,6 +90,8 @@ interface IProps {
71
90
  isGlobal?: boolean;
72
91
  theme: string;
73
92
  setHistoryPush?: (path: string, isEditor: boolean) => void;
93
+ header?: number | null;
94
+ footer?: number | null;
74
95
  }
75
96
 
76
97
  export default Form;
@@ -0,0 +1,19 @@
1
+ import styled from "styled-components";
2
+
3
+ const FieldWrapper = styled.div`
4
+ margin-top: ${(p) => p.theme.spacing.s};
5
+ margin-bottom: ${(p) => p.theme.spacing.s};
6
+ background-color: ${(p) => p.theme.color?.uiBackground03};
7
+ padding: ${(p) => p.theme.spacing?.s};
8
+ border-radius: ${(p) => p.theme.radii?.s};
9
+ ${(p) => p.theme.textStyle?.uiXS};
10
+ color: ${(p) => p.theme.color?.textMediumEmphasis};
11
+ `;
12
+
13
+ const Link = styled.span`
14
+ cursor: pointer;
15
+ font-weight: bold;
16
+ color: ${(p) => p.theme.color?.interactive01};
17
+ `;
18
+
19
+ export { FieldWrapper, Link };