@griddo/ax 10.4.6 → 10.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/__tests__/components/Browser/Browser.test.tsx +4 -4
- package/src/__tests__/components/Fields/ComponentArray/MixableComponentArray/MixableComponentArray.test.tsx +39 -7
- package/src/__tests__/components/Fields/ComponentArray/MixableComponentArray/PasteModuleButton/PasteModuleButton.test.tsx +8 -8
- package/src/__tests__/components/Fields/ComponentContainer/ComponentContainer.test.tsx +28 -16
- package/src/components/Browser/index.tsx +5 -5
- package/src/components/BulkSelectionOptions/style.tsx +1 -0
- package/src/components/ConfigPanel/Header/index.tsx +8 -4
- package/src/components/Fields/AsyncCheckGroup/style.tsx +3 -0
- package/src/components/Fields/CheckField/index.tsx +4 -1
- package/src/components/Fields/CheckField/style.tsx +19 -3
- package/src/components/Fields/CheckGroup/index.tsx +3 -2
- package/src/components/Fields/CheckGroup/style.tsx +3 -0
- package/src/components/Fields/ComponentArray/MixableComponentArray/BulkHeader/index.tsx +47 -0
- package/src/components/Fields/ComponentArray/MixableComponentArray/BulkHeader/style.tsx +44 -0
- package/src/components/Fields/ComponentArray/MixableComponentArray/PasteModuleButton/index.tsx +31 -12
- package/src/components/Fields/ComponentArray/MixableComponentArray/index.tsx +153 -59
- package/src/components/Fields/ComponentArray/SameComponentArray/index.tsx +1 -1
- package/src/components/Fields/ComponentArray/helpers.tsx +45 -4
- package/src/components/Fields/ComponentContainer/EmptyContainer/index.tsx +2 -2
- package/src/components/Fields/ComponentContainer/index.tsx +68 -33
- package/src/components/Fields/ComponentContainer/style.tsx +78 -11
- package/src/components/Fields/ReferenceField/Context/index.tsx +1 -1
- package/src/components/MainWrapper/AppBar/atoms.tsx +5 -8
- package/src/components/SideModal/SideModalOption/index.tsx +5 -3
- package/src/containers/Navigation/Defaults/actions.tsx +86 -55
- package/src/containers/Navigation/Defaults/interfaces.tsx +2 -2
- package/src/containers/Navigation/Defaults/reducer.tsx +3 -3
- package/src/containers/PageEditor/actions.tsx +142 -109
- package/src/containers/PageEditor/interfaces.tsx +1 -1
- package/src/containers/PageEditor/reducer.tsx +2 -2
- package/src/containers/PageEditor/utils.tsx +1 -1
- package/src/containers/Settings/DataPacks/actions.tsx +7 -2
- package/src/forms/elements.tsx +20 -14
- package/src/hooks/bulk.tsx +57 -2
- package/src/hooks/iframe.ts +5 -5
- package/src/modules/Content/index.tsx +10 -1
- package/src/modules/FramePreview/index.tsx +4 -4
- package/src/modules/GlobalEditor/Editor/index.tsx +6 -6
- package/src/modules/GlobalEditor/PageBrowser/index.tsx +2 -2
- package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/index.tsx +6 -6
- package/src/modules/PageEditor/Editor/index.tsx +7 -7
- package/src/modules/PageEditor/PageBrowser/index.tsx +2 -2
- package/src/modules/Users/UserForm/index.tsx +52 -34
- package/src/types/index.tsx +1 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@griddo/ax",
|
|
3
3
|
"description": "Griddo Author Experience",
|
|
4
|
-
"version": "10.4.
|
|
4
|
+
"version": "10.4.8",
|
|
5
5
|
"authors": [
|
|
6
6
|
"Álvaro Sánchez' <alvaro.sanches@secuoyas.com>",
|
|
7
7
|
"Carlos Torres <carlos.torres@secuoyas.com>",
|
|
@@ -231,5 +231,5 @@
|
|
|
231
231
|
"publishConfig": {
|
|
232
232
|
"access": "public"
|
|
233
233
|
},
|
|
234
|
-
"gitHead": "
|
|
234
|
+
"gitHead": "1390ad1d87acd73442f46bed3f505df9b6fd4adc"
|
|
235
235
|
}
|
|
@@ -146,10 +146,10 @@ describe("Browser component rendering", () => {
|
|
|
146
146
|
defaultProps.isPreview = false;
|
|
147
147
|
defaultProps.showIframe = false;
|
|
148
148
|
const deleteModuleActionMock = defaultProps.actions?.deleteModuleAction as jest.MockedFunction<
|
|
149
|
-
(editorID: number) => void
|
|
149
|
+
(editorID: number[]) => void
|
|
150
150
|
>;
|
|
151
151
|
const duplicateModuleActionMock = defaultProps.actions?.duplicateModuleAction as jest.MockedFunction<
|
|
152
|
-
(editorID: number) =>
|
|
152
|
+
(editorID: number[]) => number
|
|
153
153
|
>;
|
|
154
154
|
const setSelectedContentActionMock = defaultProps.actions?.setSelectedContentAction as jest.MockedFunction<
|
|
155
155
|
() => void
|
|
@@ -172,10 +172,10 @@ describe("Browser component rendering", () => {
|
|
|
172
172
|
defaultProps.isPreview = true;
|
|
173
173
|
defaultProps.showIframe = true;
|
|
174
174
|
const deleteModuleActionMock = defaultProps.actions?.deleteModuleAction as jest.MockedFunction<
|
|
175
|
-
(editorID: number) => void
|
|
175
|
+
(editorID: number[]) => void
|
|
176
176
|
>;
|
|
177
177
|
const duplicateModuleActionMock = defaultProps.actions?.duplicateModuleAction as jest.MockedFunction<
|
|
178
|
-
(editorID: number) =>
|
|
178
|
+
(editorID: number[]) => number
|
|
179
179
|
>;
|
|
180
180
|
const setSelectedContentActionMock = defaultProps.actions?.setSelectedContentAction as jest.MockedFunction<
|
|
181
181
|
() => void
|
|
@@ -23,7 +23,7 @@ otherMixableModule.editorID = 2;
|
|
|
23
23
|
otherMixableModule.component = "HeroCard";
|
|
24
24
|
otherMixableModule.title = "Hero Section";
|
|
25
25
|
otherMixableModule.modules = [];
|
|
26
|
-
mixableProps.field = { type: "components" };
|
|
26
|
+
mixableProps.field = { type: "components", title: "", key: "elements" };
|
|
27
27
|
const testModule = {
|
|
28
28
|
value: {
|
|
29
29
|
editorID: 1,
|
|
@@ -59,7 +59,7 @@ describe("ComponentArraySelector component rendering", () => {
|
|
|
59
59
|
otherMixableModule.title = "Hero Section";
|
|
60
60
|
otherMixableModule.modules = [];
|
|
61
61
|
mixableProps.value = [mixableModule, otherMixableModule];
|
|
62
|
-
mixableProps.field = { contentType: "modules" };
|
|
62
|
+
mixableProps.field = { contentType: "modules", title: "", key: "elements", type: "" };
|
|
63
63
|
mixableProps.objKey = "elements";
|
|
64
64
|
mixableProps.disabled = false;
|
|
65
65
|
mixableProps.maxItems = 10;
|
|
@@ -68,6 +68,12 @@ describe("ComponentArraySelector component rendering", () => {
|
|
|
68
68
|
addComponentAction: jest.fn(),
|
|
69
69
|
deleteModuleAction: jest.fn(),
|
|
70
70
|
replaceElementsInCollectionAction: jest.fn(),
|
|
71
|
+
duplicateModuleAction: jest.fn(),
|
|
72
|
+
copyModuleAction: jest.fn(),
|
|
73
|
+
moveModuleAction: jest.fn(),
|
|
74
|
+
pasteModuleAction: jest.fn(),
|
|
75
|
+
setNotificationAction: jest.fn(),
|
|
76
|
+
replaceModuleAction: jest.fn(),
|
|
71
77
|
};
|
|
72
78
|
|
|
73
79
|
render(
|
|
@@ -122,6 +128,7 @@ describe("ComponentArraySelector component rendering", () => {
|
|
|
122
128
|
mixableProps.field = {
|
|
123
129
|
contentType: "modules",
|
|
124
130
|
key: "mainContent",
|
|
131
|
+
title: "", type: ""
|
|
125
132
|
};
|
|
126
133
|
mixableProps.objKey = "elements";
|
|
127
134
|
mixableProps.disabled = false;
|
|
@@ -131,6 +138,12 @@ describe("ComponentArraySelector component rendering", () => {
|
|
|
131
138
|
addComponentAction: jest.fn(),
|
|
132
139
|
deleteModuleAction: jest.fn(),
|
|
133
140
|
replaceElementsInCollectionAction: jest.fn(),
|
|
141
|
+
duplicateModuleAction: jest.fn(),
|
|
142
|
+
copyModuleAction: jest.fn(),
|
|
143
|
+
moveModuleAction: jest.fn(),
|
|
144
|
+
pasteModuleAction: jest.fn(),
|
|
145
|
+
setNotificationAction: jest.fn(),
|
|
146
|
+
replaceModuleAction: jest.fn(),
|
|
134
147
|
};
|
|
135
148
|
mixableProps.template = { component: "BasicTemplate" };
|
|
136
149
|
mixableProps.availableDataPacks = [
|
|
@@ -197,8 +210,9 @@ describe("ComponentArraySelector component rendering", () => {
|
|
|
197
210
|
];
|
|
198
211
|
const actualDate = new Date();
|
|
199
212
|
mixableProps.moduleCopy = {
|
|
200
|
-
date: actualDate
|
|
201
|
-
|
|
213
|
+
date: actualDate,
|
|
214
|
+
elements: [{
|
|
215
|
+
editorID: 1,
|
|
202
216
|
component: "ArticlesDistributor",
|
|
203
217
|
anchorID: null,
|
|
204
218
|
verticalSpacing: "medium",
|
|
@@ -224,7 +238,7 @@ describe("ComponentArraySelector component rendering", () => {
|
|
|
224
238
|
editorID: 40,
|
|
225
239
|
parentEditorID: 39,
|
|
226
240
|
},
|
|
227
|
-
},
|
|
241
|
+
}],
|
|
228
242
|
};
|
|
229
243
|
mixableProps.mandatory = true;
|
|
230
244
|
|
|
@@ -245,7 +259,7 @@ describe("ComponentArraySelector component events trigger", () => {
|
|
|
245
259
|
otherMixableModule.title = "Hero Section";
|
|
246
260
|
otherMixableModule.modules = [];
|
|
247
261
|
mixableProps.value = [mixableModule, otherMixableModule];
|
|
248
|
-
mixableProps.field = { contentType: "modules" };
|
|
262
|
+
mixableProps.field = { contentType: "modules", title: "", key: "elements", type: "" };
|
|
249
263
|
mixableProps.objKey = "elements";
|
|
250
264
|
mixableProps.disabled = false;
|
|
251
265
|
mixableProps.maxItems = 10;
|
|
@@ -254,6 +268,12 @@ describe("ComponentArraySelector component events trigger", () => {
|
|
|
254
268
|
addComponentAction: jest.fn(),
|
|
255
269
|
deleteModuleAction: jest.fn(),
|
|
256
270
|
replaceElementsInCollectionAction: jest.fn(),
|
|
271
|
+
duplicateModuleAction: jest.fn(),
|
|
272
|
+
copyModuleAction: jest.fn(),
|
|
273
|
+
moveModuleAction: jest.fn(),
|
|
274
|
+
pasteModuleAction: jest.fn(),
|
|
275
|
+
setNotificationAction: jest.fn(),
|
|
276
|
+
replaceModuleAction: jest.fn(),
|
|
257
277
|
};
|
|
258
278
|
|
|
259
279
|
render(
|
|
@@ -276,11 +296,23 @@ describe("ComponentArraySelector component events trigger", () => {
|
|
|
276
296
|
otherMixableModule.component = "HeroCard";
|
|
277
297
|
otherMixableModule.title = "Hero Section";
|
|
278
298
|
otherMixableModule.modules = [];
|
|
279
|
-
mixableProps.field = { type: "components" };
|
|
299
|
+
mixableProps.field = { type: "components", title: "", key: "elements" };
|
|
280
300
|
mixableProps.value = [mixableModule];
|
|
281
301
|
mixableProps.activatedModules = ["HeroSection"];
|
|
282
302
|
mixableProps.whiteList = [];
|
|
283
303
|
mixableProps.moduleCopy = null;
|
|
304
|
+
mixableProps.actions = {
|
|
305
|
+
addModuleAction: jest.fn(),
|
|
306
|
+
addComponentAction: jest.fn(),
|
|
307
|
+
deleteModuleAction: jest.fn(),
|
|
308
|
+
replaceElementsInCollectionAction: jest.fn(),
|
|
309
|
+
duplicateModuleAction: jest.fn(),
|
|
310
|
+
copyModuleAction: jest.fn(),
|
|
311
|
+
moveModuleAction: jest.fn(),
|
|
312
|
+
pasteModuleAction: jest.fn(),
|
|
313
|
+
setNotificationAction: jest.fn(),
|
|
314
|
+
replaceModuleAction: jest.fn(),
|
|
315
|
+
};
|
|
284
316
|
|
|
285
317
|
render(
|
|
286
318
|
<ThemeProvider theme={parseTheme(globalTheme)}>
|
|
@@ -6,7 +6,7 @@ import { ThemeProvider } from "styled-components";
|
|
|
6
6
|
import { parseTheme } from "@ax/helpers";
|
|
7
7
|
import "@testing-library/jest-dom";
|
|
8
8
|
import globalTheme from "@ax/themes/theme.json";
|
|
9
|
-
import { INotification } from "@ax/types";
|
|
9
|
+
import { IModule, INotification } from "@ax/types";
|
|
10
10
|
import { render, screen, cleanup, fireEvent, act } from "@testing-library/react";
|
|
11
11
|
import { mock } from "jest-mock-extended";
|
|
12
12
|
|
|
@@ -22,7 +22,7 @@ jest.mock("react-router-dom", () => ({
|
|
|
22
22
|
const defaultProps = mock<IPasteModuleProps>();
|
|
23
23
|
|
|
24
24
|
const mockedFunction = defaultProps.pasteModule as jest.MockedFunction<
|
|
25
|
-
(editorID: number, key: string) => Promise<{ error?: INotification }>
|
|
25
|
+
(editorID: number, key: string, modulesToPaste: IModule[]) => Promise<{ error?: INotification }>
|
|
26
26
|
>;
|
|
27
27
|
const mockedNotification = defaultProps.setNotification as jest.MockedFunction<(notification: INotification) => void>;
|
|
28
28
|
defaultProps.editorID = 1;
|
|
@@ -65,8 +65,8 @@ describe("ComponentArraySelector trigger events", () => {
|
|
|
65
65
|
await act(async () => {
|
|
66
66
|
fireEvent.click(iconButton);
|
|
67
67
|
});
|
|
68
|
-
|
|
69
|
-
await expect(mockedFunction(1, "")).resolves.toEqual({
|
|
68
|
+
expect(mockedFunction).toHaveBeenCalled();
|
|
69
|
+
await expect(mockedFunction(1, "", [{ editorID: 1, component: "BasicContent" }])).resolves.toEqual({
|
|
70
70
|
error: {
|
|
71
71
|
type: "warning",
|
|
72
72
|
text: "This is a warning",
|
|
@@ -90,8 +90,8 @@ describe("ComponentArraySelector trigger events", () => {
|
|
|
90
90
|
await act(async () => {
|
|
91
91
|
fireEvent.click(iconButton);
|
|
92
92
|
});
|
|
93
|
-
|
|
94
|
-
await expect(mockedFunction(1, "")).resolves.toEqual({});
|
|
93
|
+
expect(mockedFunction).toHaveBeenCalled();
|
|
94
|
+
await expect(mockedFunction(1, "", [{ editorID: 1, component: "BasicContent" }])).resolves.toEqual({});
|
|
95
95
|
expect(screen.getByTestId("toast-message")).toHaveTextContent("Module pasted from clipboard");
|
|
96
96
|
});
|
|
97
97
|
|
|
@@ -109,8 +109,8 @@ describe("ComponentArraySelector trigger events", () => {
|
|
|
109
109
|
await act(async () => {
|
|
110
110
|
fireEvent.click(iconButton);
|
|
111
111
|
});
|
|
112
|
-
|
|
113
|
-
await expect(mockedFunction(1, "")).resolves.toEqual({ error: undefined });
|
|
112
|
+
expect(mockedFunction).toHaveBeenCalled();
|
|
113
|
+
await expect(mockedFunction(1, "", [{ editorID: 1, component: "BasicContent" }])).resolves.toEqual({ error: undefined });
|
|
114
114
|
expect(screen.getByTestId("toast-message")).toHaveTextContent("Module pasted from clipboard");
|
|
115
115
|
});
|
|
116
116
|
});
|
|
@@ -61,10 +61,11 @@ describe("ComponentContainer component rendering", () => {
|
|
|
61
61
|
defaultProps.value = {};
|
|
62
62
|
defaultProps.actionReplace = jest.fn();
|
|
63
63
|
defaultProps.actions = {
|
|
64
|
+
addComponentAction: jest.fn(),
|
|
64
65
|
deleteModuleAction: jest.fn(),
|
|
65
|
-
|
|
66
|
-
duplicateModuleAction: jest.fn,
|
|
66
|
+
duplicateModuleAction: jest.fn(),
|
|
67
67
|
copyModuleAction: jest.fn(),
|
|
68
|
+
replaceModuleAction: jest.fn(),
|
|
68
69
|
};
|
|
69
70
|
defaultProps.canDuplicate = true;
|
|
70
71
|
defaultProps.canReplace = true;
|
|
@@ -147,10 +148,11 @@ describe("ComponentContainer component rendering", () => {
|
|
|
147
148
|
defaultProps.value = {};
|
|
148
149
|
defaultProps.actionReplace = jest.fn();
|
|
149
150
|
defaultProps.actions = {
|
|
151
|
+
addComponentAction: jest.fn(),
|
|
150
152
|
deleteModuleAction: jest.fn(),
|
|
151
|
-
|
|
152
|
-
duplicateModuleAction: jest.fn,
|
|
153
|
+
duplicateModuleAction: jest.fn(),
|
|
153
154
|
copyModuleAction: jest.fn(),
|
|
155
|
+
replaceModuleAction: jest.fn(),
|
|
154
156
|
};
|
|
155
157
|
defaultProps.canDuplicate = true;
|
|
156
158
|
defaultProps.canReplace = true;
|
|
@@ -190,7 +192,11 @@ describe("ComponentContainer component rendering", () => {
|
|
|
190
192
|
parentEditorID: 4,
|
|
191
193
|
};
|
|
192
194
|
defaultProps.actions = {
|
|
195
|
+
addComponentAction: jest.fn(),
|
|
193
196
|
deleteModuleAction: jest.fn(),
|
|
197
|
+
duplicateModuleAction: jest.fn(),
|
|
198
|
+
copyModuleAction: jest.fn(),
|
|
199
|
+
replaceModuleAction: jest.fn(),
|
|
194
200
|
};
|
|
195
201
|
defaultProps.parentKey = "title";
|
|
196
202
|
defaultProps.objKey = "content";
|
|
@@ -307,10 +313,11 @@ describe("ComponentContainer component rendering", () => {
|
|
|
307
313
|
};
|
|
308
314
|
defaultProps.actionReplace = jest.fn();
|
|
309
315
|
defaultProps.actions = {
|
|
316
|
+
addComponentAction: jest.fn(),
|
|
310
317
|
deleteModuleAction: jest.fn(),
|
|
311
|
-
|
|
312
|
-
duplicateModuleAction: jest.fn,
|
|
318
|
+
duplicateModuleAction: jest.fn(),
|
|
313
319
|
copyModuleAction: jest.fn(),
|
|
320
|
+
replaceModuleAction: jest.fn(),
|
|
314
321
|
};
|
|
315
322
|
defaultProps.canDuplicate = true;
|
|
316
323
|
defaultProps.canReplace = true;
|
|
@@ -345,10 +352,11 @@ describe("ComponentContainer component rendering", () => {
|
|
|
345
352
|
};
|
|
346
353
|
defaultProps.actionReplace = jest.fn();
|
|
347
354
|
defaultProps.actions = {
|
|
355
|
+
addComponentAction: jest.fn(),
|
|
348
356
|
deleteModuleAction: jest.fn(),
|
|
349
|
-
|
|
350
|
-
duplicateModuleAction: jest.fn,
|
|
357
|
+
duplicateModuleAction: jest.fn(),
|
|
351
358
|
copyModuleAction: jest.fn(),
|
|
359
|
+
replaceModuleAction: jest.fn(),
|
|
352
360
|
};
|
|
353
361
|
defaultProps.canDuplicate = true;
|
|
354
362
|
defaultProps.canReplace = true;
|
|
@@ -392,10 +400,11 @@ test("should render the FloatingMenu with options when click Component Container
|
|
|
392
400
|
};
|
|
393
401
|
defaultProps.actionReplace = jest.fn();
|
|
394
402
|
defaultProps.actions = {
|
|
403
|
+
addComponentAction: jest.fn(),
|
|
395
404
|
deleteModuleAction: jest.fn(),
|
|
396
|
-
|
|
397
|
-
duplicateModuleAction: jest.fn,
|
|
405
|
+
duplicateModuleAction: jest.fn(),
|
|
398
406
|
copyModuleAction: jest.fn(),
|
|
407
|
+
replaceModuleAction: jest.fn(),
|
|
399
408
|
};
|
|
400
409
|
defaultProps.canDuplicate = true;
|
|
401
410
|
defaultProps.canReplace = true;
|
|
@@ -440,10 +449,11 @@ test("should render the SideModal with options when click the replace action", a
|
|
|
440
449
|
};
|
|
441
450
|
defaultProps.actionReplace = jest.fn();
|
|
442
451
|
defaultProps.actions = {
|
|
452
|
+
addComponentAction: jest.fn(),
|
|
443
453
|
deleteModuleAction: jest.fn(),
|
|
444
|
-
|
|
445
|
-
duplicateModuleAction: jest.fn,
|
|
454
|
+
duplicateModuleAction: jest.fn(),
|
|
446
455
|
copyModuleAction: jest.fn(),
|
|
456
|
+
replaceModuleAction: jest.fn(),
|
|
447
457
|
};
|
|
448
458
|
defaultProps.canDuplicate = true;
|
|
449
459
|
defaultProps.canReplace = true;
|
|
@@ -496,10 +506,11 @@ test("should not render the drag handle if arrays length is lower than two", asy
|
|
|
496
506
|
};
|
|
497
507
|
defaultProps.actionReplace = jest.fn();
|
|
498
508
|
defaultProps.actions = {
|
|
509
|
+
addComponentAction: jest.fn(),
|
|
499
510
|
deleteModuleAction: jest.fn(),
|
|
500
|
-
|
|
501
|
-
duplicateModuleAction: jest.fn,
|
|
511
|
+
duplicateModuleAction: jest.fn(),
|
|
502
512
|
copyModuleAction: jest.fn(),
|
|
513
|
+
replaceModuleAction: jest.fn(),
|
|
503
514
|
};
|
|
504
515
|
defaultProps.canDuplicate = true;
|
|
505
516
|
defaultProps.canReplace = true;
|
|
@@ -537,10 +548,11 @@ test("should render the drag handle if arrays length is greater than two", async
|
|
|
537
548
|
};
|
|
538
549
|
defaultProps.actionReplace = jest.fn();
|
|
539
550
|
defaultProps.actions = {
|
|
551
|
+
addComponentAction: jest.fn(),
|
|
540
552
|
deleteModuleAction: jest.fn(),
|
|
541
|
-
|
|
542
|
-
duplicateModuleAction: jest.fn,
|
|
553
|
+
duplicateModuleAction: jest.fn(),
|
|
543
554
|
copyModuleAction: jest.fn(),
|
|
555
|
+
replaceModuleAction: jest.fn(),
|
|
544
556
|
};
|
|
545
557
|
defaultProps.canDuplicate = true;
|
|
546
558
|
defaultProps.canReplace = true;
|
|
@@ -91,11 +91,11 @@ const Browser = (props: IBrowserProps): JSX.Element => {
|
|
|
91
91
|
|
|
92
92
|
const deleteModuleSelected = (editorID: number) => {
|
|
93
93
|
actions?.setSelectedContentAction(0);
|
|
94
|
-
actions?.deleteModuleAction(editorID);
|
|
94
|
+
actions?.deleteModuleAction([editorID]);
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
-
const duplicateModuleSelected =
|
|
98
|
-
const duplicatedEditorID =
|
|
97
|
+
const duplicateModuleSelected = (editorID: number) => {
|
|
98
|
+
const duplicatedEditorID = actions?.duplicateModuleAction([editorID]);
|
|
99
99
|
actions?.setSelectedContentAction(duplicatedEditorID);
|
|
100
100
|
};
|
|
101
101
|
|
|
@@ -191,8 +191,8 @@ export interface IBrowserProps {
|
|
|
191
191
|
browserRef?: React.RefObject<HTMLDivElement>;
|
|
192
192
|
actions?: {
|
|
193
193
|
setSelectedContentAction: any;
|
|
194
|
-
deleteModuleAction(editorID: number): void;
|
|
195
|
-
duplicateModuleAction(editorID: number):
|
|
194
|
+
deleteModuleAction(editorID: number[]): void;
|
|
195
|
+
duplicateModuleAction(editorID: number[]): number;
|
|
196
196
|
};
|
|
197
197
|
}
|
|
198
198
|
|
|
@@ -20,16 +20,16 @@ const Header = (props: IHeaderProps) => {
|
|
|
20
20
|
|
|
21
21
|
const removeItem = () => {
|
|
22
22
|
setSelectedContent(parentID);
|
|
23
|
-
deleteModuleAction(editorID);
|
|
23
|
+
deleteModuleAction([editorID]);
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
const duplicateItem = () => {
|
|
27
|
-
duplicateModuleAction(editorID);
|
|
27
|
+
duplicateModuleAction([editorID]);
|
|
28
28
|
setSelectedContent(parentID);
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
const copyItem = () => {
|
|
32
|
-
const isCopied = copyModuleAction(editorID);
|
|
32
|
+
const isCopied = copyModuleAction([editorID]);
|
|
33
33
|
isCopied && toggleToast();
|
|
34
34
|
};
|
|
35
35
|
|
|
@@ -71,7 +71,11 @@ const Header = (props: IHeaderProps) => {
|
|
|
71
71
|
|
|
72
72
|
export interface IHeaderProps {
|
|
73
73
|
schema: any;
|
|
74
|
-
actions:
|
|
74
|
+
actions: {
|
|
75
|
+
deleteModuleAction: (editorID: number[], key?: string) => void;
|
|
76
|
+
duplicateModuleAction: (editorID: number[], key?: string) => number;
|
|
77
|
+
copyModuleAction: (editorID: number[]) => boolean;
|
|
78
|
+
};
|
|
75
79
|
breadcrumb: IBreadcrumbItem[];
|
|
76
80
|
selectedParent: any;
|
|
77
81
|
activatedModules: string[];
|
|
@@ -6,4 +6,7 @@ export const FieldGroup = styled.div<{ full?: boolean }>`
|
|
|
6
6
|
max-height: ${(p) => (p.full ? "auto" : `calc(${p.theme.spacing.l} * 3)`)};
|
|
7
7
|
overflow: auto;
|
|
8
8
|
margin-bottom: ${(p) => p.theme.spacing.xxs};
|
|
9
|
+
& > div {
|
|
10
|
+
margin-bottom: ${p => p.theme.spacing.xxs}
|
|
11
|
+
}
|
|
9
12
|
`;
|
|
@@ -17,6 +17,7 @@ const CheckField = (props: ICheckFieldProps): JSX.Element => {
|
|
|
17
17
|
icon,
|
|
18
18
|
className,
|
|
19
19
|
inversed = false,
|
|
20
|
+
light = false,
|
|
20
21
|
} = props;
|
|
21
22
|
|
|
22
23
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
@@ -28,7 +29,7 @@ const CheckField = (props: ICheckFieldProps): JSX.Element => {
|
|
|
28
29
|
|
|
29
30
|
return (
|
|
30
31
|
<S.Wrapper className={className}>
|
|
31
|
-
<S.Label data-testid="check-field-label" disabled={disabled} inversed={inversed}>
|
|
32
|
+
<S.Label data-testid="check-field-label" disabled={disabled} inversed={inversed} hasText={!!title}>
|
|
32
33
|
{icon ? (
|
|
33
34
|
<S.IconLabelWrapper data-testid="check-field-icon-label">
|
|
34
35
|
<S.IconWrapper>
|
|
@@ -55,6 +56,7 @@ const CheckField = (props: ICheckFieldProps): JSX.Element => {
|
|
|
55
56
|
error={error}
|
|
56
57
|
indeterminate={indeterminate}
|
|
57
58
|
inversed={inversed}
|
|
59
|
+
className={light ? "light" : ""}
|
|
58
60
|
/>
|
|
59
61
|
</S.Label>
|
|
60
62
|
</S.Wrapper>
|
|
@@ -73,6 +75,7 @@ export interface ICheckFieldProps {
|
|
|
73
75
|
icon?: string;
|
|
74
76
|
inversed?: boolean;
|
|
75
77
|
className?: string;
|
|
78
|
+
light?: boolean;
|
|
76
79
|
}
|
|
77
80
|
|
|
78
81
|
export default CheckField;
|
|
@@ -2,12 +2,11 @@ import styled from "styled-components";
|
|
|
2
2
|
|
|
3
3
|
const Wrapper = styled.div``;
|
|
4
4
|
|
|
5
|
-
const Label = styled.label<{ disabled: boolean | undefined; inversed: boolean }>`
|
|
5
|
+
const Label = styled.label<{ disabled: boolean | undefined; inversed: boolean; hasText: boolean }>`
|
|
6
6
|
${(p) => p.theme.textStyle.fieldContent};
|
|
7
|
-
display: block;
|
|
8
7
|
position: relative;
|
|
8
|
+
display: ${(p) => (p.hasText ? "block" : "inline")};
|
|
9
9
|
padding-left: calc(${(p) => p.theme.spacing.s} + ${(p) => p.theme.spacing.xs});
|
|
10
|
-
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
11
10
|
cursor: pointer;
|
|
12
11
|
user-select: none;
|
|
13
12
|
color: ${(p) =>
|
|
@@ -60,6 +59,23 @@ const CheckMark = styled.span<{
|
|
|
60
59
|
border-width: ${(p) => (p.indeterminate ? "0 2px 0 0" : "0 2px 2px 0")};
|
|
61
60
|
transform: ${(p) => (p.indeterminate ? "rotate(90deg)" : "rotate(45deg)")};
|
|
62
61
|
}
|
|
62
|
+
|
|
63
|
+
&.light {
|
|
64
|
+
border-color: ${(p) =>
|
|
65
|
+
p.error
|
|
66
|
+
? p.theme.color.error
|
|
67
|
+
: p.checked || p.indeterminate
|
|
68
|
+
? p.theme.color.interactive01
|
|
69
|
+
: p.theme.color.textLowEmphasis};
|
|
70
|
+
&:hover {
|
|
71
|
+
border-color: ${(p) =>
|
|
72
|
+
p.error
|
|
73
|
+
? p.theme.color.error
|
|
74
|
+
: p.checked || p.indeterminate
|
|
75
|
+
? p.theme.color.interactive01
|
|
76
|
+
: p.theme.color.interactiveInactive};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
63
79
|
`;
|
|
64
80
|
|
|
65
81
|
const Input = styled.input`
|
|
@@ -24,9 +24,10 @@ const CheckGroup = (props: ICheckGroupProps): JSX.Element => {
|
|
|
24
24
|
|
|
25
25
|
if (selectAllOption) {
|
|
26
26
|
const valueArrayNoAll = valueArray.filter((item: string | number) => item !== selectAllOption);
|
|
27
|
-
|
|
27
|
+
const uniqueOption = options && options.length === 2;
|
|
28
28
|
const isAllSelected =
|
|
29
|
-
newValue.value === selectAllOption ||
|
|
29
|
+
newValue.value === selectAllOption ||
|
|
30
|
+
(options && valueArrayNoAll.length === options.length - 1 && !uniqueOption);
|
|
30
31
|
|
|
31
32
|
valueArray = isAllSelected ? [selectAllOption] : valueArrayNoAll;
|
|
32
33
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { CheckField, Icon, IconAction } from "@ax/components";
|
|
3
|
+
import { IBulkAction } from "@ax/types";
|
|
4
|
+
|
|
5
|
+
import * as S from "./style";
|
|
6
|
+
|
|
7
|
+
const BulkHeader = (props: IProps): JSX.Element => {
|
|
8
|
+
const { checkState, selectItems, totalItems, actions, toggleBulk } = props;
|
|
9
|
+
|
|
10
|
+
const handleClick = () => toggleBulk();
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<S.Wrapper>
|
|
14
|
+
<S.CloseWrapper onClick={handleClick}>
|
|
15
|
+
<Icon name="close" size="16" />
|
|
16
|
+
</S.CloseWrapper>
|
|
17
|
+
<S.SelectAllCheckField>
|
|
18
|
+
<CheckField
|
|
19
|
+
key="selectAll"
|
|
20
|
+
name="selectAll"
|
|
21
|
+
value="selectAll"
|
|
22
|
+
onChange={selectItems}
|
|
23
|
+
checked={checkState.isAllSelected}
|
|
24
|
+
indeterminate={checkState.indeterminate}
|
|
25
|
+
disabled={false}
|
|
26
|
+
error={false}
|
|
27
|
+
/>
|
|
28
|
+
</S.SelectAllCheckField>
|
|
29
|
+
<S.Counter>{totalItems} selected</S.Counter>
|
|
30
|
+
<S.BulkActions>
|
|
31
|
+
{actions.map((item: IBulkAction) => (
|
|
32
|
+
<IconAction key={item.text} icon={item.icon || ""} onClick={item.action} size="s" />
|
|
33
|
+
))}
|
|
34
|
+
</S.BulkActions>
|
|
35
|
+
</S.Wrapper>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
interface IProps {
|
|
40
|
+
checkState: any;
|
|
41
|
+
selectItems: () => void;
|
|
42
|
+
totalItems: number;
|
|
43
|
+
toggleBulk: () => void;
|
|
44
|
+
actions: IBulkAction[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export default BulkHeader;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
const Wrapper = styled.div`
|
|
4
|
+
display: flex;
|
|
5
|
+
background-color: ${(p) => p.theme.color.uiBackground03};
|
|
6
|
+
width: 236px;
|
|
7
|
+
height: 32px;
|
|
8
|
+
margin-top: ${(p) => p.theme.spacing.xxs};
|
|
9
|
+
border-radius: ${(p) => p.theme.radii.s};
|
|
10
|
+
align-items: center;
|
|
11
|
+
padding: ${(p) => `0 ${p.theme.spacing.xs}`};
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
const SelectAllCheckField = styled.div`
|
|
15
|
+
margin-left: ${(p) => p.theme.spacing.xxs};
|
|
16
|
+
width: ${(p) => p.theme.spacing.s};
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
const CloseWrapper = styled.div`
|
|
20
|
+
width: ${(p) => p.theme.spacing.s};
|
|
21
|
+
height: ${(p) => p.theme.spacing.s};
|
|
22
|
+
cursor: pointer;
|
|
23
|
+
svg {
|
|
24
|
+
path {
|
|
25
|
+
fill: ${(p) => p.theme.color.iconMediumEmphasis};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
const Counter = styled.div`
|
|
31
|
+
${(p) => p.theme.textStyle.uiS};
|
|
32
|
+
color: ${(p) => p.theme.color.textMediumEmphasis};
|
|
33
|
+
margin-left: ${(p) => p.theme.spacing.xs};
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
const BulkActions = styled.div`
|
|
37
|
+
display: flex;
|
|
38
|
+
margin-left: auto;
|
|
39
|
+
button {
|
|
40
|
+
margin-left: ${(p) => p.theme.spacing.xxs};
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
export { Wrapper, CloseWrapper, SelectAllCheckField, Counter, BulkActions };
|
package/src/components/Fields/ComponentArray/MixableComponentArray/PasteModuleButton/index.tsx
CHANGED
|
@@ -2,23 +2,24 @@ import React, { memo } from "react";
|
|
|
2
2
|
|
|
3
3
|
import { useToast } from "@ax/hooks";
|
|
4
4
|
import { Tooltip, IconAction, Toast } from "@ax/components";
|
|
5
|
-
import { INotification } from "@ax/types";
|
|
5
|
+
import { IModule, INotification } from "@ax/types";
|
|
6
6
|
|
|
7
7
|
const PasteModuleButton = (props: IPasteModuleProps): JSX.Element => {
|
|
8
|
-
const {
|
|
8
|
+
const {
|
|
9
|
+
pasteModule,
|
|
10
|
+
setNotification,
|
|
11
|
+
setHistoryPush,
|
|
12
|
+
editorID,
|
|
13
|
+
isModuleCopyUnavailable,
|
|
14
|
+
arrayKey,
|
|
15
|
+
modulesToPaste,
|
|
16
|
+
slots,
|
|
17
|
+
} = props;
|
|
9
18
|
|
|
10
19
|
const { isVisible, toggleToast, setIsVisible } = useToast();
|
|
11
20
|
|
|
12
21
|
const handlePasteModule = async () => {
|
|
13
|
-
if (
|
|
14
|
-
const pasteResult = await pasteModule(editorID, arrayKey);
|
|
15
|
-
if (pasteResult.error) {
|
|
16
|
-
const { type, text } = pasteResult.error;
|
|
17
|
-
setNotification && setNotification({ type, text });
|
|
18
|
-
} else {
|
|
19
|
-
toggleToast();
|
|
20
|
-
}
|
|
21
|
-
} else {
|
|
22
|
+
if (isModuleCopyUnavailable) {
|
|
22
23
|
const notification: INotification = {
|
|
23
24
|
type: "error",
|
|
24
25
|
text: "You are trying to paste a module that is part of a disabled content type package. To copy it, you must first activate it.",
|
|
@@ -27,6 +28,22 @@ const PasteModuleButton = (props: IPasteModuleProps): JSX.Element => {
|
|
|
27
28
|
};
|
|
28
29
|
setNotification && setNotification(notification);
|
|
29
30
|
}
|
|
31
|
+
|
|
32
|
+
if (slots && modulesToPaste.length > slots) {
|
|
33
|
+
const notification: INotification = {
|
|
34
|
+
type: "error",
|
|
35
|
+
text: "Unable to paste modules: The destination area has a limit on the number of modules allowed. Please adjust the selection accordingly.",
|
|
36
|
+
};
|
|
37
|
+
setNotification && setNotification(notification);
|
|
38
|
+
} else {
|
|
39
|
+
const pasteResult = await pasteModule(editorID, arrayKey, modulesToPaste);
|
|
40
|
+
if (pasteResult?.error) {
|
|
41
|
+
const { type, text } = pasteResult.error;
|
|
42
|
+
setNotification && setNotification({ type, text });
|
|
43
|
+
} else {
|
|
44
|
+
toggleToast();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
30
47
|
};
|
|
31
48
|
|
|
32
49
|
return (
|
|
@@ -40,12 +57,14 @@ const PasteModuleButton = (props: IPasteModuleProps): JSX.Element => {
|
|
|
40
57
|
};
|
|
41
58
|
|
|
42
59
|
export interface IPasteModuleProps {
|
|
43
|
-
pasteModule: (editorID: number, key: string) => Promise<{ error?: INotification }>;
|
|
60
|
+
pasteModule: (editorID: number, key: string, modulesToPaste: IModule[]) => Promise<{ error?: INotification }>;
|
|
44
61
|
setNotification?: (notification: INotification) => void;
|
|
45
62
|
setHistoryPush?: (path: string, isEditor: boolean) => void;
|
|
46
63
|
editorID: number;
|
|
47
64
|
isModuleCopyUnavailable: boolean;
|
|
48
65
|
arrayKey: string;
|
|
66
|
+
modulesToPaste: IModule[];
|
|
67
|
+
slots: number | null;
|
|
49
68
|
}
|
|
50
69
|
|
|
51
70
|
export default memo(PasteModuleButton);
|