@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.
- package/package.json +2 -2
- package/src/components/Fields/CheckField/index.tsx +16 -4
- package/src/components/Fields/DateField/index.tsx +9 -3
- package/src/components/Fields/TimeField/index.tsx +8 -2
- package/src/components/Icon/components/CancelEvent.js +10 -0
- package/src/components/Icon/svgs/cancel-event.svg +3 -0
- package/src/components/MainWrapper/AppBar/index.tsx +8 -1
- package/src/components/MainWrapper/AppBar/style.tsx +9 -1
- package/src/components/MainWrapper/index.tsx +1 -0
- package/src/components/Modal/index.tsx +17 -1
- package/src/components/ScheduleModal/index.tsx +100 -0
- package/src/components/ScheduleModal/style.tsx +19 -0
- package/src/components/TableFilters/LiveFilter/index.tsx +1 -1
- package/src/components/index.tsx +3 -0
- package/src/containers/PageEditor/actions.tsx +21 -1
- package/src/containers/PageEditor/interfaces.tsx +1 -0
- package/src/forms/validators.tsx +3 -2
- package/src/helpers/dates.tsx +6 -0
- package/src/helpers/index.tsx +2 -0
- package/src/hooks/bulk.tsx +5 -1
- package/src/modules/Categories/CategoriesList/BulkHeader/TableHeader/index.tsx +17 -12
- package/src/modules/Categories/CategoriesList/BulkHeader/index.tsx +5 -1
- package/src/modules/Categories/CategoriesList/CategoryItem/index.tsx +3 -1
- package/src/modules/Categories/CategoriesList/index.tsx +3 -0
- package/src/modules/Content/BulkHeader/TableHeader/index.tsx +15 -9
- package/src/modules/Content/BulkHeader/index.tsx +3 -0
- package/src/modules/Content/PageItem/index.tsx +10 -4
- package/src/modules/Content/index.tsx +4 -0
- package/src/modules/Content/utils.tsx +13 -10
- package/src/modules/FileDrive/BulkListHeader/TableHeader/index.tsx +15 -11
- package/src/modules/FileDrive/BulkListHeader/index.tsx +4 -1
- package/src/modules/FileDrive/ListItem/index.tsx +3 -1
- package/src/modules/FileDrive/index.tsx +6 -3
- package/src/modules/GlobalEditor/index.tsx +83 -3
- package/src/modules/GlobalEditor/style.tsx +12 -1
- package/src/modules/Navigation/Defaults/BulkHeader/TableHeader/index.tsx +18 -12
- package/src/modules/Navigation/Defaults/BulkHeader/index.tsx +11 -3
- package/src/modules/Navigation/Defaults/Item/index.tsx +9 -2
- package/src/modules/Navigation/Defaults/index.tsx +4 -0
- package/src/modules/PageEditor/index.tsx +82 -2
- package/src/modules/PageEditor/style.tsx +9 -1
- package/src/modules/Redirects/BulkHeader/TableHeader/index.tsx +17 -10
- package/src/modules/Redirects/BulkHeader/index.tsx +4 -0
- package/src/modules/Redirects/RedirectItem/index.tsx +8 -1
- package/src/modules/Redirects/index.tsx +3 -0
- package/src/modules/Settings/Integrations/BulkHeader/TableHeader/index.tsx +16 -11
- package/src/modules/Settings/Integrations/BulkHeader/index.tsx +5 -1
- package/src/modules/Settings/Integrations/IntegrationItem/index.tsx +3 -1
- package/src/modules/Settings/Integrations/index.tsx +3 -0
- package/src/modules/Sites/SitesList/ListView/BulkHeader/TableHeader/index.tsx +15 -10
- package/src/modules/Sites/SitesList/ListView/BulkHeader/index.tsx +3 -0
- package/src/modules/Sites/SitesList/ListView/ListSiteItem/index.tsx +14 -3
- package/src/modules/Sites/SitesList/index.tsx +3 -0
- package/src/modules/StructuredData/Form/index.tsx +72 -6
- package/src/modules/StructuredData/Form/style.tsx +17 -1
- package/src/modules/StructuredData/StructuredDataList/BulkHeader/TableHeader/index.tsx +15 -9
- package/src/modules/StructuredData/StructuredDataList/BulkHeader/index.tsx +3 -0
- package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +10 -3
- package/src/modules/StructuredData/StructuredDataList/StructuredDataItem/index.tsx +13 -4
- package/src/modules/StructuredData/StructuredDataList/atoms.tsx +1 -1
- package/src/modules/StructuredData/StructuredDataList/index.tsx +4 -0
- package/src/modules/Users/Roles/BulkHeader/TableHeader/index.tsx +24 -10
- package/src/modules/Users/Roles/BulkHeader/index.tsx +4 -0
- package/src/modules/Users/Roles/RoleItem/index.tsx +3 -2
- package/src/modules/Users/Roles/index.tsx +12 -2
- package/src/modules/Users/UserList/BulkHeader/TableHeader/index.tsx +17 -10
- package/src/modules/Users/UserList/BulkHeader/index.tsx +4 -0
- package/src/modules/Users/UserList/UserItem/index.tsx +3 -1
- package/src/modules/Users/UserList/index.tsx +24 -7
- package/src/types/index.tsx +2 -0
|
@@ -106,6 +106,7 @@ const CategoriesList = (props: IProps): JSX.Element => {
|
|
|
106
106
|
checkState,
|
|
107
107
|
addToBulkSelection,
|
|
108
108
|
selectAllItems,
|
|
109
|
+
setHoverCheck,
|
|
109
110
|
} = useBulkSelection(catIds);
|
|
110
111
|
|
|
111
112
|
const getParams = useCallback((): IGetStructuredDataParams => {
|
|
@@ -222,6 +223,7 @@ const CategoriesList = (props: IProps): JSX.Element => {
|
|
|
222
223
|
bulkActions={bulkActions}
|
|
223
224
|
filterValues={filterValues}
|
|
224
225
|
filterItems={filterItems}
|
|
226
|
+
setHoverCheck={setHoverCheck}
|
|
225
227
|
/>
|
|
226
228
|
);
|
|
227
229
|
|
|
@@ -276,6 +278,7 @@ const CategoriesList = (props: IProps): JSX.Element => {
|
|
|
276
278
|
getContents={getContents}
|
|
277
279
|
icon={getIcon(item, onExpand, onCollapse)}
|
|
278
280
|
dragHandleProps={provided.dragHandleProps}
|
|
281
|
+
hoverCheck={checkState.hoverCheck}
|
|
279
282
|
/>
|
|
280
283
|
</S.Draggable>
|
|
281
284
|
);
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
StatusFilter,
|
|
10
10
|
LiveFilter,
|
|
11
11
|
TranslationsFilter,
|
|
12
|
+
Tooltip,
|
|
12
13
|
} from "@ax/components";
|
|
13
14
|
import { IColumn, IQueryValue, ISchemaField } from "@ax/types";
|
|
14
15
|
|
|
@@ -31,6 +32,7 @@ const TableHeader = (props: IProps): JSX.Element => {
|
|
|
31
32
|
filterValues,
|
|
32
33
|
siteID,
|
|
33
34
|
maxColumns,
|
|
35
|
+
setHoverCheck,
|
|
34
36
|
} = props;
|
|
35
37
|
|
|
36
38
|
const activeColumns = columns.filter((col) => col.show).map((col) => col.id);
|
|
@@ -54,15 +56,18 @@ const TableHeader = (props: IProps): JSX.Element => {
|
|
|
54
56
|
return (
|
|
55
57
|
<S.TableHeader isScrolling={isScrolling}>
|
|
56
58
|
<S.CheckHeader>
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
<Tooltip content="Select All Pages" bottom>
|
|
60
|
+
<CheckField
|
|
61
|
+
key="selectAll"
|
|
62
|
+
name="selectAll"
|
|
63
|
+
value="selectAll"
|
|
64
|
+
onChange={selectAllItems}
|
|
65
|
+
checked={checkState.isAllSelected || checkState.hoverCheck}
|
|
66
|
+
disabled={false}
|
|
67
|
+
error={false}
|
|
68
|
+
setHoverCheck={setHoverCheck}
|
|
69
|
+
/>
|
|
70
|
+
</Tooltip>
|
|
66
71
|
</S.CheckHeader>
|
|
67
72
|
{isStructuredData ? (
|
|
68
73
|
<>
|
|
@@ -137,6 +142,7 @@ interface IProps {
|
|
|
137
142
|
isGlobalPages: boolean;
|
|
138
143
|
filterValues: any;
|
|
139
144
|
siteID: number;
|
|
145
|
+
setHoverCheck: (state: boolean) => void;
|
|
140
146
|
}
|
|
141
147
|
|
|
142
148
|
export default TableHeader;
|
|
@@ -28,6 +28,7 @@ const BulkHeader = (props: IProps): JSX.Element => {
|
|
|
28
28
|
siteID,
|
|
29
29
|
maxColumns,
|
|
30
30
|
exportAction,
|
|
31
|
+
setHoverCheck,
|
|
31
32
|
} = props;
|
|
32
33
|
|
|
33
34
|
const isAllowedToDeletePage = usePermission("content.deletePages");
|
|
@@ -82,6 +83,7 @@ const BulkHeader = (props: IProps): JSX.Element => {
|
|
|
82
83
|
isGlobalPages={isGlobalPages}
|
|
83
84
|
siteID={siteID}
|
|
84
85
|
maxColumns={maxColumns}
|
|
86
|
+
setHoverCheck={setHoverCheck}
|
|
85
87
|
/>
|
|
86
88
|
);
|
|
87
89
|
};
|
|
@@ -109,6 +111,7 @@ interface IProps {
|
|
|
109
111
|
isGlobalPages: boolean;
|
|
110
112
|
siteID: number;
|
|
111
113
|
exportAction?(formats: (number | string)[]): void;
|
|
114
|
+
setHoverCheck: (state: boolean) => void;
|
|
112
115
|
}
|
|
113
116
|
|
|
114
117
|
export default BulkHeader;
|
|
@@ -3,7 +3,7 @@ import { schemas } from "components";
|
|
|
3
3
|
import { useTheme } from "styled-components";
|
|
4
4
|
|
|
5
5
|
import { useAdaptiveText, useModal, usePermission } from "@ax/hooks";
|
|
6
|
-
import { getHumanLastModifiedDate, getTemplateDisplayName, slugify } from "@ax/helpers";
|
|
6
|
+
import { getHumanLastModifiedDate, getScheduleFormatDate, getTemplateDisplayName, slugify } from "@ax/helpers";
|
|
7
7
|
import { IPage, ISite, ISavePageParams, ICheck, IColumn, IPageLanguage, IDataPack } from "@ax/types";
|
|
8
8
|
import { pageStatus, ISetCurrentPageIDAction } from "@ax/containers/PageEditor/interfaces";
|
|
9
9
|
import {
|
|
@@ -37,6 +37,7 @@ const PageItem = (props: IPageItemProps): JSX.Element => {
|
|
|
37
37
|
dataPacks,
|
|
38
38
|
sites,
|
|
39
39
|
skipReview,
|
|
40
|
+
hoverCheck,
|
|
40
41
|
} = props;
|
|
41
42
|
const { isSelected, siteLanguages, page, lang, isDuplicable } = item;
|
|
42
43
|
const {
|
|
@@ -68,6 +69,8 @@ const PageItem = (props: IPageItemProps): JSX.Element => {
|
|
|
68
69
|
templateId,
|
|
69
70
|
structuredDataContent,
|
|
70
71
|
liveStatus,
|
|
72
|
+
publicationScheduled,
|
|
73
|
+
haveDraftPage,
|
|
71
74
|
} = page;
|
|
72
75
|
|
|
73
76
|
const displayName = getTemplateDisplayName(templateId);
|
|
@@ -105,13 +108,15 @@ const PageItem = (props: IPageItemProps): JSX.Element => {
|
|
|
105
108
|
const API_URL = process.env.REACT_APP_API_ENDPOINT;
|
|
106
109
|
const isPublished = liveStatus.status === pageStatus.PUBLISHED || liveStatus.status === pageStatus.UPLOAD_PENDING;
|
|
107
110
|
const isAllowedToDelete = (isPublished && isAllowedToDeletePublishedPage) || (!isPublished && isAllowedToDeletePage);
|
|
111
|
+
const isScheduledPub = !!publicationScheduled && liveStatus.status === pageStatus.SCHEDULED;
|
|
108
112
|
|
|
109
|
-
const publishedTooltip:
|
|
113
|
+
const publishedTooltip: Record<string, string> = {
|
|
110
114
|
active: "Live",
|
|
111
115
|
"upload-pending": "Publication pending",
|
|
112
116
|
offline: "Offline",
|
|
113
117
|
"offline-pending": "Offline pending",
|
|
114
118
|
modified: "Live & Modified",
|
|
119
|
+
scheduled: `Scheduled publication: ${isScheduledPub ? getScheduleFormatDate(publicationScheduled) : ""}`,
|
|
115
120
|
};
|
|
116
121
|
|
|
117
122
|
const setRoute = (path: string) => setHistoryPush(path, true);
|
|
@@ -456,7 +461,7 @@ const PageItem = (props: IPageItemProps): JSX.Element => {
|
|
|
456
461
|
|
|
457
462
|
const mainCopyModalAction = { title: "Copy page", onClick: copyToOtherSite, disabled: !site };
|
|
458
463
|
|
|
459
|
-
const getLiveStatus = () => (
|
|
464
|
+
const getLiveStatus = () => (haveDraftPage ? "modified" : liveStatus.status);
|
|
460
465
|
|
|
461
466
|
const mainUnpublishAction = { title: "Ok", onClick: toggleUnpublishModal };
|
|
462
467
|
|
|
@@ -491,7 +496,7 @@ const PageItem = (props: IPageItemProps): JSX.Element => {
|
|
|
491
496
|
<>
|
|
492
497
|
<S.PageRow role="rowgroup" selected={isSelected} global={isGlobal}>
|
|
493
498
|
<S.CheckCell role="cell">
|
|
494
|
-
<CheckField name="check" value={page.id} checked={isSelected} onChange={handleOnChange} />
|
|
499
|
+
<CheckField name="check" value={page.id} checked={isSelected || hoverCheck} onChange={handleOnChange} />
|
|
495
500
|
</S.CheckCell>
|
|
496
501
|
<S.NameCell role="cell" onClick={goToPage} ref={nameCellRef}>
|
|
497
502
|
{isHome && (
|
|
@@ -689,6 +694,7 @@ interface IPageItemProps {
|
|
|
689
694
|
dataPacks: IDataPack[];
|
|
690
695
|
sites: ISite[];
|
|
691
696
|
skipReview?: boolean;
|
|
697
|
+
hoverCheck?: boolean;
|
|
692
698
|
}
|
|
693
699
|
|
|
694
700
|
export default memo(PageItem);
|
|
@@ -217,6 +217,7 @@ const Content = (props: IProps): JSX.Element => {
|
|
|
217
217
|
checkState,
|
|
218
218
|
addToBulkSelection,
|
|
219
219
|
selectAllItems,
|
|
220
|
+
setHoverCheck,
|
|
220
221
|
} = useBulkSelection(contentIds);
|
|
221
222
|
|
|
222
223
|
const { isVisible, toggleToast, setIsVisible } = useToast();
|
|
@@ -582,6 +583,7 @@ const Content = (props: IProps): JSX.Element => {
|
|
|
582
583
|
siteID={currentSiteInfo.id}
|
|
583
584
|
maxColumns={maxColumns}
|
|
584
585
|
exportAction={exportContent}
|
|
586
|
+
setHoverCheck={setHoverCheck}
|
|
585
587
|
/>
|
|
586
588
|
);
|
|
587
589
|
|
|
@@ -633,6 +635,7 @@ const Content = (props: IProps): JSX.Element => {
|
|
|
633
635
|
columns={columnsState}
|
|
634
636
|
categoryColors={categoryColors}
|
|
635
637
|
addCategoryColors={addCategoryColors}
|
|
638
|
+
hoverCheck={checkState.hoverCheck}
|
|
636
639
|
/>
|
|
637
640
|
);
|
|
638
641
|
});
|
|
@@ -722,6 +725,7 @@ const Content = (props: IProps): JSX.Element => {
|
|
|
722
725
|
addCategoryColors={addCategoryColors}
|
|
723
726
|
dataPacks={dataPacks}
|
|
724
727
|
skipReview={skipReviewOnPublish}
|
|
728
|
+
hoverCheck={checkState.hoverCheck}
|
|
725
729
|
/>
|
|
726
730
|
);
|
|
727
731
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { schemas } from "components";
|
|
2
|
-
import { arrayInsert,
|
|
2
|
+
import { arrayInsert, getActivatedDataPacksIds } from "@ax/helpers";
|
|
3
3
|
import { pageStatus } from "@ax/containers/PageEditor/interfaces";
|
|
4
4
|
import { IColumn, IDataPack, IPage, ISchemaField, IStructuredData } from "@ax/types";
|
|
5
5
|
|
|
@@ -7,10 +7,15 @@ const getTemplatesFilters = (activatedDataPacks: IDataPack[]) => {
|
|
|
7
7
|
const activatedDataPacksIds = getActivatedDataPacksIds(activatedDataPacks);
|
|
8
8
|
const { templates } = schemas;
|
|
9
9
|
|
|
10
|
-
const
|
|
11
|
-
.filter((templateName: string) => !templates[templateName].dataPacks)
|
|
10
|
+
const staticFilters: { label: string; value: string; mode?: string }[] = Object.keys(templates)
|
|
11
|
+
.filter((templateName: string) => !Array.isArray(templates[templateName].dataPacks))
|
|
12
12
|
.map((templateName: string) => templates[templateName].type);
|
|
13
13
|
|
|
14
|
+
const uniqueStaticFilters = [...new Map(staticFilters.map((item: any) => [item.value, item])).values()];
|
|
15
|
+
const sortedUniqueFilters = uniqueStaticFilters.sort((a, b) => a.label.localeCompare(b.label));
|
|
16
|
+
|
|
17
|
+
const dataPackFilters: { label: string; value: string; mode?: string }[] = [];
|
|
18
|
+
|
|
14
19
|
Object.keys(templates)
|
|
15
20
|
.filter((templateName: string) => Array.isArray(templates[templateName].dataPacks))
|
|
16
21
|
.forEach((templateName: string) => {
|
|
@@ -24,7 +29,7 @@ const getTemplatesFilters = (activatedDataPacks: IDataPack[]) => {
|
|
|
24
29
|
);
|
|
25
30
|
|
|
26
31
|
if (currentDataPack) {
|
|
27
|
-
|
|
32
|
+
dataPackFilters.push({
|
|
28
33
|
label: currentDataPack?.title,
|
|
29
34
|
value: currentDataPack?.id,
|
|
30
35
|
mode: type.mode,
|
|
@@ -34,9 +39,7 @@ const getTemplatesFilters = (activatedDataPacks: IDataPack[]) => {
|
|
|
34
39
|
}
|
|
35
40
|
});
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return uniqueFilters;
|
|
42
|
+
return { staticFilters: sortedUniqueFilters, dataPackFilters };
|
|
40
43
|
};
|
|
41
44
|
|
|
42
45
|
const mapStructuredOptions = (options: any[]) => {
|
|
@@ -82,7 +85,7 @@ const getOptionValues = (options: IStructuredData[]) => {
|
|
|
82
85
|
|
|
83
86
|
const getOptionFilters = (options: IStructuredData[], activatedDataPacks: IDataPack[]) => {
|
|
84
87
|
const pureOptions = options.filter((option: IStructuredData) => !option.fromPage);
|
|
85
|
-
const
|
|
88
|
+
const { staticFilters, dataPackFilters } = getTemplatesFilters(activatedDataPacks);
|
|
86
89
|
const activatedDataPacksIds = getActivatedDataPacksIds(activatedDataPacks);
|
|
87
90
|
|
|
88
91
|
const mappedOptions = pureOptions.flatMap((option: IStructuredData) =>
|
|
@@ -104,10 +107,10 @@ const getOptionFilters = (options: IStructuredData[], activatedDataPacks: IDataP
|
|
|
104
107
|
}, [])
|
|
105
108
|
);
|
|
106
109
|
|
|
107
|
-
const filters = [...
|
|
110
|
+
const filters = [...dataPackFilters, ...mappedOptions];
|
|
108
111
|
const uniqueFilters = [...new Map(filters.map((item: any) => [item.value, item])).values()];
|
|
109
112
|
const sortedUniqueFilters = uniqueFilters.sort((a, b) => a.label.localeCompare(b.label));
|
|
110
|
-
return sortedUniqueFilters;
|
|
113
|
+
return [...staticFilters, ...sortedUniqueFilters];
|
|
111
114
|
};
|
|
112
115
|
|
|
113
116
|
const getCurrentFilter = (structuredData: any, filter: any) =>
|
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import { CheckField, TableCounter } from "@ax/components";
|
|
3
|
+
import { CheckField, TableCounter, Tooltip } from "@ax/components";
|
|
4
4
|
|
|
5
5
|
import * as S from "./style";
|
|
6
6
|
|
|
7
7
|
const TableHeader = (props: IProps): JSX.Element => {
|
|
8
|
-
const { isScrolling, selectAllItems, checkState, totalItems, isSearching } = props;
|
|
8
|
+
const { isScrolling, selectAllItems, checkState, totalItems, isSearching, setHoverCheck } = props;
|
|
9
9
|
|
|
10
10
|
return (
|
|
11
11
|
<S.TableHeader isScrolling={isScrolling}>
|
|
12
12
|
<S.CheckHeader>
|
|
13
|
-
<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
<Tooltip content="Select All Files">
|
|
14
|
+
<CheckField
|
|
15
|
+
key="selectAll"
|
|
16
|
+
name="selectAll"
|
|
17
|
+
value="selectAll"
|
|
18
|
+
onChange={selectAllItems}
|
|
19
|
+
checked={checkState.isAllSelected || checkState.hoverCheck}
|
|
20
|
+
disabled={false}
|
|
21
|
+
error={false}
|
|
22
|
+
setHoverCheck={setHoverCheck}
|
|
23
|
+
/>
|
|
24
|
+
</Tooltip>
|
|
22
25
|
</S.CheckHeader>
|
|
23
26
|
<S.NameHeader>Name</S.NameHeader>
|
|
24
27
|
<S.TypeHeader>Type</S.TypeHeader>
|
|
@@ -39,6 +42,7 @@ interface IProps {
|
|
|
39
42
|
selectAllItems: () => void;
|
|
40
43
|
checkState: Record<string, boolean>;
|
|
41
44
|
isSearching: boolean;
|
|
45
|
+
setHoverCheck: (state: boolean) => void;
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
export default TableHeader;
|
|
@@ -6,7 +6,8 @@ import TableHeader from "./TableHeader";
|
|
|
6
6
|
import * as S from "./style";
|
|
7
7
|
|
|
8
8
|
const BulkListHeader = (props: IBulkHeaderProps): JSX.Element => {
|
|
9
|
-
const { showBulk, checkState, selectItems, selectAllItems, totalItems, bulkActions, isSearching } =
|
|
9
|
+
const { showBulk, checkState, selectItems, selectAllItems, totalItems, bulkActions, isSearching, setHoverCheck } =
|
|
10
|
+
props;
|
|
10
11
|
|
|
11
12
|
return showBulk ? (
|
|
12
13
|
<S.BulkWrapper>
|
|
@@ -25,6 +26,7 @@ const BulkListHeader = (props: IBulkHeaderProps): JSX.Element => {
|
|
|
25
26
|
checkState={checkState}
|
|
26
27
|
totalItems={totalItems}
|
|
27
28
|
isSearching={isSearching}
|
|
29
|
+
setHoverCheck={setHoverCheck}
|
|
28
30
|
/>
|
|
29
31
|
);
|
|
30
32
|
};
|
|
@@ -37,6 +39,7 @@ export interface IBulkHeaderProps {
|
|
|
37
39
|
totalItems: number;
|
|
38
40
|
bulkActions: IBulkAction[];
|
|
39
41
|
isSearching: boolean;
|
|
42
|
+
setHoverCheck: (state: boolean) => void;
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
export default BulkListHeader;
|
|
@@ -17,6 +17,7 @@ const ListItem = (props: IProps) => {
|
|
|
17
17
|
isAllowedToEdit,
|
|
18
18
|
isAllowedToMove,
|
|
19
19
|
isSearching,
|
|
20
|
+
hoverCheck,
|
|
20
21
|
onChange,
|
|
21
22
|
onClick,
|
|
22
23
|
onDelete,
|
|
@@ -117,7 +118,7 @@ const ListItem = (props: IProps) => {
|
|
|
117
118
|
<>
|
|
118
119
|
<S.ItemRow role="rowgroup" selected={isSelected}>
|
|
119
120
|
<S.CheckCell role="cell">
|
|
120
|
-
<CheckField name="check" value={id} checked={isSelected} onChange={handleChange} />
|
|
121
|
+
<CheckField name="check" value={id} checked={isSelected || hoverCheck} onChange={handleChange} />
|
|
121
122
|
</S.CheckCell>
|
|
122
123
|
<S.IconCell role="cell" onClick={handleClick}>
|
|
123
124
|
<img src={iconUrl} alt={`${fileType} Icon`} />
|
|
@@ -192,6 +193,7 @@ interface IProps {
|
|
|
192
193
|
onClick(file: IFile): void;
|
|
193
194
|
onDelete(fileID: number): void;
|
|
194
195
|
onMove(fileID: number, folderID: number): void;
|
|
196
|
+
hoverCheck: boolean;
|
|
195
197
|
}
|
|
196
198
|
|
|
197
199
|
export default ListItem;
|
|
@@ -201,6 +201,7 @@ const FileDrive = (props: IProps) => {
|
|
|
201
201
|
checkState,
|
|
202
202
|
addToBulkSelection,
|
|
203
203
|
selectAllItems,
|
|
204
|
+
setHoverCheck,
|
|
204
205
|
} = useBulkSelection(filesIds);
|
|
205
206
|
|
|
206
207
|
const handleSelectedTab = (tab: "site" | "global") => {
|
|
@@ -431,10 +432,11 @@ const FileDrive = (props: IProps) => {
|
|
|
431
432
|
selectItems={selectItems}
|
|
432
433
|
bulkActions={bulkActions}
|
|
433
434
|
isSearching={isSearching}
|
|
435
|
+
setHoverCheck={setHoverCheck}
|
|
434
436
|
/>
|
|
435
437
|
);
|
|
436
438
|
|
|
437
|
-
const
|
|
439
|
+
const gridList = (
|
|
438
440
|
<S.GridWrapper isSearching={isSearching}>
|
|
439
441
|
{progressItems.map((progress: number, index: number) => (
|
|
440
442
|
<UploadItem uploadPercentage={progress} grid={true} key={index} />
|
|
@@ -461,7 +463,7 @@ const FileDrive = (props: IProps) => {
|
|
|
461
463
|
</S.GridWrapper>
|
|
462
464
|
);
|
|
463
465
|
|
|
464
|
-
const
|
|
466
|
+
const listTable = (
|
|
465
467
|
<TableList tableHeader={Header} hasFixedHeader={true} tableRef={tableRef} className="no-padding">
|
|
466
468
|
<>
|
|
467
469
|
{progressItems.map((progress: number, index: number) => (
|
|
@@ -483,6 +485,7 @@ const FileDrive = (props: IProps) => {
|
|
|
483
485
|
isAllowedToEdit={allowedToEditFile}
|
|
484
486
|
isAllowedToMove={!isRoot || (isRoot && (folders.length > 0 || isSearching))}
|
|
485
487
|
isSearching={isSearching}
|
|
488
|
+
hoverCheck={checkState.hoverCheck}
|
|
486
489
|
/>
|
|
487
490
|
);
|
|
488
491
|
})}
|
|
@@ -681,7 +684,7 @@ const FileDrive = (props: IProps) => {
|
|
|
681
684
|
)}
|
|
682
685
|
{!hasFolders && isRoot && !isSearching && <NewFolderButton />}
|
|
683
686
|
</S.SectionHeader>
|
|
684
|
-
<S.DocumentsWrapper>{isGrid ?
|
|
687
|
+
<S.DocumentsWrapper>{isGrid ? gridList : listTable}</S.DocumentsWrapper>
|
|
685
688
|
{totalItems === 0 && !hasFolders && (
|
|
686
689
|
<S.EmptyStateWrapper data-testid="empty-state" margin={!isRoot}>
|
|
687
690
|
{isSearching ? <EmptyState {...emptySearchStateProps} /> : <EmptyState {...emptyProps} />}
|
|
@@ -4,7 +4,16 @@ import { RouteComponentProps } from "react-router-dom";
|
|
|
4
4
|
import { withErrorBoundary } from "react-error-boundary";
|
|
5
5
|
|
|
6
6
|
import { IErrorItem, INotification, IRootState, ISavePageParams, ISite, IUserEditing } from "@ax/types";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
MainWrapper,
|
|
9
|
+
Loading,
|
|
10
|
+
ErrorToast,
|
|
11
|
+
Notification,
|
|
12
|
+
Modal,
|
|
13
|
+
ErrorPage,
|
|
14
|
+
CancelScheduleModal,
|
|
15
|
+
ScheduleModal,
|
|
16
|
+
} from "@ax/components";
|
|
8
17
|
import { pageEditorActions } from "@ax/containers/PageEditor";
|
|
9
18
|
import { structuredDataActions } from "@ax/containers/StructuredData";
|
|
10
19
|
import { usersActions } from "@ax/containers/Users";
|
|
@@ -13,7 +22,7 @@ import { sitesActions } from "@ax/containers/Sites";
|
|
|
13
22
|
import { pageStatus } from "@ax/containers/PageEditor/interfaces";
|
|
14
23
|
import { RouteLeavingGuard } from "@ax/guards";
|
|
15
24
|
import { useIsDirty, useModal, usePermission } from "@ax/hooks";
|
|
16
|
-
import { getDefaultTheme } from "@ax/helpers";
|
|
25
|
+
import { dateToString, getDefaultTheme } from "@ax/helpers";
|
|
17
26
|
|
|
18
27
|
import Editor from "./Editor";
|
|
19
28
|
import Preview from "./Preview";
|
|
@@ -45,6 +54,7 @@ const GlobalEditor = (props: IProps) => {
|
|
|
45
54
|
isNewTranslation,
|
|
46
55
|
currentSiteErrorPages,
|
|
47
56
|
getUserCurrentPermissions,
|
|
57
|
+
schedulePublication,
|
|
48
58
|
} = props;
|
|
49
59
|
|
|
50
60
|
const isAllowedToPublishPages = usePermission("global.globalData.publishUnpublishAllGlobalData");
|
|
@@ -61,6 +71,9 @@ const GlobalEditor = (props: IProps) => {
|
|
|
61
71
|
const [notification, setNotification] = useState<INotification | null>(null);
|
|
62
72
|
const { isDirty, setIsDirty, resetDirty } = useIsDirty(editorContent, isNewTranslation);
|
|
63
73
|
const [errorPagesChecked, setErrorPagesChecked] = useState(false);
|
|
74
|
+
const [scheduleDate, setScheduleDate] = useState({ date: "", time: "" });
|
|
75
|
+
const { isOpen: isScheduleOpen, toggleModal: toggleScheduleModal } = useModal();
|
|
76
|
+
const { isOpen: isCancelScheduleOpen, toggleModal: toggleCancelScheduleModal } = useModal();
|
|
64
77
|
const browserRef = useRef<HTMLDivElement>(null);
|
|
65
78
|
|
|
66
79
|
const isPublished = props.pageStatus === pageStatus.PUBLISHED || props.pageStatus === pageStatus.UPLOAD_PENDING;
|
|
@@ -68,7 +81,8 @@ const GlobalEditor = (props: IProps) => {
|
|
|
68
81
|
const hasDraft: boolean = editorContent && !!editorContent.haveDraftPage;
|
|
69
82
|
const isLivePageChanged = editorContent && editorContent.liveChanged;
|
|
70
83
|
const structuredData = editorContent ? editorContent.structuredData : "";
|
|
71
|
-
const isEditLive
|
|
84
|
+
const isEditLive = isPublished && hasDraft;
|
|
85
|
+
const isScheduled = props.pageStatus === pageStatus.SCHEDULED;
|
|
72
86
|
|
|
73
87
|
const errorNotificationText =
|
|
74
88
|
"There are some errors on the page so you can not publish yet. Please review them in the error panel.";
|
|
@@ -228,6 +242,25 @@ const GlobalEditor = (props: IProps) => {
|
|
|
228
242
|
if (isSaved) resetDirty();
|
|
229
243
|
};
|
|
230
244
|
|
|
245
|
+
const handleSchedulePublication = async () => {
|
|
246
|
+
const date = new Date(`${scheduleDate.date} ${scheduleDate.time}`);
|
|
247
|
+
const dateString = dateToString(date, "dd/MM/yyyy HH:mm:ss");
|
|
248
|
+
const saved = await schedulePublication(dateString);
|
|
249
|
+
if (saved) {
|
|
250
|
+
resetDirty();
|
|
251
|
+
toggleScheduleModal();
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const handleCancelSchedulePublication = async () => {
|
|
256
|
+
const saved = await schedulePublication(null);
|
|
257
|
+
if (saved) {
|
|
258
|
+
setScheduleDate({ date: "", time: "" });
|
|
259
|
+
resetDirty();
|
|
260
|
+
toggleCancelScheduleModal();
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
|
|
231
264
|
const getPublishButton = (status: string) => {
|
|
232
265
|
switch (status) {
|
|
233
266
|
case pageStatus.OFFLINE:
|
|
@@ -270,6 +303,22 @@ const GlobalEditor = (props: IProps) => {
|
|
|
270
303
|
|
|
271
304
|
const menuOptions = [];
|
|
272
305
|
|
|
306
|
+
if (isAllowedToPublishPages && !isScheduled) {
|
|
307
|
+
menuOptions.push({
|
|
308
|
+
label: "Schedule",
|
|
309
|
+
icon: "calendar",
|
|
310
|
+
action: toggleScheduleModal,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
if (isAllowedToPublishPages && isScheduled) {
|
|
315
|
+
menuOptions.push({
|
|
316
|
+
label: "Cancel Schedule",
|
|
317
|
+
icon: "cancelEvent",
|
|
318
|
+
action: toggleCancelScheduleModal,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
|
|
273
322
|
if (isAllowedToEditContentPage) {
|
|
274
323
|
menuOptions.push({
|
|
275
324
|
label: "Review",
|
|
@@ -418,6 +467,20 @@ const GlobalEditor = (props: IProps) => {
|
|
|
418
467
|
|
|
419
468
|
const mainUnpublishAction = { title: "Ok", onClick: toggleUnpublishModal };
|
|
420
469
|
|
|
470
|
+
const mainScheduleModalAction = {
|
|
471
|
+
title: "Schedule",
|
|
472
|
+
onClick: handleSchedulePublication,
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
const secondaryScheduleModalAction = { title: "Cancel", onClick: toggleScheduleModal };
|
|
476
|
+
|
|
477
|
+
const mainCancelScheduleModalAction = {
|
|
478
|
+
title: "Cancel Schedule",
|
|
479
|
+
onClick: handleCancelSchedulePublication,
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
const secondaryCancelScheduleModalAction = { title: "Back", onClick: toggleCancelScheduleModal };
|
|
483
|
+
|
|
421
484
|
const tabIcons = isAllowedToEditContentPage
|
|
422
485
|
? [
|
|
423
486
|
{ name: "edit", text: "Edit mode" },
|
|
@@ -457,6 +520,7 @@ const GlobalEditor = (props: IProps) => {
|
|
|
457
520
|
pageStatusActions={pageStatusActions}
|
|
458
521
|
tabs={tabsPreview}
|
|
459
522
|
isDirty={isDirty}
|
|
523
|
+
scheduledPublication={editorContent?.publicationScheduled}
|
|
460
524
|
>
|
|
461
525
|
{selectedTab === "edit" ? (
|
|
462
526
|
<>
|
|
@@ -531,6 +595,20 @@ const GlobalEditor = (props: IProps) => {
|
|
|
531
595
|
</S.ModalContent>
|
|
532
596
|
)}
|
|
533
597
|
</Modal>
|
|
598
|
+
<ScheduleModal
|
|
599
|
+
isOpen={isScheduleOpen}
|
|
600
|
+
toggleModal={toggleScheduleModal}
|
|
601
|
+
mainModalAction={mainScheduleModalAction}
|
|
602
|
+
secondaryModalAction={secondaryScheduleModalAction}
|
|
603
|
+
scheduleDate={scheduleDate}
|
|
604
|
+
setScheduleDate={setScheduleDate}
|
|
605
|
+
/>
|
|
606
|
+
<CancelScheduleModal
|
|
607
|
+
isOpen={isCancelScheduleOpen}
|
|
608
|
+
toggleModal={toggleCancelScheduleModal}
|
|
609
|
+
mainModalAction={mainCancelScheduleModalAction}
|
|
610
|
+
secondaryModalAction={secondaryCancelScheduleModalAction}
|
|
611
|
+
/>
|
|
534
612
|
</MainWrapper>
|
|
535
613
|
</>
|
|
536
614
|
);
|
|
@@ -593,6 +671,7 @@ const mapDispatchToProps = {
|
|
|
593
671
|
setStructuredDataFilter: structuredDataActions.setFilter,
|
|
594
672
|
discardDraft: pageEditorActions.discardDraft,
|
|
595
673
|
getUserCurrentPermissions: usersActions.getUserCurrentPermissions,
|
|
674
|
+
schedulePublication: pageEditorActions.schedulePublication,
|
|
596
675
|
};
|
|
597
676
|
|
|
598
677
|
interface IPageEditorDispatchProps {
|
|
@@ -612,6 +691,7 @@ interface IPageEditorDispatchProps {
|
|
|
612
691
|
setStructuredDataFilter(filter: string | null): void;
|
|
613
692
|
discardDraft(): Promise<void>;
|
|
614
693
|
getUserCurrentPermissions(): void;
|
|
694
|
+
schedulePublication(date: string | null): Promise<boolean>;
|
|
615
695
|
}
|
|
616
696
|
|
|
617
697
|
type IProps = IPageEditorStateProps & IPageEditorDispatchProps & RouteComponentProps;
|
|
@@ -16,6 +16,17 @@ const NotificationWrapper = styled.div`
|
|
|
16
16
|
|
|
17
17
|
const ModalContent = styled.div`
|
|
18
18
|
padding: ${(p) => p.theme.spacing.m};
|
|
19
|
+
p {
|
|
20
|
+
margin-bottom: ${(p) => p.theme.spacing.m};
|
|
21
|
+
}
|
|
19
22
|
`;
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
const ModalFields = styled.div`
|
|
25
|
+
display: flex;
|
|
26
|
+
width: 100%;
|
|
27
|
+
& > div:nth-child(odd) {
|
|
28
|
+
margin-right: ${(p) => p.theme.spacing.m};
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
export { Content, NotificationWrapper, ModalContent, ModalFields };
|
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import { CheckField, TableCounter } from "@ax/components";
|
|
3
|
+
import { CheckField, TableCounter, Tooltip } from "@ax/components";
|
|
4
4
|
import * as S from "./style";
|
|
5
5
|
|
|
6
|
-
const TableHeader = (props: IProps) => {
|
|
7
|
-
const { totalItems, selectAllItems, isScrolling } = props;
|
|
6
|
+
const TableHeader = (props: IProps): JSX.Element => {
|
|
7
|
+
const { totalItems, selectAllItems, isScrolling, checkState, setHoverCheck } = props;
|
|
8
|
+
|
|
8
9
|
return (
|
|
9
10
|
<S.TableHeader isScrolling={isScrolling}>
|
|
10
11
|
<S.CheckHeader>
|
|
11
|
-
<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
<Tooltip content="Select All Items" bottom>
|
|
13
|
+
<CheckField
|
|
14
|
+
key="selectAll"
|
|
15
|
+
name="selectAll"
|
|
16
|
+
value="selectAll"
|
|
17
|
+
onChange={selectAllItems}
|
|
18
|
+
checked={checkState.isAllSelected || checkState.hoverCheck}
|
|
19
|
+
disabled={false}
|
|
20
|
+
error={false}
|
|
21
|
+
setHoverCheck={setHoverCheck}
|
|
22
|
+
/>
|
|
23
|
+
</Tooltip>
|
|
20
24
|
</S.CheckHeader>
|
|
21
25
|
<S.NameHeader>Name</S.NameHeader>
|
|
22
26
|
<S.TransHeader>Translations</S.TransHeader>
|
|
@@ -32,6 +36,8 @@ interface IProps {
|
|
|
32
36
|
totalItems: number;
|
|
33
37
|
isScrolling: boolean;
|
|
34
38
|
selectAllItems: () => void;
|
|
39
|
+
checkState: Record<string, boolean>;
|
|
40
|
+
setHoverCheck: (state: boolean) => void;
|
|
35
41
|
}
|
|
36
42
|
|
|
37
43
|
export default TableHeader;
|