@griddo/ax 10.6.9 → 10.6.12

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 (70) hide show
  1. package/package.json +2 -2
  2. package/src/components/Fields/CheckField/index.tsx +16 -4
  3. package/src/components/Fields/DateField/index.tsx +9 -3
  4. package/src/components/Fields/TimeField/index.tsx +8 -2
  5. package/src/components/Icon/components/CancelEvent.js +10 -0
  6. package/src/components/Icon/svgs/cancel-event.svg +3 -0
  7. package/src/components/MainWrapper/AppBar/index.tsx +8 -1
  8. package/src/components/MainWrapper/AppBar/style.tsx +9 -1
  9. package/src/components/MainWrapper/index.tsx +1 -0
  10. package/src/components/Modal/index.tsx +17 -1
  11. package/src/components/ScheduleModal/index.tsx +100 -0
  12. package/src/components/ScheduleModal/style.tsx +19 -0
  13. package/src/components/TableFilters/LiveFilter/index.tsx +1 -1
  14. package/src/components/index.tsx +3 -0
  15. package/src/containers/PageEditor/actions.tsx +21 -1
  16. package/src/containers/PageEditor/interfaces.tsx +1 -0
  17. package/src/forms/validators.tsx +3 -2
  18. package/src/helpers/dates.tsx +6 -0
  19. package/src/helpers/index.tsx +2 -0
  20. package/src/hooks/bulk.tsx +5 -1
  21. package/src/modules/Categories/CategoriesList/BulkHeader/TableHeader/index.tsx +17 -12
  22. package/src/modules/Categories/CategoriesList/BulkHeader/index.tsx +5 -1
  23. package/src/modules/Categories/CategoriesList/CategoryItem/index.tsx +3 -1
  24. package/src/modules/Categories/CategoriesList/index.tsx +3 -0
  25. package/src/modules/Content/BulkHeader/TableHeader/index.tsx +15 -9
  26. package/src/modules/Content/BulkHeader/index.tsx +3 -0
  27. package/src/modules/Content/PageItem/index.tsx +10 -4
  28. package/src/modules/Content/index.tsx +4 -0
  29. package/src/modules/Content/utils.tsx +13 -10
  30. package/src/modules/FileDrive/BulkListHeader/TableHeader/index.tsx +15 -11
  31. package/src/modules/FileDrive/BulkListHeader/index.tsx +4 -1
  32. package/src/modules/FileDrive/ListItem/index.tsx +3 -1
  33. package/src/modules/FileDrive/index.tsx +6 -3
  34. package/src/modules/GlobalEditor/index.tsx +83 -3
  35. package/src/modules/GlobalEditor/style.tsx +12 -1
  36. package/src/modules/Navigation/Defaults/BulkHeader/TableHeader/index.tsx +18 -12
  37. package/src/modules/Navigation/Defaults/BulkHeader/index.tsx +11 -3
  38. package/src/modules/Navigation/Defaults/Item/index.tsx +9 -2
  39. package/src/modules/Navigation/Defaults/index.tsx +4 -0
  40. package/src/modules/PageEditor/index.tsx +82 -2
  41. package/src/modules/PageEditor/style.tsx +9 -1
  42. package/src/modules/Redirects/BulkHeader/TableHeader/index.tsx +17 -10
  43. package/src/modules/Redirects/BulkHeader/index.tsx +4 -0
  44. package/src/modules/Redirects/RedirectItem/index.tsx +8 -1
  45. package/src/modules/Redirects/index.tsx +3 -0
  46. package/src/modules/Settings/Integrations/BulkHeader/TableHeader/index.tsx +16 -11
  47. package/src/modules/Settings/Integrations/BulkHeader/index.tsx +5 -1
  48. package/src/modules/Settings/Integrations/IntegrationItem/index.tsx +3 -1
  49. package/src/modules/Settings/Integrations/index.tsx +3 -0
  50. package/src/modules/Sites/SitesList/ListView/BulkHeader/TableHeader/index.tsx +15 -10
  51. package/src/modules/Sites/SitesList/ListView/BulkHeader/index.tsx +3 -0
  52. package/src/modules/Sites/SitesList/ListView/ListSiteItem/index.tsx +14 -3
  53. package/src/modules/Sites/SitesList/index.tsx +3 -0
  54. package/src/modules/StructuredData/Form/index.tsx +72 -6
  55. package/src/modules/StructuredData/Form/style.tsx +17 -1
  56. package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/index.tsx +15 -9
  57. package/src/modules/StructuredData/StructuredDataList/BulkHeader/index.tsx +3 -0
  58. package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +10 -3
  59. package/src/modules/StructuredData/StructuredDataList/StructuredDataItem/index.tsx +13 -4
  60. package/src/modules/StructuredData/StructuredDataList/atoms.tsx +1 -1
  61. package/src/modules/StructuredData/StructuredDataList/index.tsx +4 -0
  62. package/src/modules/Users/Roles/BulkHeader/TableHeader/index.tsx +24 -10
  63. package/src/modules/Users/Roles/BulkHeader/index.tsx +4 -0
  64. package/src/modules/Users/Roles/RoleItem/index.tsx +3 -2
  65. package/src/modules/Users/Roles/index.tsx +12 -2
  66. package/src/modules/Users/UserList/BulkHeader/TableHeader/index.tsx +17 -10
  67. package/src/modules/Users/UserList/BulkHeader/index.tsx +4 -0
  68. package/src/modules/Users/UserList/UserItem/index.tsx +3 -1
  69. package/src/modules/Users/UserList/index.tsx +24 -7
  70. package/src/types/index.tsx +2 -0
@@ -244,6 +244,7 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
244
244
  checkState,
245
245
  addToBulkSelection,
246
246
  selectAllItems,
247
+ setHoverCheck,
247
248
  } = useBulkSelection(sitesIds);
248
249
 
249
250
  const bulkFilter = (bulkSelection: number[]) => filterByStatus(bulkSelection, sites);
@@ -285,6 +286,7 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
285
286
  sortedListStatus={currentConfig.sortedListStatus}
286
287
  filterItems={filterItems}
287
288
  filterValues={currentConfig.filterValues}
289
+ setHoverCheck={setHoverCheck}
288
290
  />
289
291
  );
290
292
 
@@ -301,6 +303,7 @@ const SitesList = (props: ISitesListProps): JSX.Element => {
301
303
  isSelected={isItemSelected}
302
304
  onCheck={handleAddToBulk}
303
305
  getParams={getParams}
306
+ hoverCheck={checkState.hoverCheck}
304
307
  />
305
308
  );
306
309
  })
@@ -3,11 +3,11 @@ import { connect } from "react-redux";
3
3
 
4
4
  import { IDataPack, IErrorItem, ILanguage, INotification, IRootState, ISchemaField, ISite } from "@ax/types";
5
5
  import { structuredDataActions } from "@ax/containers/StructuredData";
6
- import { MainWrapper, ErrorToast, Notification, Loading } from "@ax/components";
7
- import { getActivatedDataPacksIds, getDefaultTheme } from "@ax/helpers";
6
+ import { MainWrapper, ErrorToast, Notification, Loading, CancelScheduleModal, ScheduleModal } from "@ax/components";
7
+ import { dateToString, getActivatedDataPacksIds, getDefaultTheme } from "@ax/helpers";
8
8
  import { appActions } from "@ax/containers/App";
9
9
  import { RouteLeavingGuard } from "@ax/guards";
10
- import { useIsDirty } from "@ax/hooks";
10
+ import { useIsDirty, useModal } from "@ax/hooks";
11
11
  import { setIsSavedData } from "@ax/forms";
12
12
  import { dataPacksActions } from "@ax/containers/Settings/DataPacks";
13
13
 
@@ -44,6 +44,9 @@ const Form = (props: IProps) => {
44
44
 
45
45
  const [isNewStructuredData, setIsNewStructuredData] = useState(!currentStructuredDataId);
46
46
  const [notification, setNotification] = useState<INotification | null>(null);
47
+ const [scheduleDate, setScheduleDate] = useState({ date: "", time: "" });
48
+ const { isOpen: isScheduleOpen, toggleModal: toggleScheduleModal } = useModal();
49
+ const { isOpen: isCancelScheduleOpen, toggleModal: toggleCancelScheduleModal } = useModal();
47
50
  const { isDirty, resetDirty, setIsDirty } = useIsDirty(form);
48
51
 
49
52
  const { fields } = schema;
@@ -62,6 +65,12 @@ const Form = (props: IProps) => {
62
65
  currentStructuredData.local &&
63
66
  !activatedDataPacksIds.some((pack: string) => currentStructuredData.dataPacks.includes(pack));
64
67
  const isDataTranslatable = currentStructuredData && currentStructuredData.translate;
68
+ const isScheduled = !!form && !!form.publicationScheduled;
69
+ const status = isScheduled
70
+ ? "scheduled"
71
+ : !form || form.draft === true || form.draft === undefined
72
+ ? "offline"
73
+ : "active";
65
74
 
66
75
  let title = "";
67
76
 
@@ -102,7 +111,7 @@ const Form = (props: IProps) => {
102
111
  );
103
112
  });
104
113
 
105
- const handleSave = async (publish: boolean) => {
114
+ const handleSave = async (publish: boolean, scheduleDate?: string | null) => {
106
115
  const validated = publish && !skipReviewOnPublish ? await validateForm(true) : true;
107
116
 
108
117
  if (validated) {
@@ -114,6 +123,7 @@ const Form = (props: IProps) => {
114
123
  structuredData: currentStructuredData ? currentStructuredData.id : null,
115
124
  draft: publish === true ? false : status,
116
125
  relatedSite: site ? site.id : null,
126
+ publicationScheduled: scheduleDate !== undefined ? scheduleDate : form.publicationScheduled,
117
127
  };
118
128
 
119
129
  let saved = false;
@@ -196,7 +206,7 @@ const Form = (props: IProps) => {
196
206
  setHistoryPush("/sites/settings/content-types", false);
197
207
  };
198
208
 
199
- const removeItem = async () => {
209
+ const removeItem = () => {
200
210
  const path = site ? "/sites/pages" : "/data";
201
211
  deleteStructuredDataContent(form.id).then((deleted: boolean) => {
202
212
  if (deleted) {
@@ -245,6 +255,19 @@ const Form = (props: IProps) => {
245
255
  await validateForm();
246
256
  };
247
257
 
258
+ const handleSchedulePublication = () => {
259
+ const date = new Date(`${scheduleDate.date} ${scheduleDate.time}`);
260
+ const dateString = dateToString(date, "dd/MM/yyyy HH:mm:ss");
261
+ handleSave(false, dateString);
262
+ toggleScheduleModal();
263
+ };
264
+
265
+ const handleCancelSchedulePublication = () => {
266
+ handleSave(false, null);
267
+ setScheduleDate({ date: "", time: "" });
268
+ toggleCancelScheduleModal();
269
+ };
270
+
248
271
  const downArrowMenu = {
249
272
  displayed: true,
250
273
  button: getPublishButton(form?.draft),
@@ -262,13 +285,41 @@ const Form = (props: IProps) => {
262
285
  ],
263
286
  };
264
287
 
265
- const status = !form || form.draft === true || form.draft === undefined ? "offline" : "active";
288
+ if (status === "offline" && !isScheduled) {
289
+ downArrowMenu.options.unshift({
290
+ label: "Schedule",
291
+ icon: "calendar",
292
+ action: toggleScheduleModal,
293
+ });
294
+ }
295
+
296
+ if (isScheduled) {
297
+ downArrowMenu.options.unshift({
298
+ label: "Cancel Schedule",
299
+ icon: "cancelEvent",
300
+ action: toggleCancelScheduleModal,
301
+ });
302
+ }
266
303
 
267
304
  const languageProps = {
268
305
  lang: isDataTranslatable ? lang : null,
269
306
  languageActions: isDataTranslatable ? languageActions : null,
270
307
  };
271
308
 
309
+ const mainScheduleModalAction = {
310
+ title: "Schedule",
311
+ onClick: handleSchedulePublication,
312
+ };
313
+
314
+ const secondaryScheduleModalAction = { title: "Cancel", onClick: toggleScheduleModal };
315
+
316
+ const mainCancelScheduleModalAction = {
317
+ title: "Cancel Schedule",
318
+ onClick: handleCancelSchedulePublication,
319
+ };
320
+
321
+ const secondaryCancelScheduleModalAction = { title: "Back", onClick: toggleCancelScheduleModal };
322
+
272
323
  return isLoading ? (
273
324
  <Loading />
274
325
  ) : (
@@ -289,6 +340,7 @@ const Form = (props: IProps) => {
289
340
  isFromEditor={true}
290
341
  currentPageID={form?.id}
291
342
  errors={errors}
343
+ scheduledPublication={form?.publicationScheduled}
292
344
  >
293
345
  {isDisabled && (
294
346
  <S.NotificationWrapper>
@@ -314,6 +366,20 @@ const Form = (props: IProps) => {
314
366
  <ErrorToast size="l" />
315
367
  <S.Wrapper>{Fields}</S.Wrapper>
316
368
  </MainWrapper>
369
+ <ScheduleModal
370
+ isOpen={isScheduleOpen}
371
+ toggleModal={toggleScheduleModal}
372
+ mainModalAction={mainScheduleModalAction}
373
+ secondaryModalAction={secondaryScheduleModalAction}
374
+ scheduleDate={scheduleDate}
375
+ setScheduleDate={setScheduleDate}
376
+ />
377
+ <CancelScheduleModal
378
+ isOpen={isCancelScheduleOpen}
379
+ toggleModal={toggleCancelScheduleModal}
380
+ mainModalAction={mainCancelScheduleModalAction}
381
+ secondaryModalAction={secondaryCancelScheduleModalAction}
382
+ />
317
383
  </>
318
384
  );
319
385
  };
@@ -14,4 +14,20 @@ const NotificationWrapper = styled.div`
14
14
  z-index: 2;
15
15
  `;
16
16
 
17
- export { Wrapper, NotificationWrapper };
17
+ const ModalContent = styled.div`
18
+ padding: ${(p) => p.theme.spacing.m};
19
+
20
+ p {
21
+ margin-bottom: ${(p) => p.theme.spacing.m};
22
+ }
23
+ `;
24
+
25
+ const ModalFields = styled.div`
26
+ display: flex;
27
+ width: 100%;
28
+ & > div:nth-child(odd) {
29
+ margin-right: ${(p) => p.theme.spacing.m};
30
+ }
31
+ `;
32
+
33
+ export { Wrapper, NotificationWrapper, ModalContent, ModalFields };
@@ -10,6 +10,7 @@ import {
10
10
  SiteFilter,
11
11
  LiveFilter,
12
12
  TranslationsFilter,
13
+ Tooltip,
13
14
  } from "@ax/components";
14
15
  import { IColumn, IQueryValue, ISchemaField, IStructuredDataQueryValues } from "@ax/types";
15
16
  import { getGlobalPageTypes } from "@ax/helpers";
@@ -32,6 +33,7 @@ const TableHeader = (props: IProps): JSX.Element => {
32
33
  columns,
33
34
  setColumns,
34
35
  maxColumns,
36
+ setHoverCheck,
35
37
  } = props;
36
38
 
37
39
  const activeColumns = columns.filter((col) => col.show).map((col) => col.id);
@@ -56,15 +58,18 @@ const TableHeader = (props: IProps): JSX.Element => {
56
58
  return (
57
59
  <S.TableHeader isScrolling={isScrolling}>
58
60
  <S.CheckHeader>
59
- <CheckField
60
- key="selectAll"
61
- name="selectAll"
62
- value="selectAll"
63
- onChange={selectAllItems}
64
- disabled={false}
65
- error={false}
66
- checked={checkState.isAllSelected}
67
- />
61
+ <Tooltip content="Select All Pages" bottom>
62
+ <CheckField
63
+ key="selectAll"
64
+ name="selectAll"
65
+ value="selectAll"
66
+ onChange={selectAllItems}
67
+ disabled={false}
68
+ error={false}
69
+ checked={checkState.isAllSelected || checkState.hoverCheck}
70
+ setHoverCheck={setHoverCheck}
71
+ />
72
+ </Tooltip>
68
73
  </S.CheckHeader>
69
74
  {isFromPage ? (
70
75
  <>
@@ -141,6 +146,7 @@ interface IProps {
141
146
  columns: IColumn[];
142
147
  setColumns: (columns: IColumn[]) => void;
143
148
  maxColumns: { value: number; text: string };
149
+ setHoverCheck: (state: boolean) => void;
144
150
  }
145
151
 
146
152
  export default TableHeader;
@@ -33,6 +33,7 @@ const BulkHeader = (props: IProps): JSX.Element => {
33
33
  setColumns,
34
34
  maxColumns,
35
35
  exportAction,
36
+ setHoverCheck,
36
37
  } = props;
37
38
 
38
39
  const isAllowedToPublishPages = usePermission("global.globalData.publishUnpublishAllGlobalData");
@@ -86,6 +87,7 @@ const BulkHeader = (props: IProps): JSX.Element => {
86
87
  columns={columns}
87
88
  setColumns={setColumns}
88
89
  maxColumns={maxColumns}
90
+ setHoverCheck={setHoverCheck}
89
91
  />
90
92
  );
91
93
  };
@@ -112,6 +114,7 @@ interface IProps {
112
114
  setColumns: (columns: IColumn[]) => void;
113
115
  maxColumns: { value: number; text: string };
114
116
  exportAction?(formats: (number | string)[]): void;
117
+ setHoverCheck: (state: boolean) => void;
115
118
  }
116
119
 
117
120
  export default BulkHeader;
@@ -3,7 +3,7 @@ import { connect } from "react-redux";
3
3
  import { useTheme } from "styled-components";
4
4
 
5
5
  import { ICheck, IAvailableSites, ISavePageParams, ILanguage, IPageLanguage, IPage, IColumn } from "@ax/types";
6
- import { getHumanLastModifiedDate, getStructuredDataTitle, trimText } from "@ax/helpers";
6
+ import { getHumanLastModifiedDate, getScheduleFormatDate, getStructuredDataTitle, trimText } from "@ax/helpers";
7
7
  import { appActions } from "@ax/containers/App";
8
8
  import { pageStatus, ISetCurrentPageIDAction } from "@ax/containers/PageEditor/interfaces";
9
9
  import {
@@ -52,6 +52,7 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
52
52
  categoryColors,
53
53
  addCategoryColors,
54
54
  skipReview,
55
+ hoverCheck,
55
56
  } = props;
56
57
 
57
58
  const { locale } = lang;
@@ -64,9 +65,13 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
64
65
  structuredData,
65
66
  structuredDataContent,
66
67
  fullPath,
68
+ publicationScheduled,
69
+ liveStatus,
70
+ haveDraftPage,
67
71
  } = globalPage;
68
72
 
69
73
  const activeColumns = columns.filter((col) => col.show).map((col) => col.id);
74
+ const isScheduledPub = !!publicationScheduled && liveStatus.status === pageStatus.SCHEDULED;
70
75
 
71
76
  const initValue = { title: "", slug: "" };
72
77
  const [duplicateModalState, setDuplicateModalState] = useState(initValue);
@@ -94,6 +99,7 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
94
99
  offline: "Offline",
95
100
  "offline-pending": "Offline pending",
96
101
  modified: "Live & Modified",
102
+ scheduled: `Scheduled publication: ${isScheduledPub ? getScheduleFormatDate(publicationScheduled) : ""}`,
97
103
  };
98
104
 
99
105
  const _handleClick = () => {
@@ -346,7 +352,7 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
346
352
 
347
353
  const availableSiteNames = availableSites && availableSites.map((site: IAvailableSites) => site.name);
348
354
 
349
- const getLiveStatus = () => (globalPage.haveDraftPage ? "modified" : globalPage.liveStatus.status);
355
+ const getLiveStatus = () => (haveDraftPage ? "modified" : liveStatus.status);
350
356
 
351
357
  const mainUnpublishAction = { title: "Ok", onClick: toggleUnpublishModal };
352
358
 
@@ -384,7 +390,7 @@ const GlobalPageItem = (props: IGlobalPageItemProps): JSX.Element => {
384
390
  <>
385
391
  <S.StructuredDataRow role="rowgroup" selected={isSelected} disabled={!isEditable}>
386
392
  <S.CheckCell role="cell">
387
- <CheckField name="check" value={globalPage.id} checked={isSelected} onChange={handleOnChange} />
393
+ <CheckField name="check" value={globalPage.id} checked={isSelected || hoverCheck} onChange={handleOnChange} />
388
394
  </S.CheckCell>
389
395
  <S.NameCell role="cell" onClick={_handleClick} ref={nameCellRef}>
390
396
  <Tooltip
@@ -485,6 +491,7 @@ interface IGlobalPageItemProps {
485
491
  categoryColors: any;
486
492
  addCategoryColors(cats: string[]): void;
487
493
  skipReview?: boolean;
494
+ hoverCheck?: boolean;
488
495
  }
489
496
 
490
497
  const mapDispatchToProps = {
@@ -12,7 +12,7 @@ import {
12
12
  IColumn,
13
13
  ISite,
14
14
  } from "@ax/types";
15
- import { getActivatedDataPacksIds, getHumanLastModifiedDate } from "@ax/helpers";
15
+ import { getActivatedDataPacksIds, getHumanLastModifiedDate, getScheduleFormatDate } from "@ax/helpers";
16
16
  import { setIsSavedData } from "@ax/forms";
17
17
  import { structuredDataActions } from "@ax/containers/StructuredData";
18
18
  import { appActions } from "@ax/containers/App";
@@ -46,6 +46,7 @@ const StructuredDataItem = (props: IStructuredDataItemProps): JSX.Element => {
46
46
  categoryColors,
47
47
  addCategoryColors,
48
48
  currentSiteInfo,
49
+ hoverCheck,
49
50
  } = props;
50
51
 
51
52
  const isAllowedToDuplicatePagesGlobal = usePermission("global.globalData.duplicateGlobalData");
@@ -72,8 +73,9 @@ const StructuredDataItem = (props: IStructuredDataItemProps): JSX.Element => {
72
73
  const title = useAdaptiveText(nameCellRef, structuredData.content.title, nameCellPadding);
73
74
 
74
75
  const { locale } = lang;
75
- const { dataLanguages } = structuredData;
76
+ const { dataLanguages, publicationScheduled } = structuredData;
76
77
 
78
+ const isScheduledPub = !!publicationScheduled && structuredData.draft;
77
79
  const activeColumns = columns.filter((col) => col.show).map((col) => col.id);
78
80
 
79
81
  const publishedTooltip: Record<string, string> = {
@@ -81,6 +83,7 @@ const StructuredDataItem = (props: IStructuredDataItemProps): JSX.Element => {
81
83
  "upload-pending": "Publication pending",
82
84
  offline: "Offline",
83
85
  "offline-pending": "Offline pending",
86
+ scheduled: `Scheduled publication: ${isScheduledPub ? getScheduleFormatDate(publicationScheduled) : ""}`,
84
87
  };
85
88
 
86
89
  const _handleClick = () => {
@@ -110,7 +113,7 @@ const StructuredDataItem = (props: IStructuredDataItemProps): JSX.Element => {
110
113
  };
111
114
 
112
115
  const checkStatus = () => {
113
- return structuredData.draft ? "offline" : "active";
116
+ return isScheduledPub ? "scheduled" : structuredData.draft ? "offline" : "active";
114
117
  };
115
118
 
116
119
  const getCurrentLanguages = () => {
@@ -236,7 +239,12 @@ const StructuredDataItem = (props: IStructuredDataItemProps): JSX.Element => {
236
239
  return (
237
240
  <S.StructuredDataRow role="rowgroup" selected={isSelected} disabled={!isEditable}>
238
241
  <S.CheckCell role="cell">
239
- <CheckField name="check" value={structuredData.id} checked={isSelected} onChange={handleOnChange} />
242
+ <CheckField
243
+ name="check"
244
+ value={structuredData.id}
245
+ checked={isSelected || hoverCheck}
246
+ onChange={handleOnChange}
247
+ />
240
248
  </S.CheckCell>
241
249
  <S.NameCell role="cell" onClick={_handleClick} ref={nameCellRef}>
242
250
  <Tooltip content={structuredData.content.title} left={0} top={1} expanded>
@@ -289,6 +297,7 @@ interface IStructuredDataItemProps {
289
297
  addCategoryColors(cats: string[]): void;
290
298
  setCurrentDataID(id: number | null): void;
291
299
  currentSiteInfo: ISite | null;
300
+ hoverCheck?: boolean;
292
301
  }
293
302
 
294
303
  const mapStateToProps = (state: IRootState) => ({
@@ -87,4 +87,4 @@ interface IActionButton {
87
87
  title: string;
88
88
  }
89
89
 
90
- export { DeleteModal, MainActionButton, SecondaryActionButton };
90
+ export { DeleteModal, MainActionButton, SecondaryActionButton };
@@ -181,6 +181,7 @@ const StructuredDataList = (props: IProps): JSX.Element => {
181
181
  checkState,
182
182
  addToBulkSelection,
183
183
  selectAllItems,
184
+ setHoverCheck,
184
185
  } = useBulkSelection(dataIds);
185
186
 
186
187
  const getParams = useCallback(() => {
@@ -488,6 +489,7 @@ const StructuredDataList = (props: IProps): JSX.Element => {
488
489
  setColumns={changeColumnsState}
489
490
  maxColumns={maxColumns}
490
491
  exportAction={exportContent}
492
+ setHoverCheck={setHoverCheck}
491
493
  />
492
494
  );
493
495
 
@@ -558,6 +560,7 @@ const StructuredDataList = (props: IProps): JSX.Element => {
558
560
  columns={currentDataColumnsState}
559
561
  categoryColors={categoryColors}
560
562
  addCategoryColors={addCategoryColors}
563
+ hoverCheck={checkState.hoverCheck}
561
564
  />
562
565
  );
563
566
  });
@@ -590,6 +593,7 @@ const StructuredDataList = (props: IProps): JSX.Element => {
590
593
  categoryColors={categoryColors}
591
594
  addCategoryColors={addCategoryColors}
592
595
  skipReview={skipReviewOnPublish}
596
+ hoverCheck={checkState.hoverCheck}
593
597
  />
594
598
  );
595
599
  });
@@ -1,24 +1,36 @@
1
1
  import React from "react";
2
2
 
3
- import { CheckField, TableCounter, NameFilter, PermissionsFilter, UsersFilter } from "@ax/components";
3
+ import { CheckField, TableCounter, NameFilter, PermissionsFilter, UsersFilter, Tooltip } from "@ax/components";
4
4
  import { IQueryValue } from "@ax/types";
5
5
 
6
6
  import * as S from "./style";
7
7
 
8
8
  const TableHeader = (props: IProps): JSX.Element => {
9
- const { totalItems, selectAllItems, isScrolling, sortItems, sortedListStatus, isSiteView } = props;
9
+ const {
10
+ totalItems,
11
+ selectAllItems,
12
+ isScrolling,
13
+ sortItems,
14
+ sortedListStatus,
15
+ isSiteView,
16
+ checkState,
17
+ setHoverCheck,
18
+ } = props;
10
19
 
11
20
  return (
12
21
  <S.TableHeader isScrolling={isScrolling} data-testid="roles-table-header">
13
22
  <S.CheckHeader>
14
- <CheckField
15
- key="selectAll"
16
- name="selectAll"
17
- value="selectAll"
18
- onChange={selectAllItems}
19
- checked={false}
20
- error={false}
21
- />
23
+ <Tooltip content="Select All Roles" bottom>
24
+ <CheckField
25
+ key="selectAll"
26
+ name="selectAll"
27
+ value="selectAll"
28
+ onChange={selectAllItems}
29
+ checked={checkState.isAllSelected || checkState.hoverCheck}
30
+ error={false}
31
+ setHoverCheck={setHoverCheck}
32
+ />
33
+ </Tooltip>
22
34
  </S.CheckHeader>
23
35
  <S.NameWrapper>
24
36
  <NameFilter sortItems={sortItems} sortedState={sortedListStatus} pointer="name" />
@@ -47,6 +59,8 @@ interface IProps {
47
59
  sortedListStatus: any;
48
60
  filterValues: any;
49
61
  isSiteView: boolean;
62
+ checkState: Record<string, boolean>;
63
+ setHoverCheck: (state: boolean) => void;
50
64
  }
51
65
 
52
66
  export default TableHeader;
@@ -18,6 +18,7 @@ const BulkHeader = (props: IBulkHeaderProps): JSX.Element => {
18
18
  isSiteView,
19
19
  roles,
20
20
  selectedRoles,
21
+ setHoverCheck,
21
22
  } = props;
22
23
 
23
24
  const deactivatedSelectedRoles = roles.filter((role: IRole) => selectedRoles.includes(role.id) && !role.active);
@@ -48,6 +49,8 @@ const BulkHeader = (props: IBulkHeaderProps): JSX.Element => {
48
49
  sortItems={sortItems}
49
50
  sortedListStatus={sortedListStatus}
50
51
  isSiteView={isSiteView}
52
+ checkState={checkState}
53
+ setHoverCheck={setHoverCheck}
51
54
  />
52
55
  );
53
56
  };
@@ -66,6 +69,7 @@ export interface IBulkHeaderProps {
66
69
  isSiteView: boolean;
67
70
  roles: IRole[];
68
71
  selectedRoles: number[];
72
+ setHoverCheck: (state: boolean) => void;
69
73
  }
70
74
 
71
75
  export default BulkHeader;
@@ -8,7 +8,7 @@ import { CheckField, ToggleField, Tag, Tooltip, Avatar } from "@ax/components";
8
8
  import * as S from "./style";
9
9
 
10
10
  const RoleItem = (props: IRoleItemProps): JSX.Element => {
11
- const { role, users, isSelected, onChange, activateRole, siteId, onClick } = props;
11
+ const { role, users, isSelected, onChange, activateRole, siteId, onClick, hoverCheck } = props;
12
12
  const isSiteView = siteId !== "global";
13
13
  const [isOpen, setIsOpen] = useState(false);
14
14
 
@@ -41,7 +41,7 @@ const RoleItem = (props: IRoleItemProps): JSX.Element => {
41
41
  <CheckField
42
42
  name="check"
43
43
  value={role.id ?? ""}
44
- checked={isSelected}
44
+ checked={isSelected || (hoverCheck && role.editable)}
45
45
  onChange={(value: ICheck) => onChange(value)}
46
46
  disabled={!role.editable}
47
47
  />
@@ -92,6 +92,7 @@ interface IRoleItemProps {
92
92
  users: IUser[];
93
93
  isSelected: boolean;
94
94
  siteId: string | number;
95
+ hoverCheck: boolean;
95
96
  onChange: (value: ICheck) => void;
96
97
  onClick: () => void;
97
98
  activateRole(value: boolean): void;
@@ -47,6 +47,7 @@ const Roles = (props: IRolesProps): JSX.Element => {
47
47
  addToBulkSelection,
48
48
  selectAllItems,
49
49
  selectedItems,
50
+ setHoverCheck,
50
51
  } = useBulkSelection(rolesIds);
51
52
 
52
53
  useEffect(() => {
@@ -67,9 +68,16 @@ const Roles = (props: IRolesProps): JSX.Element => {
67
68
 
68
69
  const unselectAllItems = () => resetBulkSelection();
69
70
 
70
- const selectItems = () => (checkState.isAllSelected ? unselectAllItems() : handleSelectAll());
71
+ const checkAllEditableSelected = () => pageRoles.filter((role) => role.editable).length === selectedItems.all.length;
71
72
 
72
- const handleSelectAll = () => selectAllItems();
73
+ const selectItems = () => (checkAllEditableSelected() ? unselectAllItems() : handleSelectAll());
74
+
75
+ const bulkFilter = (bulkSelection: number[]) => {
76
+ const activeRoles = bulkSelection.filter((item) => pageRoles.find((role) => role.id === item)?.editable);
77
+ return { all: activeRoles };
78
+ };
79
+
80
+ const handleSelectAll = () => selectAllItems(bulkFilter);
73
81
 
74
82
  const onScroll = (e: any) => setIsScrolling(e.target.scrollTop > 0);
75
83
 
@@ -147,6 +155,7 @@ const Roles = (props: IRolesProps): JSX.Element => {
147
155
  isSiteView={isSiteView}
148
156
  roles={roles}
149
157
  selectedRoles={selectedItems.all}
158
+ setHoverCheck={setHoverCheck}
150
159
  />
151
160
  );
152
161
 
@@ -192,6 +201,7 @@ const Roles = (props: IRolesProps): JSX.Element => {
192
201
  onClick={() => openSideModal(role)}
193
202
  siteId={siteId}
194
203
  activateRole={handleActivateRole}
204
+ hoverCheck={checkState.hoverCheck}
195
205
  />
196
206
  );
197
207
  })
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
 
3
- import { CheckField, TableCounter, SiteFilter, NameFilter, RoleFilter } from "@ax/components";
3
+ import { CheckField, TableCounter, SiteFilter, NameFilter, RoleFilter, Tooltip } from "@ax/components";
4
4
  import { IQueryValue, IRole } from "@ax/types";
5
5
 
6
6
  import * as S from "./style";
@@ -16,6 +16,8 @@ const TableHeader = (props: IProps): JSX.Element => {
16
16
  filterValues,
17
17
  isSiteView,
18
18
  roles,
19
+ checkState,
20
+ setHoverCheck,
19
21
  } = props;
20
22
 
21
23
  const roleFilters = [
@@ -38,15 +40,18 @@ const TableHeader = (props: IProps): JSX.Element => {
38
40
  return (
39
41
  <S.TableHeader isScrolling={isScrolling}>
40
42
  <S.CheckHeader>
41
- <CheckField
42
- key="selectAll"
43
- name="selectAll"
44
- value="selectAll"
45
- onChange={selectAllItems}
46
- checked={false}
47
- disabled={false}
48
- error={false}
49
- />
43
+ <Tooltip content="Select All Users" bottom>
44
+ <CheckField
45
+ key="selectAll"
46
+ name="selectAll"
47
+ value="selectAll"
48
+ onChange={selectAllItems}
49
+ checked={checkState.isAllSelected || checkState.hoverCheck}
50
+ disabled={false}
51
+ error={false}
52
+ setHoverCheck={setHoverCheck}
53
+ />
54
+ </Tooltip>
50
55
  </S.CheckHeader>
51
56
  <S.NameWrapper>
52
57
  <NameFilter sortItems={sortItems} sortedState={sortedListStatus} pointer="name" />
@@ -91,6 +96,8 @@ interface IProps {
91
96
  sortedListStatus: { isAscending: boolean; sortedByName: boolean; sortedByDateCreated: boolean };
92
97
  filterValues: Record<string, IQueryValue[]>;
93
98
  roles: IRole[];
99
+ checkState: Record<string, boolean>;
100
+ setHoverCheck: (state: boolean) => void;
94
101
  }
95
102
 
96
103
  export default TableHeader;
@@ -19,6 +19,7 @@ const BulkHeader = (props: IProps): JSX.Element => {
19
19
  filterValues,
20
20
  isSiteView = false,
21
21
  roles,
22
+ setHoverCheck,
22
23
  } = props;
23
24
 
24
25
  const isAllowedToRemoveUsers = usePermission("usersRoles.removeUsers");
@@ -51,6 +52,8 @@ const BulkHeader = (props: IProps): JSX.Element => {
51
52
  sortedListStatus={sortedListStatus}
52
53
  isSiteView={isSiteView}
53
54
  roles={roles}
55
+ setHoverCheck={setHoverCheck}
56
+ checkState={checkState}
54
57
  />
55
58
  );
56
59
  };
@@ -69,6 +72,7 @@ interface IProps {
69
72
  filterValues: Record<string, IQueryValue[]>;
70
73
  filterItems: (filterPointer: string, filtersSelected: IQueryValue[]) => void;
71
74
  roles: IRole[];
75
+ setHoverCheck: (state: boolean) => void;
72
76
  }
73
77
 
74
78
  export default BulkHeader;