@griddo/ax 11.15.9 → 11.16.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/__tests__/components/RestrictionsModal/CurrentAccessList/CurrentAccessList.test.tsx +173 -0
- package/src/__tests__/components/RestrictionsModal/OptionsStep/OptionsStep.test.tsx +160 -0
- package/src/__tests__/components/RestrictionsModal/RestrictionsModal.test.tsx +134 -0
- package/src/__tests__/components/RestrictionsModal/RolesList/RolesList.test.tsx +234 -0
- package/src/__tests__/components/RestrictionsModal/UsersList/UsersList.test.tsx +288 -0
- package/src/__tests__/hooks/users.test.tsx +382 -0
- package/src/api/pages.tsx +24 -1
- package/src/api/sites.tsx +14 -14
- package/src/api/structuredData.tsx +17 -7
- package/src/components/Browser/index.tsx +12 -0
- package/src/components/Browser/style.tsx +5 -1
- package/src/components/ConfigPanel/Form/index.tsx +11 -10
- package/src/components/ContentItem/index.tsx +31 -0
- package/src/components/ContentItem/style.tsx +43 -0
- package/src/components/Fields/ImageField/index.tsx +2 -1
- package/src/components/Fields/RadioField/index.tsx +3 -3
- package/src/components/Fields/RadioField/style.tsx +1 -1
- package/src/components/FloatingNote/index.tsx +12 -1
- package/src/components/FloatingNote/style.tsx +2 -1
- package/src/components/Modal/style.tsx +11 -0
- package/src/components/PageFinder/SelectionListItem/index.tsx +27 -17
- package/src/components/PageFinder/index.tsx +65 -28
- package/src/components/PageFinder/style.tsx +0 -1
- package/src/components/RestrictionsModal/CurrentAccessList/index.tsx +74 -0
- package/src/components/RestrictionsModal/CurrentAccessList/style.tsx +155 -0
- package/src/components/RestrictionsModal/OptionsStep/index.tsx +55 -0
- package/src/components/RestrictionsModal/OptionsStep/style.tsx +29 -0
- package/src/components/RestrictionsModal/RolesList/RoleItem/index.tsx +54 -0
- package/src/components/RestrictionsModal/RolesList/RoleItem/style.tsx +34 -0
- package/src/components/RestrictionsModal/RolesList/index.tsx +107 -0
- package/src/components/RestrictionsModal/RolesList/style.tsx +76 -0
- package/src/components/RestrictionsModal/UsersList/UserItem/index.tsx +78 -0
- package/src/components/RestrictionsModal/UsersList/UserItem/style.tsx +73 -0
- package/src/components/RestrictionsModal/UsersList/index.tsx +151 -0
- package/src/components/RestrictionsModal/UsersList/style.tsx +55 -0
- package/src/components/RestrictionsModal/index.tsx +181 -0
- package/src/components/RestrictionsModal/style.tsx +31 -0
- package/src/components/RestrictionsModal/utils.tsx +24 -0
- package/src/components/ScheduleModal/index.tsx +32 -8
- package/src/components/SelectionComponent/index.tsx +65 -0
- package/src/components/SelectionComponent/style.tsx +69 -0
- package/src/components/TableFilters/RoleFilter/index.tsx +3 -3
- package/src/components/TableList/TableItem/style.tsx +7 -13
- package/src/components/Tabs/index.tsx +2 -1
- package/src/components/UserRolesAndSites/index.tsx +2 -2
- package/src/components/index.tsx +6 -0
- package/src/containers/PageEditor/actions.tsx +43 -0
- package/src/containers/PageEditor/constants.tsx +1 -0
- package/src/containers/PageEditor/interfaces.tsx +26 -19
- package/src/containers/PageEditor/reducer.tsx +32 -19
- package/src/containers/Users/reducer.tsx +1 -0
- package/src/helpers/forms.tsx +3 -1
- package/src/hooks/index.tsx +2 -1
- package/src/hooks/users.tsx +154 -14
- package/src/modules/ActivityLog/LogFilters/UserFilter/index.tsx +11 -12
- package/src/modules/Content/PageItem/index.tsx +17 -10
- package/src/modules/Content/index.tsx +1 -3
- package/src/modules/GlobalEditor/Editor/index.tsx +6 -0
- package/src/modules/GlobalEditor/PageBrowser/index.tsx +6 -0
- package/src/modules/GlobalEditor/Preview/index.tsx +4 -2
- package/src/modules/GlobalEditor/index.tsx +72 -45
- package/src/modules/Navigation/Menus/List/Table/ConfigPanel/Form/index.tsx +3 -5
- package/src/modules/Navigation/Menus/List/Table/ConfigPanel/index.tsx +4 -4
- package/src/modules/Navigation/Menus/List/Table/SidePanel/Form/ConnectedField/index.tsx +2 -3
- package/src/modules/Navigation/Menus/List/Table/SidePanel/Form/index.tsx +3 -4
- package/src/modules/Navigation/Menus/List/Table/SidePanel/index.tsx +5 -6
- package/src/modules/PageEditor/Editor/index.tsx +6 -0
- package/src/modules/PageEditor/PageBrowser/index.tsx +6 -0
- package/src/modules/PageEditor/Preview/index.tsx +9 -2
- package/src/modules/PageEditor/atoms.tsx +110 -3
- package/src/modules/PageEditor/index.tsx +76 -95
- package/src/modules/Settings/Integrations/IntegrationForm/index.tsx +1 -3
- package/src/modules/Sites/SitesList/GridView/GridSiteItem/style.tsx +19 -2
- package/src/modules/Sites/SitesList/WelcomeModal/FinalStep/index.tsx +2 -2
- package/src/modules/Sites/SitesList/WelcomeModal/utils.ts +2 -2
- package/src/modules/StructuredData/Form/ConnectedField/index.tsx +2 -2
- package/src/modules/StructuredData/Form/index.tsx +120 -75
- package/src/modules/StructuredData/Form/style.tsx +7 -1
- package/src/modules/StructuredData/StructuredDataList/GlobalPageItem/index.tsx +15 -8
- package/src/modules/StructuredData/StructuredDataList/StructuredDataItem/index.tsx +15 -9
- package/src/modules/StructuredData/{StructuredDataList/StructuredDataItem/utils.tsx → utils.tsx} +16 -2
- package/src/modules/Users/Profile/atoms.tsx +62 -4
- package/src/modules/Users/Profile/index.tsx +83 -4
- package/src/modules/Users/Profile/style.tsx +60 -0
- package/src/modules/Users/UserCreate/SiteItem/RolesModal/RoleItem/index.tsx +3 -5
- package/src/modules/Users/UserCreate/SiteItem/index.tsx +2 -2
- package/src/modules/Users/UserCreate/atoms.tsx +69 -0
- package/src/modules/Users/UserCreate/index.tsx +149 -70
- package/src/modules/Users/UserCreate/style.tsx +24 -1
- package/src/modules/Users/UserForm/index.tsx +260 -146
- package/src/modules/Users/UserForm/style.tsx +13 -1
- package/src/modules/Users/UserList/UserItem/index.tsx +3 -3
- package/src/types/index.tsx +19 -6
- package/src/types/logs.tsx +1 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
const ListItem = styled.li`
|
|
4
|
+
display: flex;
|
|
5
|
+
width: 100%;
|
|
6
|
+
padding: ${(p) => p.theme.spacing.s};
|
|
7
|
+
background-color: ${(p) => p.theme.color.uiBarBackground};
|
|
8
|
+
border: 1px solid ${(p) => p.theme.color.uiLine};
|
|
9
|
+
border-radius: ${(p) => p.theme.radii.s};
|
|
10
|
+
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
11
|
+
`;
|
|
12
|
+
|
|
13
|
+
const Title = styled.div`
|
|
14
|
+
${(p) => p.theme.textStyle.fieldContent}
|
|
15
|
+
color: ${(p) => p.theme.colors.textHighEmphasis};
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
const Header = styled.div`
|
|
19
|
+
display: flex;
|
|
20
|
+
margin-bottom: ${(p) => p.theme.spacing.xxs};
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
const Type = styled.div`
|
|
24
|
+
${(p) => p.theme.textStyle.headingXXS};
|
|
25
|
+
color: ${(p) => p.theme.colors.textLowEmphasis};
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
const ContentDate = styled.div`
|
|
29
|
+
${(p) => p.theme.textStyle.uiXS};
|
|
30
|
+
color: ${(p) => p.theme.colors.textLowEmphasis};
|
|
31
|
+
margin-left: auto;
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
const Content = styled.div`
|
|
35
|
+
width: 100%;
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
const Slug = styled.span`
|
|
39
|
+
${({ theme }) => theme.textStyle.uiXS};
|
|
40
|
+
color: ${({ theme }) => theme.colors.textMediumEmphasis};
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
export { Content, ContentDate, Header, ListItem, Slug, Title, Type };
|
|
@@ -134,7 +134,7 @@ const ImageField = (props: IImageFieldProps) => {
|
|
|
134
134
|
{imageElement}
|
|
135
135
|
</S.ImageContainer>
|
|
136
136
|
)}
|
|
137
|
-
{selectPosition && (
|
|
137
|
+
{selectPosition && !disabled && (
|
|
138
138
|
<S.PositionWrapper>
|
|
139
139
|
<S.PositionTitle>
|
|
140
140
|
<Icon name="grid" size="16" />
|
|
@@ -166,6 +166,7 @@ const ImageField = (props: IImageFieldProps) => {
|
|
|
166
166
|
fieldType="TextField"
|
|
167
167
|
value={value.alt || ""}
|
|
168
168
|
onChange={handleAltChange}
|
|
169
|
+
disabled={disabled}
|
|
169
170
|
/>
|
|
170
171
|
</S.FieldsWrapper>
|
|
171
172
|
)}
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
|
|
3
1
|
import * as S from "./style";
|
|
4
2
|
|
|
5
3
|
const RadioField = (props: IRadioFieldProps): JSX.Element => {
|
|
6
|
-
const { name, title, value, checked, error, disabled, onChange } = props;
|
|
4
|
+
const { name, title, value, checked, error, disabled, tabIndex, onChange } = props;
|
|
7
5
|
|
|
8
6
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
9
7
|
if (onChange) {
|
|
@@ -23,6 +21,7 @@ const RadioField = (props: IRadioFieldProps): JSX.Element => {
|
|
|
23
21
|
disabled={disabled}
|
|
24
22
|
onChange={handleChange}
|
|
25
23
|
data-testid="radio-field-input"
|
|
24
|
+
tabIndex={tabIndex}
|
|
26
25
|
/>
|
|
27
26
|
<S.CheckMark checked={checked} error={error} />
|
|
28
27
|
</S.Label>
|
|
@@ -38,6 +37,7 @@ export interface IRadioFieldProps {
|
|
|
38
37
|
error?: boolean;
|
|
39
38
|
disabled?: boolean;
|
|
40
39
|
onChange?: (value: string) => void;
|
|
40
|
+
tabIndex?: number;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
export default RadioField;
|
|
@@ -4,12 +4,12 @@ export const Wrapper = styled.div``;
|
|
|
4
4
|
|
|
5
5
|
export const Label = styled.label`
|
|
6
6
|
${(p) => p.theme.textStyle.fieldContent};
|
|
7
|
-
display: block;
|
|
8
7
|
position: relative;
|
|
9
8
|
padding-left: calc(${(p) => p.theme.spacing.s} + ${(p) => p.theme.spacing.xs});
|
|
10
9
|
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
11
10
|
cursor: pointer;
|
|
12
11
|
user-select: none;
|
|
12
|
+
min-height: 16px;
|
|
13
13
|
`;
|
|
14
14
|
|
|
15
15
|
export const CheckMark = styled.span<{ checked: boolean | undefined; error: boolean | undefined }>`
|
|
@@ -5,8 +5,19 @@ import * as S from "./style";
|
|
|
5
5
|
const FloatingNote = (props: IFloatingNoteProps): JSX.Element => {
|
|
6
6
|
const { message, icon, className, btnText, onClick } = props;
|
|
7
7
|
|
|
8
|
+
const handleClick = () => {
|
|
9
|
+
if (!btnText && onClick) {
|
|
10
|
+
onClick();
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
8
14
|
return (
|
|
9
|
-
<S.Wrapper
|
|
15
|
+
<S.Wrapper
|
|
16
|
+
data-testid="floating-note-wrapper"
|
|
17
|
+
className={className}
|
|
18
|
+
onClick={handleClick}
|
|
19
|
+
interactive={!btnText && !!onClick}
|
|
20
|
+
>
|
|
10
21
|
{icon && (
|
|
11
22
|
<S.IconWrapper>
|
|
12
23
|
<Icon name={icon} size="16" />
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import styled from "styled-components";
|
|
2
2
|
|
|
3
|
-
const Wrapper = styled.div
|
|
3
|
+
const Wrapper = styled.div<{ interactive: boolean }>`
|
|
4
4
|
display: flex;
|
|
5
5
|
background-color: ${(p) => p.theme.color.uiBackground03};
|
|
6
6
|
padding: ${(p) => p.theme.spacing.s};
|
|
7
7
|
border-radius: ${(p) => p.theme.radii.s};
|
|
8
8
|
z-index: 98;
|
|
9
|
+
cursor: ${(p) => (p.interactive ? "pointer" : "default")};
|
|
9
10
|
`;
|
|
10
11
|
|
|
11
12
|
const Text = styled.div`
|
|
@@ -84,6 +84,17 @@ const ModalContent = styled.div<{ overflow: string | undefined }>`
|
|
|
84
84
|
position: relative;
|
|
85
85
|
flex-grow: 1;
|
|
86
86
|
overflow: ${(p) => p.overflow};
|
|
87
|
+
|
|
88
|
+
::-webkit-scrollbar {
|
|
89
|
+
-webkit-appearance: none;
|
|
90
|
+
width: 4px;
|
|
91
|
+
height: 4px;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
::-webkit-scrollbar-thumb {
|
|
95
|
+
border-radius: 4px;
|
|
96
|
+
background-color: ${(p) => p.theme.colors.iconNonActive};
|
|
97
|
+
}
|
|
87
98
|
`;
|
|
88
99
|
|
|
89
100
|
const Title = styled.div`
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { CheckField } from "@ax/components";
|
|
1
|
+
import { CheckField, Tooltip } from "@ax/components";
|
|
2
2
|
import { getFormattedDateWithTimezone } from "@ax/helpers";
|
|
3
3
|
import type { ICheck, IPage } from "@ax/types";
|
|
4
4
|
|
|
5
5
|
import * as S from "./style";
|
|
6
6
|
|
|
7
7
|
const SelectionListItem = (props: ISelectionListItemProps): JSX.Element => {
|
|
8
|
-
const { option, title, type, date, onClick, pageID, isSelected, onChange, multiple, slug } =
|
|
8
|
+
const { option, title, type, date, onClick, pageID, isSelected, onChange, multiple, slug, isCheckboxDisabled } =
|
|
9
|
+
props;
|
|
9
10
|
|
|
10
11
|
const handleClick = () => (multiple ? onChange({ value: option, isChecked: !isSelected }) : onClick(option));
|
|
11
12
|
const handleChange = (value: ICheck) => onChange({ value: option, isChecked: value.isChecked });
|
|
@@ -13,21 +14,29 @@ const SelectionListItem = (props: ISelectionListItemProps): JSX.Element => {
|
|
|
13
14
|
const pageType = type || "Page";
|
|
14
15
|
|
|
15
16
|
return (
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
17
|
+
<Tooltip content={isCheckboxDisabled ? "Already selected in another language version" : undefined} bottom>
|
|
18
|
+
<S.ListItem>
|
|
19
|
+
{multiple && (
|
|
20
|
+
<S.CheckWrapper>
|
|
21
|
+
<CheckField
|
|
22
|
+
name="check"
|
|
23
|
+
value={pageID}
|
|
24
|
+
checked={isSelected}
|
|
25
|
+
onChange={handleChange}
|
|
26
|
+
disabled={isCheckboxDisabled}
|
|
27
|
+
/>
|
|
28
|
+
</S.CheckWrapper>
|
|
29
|
+
)}
|
|
30
|
+
<S.Content onClick={handleClick} data-testid="selection-list-item">
|
|
31
|
+
<S.Header>
|
|
32
|
+
<S.Type>{pageType}</S.Type>
|
|
33
|
+
<S.Date>{getFormattedDateWithTimezone(date, "d MMM Y")}</S.Date>
|
|
34
|
+
</S.Header>
|
|
35
|
+
<S.Title>{title}</S.Title>
|
|
36
|
+
<S.Slug>{slug}</S.Slug>
|
|
37
|
+
</S.Content>
|
|
38
|
+
</S.ListItem>
|
|
39
|
+
</Tooltip>
|
|
31
40
|
);
|
|
32
41
|
};
|
|
33
42
|
|
|
@@ -42,6 +51,7 @@ interface ISelectionListItemProps {
|
|
|
42
51
|
isSelected: boolean;
|
|
43
52
|
onChange: (item: { value: IPage; isChecked: boolean }) => void;
|
|
44
53
|
multiple?: boolean;
|
|
54
|
+
isCheckboxDisabled?: boolean;
|
|
45
55
|
}
|
|
46
56
|
|
|
47
57
|
export default SelectionListItem;
|
|
@@ -12,13 +12,28 @@ import SelectionListItem from "./SelectionListItem";
|
|
|
12
12
|
import * as S from "./style";
|
|
13
13
|
|
|
14
14
|
const PageFinder = (props: IPageFinderProps): JSX.Element => {
|
|
15
|
-
const {
|
|
15
|
+
const {
|
|
16
|
+
onClick,
|
|
17
|
+
currentSiteID,
|
|
18
|
+
isOpen,
|
|
19
|
+
allSites,
|
|
20
|
+
lang,
|
|
21
|
+
globalLangs,
|
|
22
|
+
multiple,
|
|
23
|
+
hideSites,
|
|
24
|
+
pages,
|
|
25
|
+
globalContent,
|
|
26
|
+
alwaysShowButton,
|
|
27
|
+
fromPageOnly = true,
|
|
28
|
+
defaultLang,
|
|
29
|
+
disableTranslations = false,
|
|
30
|
+
} = props;
|
|
16
31
|
|
|
17
32
|
const langOptions = globalLangs.map((lang) => ({ label: lang.label, value: lang.id.toString() }));
|
|
18
33
|
|
|
19
34
|
const initialState: IState = {
|
|
20
|
-
site: currentSiteID || allSites[0].id,
|
|
21
|
-
lang: lang.id,
|
|
35
|
+
site: globalContent ? null : currentSiteID || allSites[0].id,
|
|
36
|
+
lang: defaultLang || lang.id,
|
|
22
37
|
type: "all",
|
|
23
38
|
items: [],
|
|
24
39
|
page: 1,
|
|
@@ -32,12 +47,14 @@ const PageFinder = (props: IPageFinderProps): JSX.Element => {
|
|
|
32
47
|
const [showSelected, setShowSelected] = useState(false);
|
|
33
48
|
const [searchQuery, setSearchQuery] = useState<string>("");
|
|
34
49
|
|
|
35
|
-
const defultTypeOptions =
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
50
|
+
const defultTypeOptions = !globalContent
|
|
51
|
+
? [
|
|
52
|
+
{ label: "All content", value: "all" },
|
|
53
|
+
{ label: "Base templates", value: "basic" },
|
|
54
|
+
{ label: "List pages", value: "list" },
|
|
55
|
+
{ label: "Static pages", value: "static" },
|
|
56
|
+
]
|
|
57
|
+
: [{ label: "All content", value: "all" }];
|
|
41
58
|
|
|
42
59
|
const [contentTypeOptions, setContentTypeOptions] = useState<{ label: string; value: string }[]>(defultTypeOptions);
|
|
43
60
|
|
|
@@ -133,10 +150,15 @@ const PageFinder = (props: IPageFinderProps): JSX.Element => {
|
|
|
133
150
|
|
|
134
151
|
const getAndSetContentTypes = async () => {
|
|
135
152
|
const { site, lang } = state;
|
|
136
|
-
const { data } = await structuredData.
|
|
137
|
-
|
|
138
|
-
? data.items.map((type
|
|
153
|
+
const { data }: { data: { items: IContentType[] } } = await structuredData.getData(null, site, lang);
|
|
154
|
+
let contentTypes = data.items
|
|
155
|
+
? data.items.map((type) => ({ label: type.title, value: type.id, fromPage: type.fromPage }))
|
|
139
156
|
: [];
|
|
157
|
+
|
|
158
|
+
if (fromPageOnly) {
|
|
159
|
+
contentTypes = contentTypes.filter((type) => type.fromPage === true);
|
|
160
|
+
}
|
|
161
|
+
|
|
140
162
|
changeContentTypeOptions(contentTypes);
|
|
141
163
|
changeState("type", "all");
|
|
142
164
|
};
|
|
@@ -178,21 +200,31 @@ const PageFinder = (props: IPageFinderProps): JSX.Element => {
|
|
|
178
200
|
};
|
|
179
201
|
|
|
180
202
|
const getPageList = (items: IPage[]) =>
|
|
181
|
-
items?.map((page: IPage) =>
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
203
|
+
items?.map((page: IPage) => {
|
|
204
|
+
const hasTranslationSelected = page.pageLanguages?.some((lang) => selectedPagesIds.includes(lang.pageId));
|
|
205
|
+
const isPageSelected = selectedPagesIds.includes(page.id);
|
|
206
|
+
const isPageOrTranslationSelected = disableTranslations
|
|
207
|
+
? isPageSelected || hasTranslationSelected
|
|
208
|
+
: isPageSelected;
|
|
209
|
+
const isCheckboxDisabled = disableTranslations && isPageOrTranslationSelected && !isPageSelected;
|
|
210
|
+
|
|
211
|
+
return (
|
|
212
|
+
<SelectionListItem
|
|
213
|
+
option={page}
|
|
214
|
+
key={page.id}
|
|
215
|
+
title={page.title}
|
|
216
|
+
type={getStructuredDataTitle(page.structuredData)}
|
|
217
|
+
date={page.modified}
|
|
218
|
+
onClick={onClick}
|
|
219
|
+
pageID={page.id}
|
|
220
|
+
isSelected={isPageOrTranslationSelected}
|
|
221
|
+
onChange={handleChange}
|
|
222
|
+
multiple={multiple}
|
|
223
|
+
slug={page.slug.replace(/^\//, "")}
|
|
224
|
+
isCheckboxDisabled={isCheckboxDisabled}
|
|
225
|
+
/>
|
|
226
|
+
);
|
|
227
|
+
});
|
|
196
228
|
|
|
197
229
|
const showPagination = state.totalItems > itemsPerPage;
|
|
198
230
|
|
|
@@ -267,7 +299,7 @@ const PageFinder = (props: IPageFinderProps): JSX.Element => {
|
|
|
267
299
|
</S.PaginationWrapper>
|
|
268
300
|
</S.ListWrapper>
|
|
269
301
|
)}
|
|
270
|
-
{selectedPages.length > 0 && (
|
|
302
|
+
{(selectedPages.length > 0 || alwaysShowButton) && (
|
|
271
303
|
<S.ActionWrapper>
|
|
272
304
|
<Button type="button" onClick={handleButtonClick}>
|
|
273
305
|
Add pages
|
|
@@ -297,6 +329,11 @@ interface IPageFinderProps {
|
|
|
297
329
|
multiple?: boolean;
|
|
298
330
|
hideSites?: boolean;
|
|
299
331
|
pages?: number[];
|
|
332
|
+
globalContent?: boolean;
|
|
333
|
+
alwaysShowButton?: boolean;
|
|
334
|
+
fromPageOnly?: boolean;
|
|
335
|
+
defaultLang?: number;
|
|
336
|
+
disableTranslations?: boolean;
|
|
300
337
|
}
|
|
301
338
|
|
|
302
339
|
const mapStateToProps = (state: IRootState) => ({
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { useSelector } from "react-redux";
|
|
2
|
+
|
|
3
|
+
import { Button } from "@ax/components";
|
|
4
|
+
import type { IRole, IRootState, IUser } from "@ax/types";
|
|
5
|
+
|
|
6
|
+
import RoleItem from "../RolesList/RoleItem";
|
|
7
|
+
import UserItem from "../UsersList/UserItem";
|
|
8
|
+
|
|
9
|
+
import * as S from "./style";
|
|
10
|
+
|
|
11
|
+
const CurrentAccessList = (props: ICurrentAccessListProps): JSX.Element => {
|
|
12
|
+
const { restrictionType, currentAccessGrants, onEdit, users: allUsers } = props;
|
|
13
|
+
const roles = useSelector((state: IRootState) => state.users.roles);
|
|
14
|
+
|
|
15
|
+
const isRoles = restrictionType === "roles";
|
|
16
|
+
const itemIds = isRoles ? currentAccessGrants?.roles || [] : currentAccessGrants?.users || [];
|
|
17
|
+
|
|
18
|
+
// Filter users to show only those selected
|
|
19
|
+
const selectedUsers = allUsers.filter((user) => itemIds.includes(user.id!));
|
|
20
|
+
|
|
21
|
+
const getTitle = () => {
|
|
22
|
+
return isRoles ? (
|
|
23
|
+
<>
|
|
24
|
+
Only these roles <strong>can edit</strong> this page
|
|
25
|
+
</>
|
|
26
|
+
) : (
|
|
27
|
+
<>
|
|
28
|
+
Only these users <strong>can edit</strong> this page
|
|
29
|
+
</>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<S.Wrapper>
|
|
35
|
+
<S.Content>
|
|
36
|
+
<S.Text>{getTitle()}</S.Text>
|
|
37
|
+
<S.List>
|
|
38
|
+
{isRoles ? (
|
|
39
|
+
<>
|
|
40
|
+
{(roles as IRole[])
|
|
41
|
+
.filter((role) => itemIds.includes(role.id))
|
|
42
|
+
.map((role) => (
|
|
43
|
+
<RoleItem key={role.id} role={role} selection={false} />
|
|
44
|
+
))}
|
|
45
|
+
</>
|
|
46
|
+
) : (
|
|
47
|
+
<>
|
|
48
|
+
{selectedUsers.map((user) => (
|
|
49
|
+
<UserItem key={user.id} user={user} selection={false} />
|
|
50
|
+
))}
|
|
51
|
+
</>
|
|
52
|
+
)}
|
|
53
|
+
</S.List>
|
|
54
|
+
</S.Content>
|
|
55
|
+
<S.Actions>
|
|
56
|
+
<Button type="button" onClick={onEdit}>
|
|
57
|
+
MANAGE USER ACCESS
|
|
58
|
+
</Button>
|
|
59
|
+
</S.Actions>
|
|
60
|
+
</S.Wrapper>
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
interface ICurrentAccessListProps {
|
|
65
|
+
restrictionType: "users" | "roles";
|
|
66
|
+
currentAccessGrants?: {
|
|
67
|
+
users?: number[];
|
|
68
|
+
roles?: number[];
|
|
69
|
+
};
|
|
70
|
+
onEdit: () => void;
|
|
71
|
+
users: IUser[];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export default CurrentAccessList;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { Row } from "@ax/components/TableList/TableItem/style";
|
|
2
|
+
import styled from "styled-components";
|
|
3
|
+
|
|
4
|
+
const Wrapper = styled.div`
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
width: 100%;
|
|
8
|
+
height: 100%;
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
const Text = styled.div`
|
|
12
|
+
${(p) => p.theme.textStyle.uiM};
|
|
13
|
+
margin-bottom: ${(p) => p.theme.spacing.s};
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
const List = styled.div`
|
|
17
|
+
flex: 1;
|
|
18
|
+
overflow-y: auto;
|
|
19
|
+
min-height: 0;
|
|
20
|
+
|
|
21
|
+
::-webkit-scrollbar {
|
|
22
|
+
-webkit-appearance: none;
|
|
23
|
+
width: 4px;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
::-webkit-scrollbar-thumb {
|
|
27
|
+
border-radius: 4px;
|
|
28
|
+
background-color: ${(p) => p.theme.colors.iconNonActive};
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
const Content = styled.div`
|
|
33
|
+
flex: 1;
|
|
34
|
+
overflow-y: auto;
|
|
35
|
+
min-height: 0;
|
|
36
|
+
padding: ${(p) => `${p.theme.spacing.m} ${p.theme.spacing.m} 0 ${p.theme.spacing.m}`};
|
|
37
|
+
|
|
38
|
+
::-webkit-scrollbar {
|
|
39
|
+
-webkit-appearance: none;
|
|
40
|
+
width: 4px;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
::-webkit-scrollbar-thumb {
|
|
44
|
+
border-radius: 4px;
|
|
45
|
+
background-color: ${(p) => p.theme.colors.iconNonActive};
|
|
46
|
+
}
|
|
47
|
+
`;
|
|
48
|
+
|
|
49
|
+
const Actions = styled.div`
|
|
50
|
+
display: flex;
|
|
51
|
+
justify-content: flex-end;
|
|
52
|
+
flex-shrink: 0;
|
|
53
|
+
padding: ${(p) => p.theme.spacing.m};
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
const ItemRow = styled(Row)`
|
|
57
|
+
display: flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
padding: ${(p) => `0 ${p.theme.spacing.s}`};
|
|
60
|
+
margin-bottom: ${(p) => p.theme.spacing.xxs};
|
|
61
|
+
height: 61px;
|
|
62
|
+
`;
|
|
63
|
+
|
|
64
|
+
const AvatarWrapper = styled.div`
|
|
65
|
+
padding-left: ${(p) => p.theme.spacing.xs};
|
|
66
|
+
padding-right: ${(p) => p.theme.spacing.xs};
|
|
67
|
+
`;
|
|
68
|
+
|
|
69
|
+
const UserInfo = styled.div`
|
|
70
|
+
display: flex;
|
|
71
|
+
flex-flow: column nowrap;
|
|
72
|
+
flex-grow: 1;
|
|
73
|
+
min-width: 0;
|
|
74
|
+
padding-left: ${(p) => p.theme.spacing.xs};
|
|
75
|
+
`;
|
|
76
|
+
|
|
77
|
+
const UserName = styled.div`
|
|
78
|
+
${(p) => p.theme.textStyle.uiM};
|
|
79
|
+
font-weight: 600;
|
|
80
|
+
color: ${(p) => p.theme.colors.textHighEmphasis};
|
|
81
|
+
width: 100%;
|
|
82
|
+
min-width: 0;
|
|
83
|
+
> * {
|
|
84
|
+
min-width: 0;
|
|
85
|
+
max-width: 100%;
|
|
86
|
+
}
|
|
87
|
+
`;
|
|
88
|
+
|
|
89
|
+
const Name = styled.div`
|
|
90
|
+
width: 100%;
|
|
91
|
+
${(p) => p.theme.textStyle.uiM};
|
|
92
|
+
font-weight: 600;
|
|
93
|
+
color: ${(p) => p.theme.colors.textHighEmphasis};
|
|
94
|
+
overflow: hidden;
|
|
95
|
+
text-overflow: ellipsis;
|
|
96
|
+
white-space: nowrap;
|
|
97
|
+
display: block;
|
|
98
|
+
min-width: 0;
|
|
99
|
+
`;
|
|
100
|
+
|
|
101
|
+
const UserEmail = styled.div`
|
|
102
|
+
${(p) => p.theme.textStyle.uiXS};
|
|
103
|
+
color: ${(p) => p.theme.colors.textMediumEmphasis};
|
|
104
|
+
width: 100%;
|
|
105
|
+
min-width: 0;
|
|
106
|
+
> * {
|
|
107
|
+
min-width: 0;
|
|
108
|
+
max-width: 100%;
|
|
109
|
+
}
|
|
110
|
+
`;
|
|
111
|
+
|
|
112
|
+
const Email = styled.div`
|
|
113
|
+
width: 100%;
|
|
114
|
+
${(p) => p.theme.textStyle.uiXS};
|
|
115
|
+
color: ${(p) => p.theme.colors.textMediumEmphasis};
|
|
116
|
+
overflow: hidden;
|
|
117
|
+
text-overflow: ellipsis;
|
|
118
|
+
white-space: nowrap;
|
|
119
|
+
display: block;
|
|
120
|
+
min-width: 0;
|
|
121
|
+
`;
|
|
122
|
+
|
|
123
|
+
const RoleContent = styled.div`
|
|
124
|
+
display: flex;
|
|
125
|
+
flex-flow: column nowrap;
|
|
126
|
+
flex-grow: 1;
|
|
127
|
+
min-width: 0;
|
|
128
|
+
`;
|
|
129
|
+
|
|
130
|
+
const RoleName = styled.div`
|
|
131
|
+
margin-bottom: ${(p) => p.theme.spacing.xxs};
|
|
132
|
+
`;
|
|
133
|
+
|
|
134
|
+
const RoleDescription = styled.div`
|
|
135
|
+
${(p) => p.theme.textStyle.uiXS};
|
|
136
|
+
color: ${(p) => p.theme.colors.textMediumEmphasis};
|
|
137
|
+
`;
|
|
138
|
+
|
|
139
|
+
export {
|
|
140
|
+
Wrapper,
|
|
141
|
+
Content,
|
|
142
|
+
Text,
|
|
143
|
+
List,
|
|
144
|
+
Actions,
|
|
145
|
+
ItemRow,
|
|
146
|
+
AvatarWrapper,
|
|
147
|
+
UserInfo,
|
|
148
|
+
UserName,
|
|
149
|
+
Name,
|
|
150
|
+
UserEmail,
|
|
151
|
+
Email,
|
|
152
|
+
RoleContent,
|
|
153
|
+
RoleName,
|
|
154
|
+
RoleDescription,
|
|
155
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Button, SelectionComponent } from "@ax/components";
|
|
2
|
+
|
|
3
|
+
import * as S from "./style";
|
|
4
|
+
|
|
5
|
+
const OptionsStep = (props: IOptionsStepProps): JSX.Element => {
|
|
6
|
+
const { restrictionType, onRestrictionTypeChange, onCancel, onNext } = props;
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<S.Wrapper>
|
|
10
|
+
<S.Text>
|
|
11
|
+
By default, <strong>all users</strong> have access to the page. However, you can manage access by{" "}
|
|
12
|
+
<strong>granting permissions to specific users or assigning a specific role.</strong>
|
|
13
|
+
</S.Text>
|
|
14
|
+
|
|
15
|
+
<S.OptionsGroup>
|
|
16
|
+
<SelectionComponent
|
|
17
|
+
name="restrictionType"
|
|
18
|
+
label="By users"
|
|
19
|
+
value="users"
|
|
20
|
+
isSelected={restrictionType === "users"}
|
|
21
|
+
onToggle={onRestrictionTypeChange}
|
|
22
|
+
description="Only the selected users can edit the page."
|
|
23
|
+
multi={false}
|
|
24
|
+
/>
|
|
25
|
+
<SelectionComponent
|
|
26
|
+
name="restrictionType"
|
|
27
|
+
label="By roles"
|
|
28
|
+
value="roles"
|
|
29
|
+
isSelected={restrictionType === "roles"}
|
|
30
|
+
onToggle={onRestrictionTypeChange}
|
|
31
|
+
description="Only users with a specific roles can edit the page."
|
|
32
|
+
multi={false}
|
|
33
|
+
/>
|
|
34
|
+
</S.OptionsGroup>
|
|
35
|
+
|
|
36
|
+
<S.Actions>
|
|
37
|
+
<Button type="button" buttonStyle="text" onClick={onCancel}>
|
|
38
|
+
Cancel
|
|
39
|
+
</Button>
|
|
40
|
+
<Button type="button" onClick={onNext}>
|
|
41
|
+
Manage users access
|
|
42
|
+
</Button>
|
|
43
|
+
</S.Actions>
|
|
44
|
+
</S.Wrapper>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
interface IOptionsStepProps {
|
|
49
|
+
restrictionType: "users" | "roles";
|
|
50
|
+
onRestrictionTypeChange: (value: string) => void;
|
|
51
|
+
onCancel: () => void;
|
|
52
|
+
onNext: () => void;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default OptionsStep;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
const Wrapper = styled.div`
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
width: 100%;
|
|
7
|
+
height: 100%;
|
|
8
|
+
padding: ${(p) => `${p.theme.spacing.m} ${p.theme.spacing.m} ${p.theme.spacing.m} ${p.theme.spacing.m}`};
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
const Text = styled.div`
|
|
12
|
+
${(p) => p.theme.textStyle.uiM};
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
const OptionsGroup = styled.div`
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-direction: column;
|
|
18
|
+
gap: ${(p) => p.theme.spacing.xs};
|
|
19
|
+
margin: ${(p) => `${p.theme.spacing.m} 0`};
|
|
20
|
+
`;
|
|
21
|
+
|
|
22
|
+
const Actions = styled.div`
|
|
23
|
+
display: flex;
|
|
24
|
+
gap: ${(p) => p.theme.spacing.s};
|
|
25
|
+
justify-content: flex-end;
|
|
26
|
+
margin-top: auto;
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
export { Wrapper, Text, OptionsGroup, Actions };
|