@griddo/ax 11.7.13-rc.0 → 11.8.0-rc.0

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 (95) hide show
  1. package/package.json +3 -2
  2. package/src/GlobalStore.tsx +3 -0
  3. package/src/api/index.tsx +4 -0
  4. package/src/api/logs.tsx +97 -0
  5. package/src/api/navigation.tsx +1 -1
  6. package/src/api/pages.tsx +1 -1
  7. package/src/api/schemas.tsx +18 -0
  8. package/src/api/users.tsx +17 -0
  9. package/src/components/ConfigPanel/Form/ConnectedField/NavConnectedField/index.tsx +3 -2
  10. package/src/components/ConfigPanel/Form/index.tsx +3 -1
  11. package/src/components/ConfigPanel/index.tsx +3 -0
  12. package/src/components/Fields/SummaryButton/index.tsx +6 -4
  13. package/src/components/Fields/TimeField/style.tsx +0 -1
  14. package/src/components/Fields/TranslateButton/index.tsx +3 -0
  15. package/src/components/FloatingMenu/index.tsx +25 -1
  16. package/src/components/FloatingMenu/style.tsx +3 -2
  17. package/src/components/LanguageMenu/index.tsx +1 -1
  18. package/src/components/MainWrapper/AppBar/index.tsx +4 -3
  19. package/src/components/RestoreModal/index.tsx +51 -0
  20. package/src/components/RestoreModal/style.tsx +7 -0
  21. package/src/components/SearchField/index.tsx +1 -1
  22. package/src/components/SearchField/style.tsx +4 -4
  23. package/src/components/TableFilters/CheckGroupFilter/index.tsx +42 -5
  24. package/src/components/TableFilters/CheckGroupFilter/style.tsx +8 -1
  25. package/src/components/TableFilters/SiteFilter/index.tsx +26 -57
  26. package/src/components/Tag/index.tsx +6 -3
  27. package/src/components/Tag/style.tsx +2 -2
  28. package/src/components/index.tsx +2 -0
  29. package/src/containers/ActivityLog/actions.tsx +262 -0
  30. package/src/containers/ActivityLog/constants.tsx +6 -0
  31. package/src/containers/ActivityLog/index.tsx +4 -0
  32. package/src/containers/ActivityLog/interfaces.tsx +12 -0
  33. package/src/containers/ActivityLog/reducer.tsx +25 -0
  34. package/src/containers/Navigation/Defaults/actions.tsx +4 -3
  35. package/src/containers/StructuredData/actions.tsx +7 -4
  36. package/src/containers/StructuredData/interfaces.tsx +2 -8
  37. package/src/containers/StructuredData/reducer.tsx +2 -8
  38. package/src/containers/Users/actions.tsx +22 -19
  39. package/src/modules/ActivityLog/DetailModal/index.tsx +108 -0
  40. package/src/modules/ActivityLog/DetailModal/style.tsx +52 -0
  41. package/src/modules/ActivityLog/DownloadModal/index.tsx +104 -0
  42. package/src/modules/ActivityLog/DownloadModal/style.tsx +12 -0
  43. package/src/modules/ActivityLog/ItemGroup/index.tsx +27 -0
  44. package/src/modules/ActivityLog/ItemGroup/style.tsx +39 -0
  45. package/src/modules/ActivityLog/ItemLog/EventItem/index.tsx +167 -0
  46. package/src/modules/ActivityLog/ItemLog/EventItem/style.tsx +79 -0
  47. package/src/modules/ActivityLog/ItemLog/index.tsx +24 -0
  48. package/src/modules/ActivityLog/ItemLogUser/UserItem/EventItem/index.tsx +170 -0
  49. package/src/modules/ActivityLog/ItemLogUser/UserItem/EventItem/style.tsx +79 -0
  50. package/src/modules/ActivityLog/ItemLogUser/UserItem/index.tsx +46 -0
  51. package/src/modules/ActivityLog/ItemLogUser/UserItem/style.tsx +60 -0
  52. package/src/modules/ActivityLog/ItemLogUser/index.tsx +25 -0
  53. package/src/modules/ActivityLog/LogFilters/ContentFilter/index.tsx +79 -0
  54. package/src/modules/ActivityLog/LogFilters/DateFilter/index.tsx +91 -0
  55. package/src/modules/ActivityLog/LogFilters/DateFilter/style.tsx +208 -0
  56. package/src/modules/ActivityLog/LogFilters/EventFilter/index.tsx +80 -0
  57. package/src/modules/ActivityLog/LogFilters/OrderFilter/index.tsx +49 -0
  58. package/src/modules/ActivityLog/LogFilters/OrderFilter/style.tsx +35 -0
  59. package/src/modules/ActivityLog/LogFilters/UserFilter/index.tsx +79 -0
  60. package/src/modules/ActivityLog/TableHeader/index.tsx +72 -0
  61. package/src/modules/ActivityLog/TableHeader/style.tsx +73 -0
  62. package/src/modules/ActivityLog/constants.tsx +10 -0
  63. package/src/modules/ActivityLog/hooks.tsx +53 -0
  64. package/src/modules/ActivityLog/index.tsx +313 -0
  65. package/src/modules/ActivityLog/style.tsx +57 -0
  66. package/src/modules/ActivityLog/utils.tsx +31 -0
  67. package/src/modules/Categories/CategoriesList/index.tsx +1 -1
  68. package/src/modules/Forms/FormEditor/Editor/FormConfigPanel/Form/index.tsx +3 -0
  69. package/src/modules/Forms/FormEditor/Editor/FormConfigPanel/index.tsx +3 -0
  70. package/src/modules/Forms/FormEditor/Editor/index.tsx +5 -2
  71. package/src/modules/Forms/FormEditor/index.tsx +20 -3
  72. package/src/modules/GlobalEditor/Editor/index.tsx +3 -0
  73. package/src/modules/GlobalEditor/index.tsx +48 -9
  74. package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/DefaultsBrowser/index.tsx +3 -1
  75. package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/index.tsx +4 -1
  76. package/src/modules/Navigation/Defaults/DefaultsEditor/index.tsx +45 -6
  77. package/src/modules/PageEditor/Editor/index.tsx +4 -1
  78. package/src/modules/PageEditor/index.tsx +46 -7
  79. package/src/modules/Redirects/BulkHeader/TableHeader/style.tsx +1 -7
  80. package/src/modules/StructuredData/Form/index.tsx +56 -7
  81. package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/index.tsx +2 -2
  82. package/src/modules/StructuredData/StructuredDataList/BulkHeader/index.tsx +2 -8
  83. package/src/modules/StructuredData/StructuredDataList/hooks.tsx +9 -9
  84. package/src/modules/StructuredData/StructuredDataList/index.tsx +3 -4
  85. package/src/modules/Users/Roles/index.tsx +0 -2
  86. package/src/modules/Users/UserEdit/index.tsx +12 -28
  87. package/src/modules/Users/UserList/BulkHeader/TableHeader/style.tsx +1 -0
  88. package/src/modules/Users/UserList/UserItem/index.tsx +10 -25
  89. package/src/modules/Users/UserList/index.tsx +8 -10
  90. package/src/routes/multisite.tsx +9 -0
  91. package/src/themes/theme.json +2 -1
  92. package/src/types/forms.tsx +1 -0
  93. package/src/types/index.tsx +8 -0
  94. package/src/types/logs.tsx +12 -0
  95. package/src/components/TableFilters/SiteFilter/style.tsx +0 -28
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@griddo/ax",
3
3
  "description": "Griddo Author Experience",
4
- "version": "11.7.13-rc.0",
4
+ "version": "11.8.0-rc.0",
5
5
  "authors": [
6
6
  "Álvaro Sánchez' <alvaro.sanches@secuoyas.com>",
7
7
  "Diego M. Béjar <diego.bejar@secuoyas.com>",
@@ -159,6 +159,7 @@
159
159
  "@babel/preset-env": "7.26.9",
160
160
  "@babel/preset-react": "7.26.3",
161
161
  "@babel/preset-typescript": "7.26.0",
162
+ "@griddo/api-types": "^1.0.12",
162
163
  "@types/jest": "27.5.2",
163
164
  "@types/redux-mock-store": "1.0.3",
164
165
  "@typescript-eslint/eslint-plugin": "7.18.0",
@@ -223,5 +224,5 @@
223
224
  "publishConfig": {
224
225
  "access": "public"
225
226
  },
226
- "gitHead": "5a9e624c2b0b432051abcac24ffdb6da14aa95c0"
227
+ "gitHead": "130006b9b240d0f92e0950041a0d1012af33e556"
227
228
  }
@@ -22,6 +22,7 @@ import { analyticsReducer, analyticsInitialState } from "./containers/Analytics/
22
22
  import { integrationsReducer, integrationsInitialState } from "./containers/Integrations/reducer";
23
23
  import { fileDriveReducer, fileDriveInitialState } from "./containers/FileDrive/reducer";
24
24
  import { formsReducer, formsInitialState } from "./containers/Forms/reducer";
25
+ import { activityLogReducer, activityLogInitialState } from "./containers/ActivityLog/reducer";
25
26
  import { LOGOUT } from "./containers/App/constants";
26
27
 
27
28
  import { IRootState } from "@ax/types";
@@ -58,6 +59,7 @@ export class GlobalStore {
58
59
  integrations: integrationsReducer as Reducer<any, Action<any>>,
59
60
  fileDrive: fileDriveReducer as Reducer<any, Action<any>>,
60
61
  forms: formsReducer as Reducer<any, Action<any>>,
62
+ activityLog: activityLogReducer as Reducer<any, Action<any>>,
61
63
  });
62
64
 
63
65
  const rootReducer = (state: IRootState | undefined, action: any) => {
@@ -81,6 +83,7 @@ export class GlobalStore {
81
83
  integrations: integrationsInitialState,
82
84
  fileDrive: fileDriveInitialState,
83
85
  forms: formsInitialState,
86
+ activityLog: activityLogInitialState,
84
87
  };
85
88
  }
86
89
 
package/src/api/index.tsx CHANGED
@@ -20,6 +20,8 @@ import roles from "./roles";
20
20
  import integrations from "./integrations";
21
21
  import forms from "./forms";
22
22
  import folders from "./folders";
23
+ import logs from "./logs";
24
+ import schemas from "./schemas";
23
25
 
24
26
  export {
25
27
  sites,
@@ -44,4 +46,6 @@ export {
44
46
  integrations,
45
47
  forms,
46
48
  folders,
49
+ logs,
50
+ schemas,
47
51
  };
@@ -0,0 +1,97 @@
1
+ import { AxiosResponse } from "axios";
2
+ import { template } from "./config";
3
+ import { IServiceConfig, sendRequest } from "./utils";
4
+ import { LogActivityExportRequest, LogActivityPaginationRequest } from "@griddo/api-types";
5
+
6
+ const SERVICES: { [key: string]: IServiceConfig } = {
7
+ GET_LOG_ACTIVITY: {
8
+ ...template,
9
+ endpoint: "/logs/activity-timeline",
10
+ method: "GET",
11
+ },
12
+ GET_LOG_ACTIVITY_BY_DAY: {
13
+ ...template,
14
+ endpoint: "/logs/activity-grouped-day",
15
+ method: "GET",
16
+ },
17
+ GET_LOG_ACTIVITY_BY_USER: {
18
+ ...template,
19
+ endpoint: "/logs/activity-grouped-user",
20
+ method: "GET",
21
+ },
22
+ GET_LOG_EVENT_TYPES: {
23
+ ...template,
24
+ endpoint: "/logs/activity-events-type",
25
+ method: "GET",
26
+ },
27
+ LOG_EXPORT: {
28
+ ...template,
29
+ endpoint: "/logs/activity-timeline/export",
30
+ method: "POST",
31
+ responseType: "blob",
32
+ },
33
+ };
34
+
35
+ const getLogActivityTimeline = async (params: LogActivityPaginationRequest): Promise<AxiosResponse> => {
36
+ const { host, endpoint } = SERVICES.GET_LOG_ACTIVITY;
37
+
38
+ const paramsUrl = new URLSearchParams();
39
+
40
+ for (const [clave, valor] of Object.entries(params)) {
41
+ if (valor !== undefined && valor !== null) {
42
+ paramsUrl.append(clave, String(valor));
43
+ }
44
+ }
45
+
46
+ SERVICES.GET_LOG_ACTIVITY.dynamicUrl = `${host}${endpoint}?${paramsUrl.toString()}`;
47
+
48
+ return sendRequest(SERVICES.GET_LOG_ACTIVITY);
49
+ };
50
+
51
+ const getLogActivityTimelineByDay = async (params: LogActivityPaginationRequest): Promise<AxiosResponse> => {
52
+ const { host, endpoint } = SERVICES.GET_LOG_ACTIVITY_BY_DAY;
53
+
54
+ const paramsUrl = new URLSearchParams();
55
+
56
+ for (const [clave, valor] of Object.entries(params)) {
57
+ if (valor !== undefined && valor !== null) {
58
+ paramsUrl.append(clave, String(valor));
59
+ }
60
+ }
61
+
62
+ SERVICES.GET_LOG_ACTIVITY_BY_DAY.dynamicUrl = `${host}${endpoint}?${paramsUrl.toString()}`;
63
+
64
+ return sendRequest(SERVICES.GET_LOG_ACTIVITY_BY_DAY);
65
+ };
66
+
67
+ const getLogActivityTimelineByUser = async (params: LogActivityPaginationRequest): Promise<AxiosResponse> => {
68
+ const { host, endpoint } = SERVICES.GET_LOG_ACTIVITY_BY_USER;
69
+
70
+ const paramsUrl = new URLSearchParams();
71
+
72
+ for (const [clave, valor] of Object.entries(params)) {
73
+ if (valor !== undefined && valor !== null) {
74
+ paramsUrl.append(clave, String(valor));
75
+ }
76
+ }
77
+
78
+ SERVICES.GET_LOG_ACTIVITY_BY_USER.dynamicUrl = `${host}${endpoint}?${paramsUrl.toString()}`;
79
+
80
+ return sendRequest(SERVICES.GET_LOG_ACTIVITY_BY_USER);
81
+ };
82
+
83
+ const getLogActivityEventTypes = async (): Promise<AxiosResponse> => {
84
+ return sendRequest(SERVICES.GET_LOG_EVENT_TYPES);
85
+ };
86
+
87
+ const logExport = async (data: LogActivityExportRequest): Promise<AxiosResponse> => {
88
+ return sendRequest(SERVICES.LOG_EXPORT, { ...data });
89
+ };
90
+
91
+ export default {
92
+ getLogActivityTimeline,
93
+ getLogActivityTimelineByDay,
94
+ getLogActivityTimelineByUser,
95
+ getLogActivityEventTypes,
96
+ logExport,
97
+ };
@@ -77,7 +77,7 @@ const SERVICES: { [key: string]: IServiceConfig } = {
77
77
  const getNavigation = (id: number) => {
78
78
  const { host, endpoint } = SERVICES.GET_NAVIGATION;
79
79
 
80
- SERVICES.GET_NAVIGATION.dynamicUrl = `${host}${endpoint}${id}`;
80
+ SERVICES.GET_NAVIGATION.dynamicUrl = `${host}${endpoint}${id}?skipDelete=false`;
81
81
 
82
82
  return sendRequest(SERVICES.GET_NAVIGATION);
83
83
  };
package/src/api/pages.tsx CHANGED
@@ -165,7 +165,7 @@ const deletePage = async (pageID: number) => {
165
165
  return sendRequest(SERVICES.DELETE_PAGE);
166
166
  };
167
167
 
168
- const restorePage = async (id: number | number[]) => {
168
+ const restorePage = async (id: number) => {
169
169
  const {
170
170
  host,
171
171
  endpoint: [prefix, suffix],
@@ -0,0 +1,18 @@
1
+ import { template } from "./config";
2
+ import { IServiceConfig, sendRequest } from "./utils";
3
+
4
+ const SERVICES: { [key: string]: IServiceConfig } = {
5
+ SCHEMAS_SELECT_ALL: {
6
+ ...template,
7
+ endpoint: "/schemas/select/all",
8
+ method: "GET",
9
+ },
10
+ };
11
+
12
+ const getSchemasSelectAll = async () => {
13
+ return sendRequest(SERVICES.SCHEMAS_SELECT_ALL);
14
+ };
15
+
16
+ export default {
17
+ getSchemasSelectAll,
18
+ };
package/src/api/users.tsx CHANGED
@@ -47,6 +47,11 @@ const SERVICES: { [key: string]: IServiceConfig } = {
47
47
  endpoint: ["/user/", "/resend"],
48
48
  method: "PUT",
49
49
  },
50
+ REMOVE_USER_SITE: {
51
+ ...template,
52
+ endpoint: ["/user/", "/site/"],
53
+ method: "DELETE",
54
+ },
50
55
  };
51
56
 
52
57
  const getUsers = async (params: any) => {
@@ -133,6 +138,17 @@ const resendInvitation = async (id: number) => {
133
138
  return sendRequest(SERVICES.RESEND);
134
139
  };
135
140
 
141
+ const removeUserFromSite = async (userID: number, siteID: number) => {
142
+ const {
143
+ host,
144
+ endpoint: [prefix, suffix],
145
+ } = SERVICES.REMOVE_USER_SITE;
146
+
147
+ SERVICES.REMOVE_USER_SITE.dynamicUrl = `${host}${prefix}${userID}${suffix}${siteID}`;
148
+
149
+ return sendRequest(SERVICES.REMOVE_USER_SITE);
150
+ };
151
+
136
152
  export default {
137
153
  getUsers,
138
154
  getSiteUsers,
@@ -143,4 +159,5 @@ export default {
143
159
  deleteUser,
144
160
  deleteUserBulk,
145
161
  resendInvitation,
162
+ removeUserFromSite,
146
163
  };
@@ -27,6 +27,7 @@ const NavConnectedField = (props: any): JSX.Element => {
27
27
  disabled,
28
28
  moduleCopy,
29
29
  themeElements,
30
+ isReadOnly,
30
31
  } = props;
31
32
 
32
33
  const updateValue = (key: string, value: any) => {
@@ -44,7 +45,7 @@ const NavConnectedField = (props: any): JSX.Element => {
44
45
  const defaultNavId = currentDefaultNav && currentDefaultNav.id;
45
46
  const selectedContentId = selectedContent && selectedContent.id;
46
47
  const isDefaultNav = defaultNavId === selectedContentId;
47
- const isDisabled = isSetAsDefaultField && isDefaultNav;
48
+ const isDisabled = (isSetAsDefaultField && isDefaultNav) || isReadOnly;
48
49
  const isConditional = field.type === "ConditionalField";
49
50
 
50
51
  let isTemplateActivated = true;
@@ -64,7 +65,7 @@ const NavConnectedField = (props: any): JSX.Element => {
64
65
  selectedContent,
65
66
  isTemplateActivated,
66
67
  theme,
67
- disabled,
68
+ disabled || isDisabled,
68
69
  site
69
70
  );
70
71
  }
@@ -22,6 +22,7 @@ export const Form = (props: IFormProps): JSX.Element => {
22
22
  footer,
23
23
  isEditLive,
24
24
  headerHeight,
25
+ isDisabled,
25
26
  } = props;
26
27
 
27
28
  const isAllowedToEditSitePages = usePermission("content.editContentPages");
@@ -58,7 +59,7 @@ export const Form = (props: IFormProps): JSX.Element => {
58
59
  isGlobal={isGlobal}
59
60
  theme={theme}
60
61
  setHistoryPush={setHistoryPush}
61
- isReadOnly={isEditLive}
62
+ isReadOnly={isEditLive || isDisabled}
62
63
  />
63
64
  );
64
65
  };
@@ -149,6 +150,7 @@ export interface IFormProps {
149
150
  footer?: number | null;
150
151
  isEditLive?: boolean;
151
152
  headerHeight: number;
153
+ isDisabled: boolean;
152
154
  }
153
155
 
154
156
  export default Form;
@@ -36,6 +36,7 @@ const ConfigPanel = (props: IStateProps): JSX.Element => {
36
36
  header,
37
37
  footer,
38
38
  isEditLive,
39
+ isDisabled = false,
39
40
  } = props;
40
41
 
41
42
  const wrapperRef = useRef<HTMLDivElement>(null);
@@ -91,6 +92,7 @@ const ConfigPanel = (props: IStateProps): JSX.Element => {
91
92
  footer={footer}
92
93
  isEditLive={isEditLive}
93
94
  headerHeight={headerHeight}
95
+ isDisabled={isDisabled}
94
96
  />
95
97
  );
96
98
  }
@@ -136,6 +138,7 @@ export interface IStateProps {
136
138
  header?: number | null;
137
139
  footer?: number | null;
138
140
  isEditLive?: boolean;
141
+ isDisabled?: boolean;
139
142
  }
140
143
 
141
144
  export default ConfigPanel;
@@ -6,7 +6,7 @@ import { pageEditorActions } from "@ax/containers/PageEditor";
6
6
  import * as S from "./style";
7
7
 
8
8
  const SummaryButton = (props: ISummaryButtonProps): JSX.Element => {
9
- const { autoSummary, getPageSummary } = props;
9
+ const { autoSummary, getPageSummary, disabled } = props;
10
10
 
11
11
  const initialState = {
12
12
  isLoading: false,
@@ -30,8 +30,8 @@ const SummaryButton = (props: ISummaryButtonProps): JSX.Element => {
30
30
  const buttonText = state.isLoading
31
31
  ? "Processing..."
32
32
  : state.isClicked
33
- ? "Regenerate SEO data with AI"
34
- : "Generate SEO data with AI";
33
+ ? "Regenerate SEO data with AI"
34
+ : "Generate SEO data with AI";
35
35
 
36
36
  return (
37
37
  <>
@@ -47,11 +47,12 @@ const SummaryButton = (props: ISummaryButtonProps): JSX.Element => {
47
47
  onClick={handleClick}
48
48
  icon={!state.isLoading ? "Ia" : undefined}
49
49
  loader={state.isLoading ? "circle" : undefined}
50
+ disabled={disabled}
50
51
  >
51
52
  {buttonText}
52
53
  </S.StyledButton>
53
54
  </S.ButtonWrapper>
54
- {state.error && <S.ErrorText>We're having problems. Please try again in a few minutes.</S.ErrorText>}
55
+ {state.error && <S.ErrorText>We&apos;re having problems. Please try again in a few minutes.</S.ErrorText>}
55
56
  </S.Wrapper>
56
57
  ) : (
57
58
  <></>
@@ -62,6 +63,7 @@ const SummaryButton = (props: ISummaryButtonProps): JSX.Element => {
62
63
 
63
64
  export interface ISummaryButtonProps {
64
65
  autoSummary: boolean;
66
+ disabled: boolean;
65
67
  getPageSummary: () => Promise<boolean>;
66
68
  }
67
69
 
@@ -3,7 +3,6 @@ import styled from "styled-components";
3
3
  const FieldWrapper = styled.div<{ error?: boolean; disabled?: boolean }>`
4
4
  display: flex;
5
5
  height: ${(p) => p.theme.spacing.l};
6
- max-width: ${(p) => `calc(8 * ${p.theme.spacing.l})`};
7
6
  min-width: ${(p) => `calc(5 * ${p.theme.spacing.l})`};
8
7
  width: 100%;
9
8
  border: 1px solid
@@ -26,6 +26,7 @@ const TranslateButton = (props: ITranslateButtonProps): JSX.Element => {
26
26
  isFormIATranslated,
27
27
  getFormTranslation,
28
28
  setIsFormTranslated,
29
+ disabled,
29
30
  } = props;
30
31
 
31
32
  const getContent = (type: "page" | "data" | "form") => {
@@ -99,6 +100,7 @@ const TranslateButton = (props: ITranslateButtonProps): JSX.Element => {
99
100
  onClick={toggleModal}
100
101
  icon={!state.isLoading ? "Ia" : undefined}
101
102
  loader={state.isLoading ? "circle" : undefined}
103
+ disabled={disabled}
102
104
  >
103
105
  {buttonText}
104
106
  </S.StyledButton>
@@ -136,6 +138,7 @@ export interface ITranslateButtonProps {
136
138
  isFormIATranslated: boolean;
137
139
  contentType: "page" | "data" | "form";
138
140
  formContent: FormContent | null;
141
+ disabled: boolean;
139
142
  getPageTranslation: (langID: number) => Promise<boolean>;
140
143
  getDataContentTranslation: (langID: number) => Promise<boolean>;
141
144
  getFormTranslation: (langID: number) => Promise<boolean>;
@@ -14,6 +14,10 @@ const FloatingMenu = (props: IFloatingProps): JSX.Element => {
14
14
  isCheckGroup,
15
15
  reactiveToHover,
16
16
  offset,
17
+ hasMargin = true,
18
+ fixedWidth,
19
+ actionOnClose,
20
+ disabled = false,
17
21
  } = props;
18
22
  const wrapperRef = useRef<HTMLDivElement | null>(null);
19
23
  const buttonRef = useRef<HTMLDivElement | null>(null);
@@ -40,6 +44,10 @@ const FloatingMenu = (props: IFloatingProps): JSX.Element => {
40
44
  return;
41
45
  }
42
46
 
47
+ if (actionOnClose) {
48
+ actionOnClose();
49
+ }
50
+
43
51
  setOpen(false);
44
52
  };
45
53
 
@@ -49,8 +57,16 @@ const FloatingMenu = (props: IFloatingProps): JSX.Element => {
49
57
  isChecked && setOpen(false);
50
58
  };
51
59
 
60
+ const closeWhenApply = (e: React.MouseEvent<HTMLDivElement>) => {
61
+ const target = e.target as HTMLSpanElement;
62
+ if (target.innerHTML === "Apply") {
63
+ setOpen(false);
64
+ }
65
+ };
66
+
52
67
  const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
53
68
  e.stopPropagation();
69
+ if (disabled) return;
54
70
  const buttonWasClicked = buttonRef.current?.contains(e.target as HTMLElement);
55
71
  const optionWasSelected = isOpen && menuOptionsRef.current?.contains(e.target as HTMLElement);
56
72
 
@@ -61,6 +77,8 @@ const FloatingMenu = (props: IFloatingProps): JSX.Element => {
61
77
  if (optionWasSelected) {
62
78
  closeOnSelect ? (isCheckGroup ? closeWhenChecked(e) : setOpen(!isOpen)) : setOpen(true);
63
79
  }
80
+
81
+ closeWhenApply(e);
64
82
  };
65
83
 
66
84
  const handleMouseEnter = (e: React.MouseEvent<HTMLDivElement>) =>
@@ -90,7 +108,9 @@ const FloatingMenu = (props: IFloatingProps): JSX.Element => {
90
108
  offset={offset}
91
109
  data-testid="floating-menu-wrapper"
92
110
  >
93
- <S.Menu>{children}</S.Menu>
111
+ <S.Menu hasMargin={hasMargin} width={fixedWidth}>
112
+ {children}
113
+ </S.Menu>
94
114
  </S.MenuWrapper>
95
115
  )}
96
116
  </S.Wrapper>
@@ -106,6 +126,10 @@ export interface IFloatingProps {
106
126
  isCheckGroup?: boolean;
107
127
  reactiveToHover?: boolean;
108
128
  offset?: number;
129
+ hasMargin?: boolean;
130
+ fixedWidth?: number;
131
+ actionOnClose?(): void;
132
+ disabled?: boolean;
109
133
  }
110
134
 
111
135
  export default FloatingMenu;
@@ -16,8 +16,9 @@ const MenuWrapper = styled.div<{ isInAppBar?: boolean; position: string; offset?
16
16
  ${(p) => p.position}: ${(p) => (p.offset ? `${p.offset}px` : "0")};
17
17
  `;
18
18
 
19
- const Menu = styled.div`
20
- padding: ${(p) => p.theme.spacing.xs} 0;
19
+ const Menu = styled.div<{ hasMargin: boolean; width?: number }>`
20
+ padding: ${(p) => (p.hasMargin ? `${p.theme.spacing.xs} 0` : `${p.theme.spacing.xs} 0 0 0`)};
21
+ width: ${(p) => (p.width ? `${p.width}px` : "auto")};
21
22
  max-width: ${(p) => `calc(${p.theme.spacing.l} * 5)`};
22
23
  min-width: ${(p) => `calc(${p.theme.spacing.m} * 7)`};
23
24
  background: ${(p) => p.theme.color.uiBackground02};
@@ -63,7 +63,7 @@ const LanguageMenu = (props: ILanguageMenuProps): JSX.Element => {
63
63
 
64
64
  return (
65
65
  <S.ActionMenu data-testid="language-menu">
66
- {availableLanguages && availableLanguages.map((item) => languageMenuItem(item))}
66
+ {!!availableLanguages.length && availableLanguages.map((item) => languageMenuItem(item))}
67
67
  </S.ActionMenu>
68
68
  );
69
69
  };
@@ -93,7 +93,7 @@ const AppBar = (props: IProps): JSX.Element => {
93
93
  <Flag name={language.locale} size="24" />
94
94
  </S.FlagWrapper>
95
95
  <S.LanguageTextWrapper data-testid="language-locale-label">{language.locale}</S.LanguageTextWrapper>
96
- <DownArrowButton />
96
+ {!!availableLanguages?.length && <DownArrowButton />}
97
97
  </>
98
98
  ) : (
99
99
  <></>
@@ -218,6 +218,7 @@ const AppBar = (props: IProps): JSX.Element => {
218
218
  isInAppBar={true}
219
219
  position="left"
220
220
  offset={rightButton || rightLineButton ? 0 : -85}
221
+ disabled={!availableLanguages.length}
221
222
  >
222
223
  <LanguageMenu
223
224
  language={language.locale}
@@ -262,13 +263,13 @@ const AppBar = (props: IProps): JSX.Element => {
262
263
  type="button"
263
264
  buttonStyle="line"
264
265
  onClick={rightLineButton.action}
265
- disabled={rightLineButton.disabled}
266
+ {...rightLineButton}
266
267
  >
267
268
  {rightLineButton.label}
268
269
  </Button>
269
270
  )}
270
271
  {rightButton && (
271
- <Button className="button" type="button" onClick={rightButton.action} disabled={rightButton.disabled}>
272
+ <Button className="button" type="button" onClick={rightButton.action} {...rightButton}>
272
273
  {rightButton.label}
273
274
  </Button>
274
275
  )}
@@ -0,0 +1,51 @@
1
+ import React from "react";
2
+
3
+ import { IModal } from "@ax/types";
4
+ import { Modal } from "@ax/components";
5
+
6
+ import * as S from "./style";
7
+
8
+ const RestorePageModal = (props: IRestorePageProps): JSX.Element => {
9
+ const { isOpen, toggleModal, isChild, hasIssues, restorePage } = props;
10
+
11
+ const buttonText = hasIssues ? "Ok, restore it" : "Yes, restore it";
12
+
13
+ const mainRestoreAction = { title: buttonText, onClick: restorePage };
14
+ const secondaryModalAction = { title: "Cancel", onClick: toggleModal };
15
+
16
+ const title = hasIssues ? "Possible compatibility issues" : "Restore item";
17
+ const modalText = hasIssues ? (
18
+ <>
19
+ Restoring deleted items <strong>may cause conflicts if their structure has changed since removal</strong>. Please
20
+ review the restored content after recovery.
21
+ </>
22
+ ) : (
23
+ <>
24
+ You are about to restore this item.{" "}
25
+ <strong>It will reappear on your site exactly as it was before it was deleted.</strong> Are you sure you want to
26
+ continue?
27
+ </>
28
+ );
29
+
30
+ return (
31
+ <Modal
32
+ isOpen={isOpen}
33
+ hide={toggleModal}
34
+ title={title}
35
+ secondaryAction={secondaryModalAction}
36
+ mainAction={mainRestoreAction}
37
+ size="S"
38
+ height={240}
39
+ isChild={isChild}
40
+ >
41
+ <S.ModalContent>{modalText}</S.ModalContent>
42
+ </Modal>
43
+ );
44
+ };
45
+
46
+ interface IRestorePageProps extends IModal {
47
+ hasIssues: boolean;
48
+ restorePage(): void;
49
+ }
50
+
51
+ export default RestorePageModal;
@@ -0,0 +1,7 @@
1
+ import styled from "styled-components";
2
+
3
+ const ModalContent = styled.div`
4
+ padding: ${(p) => `${p.theme.spacing.xs} ${p.theme.spacing.m}`};
5
+ `;
6
+
7
+ export { ModalContent };
@@ -132,7 +132,7 @@ export interface ISearchFieldProps {
132
132
  onFilterChange?(filter: string): void;
133
133
  small?: boolean;
134
134
  focus?: boolean;
135
- size?: "M" | "S" | "XS";
135
+ size?: "M" | "S" | "XS" | "XXS";
136
136
  value?: string;
137
137
  }
138
138
 
@@ -12,8 +12,8 @@ const FieldWrapper = styled.div<{ closeOnInactive: boolean; disabled: boolean }>
12
12
  p.disabled
13
13
  ? p.theme.color.interactiveDisabled
14
14
  : p.closeOnInactive
15
- ? p.theme.color.interactive01
16
- : p.theme.color.uiLine};
15
+ ? p.theme.color.interactive01
16
+ : p.theme.color.uiLine};
17
17
  border-width: ${(p) => (p.closeOnInactive ? "0 0 1px" : "1px")};
18
18
  border-style: solid;
19
19
  border-radius: ${(p) => (p.closeOnInactive ? 0 : p.theme.radii.s)};
@@ -26,13 +26,13 @@ const Input = styled.input<{
26
26
  closeOnInactive: boolean;
27
27
  disabled: boolean;
28
28
  small?: boolean;
29
- inputSize: "M" | "S" | "XS";
29
+ inputSize: "M" | "S" | "XS" | "XXS";
30
30
  }>`
31
31
  ${(p) => p.theme.textStyle.fieldContent};
32
32
  color: ${(p) => p.theme.color.textHighEmphasis};
33
33
  background-color: ${(p) => p.theme.color.interactiveBackground};
34
34
  flex: 1 1 auto;
35
- height: ${(p) => (p.inputSize === "XS" ? "40px" : p.theme.spacing.l)};
35
+ height: ${(p) => (p.inputSize === "XXS" ? "32px" : p.inputSize === "XS" ? "40px" : p.theme.spacing.l)};
36
36
  padding-left: ${(p) => p.theme.spacing.s};
37
37
  border: none;
38
38
  border-radius: ${(p) => (p.closeOnInactive ? 0 : p.theme.radii.s)};