@truedat/core 5.18.0 → 5.18.2
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/ConfirmModal.js +1 -0
- package/src/components/FilterMultilevelDropdown.js +3 -0
- package/src/components/HierarchyFilterDropdown.js +2 -1
- package/src/components/SearchFilterDropdown.js +155 -0
- package/src/components/SelectedFilters.js +26 -10
- package/src/components/StructureFilterItem.js +33 -0
- package/src/components/__tests__/FilterDropdown.spec.js +5 -2
- package/src/components/__tests__/SearchFilterDropdown.spec.js +106 -0
- package/src/components/__tests__/SelectedFilters.spec.js +89 -32
- package/src/components/__tests__/StructureFilterItem.spec.js +26 -0
- package/src/components/__tests__/__snapshots__/FilterMultilevelDropdown.spec.js.snap +1 -0
- package/src/components/__tests__/__snapshots__/HierarchyFilterDropdown.spec.js.snap +2 -0
- package/src/components/__tests__/__snapshots__/SearchFilterDropdown.spec.js.snap +147 -0
- package/src/components/__tests__/__snapshots__/SelectedFilters.spec.js.snap +97 -49
- package/src/components/__tests__/__snapshots__/StructureFilterItem.spec.js.snap +28 -0
- package/src/components/index.js +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/core",
|
|
3
|
-
"version": "5.18.
|
|
3
|
+
"version": "5.18.2",
|
|
4
4
|
"description": "Truedat Web Core",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"jsnext:main": "src/index.js",
|
|
@@ -117,5 +117,5 @@
|
|
|
117
117
|
"react-dom": ">= 16.8.6 < 17",
|
|
118
118
|
"semantic-ui-react": ">= 2.0.3 < 2.2"
|
|
119
119
|
},
|
|
120
|
-
"gitHead": "
|
|
120
|
+
"gitHead": "d69ace0ddcf34baa4f4b60a6862a053327c1d299"
|
|
121
121
|
}
|
|
@@ -14,6 +14,7 @@ import { lowerDeburr } from "../services/sort";
|
|
|
14
14
|
import DropdownMenuItem from "./DropdownMenuItem";
|
|
15
15
|
|
|
16
16
|
export const FilterMultilevelDropdown = ({
|
|
17
|
+
name,
|
|
17
18
|
activeValues,
|
|
18
19
|
closeFilter,
|
|
19
20
|
filter,
|
|
@@ -130,6 +131,7 @@ export const FilterMultilevelDropdown = ({
|
|
|
130
131
|
|
|
131
132
|
return (
|
|
132
133
|
<Dropdown
|
|
134
|
+
name={name || "filterMultilevelDropdown"}
|
|
133
135
|
item
|
|
134
136
|
floating
|
|
135
137
|
icon={false}
|
|
@@ -193,6 +195,7 @@ export const FilterMultilevelDropdown = ({
|
|
|
193
195
|
};
|
|
194
196
|
|
|
195
197
|
FilterMultilevelDropdown.propTypes = {
|
|
198
|
+
name: PropTypes.string,
|
|
196
199
|
activeValues: PropTypes.array,
|
|
197
200
|
closeFilter: PropTypes.func,
|
|
198
201
|
filter: PropTypes.string,
|
|
@@ -72,6 +72,7 @@ const PopulatedHierarchyFilterDropdown = (props) => {
|
|
|
72
72
|
|
|
73
73
|
return (
|
|
74
74
|
<FilterMultilevelDropdown
|
|
75
|
+
name="hierarchyFilterDropdown"
|
|
75
76
|
activeValues={idActiveValues}
|
|
76
77
|
closeFilter={closeFilter}
|
|
77
78
|
filter={filter}
|
|
@@ -97,7 +98,7 @@ PopulatedHierarchyFilterDropdown.propTypes = {
|
|
|
97
98
|
|
|
98
99
|
const HierarchyFilterDropdown = (props) =>
|
|
99
100
|
_.isEmpty(props.options) ? (
|
|
100
|
-
<FilterMultilevelDropdown {...props} />
|
|
101
|
+
<FilterMultilevelDropdown {...props} name="hierarchyFilterDropdown" />
|
|
101
102
|
) : (
|
|
102
103
|
<PopulatedHierarchyFilterDropdown {...props} />
|
|
103
104
|
);
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
|
|
4
|
+
import _ from "lodash/fp";
|
|
5
|
+
import { useIntl } from "react-intl";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
Label,
|
|
9
|
+
Icon,
|
|
10
|
+
Dropdown,
|
|
11
|
+
Dimmer,
|
|
12
|
+
Loader,
|
|
13
|
+
Input,
|
|
14
|
+
} from "semantic-ui-react";
|
|
15
|
+
import { accentInsensitivePathOrder } from "../services/sort";
|
|
16
|
+
|
|
17
|
+
const removePrefix = _.replace(/^.*\./, "");
|
|
18
|
+
const SPACE_CODE = 32;
|
|
19
|
+
|
|
20
|
+
export const SearchFilterDropdown = ({
|
|
21
|
+
query,
|
|
22
|
+
searchCallback,
|
|
23
|
+
placeholder,
|
|
24
|
+
options,
|
|
25
|
+
open,
|
|
26
|
+
loading,
|
|
27
|
+
activeValues,
|
|
28
|
+
closeFilter,
|
|
29
|
+
filter,
|
|
30
|
+
FilterDataLoader,
|
|
31
|
+
loaderProps,
|
|
32
|
+
FilterItem,
|
|
33
|
+
openFilter,
|
|
34
|
+
removeFilter,
|
|
35
|
+
toggleFilterValue,
|
|
36
|
+
searchFilterDispacher,
|
|
37
|
+
}) => {
|
|
38
|
+
const [selectedOptions, setSelectedOptions] = useState([]);
|
|
39
|
+
const { formatMessage } = useIntl();
|
|
40
|
+
|
|
41
|
+
const toogleSelectedOption = (selectedOption) => {
|
|
42
|
+
const newSelectedOptions = selectedOptions.find(
|
|
43
|
+
(s) => s.id === selectedOption.id
|
|
44
|
+
)
|
|
45
|
+
? selectedOptions.filter((s) => s.id !== selectedOption.id)
|
|
46
|
+
: [...selectedOptions, selectedOption];
|
|
47
|
+
setSelectedOptions(newSelectedOptions);
|
|
48
|
+
toggleFilterValue({ filter, value: selectedOption.id });
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<Dropdown
|
|
53
|
+
name="searchFilterDropdown"
|
|
54
|
+
item
|
|
55
|
+
floating
|
|
56
|
+
scrolling
|
|
57
|
+
icon={false}
|
|
58
|
+
upward={false}
|
|
59
|
+
trigger={
|
|
60
|
+
<Label key={filter}>
|
|
61
|
+
{formatMessage({
|
|
62
|
+
id: `filters.${filter}`,
|
|
63
|
+
defaultMessage: removePrefix(filter),
|
|
64
|
+
})}
|
|
65
|
+
<Icon
|
|
66
|
+
name="delete"
|
|
67
|
+
onClick={(e) => {
|
|
68
|
+
e.preventDefault();
|
|
69
|
+
e.stopPropagation();
|
|
70
|
+
removeFilter({ filter });
|
|
71
|
+
}}
|
|
72
|
+
/>
|
|
73
|
+
</Label>
|
|
74
|
+
}
|
|
75
|
+
onOpen={() => openFilter({ filter })}
|
|
76
|
+
onClose={(e) => {
|
|
77
|
+
// Next line Fix bug: https://github.com/Semantic-Org/Semantic-UI-React/pull/3766
|
|
78
|
+
if (e?.type === "keydown" && e?.keyCode === SPACE_CODE) return;
|
|
79
|
+
closeFilter({ filter });
|
|
80
|
+
}}
|
|
81
|
+
open={open}
|
|
82
|
+
>
|
|
83
|
+
<Dimmer.Dimmable as={Dropdown.Menu} dimmed={loading}>
|
|
84
|
+
<FilterDataLoader {...loaderProps} />
|
|
85
|
+
<Input
|
|
86
|
+
icon="search"
|
|
87
|
+
iconPosition="left"
|
|
88
|
+
placeholder={placeholder}
|
|
89
|
+
// Next line Fix bug: https://github.com/Semantic-Org/Semantic-UI-React/issues/1593
|
|
90
|
+
onClick={(e) => e.stopPropagation()}
|
|
91
|
+
value={query}
|
|
92
|
+
onChange={(_e, data) =>
|
|
93
|
+
searchFilterDispacher(searchCallback({ query: data.value }))
|
|
94
|
+
}
|
|
95
|
+
// Next line Fix bug: https://github.com/Semantic-Org/Semantic-UI-React/issues/4374
|
|
96
|
+
onKeyDown={(e) => e.keyCode === SPACE_CODE && e.stopPropagation()}
|
|
97
|
+
/>
|
|
98
|
+
{selectedOptions &&
|
|
99
|
+
_.flow(
|
|
100
|
+
_.sortBy(accentInsensitivePathOrder("text")),
|
|
101
|
+
_.map.convert({ cap: false })((option, i) => (
|
|
102
|
+
<FilterItem
|
|
103
|
+
key={i}
|
|
104
|
+
filter={filter}
|
|
105
|
+
option={option}
|
|
106
|
+
toggleFilterValue={toogleSelectedOption}
|
|
107
|
+
active={_.includes(_.prop("id")(option))(activeValues)}
|
|
108
|
+
/>
|
|
109
|
+
))
|
|
110
|
+
)(selectedOptions)}
|
|
111
|
+
<Dropdown.Divider />
|
|
112
|
+
{options &&
|
|
113
|
+
_.flow(
|
|
114
|
+
_.sortBy(accentInsensitivePathOrder("text")),
|
|
115
|
+
_.filter((o) => !_.includes(_.prop("id")(o))(activeValues)),
|
|
116
|
+
_.map.convert({ cap: false })((option, i) => (
|
|
117
|
+
<FilterItem
|
|
118
|
+
key={i}
|
|
119
|
+
filter={filter}
|
|
120
|
+
option={option}
|
|
121
|
+
toggleFilterValue={toogleSelectedOption}
|
|
122
|
+
active={_.includes(_.prop("id")(option))(activeValues)}
|
|
123
|
+
/>
|
|
124
|
+
))
|
|
125
|
+
)(options)}
|
|
126
|
+
{loading && (
|
|
127
|
+
<Dimmer active inverted>
|
|
128
|
+
<Loader size="tiny" />
|
|
129
|
+
</Dimmer>
|
|
130
|
+
)}
|
|
131
|
+
</Dimmer.Dimmable>
|
|
132
|
+
</Dropdown>
|
|
133
|
+
);
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
SearchFilterDropdown.propTypes = {
|
|
137
|
+
query: PropTypes.string,
|
|
138
|
+
searchCallback: PropTypes.func,
|
|
139
|
+
placeholder: PropTypes.string,
|
|
140
|
+
options: PropTypes.object,
|
|
141
|
+
open: PropTypes.bool,
|
|
142
|
+
loading: PropTypes.bool,
|
|
143
|
+
activeValues: PropTypes.array,
|
|
144
|
+
closeFilter: PropTypes.func,
|
|
145
|
+
filter: PropTypes.string,
|
|
146
|
+
FilterDataLoader: PropTypes.node,
|
|
147
|
+
loaderProps: PropTypes.object,
|
|
148
|
+
FilterItem: PropTypes.object,
|
|
149
|
+
openFilter: PropTypes.func,
|
|
150
|
+
removeFilter: PropTypes.func,
|
|
151
|
+
toggleFilterValue: PropTypes.func,
|
|
152
|
+
searchFilterDispacher: PropTypes.func,
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
export default SearchFilterDropdown;
|
|
@@ -5,6 +5,7 @@ import { FormattedMessage } from "react-intl";
|
|
|
5
5
|
import FilterDropdown from "./FilterDropdown";
|
|
6
6
|
import FilterMultilevelDropdown from "./FilterMultilevelDropdown";
|
|
7
7
|
import HierarchyFilterDropdown from "./HierarchyFilterDropdown";
|
|
8
|
+
import SearchFilterDropdown from "./SearchFilterDropdown";
|
|
8
9
|
import ModalSaveFilter from "./ModalSaveFilter";
|
|
9
10
|
import UserFilters from "./UserFilters";
|
|
10
11
|
|
|
@@ -27,6 +28,8 @@ export const SelectedFilters = ({
|
|
|
27
28
|
toggleFilterValue,
|
|
28
29
|
userFilters,
|
|
29
30
|
userFilterScope,
|
|
31
|
+
searchFiltersPropsMapping,
|
|
32
|
+
searchFilterDispacher,
|
|
30
33
|
}) => (
|
|
31
34
|
<>
|
|
32
35
|
{_.isEmpty(userFilters) ? null : (
|
|
@@ -47,10 +50,10 @@ export const SelectedFilters = ({
|
|
|
47
50
|
<FormattedMessage id="search.applied_filters" />
|
|
48
51
|
</div>
|
|
49
52
|
{selectedFilters.map((filter) => {
|
|
53
|
+
const isSelectedFilter = _.isEqual(filter, selectedFilter);
|
|
54
|
+
|
|
50
55
|
const filterType = _.prop(filter)(filterTypes);
|
|
51
|
-
const options =
|
|
52
|
-
? selectedFilterValues
|
|
53
|
-
: null;
|
|
56
|
+
const options = isSelectedFilter ? selectedFilterValues : null;
|
|
54
57
|
|
|
55
58
|
const props = {
|
|
56
59
|
key: filter,
|
|
@@ -63,13 +66,24 @@ export const SelectedFilters = ({
|
|
|
63
66
|
removeFilter,
|
|
64
67
|
toggleFilterValue,
|
|
65
68
|
};
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
|
|
70
|
+
switch (filterType) {
|
|
71
|
+
case "domain":
|
|
72
|
+
return <FilterMultilevelDropdown {...props} />;
|
|
73
|
+
case "hierarchy":
|
|
74
|
+
return <HierarchyFilterDropdown {...props} />;
|
|
75
|
+
case "search":
|
|
76
|
+
return (
|
|
77
|
+
<SearchFilterDropdown
|
|
78
|
+
{...props}
|
|
79
|
+
{...searchFiltersPropsMapping[filter]}
|
|
80
|
+
open={isSelectedFilter}
|
|
81
|
+
searchFilterDispacher={searchFilterDispacher}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
default:
|
|
85
|
+
return <FilterDropdown {...props} />;
|
|
86
|
+
}
|
|
73
87
|
})}
|
|
74
88
|
<a className="resetFilters" onClick={() => resetFilters()}>
|
|
75
89
|
<FormattedMessage id="search.clear_filters" />
|
|
@@ -106,6 +120,8 @@ SelectedFilters.propTypes = {
|
|
|
106
120
|
toggleFilterValue: PropTypes.func,
|
|
107
121
|
userFilters: PropTypes.array,
|
|
108
122
|
userFilterScope: PropTypes.string,
|
|
123
|
+
searchFiltersPropsMapping: PropTypes.object,
|
|
124
|
+
searchFilterDispacher: PropTypes.func,
|
|
109
125
|
};
|
|
110
126
|
|
|
111
127
|
export default SelectedFilters;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { Icon, Dropdown, Segment } from "semantic-ui-react";
|
|
5
|
+
|
|
6
|
+
const preventDefault = (e, callback) => {
|
|
7
|
+
e && e.preventDefault();
|
|
8
|
+
e && e.stopPropagation();
|
|
9
|
+
callback();
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const StructureFilterItem = ({ active, toggleFilterValue, option }) => (
|
|
13
|
+
<Dropdown.Item
|
|
14
|
+
onClick={(e) => preventDefault(e, () => toggleFilterValue(option))}
|
|
15
|
+
active={active}
|
|
16
|
+
>
|
|
17
|
+
<Segment vertical>
|
|
18
|
+
<Icon name={active ? "check square outline" : "square outline"} />
|
|
19
|
+
{_.trim(option.name)}
|
|
20
|
+
<small>{` - (${option.type})`}</small>
|
|
21
|
+
<br />
|
|
22
|
+
<small>{option.path.join(" > ")}</small>
|
|
23
|
+
</Segment>
|
|
24
|
+
</Dropdown.Item>
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
StructureFilterItem.propTypes = {
|
|
28
|
+
active: PropTypes.bool,
|
|
29
|
+
toggleFilterValue: PropTypes.func,
|
|
30
|
+
option: PropTypes.object,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export default StructureFilterItem;
|
|
@@ -4,7 +4,10 @@ import { shallow } from "enzyme";
|
|
|
4
4
|
import { Dropdown } from "semantic-ui-react";
|
|
5
5
|
import { FilterDropdown } from "../FilterDropdown";
|
|
6
6
|
|
|
7
|
-
const options = _.map(value => ({ value, text: value }))([
|
|
7
|
+
const options = _.map((value) => ({ value, text: value }))([
|
|
8
|
+
"value1",
|
|
9
|
+
"value2",
|
|
10
|
+
]);
|
|
8
11
|
|
|
9
12
|
describe("<FilterDropdown/>", () => {
|
|
10
13
|
it("matches the latest snapshot", () => {
|
|
@@ -24,7 +27,7 @@ describe("<FilterDropdown/>", () => {
|
|
|
24
27
|
filter,
|
|
25
28
|
openFilter,
|
|
26
29
|
options,
|
|
27
|
-
removeFilter
|
|
30
|
+
removeFilter,
|
|
28
31
|
};
|
|
29
32
|
const wrapper = shallow(<FilterDropdown {...props} />);
|
|
30
33
|
expect(openFilter.mock.calls.length).toBe(0);
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/* eslint-disable react/prop-types */
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { render } from "@truedat/test/render";
|
|
4
|
+
import { within, waitFor } from "@testing-library/react";
|
|
5
|
+
import userEvent from "@testing-library/user-event";
|
|
6
|
+
|
|
7
|
+
import { Icon, Dropdown, Segment } from "semantic-ui-react";
|
|
8
|
+
|
|
9
|
+
import SearchFilterDropdown from "../SearchFilterDropdown";
|
|
10
|
+
|
|
11
|
+
const DummyLoader = () => <div></div>;
|
|
12
|
+
const DummyFilerItem = ({ active, toggleFilterValue, option }) => (
|
|
13
|
+
<Dropdown.Item onClick={() => toggleFilterValue(option)} active={active}>
|
|
14
|
+
<Segment vertical>
|
|
15
|
+
<Icon name={active ? "check square outline" : "square outline"} />
|
|
16
|
+
{option.name}
|
|
17
|
+
</Segment>
|
|
18
|
+
</Dropdown.Item>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const props = {
|
|
22
|
+
query: "foo_query",
|
|
23
|
+
searchCallback: jest.fn(),
|
|
24
|
+
placeholder: "search dropdown",
|
|
25
|
+
options: [
|
|
26
|
+
{
|
|
27
|
+
id: 1,
|
|
28
|
+
name: "foo_option",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 2,
|
|
32
|
+
name: "bar_option",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
id: 3,
|
|
36
|
+
name: "baz_option",
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
open: true,
|
|
40
|
+
loading: false,
|
|
41
|
+
activeValues: [1],
|
|
42
|
+
closeFilter: jest.fn(),
|
|
43
|
+
filter: "foo_filter",
|
|
44
|
+
FilterDataLoader: DummyLoader,
|
|
45
|
+
loaderProps: { name: "loader-prop" },
|
|
46
|
+
FilterItem: DummyFilerItem,
|
|
47
|
+
openFilter: jest.fn(),
|
|
48
|
+
removeFilter: jest.fn(),
|
|
49
|
+
toggleFilterValue: jest.fn(),
|
|
50
|
+
searchFilterDispacher: jest.fn(),
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
describe("<SearchFilterDropDown/>", () => {
|
|
54
|
+
it("matches the latest snapshot unfolded", () => {
|
|
55
|
+
const { container } = render(<SearchFilterDropdown {...props} />);
|
|
56
|
+
expect(container).toMatchSnapshot();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("matches the latest snapshot folded", () => {
|
|
60
|
+
const customProps = {
|
|
61
|
+
...props,
|
|
62
|
+
open: false,
|
|
63
|
+
};
|
|
64
|
+
const { container } = render(<SearchFilterDropdown {...customProps} />);
|
|
65
|
+
expect(container).toMatchSnapshot();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("check option check it correctly", () => {
|
|
69
|
+
const { getByRole, getAllByRole } = render(
|
|
70
|
+
<SearchFilterDropdown {...props} />
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
expect(props.toggleFilterValue).toBeCalledTimes(0);
|
|
74
|
+
userEvent.click(getByRole("option", { name: "baz_option" }));
|
|
75
|
+
expect(props.toggleFilterValue).toBeCalledWith({
|
|
76
|
+
value: 3,
|
|
77
|
+
filter: "foo_filter",
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(
|
|
81
|
+
within(getAllByRole("option")[0]).queryByText("baz_option")
|
|
82
|
+
).not.toBeNull();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("type in filter input dispatch searchCallback with correct query", () => {
|
|
86
|
+
const searchText = "a";
|
|
87
|
+
|
|
88
|
+
const { getByRole } = render(<SearchFilterDropdown {...props} />);
|
|
89
|
+
const input = getByRole("textbox");
|
|
90
|
+
|
|
91
|
+
userEvent.type(input, searchText);
|
|
92
|
+
|
|
93
|
+
expect(props.searchCallback).toBeCalledWith({
|
|
94
|
+
query: `${props.query}${searchText}`,
|
|
95
|
+
});
|
|
96
|
+
expect(props.searchFilterDispacher).toBeCalledTimes(1);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("remove filter dispatches removeFilter", async () => {
|
|
100
|
+
const { container } = render(<SearchFilterDropdown {...props} />);
|
|
101
|
+
userEvent.click(container.querySelector('[class="delete icon"]'));
|
|
102
|
+
await waitFor(() => {
|
|
103
|
+
expect(props.removeFilter).toBeCalledTimes(1);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
});
|
|
@@ -1,66 +1,94 @@
|
|
|
1
|
+
/* eslint-disable react/prop-types */
|
|
1
2
|
import React from "react";
|
|
2
|
-
import {
|
|
3
|
+
import { render } from "@truedat/test/render";
|
|
4
|
+
|
|
5
|
+
import userEvent from "@testing-library/user-event";
|
|
6
|
+
import { Icon, Dropdown, Segment } from "semantic-ui-react";
|
|
7
|
+
|
|
3
8
|
import { SelectedFilters } from "../SelectedFilters";
|
|
4
9
|
|
|
10
|
+
const DummyLoader = () => <div></div>;
|
|
11
|
+
const DummyFilerItem = ({ active, toggleFilterValue, option }) => (
|
|
12
|
+
<Dropdown.Item onClick={() => toggleFilterValue(option)} active={active}>
|
|
13
|
+
<Segment vertical>
|
|
14
|
+
<Icon name={active ? "check square outline" : "square outline"} />
|
|
15
|
+
{option.name}
|
|
16
|
+
</Segment>
|
|
17
|
+
</Dropdown.Item>
|
|
18
|
+
);
|
|
19
|
+
|
|
5
20
|
describe("<SelectedFilters/>", () => {
|
|
6
|
-
const
|
|
21
|
+
const props = {
|
|
7
22
|
resetFilters: jest.fn(),
|
|
8
23
|
filterTypes: {
|
|
9
24
|
foo: "fooType",
|
|
10
25
|
},
|
|
26
|
+
openFilter: jest.fn(),
|
|
27
|
+
closeFilter: jest.fn(),
|
|
11
28
|
selectedFilter: "foo",
|
|
12
29
|
selectedFilters: ["foo", "bar"],
|
|
13
30
|
selectedFilterActiveValues: ["value2"],
|
|
14
31
|
selectedFilterValues: ["value1", "value2"],
|
|
15
|
-
saveFilters: jest.fn(),
|
|
16
32
|
selectedUserFilter: null,
|
|
17
33
|
userFilters: ["uf1", "uf2"],
|
|
18
|
-
|
|
34
|
+
searchFiltersPropsMapping: {},
|
|
35
|
+
searchFilterDispacher: jest.fn(),
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const messages = {
|
|
39
|
+
"search.clear_filters": "clean filters",
|
|
40
|
+
"search.save_filters": "save filters",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const renderOptions = {
|
|
44
|
+
messages: {
|
|
45
|
+
en: messages,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
19
48
|
|
|
20
49
|
it("matches the latest snapshot", () => {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
expect(wrapper).toMatchSnapshot();
|
|
50
|
+
const { container } = render(<SelectedFilters {...props} />);
|
|
51
|
+
expect(container).toMatchSnapshot();
|
|
24
52
|
});
|
|
25
53
|
|
|
26
54
|
it("dispatches resetFilters", () => {
|
|
27
|
-
const
|
|
28
|
-
const wrapper = shallowWithIntl(<SelectedFilters {...props} />);
|
|
55
|
+
const { getByText } = render(<SelectedFilters {...props} />, renderOptions);
|
|
29
56
|
|
|
30
|
-
expect(props.resetFilters
|
|
31
|
-
|
|
32
|
-
expect(props.resetFilters
|
|
57
|
+
expect(props.resetFilters).toBeCalledTimes(0);
|
|
58
|
+
userEvent.click(getByText(messages["search.clear_filters"]));
|
|
59
|
+
expect(props.resetFilters).toBeCalledTimes(1);
|
|
33
60
|
});
|
|
34
61
|
|
|
35
62
|
it("does not render Save filters option if saveFilters is undefined", () => {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
63
|
+
const { queryByText } = render(
|
|
64
|
+
<SelectedFilters {...props} />,
|
|
65
|
+
renderOptions
|
|
66
|
+
);
|
|
67
|
+
expect(queryByText(messages["search.save_filters"])).toBeNull();
|
|
40
68
|
});
|
|
41
69
|
|
|
42
70
|
it("renders Save filters option if saveFilters is defined", () => {
|
|
43
|
-
const
|
|
44
|
-
const
|
|
45
|
-
|
|
71
|
+
const customProps = { ...props, saveFilters: jest.fn() };
|
|
72
|
+
const { getByText } = render(
|
|
73
|
+
<SelectedFilters {...customProps} />,
|
|
74
|
+
renderOptions
|
|
75
|
+
);
|
|
76
|
+
expect(getByText(messages["search.save_filters"])).toBeInTheDocument();
|
|
46
77
|
});
|
|
47
78
|
|
|
48
79
|
it("does not render userFilters if they are empty", () => {
|
|
49
|
-
const props = getProps();
|
|
50
80
|
const customProps = { ...props, userFilters: [] };
|
|
51
|
-
const
|
|
52
|
-
expect(
|
|
81
|
+
const { container } = render(<SelectedFilters {...customProps} />);
|
|
82
|
+
expect(container.getElementsByClassName("userFilter")).toHaveLength(0);
|
|
53
83
|
});
|
|
54
84
|
|
|
55
85
|
it("renders userFilters if they are defined", () => {
|
|
56
|
-
const props = getProps();
|
|
57
86
|
const customProps = { ...props, userFilters: [{ country: ["a"] }] };
|
|
58
|
-
const
|
|
59
|
-
expect(
|
|
87
|
+
const { container } = render(<SelectedFilters {...customProps} />);
|
|
88
|
+
expect(container.getElementsByClassName("userFilter")).toHaveLength(1);
|
|
60
89
|
});
|
|
61
90
|
|
|
62
91
|
it("renders FilterMultilevelDropdown if filter is of type domain", () => {
|
|
63
|
-
const props = getProps();
|
|
64
92
|
const customProps = {
|
|
65
93
|
...props,
|
|
66
94
|
selectedFilters: ["taxonomy"],
|
|
@@ -68,20 +96,49 @@ describe("<SelectedFilters/>", () => {
|
|
|
68
96
|
filterTypes: { taxonomy: "domain" },
|
|
69
97
|
selectedFilterValues: [{ id: 1, name: "foo", level: 0 }],
|
|
70
98
|
};
|
|
71
|
-
const
|
|
72
|
-
expect(
|
|
99
|
+
const { container } = render(<SelectedFilters {...customProps} />);
|
|
100
|
+
expect(
|
|
101
|
+
container.querySelector('[name="filterMultilevelDropdown"]')
|
|
102
|
+
).not.toBeNull();
|
|
73
103
|
});
|
|
74
104
|
|
|
75
105
|
it("renders HierarchyFilterDropdown if filter is of type hierarchy", () => {
|
|
76
|
-
const props = getProps();
|
|
77
106
|
const customProps = {
|
|
78
107
|
...props,
|
|
79
108
|
selectedFilters: ["hierarchy_field"],
|
|
80
109
|
selectedFilter: "hierarchy_field",
|
|
81
110
|
filterTypes: { hierarchy_field: "hierarchy" },
|
|
82
|
-
selectedFilterValues: [
|
|
111
|
+
selectedFilterValues: [],
|
|
112
|
+
};
|
|
113
|
+
const { container } = render(<SelectedFilters {...customProps} />);
|
|
114
|
+
expect(
|
|
115
|
+
container.querySelector('[name="hierarchyFilterDropdown"]')
|
|
116
|
+
).not.toBeNull();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("renders SearchFilterDropdown if filter is of type search", () => {
|
|
120
|
+
const customProps = {
|
|
121
|
+
...props,
|
|
122
|
+
selectedFilters: ["search_filter"],
|
|
123
|
+
selectedFilter: "search_filter",
|
|
124
|
+
filterTypes: { search_filter: "search" },
|
|
125
|
+
selectedFilterValues: [],
|
|
126
|
+
searchFiltersPropsMapping: {
|
|
127
|
+
search_filter: {
|
|
128
|
+
query: "query test",
|
|
129
|
+
searchCallback: jest.fn(),
|
|
130
|
+
options: [],
|
|
131
|
+
placeholder: "test",
|
|
132
|
+
FilterDataLoader: DummyLoader,
|
|
133
|
+
loaderProps: { pageSize: 50 },
|
|
134
|
+
FilterItem: DummyFilerItem,
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
searchFilterDispacher: jest.fn(),
|
|
83
138
|
};
|
|
84
|
-
const
|
|
85
|
-
expect(
|
|
139
|
+
const { container } = render(<SelectedFilters {...customProps} />);
|
|
140
|
+
expect(
|
|
141
|
+
container.querySelector('[name="searchFilterDropdown"]')
|
|
142
|
+
).not.toBeNull();
|
|
86
143
|
});
|
|
87
144
|
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@truedat/test/render";
|
|
3
|
+
import { within } from "@testing-library/react";
|
|
4
|
+
import userEvent from "@testing-library/user-event";
|
|
5
|
+
import { StructureFilterItem } from "../StructureFilterItem";
|
|
6
|
+
|
|
7
|
+
const props = {
|
|
8
|
+
active: true,
|
|
9
|
+
filter: "foo",
|
|
10
|
+
toggleFilterValue: jest.fn(),
|
|
11
|
+
option: { id: 123, name: "bar", path: ["one", "two", "three"], type: "baz" },
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
describe("<StructureFilterItem/>", () => {
|
|
15
|
+
it("matches the latest snapshot", () => {
|
|
16
|
+
const { container } = render(<StructureFilterItem {...props} />);
|
|
17
|
+
expect(container).toMatchSnapshot();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("dispatches toggleFilterValue on click", () => {
|
|
21
|
+
const { container } = render(<StructureFilterItem {...props} />);
|
|
22
|
+
expect(props.toggleFilterValue.mock.calls.length).toBe(0);
|
|
23
|
+
userEvent.click(within(container).getByText(props.option.name));
|
|
24
|
+
expect(props.toggleFilterValue.mock.calls.length).toBe(1);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -5,6 +5,7 @@ exports[`<HierarchyFilterDropdown /> matches the latest snapshot 1`] = `
|
|
|
5
5
|
<div
|
|
6
6
|
aria-expanded="true"
|
|
7
7
|
class="ui active visible floating item dropdown"
|
|
8
|
+
name="hierarchyFilterDropdown"
|
|
8
9
|
role="listbox"
|
|
9
10
|
tabindex="0"
|
|
10
11
|
>
|
|
@@ -68,6 +69,7 @@ exports[`<HierarchyFilterDropdown /> matches the latest snapshot for empty optio
|
|
|
68
69
|
<div
|
|
69
70
|
aria-expanded="false"
|
|
70
71
|
class="ui floating item dropdown"
|
|
72
|
+
name="hierarchyFilterDropdown"
|
|
71
73
|
role="listbox"
|
|
72
74
|
tabindex="0"
|
|
73
75
|
>
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`<SearchFilterDropDown/> matches the latest snapshot folded 1`] = `
|
|
4
|
+
<div>
|
|
5
|
+
<div
|
|
6
|
+
aria-expanded="false"
|
|
7
|
+
class="ui floating item scrolling dropdown"
|
|
8
|
+
name="searchFilterDropdown"
|
|
9
|
+
role="listbox"
|
|
10
|
+
tabindex="0"
|
|
11
|
+
>
|
|
12
|
+
<div
|
|
13
|
+
class="ui label"
|
|
14
|
+
>
|
|
15
|
+
foo_filter
|
|
16
|
+
<i
|
|
17
|
+
aria-hidden="true"
|
|
18
|
+
class="delete icon"
|
|
19
|
+
/>
|
|
20
|
+
</div>
|
|
21
|
+
<div
|
|
22
|
+
class="menu transition dimmable"
|
|
23
|
+
>
|
|
24
|
+
<div />
|
|
25
|
+
<div
|
|
26
|
+
class="ui left icon input"
|
|
27
|
+
>
|
|
28
|
+
<input
|
|
29
|
+
placeholder="search dropdown"
|
|
30
|
+
type="text"
|
|
31
|
+
value="foo_query"
|
|
32
|
+
/>
|
|
33
|
+
<i
|
|
34
|
+
aria-hidden="true"
|
|
35
|
+
class="search icon"
|
|
36
|
+
/>
|
|
37
|
+
</div>
|
|
38
|
+
<div
|
|
39
|
+
class="divider"
|
|
40
|
+
/>
|
|
41
|
+
<div
|
|
42
|
+
aria-checked="false"
|
|
43
|
+
class="item"
|
|
44
|
+
role="option"
|
|
45
|
+
>
|
|
46
|
+
<div
|
|
47
|
+
class="ui vertical segment"
|
|
48
|
+
>
|
|
49
|
+
<i
|
|
50
|
+
aria-hidden="true"
|
|
51
|
+
class="square outline icon"
|
|
52
|
+
/>
|
|
53
|
+
bar_option
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
<div
|
|
57
|
+
aria-checked="false"
|
|
58
|
+
class="item"
|
|
59
|
+
role="option"
|
|
60
|
+
>
|
|
61
|
+
<div
|
|
62
|
+
class="ui vertical segment"
|
|
63
|
+
>
|
|
64
|
+
<i
|
|
65
|
+
aria-hidden="true"
|
|
66
|
+
class="square outline icon"
|
|
67
|
+
/>
|
|
68
|
+
baz_option
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
`;
|
|
75
|
+
|
|
76
|
+
exports[`<SearchFilterDropDown/> matches the latest snapshot unfolded 1`] = `
|
|
77
|
+
<div>
|
|
78
|
+
<div
|
|
79
|
+
aria-expanded="true"
|
|
80
|
+
class="ui active visible floating item scrolling dropdown"
|
|
81
|
+
name="searchFilterDropdown"
|
|
82
|
+
role="listbox"
|
|
83
|
+
tabindex="0"
|
|
84
|
+
>
|
|
85
|
+
<div
|
|
86
|
+
class="ui label"
|
|
87
|
+
>
|
|
88
|
+
foo_filter
|
|
89
|
+
<i
|
|
90
|
+
aria-hidden="true"
|
|
91
|
+
class="delete icon"
|
|
92
|
+
/>
|
|
93
|
+
</div>
|
|
94
|
+
<div
|
|
95
|
+
class="menu transition dimmable visible"
|
|
96
|
+
>
|
|
97
|
+
<div />
|
|
98
|
+
<div
|
|
99
|
+
class="ui left icon input"
|
|
100
|
+
>
|
|
101
|
+
<input
|
|
102
|
+
placeholder="search dropdown"
|
|
103
|
+
type="text"
|
|
104
|
+
value="foo_query"
|
|
105
|
+
/>
|
|
106
|
+
<i
|
|
107
|
+
aria-hidden="true"
|
|
108
|
+
class="search icon"
|
|
109
|
+
/>
|
|
110
|
+
</div>
|
|
111
|
+
<div
|
|
112
|
+
class="divider"
|
|
113
|
+
/>
|
|
114
|
+
<div
|
|
115
|
+
aria-checked="false"
|
|
116
|
+
class="item"
|
|
117
|
+
role="option"
|
|
118
|
+
>
|
|
119
|
+
<div
|
|
120
|
+
class="ui vertical segment"
|
|
121
|
+
>
|
|
122
|
+
<i
|
|
123
|
+
aria-hidden="true"
|
|
124
|
+
class="square outline icon"
|
|
125
|
+
/>
|
|
126
|
+
bar_option
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
<div
|
|
130
|
+
aria-checked="false"
|
|
131
|
+
class="item"
|
|
132
|
+
role="option"
|
|
133
|
+
>
|
|
134
|
+
<div
|
|
135
|
+
class="ui vertical segment"
|
|
136
|
+
>
|
|
137
|
+
<i
|
|
138
|
+
aria-hidden="true"
|
|
139
|
+
class="square outline icon"
|
|
140
|
+
/>
|
|
141
|
+
baz_option
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
`;
|
|
@@ -1,63 +1,111 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
3
|
exports[`<SelectedFilters/> matches the latest snapshot 1`] = `
|
|
4
|
-
<
|
|
5
|
-
<UserFilters
|
|
6
|
-
resetFilters={[MockFunction]}
|
|
7
|
-
selectedUserFilter={null}
|
|
8
|
-
userFilters={
|
|
9
|
-
[
|
|
10
|
-
"uf1",
|
|
11
|
-
"uf2",
|
|
12
|
-
]
|
|
13
|
-
}
|
|
14
|
-
/>
|
|
4
|
+
<div>
|
|
15
5
|
<div
|
|
16
|
-
|
|
6
|
+
class="selectedFilters"
|
|
17
7
|
>
|
|
18
8
|
<div
|
|
19
|
-
|
|
9
|
+
class="ui circular label"
|
|
20
10
|
>
|
|
21
|
-
<
|
|
22
|
-
|
|
11
|
+
<span
|
|
12
|
+
class="userFilter"
|
|
13
|
+
/>
|
|
14
|
+
<i
|
|
15
|
+
aria-hidden="true"
|
|
16
|
+
class="grey trash alternate outline small icon selectable"
|
|
23
17
|
/>
|
|
24
18
|
</div>
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
19
|
+
<div
|
|
20
|
+
class="ui circular label"
|
|
21
|
+
>
|
|
22
|
+
<span
|
|
23
|
+
class="userFilter"
|
|
24
|
+
/>
|
|
25
|
+
<i
|
|
26
|
+
aria-hidden="true"
|
|
27
|
+
class="grey trash alternate outline small icon selectable"
|
|
28
|
+
/>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
<div
|
|
32
|
+
class="selectedFilters"
|
|
33
|
+
>
|
|
34
|
+
<div
|
|
35
|
+
class="appliedFilters"
|
|
36
|
+
>
|
|
37
|
+
Filters:
|
|
38
|
+
</div>
|
|
39
|
+
<div
|
|
40
|
+
aria-expanded="true"
|
|
41
|
+
class="ui active visible floating item scrolling dropdown"
|
|
42
|
+
role="listbox"
|
|
43
|
+
tabindex="0"
|
|
44
|
+
>
|
|
45
|
+
<div
|
|
46
|
+
class="ui label"
|
|
47
|
+
>
|
|
48
|
+
foo
|
|
49
|
+
<i
|
|
50
|
+
aria-hidden="true"
|
|
51
|
+
class="delete icon"
|
|
52
|
+
/>
|
|
53
|
+
</div>
|
|
54
|
+
<div
|
|
55
|
+
class="menu transition dimmable visible"
|
|
56
|
+
>
|
|
57
|
+
<div
|
|
58
|
+
aria-checked="false"
|
|
59
|
+
class="item"
|
|
60
|
+
role="option"
|
|
61
|
+
>
|
|
62
|
+
<i
|
|
63
|
+
aria-hidden="true"
|
|
64
|
+
class="square outline icon"
|
|
65
|
+
/>
|
|
66
|
+
<i>
|
|
67
|
+
Empty
|
|
68
|
+
</i>
|
|
69
|
+
</div>
|
|
70
|
+
<div
|
|
71
|
+
aria-checked="false"
|
|
72
|
+
class="item"
|
|
73
|
+
role="option"
|
|
74
|
+
>
|
|
75
|
+
<i
|
|
76
|
+
aria-hidden="true"
|
|
77
|
+
class="square outline icon"
|
|
78
|
+
/>
|
|
79
|
+
<i>
|
|
80
|
+
Empty
|
|
81
|
+
</i>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
<div
|
|
86
|
+
aria-expanded="false"
|
|
87
|
+
class="ui floating item scrolling dropdown"
|
|
88
|
+
role="listbox"
|
|
89
|
+
tabindex="0"
|
|
53
90
|
>
|
|
54
|
-
<
|
|
55
|
-
|
|
91
|
+
<div
|
|
92
|
+
class="ui label"
|
|
93
|
+
>
|
|
94
|
+
bar
|
|
95
|
+
<i
|
|
96
|
+
aria-hidden="true"
|
|
97
|
+
class="delete icon"
|
|
98
|
+
/>
|
|
99
|
+
</div>
|
|
100
|
+
<div
|
|
101
|
+
class="menu transition dimmable"
|
|
56
102
|
/>
|
|
103
|
+
</div>
|
|
104
|
+
<a
|
|
105
|
+
class="resetFilters"
|
|
106
|
+
>
|
|
107
|
+
Clear filters
|
|
57
108
|
</a>
|
|
58
|
-
<ModalSaveFilter
|
|
59
|
-
saveFilters={[MockFunction]}
|
|
60
|
-
/>
|
|
61
109
|
</div>
|
|
62
|
-
</
|
|
110
|
+
</div>
|
|
63
111
|
`;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`<StructureFilterItem/> matches the latest snapshot 1`] = `
|
|
4
|
+
<div>
|
|
5
|
+
<div
|
|
6
|
+
aria-checked="true"
|
|
7
|
+
class="active item"
|
|
8
|
+
role="option"
|
|
9
|
+
>
|
|
10
|
+
<div
|
|
11
|
+
class="ui vertical segment"
|
|
12
|
+
>
|
|
13
|
+
<i
|
|
14
|
+
aria-hidden="true"
|
|
15
|
+
class="check square outline icon"
|
|
16
|
+
/>
|
|
17
|
+
bar
|
|
18
|
+
<small>
|
|
19
|
+
- (baz)
|
|
20
|
+
</small>
|
|
21
|
+
<br />
|
|
22
|
+
<small>
|
|
23
|
+
one > two > three
|
|
24
|
+
</small>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
`;
|
package/src/components/index.js
CHANGED
|
@@ -39,11 +39,13 @@ import RichTextEditor from "./RichTextEditor";
|
|
|
39
39
|
import RouteListener from "./RouteListener";
|
|
40
40
|
import SafeLink from "./SafeLink";
|
|
41
41
|
import ScrollToTop from "./ScrollToTop";
|
|
42
|
+
import SearchFilterDropdown from "./SearchFilterDropdown";
|
|
42
43
|
import SearchInput from "./SearchInput";
|
|
43
44
|
import SearchMenu from "./SearchMenu";
|
|
44
45
|
import SelectedFilters from "./SelectedFilters";
|
|
45
46
|
import SidebarToggle from "./SidebarToggle";
|
|
46
47
|
import SideMenu from "./SideMenu";
|
|
48
|
+
import StructureFilterItem from "./StructureFilterItem";
|
|
47
49
|
import Submenu from "./Submenu";
|
|
48
50
|
import TaxonomyMenu from "./TaxonomyMenu";
|
|
49
51
|
import TemplateSelector from "./TemplateSelector";
|
|
@@ -93,11 +95,13 @@ export {
|
|
|
93
95
|
RouteListener,
|
|
94
96
|
SafeLink,
|
|
95
97
|
ScrollToTop,
|
|
98
|
+
SearchFilterDropdown,
|
|
96
99
|
SearchInput,
|
|
97
100
|
SearchMenu,
|
|
98
101
|
SelectedFilters,
|
|
99
102
|
SidebarToggle,
|
|
100
103
|
SideMenu,
|
|
104
|
+
StructureFilterItem,
|
|
101
105
|
Submenu,
|
|
102
106
|
TaxonomyMenu,
|
|
103
107
|
TemplateSelector,
|