@griddo/ax 11.10.30 → 11.10.34-rc.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@griddo/ax",
3
3
  "description": "Griddo Author Experience",
4
- "version": "11.10.30",
4
+ "version": "11.10.34-rc.1",
5
5
  "authors": [
6
6
  "Álvaro Sánchez' <alvaro.sanches@secuoyas.com>",
7
7
  "Diego M. Béjar <diego.bejar@secuoyas.com>",
@@ -217,5 +217,5 @@
217
217
  "publishConfig": {
218
218
  "access": "public"
219
219
  },
220
- "gitHead": "287381274d3d0fdae99a83dd5bf5633a3ddbb4e2"
220
+ "gitHead": "11975ec49f376d26b53ebd7c338b5eddd961bc5f"
221
221
  }
@@ -1,5 +1,6 @@
1
1
  import axios from "axios";
2
2
  import configureStore from "redux-mock-store";
3
+ import thunk from "redux-thunk";
3
4
  import { ThemeProvider } from "styled-components";
4
5
 
5
6
  import { cleanup, fireEvent, render, screen } from "../../../../../../../config/jest/test-utils";
@@ -9,7 +10,7 @@ import PageConnectedField from "@ax/components/ConfigPanel/Form/ConnectedField/P
9
10
  import { parseTheme } from "@ax/helpers";
10
11
  import globalTheme from "@ax/themes/theme.json";
11
12
 
12
- import thunk from "redux-thunk";
13
+ // Mocks configuration
13
14
 
14
15
  beforeEach(() => {
15
16
  cleanup();
@@ -18,7 +19,7 @@ beforeEach(() => {
18
19
  jest.mock("axios");
19
20
  const mockedAxios = axios as jest.MockedFunction<typeof axios>;
20
21
 
21
- // Mock schemasService to prevent access to undefined config and ensure all helper functions work
22
+ // Mock @ax/services
22
23
  jest.mock("@ax/services", () => ({
23
24
  schemasService: {
24
25
  isLoaded: jest.fn(() => true),
@@ -79,15 +80,54 @@ jest.mock("@ax/services", () => ({
79
80
  },
80
81
  }));
81
82
 
82
- // Mock schemas to prevent getPageSchemas from accessing schemasService
83
+ // Mock @ax/schemas
83
84
  jest.mock("@ax/schemas", () => ({
84
85
  getPageSchemas: jest.fn(() => ({})),
85
86
  getFixedSchemas: jest.fn(() => ({})),
86
87
  }));
87
88
 
89
+ // Mock @ax/containers/PageEditor
90
+ jest.mock("@ax/containers/PageEditor", () => ({
91
+ pageEditorActions: {
92
+ updateEditorContent: jest.fn((_editorID: number, _key: string | string[], _value: any) => {
93
+ return (dispatch: any, getState: any) => {
94
+ const state = getState();
95
+ dispatch({
96
+ type: "pageEditor/SET_EDITOR_CONTENT",
97
+ payload: { editorContent: state.pageEditor.editorContent || {} },
98
+ });
99
+ dispatch({
100
+ type: "pageEditor/SET_SELECTED_PAGE_CONTENT",
101
+ payload: { selectedContent: state.pageEditor.selectedContent || {} },
102
+ });
103
+ };
104
+ }),
105
+ overwriteHeaderConfig: jest.fn(() => ({
106
+ type: "pageEditor/OVERWRITE_HEADER_CONFIG",
107
+ payload: {},
108
+ })),
109
+ setCurrentPageName: jest.fn(() => ({
110
+ type: "pageEditor/SET_CURRENT_PAGE_NAME",
111
+ payload: {},
112
+ })),
113
+ getPageBreadcrumb: jest.fn(() => (dispatch: any) => {
114
+ dispatch({
115
+ type: "pageEditor/SET_BREADCRUMB",
116
+ payload: {},
117
+ });
118
+ }),
119
+ deleteError: jest.fn(() => ({
120
+ type: "pageEditor/DELETE_ERROR",
121
+ payload: {},
122
+ })),
123
+ },
124
+ }));
125
+
126
+ // Configuración de datos (store & props)
127
+
88
128
  const middlewares: any = [thunk];
89
129
  const mockStore = configureStore(middlewares);
90
- const updateEditorContentMock = jest.fn();
130
+
91
131
  const initialStore = {
92
132
  pageEditor: {
93
133
  selectedContent: {
@@ -132,7 +172,9 @@ const initialStore = {
132
172
  savedMenus: null,
133
173
  },
134
174
  navigationActions: {
135
- updateEditorContent: updateEditorContentMock,
175
+ // Aquí usamos un jest.fn() simple placeholder si es necesario,
176
+ // o podemos omitirlo si el componente no lo llama directamente desde el state
177
+ updateEditorContent: jest.fn(),
136
178
  },
137
179
  };
138
180
 
@@ -249,7 +291,6 @@ describe("PageConnectedField component rendering", () => {
249
291
  { store },
250
292
  );
251
293
 
252
- // Check that "Template Options" title is rendered
253
294
  const templateTitles = screen.getAllByText("Template Options");
254
295
  expect(templateTitles).toHaveLength(2); // Title and label
255
296
  const titleElement = templateTitles[0]; // First one should be the title
@@ -257,9 +298,13 @@ describe("PageConnectedField component rendering", () => {
257
298
  });
258
299
 
259
300
  it("should call getPageBreadCrumb", () => {
260
- defaultProps.field.key = "parent";
261
- const initialStore = {
301
+ // Clonamos para no mutar el original en otros tests si corren en paralelo/secuencia
302
+ const props = { ...defaultProps, field: { ...defaultProps.field, key: "parent" } };
303
+
304
+ const localStoreState = {
305
+ ...initialStore,
262
306
  pageEditor: {
307
+ ...initialStore.pageEditor,
263
308
  selectedEditorID: 1,
264
309
  selectedContent: {
265
310
  type: "TextField",
@@ -272,29 +317,13 @@ describe("PageConnectedField component rendering", () => {
272
317
  headerConfig: {},
273
318
  },
274
319
  },
275
- errors: [{}],
276
- },
277
- sites: {
278
- currentSitePages: [
279
- {
280
- editorID: 1,
281
- },
282
- ],
283
- themeElements: null,
284
- },
285
- app: {
286
- lang: { locale: "es-ES", id: 0 },
287
- },
288
- dataPacks: {
289
- templates: [{ id: "default" }, { id: "BasicTemplate" }],
290
- activated: [],
291
320
  },
292
321
  };
293
322
 
294
- const store = mockStore(initialStore);
323
+ const store = mockStore(localStoreState);
295
324
  const component = (
296
325
  <ThemeProvider theme={parseTheme(globalTheme)}>
297
- <PageConnectedField {...defaultProps} />
326
+ <PageConnectedField {...props} />
298
327
  </ThemeProvider>
299
328
  );
300
329
 
@@ -304,16 +333,19 @@ describe("PageConnectedField component rendering", () => {
304
333
  const inputComponent = screen.getByTestId<HTMLInputElement>("input-component");
305
334
  expect(inputComponent).toBeTruthy();
306
335
  fireEvent.change(inputComponent, { target: { value: "value" } });
336
+
307
337
  expect(store.getActions()).toContainEqual({
308
- payload: { editorContent: initialStore.pageEditor.editorContent },
338
+ payload: { editorContent: localStoreState.pageEditor.editorContent },
309
339
  type: "pageEditor/SET_EDITOR_CONTENT",
310
340
  });
311
341
  });
312
342
 
313
343
  it("should call updateEditorContent if key is title and isPageTitle", () => {
314
- defaultProps.field.key = "title";
315
- const initialStore = {
344
+ const props = { ...defaultProps, field: { ...defaultProps.field, key: "title" } };
345
+ const localStoreState = {
346
+ ...initialStore,
316
347
  pageEditor: {
348
+ ...initialStore.pageEditor,
317
349
  selectedEditorID: 1,
318
350
  selectedContent: {
319
351
  type: "TextField",
@@ -326,48 +358,33 @@ describe("PageConnectedField component rendering", () => {
326
358
  headerConfig: {},
327
359
  },
328
360
  },
329
- errors: [{}],
330
- },
331
- sites: {
332
- currentSitePages: [
333
- {
334
- editorID: 1,
335
- },
336
- ],
337
- themeElements: null,
338
- },
339
- app: {
340
- lang: { locale: "es-ES", id: 0 },
341
- },
342
- dataPacks: {
343
- templates: [{ id: "default" }, { id: "BasicTemplate" }],
344
- activated: [],
345
361
  },
346
362
  };
347
363
 
348
- const store = mockStore(initialStore);
364
+ const store = mockStore(localStoreState);
349
365
  const component = (
350
366
  <ThemeProvider theme={parseTheme(globalTheme)}>
351
- <PageConnectedField {...defaultProps} />
367
+ <PageConnectedField {...props} />
352
368
  </ThemeProvider>
353
369
  );
354
370
 
355
371
  render(component, { store });
356
372
 
357
- // It's loading Field -> FieldContainer with a TextField
358
373
  const inputComponent = screen.getByTestId<HTMLInputElement>("input-component");
359
374
  expect(inputComponent).toBeTruthy();
360
375
  fireEvent.change(inputComponent, { target: { value: "value" } });
361
376
  expect(store.getActions()).toContainEqual({
362
- payload: { editorContent: initialStore.pageEditor.editorContent },
377
+ payload: { editorContent: localStoreState.pageEditor.editorContent },
363
378
  type: "pageEditor/SET_EDITOR_CONTENT",
364
379
  });
365
380
  });
366
381
 
367
382
  it("should call updateEditorContent if key is file and isComponentImage", () => {
368
- defaultProps.field.key = "file";
369
- const initialStore = {
383
+ const props = { ...defaultProps, field: { ...defaultProps.field, key: "file" } };
384
+ const localStoreState = {
385
+ ...initialStore,
370
386
  pageEditor: {
387
+ ...initialStore.pageEditor,
371
388
  selectedEditorID: 1,
372
389
  selectedContent: {
373
390
  type: "TextField",
@@ -380,29 +397,13 @@ describe("PageConnectedField component rendering", () => {
380
397
  headerConfig: {},
381
398
  },
382
399
  },
383
- errors: [{}],
384
- },
385
- sites: {
386
- currentSitePages: [
387
- {
388
- editorID: 1,
389
- },
390
- ],
391
- themeElements: null,
392
- },
393
- app: {
394
- lang: { locale: "es-ES", id: 0 },
395
- },
396
- dataPacks: {
397
- templates: [{ id: "default" }, { id: "BasicTemplate" }],
398
- activated: [],
399
400
  },
400
401
  };
401
402
 
402
- const store = mockStore(initialStore);
403
+ const store = mockStore(localStoreState);
403
404
  const component = (
404
405
  <ThemeProvider theme={parseTheme(globalTheme)}>
405
- <PageConnectedField {...defaultProps} />
406
+ <PageConnectedField {...props} />
406
407
  </ThemeProvider>
407
408
  );
408
409
 
@@ -413,17 +414,25 @@ describe("PageConnectedField component rendering", () => {
413
414
  expect(inputComponent).toBeTruthy();
414
415
  fireEvent.change(inputComponent, { target: { value: "value" } });
415
416
  expect(store.getActions()).toContainEqual({
416
- payload: { editorContent: initialStore.pageEditor.editorContent },
417
+ payload: { editorContent: localStoreState.pageEditor.editorContent },
417
418
  type: "pageEditor/SET_EDITOR_CONTENT",
418
419
  });
419
420
  });
420
421
 
421
422
  it("should call updateEditorContent if key is slugTo is present", () => {
422
- defaultProps.field.key = "file";
423
- defaultProps.field.slugTo = "value";
423
+ const props = {
424
+ ...defaultProps,
425
+ field: {
426
+ ...defaultProps.field,
427
+ key: "file",
428
+ slugTo: "value",
429
+ },
430
+ };
424
431
 
425
- const initialStore = {
432
+ const localStoreState = {
433
+ ...initialStore,
426
434
  pageEditor: {
435
+ ...initialStore.pageEditor,
427
436
  selectedEditorID: 1,
428
437
  selectedContent: {
429
438
  type: "TextField",
@@ -436,29 +445,13 @@ describe("PageConnectedField component rendering", () => {
436
445
  headerConfig: {},
437
446
  },
438
447
  },
439
- errors: [{}],
440
- },
441
- sites: {
442
- currentSitePages: [
443
- {
444
- editorID: 1,
445
- },
446
- ],
447
- themeElements: null,
448
- },
449
- app: {
450
- lang: { locale: "es-ES", id: 0 },
451
- },
452
- dataPacks: {
453
- templates: [{ id: "default" }, { id: "BasicTemplate" }],
454
- activated: [],
455
448
  },
456
449
  };
457
450
 
458
- const store = mockStore(initialStore);
451
+ const store = mockStore(localStoreState);
459
452
  const component = (
460
453
  <ThemeProvider theme={parseTheme(globalTheme)}>
461
- <PageConnectedField {...defaultProps} />
454
+ <PageConnectedField {...props} />
462
455
  </ThemeProvider>
463
456
  );
464
457
 
@@ -469,7 +462,7 @@ describe("PageConnectedField component rendering", () => {
469
462
  expect(inputComponent).toBeTruthy();
470
463
  fireEvent.change(inputComponent, { target: { value: "value" } });
471
464
  expect(store.getActions()).toContainEqual({
472
- payload: { editorContent: initialStore.pageEditor.editorContent },
465
+ payload: { editorContent: localStoreState.pageEditor.editorContent },
473
466
  type: "pageEditor/SET_EDITOR_CONTENT",
474
467
  });
475
468
  });
@@ -90,7 +90,6 @@ export const ButtonWrapper = styled.div`
90
90
  `;
91
91
 
92
92
  export const ModalFooter = styled.div`
93
- position: fixed;
94
93
  bottom: 0;
95
94
  left: 0;
96
95
  width: 100%;
@@ -66,7 +66,7 @@ function setHistoryPush(path: string, isEditor?: boolean): (dispatch: Dispatch)
66
66
  if (isEditor) {
67
67
  resetStateValues(dispatch);
68
68
  }
69
- history.push(path);
69
+ history.push(path, isEditor ? { isFromEditor: true } : undefined);
70
70
  } catch (e) {
71
71
  console.log("Error", e);
72
72
  }
@@ -1,9 +1,10 @@
1
- import { useState, useEffect, useRef, memo } from "react";
2
- import isEqual from "lodash.isequal";
1
+ import { memo, useEffect, useRef, useState } from "react";
3
2
 
4
- import { deepClone } from "@ax/helpers";
5
3
  import { cleanPageValues, getIsSavedData } from "@ax/forms";
6
- import { FormContent, IUser } from "@ax/types";
4
+ import { deepClone, isEmptyObj } from "@ax/helpers";
5
+ import type { FormContent, IUser } from "@ax/types";
6
+
7
+ import isEqual from "lodash.isequal";
7
8
 
8
9
  const useDebounce = (value: any) => {
9
10
  // State and setters for debounced value
@@ -26,28 +27,38 @@ const useDebounce = (value: any) => {
26
27
  const useEqualStructured = (component: any) => {
27
28
  return memo(component, (prevProps: any, newProps: any) => {
28
29
  const { fieldKey } = prevProps;
29
- const prevValue = prevProps.form.content && prevProps.form.content[fieldKey];
30
+ const prevValue = prevProps.form.content?.[fieldKey];
30
31
  const newValue = newProps.form.content[fieldKey];
31
32
 
32
33
  return prevValue === newValue;
33
34
  });
34
35
  };
35
36
 
36
- const usePrevious = (value: any, isSaved?: boolean): Record<string, unknown> | undefined => {
37
- const stringValue = value && JSON.stringify(value);
38
- const ref = useRef();
37
+ /**
38
+ * Stores the provided value (object or string) and returns the previous value,
39
+ * updating it only when a "saved" state is detected (either from the external state
40
+ * manager, or explicitly via the second argument). Useful for detecting changes
41
+ * and implementing dirty checks.
42
+ *
43
+ * @param value - The current value to track.
44
+ * @param isSaved - Optional flag to indicate if the value has been saved/reset externally.
45
+ * @returns The previously saved value, or undefined for first render.
46
+ */
47
+ const usePrevious = (value: Record<string, unknown> | string, isSaved?: boolean) => {
48
+ const valueStr = value && JSON.stringify(value);
49
+ const ref = useRef<Record<string, unknown> | string | undefined>(undefined);
39
50
  const isSavedData = getIsSavedData();
40
51
 
41
52
  useEffect(() => {
42
- if (!ref.current) {
43
- ref.current = stringValue && JSON.parse(stringValue);
53
+ if (!ref.current || isEmptyObj(ref.current)) {
54
+ ref.current = valueStr && JSON.parse(valueStr);
44
55
  }
45
- }, [stringValue]);
56
+ }, [valueStr]);
46
57
 
47
- // biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
58
+ // biome-ignore lint/correctness/useExhaustiveDependencies: TODO fix this
48
59
  useEffect(() => {
49
60
  if (isSavedData || isSaved) {
50
- ref.current = stringValue && JSON.parse(stringValue);
61
+ ref.current = valueStr && JSON.parse(valueStr);
51
62
  }
52
63
  }, [isSavedData, isSaved]);
53
64
 
@@ -62,14 +73,12 @@ const useIsDirty = (
62
73
  const [isSaved, setIsSaved] = useState(false);
63
74
  const [isResetting, setIsResetting] = useState(false);
64
75
 
65
- const updatedValuesStr = JSON.stringify(updatedValues);
66
-
67
76
  const prevContent = usePrevious(updatedValues, isSaved);
68
77
 
69
78
  const hasChanged = (): boolean => {
70
- if (prevContent && updatedValuesStr) {
71
- const updatedValuesCloned = updatedValuesStr && deepClone(updatedValuesStr);
79
+ if (prevContent && updatedValues) {
72
80
  const originalValuesCloned = prevContent && deepClone(prevContent);
81
+ const updatedValuesCloned = updatedValues && deepClone(updatedValues);
73
82
 
74
83
  const { cleanUpdatedValues, cleanOriginalValues } = cleanPageValues(updatedValuesCloned, originalValuesCloned);
75
84
 
@@ -95,7 +104,7 @@ const useIsDirty = (
95
104
 
96
105
  if (isNew) {
97
106
  setIsDirty(false);
98
- } else if (prevContent && updatedValuesStr) {
107
+ } else if (prevContent && updatedValues) {
99
108
  const isUpdated = hasChanged();
100
109
 
101
110
  if (isUpdated) {
@@ -105,15 +114,15 @@ const useIsDirty = (
105
114
  setIsDirty(false);
106
115
  }
107
116
  }
108
- }, [updatedValuesStr]);
117
+ }, [updatedValues]);
109
118
 
110
119
  return { isDirty, setIsDirty, resetDirty };
111
120
  };
112
121
 
113
122
  const cleanModified = (updatedValues: any, originalValues: any) => {
114
- delete updatedValues["modified"];
123
+ delete updatedValues.modified;
115
124
 
116
- delete originalValues["modified"];
125
+ delete originalValues.modified;
117
126
 
118
127
  return {
119
128
  cleanUpdatedValues: updatedValues,
@@ -127,6 +136,7 @@ const useShouldBeSaved = (form: Record<string, unknown> | IUser | FormContent) =
127
136
 
128
137
  const stringValue = form && JSON.stringify(form);
129
138
 
139
+ // biome-ignore lint/correctness/useExhaustiveDependencies: TODO fix this
130
140
  useEffect(() => {
131
141
  if (!formRef.current) {
132
142
  formRef.current = stringValue && JSON.parse(stringValue);
@@ -321,7 +321,16 @@ const Content = (props: IProps): JSX.Element => {
321
321
  // biome-ignore lint/correctness/useExhaustiveDependencies: TODO: fix this
322
322
  useLayoutEffect(() => {
323
323
  checkUserSession();
324
- if (history.action !== "POP" && (!locationState || locationState.isFromEditor !== true)) {
324
+ const isFromEditor = locationState?.isFromEditor === true;
325
+ const hasFilterSet = filter && filter !== "unique-pages";
326
+ // Only reset filter if:
327
+ // - Not a POP navigation (back button) - preserve filter when going back
328
+ // - Not coming from editor - preserve filter when returning from editor
329
+ // - If POP without filter set and not from editor, reset to default
330
+ if (history.action !== "POP" && !isFromEditor) {
331
+ setFilter("unique-pages");
332
+ } else if (history.action === "POP" && !hasFilterSet && !isFromEditor) {
333
+ // Only reset on POP if no filter was set and not coming from editor
325
334
  setFilter("unique-pages");
326
335
  }
327
336
  resetPageEditor();
@@ -1,7 +1,10 @@
1
- import React, { useState } from "react";
1
+ import { useState } from "react";
2
2
  import { connect } from "react-redux";
3
3
 
4
- import {
4
+ import { FieldsBehavior, Modal, Tag } from "@ax/components";
5
+ import { dataPacksActions } from "@ax/containers/Settings";
6
+ import { useModal } from "@ax/hooks";
7
+ import type {
5
8
  IDataPack,
6
9
  IDataPackConfigImport,
7
10
  IDataPackConfigImportCategory,
@@ -10,11 +13,9 @@ import {
10
13
  IStructuredData,
11
14
  ITemplate,
12
15
  } from "@ax/types";
13
- import { dataPacksActions } from "@ax/containers/Settings";
14
- import { FieldsBehavior, Modal, Tag } from "@ax/components";
15
- import { useModal } from "@ax/hooks";
16
16
 
17
17
  import TemplateConfig from "./TemplateConfig";
18
+
18
19
  import * as S from "./style";
19
20
 
20
21
  const Form = (props: IProps): JSX.Element => {
@@ -34,11 +35,10 @@ const Form = (props: IProps): JSX.Element => {
34
35
  const value: Record<string, ICategoryValue[]> = {};
35
36
  if (!importValue) return value;
36
37
  importValue.forEach((item: IDataPackConfigImport) => {
37
- item.categories &&
38
- item.categories.forEach((cat: IDataPackConfigImportCategory) => {
39
- const catObj = { value: cat.id, title: cat.title, structuredData: cat.structuredData };
40
- value[cat.structuredData] = value[cat.structuredData] ? [...value[cat.structuredData], catObj] : [catObj];
41
- });
38
+ item.categories?.forEach((cat: IDataPackConfigImportCategory) => {
39
+ const catObj = { value: cat.id, title: cat.title, structuredData: cat.structuredData };
40
+ value[cat.structuredData] = value[cat.structuredData] ? [...value[cat.structuredData], catObj] : [catObj];
41
+ });
42
42
  });
43
43
  return value;
44
44
  };
@@ -48,12 +48,12 @@ const Form = (props: IProps): JSX.Element => {
48
48
  const { isOpen, toggleModal } = useModal();
49
49
 
50
50
  const selectOptions: { value: string; label: string }[] = [];
51
- templates.forEach((template: ITemplate) =>
51
+ templates.forEach((template: ITemplate) => {
52
52
  selectOptions.push({
53
53
  value: template.id,
54
54
  label: template.title,
55
- }),
56
- );
55
+ });
56
+ });
57
57
 
58
58
  const indexDefaultOptions = [
59
59
  {
@@ -100,18 +100,15 @@ const Form = (props: IProps): JSX.Element => {
100
100
  };
101
101
 
102
102
  const getIsGlobal = (id: string): boolean => {
103
- const data = allStructuredData && allStructuredData.site.find((elem) => elem.id === id);
104
- return data && data.local ? false : true;
103
+ const data = allStructuredData?.site.find((elem) => elem.id === id);
104
+ return !data?.local;
105
105
  };
106
106
 
107
107
  const globalPageData = structuredData.find((data) => data.fromPage && !data.local);
108
108
 
109
- const elements =
110
- globalPageData &&
111
- globalPageData.relatedCategories &&
112
- globalPageData.relatedCategories.map((cat) => {
113
- return { source: cat, key: cat, placeholder: getCategoryText(cat), isGlobal: getIsGlobal(cat) };
114
- });
109
+ const elements = globalPageData?.relatedCategories?.map((cat) => {
110
+ return { source: cat, key: cat, placeholder: getCategoryText(cat), isGlobal: getIsGlobal(cat) };
111
+ });
115
112
 
116
113
  const deleteTag = (catID: number) => {
117
114
  const newCategories = configFormData.import.map((type: IDataPackConfigImport) => {
@@ -124,24 +121,19 @@ const Form = (props: IProps): JSX.Element => {
124
121
 
125
122
  const getCategoryLabels = () => (
126
123
  <S.CategoriesWrapper isEmpty={!Object.keys(selectedCategories).length}>
127
- {configFormData &&
128
- configFormData.import &&
129
- configFormData.import.map((data: IDataPackConfigImport) => {
124
+ {configFormData?.import?.map((data: IDataPackConfigImport) => {
125
+ return data.categories?.map((category: IDataPackConfigImportCategory) => {
126
+ const categoryText = getCategoryText(category.structuredData);
127
+ const handleDeleteTag = () => deleteTag(category.id);
130
128
  return (
131
- data.categories &&
132
- data.categories.map((category: IDataPackConfigImportCategory) => {
133
- const categoryText = getCategoryText(category.structuredData);
134
- const handleDeleteTag = () => deleteTag(category.id);
135
- return (
136
- <Tag
137
- key={`${categoryText}-${category.title}`}
138
- text={`${categoryText}: ${category.title}`}
139
- onDeleteAction={handleDeleteTag}
140
- />
141
- );
142
- })
129
+ <Tag
130
+ key={`${categoryText}-${category.title}`}
131
+ text={`${categoryText}: ${category.title}`}
132
+ onDeleteAction={handleDeleteTag}
133
+ />
143
134
  );
144
- })}
135
+ });
136
+ })}
145
137
  </S.CategoriesWrapper>
146
138
  );
147
139
 
@@ -156,10 +148,12 @@ const Form = (props: IProps): JSX.Element => {
156
148
  If you want to get any Global {selected.title} Pages on this site automatically, you can do so by
157
149
  selecting the respective categories.
158
150
  </S.Text>
159
- {configFormData && configFormData.import && getCategoryLabels()}
160
- <S.StyledButton type="button" buttonStyle="text" icon="addCircle" onClick={toggleModal}>
161
- Add Category
162
- </S.StyledButton>
151
+ {configFormData?.import && getCategoryLabels()}
152
+ {elements && elements.length > 0 ? (
153
+ <S.StyledButton type="button" buttonStyle="text" icon="addCircle" onClick={toggleModal}>
154
+ Add Category
155
+ </S.StyledButton>
156
+ ) : null}
163
157
  </S.SubscribeWrapper>
164
158
  </S.SectionContent>
165
159
  )}
@@ -171,7 +165,7 @@ const Form = (props: IProps): JSX.Element => {
171
165
  fieldType="AsyncSelect"
172
166
  site={currentSite}
173
167
  entity={"pages"}
174
- value={configFormData && configFormData.defaultParent}
168
+ value={configFormData?.defaultParent}
175
169
  onChange={setDefaultParent}
176
170
  options={{ excludeDetailPages: true }}
177
171
  />
@@ -179,14 +173,14 @@ const Form = (props: IProps): JSX.Element => {
179
173
  title="Modifiable in page"
180
174
  name="defaultParent"
181
175
  fieldType="ToggleField"
182
- value={(configFormData && configFormData.modifiableOnPage) || false}
176
+ value={configFormData?.modifiableOnPage || false}
183
177
  onChange={setModifiableOnPage}
184
178
  />
185
179
  <FieldsBehavior
186
180
  title="Meta robots index default"
187
181
  name="indexDefault"
188
182
  fieldType="RadioGroup"
189
- value={(configFormData && configFormData.indexDefault) || false}
183
+ value={configFormData?.indexDefault || false}
190
184
  options={indexDefaultOptions}
191
185
  onChange={setIndexDefault}
192
186
  />
@@ -92,7 +92,7 @@ const Form = (props: IProps) => {
92
92
  const isDeleted = !!form?.deleted;
93
93
  const isDisabled = isDeleted || disabledDatapack;
94
94
 
95
- const isDataTranslatable = currentStructuredData && currentStructuredData.translate;
95
+ const isDataTranslatable = currentStructuredData?.translate;
96
96
  const isScheduled = !!form && !!form.publicationScheduled;
97
97
  const status = isScheduled
98
98
  ? "scheduled"
@@ -117,27 +117,25 @@ const Form = (props: IProps) => {
117
117
  }
118
118
  }, []);
119
119
 
120
- const Fields =
121
- fieldsTranslate &&
122
- fieldsTranslate
123
- .filter((field: ISchemaField) => !field.hidden)
124
- .map((field: ISchemaField, i: number) => {
125
- const { type, key } = field;
126
- if (key === "title") {
127
- title = form?.content && form.content[key] ? form.content[key] : "";
128
- }
129
- return (
130
- <ConnectedField
131
- fieldKey={key}
132
- field={field}
133
- key={`${type}${i}`}
134
- site={site}
135
- disabled={isDisabled}
136
- theme={site ? site.theme : theme}
137
- languages={languages}
138
- />
139
- );
140
- });
120
+ const Fields = fieldsTranslate
121
+ ?.filter((field: ISchemaField) => !field.hidden)
122
+ .map((field: ISchemaField, i: number) => {
123
+ const { type, key } = field;
124
+ if (key === "title") {
125
+ title = form?.content?.[key] ? form.content[key] : "";
126
+ }
127
+ return (
128
+ <ConnectedField
129
+ fieldKey={key}
130
+ field={field}
131
+ key={`${type}${i}`}
132
+ site={site}
133
+ disabled={isDisabled}
134
+ theme={site ? site.theme : theme}
135
+ languages={languages}
136
+ />
137
+ );
138
+ });
141
139
 
142
140
  const handleSave = async (publish: boolean, scheduleDate?: string | null) => {
143
141
  const validated = publish && !skipReviewOnPublish ? await validateForm(true) : true;
@@ -195,7 +193,7 @@ const Form = (props: IProps) => {
195
193
 
196
194
  const availableLanguages = isDisabled ? currentLanguages : languages;
197
195
 
198
- const setRoute = (path: string) => setHistoryPush(path);
196
+ const setRoute = (path: string) => setHistoryPush(path, true);
199
197
 
200
198
  const modalText = (
201
199
  <>