@griddo/ax 1.69.7 → 1.71.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.
- package/config/jest/componentsMock.js +0 -26
- package/package.json +4 -3
- package/src/__tests__/components/ElementsTooltip/ElementsTooltip.test.tsx +97 -0
- package/src/__tests__/components/EmptyState/EmptyState.test.tsx +78 -0
- package/src/__tests__/components/Fields/AnalyticsField/PageAnalytics/PageAnalytics.test.tsx +0 -14
- package/src/__tests__/components/Fields/AnalyticsField/StructuredDataAnalytics/StructuredDataAnalytics.test.tsx +0 -15
- package/src/__tests__/components/Fields/ArrayFieldGroup/ArrayFieldGroup.test.tsx +6 -15
- package/src/__tests__/components/Fields/AsyncCheckGroup/AsyncCheckGroup.test.tsx +1 -13
- package/src/__tests__/components/Fields/AsyncSelect/AsyncSelect.test.tsx +1 -19
- package/src/__tests__/components/Fields/ColorPicker/ColorPicker.test.tsx +1 -10
- package/src/__tests__/components/Fields/ComponentArray/ComponentArray.test.tsx +1 -22
- package/src/__tests__/components/Fields/ComponentArray/MixableComponentArray/MixableComponentArray.test.tsx +4 -24
- package/src/__tests__/components/Fields/ComponentArray/MixableComponentArray/PasteModuleButton/PasteModuleButton.test.tsx +6 -12
- package/src/__tests__/components/Fields/ComponentArray/SameComponentArray/SameComponentArray.test.tsx +1 -20
- package/src/__tests__/components/Fields/ComponentContainer/ComponentContainer.test.tsx +559 -0
- package/src/__tests__/components/Fields/HiddenField/HiddenField.test.tsx +1 -7
- package/src/__tests__/components/Fields/ImageField/ImageField.test.tsx +471 -0
- package/src/__tests__/components/Fields/MultiCheckSelect/MultiCheckSelect.test.tsx +1 -15
- package/src/__tests__/components/Fields/NoteField/NoteField.test.tsx +1 -6
- package/src/__tests__/components/Fields/NumberField/NumberField.test.tsx +1 -14
- package/src/__tests__/components/Fields/RadioField/RadioField.test.tsx +1 -11
- package/src/__tests__/components/Fields/ReferenceField/ReferenceField.test.tsx +77 -13
- package/src/__tests__/components/Fields/RichText/RichText.test.tsx +1 -12
- package/src/__tests__/components/Fields/Select/Select.test.tsx +1 -21
- package/src/__tests__/components/Fields/SliderField/SliderField.test.tsx +1 -14
- package/src/__tests__/components/Fields/TagField/TagField.test.tsx +3 -3
- package/src/__tests__/components/Fields/TimeField/HourInput/HourInput.test.tsx +142 -0
- package/src/__tests__/components/Fields/TimeField/TimeField.test.tsx +100 -0
- package/src/__tests__/components/Fields/ToggleField/ToggleField.test.tsx +1 -9
- package/src/__tests__/components/Fields/Tooltip/Tooltip.test.tsx +151 -0
- package/src/__tests__/components/Fields/VisualUniqueSelection/ImageSelection/ImageSelection.test.tsx +1 -13
- package/src/__tests__/components/Fields/VisualUniqueSelection/ScrollableSelection/ScrollableSelection.test.tsx +3 -17
- package/src/__tests__/components/Fields/VisualUniqueSelection/VisualUniqueSelection.test.tsx +2 -28
- package/src/__tests__/components/TableList/TableList.test.tsx +119 -0
- package/src/__tests__/components/Tabs/Tabs.test.tsx +202 -0
- package/src/__tests__/components/Tag/Tag.test.tsx +138 -0
- package/src/__tests__/components/Toast/Toast.test.tsx +100 -0
- package/src/api/navigation.tsx +1 -1
- package/src/components/Browser/index.tsx +1 -1
- package/src/components/Button/index.tsx +3 -3
- package/src/components/ConfigPanel/NavigationForm/Field/index.tsx +14 -3
- package/src/components/ElementsTooltip/index.tsx +10 -9
- package/src/components/EmptyState/index.tsx +2 -2
- package/src/components/Fields/ArrayFieldGroup/index.tsx +1 -1
- package/src/components/Fields/AsyncCheckGroup/index.tsx +1 -1
- package/src/components/Fields/AsyncSelect/index.tsx +1 -1
- package/src/components/Fields/ComponentContainer/index.tsx +7 -6
- package/src/components/Fields/ComponentContainer/style.tsx +2 -2
- package/src/components/Fields/HiddenField/index.tsx +1 -1
- package/src/components/Fields/ImageField/index.tsx +10 -5
- package/src/components/Fields/MultiCheckSelect/index.tsx +3 -3
- package/src/components/Fields/NumberField/index.tsx +2 -1
- package/src/components/Fields/ReferenceField/ItemList/Item/index.tsx +5 -7
- package/src/components/Fields/ReferenceField/ItemList/Item/style.tsx +2 -2
- package/src/components/Fields/ReferenceField/ItemList/index.tsx +1 -1
- package/src/components/Fields/RichText/index.tsx +10 -6
- package/src/components/Fields/Select/index.tsx +1 -1
- package/src/components/Fields/SliderField/index.tsx +1 -1
- package/src/components/Fields/TimeField/HourInput/index.tsx +103 -0
- package/src/components/Fields/TimeField/HourInput/style.tsx +19 -0
- package/src/components/Fields/TimeField/HourInput/utils.tsx +35 -0
- package/src/components/Fields/TimeField/index.tsx +57 -0
- package/src/components/Fields/TimeField/style.tsx +37 -0
- package/src/components/Fields/index.tsx +2 -0
- package/src/components/FloatingMenu/index.tsx +1 -1
- package/src/components/Gallery/GalleryFilters/Type/index.tsx +50 -0
- package/src/components/Gallery/GalleryFilters/Type/style.tsx +39 -0
- package/src/components/Gallery/GalleryPanel/DetailPanel/index.tsx +2 -1
- package/src/components/Gallery/GalleryPanel/GalleryDragAndDrop/style.tsx +3 -3
- package/src/components/Gallery/hooks.tsx +10 -4
- package/src/components/Gallery/index.tsx +2 -0
- package/src/components/Icon/index.tsx +1 -1
- package/src/components/Loading/index.tsx +1 -1
- package/src/components/Pagination/index.tsx +1 -1
- package/src/components/SideModal/SideModalOption/index.tsx +4 -2
- package/src/components/SideModal/index.tsx +1 -1
- package/src/components/TableList/index.tsx +6 -6
- package/src/components/TableList/style.tsx +1 -1
- package/src/components/Tabs/index.tsx +19 -7
- package/src/components/Tag/index.tsx +6 -6
- package/src/components/Toast/index.tsx +4 -4
- package/src/components/Tooltip/index.tsx +5 -3
- package/src/components/index.tsx +2 -0
- package/src/containers/Navigation/Defaults/actions.tsx +10 -5
- package/src/containers/Navigation/Defaults/utils.tsx +13 -4
- package/src/containers/Sites/actions.tsx +7 -0
- package/src/containers/Sites/constants.tsx +1 -0
- package/src/containers/Sites/interfaces.tsx +6 -0
- package/src/containers/Sites/reducer.tsx +4 -0
- package/src/containers/StructuredData/actions.tsx +21 -8
- package/src/containers/StructuredData/constants.tsx +2 -0
- package/src/containers/StructuredData/interfaces.tsx +7 -1
- package/src/containers/StructuredData/reducer.tsx +5 -1
- package/src/helpers/fields.tsx +2 -2
- package/src/helpers/schemas.tsx +2 -2
- package/src/hooks/forms.tsx +2 -1
- package/src/modules/App/Routing/NavMenu/index.tsx +9 -1
- package/src/modules/Content/BulkHeader/TableHeader/index.tsx +1 -1
- package/src/modules/Content/hooks.tsx +19 -12
- package/src/modules/Content/index.tsx +23 -14
- package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/DefaultsBrowser/index.tsx +3 -0
- package/src/modules/Navigation/Defaults/DefaultsEditor/Editor/index.tsx +3 -1
- package/src/modules/Navigation/Defaults/DefaultsEditor/index.tsx +16 -18
- package/src/modules/Navigation/Defaults/DefaultsEditor/utils.tsx +37 -0
- package/src/modules/StructuredData/Form/ConnectedField/index.tsx +3 -2
- package/src/modules/StructuredData/Form/index.tsx +22 -17
- package/src/modules/StructuredData/StructuredDataList/hooks.tsx +30 -20
- package/src/modules/StructuredData/StructuredDataList/index.tsx +24 -14
- package/src/types/index.tsx +8 -7
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
const FieldWrapper = styled.div<{ error?: boolean; disabled?: boolean }>`
|
|
4
|
+
display: flex;
|
|
5
|
+
height: ${(p) => p.theme.spacing.l};
|
|
6
|
+
max-width: ${(p) => `calc(8 * ${p.theme.spacing.l})`};
|
|
7
|
+
min-width: ${(p) => `calc(5 * ${p.theme.spacing.l})`};
|
|
8
|
+
width: 100%;
|
|
9
|
+
border: 1px solid
|
|
10
|
+
${(p) => (p.error ? p.theme.color.error : p.disabled ? p.theme.color.interactiveDisabled : p.theme.color.uiLine)};
|
|
11
|
+
border-radius: ${(p) => p.theme.radii.s};
|
|
12
|
+
background: ${(p) => p.theme.color.uiBackground02};
|
|
13
|
+
padding: ${(p) => `0 ${p.theme.spacing.s}`};
|
|
14
|
+
align-items: center;
|
|
15
|
+
|
|
16
|
+
&:focus-within {
|
|
17
|
+
border-color: ${(p) => (p.error ? p.theme.color.error : p.theme.color.interactive01)};
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
const IconWrapper = styled.div`
|
|
22
|
+
width: ${(p) => p.theme.spacing.m};
|
|
23
|
+
height: ${(p) => p.theme.spacing.m};
|
|
24
|
+
margin-left: auto;
|
|
25
|
+
svg {
|
|
26
|
+
path {
|
|
27
|
+
fill: ${(p) => p.theme.color.interactive01};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
|
|
32
|
+
const SelectWrapper = styled.div`
|
|
33
|
+
padding-top: 4px;
|
|
34
|
+
color: ${(p) => p.theme.color.textMediumEmphasis};
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
export { FieldWrapper, IconWrapper, SelectWrapper };
|
|
@@ -29,6 +29,7 @@ import SliderField from "./SliderField";
|
|
|
29
29
|
import TagField from "./TagField";
|
|
30
30
|
import TextArea from "./TextArea";
|
|
31
31
|
import TextField from "./TextField";
|
|
32
|
+
import TimeField from "./TimeField";
|
|
32
33
|
import ToggleField from "./ToggleField";
|
|
33
34
|
import UniqueCheck from "./UniqueCheck";
|
|
34
35
|
import UrlField from "./UrlField";
|
|
@@ -68,6 +69,7 @@ export {
|
|
|
68
69
|
TagField,
|
|
69
70
|
TextArea,
|
|
70
71
|
TextField,
|
|
72
|
+
TimeField,
|
|
71
73
|
ToggleField,
|
|
72
74
|
UniqueCheck,
|
|
73
75
|
UrlField,
|
|
@@ -64,7 +64,7 @@ const FloatingMenu = (props: IProps) => {
|
|
|
64
64
|
onMouseLeave={handleMouseLeave}
|
|
65
65
|
data-testid="floating-menu"
|
|
66
66
|
>
|
|
67
|
-
<S.ButtonWrapper ref={button}>
|
|
67
|
+
<S.ButtonWrapper ref={button} data-testid="floating-menu-button">
|
|
68
68
|
<Button />
|
|
69
69
|
</S.ButtonWrapper>
|
|
70
70
|
{isOpen && (
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { FloatingMenu, Icon, ListTitle, ListItem } from "@ax/components";
|
|
4
|
+
|
|
5
|
+
import { areEquals } from "@ax/helpers";
|
|
6
|
+
|
|
7
|
+
import * as S from "./style";
|
|
8
|
+
|
|
9
|
+
const Type = ({ filterItems }: ITypeProps): JSX.Element => {
|
|
10
|
+
const initialState = ["all"];
|
|
11
|
+
const [selectedValue, setSelectedValue] = useState(initialState);
|
|
12
|
+
|
|
13
|
+
const setQuery = (selection: any) => {
|
|
14
|
+
if (!selection.length) {
|
|
15
|
+
selection = initialState;
|
|
16
|
+
}
|
|
17
|
+
setSelectedValue([selection]);
|
|
18
|
+
const pointer = "format";
|
|
19
|
+
filterItems(pointer, selection);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const isActive = !areEquals(selectedValue, initialState);
|
|
23
|
+
|
|
24
|
+
const Header = () => (
|
|
25
|
+
<S.Type isActive={isActive}>
|
|
26
|
+
Media type
|
|
27
|
+
<S.IconsWrapper>
|
|
28
|
+
{isActive && <Icon name="Filter" size="16" />}
|
|
29
|
+
<S.InteractiveArrow>
|
|
30
|
+
<Icon name="DownArrow" size="16" />
|
|
31
|
+
</S.InteractiveArrow>
|
|
32
|
+
</S.IconsWrapper>
|
|
33
|
+
</S.Type>
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<FloatingMenu Button={Header} position="center" closeOnSelect={true}>
|
|
38
|
+
<ListTitle>Filter by type</ListTitle>
|
|
39
|
+
<ListItem isSelected={selectedValue.includes("all")} onClick={() => setQuery("all")}>All</ListItem>
|
|
40
|
+
<ListItem isSelected={selectedValue.includes("bitmap")} onClick={() => setQuery("bitmap")}>Image</ListItem>
|
|
41
|
+
<ListItem isSelected={selectedValue.includes("vectorial")} onClick={() => setQuery("vectorial")}>Icons</ListItem>
|
|
42
|
+
</FloatingMenu>
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
interface ITypeProps {
|
|
47
|
+
filterItems(pointer: string, filter: string): void;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export default Type;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import styled from "styled-components";
|
|
3
|
+
import { Header } from "@ax/components/TableList/style";
|
|
4
|
+
|
|
5
|
+
const Type = styled((props) => <Header {...props} />)<{ isActive: boolean }>`
|
|
6
|
+
width: 90px;
|
|
7
|
+
white-space: nowrap;
|
|
8
|
+
justify-content: center;
|
|
9
|
+
flex-wrap: nowrap;
|
|
10
|
+
align-items: center;
|
|
11
|
+
cursor: pointer;
|
|
12
|
+
&:hover {
|
|
13
|
+
color: ${(p) => p.theme.color.interactive01};
|
|
14
|
+
}
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
const IconsWrapper = styled.div`
|
|
18
|
+
display: flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
flex-direction: row;
|
|
21
|
+
svg {
|
|
22
|
+
margin-left: 4px;
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
const InteractiveArrow = styled.div`
|
|
27
|
+
display: flex;
|
|
28
|
+
svg {
|
|
29
|
+
path {
|
|
30
|
+
fill: ${(p) => p.theme.color.interactive01};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
const ChecksWrapper = styled.div`
|
|
36
|
+
padding: ${(p) => p.theme.spacing.xs} ${(p) => p.theme.spacing.s};
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
export { Type, IconsWrapper, InteractiveArrow, ChecksWrapper };
|
|
@@ -71,7 +71,8 @@ const GalleryDetailPanel = (props: IProps) => {
|
|
|
71
71
|
|
|
72
72
|
const handleSetAsGlobal = async () => {
|
|
73
73
|
const saveAsGlobal = !isGlobalTab && addToGlobal.isChecked && imageSelected?.file;
|
|
74
|
-
const image =
|
|
74
|
+
const image =
|
|
75
|
+
saveAsGlobal && imageSelected && imageSelected.file && (await uploadImage(imageSelected.file, "global"));
|
|
75
76
|
if (image && image.id) await updateImage(image.id, imageForm);
|
|
76
77
|
setAddToGlobal({ value: "addToGlobal", isChecked: false });
|
|
77
78
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import React from "react";
|
|
1
2
|
import styled from "styled-components";
|
|
2
3
|
import { Button } from "@ax/components";
|
|
3
4
|
|
|
@@ -163,9 +164,8 @@ export const FilesInput = styled.input<{ ref: any }>`
|
|
|
163
164
|
display: none;
|
|
164
165
|
`;
|
|
165
166
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}))<{ ref: any }>`
|
|
167
|
+
const _Button: any = React.forwardRef((props: any, ref?: React.Ref<HTMLDivElement>) => <Button {...props} />);
|
|
168
|
+
export const FilesButton = styled(_Button)`
|
|
169
169
|
margin-top: ${(p) => p.theme.spacing.xs};
|
|
170
170
|
margin-bottom: ${(p) => p.theme.spacing.xs};
|
|
171
171
|
`;
|
|
@@ -21,13 +21,14 @@ const useSortedListStatus = () => {
|
|
|
21
21
|
const useFilterQuery = () => {
|
|
22
22
|
const initialQueryValues = {
|
|
23
23
|
orientation: "",
|
|
24
|
-
order: ""
|
|
24
|
+
order: "",
|
|
25
|
+
format: ""
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
const [query, setQuery] = useState(initialQueryValues);
|
|
28
29
|
|
|
29
30
|
const setFilterQuery = (filterValues: any) => {
|
|
30
|
-
const { orientation, order } = filterValues;
|
|
31
|
+
const { orientation, order, format } = filterValues;
|
|
31
32
|
let filterQuery = "";
|
|
32
33
|
|
|
33
34
|
const currentQuery = (pointer: string, values: string) => {
|
|
@@ -44,15 +45,20 @@ const useFilterQuery = () => {
|
|
|
44
45
|
filterQuery = currentQuery("order", order);
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
if (format) {
|
|
49
|
+
filterQuery = currentQuery("format", format);
|
|
50
|
+
}
|
|
51
|
+
|
|
47
52
|
return filterQuery;
|
|
48
53
|
};
|
|
49
54
|
|
|
50
55
|
const setFiltersSelection = (pointer: string, filter: string, isAscendent?: boolean) => {
|
|
51
|
-
const { orientation, order } = query;
|
|
56
|
+
const { orientation, order, format } = query;
|
|
52
57
|
const orderMethod = isAscendent ? "asc" : "desc";
|
|
53
58
|
const filterValues = {
|
|
54
59
|
orientation: pointer === "orientation" ? filter : orientation,
|
|
55
|
-
order: pointer === "order" ? `${filter}-${orderMethod}` : order
|
|
60
|
+
order: pointer === "order" ? `${filter}-${orderMethod}` : order,
|
|
61
|
+
format: pointer === "format" ? filter : format,
|
|
56
62
|
};
|
|
57
63
|
|
|
58
64
|
setQuery(filterValues);
|
|
@@ -8,6 +8,7 @@ import { Icon, Loader, Tabs, SearchField, EmptyState, ErrorToast, Notification }
|
|
|
8
8
|
|
|
9
9
|
import Orientation from "./GalleryFilters/Orientation";
|
|
10
10
|
import SortBy from "./GalleryFilters/SortBy";
|
|
11
|
+
import Type from "./GalleryFilters/Type";
|
|
11
12
|
import GalleryPanel from "./GalleryPanel";
|
|
12
13
|
import * as S from "./style";
|
|
13
14
|
import { useFilterQuery, useSortedListStatus } from "./hooks";
|
|
@@ -136,6 +137,7 @@ const Gallery = (props: IProps): JSX.Element => {
|
|
|
136
137
|
)}
|
|
137
138
|
<S.Filters>
|
|
138
139
|
<Orientation filterItems={filterItems} />
|
|
140
|
+
<Type filterItems={filterItems} />
|
|
139
141
|
<SortBy sortItems={sortItems} sortedState={sortedListStatus} />
|
|
140
142
|
</S.Filters>
|
|
141
143
|
</S.Header>
|
|
@@ -22,7 +22,7 @@ const Icon = (props: IProps) => {
|
|
|
22
22
|
const Svg = getImage(name);
|
|
23
23
|
|
|
24
24
|
if (Svg) {
|
|
25
|
-
return <Svg data-testid="
|
|
25
|
+
return <Svg data-testid="icon-component" height={size} width={size} viewBox="0 0 24 24" fill={fill} />;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
return null;
|
|
@@ -36,7 +36,7 @@ const Pagination = (props: IProps) => {
|
|
|
36
36
|
const CurrentPage = size === "S" ? currPage : <S.Input type="text" value={currPage} onChange={_handleChange} />;
|
|
37
37
|
|
|
38
38
|
return (
|
|
39
|
-
<S.Wrapper>
|
|
39
|
+
<S.Wrapper data-testid="pagination-wrapper">
|
|
40
40
|
<S.Literal size={size}>
|
|
41
41
|
Page {CurrentPage} of {lastPage}
|
|
42
42
|
</S.Literal>
|
|
@@ -14,7 +14,9 @@ const SideModalOption = (props: IProps) => {
|
|
|
14
14
|
|
|
15
15
|
const isNavigationDefault = ["header", "footer"].includes(option.type);
|
|
16
16
|
|
|
17
|
-
const
|
|
17
|
+
const navigationThumbnail = isNavigationDefault &&
|
|
18
|
+
option.thumbnail && { alt: option.title, src: option.thumbnail.url };
|
|
19
|
+
const thumbnailProps = navigationThumbnail || getThumbnailData(option, theme);
|
|
18
20
|
|
|
19
21
|
const optionParam = option.component || option;
|
|
20
22
|
const label = isNavigationDefault ? option.title : getDisplayName(optionParam);
|
|
@@ -25,7 +27,7 @@ const SideModalOption = (props: IProps) => {
|
|
|
25
27
|
};
|
|
26
28
|
|
|
27
29
|
return (
|
|
28
|
-
<S.Item onClick={setOption}>
|
|
30
|
+
<S.Item onClick={setOption} data-testid="side-modal-option">
|
|
29
31
|
<S.Thumbnail {...thumbnailProps} />
|
|
30
32
|
{label}
|
|
31
33
|
</S.Item>
|
|
@@ -137,7 +137,7 @@ const SideModal = (props: ISideModalProps): JSX.Element | null => {
|
|
|
137
137
|
|
|
138
138
|
return isOpen
|
|
139
139
|
? createPortal(
|
|
140
|
-
<S.Wrapper ref={node} optionsType={optionsType}>
|
|
140
|
+
<S.Wrapper ref={node} optionsType={optionsType} data-testid="side-modal">
|
|
141
141
|
<S.Header>
|
|
142
142
|
<S.Title>{optionsType}</S.Title>
|
|
143
143
|
{showSearch && optionsType !== "components" && (
|
|
@@ -5,7 +5,7 @@ import { Loading, Pagination } from "@ax/components";
|
|
|
5
5
|
|
|
6
6
|
import * as S from "./style";
|
|
7
7
|
|
|
8
|
-
const TableList = (props:
|
|
8
|
+
const TableList = (props: ITableListProps): JSX.Element => {
|
|
9
9
|
const { tableHeader, children, pagination, isLoading, onScroll, hasFixedHeader, tableRef } = props;
|
|
10
10
|
|
|
11
11
|
const { totalItems, setPage, itemsPerPage, currPage } = pagination;
|
|
@@ -13,11 +13,11 @@ const TableList = (props: IPagesProps): JSX.Element => {
|
|
|
13
13
|
const showPagination = totalItems > itemsPerPage;
|
|
14
14
|
|
|
15
15
|
return (
|
|
16
|
-
<S.TableList onScroll={onScroll} ref={tableRef}>
|
|
17
|
-
<S.Table
|
|
16
|
+
<S.TableList onScroll={onScroll} ref={tableRef} data-testid="table-list">
|
|
17
|
+
<S.Table>
|
|
18
18
|
<>
|
|
19
|
-
<S.TableHeader hasFixedHeader={hasFixedHeader}>{tableHeader}</S.TableHeader>
|
|
20
|
-
{isLoading ? <Loading /> : <S.TableBody>{children}</S.TableBody>}
|
|
19
|
+
<S.TableHeader hasFixedHeader={hasFixedHeader} data-testid="table-list-header">{tableHeader}</S.TableHeader>
|
|
20
|
+
{isLoading ? <Loading /> : <S.TableBody data-testid="table-body">{children}</S.TableBody>}
|
|
21
21
|
</>
|
|
22
22
|
</S.Table>
|
|
23
23
|
<S.PaginationWrapper>
|
|
@@ -33,7 +33,7 @@ const mapStateToProps = (state: IRootState) => ({
|
|
|
33
33
|
isLoading: state.app.isLoading,
|
|
34
34
|
});
|
|
35
35
|
|
|
36
|
-
interface
|
|
36
|
+
export interface ITableListProps {
|
|
37
37
|
tableHeader: JSX.Element | JSX.Element[];
|
|
38
38
|
children: JSX.Element | JSX.Element[];
|
|
39
39
|
pagination: {
|
|
@@ -6,7 +6,7 @@ const TableList = styled.div`
|
|
|
6
6
|
overflow: auto;
|
|
7
7
|
`;
|
|
8
8
|
|
|
9
|
-
const Table = styled.div
|
|
9
|
+
const Table = styled.div`
|
|
10
10
|
width: 100%;
|
|
11
11
|
min-height: calc(100% - ${(p) => p.theme.spacing.l} - ${(p) => p.theme.spacing.m});
|
|
12
12
|
padding-bottom: ${(p) => p.theme.spacing.m};
|
|
@@ -12,11 +12,17 @@ const Tabs = (props: ITabsProps): JSX.Element => {
|
|
|
12
12
|
|
|
13
13
|
if (tabs) {
|
|
14
14
|
return (
|
|
15
|
-
<S.TabsRow isInAppBar={isInAppBar} noMargins={noMargins}>
|
|
15
|
+
<S.TabsRow isInAppBar={isInAppBar} noMargins={noMargins} data-testid="tabs-row">
|
|
16
16
|
{tabs.map((tab: any) => {
|
|
17
17
|
const handleClick = () => setSelectedTab(tab);
|
|
18
18
|
return (
|
|
19
|
-
<S.TabItem
|
|
19
|
+
<S.TabItem
|
|
20
|
+
isInAppBar={isInAppBar}
|
|
21
|
+
key={tab}
|
|
22
|
+
active={tab === active}
|
|
23
|
+
onClick={handleClick}
|
|
24
|
+
data-testid="tab"
|
|
25
|
+
>
|
|
20
26
|
{tab}
|
|
21
27
|
</S.TabItem>
|
|
22
28
|
);
|
|
@@ -27,11 +33,17 @@ const Tabs = (props: ITabsProps): JSX.Element => {
|
|
|
27
33
|
|
|
28
34
|
if (icons) {
|
|
29
35
|
return (
|
|
30
|
-
<S.TabsRow icons={true} isInAppBar={isInAppBar}>
|
|
36
|
+
<S.TabsRow icons={true} isInAppBar={isInAppBar} data-testid="icons-tabs-row">
|
|
31
37
|
{icons.map((tab: ITabIcon) => {
|
|
32
38
|
const handleClick = () => setSelectedTab(tab.name);
|
|
33
39
|
return (
|
|
34
|
-
<S.TabItem
|
|
40
|
+
<S.TabItem
|
|
41
|
+
key={tab.name}
|
|
42
|
+
active={tab.name === active}
|
|
43
|
+
onClick={handleClick}
|
|
44
|
+
inversed={inversed}
|
|
45
|
+
data-testid="icon-tab"
|
|
46
|
+
>
|
|
35
47
|
<S.TabIcon>
|
|
36
48
|
<Tooltip content={tab.text} bottom>
|
|
37
49
|
<Icon name={tab.name} />
|
|
@@ -44,10 +56,10 @@ const Tabs = (props: ITabsProps): JSX.Element => {
|
|
|
44
56
|
);
|
|
45
57
|
}
|
|
46
58
|
|
|
47
|
-
return <S.TabsRow />;
|
|
59
|
+
return <S.TabsRow data-testid="empty-tabs-row"/>;
|
|
48
60
|
};
|
|
49
61
|
|
|
50
|
-
interface ITabsProps {
|
|
62
|
+
export interface ITabsProps {
|
|
51
63
|
tabs?: any[];
|
|
52
64
|
icons?: ITabIcon[];
|
|
53
65
|
isInAppBar?: boolean;
|
|
@@ -57,7 +69,7 @@ interface ITabsProps {
|
|
|
57
69
|
inversed?: boolean;
|
|
58
70
|
}
|
|
59
71
|
|
|
60
|
-
interface ITabIcon {
|
|
72
|
+
export interface ITabIcon {
|
|
61
73
|
name: string;
|
|
62
74
|
text: string;
|
|
63
75
|
}
|
|
@@ -13,7 +13,7 @@ const Tag = (props: ITagProps): JSX.Element => {
|
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
const deleteIcon = onDeleteAction ? (
|
|
16
|
-
<S.IconWrapper onClick={handleClick} data-testid="
|
|
16
|
+
<S.IconWrapper onClick={handleClick} data-testid="delete-icon-wrapper">
|
|
17
17
|
<Icon name="close" size="16" />
|
|
18
18
|
</S.IconWrapper>
|
|
19
19
|
) : null;
|
|
@@ -21,18 +21,18 @@ const Tag = (props: ITagProps): JSX.Element => {
|
|
|
21
21
|
switch (type) {
|
|
22
22
|
case "status":
|
|
23
23
|
return (
|
|
24
|
-
<S.TagStatus>
|
|
24
|
+
<S.TagStatus data-testid="tag-status">
|
|
25
25
|
<S.Bullet color={color} />
|
|
26
26
|
{text}
|
|
27
27
|
</S.TagStatus>
|
|
28
28
|
);
|
|
29
29
|
case "square":
|
|
30
|
-
return <S.TagSquare color={color}>{text}</S.TagSquare>;
|
|
30
|
+
return <S.TagSquare color={color} data-testid="tag-square">{text}</S.TagSquare>;
|
|
31
31
|
default:
|
|
32
32
|
return (
|
|
33
|
-
<S.TagFixed color={color}>
|
|
33
|
+
<S.TagFixed color={color} data-testid="tag-fixed">
|
|
34
34
|
<S.TagText>
|
|
35
|
-
<S.Title>{text}</S.Title>
|
|
35
|
+
<S.Title data-testid="tag-fixed-title">{text}</S.Title>
|
|
36
36
|
{deleteIcon}
|
|
37
37
|
</S.TagText>
|
|
38
38
|
</S.TagFixed>
|
|
@@ -40,7 +40,7 @@ const Tag = (props: ITagProps): JSX.Element => {
|
|
|
40
40
|
}
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
interface ITagProps {
|
|
43
|
+
export interface ITagProps {
|
|
44
44
|
type?: "status" | "fixed" | "interactive" | "square" | undefined;
|
|
45
45
|
text: string;
|
|
46
46
|
color?: string;
|
|
@@ -5,7 +5,7 @@ import { Button, IconAction } from "@ax/components";
|
|
|
5
5
|
|
|
6
6
|
import * as S from "./style";
|
|
7
7
|
|
|
8
|
-
const Toast = (props:
|
|
8
|
+
const Toast = (props: IToastProps) => {
|
|
9
9
|
const { action, message, setIsVisible } = props;
|
|
10
10
|
const toast = useRef<any>(null);
|
|
11
11
|
|
|
@@ -24,8 +24,8 @@ const Toast = (props: IProps) => {
|
|
|
24
24
|
}, []);
|
|
25
25
|
|
|
26
26
|
return createPortal(
|
|
27
|
-
<S.Wrapper ref={toast}>
|
|
28
|
-
<S.Text data-testid="
|
|
27
|
+
<S.Wrapper ref={toast} data-testid="toast-wrapper">
|
|
28
|
+
<S.Text data-testid="toast-message">{message}</S.Text>
|
|
29
29
|
<S.Buttons>
|
|
30
30
|
{action &&
|
|
31
31
|
<Button type="button" buttonStyle="lineInverse" onClick={action}>
|
|
@@ -39,7 +39,7 @@ const Toast = (props: IProps) => {
|
|
|
39
39
|
);
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
interface
|
|
42
|
+
export interface IToastProps {
|
|
43
43
|
action?: () => void;
|
|
44
44
|
message: string;
|
|
45
45
|
setIsVisible: (visibility: boolean) => void;
|
|
@@ -3,7 +3,7 @@ import { useHandleClickOutside } from "@ax/hooks";
|
|
|
3
3
|
|
|
4
4
|
import * as S from "./style";
|
|
5
5
|
|
|
6
|
-
const Tooltip = (props:
|
|
6
|
+
const Tooltip = (props: ITooltipProps): JSX.Element => {
|
|
7
7
|
const { content, children, hideOnClick = true, bottom, left } = props;
|
|
8
8
|
|
|
9
9
|
const initialState: IState = {
|
|
@@ -64,6 +64,7 @@ const Tooltip = (props: IProps): JSX.Element => {
|
|
|
64
64
|
useEffect(() => {
|
|
65
65
|
if (active && tipRef.current) {
|
|
66
66
|
const clientRect = tipRef.current.getBoundingClientRect();
|
|
67
|
+
|
|
67
68
|
const { left, right } = clientRect;
|
|
68
69
|
const windowSize = window.innerWidth;
|
|
69
70
|
if (left < 0) {
|
|
@@ -78,9 +79,10 @@ const Tooltip = (props: IProps): JSX.Element => {
|
|
|
78
79
|
if (!content) return children;
|
|
79
80
|
|
|
80
81
|
return (
|
|
81
|
-
<S.Tooltip data-testid="
|
|
82
|
+
<S.Tooltip data-testid="tooltip-component" onMouseEnter={showTip} onMouseLeave={hideTip} onMouseDown={handleClick}>
|
|
82
83
|
<div ref={childrenRef}>{children}</div>
|
|
83
84
|
<S.Tip
|
|
85
|
+
data-testid="tipComponent"
|
|
84
86
|
active={active}
|
|
85
87
|
childrenWidth={childrenWidth}
|
|
86
88
|
bottom={bottom}
|
|
@@ -101,7 +103,7 @@ interface IState {
|
|
|
101
103
|
fixOutOfBounds: number;
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
interface
|
|
106
|
+
export interface ITooltipProps {
|
|
105
107
|
content: string | boolean | undefined;
|
|
106
108
|
children: any;
|
|
107
109
|
hideOnClick?: boolean;
|
package/src/components/index.tsx
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
Select,
|
|
24
24
|
TextArea,
|
|
25
25
|
TextField,
|
|
26
|
+
TimeField,
|
|
26
27
|
ToggleField,
|
|
27
28
|
UniqueCheck,
|
|
28
29
|
UrlField,
|
|
@@ -117,6 +118,7 @@ export {
|
|
|
117
118
|
Select,
|
|
118
119
|
TextArea,
|
|
119
120
|
TextField,
|
|
121
|
+
TimeField,
|
|
120
122
|
ToggleField,
|
|
121
123
|
UniqueCheck,
|
|
122
124
|
UrlField,
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
|
|
25
25
|
import { appActions } from "@ax/containers/App";
|
|
26
26
|
|
|
27
|
-
import { getStateValues } from "./utils";
|
|
27
|
+
import { getFormData, getStateValues } from "./utils";
|
|
28
28
|
|
|
29
29
|
import {
|
|
30
30
|
SET_EDITOR_CONTENT,
|
|
@@ -221,7 +221,7 @@ function getNavigationByType(type: string): (dispatch: Dispatch, getState: any)
|
|
|
221
221
|
};
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
function createNavigation(): (dispatch: Dispatch, getState: any) => Promise<boolean> {
|
|
224
|
+
function createNavigation(image: File | null): (dispatch: Dispatch, getState: any) => Promise<boolean> {
|
|
225
225
|
return async (dispatch, getState) => {
|
|
226
226
|
try {
|
|
227
227
|
const {
|
|
@@ -237,6 +237,8 @@ function createNavigation(): (dispatch: Dispatch, getState: any) => Promise<bool
|
|
|
237
237
|
const navigationValues = { ...editorContent, site: currentSiteInfo.id, language: lang.id };
|
|
238
238
|
const cleanValues = removeEditorIds(navigationValues);
|
|
239
239
|
|
|
240
|
+
const form = getFormData(cleanValues, image);
|
|
241
|
+
|
|
240
242
|
const successAction = async (response: any) => {
|
|
241
243
|
const updatedContent = { ...editorContent, ...response };
|
|
242
244
|
generateContent(updatedContent, dispatch, getState);
|
|
@@ -248,7 +250,7 @@ function createNavigation(): (dispatch: Dispatch, getState: any) => Promise<bool
|
|
|
248
250
|
handleError: (response: any) => appActions.handleError(response)(dispatch),
|
|
249
251
|
};
|
|
250
252
|
|
|
251
|
-
const callback = async () => navigation.createNavigation(
|
|
253
|
+
const callback = async () => navigation.createNavigation(form);
|
|
252
254
|
|
|
253
255
|
return await handleRequest(callback, responseActions, [appActions.setIsSaving])(dispatch);
|
|
254
256
|
} catch (e) {
|
|
@@ -261,7 +263,8 @@ function createNavigation(): (dispatch: Dispatch, getState: any) => Promise<bool
|
|
|
261
263
|
function updateNavigation(
|
|
262
264
|
navID: number,
|
|
263
265
|
data: any,
|
|
264
|
-
fromEditor?: boolean
|
|
266
|
+
fromEditor?: boolean,
|
|
267
|
+
image?: File | null
|
|
265
268
|
): (dispatch: Dispatch, getState: any) => Promise<boolean> {
|
|
266
269
|
return async (dispatch, getState) => {
|
|
267
270
|
try {
|
|
@@ -272,6 +275,8 @@ function updateNavigation(
|
|
|
272
275
|
|
|
273
276
|
const cleanValues = removeEditorIds(data);
|
|
274
277
|
|
|
278
|
+
const form = getFormData(cleanValues, image);
|
|
279
|
+
|
|
275
280
|
const successAction = async (response: any) => {
|
|
276
281
|
if (fromEditor) {
|
|
277
282
|
generateContent(response, dispatch, getState);
|
|
@@ -284,7 +289,7 @@ function updateNavigation(
|
|
|
284
289
|
handleError: (response: any) => appActions.handleError(response)(dispatch),
|
|
285
290
|
};
|
|
286
291
|
|
|
287
|
-
const callback = async () => navigation.updateNavigation(navID,
|
|
292
|
+
const callback = async () => navigation.updateNavigation(navID, form);
|
|
288
293
|
|
|
289
294
|
return await handleRequest(callback, responseActions, [appActions.setIsSaving])(dispatch);
|
|
290
295
|
} catch (e) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
const getStateValues = (getState: any) => {
|
|
2
2
|
const {
|
|
3
3
|
sites: { currentSiteInfo },
|
|
4
4
|
navigation: {
|
|
@@ -10,9 +10,9 @@ export const getStateValues = (getState: any) => {
|
|
|
10
10
|
footer,
|
|
11
11
|
isNewTranslation,
|
|
12
12
|
currentDefaultsContent,
|
|
13
|
-
selectedContent
|
|
13
|
+
selectedContent,
|
|
14
14
|
},
|
|
15
|
-
app: { isSaving, isLoading }
|
|
15
|
+
app: { isSaving, isLoading },
|
|
16
16
|
} = getState();
|
|
17
17
|
const section = editorContent && editorContent[0];
|
|
18
18
|
const { modules } = !!section && section;
|
|
@@ -31,6 +31,15 @@ export const getStateValues = (getState: any) => {
|
|
|
31
31
|
isLoading,
|
|
32
32
|
section,
|
|
33
33
|
modules,
|
|
34
|
-
selectedContent
|
|
34
|
+
selectedContent,
|
|
35
35
|
};
|
|
36
36
|
};
|
|
37
|
+
|
|
38
|
+
const getFormData = (values: any, image?: File | null): FormData => {
|
|
39
|
+
const form = new FormData();
|
|
40
|
+
form.append("navigation", JSON.stringify(values));
|
|
41
|
+
image && form.append("file", image);
|
|
42
|
+
return form;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export { getStateValues, getFormData };
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
SET_SAVED_SITE_INFO,
|
|
11
11
|
DEFAULT_PARAMS,
|
|
12
12
|
SET_CURRENT_SITE_ERROR_PAGES,
|
|
13
|
+
SET_CONTENT_FILTERS,
|
|
13
14
|
} from "./constants";
|
|
14
15
|
import {
|
|
15
16
|
ISetSitesAction,
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
ISetCurrentSiteLanguagesAction,
|
|
22
23
|
ISetSavedSiteInfoAction,
|
|
23
24
|
ISetCurrentSiteErrorPages,
|
|
25
|
+
ISetContentFilters,
|
|
24
26
|
} from "./interfaces";
|
|
25
27
|
|
|
26
28
|
import { ISite, IGetSitePagesParams, ISettingsForm, IGetGlobalPagesParams, IPage } from "@ax/types";
|
|
@@ -77,6 +79,10 @@ function setCurrentSiteErrorPages(currentSiteErrorPages: number[]): ISetCurrentS
|
|
|
77
79
|
return { type: SET_CURRENT_SITE_ERROR_PAGES, payload: { currentSiteErrorPages } };
|
|
78
80
|
}
|
|
79
81
|
|
|
82
|
+
function setContentFilters(contentFilters: Record<string, string> | null): ISetContentFilters {
|
|
83
|
+
return { type: SET_CONTENT_FILTERS, payload: { contentFilters } };
|
|
84
|
+
}
|
|
85
|
+
|
|
80
86
|
// TODO: hay que controlar que cuando da error la API borrar los sites ya guardados y sacar el error (ver los siguientes FIXME)
|
|
81
87
|
function getSites(): (dispatch: Dispatch) => Promise<void> {
|
|
82
88
|
return async (dispatch) => {
|
|
@@ -507,4 +513,5 @@ export {
|
|
|
507
513
|
removeUsersBulk,
|
|
508
514
|
setCurrentSiteErrorPages,
|
|
509
515
|
resetCurrentSiteErrorPages,
|
|
516
|
+
setContentFilters,
|
|
510
517
|
};
|