@griddo/ax 1.75.224 → 1.75.226

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 (32) hide show
  1. package/package.json +2 -2
  2. package/src/components/ConfigPanel/Form/ConnectedField/NavConnectedField/index.tsx +10 -1
  3. package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/Field/index.tsx +1 -0
  4. package/src/components/ConfigPanel/Form/ConnectedField/PageConnectedField/index.tsx +15 -11
  5. package/src/components/ConfigPanel/Form/index.tsx +22 -2
  6. package/src/components/ConfigPanel/index.tsx +3 -0
  7. package/src/components/ErrorCenter/index.tsx +2 -2
  8. package/src/components/Fields/AnalyticsField/PageAnalytics/atoms.tsx +19 -9
  9. package/src/components/Fields/AnalyticsField/PageAnalytics/index.tsx +6 -3
  10. package/src/components/Fields/AnalyticsField/StructuredDataAnalytics/atoms.tsx +11 -5
  11. package/src/components/Fields/AnalyticsField/StructuredDataAnalytics/index.tsx +4 -3
  12. package/src/components/Fields/AnalyticsField/index.tsx +1 -0
  13. package/src/components/Fields/ConditionalField/index.tsx +3 -2
  14. package/src/components/Fields/MultiCheckSelect/index.tsx +30 -5
  15. package/src/components/Fields/MultiCheckSelect/style.tsx +9 -3
  16. package/src/components/Fields/MultiCheckSelectGroup/index.tsx +6 -1
  17. package/src/components/FieldsBehavior/index.tsx +1 -1
  18. package/src/components/MainWrapper/AppBar/atoms.tsx +3 -1
  19. package/src/components/MainWrapper/AppBar/index.tsx +6 -1
  20. package/src/components/MainWrapper/AppBar/style.tsx +2 -1
  21. package/src/containers/Sites/actions.tsx +3 -4
  22. package/src/forms/fields.tsx +5 -3
  23. package/src/forms/validators.tsx +30 -3
  24. package/src/modules/Content/PageItem/index.tsx +2 -2
  25. package/src/modules/Content/hooks.tsx +1 -1
  26. package/src/modules/Content/index.tsx +4 -1
  27. package/src/modules/Content/utils.tsx +0 -1
  28. package/src/modules/GlobalEditor/Editor/index.tsx +4 -1
  29. package/src/modules/GlobalEditor/index.tsx +35 -35
  30. package/src/modules/PageEditor/Editor/index.tsx +8 -1
  31. package/src/modules/PageEditor/index.tsx +34 -34
  32. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +2 -2
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@griddo/ax",
3
3
  "description": "Griddo Author Experience",
4
- "version": "1.75.224",
4
+ "version": "1.75.226",
5
5
  "authors": [
6
6
  "Álvaro Sánchez' <alvaro.sanches@secuoyas.com>",
7
7
  "Carlos Torres <carlos.torres@secuoyas.com>",
@@ -235,5 +235,5 @@
235
235
  "publishConfig": {
236
236
  "access": "public"
237
237
  },
238
- "gitHead": "1c4e2c06dd6fbee54a37eba2c8f2ebd27b38781f"
238
+ "gitHead": "26895cf4c323b6031eee9c65bfefa8ecaa4eae38"
239
239
  }
@@ -24,6 +24,7 @@ const NavConnectedField = (props: any) => {
24
24
  activatedTemplates,
25
25
  menus,
26
26
  theme,
27
+ disabled,
27
28
  moduleCopy,
28
29
  } = props;
29
30
 
@@ -56,7 +57,15 @@ const NavConnectedField = (props: any) => {
56
57
 
57
58
  if (isConditional) {
58
59
  const innerActions = { ...actions, updateValue, goTo };
59
- innerFields = getInnerFields(field.fields, innerActions, selectedContent, isTemplateActivated, theme, site);
60
+ innerFields = getInnerFields(
61
+ field.fields,
62
+ innerActions,
63
+ selectedContent,
64
+ isTemplateActivated,
65
+ theme,
66
+ disabled,
67
+ site
68
+ );
60
69
  }
61
70
 
62
71
  return (
@@ -45,6 +45,7 @@ const Field = (props: IFieldProps): JSX.Element => {
45
45
  selectedContent,
46
46
  isTemplateActivated,
47
47
  theme,
48
+ disabled,
48
49
  site,
49
50
  errors,
50
51
  deleteError
@@ -37,6 +37,7 @@ const PageConnectedField = (props: any) => {
37
37
  availableDataPacks,
38
38
  template,
39
39
  setHistoryPush,
40
+ isReadOnly,
40
41
  } = props;
41
42
 
42
43
  const isTemplate = field.type === "template";
@@ -55,22 +56,25 @@ const PageConnectedField = (props: any) => {
55
56
  }
56
57
 
57
58
  const parentIsReadOnly =
58
- componentType === "page" &&
59
- objKey === "parent" &&
60
- isTemplateActivated &&
61
- templateConfig &&
62
- templateConfig.modifiableOnPage === false;
59
+ (componentType === "page" &&
60
+ objKey === "parent" &&
61
+ isTemplateActivated &&
62
+ templateConfig &&
63
+ templateConfig.modifiableOnPage === false) ||
64
+ isReadOnly;
65
+
63
66
  const defaultParent =
64
67
  isTemplateActivated && templateConfig && templateConfig.defaultParent ? templateConfig.defaultParent : null;
68
+
65
69
  const hasDefaultIndex = isTemplateActivated && templateConfig && templateConfig.indexDefault !== undefined;
66
70
 
67
- const isReadOnly =
71
+ const isFieldReadOnly =
68
72
  (["parent", "slug"].includes(objKey) && (selectedContent.setAsHome || isPageHome)) || parentIsReadOnly;
73
+
69
74
  const isDisabled =
70
- !isGlobal &&
71
- (isModuleDisabled(selectedContent.component, componentType, activatedModules) ||
72
- isReadOnly ||
73
- !isTemplateActivated);
75
+ (!isGlobal &&
76
+ (isModuleDisabled(selectedContent.component, componentType, activatedModules) || !isTemplateActivated)) ||
77
+ isFieldReadOnly;
74
78
 
75
79
  const isMetaTitleModified = selectedContent.metaTitle && selectedContent.metaTitle !== selectedContent.title;
76
80
 
@@ -176,7 +180,7 @@ const PageConnectedField = (props: any) => {
176
180
  site={site}
177
181
  lang={lang}
178
182
  disabled={isDisabled}
179
- readonly={isReadOnly}
183
+ readonly={isFieldReadOnly}
180
184
  activatedModules={activatedModules}
181
185
  isTemplateActivated={isTemplateActivated}
182
186
  error={error}
@@ -8,8 +8,20 @@ import ConnectedField from "./ConnectedField";
8
8
  import * as S from "./style";
9
9
 
10
10
  export const Form = (props: IFormProps): JSX.Element => {
11
- const { schema, selectedTab, setSelectedTab, actions, isPage, isGlobal, theme, setHistoryPush, header, footer } =
12
- props;
11
+ const {
12
+ schema,
13
+ selectedTab,
14
+ setSelectedTab,
15
+ actions,
16
+ isPage,
17
+ isGlobal,
18
+ theme,
19
+ setHistoryPush,
20
+ header,
21
+ footer,
22
+ isEditLive,
23
+ } = props;
24
+
13
25
  const tabContent = schema.configTabs.find((tab: ISchemaTab) => tab.title === selectedTab);
14
26
  const setTab = (tab: string) => setSelectedTab(tab);
15
27
 
@@ -33,6 +45,7 @@ export const Form = (props: IFormProps): JSX.Element => {
33
45
  isGlobal={isGlobal}
34
46
  theme={theme}
35
47
  setHistoryPush={setHistoryPush}
48
+ isReadOnly={isEditLive}
36
49
  />
37
50
  );
38
51
  };
@@ -65,6 +78,12 @@ export const Form = (props: IFormProps): JSX.Element => {
65
78
  return (
66
79
  <section data-testid="form-section">
67
80
  <Tabs tabs={tabs} active={selectedTab} setSelectedTab={setTab} />
81
+ {selectedTab === "content" && isEditLive && (
82
+ <S.FieldWrapper>
83
+ There are some changes in the <strong>draft associated</strong> with this page. Before making changes to the
84
+ published version, you should <strong>discard or publish your draft</strong>.
85
+ </S.FieldWrapper>
86
+ )}
68
87
  {selectedTab === "content" && !isGlobal && header === 0 && (
69
88
  <S.FieldWrapper>
70
89
  This page doesn&apos;t have a header. Click{" "}
@@ -100,6 +119,7 @@ export interface IFormProps {
100
119
  setHistoryPush?: (path: string, isEditor: boolean) => void;
101
120
  header?: number | null;
102
121
  footer?: number | null;
122
+ isEditLive?: boolean;
103
123
  }
104
124
 
105
125
  export default Form;
@@ -35,6 +35,7 @@ const ConfigPanel = (props: IStateProps): JSX.Element => {
35
35
  lastElementAddedId,
36
36
  header,
37
37
  footer,
38
+ isEditLive,
38
39
  } = props;
39
40
 
40
41
  const wrapperRef = useRef<HTMLDivElement>(null);
@@ -84,6 +85,7 @@ const ConfigPanel = (props: IStateProps): JSX.Element => {
84
85
  setHistoryPush={setHistoryPush}
85
86
  header={header}
86
87
  footer={footer}
88
+ isEditLive={isEditLive}
87
89
  />
88
90
  );
89
91
  }
@@ -125,6 +127,7 @@ export interface IStateProps {
125
127
  lastElementAddedId?: null | number;
126
128
  header?: number | null;
127
129
  footer?: number | null;
130
+ isEditLive?: boolean;
128
131
  }
129
132
 
130
133
  export default ConfigPanel;
@@ -8,7 +8,7 @@ const ErrorCenter = (props: IErrorCenterProps): JSX.Element => {
8
8
  const { errors, actions } = props;
9
9
 
10
10
  const goToElement = (key: string) => {
11
- const element = document.getElementById(key);
11
+ const element = document.getElementById(`gdd_${key}`);
12
12
 
13
13
  if (element) {
14
14
  const pos = element.style.position;
@@ -28,7 +28,7 @@ const ErrorCenter = (props: IErrorCenterProps): JSX.Element => {
28
28
  if (item.hasDeactivatedPackage) {
29
29
  actions?.goToPackage();
30
30
  } else {
31
- item.editorID && actions?.goToError(item.editorID, item.tab, item.template);
31
+ item.editorID !== null && actions?.goToError(item.editorID, item.tab, item.template);
32
32
  goToElement(item.key);
33
33
  }
34
34
  };
@@ -11,8 +11,9 @@ const DimensionsGroup = (props: {
11
11
  analytics: IAnalytics;
12
12
  state: IState;
13
13
  setDimension: (value: Record<string, string>) => void;
14
+ disabled?: boolean;
14
15
  }): JSX.Element => {
15
- const { analytics, state, setDimension } = props;
16
+ const { analytics, state, setDimension, disabled } = props;
16
17
  const { groupSelect, values } = state;
17
18
  const selectedGroup = analytics.groups.find((g) => g.name === groupSelect);
18
19
  const dimensionNames = splitAndTrim(selectedGroup?.dimensions, ";");
@@ -26,7 +27,8 @@ const DimensionsGroup = (props: {
26
27
  <S.FieldsDivider />
27
28
  {groupDimensions &&
28
29
  groupDimensions.map(
29
- (dimension, idx) => dimension && <DimensionValue key={idx} {...{ dimension, setDimension, values }} />
30
+ (dimension, idx) =>
31
+ dimension && <DimensionValue key={idx} {...{ dimension, setDimension, values, disabled }} />
30
32
  )}
31
33
  </>
32
34
  );
@@ -36,8 +38,9 @@ const DimensionsSelection = (props: {
36
38
  analytics: IAnalytics;
37
39
  state: IState;
38
40
  setDimension: (value: Record<string, string>) => void;
41
+ disabled?: boolean;
39
42
  }): JSX.Element => {
40
- const { analytics, state, setDimension } = props;
43
+ const { analytics, state, setDimension, disabled } = props;
41
44
  const { dimensionsSelect, values } = state;
42
45
  const selectedDimensions = analytics.dimensions?.filter((d) => dimensionsSelect.includes(d.name));
43
46
 
@@ -46,19 +49,24 @@ const DimensionsSelection = (props: {
46
49
  {selectedDimensions?.length ? <S.FieldsDivider /> : <></>}
47
50
  {selectedDimensions &&
48
51
  selectedDimensions.map((dimension, idx) => (
49
- <DimensionValue key={idx} {...{ dimension, setDimension, values }} />
52
+ <DimensionValue key={idx} {...{ dimension, setDimension, values, disabled }} />
50
53
  ))}
51
54
  </>
52
55
  );
53
56
  };
54
57
 
55
- const DimensionValue = (props: { dimension: IDimension, setDimension: (value: Record<string, string>) => void, values: Record<string, string> }) => {
56
- const { dimension, setDimension, values } = props;
58
+ const DimensionValue = (props: {
59
+ dimension: IDimension;
60
+ setDimension: (value: Record<string, string>) => void;
61
+ values: Record<string, string>;
62
+ disabled?: boolean;
63
+ }) => {
64
+ const { dimension, setDimension, values, disabled } = props;
57
65
  const dimensionValues = splitAndTrim(dimension?.values, ";");
58
66
  const options = dimensionValues.map((option) => ({ label: option, value: option }));
59
67
  const handleOnChange = (value: string) => {
60
68
  dimension && setDimension({ [dimension.name]: value });
61
- }
69
+ };
62
70
 
63
71
  const isNullValue = dimensionValues.includes("null");
64
72
  const fieldValue = values && dimension ? values[dimension.name] : "";
@@ -70,6 +78,7 @@ const DimensionValue = (props: { dimension: IDimension, setDimension: (value: Re
70
78
  value={fieldValue}
71
79
  onChange={handleOnChange}
72
80
  placeholder="Type a variable"
81
+ disabled={disabled}
73
82
  />
74
83
  ) : (
75
84
  <FieldsBehavior
@@ -79,8 +88,9 @@ const DimensionValue = (props: { dimension: IDimension, setDimension: (value: Re
79
88
  value={fieldValue}
80
89
  onChange={handleOnChange}
81
90
  placeholder="Select variable"
91
+ disabled={disabled}
82
92
  />
83
- )
84
- }
93
+ );
94
+ };
85
95
 
86
96
  export { DimensionsGroup, DimensionsSelection };
@@ -7,7 +7,7 @@ import { DimensionsGroup, DimensionsSelection } from "./atoms";
7
7
  import * as S from "../style";
8
8
 
9
9
  const PageAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
10
- const { value, onChange, analytics } = props;
10
+ const { value, onChange, analytics, disabled } = props;
11
11
 
12
12
  const initialState = {
13
13
  contentSelect: "",
@@ -103,6 +103,7 @@ const PageAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
103
103
  value={state.contentSelect}
104
104
  onChange={handleContentSelect}
105
105
  placeholder="Select Dimensions Options"
106
+ disabled={disabled}
106
107
  />
107
108
  </S.FieldWrapper>
108
109
  {isGroup && (
@@ -114,8 +115,9 @@ const PageAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
114
115
  value={state.groupSelect}
115
116
  onChange={handleGroupSelect}
116
117
  placeholder="Select Group"
118
+ disabled={disabled}
117
119
  />
118
- {!!state.groupSelect && <DimensionsGroup {...{ analytics, state, setDimension }} />}
120
+ {!!state.groupSelect && <DimensionsGroup {...{ analytics, state, setDimension, disabled }} />}
119
121
  </>
120
122
  )}
121
123
  {isIndividual && (
@@ -128,9 +130,10 @@ const PageAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
128
130
  onChange={handleDimensionsSelect}
129
131
  selectAllOption="all"
130
132
  placeholder="Select Dimensions"
133
+ disabled={disabled}
131
134
  floating
132
135
  />
133
- {!!state.dimensionsSelect && <DimensionsSelection {...{ analytics, state, setDimension }} />}
136
+ {!!state.dimensionsSelect && <DimensionsSelection {...{ analytics, state, setDimension, disabled }} />}
134
137
  </>
135
138
  )}
136
139
  </>
@@ -7,7 +7,7 @@ import { IAnalytics, IDimension } from "@ax/types";
7
7
  import { IState } from "..";
8
8
 
9
9
  const TemplateDimensions = (props: ITemplateDimensions): JSX.Element => {
10
- const { analytics, state, setDimension, dimensionNames } = props;
10
+ const { analytics, state, setDimension, dimensionNames, disabled } = props;
11
11
  const { values } = state;
12
12
  const groupDimensions = dimensionNames.map((dimensionName) => {
13
13
  const dimension = analytics.dimensions?.find((dimension) => dimension.name === dimensionName);
@@ -18,7 +18,8 @@ const TemplateDimensions = (props: ITemplateDimensions): JSX.Element => {
18
18
  <>
19
19
  {groupDimensions &&
20
20
  groupDimensions.map(
21
- (dimension, idx) => dimension && <DimensionValue key={idx} {...{ dimension, setDimension, values }} />
21
+ (dimension, idx) =>
22
+ dimension && <DimensionValue key={idx} {...{ dimension, setDimension, values, disabled }} />
22
23
  )}
23
24
  </>
24
25
  );
@@ -28,8 +29,9 @@ const DimensionsSelection = (props: {
28
29
  analytics: IAnalytics;
29
30
  state: IState;
30
31
  setDimension: (value: Record<string, string>) => void;
32
+ disabled?: boolean;
31
33
  }): JSX.Element => {
32
- const { analytics, state, setDimension } = props;
34
+ const { analytics, state, setDimension, disabled } = props;
33
35
  const { dimensionsSelect, values } = state;
34
36
  const selectedDimensions = analytics.dimensions?.filter((d) => dimensionsSelect.includes(d.name));
35
37
 
@@ -37,7 +39,7 @@ const DimensionsSelection = (props: {
37
39
  <>
38
40
  {selectedDimensions &&
39
41
  selectedDimensions.map((dimension, idx) => (
40
- <DimensionValue key={idx} {...{ dimension, setDimension, values }} />
42
+ <DimensionValue key={idx} {...{ dimension, setDimension, values, disabled }} />
41
43
  ))}
42
44
  </>
43
45
  );
@@ -47,8 +49,9 @@ const DimensionValue = (props: {
47
49
  dimension: IDimension;
48
50
  setDimension: (value: Record<string, string>) => void;
49
51
  values: Record<string, string>;
52
+ disabled?: boolean;
50
53
  }) => {
51
- const { dimension, setDimension, values } = props;
54
+ const { dimension, setDimension, values, disabled } = props;
52
55
  const dimensionValues = splitAndTrim(dimension?.values, ";");
53
56
 
54
57
  const options = dimensionValues.map((option) => ({ label: option, value: option }));
@@ -66,6 +69,7 @@ const DimensionValue = (props: {
66
69
  value={fieldValue}
67
70
  onChange={handleOnChange}
68
71
  placeholder="Type a variable"
72
+ disabled={disabled}
69
73
  />
70
74
  ) : (
71
75
  <FieldsBehavior
@@ -75,6 +79,7 @@ const DimensionValue = (props: {
75
79
  value={fieldValue}
76
80
  onChange={handleOnChange}
77
81
  placeholder="Select variable"
82
+ disabled={disabled}
78
83
  />
79
84
  );
80
85
  };
@@ -84,6 +89,7 @@ interface ITemplateDimensions {
84
89
  state: IState;
85
90
  setDimension: (value: Record<string, string>) => void;
86
91
  dimensionNames: string[];
92
+ disabled?: boolean;
87
93
  }
88
94
 
89
95
  export { TemplateDimensions, DimensionsSelection };
@@ -8,7 +8,7 @@ import { TemplateDimensions, DimensionsSelection } from "./atoms";
8
8
  import * as S from "../style";
9
9
 
10
10
  const StructuredDataAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
11
- const { value, onChange, analytics, template } = props;
11
+ const { value, onChange, analytics, template, disabled } = props;
12
12
 
13
13
  const initialState = {
14
14
  dimensionsSelect: [],
@@ -61,7 +61,7 @@ const StructuredDataAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
61
61
 
62
62
  return (
63
63
  <>
64
- <TemplateDimensions dimensionNames={templateDimensions} {...{ analytics, state, setDimension }} />
64
+ <TemplateDimensions dimensionNames={templateDimensions} {...{ analytics, state, setDimension, disabled }} />
65
65
  {dimensionOptions.length > 1 && (
66
66
  <>
67
67
  <S.FieldsDivider />
@@ -73,9 +73,10 @@ const StructuredDataAnalytics = (props: IAnalyticsFieldProps): JSX.Element => {
73
73
  onChange={handleDimensionsSelect}
74
74
  selectAllOption="all"
75
75
  placeholder="Select Dimensions"
76
+ disabled={disabled}
76
77
  floating
77
78
  />
78
- {!!state.dimensionsSelect && <DimensionsSelection {...{ analytics, state, setDimension }} />}
79
+ {!!state.dimensionsSelect && <DimensionsSelection {...{ analytics, state, setDimension, disabled }} />}
79
80
  </>
80
81
  )}
81
82
  </>
@@ -33,6 +33,7 @@ export interface IAnalyticsFieldProps {
33
33
  onChange: (value: IState) => void;
34
34
  analytics: IAnalytics;
35
35
  template: string;
36
+ disabled?: boolean;
36
37
  }
37
38
 
38
39
  export interface IState {
@@ -4,7 +4,7 @@ import { RadioGroup } from "@ax/components";
4
4
  import * as S from "./style";
5
5
 
6
6
  const ConditionalField = (props: IConditionalFieldProps) => {
7
- const { value, options, innerFields, onChange, defaultValue } = props;
7
+ const { value, options, innerFields, onChange, defaultValue, disabled } = props;
8
8
 
9
9
  const safeValue = value === undefined ? defaultValue : value;
10
10
 
@@ -12,7 +12,7 @@ const ConditionalField = (props: IConditionalFieldProps) => {
12
12
 
13
13
  return (
14
14
  <S.Wrapper>
15
- <RadioGroup name="radio" value={safeValue} options={options} onChange={handleChange} />
15
+ <RadioGroup name="radio" value={safeValue} options={options} onChange={handleChange} disabled={disabled} />
16
16
  <S.Content data-testid="conditionalFieldContent">
17
17
  {innerFields &&
18
18
  innerFields.map((item: any) => {
@@ -31,4 +31,5 @@ interface IConditionalFieldProps {
31
31
  innerFields: any;
32
32
  onChange: (value: any) => void;
33
33
  defaultValue?: string | boolean;
34
+ disabled?: boolean;
34
35
  }
@@ -7,8 +7,19 @@ import CheckGroup from "@ax/components/Fields/CheckGroup";
7
7
  import * as S from "./style";
8
8
 
9
9
  const MultiCheckSelect = (props: IMultiCheckSelectProps) => {
10
- const { placeholder, source, value, onChange, site, className, mandatory, options, selectAllOption, floating } =
11
- props;
10
+ const {
11
+ placeholder,
12
+ source,
13
+ value,
14
+ onChange,
15
+ site,
16
+ className,
17
+ mandatory,
18
+ options,
19
+ selectAllOption,
20
+ floating,
21
+ disabled,
22
+ } = props;
12
23
 
13
24
  const [isOpen, setIsOpen] = useState(false);
14
25
 
@@ -18,16 +29,29 @@ const MultiCheckSelect = (props: IMultiCheckSelectProps) => {
18
29
 
19
30
  return (
20
31
  <S.Wrapper className={className} data-testid="multi-check-select-wrapper">
21
- <S.Field isOpen={isOpen} onClick={handleClick} data-testid="field">
32
+ <S.Field isOpen={isOpen} onClick={handleClick} disabled={disabled} data-testid="field">
22
33
  {placeholder} <Asterisk />
23
34
  </S.Field>
24
35
  {isOpen && (
25
36
  <S.DropDown floating={floating}>
26
37
  {options && (
27
- <CheckGroup options={options} value={value} onChange={onChange} selectAllOption={selectAllOption} />
38
+ <CheckGroup
39
+ options={options}
40
+ value={value}
41
+ onChange={onChange}
42
+ selectAllOption={selectAllOption}
43
+ disabled={disabled}
44
+ />
28
45
  )}
29
46
  {source && (
30
- <AsyncCheckGroup source={source} site={site} value={value} onChange={onChange} fullHeight={true} />
47
+ <AsyncCheckGroup
48
+ source={source}
49
+ site={site}
50
+ value={value}
51
+ onChange={onChange}
52
+ fullHeight={true}
53
+ disabled={disabled}
54
+ />
31
55
  )}
32
56
  </S.DropDown>
33
57
  )}
@@ -46,6 +70,7 @@ export interface IMultiCheckSelectProps {
46
70
  options?: { name: string; value: string; title: string }[];
47
71
  selectAllOption?: string;
48
72
  floating?: boolean;
73
+ disabled?: boolean;
49
74
  }
50
75
 
51
76
  export default memo(MultiCheckSelect);
@@ -7,15 +7,21 @@ const Wrapper = styled.div`
7
7
  z-index: 2;
8
8
  `;
9
9
 
10
- const Field = styled.div<{ isOpen: boolean }>`
10
+ const Field = styled.div<{ isOpen: boolean; disabled?: boolean }>`
11
11
  position: relative;
12
12
  ${(p) => p.theme.textStyle?.fieldContent};
13
- color: ${(p) => p.theme.color?.textHighEmphasis};
13
+ color: ${(p) => (p.disabled ? p.theme.color?.interactiveDisabled : p.theme.color?.textHighEmphasis)};
14
14
  display: flex;
15
15
  width: 100%;
16
16
  height: ${(p) => p.theme.spacing?.l};
17
17
  background-color: ${(p) => p.theme.color?.interactiveBackground};
18
- border: 1px solid ${(p) => (p.isOpen ? p.theme.color?.interactive01 : p.theme.color?.uiLine)};
18
+ border: 1px solid
19
+ ${(p) =>
20
+ p.isOpen
21
+ ? p.theme.color?.interactive01
22
+ : p.disabled
23
+ ? p.theme.color?.interactiveDisabled
24
+ : p.theme.color?.uiLine};
19
25
  border-radius: ${(p) => p.theme.radii?.s};
20
26
  align-items: center;
21
27
  cursor: pointer;
@@ -5,7 +5,7 @@ import { ISite } from "@ax/types";
5
5
  import * as S from "./style";
6
6
 
7
7
  const MultiCheckSelectGroup = (props: IMultiCheckSelectGroupProps) => {
8
- const { value, onChange, site, elements, note } = props;
8
+ const { value, onChange, site, elements, note, disabled, error, handleValidation } = props;
9
9
 
10
10
  const completedValue = value ? value : {};
11
11
 
@@ -25,6 +25,7 @@ const MultiCheckSelectGroup = (props: IMultiCheckSelectGroupProps) => {
25
25
  }
26
26
 
27
27
  onChange(newValue);
28
+ error && handleValidation && handleValidation(newValue);
28
29
  };
29
30
 
30
31
  const val = completedValue[key] ? completedValue[key] : [];
@@ -39,6 +40,7 @@ const MultiCheckSelectGroup = (props: IMultiCheckSelectGroupProps) => {
39
40
  site={fromSite}
40
41
  placeholder={placeholder}
41
42
  source={source}
43
+ disabled={disabled}
42
44
  />
43
45
  );
44
46
  })}
@@ -52,6 +54,9 @@ export interface IMultiCheckSelectGroupProps {
52
54
  onChange: (value: Record<string, any[]> | Record<string, never>) => void;
53
55
  site?: ISite;
54
56
  note?: string;
57
+ error?: boolean;
58
+ handleValidation?: (value: Record<string, unknown>, validators?: Record<string, unknown>) => void;
59
+ disabled?: boolean;
55
60
  }
56
61
 
57
62
  export default memo(MultiCheckSelectGroup);
@@ -79,7 +79,7 @@ const FieldsBehavior = (props: any): JSX.Element => {
79
79
  };
80
80
 
81
81
  return (
82
- <S.Wrapper className={wrapperClass} showTitle={showTitle} id={objKey}>
82
+ <S.Wrapper className={wrapperClass} showTitle={showTitle} id={`gdd_${objKey}`}>
83
83
  <S.Content error={errorField} data-testid="fields-behavior-wrapper">
84
84
  <Field
85
85
  {...props}
@@ -52,7 +52,9 @@ const ActionSimpleMenu = (props: any) => {
52
52
  return (
53
53
  menu &&
54
54
  menu.options && (
55
- <S.ActionMenu data-testid="action-simple-menu">{menu.options.map((item: any, i: number) => ActionMenuItem(item, true))}</S.ActionMenu>
55
+ <S.ActionMenu data-testid="action-simple-menu">
56
+ {menu.options.map((item: any, i: number) => ActionMenuItem(item, true))}
57
+ </S.ActionMenu>
56
58
  )
57
59
  );
58
60
  };
@@ -130,7 +130,12 @@ const AppBar = (props: IProps): JSX.Element => {
130
130
  </S.ErrorWrapper>
131
131
  );
132
132
 
133
- const StatusBtn = () => pageStatus && <S.StatusBtn data-testid="status-button"><Icon name={pageStatus} size="24" /></S.StatusBtn>;
133
+ const StatusBtn = () =>
134
+ pageStatus && (
135
+ <S.StatusBtn data-testid="status-button">
136
+ <Icon name={pageStatus} size="24" />
137
+ </S.StatusBtn>
138
+ );
134
139
 
135
140
  const statusMenu = {
136
141
  options: pageStatusActions,
@@ -82,6 +82,7 @@ const ActionMenuTitle = styled.li`
82
82
  const ButtonWrapper = styled.div`
83
83
  padding: ${(p) => `0 ${p.theme.spacing.s} ${p.theme.spacing.xs} ${p.theme.spacing.s}`};
84
84
  margin-left: 0;
85
+ white-space: nowrap;
85
86
 
86
87
  button {
87
88
  width: 100%;
@@ -204,5 +205,5 @@ export {
204
205
  WrapperEnd,
205
206
  WrapperTitle,
206
207
  TabsContent,
207
- StatusBtn
208
+ StatusBtn,
208
209
  };
@@ -578,7 +578,7 @@ function deleteAndRemoveFromSiteBulk(
578
578
  sites: { currentSiteInfo },
579
579
  } = getState();
580
580
 
581
- let responseErrorPages: any = { data: { code: null, message: [] } };
581
+ let responseErrorPages: any = { data: { code: null, message: null } };
582
582
 
583
583
  const responsePageActions = {
584
584
  handleSuccess: () => true,
@@ -604,13 +604,12 @@ function deleteAndRemoveFromSiteBulk(
604
604
  }
605
605
  },
606
606
  handleError: (response: any) => {
607
+ const errorMessages = responseErrorPages.data?.message ? responseErrorPages.data.message : [];
607
608
  responseErrorPages = {
608
609
  ...responseErrorPages,
609
610
  data: {
610
611
  code: responseErrorPages.data?.code || response.data?.code,
611
- message: response.data
612
- ? [...responseErrorPages.data.message, ...response.data.message]
613
- : responseErrorPages.data?.message,
612
+ message: response.data ? [...errorMessages, ...response.data.message] : errorMessages,
614
613
  },
615
614
  };
616
615
 
@@ -8,9 +8,10 @@ const getInnerFields = (
8
8
  selectedContent: IPage,
9
9
  isTemplateActivated: boolean,
10
10
  theme: string,
11
+ parentDisabled?: boolean,
11
12
  site?: ISite,
12
13
  errors?: IErrorItem[],
13
- deleteError?: (error: IErrorItem) => void,
14
+ deleteError?: (error: IErrorItem) => void
14
15
  ) => {
15
16
  let fieldArr: any[] = [];
16
17
 
@@ -27,9 +28,10 @@ const getInnerFields = (
27
28
  selectedContent,
28
29
  isTemplateActivated,
29
30
  theme,
31
+ parentDisabled,
30
32
  site,
31
33
  errors,
32
- deleteError,
34
+ deleteError
33
35
  );
34
36
  }
35
37
 
@@ -45,7 +47,7 @@ const getInnerFields = (
45
47
  goTo={innerActions.goTo}
46
48
  site={site}
47
49
  {...singleFieldProps}
48
- disabled={!isTemplateActivated || singleFieldProps.disabled}
50
+ disabled={!isTemplateActivated || singleFieldProps.disabled || parentDisabled}
49
51
  error={error}
50
52
  deleteError={deleteError}
51
53
  theme={theme}
@@ -12,6 +12,7 @@ import {
12
12
  isValidDate,
13
13
  isValidDateRange,
14
14
  stringToDate,
15
+ isEmptyObj,
15
16
  } from "@ax/helpers";
16
17
 
17
18
  import { findByEditorID } from "@ax/forms";
@@ -177,6 +178,7 @@ const isEmptyField = (value: any, fieldType: string, multiple: boolean) => {
177
178
  case "AsyncCheckGroup":
178
179
  case "CheckGroup":
179
180
  case "ComponentArray":
181
+ case "MultiCheckSelect":
180
182
  return (
181
183
  !value || (Array.isArray(value) && !value.length) || (value.component === "Section" && !value.modules.length)
182
184
  );
@@ -190,6 +192,8 @@ const isEmptyField = (value: any, fieldType: string, multiple: boolean) => {
190
192
  }
191
193
  case "NumberField":
192
194
  return value === null || Number.isNaN(value);
195
+ case "MultiCheckSelectGroup":
196
+ return !value || isEmptyObj(value);
193
197
  default:
194
198
  return typeof value === "string" && value.trim().length === 0;
195
199
  }
@@ -238,7 +242,7 @@ const getValidationErrors = (
238
242
  type: "error",
239
243
  message: getErrorMessage("ERR015", null),
240
244
  validator: { mandatory: true },
241
- editorID: current && current.editorID ? current.editorID : null,
245
+ editorID: current && current.editorID ? current.editorID : 0,
242
246
  component: current && current.component ? current.component : null,
243
247
  name: name ? name : field.title,
244
248
  key: field.key,
@@ -261,7 +265,7 @@ const getValidationErrors = (
261
265
  type: "error",
262
266
  message: getErrorMessage("ERR016", null),
263
267
  validator: { isMockup: { type: field.type, defaultValue } },
264
- editorID: current.editorID ? current.editorID : null,
268
+ editorID: current.editorID ? current.editorID : 0,
265
269
  component: current.component ? current.component : null,
266
270
  name: name ? name : field.title,
267
271
  key: field.key,
@@ -285,7 +289,7 @@ const getValidationErrors = (
285
289
  type: "error",
286
290
  message: errorText,
287
291
  validator: allValidators,
288
- editorID: current.editorID ? current.editorID : null,
292
+ editorID: current.editorID ? current.editorID : 0,
289
293
  component: current.component ? current.component : null,
290
294
  name: name ? name : field.title,
291
295
  key: field.key,
@@ -320,6 +324,29 @@ const getValidationErrors = (
320
324
  errors = [...errors, ...innerErrors];
321
325
  });
322
326
  }
327
+
328
+ if (field.type === "MultiCheckSelectGroup") {
329
+ const multiCheckError = field.elements.some((item: any) =>
330
+ item.mandatory &&
331
+ (!current || !current[field.key] || !current[field.key][item.key] || !current[field.key][item.key].length)
332
+ ? true
333
+ : false
334
+ );
335
+
336
+ if (multiCheckError) {
337
+ errors.push({
338
+ type: "error",
339
+ message: getErrorMessage("ERR015", null),
340
+ validator: { mandatory: true },
341
+ editorID: current && current.editorID ? current.editorID : 0,
342
+ component: current && current.component ? current.component : null,
343
+ name: name ? name : field.title,
344
+ key: field.key,
345
+ tab,
346
+ template,
347
+ });
348
+ }
349
+ }
323
350
  });
324
351
 
325
352
  return errors;
@@ -380,7 +380,7 @@ const PageItem = (props: IPageItemProps): JSX.Element => {
380
380
  const viewPage = () => window.open(page.fullUrl || `${API_URL}/page/go/${page.id}`, "_blank");
381
381
 
382
382
  const viewOption = {
383
- label: "View live",
383
+ label: "View online",
384
384
  icon: "View",
385
385
  action: viewPage,
386
386
  };
@@ -397,7 +397,7 @@ const PageItem = (props: IPageItemProps): JSX.Element => {
397
397
  color: true,
398
398
  },
399
399
  {
400
- label: "Edit live page",
400
+ label: "View live",
401
401
  icon: "active",
402
402
  action: editLivePage,
403
403
  color: true,
@@ -1,4 +1,4 @@
1
- import { useEffect, useState } from "react";
1
+ import { useState } from "react";
2
2
 
3
3
  const useSortedListStatus = () => {
4
4
  const sortedInitialState: {
@@ -317,7 +317,10 @@ const Content = (props: IProps): JSX.Element => {
317
317
  addToBulkSelection(item, bulkFilter);
318
318
  };
319
319
 
320
- const handleSelectAll = () => selectAllItems(bulkFilter);
320
+ const handleSelectAll = () => {
321
+ selectAllItems(bulkFilter);
322
+ setPagesSelected(isStructuredData ? currentDataContent : currentSitePages);
323
+ };
321
324
 
322
325
  const unselectAllItems = () => {
323
326
  resetBulkSelection();
@@ -112,7 +112,6 @@ const filterByStatus = (bulkSelection: number[], currentSitePages: IPage[]): Rec
112
112
  case pageStatus.OFFLINE_PENDING:
113
113
  case pageStatus.OFFLINE:
114
114
  case pageStatus.UPLOAD_PENDING:
115
- notPublishedItems.push(id);
116
115
  haveDraftPage ? draftItems.push(id) : notPublishedItems.push(id);
117
116
  break;
118
117
  case pageStatus.PUBLISHED:
@@ -31,6 +31,7 @@ const Editor = (props: IProps) => {
31
31
  theme,
32
32
  browserRef,
33
33
  setNotification,
34
+ isEditLive,
34
35
  } = props;
35
36
 
36
37
  const actions = {
@@ -48,7 +49,7 @@ const Editor = (props: IProps) => {
48
49
 
49
50
  return (
50
51
  <ResizePanel
51
- leftPanel={<PageBrowser isReadOnly={isReadOnly} theme={theme} browserRef={browserRef} />}
52
+ leftPanel={<PageBrowser isReadOnly={isReadOnly || isEditLive} theme={theme} browserRef={browserRef} />}
52
53
  rightPanel={
53
54
  <ConfigPanel
54
55
  schema={schema}
@@ -66,6 +67,7 @@ const Editor = (props: IProps) => {
66
67
  isReadOnly={isReadOnly}
67
68
  userEditing={userEditing}
68
69
  theme={theme}
70
+ isEditLive={isEditLive}
69
71
  />
70
72
  }
71
73
  />
@@ -101,6 +103,7 @@ interface IPageBrowserDispatchProps {
101
103
  isReadOnly: boolean;
102
104
  theme: string;
103
105
  browserRef: any;
106
+ isEditLive: boolean;
104
107
  }
105
108
 
106
109
  type IProps = IEditorStateProps & IPageBrowserDispatchProps;
@@ -55,9 +55,10 @@ const GlobalEditor = (props: IProps) => {
55
55
 
56
56
  const isPublished = props.pageStatus === pageStatus.PUBLISHED || props.pageStatus === pageStatus.UPLOAD_PENDING;
57
57
  const isDraft = props.pageStatus === pageStatus.MODIFIED;
58
- const hasDraft = editorContent && editorContent.haveDraftPage;
58
+ const hasDraft: boolean = editorContent && !!editorContent.haveDraftPage;
59
59
  const isLivePageChanged = editorContent && editorContent.liveChanged;
60
60
  const structuredData = editorContent ? editorContent.structuredData : "";
61
+ const isEditLive: boolean = isPublished && hasDraft;
61
62
 
62
63
  const errorNotificationText =
63
64
  "There are some errors on the page so you can not publish yet. Please review them in the error panel.";
@@ -173,12 +174,6 @@ const GlobalEditor = (props: IProps) => {
173
174
  updatePageStatus([pageID], pageStatus.OFFLINE_PENDING);
174
175
  };
175
176
 
176
- const cancelPublishPage = () => {
177
- const { updatePageStatus, pageID } = props;
178
-
179
- updatePageStatus([pageID], pageStatus.OFFLINE);
180
- };
181
-
182
177
  const reviewPage = async () => {
183
178
  const { validatePage } = props;
184
179
  const validated = await validatePage(false);
@@ -214,6 +209,13 @@ const GlobalEditor = (props: IProps) => {
214
209
  getPage(pageID, true);
215
210
  };
216
211
 
212
+ const handleCreateDraft = async () => {
213
+ const { savePage } = props;
214
+
215
+ const isSaved = await savePage(true);
216
+ if (isSaved) resetDirty();
217
+ };
218
+
217
219
  const getPublishButton = (status: string) => {
218
220
  switch (status) {
219
221
  case pageStatus.OFFLINE:
@@ -222,20 +224,16 @@ const GlobalEditor = (props: IProps) => {
222
224
  label: "Publish",
223
225
  action: publishPage,
224
226
  };
225
- case pageStatus.UPLOAD_PENDING:
226
- return {
227
- label: "Cancel Publication",
228
- action: cancelPublishPage,
229
- };
230
227
  case pageStatus.PUBLISHED:
231
- return !hasDraft
228
+ case pageStatus.UPLOAD_PENDING:
229
+ return !hasDraft && isDirty
232
230
  ? {
233
- label: "Publish changes",
234
- action: publishChanges,
231
+ label: "Create new draft",
232
+ action: handleCreateDraft,
235
233
  }
236
234
  : {
237
235
  label: "Unpublish",
238
- action: unpublishPage,
236
+ action: hasDraft ? toggleUnpublishModal : unpublishPage,
239
237
  };
240
238
  case pageStatus.MODIFIED:
241
239
  return {
@@ -259,7 +257,7 @@ const GlobalEditor = (props: IProps) => {
259
257
  };
260
258
 
261
259
  const unpublishOption =
262
- props.pageStatus === pageStatus.PUBLISHED && !hasDraft
260
+ props.pageStatus === pageStatus.PUBLISHED && !hasDraft && isDirty
263
261
  ? {
264
262
  label: "Unpublish",
265
263
  icon: "offline",
@@ -276,6 +274,14 @@ const GlobalEditor = (props: IProps) => {
276
274
  }
277
275
  : undefined;
278
276
 
277
+ const deleteOption = !isDraft
278
+ ? {
279
+ label: "Delete",
280
+ icon: "delete",
281
+ action: removePage,
282
+ }
283
+ : undefined;
284
+
279
285
  const downArrowMenu = {
280
286
  displayed: !isReadOnly,
281
287
  button: getPublishButton(props.pageStatus),
@@ -287,11 +293,7 @@ const GlobalEditor = (props: IProps) => {
287
293
  },
288
294
  unpublishOption,
289
295
  discardOption,
290
- {
291
- label: "Delete",
292
- icon: "delete",
293
- action: removePage,
294
- },
296
+ deleteOption,
295
297
  ],
296
298
  };
297
299
 
@@ -300,14 +302,7 @@ const GlobalEditor = (props: IProps) => {
300
302
  const handleSavePage = async () => {
301
303
  const { savePage } = props;
302
304
 
303
- const publishPage = {
304
- status: pageStatus.UPLOAD_PENDING,
305
- };
306
-
307
- const createDraft = isPublished && !hasDraft;
308
- const status = props.pageStatus === pageStatus.PUBLISHED && !createDraft ? publishPage : undefined;
309
-
310
- const isSaved = await savePage(createDraft, status);
305
+ const isSaved = await savePage(false);
311
306
  if (isSaved) resetDirty();
312
307
  };
313
308
 
@@ -331,16 +326,20 @@ const GlobalEditor = (props: IProps) => {
331
326
  switch (props.pageStatus) {
332
327
  case pageStatus.PUBLISHED:
333
328
  case pageStatus.UPLOAD_PENDING:
334
- return !isDirty && !isNewTranslation ? "Saved" : isPublished && hasDraft ? "Save & publish" : "Save draft";
329
+ return !isDirty && !isNewTranslation ? "Saved" : isPublished && hasDraft ? "Save & publish" : "Publish changes";
335
330
  default:
336
- return !isDirty && !isNewTranslation ? "Saved" : "Save";
331
+ return !pageID || isNewTranslation || (isDirty && props.pageStatus !== pageStatus.MODIFIED)
332
+ ? "Save"
333
+ : isDirty && props.pageStatus === pageStatus.MODIFIED
334
+ ? "Save draft"
335
+ : "Saved";
337
336
  }
338
337
  };
339
338
 
340
339
  const rightButtonProps = {
341
340
  label: isSaving ? "Saving" : getSaveLabel(),
342
341
  disabled: (!isDirty && pageID !== null && !isNewTranslation) || isSaving || isReadOnly,
343
- action: handleSavePage,
342
+ action: isPublished ? publishChanges : handleSavePage,
344
343
  };
345
344
 
346
345
  const goToLivePage = () => {
@@ -361,7 +360,7 @@ const GlobalEditor = (props: IProps) => {
361
360
  props.pageStatus === pageStatus.PUBLISHED || isDraft
362
361
  ? [
363
362
  {
364
- label: "View live",
363
+ label: "Go to live page",
365
364
  icon: "view",
366
365
  action: goToLivePage,
367
366
  },
@@ -372,7 +371,7 @@ const GlobalEditor = (props: IProps) => {
372
371
  isDraft || hasDraft
373
372
  ? [
374
373
  {
375
- label: isDraft ? "Edit live" : "Edit draft",
374
+ label: isDraft ? "View live" : "Edit draft",
376
375
  icon: isDraft ? "active" : "modified",
377
376
  action: toggleDraftPage,
378
377
  },
@@ -477,6 +476,7 @@ const GlobalEditor = (props: IProps) => {
477
476
  theme={theme}
478
477
  browserRef={browserRef}
479
478
  setNotification={setNotification}
479
+ isEditLive={isEditLive}
480
480
  />
481
481
  </S.Content>
482
482
  </>
@@ -42,6 +42,7 @@ const Editor = (props: IProps) => {
42
42
  setNotification,
43
43
  restorePageNavigation,
44
44
  content,
45
+ isEditLive,
45
46
  } = props;
46
47
 
47
48
  const { header, footer, theme: pageTheme } = content;
@@ -66,7 +67,11 @@ const Editor = (props: IProps) => {
66
67
  return (
67
68
  <ResizePanel
68
69
  leftPanel={
69
- <PageBrowser isTemplateActivated={isTemplateActivated} isReadOnly={isReadOnly} browserRef={browserRef} />
70
+ <PageBrowser
71
+ isTemplateActivated={isTemplateActivated}
72
+ isReadOnly={isReadOnly || isEditLive}
73
+ browserRef={browserRef}
74
+ />
70
75
  }
71
76
  rightPanel={
72
77
  <ConfigPanel
@@ -90,6 +95,7 @@ const Editor = (props: IProps) => {
90
95
  lastElementAddedId={lastElementAddedId}
91
96
  header={header}
92
97
  footer={footer}
98
+ isEditLive={isEditLive}
93
99
  />
94
100
  }
95
101
  />
@@ -133,6 +139,7 @@ interface IPageBrowserDispatchProps {
133
139
  pageTitle: string;
134
140
  isReadOnly: boolean;
135
141
  browserRef: any;
142
+ isEditLive: boolean;
136
143
  }
137
144
 
138
145
  type IProps = IEditorStateProps & IPageBrowserDispatchProps;
@@ -66,6 +66,7 @@ const PageEditor = (props: IProps) => {
66
66
  const isLivePageChanged = editorContent && editorContent.liveChanged;
67
67
  const isTranslated = pageLanguages.length > 1;
68
68
  const structuredData = editorContent ? editorContent.structuredData : "";
69
+ const isEditLive = isPublished && hasDraft;
69
70
 
70
71
  const errorNotificationText =
71
72
  "There are some errors on the page so you can not publish yet. Please review them in the error panel.";
@@ -189,12 +190,6 @@ const PageEditor = (props: IProps) => {
189
190
  updatePageStatus([pageID], pageStatus.OFFLINE_PENDING);
190
191
  };
191
192
 
192
- const cancelPublishPage = () => {
193
- const { updatePageStatus, pageID } = props;
194
-
195
- updatePageStatus([pageID], pageStatus.OFFLINE);
196
- };
197
-
198
193
  const reviewPage = async () => {
199
194
  const { validatePage } = props;
200
195
  const validated = await validatePage(false);
@@ -231,6 +226,13 @@ const PageEditor = (props: IProps) => {
231
226
  getPage(pageID);
232
227
  };
233
228
 
229
+ const handleCreateDraft = async () => {
230
+ const { savePage } = props;
231
+
232
+ const isSaved = await savePage(true);
233
+ if (isSaved) resetDirty();
234
+ };
235
+
234
236
  const getPublishButton = (status: string) => {
235
237
  switch (status) {
236
238
  case pageStatus.OFFLINE:
@@ -239,20 +241,16 @@ const PageEditor = (props: IProps) => {
239
241
  label: "Publish",
240
242
  action: publishPage,
241
243
  };
242
- case pageStatus.UPLOAD_PENDING:
243
- return {
244
- label: "Cancel Publication",
245
- action: cancelPublishPage,
246
- };
247
244
  case pageStatus.PUBLISHED:
248
- return !isGlobal && !hasDraft
245
+ case pageStatus.UPLOAD_PENDING:
246
+ return !isGlobal && !hasDraft && isDirty
249
247
  ? {
250
- label: "Publish changes",
251
- action: publishChanges,
248
+ label: "Create new draft",
249
+ action: handleCreateDraft,
252
250
  }
253
251
  : {
254
252
  label: "Unpublish",
255
- action: unpublishPage,
253
+ action: hasDraft ? toggleUnpublishModal : unpublishPage,
256
254
  };
257
255
  case pageStatus.MODIFIED:
258
256
  return {
@@ -276,7 +274,7 @@ const PageEditor = (props: IProps) => {
276
274
  };
277
275
 
278
276
  const unpublishOption =
279
- props.pageStatus === pageStatus.PUBLISHED && !hasDraft
277
+ props.pageStatus === pageStatus.PUBLISHED && !hasDraft && isDirty
280
278
  ? {
281
279
  label: "Unpublish",
282
280
  icon: "offline",
@@ -293,6 +291,14 @@ const PageEditor = (props: IProps) => {
293
291
  }
294
292
  : undefined;
295
293
 
294
+ const deleteOption = !isDraft
295
+ ? {
296
+ label: "Delete",
297
+ icon: "delete",
298
+ action: toggleDeleteModal,
299
+ }
300
+ : undefined;
301
+
296
302
  const menuOptions = !isGlobal
297
303
  ? [
298
304
  {
@@ -302,11 +308,7 @@ const PageEditor = (props: IProps) => {
302
308
  },
303
309
  unpublishOption,
304
310
  discardOption,
305
- {
306
- label: "Delete",
307
- icon: "delete",
308
- action: toggleDeleteModal,
309
- },
311
+ deleteOption,
310
312
  ]
311
313
  : [];
312
314
 
@@ -319,14 +321,7 @@ const PageEditor = (props: IProps) => {
319
321
  const handleSavePage = async () => {
320
322
  const { savePage } = props;
321
323
 
322
- const publishPage = {
323
- status: pageStatus.UPLOAD_PENDING,
324
- };
325
-
326
- const createDraft = isPublished && !hasDraft && !isGlobal;
327
- const status = props.pageStatus === pageStatus.PUBLISHED && !createDraft ? publishPage : undefined;
328
-
329
- const isSaved = await savePage(createDraft, status);
324
+ const isSaved = await savePage(false);
330
325
  if (isSaved) resetDirty();
331
326
  };
332
327
 
@@ -381,9 +376,13 @@ const PageEditor = (props: IProps) => {
381
376
  ? "Saved"
382
377
  : isGlobal || (isPublished && hasDraft)
383
378
  ? "Save & publish"
384
- : "Save draft";
379
+ : "Publish changes";
385
380
  default:
386
- return !pageID || isNewTranslation ? "Save" : isDirty ? "Save" : "Saved";
381
+ return !pageID || isNewTranslation || (isDirty && props.pageStatus !== pageStatus.MODIFIED)
382
+ ? "Save"
383
+ : isDirty && props.pageStatus === pageStatus.MODIFIED
384
+ ? "Save draft"
385
+ : "Saved";
387
386
  }
388
387
  };
389
388
 
@@ -394,7 +393,7 @@ const PageEditor = (props: IProps) => {
394
393
  isSaving ||
395
394
  isReadOnly ||
396
395
  (!isTemplateActivated && !isGlobal),
397
- action: handleSavePage,
396
+ action: isPublished ? publishChanges : handleSavePage,
398
397
  };
399
398
 
400
399
  const goToLivePage = () => {
@@ -415,7 +414,7 @@ const PageEditor = (props: IProps) => {
415
414
  props.pageStatus === pageStatus.PUBLISHED || isDraft
416
415
  ? [
417
416
  {
418
- label: "View live",
417
+ label: "Go to live page",
419
418
  icon: "view",
420
419
  action: goToLivePage,
421
420
  },
@@ -426,7 +425,7 @@ const PageEditor = (props: IProps) => {
426
425
  isDraft || hasDraft
427
426
  ? [
428
427
  {
429
- label: isDraft ? "Edit live" : "Edit draft",
428
+ label: isDraft ? "View live" : "Edit draft",
430
429
  icon: isDraft ? "active" : "modified",
431
430
  action: toggleDraftPage,
432
431
  },
@@ -543,6 +542,7 @@ const PageEditor = (props: IProps) => {
543
542
  isReadOnly={isReadOnly}
544
543
  browserRef={browserRef}
545
544
  setNotification={setNotification}
545
+ isEditLive={isEditLive}
546
546
  />
547
547
  </S.Content>
548
548
  </>
@@ -225,7 +225,7 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
225
225
  const viewPage = () => window.open(globalPage.fullUrl || `${API_URL}/page/go/${globalPage.id}`, "_blank");
226
226
 
227
227
  const viewOption = {
228
- label: "View live",
228
+ label: "View online",
229
229
  icon: "View",
230
230
  action: viewPage,
231
231
  };
@@ -238,7 +238,7 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
238
238
  color: true,
239
239
  },
240
240
  {
241
- label: "Edit live page",
241
+ label: "View live",
242
242
  icon: "active",
243
243
  action: handleEditLivePage,
244
244
  color: true,