@truedat/core 6.3.2 → 6.3.4
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 +3 -3
- package/src/api.js +3 -0
- package/src/components/FilterItem.js +5 -0
- package/src/components/ModalSaveFilter.js +1 -1
- package/src/components/SearchFilterDropdown.js +1 -1
- package/src/components/UserFilter.js +103 -0
- package/src/hooks/useUserFilters.js +39 -0
- package/src/search/FilterDropdown.js +0 -1
- package/src/search/FilterMultilevelDropdown.js +0 -1
- package/src/search/HierarchyFilterDropdown.js +4 -2
- package/src/search/SearchContext.js +21 -6
- package/src/search/SearchSelectedFilters.js +44 -2
- package/src/search/SearchWidget.js +3 -4
- package/src/search/UserFilter.js +103 -0
- package/src/search/UserFilters.js +136 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/core",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.4",
|
|
4
4
|
"description": "Truedat Web Core",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"jsnext:main": "src/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@testing-library/react": "^12.0.0",
|
|
37
37
|
"@testing-library/react-hooks": "^8.0.1",
|
|
38
38
|
"@testing-library/user-event": "^13.2.1",
|
|
39
|
-
"@truedat/test": "6.3.
|
|
39
|
+
"@truedat/test": "6.3.4",
|
|
40
40
|
"babel-jest": "^28.1.0",
|
|
41
41
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
|
42
42
|
"babel-plugin-lodash": "^3.3.4",
|
|
@@ -118,5 +118,5 @@
|
|
|
118
118
|
"react-dom": ">= 16.8.6 < 17",
|
|
119
119
|
"semantic-ui-react": ">= 2.0.3 < 2.2"
|
|
120
120
|
},
|
|
121
|
-
"gitHead": "
|
|
121
|
+
"gitHead": "e7d4c50cf2989fde79b5d1a46c83e6c6ce34f54d"
|
|
122
122
|
}
|
package/src/api.js
CHANGED
|
@@ -6,5 +6,8 @@ export const API_MESSAGE = "/api/messages/:id";
|
|
|
6
6
|
export const API_MESSAGES = "/api/messages";
|
|
7
7
|
export const API_REINDEX_GRANTS = "/api/grants/search/reindex_all";
|
|
8
8
|
export const API_REINDEX_STRUCTURES = "/api/data_structures/search/reindex_all";
|
|
9
|
+
export const API_USER_FILTERS = "/api/:type";
|
|
10
|
+
export const API_USER_FILTER = "/api/:type/:id";
|
|
11
|
+
export const API_GET_USER_FILTERS = "/api/:type/user/me";
|
|
9
12
|
export const API_ACL_ENTRY = "/api/acl_entries/:id";
|
|
10
13
|
export const API_ACL_RESOURCE_ENTRIES = "/api/acl_entries/:type/:id";
|
|
@@ -16,6 +16,11 @@ const FilterItemText = ({ filterName, text }) =>
|
|
|
16
16
|
</i>
|
|
17
17
|
);
|
|
18
18
|
|
|
19
|
+
FilterItemText.propTypes = {
|
|
20
|
+
filterName: PropTypes.string,
|
|
21
|
+
text: PropTypes.string,
|
|
22
|
+
};
|
|
23
|
+
|
|
19
24
|
const preventDefault = (e, callback) => {
|
|
20
25
|
e && e.preventDefault();
|
|
21
26
|
e && e.stopPropagation();
|
|
@@ -145,7 +145,7 @@ SearchFilterDropdown.propTypes = {
|
|
|
145
145
|
filter: PropTypes.string,
|
|
146
146
|
FilterDataLoader: PropTypes.node,
|
|
147
147
|
loaderProps: PropTypes.object,
|
|
148
|
-
FilterItem: PropTypes.
|
|
148
|
+
FilterItem: PropTypes.func,
|
|
149
149
|
openFilter: PropTypes.func,
|
|
150
150
|
removeFilter: PropTypes.func,
|
|
151
151
|
toggleFilterValue: PropTypes.func,
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { Label, Icon } from "semantic-ui-react";
|
|
5
|
+
import { FormattedMessage } from "react-intl";
|
|
6
|
+
import { useAuthorized } from "@truedat/core/hooks";
|
|
7
|
+
import { useSearchContext } from "@truedat/core/search/SearchContext";
|
|
8
|
+
import { useUserFiltersDelete } from "../hooks/useUserFilters";
|
|
9
|
+
import { ConfirmModal } from "./ConfirmModal";
|
|
10
|
+
|
|
11
|
+
export const UserFilter = ({
|
|
12
|
+
userFilter,
|
|
13
|
+
disabled,
|
|
14
|
+
selectedUserFilter,
|
|
15
|
+
mutate,
|
|
16
|
+
setSelectedUserFilter,
|
|
17
|
+
}) => {
|
|
18
|
+
const authorized = useAuthorized();
|
|
19
|
+
const { userFiltersType, resetFilters, setAllActiveFilters } =
|
|
20
|
+
useSearchContext();
|
|
21
|
+
|
|
22
|
+
const isGlobal = _.prop("is_global")(userFilter);
|
|
23
|
+
|
|
24
|
+
const { trigger: deleteUserFilter } = useUserFiltersDelete(
|
|
25
|
+
userFilter.id,
|
|
26
|
+
userFiltersType
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const handleDelete = () => {
|
|
30
|
+
deleteUserFilter().then(() => {
|
|
31
|
+
mutate();
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Label
|
|
37
|
+
basic={selectedUserFilter == userFilter.name ? false : true}
|
|
38
|
+
circular
|
|
39
|
+
className={isGlobal ? "global" : null}
|
|
40
|
+
>
|
|
41
|
+
<span
|
|
42
|
+
onClick={
|
|
43
|
+
disabled
|
|
44
|
+
? null
|
|
45
|
+
: (e) => {
|
|
46
|
+
e.preventDefault();
|
|
47
|
+
e.stopPropagation();
|
|
48
|
+
if (selectedUserFilter == userFilter.name) {
|
|
49
|
+
resetFilters();
|
|
50
|
+
setSelectedUserFilter("");
|
|
51
|
+
} else {
|
|
52
|
+
setAllActiveFilters(userFilter.filters);
|
|
53
|
+
setSelectedUserFilter(userFilter.name);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
className="userFilter"
|
|
58
|
+
>
|
|
59
|
+
{userFilter.name}
|
|
60
|
+
</span>
|
|
61
|
+
|
|
62
|
+
{!isGlobal || authorized ? (
|
|
63
|
+
<ConfirmModal
|
|
64
|
+
icon="trash"
|
|
65
|
+
trigger={
|
|
66
|
+
<Icon
|
|
67
|
+
className="selectable"
|
|
68
|
+
color="grey"
|
|
69
|
+
size="small"
|
|
70
|
+
name="trash alternate outline"
|
|
71
|
+
/>
|
|
72
|
+
}
|
|
73
|
+
header={
|
|
74
|
+
<FormattedMessage id="search.filters.actions.delete.confirmation.header" />
|
|
75
|
+
}
|
|
76
|
+
content={
|
|
77
|
+
<FormattedMessage
|
|
78
|
+
id="search.filters.actions.delete.confirmation.content"
|
|
79
|
+
values={{
|
|
80
|
+
name: (
|
|
81
|
+
<b>
|
|
82
|
+
<i>{userFilter.name}</i>
|
|
83
|
+
</b>
|
|
84
|
+
),
|
|
85
|
+
}}
|
|
86
|
+
/>
|
|
87
|
+
}
|
|
88
|
+
onConfirm={() => handleDelete()}
|
|
89
|
+
/>
|
|
90
|
+
) : null}
|
|
91
|
+
</Label>
|
|
92
|
+
);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
UserFilter.propTypes = {
|
|
96
|
+
userFilter: PropTypes.object,
|
|
97
|
+
disabled: PropTypes.bool,
|
|
98
|
+
mutate: PropTypes.func,
|
|
99
|
+
selectedUserFilter: PropTypes.func,
|
|
100
|
+
resetFilters: PropTypes.func,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export default UserFilter;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import { compile } from "path-to-regexp";
|
|
3
|
+
import useSWR from "swr";
|
|
4
|
+
import useSWRMutations from "swr/mutation";
|
|
5
|
+
import { accentInsensitivePathOrder } from "@truedat/core/services/sort";
|
|
6
|
+
import {
|
|
7
|
+
apiJson,
|
|
8
|
+
apiJsonDelete,
|
|
9
|
+
apiJsonPost,
|
|
10
|
+
} from "@truedat/core/services/api";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
API_USER_FILTERS,
|
|
14
|
+
API_USER_FILTER,
|
|
15
|
+
API_GET_USER_FILTERS,
|
|
16
|
+
} from "../api";
|
|
17
|
+
|
|
18
|
+
export const useUserFilters = (type, scope) => {
|
|
19
|
+
const url = _.flow(
|
|
20
|
+
() => compile(API_GET_USER_FILTERS)({ type }),
|
|
21
|
+
_.concat(_.isUndefined(scope) ? "" : `?scope=${scope}`),
|
|
22
|
+
_.compact,
|
|
23
|
+
_.join("")
|
|
24
|
+
)("");
|
|
25
|
+
const { data, error, mutate } = useSWR(url, apiJson);
|
|
26
|
+
const userFilters = data?.data?.data;
|
|
27
|
+
_.sortBy(accentInsensitivePathOrder("name"))(userFilters);
|
|
28
|
+
return { userFilters, error, loading: !error && !data, mutate };
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const useUserFiltersCreate = (type) => {
|
|
32
|
+
const url = compile(API_USER_FILTERS)({ type });
|
|
33
|
+
return useSWRMutations(url, (url, { arg }) => apiJsonPost(url, arg));
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const useUserFiltersDelete = (id, type) => {
|
|
37
|
+
const url = compile(API_USER_FILTER)({ id, type });
|
|
38
|
+
return useSWRMutations(url, (url, { arg }) => apiJsonDelete(url, arg));
|
|
39
|
+
};
|
|
@@ -13,6 +13,7 @@ const PopulatedHierarchyFilterDropdown = () => {
|
|
|
13
13
|
|
|
14
14
|
const { filter, options, toggleFilterValue, activeFilterSelectedValues } =
|
|
15
15
|
context;
|
|
16
|
+
|
|
16
17
|
const hierarchyId = _.flow(
|
|
17
18
|
_.reject((item) => _.values(item).includes(undefined)),
|
|
18
19
|
_.first,
|
|
@@ -57,11 +58,13 @@ const PopulatedHierarchyFilterDropdown = () => {
|
|
|
57
58
|
const descendentKeys = _.map("key")(descendents);
|
|
58
59
|
return [key, ...descendentKeys];
|
|
59
60
|
};
|
|
61
|
+
|
|
60
62
|
const newValue = _.flow(
|
|
61
63
|
_.flatMap(getChildrenKeys),
|
|
62
64
|
_.uniq,
|
|
63
65
|
_.reject(_.isNil)
|
|
64
66
|
)(value);
|
|
67
|
+
|
|
65
68
|
toggleFilterValue({ filter, value: newValue });
|
|
66
69
|
};
|
|
67
70
|
|
|
@@ -72,8 +75,8 @@ const PopulatedHierarchyFilterDropdown = () => {
|
|
|
72
75
|
name: "hierarchyFilterDropdown",
|
|
73
76
|
filter,
|
|
74
77
|
options: filteredOptions,
|
|
75
|
-
activeFilterSelectedValues: idActiveValues,
|
|
76
78
|
toggleFilterValue: handleToggleFilterValue,
|
|
79
|
+
activeFilterSelectedValues: idActiveValues,
|
|
77
80
|
}}
|
|
78
81
|
key={filter}
|
|
79
82
|
>
|
|
@@ -84,7 +87,6 @@ const PopulatedHierarchyFilterDropdown = () => {
|
|
|
84
87
|
|
|
85
88
|
const HierarchyFilterDropdown = () => {
|
|
86
89
|
const { options } = useSearchContext();
|
|
87
|
-
|
|
88
90
|
return _.isEmpty(options) ? (
|
|
89
91
|
<FilterMultilevelDropdown />
|
|
90
92
|
) : (
|
|
@@ -24,6 +24,10 @@ export const SearchContextProvider = (props) => {
|
|
|
24
24
|
const useSearch = _.prop("useSearch")(props);
|
|
25
25
|
const useFilters = _.prop("useFilters")(props);
|
|
26
26
|
const pageSize = _.propOr(20, "pageSize")(props);
|
|
27
|
+
const userFiltersType = _.prop("userFiltersType")(props);
|
|
28
|
+
const userFilterScope = _.prop("userFilterScope")(props);
|
|
29
|
+
const omitFilters = _.propOr([], "omitFilters")(props);
|
|
30
|
+
const translations = _.propOr(() => ({}), "translations")(props);
|
|
27
31
|
|
|
28
32
|
const { formatMessage } = useIntl();
|
|
29
33
|
|
|
@@ -37,6 +41,7 @@ export const SearchContextProvider = (props) => {
|
|
|
37
41
|
const [allActiveFilters, setAllActiveFilters] = useState({});
|
|
38
42
|
const [hiddenFilters, setHiddenFilters] = useState({});
|
|
39
43
|
|
|
44
|
+
const [filterParams, setFilterParams] = useState({});
|
|
40
45
|
const [sortColumn, setSortColumn] = useState(initialSortColumn);
|
|
41
46
|
const [sortDirection, setSortDirection] = useState(initialSortDirection);
|
|
42
47
|
const [page, setPage] = useState(1);
|
|
@@ -95,16 +100,13 @@ export const SearchContextProvider = (props) => {
|
|
|
95
100
|
|
|
96
101
|
const filters = _.flow(
|
|
97
102
|
_.propOr({}, "data"),
|
|
103
|
+
_.omit(omitFilters),
|
|
98
104
|
_.omitBy(_.flow(_.propOr([], "values"), (values) => _.size(values) < 2))
|
|
99
105
|
)(filtersPayload);
|
|
100
106
|
|
|
101
107
|
const availableFilters = _.flow(_.keys, _.without(selectedFilters))(filters);
|
|
102
108
|
const filterTypes = _.mapValues("type")(filters);
|
|
103
109
|
|
|
104
|
-
const translations = (formatMessage) => ({
|
|
105
|
-
"status.raw": (v) => formatMessage({ id: v, defaultMessage: v }),
|
|
106
|
-
});
|
|
107
|
-
|
|
108
110
|
const activeFilterValues = _.flow(
|
|
109
111
|
_.propOr({ values: [] }, activeFilterName),
|
|
110
112
|
({ values, type }) => ({
|
|
@@ -152,7 +154,9 @@ export const SearchContextProvider = (props) => {
|
|
|
152
154
|
: null,
|
|
153
155
|
[sortColumn, sortDirection]
|
|
154
156
|
);
|
|
157
|
+
|
|
155
158
|
const { trigger: triggerFilters } = useFilters();
|
|
159
|
+
|
|
156
160
|
useEffect(() => {
|
|
157
161
|
setLoadingFilters(true);
|
|
158
162
|
|
|
@@ -164,9 +168,10 @@ export const SearchContextProvider = (props) => {
|
|
|
164
168
|
setFiltersPayload(data);
|
|
165
169
|
setLoadingFilters(false);
|
|
166
170
|
});
|
|
167
|
-
}, [query, filterMust
|
|
171
|
+
}, [query, filterMust]);
|
|
168
172
|
|
|
169
173
|
const { trigger: triggerSearch } = useSearch();
|
|
174
|
+
|
|
170
175
|
useEffect(() => {
|
|
171
176
|
setLoading(true);
|
|
172
177
|
|
|
@@ -177,12 +182,14 @@ export const SearchContextProvider = (props) => {
|
|
|
177
182
|
page: page - 1,
|
|
178
183
|
size,
|
|
179
184
|
};
|
|
185
|
+
setFilterParams(filterParam);
|
|
186
|
+
|
|
180
187
|
triggerSearch(filterParam).then(({ data, headers }) => {
|
|
181
188
|
setSearchData(data);
|
|
182
189
|
setCountData(headers);
|
|
183
190
|
setLoading(false);
|
|
184
191
|
});
|
|
185
|
-
}, [query, searchMust, sort,
|
|
192
|
+
}, [query, searchMust, sort, defaultFilters, page, size]);
|
|
186
193
|
|
|
187
194
|
const context = {
|
|
188
195
|
disabled: false,
|
|
@@ -209,6 +216,9 @@ export const SearchContextProvider = (props) => {
|
|
|
209
216
|
toggleHiddenFilterValue,
|
|
210
217
|
searchMust,
|
|
211
218
|
setQuery,
|
|
219
|
+
setAllActiveFilters,
|
|
220
|
+
allActiveFilters,
|
|
221
|
+
filters,
|
|
212
222
|
|
|
213
223
|
searchData,
|
|
214
224
|
loading,
|
|
@@ -222,6 +232,11 @@ export const SearchContextProvider = (props) => {
|
|
|
222
232
|
count,
|
|
223
233
|
page,
|
|
224
234
|
size,
|
|
235
|
+
sort,
|
|
236
|
+
filterParams,
|
|
237
|
+
|
|
238
|
+
userFiltersType,
|
|
239
|
+
userFilterScope,
|
|
225
240
|
};
|
|
226
241
|
|
|
227
242
|
return (
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
|
-
import React from "react";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
3
|
import { FormattedMessage } from "react-intl";
|
|
4
|
+
import { useUserFilters, useUserFiltersCreate } from "../hooks/useUserFilters";
|
|
5
|
+
import ModalSaveFilter from "../components/ModalSaveFilter";
|
|
6
|
+
import UserFilters from "./UserFilters";
|
|
4
7
|
import FilterDropdown from "./FilterDropdown";
|
|
5
8
|
import FilterMultilevelDropdown from "./FilterMultilevelDropdown";
|
|
6
9
|
import HierarchyFilterDropdown from "./HierarchyFilterDropdown";
|
|
@@ -14,10 +17,37 @@ export default function SearchSelectedFilters() {
|
|
|
14
17
|
filterTypes,
|
|
15
18
|
activeFilterName,
|
|
16
19
|
activeFilterValues,
|
|
20
|
+
allActiveFilters,
|
|
21
|
+
userFiltersType,
|
|
22
|
+
userFilterScope,
|
|
17
23
|
} = context;
|
|
24
|
+
const [selectedUserFilter, setSelectedUserFilter] = useState();
|
|
25
|
+
const { trigger: saveFilters } = useUserFiltersCreate(userFiltersType);
|
|
26
|
+
const { userFilters, loading, mutate } = useUserFilters(
|
|
27
|
+
userFiltersType,
|
|
28
|
+
userFilterScope
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const handleSubmit = ({ filterName, filters, isGlobal }) => {
|
|
32
|
+
const requestData = {
|
|
33
|
+
user_search_filter: { name: filterName, filters, is_global: isGlobal },
|
|
34
|
+
};
|
|
35
|
+
saveFilters(requestData).then(() => {
|
|
36
|
+
mutate();
|
|
37
|
+
});
|
|
38
|
+
};
|
|
18
39
|
|
|
19
40
|
return (
|
|
20
41
|
<>
|
|
42
|
+
{!_.isEmpty(userFilters) ? (
|
|
43
|
+
<UserFilters
|
|
44
|
+
mutate={mutate}
|
|
45
|
+
userFilters={userFilters}
|
|
46
|
+
disabled={loading}
|
|
47
|
+
setSelectedUserFilter={setSelectedUserFilter}
|
|
48
|
+
selectedUserFilter={selectedUserFilter}
|
|
49
|
+
/>
|
|
50
|
+
) : null}
|
|
21
51
|
<div className="selectedFilters">
|
|
22
52
|
{_.isEmpty(selectedFilters) ? null : (
|
|
23
53
|
<>
|
|
@@ -29,6 +59,7 @@ export default function SearchSelectedFilters() {
|
|
|
29
59
|
const options = _.isEqual(filter, activeFilterName)
|
|
30
60
|
? activeFilterValues
|
|
31
61
|
: null;
|
|
62
|
+
|
|
32
63
|
return (
|
|
33
64
|
<SearchContext.Provider
|
|
34
65
|
value={{ ...context, filter, options }}
|
|
@@ -44,9 +75,20 @@ export default function SearchSelectedFilters() {
|
|
|
44
75
|
</SearchContext.Provider>
|
|
45
76
|
);
|
|
46
77
|
})}
|
|
47
|
-
<a
|
|
78
|
+
<a
|
|
79
|
+
className="resetFilters"
|
|
80
|
+
onClick={() => {
|
|
81
|
+
resetFilters();
|
|
82
|
+
setSelectedUserFilter("");
|
|
83
|
+
}}
|
|
84
|
+
>
|
|
48
85
|
<FormattedMessage id="search.clear_filters" />
|
|
49
86
|
</a>
|
|
87
|
+
<ModalSaveFilter
|
|
88
|
+
saveFilters={handleSubmit}
|
|
89
|
+
activeFilters={allActiveFilters}
|
|
90
|
+
scope={userFilterScope}
|
|
91
|
+
/>
|
|
50
92
|
</>
|
|
51
93
|
)}
|
|
52
94
|
</div>
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Input } from "semantic-ui-react";
|
|
3
3
|
import { useIntl } from "react-intl";
|
|
4
|
-
import SearchFilters from "
|
|
5
|
-
import SearchSelectedFilters from "
|
|
6
|
-
|
|
7
|
-
import { useSearchContext } from "@truedat/core/search/SearchContext";
|
|
4
|
+
import SearchFilters from "./SearchFilters";
|
|
5
|
+
import SearchSelectedFilters from "./SearchSelectedFilters";
|
|
6
|
+
import { useSearchContext } from "./SearchContext";
|
|
8
7
|
|
|
9
8
|
export default function SearchWidget() {
|
|
10
9
|
const { formatMessage } = useIntl();
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { Label, Icon } from "semantic-ui-react";
|
|
5
|
+
import { FormattedMessage } from "react-intl";
|
|
6
|
+
import { useAuthorized } from "@truedat/core/hooks";
|
|
7
|
+
import { useSearchContext } from "@truedat/core/search/SearchContext";
|
|
8
|
+
import { useUserFiltersDelete } from "../hooks/useUserFilters";
|
|
9
|
+
import { ConfirmModal } from "./ConfirmModal";
|
|
10
|
+
|
|
11
|
+
export const UserFilter = ({
|
|
12
|
+
userFilter,
|
|
13
|
+
disabled,
|
|
14
|
+
selectedUserFilter,
|
|
15
|
+
mutate,
|
|
16
|
+
setSelectedUserFilter,
|
|
17
|
+
}) => {
|
|
18
|
+
const authorized = useAuthorized();
|
|
19
|
+
const { userFiltersType, resetFilters, setAllActiveFilters } =
|
|
20
|
+
useSearchContext();
|
|
21
|
+
|
|
22
|
+
const isGlobal = _.prop("is_global")(userFilter);
|
|
23
|
+
|
|
24
|
+
const { trigger: deleteUserFilter } = useUserFiltersDelete(
|
|
25
|
+
userFilter.id,
|
|
26
|
+
userFiltersType
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const handleDelete = () => {
|
|
30
|
+
deleteUserFilter().then(() => {
|
|
31
|
+
mutate();
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Label
|
|
37
|
+
basic={selectedUserFilter == userFilter.name ? false : true}
|
|
38
|
+
circular
|
|
39
|
+
className={isGlobal ? "global" : null}
|
|
40
|
+
>
|
|
41
|
+
<span
|
|
42
|
+
onClick={
|
|
43
|
+
disabled
|
|
44
|
+
? null
|
|
45
|
+
: (e) => {
|
|
46
|
+
e.preventDefault();
|
|
47
|
+
e.stopPropagation();
|
|
48
|
+
if (selectedUserFilter == userFilter.name) {
|
|
49
|
+
resetFilters();
|
|
50
|
+
setSelectedUserFilter("");
|
|
51
|
+
} else {
|
|
52
|
+
setAllActiveFilters(userFilter.filters);
|
|
53
|
+
setSelectedUserFilter(userFilter.name);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
className="userFilter"
|
|
58
|
+
>
|
|
59
|
+
{userFilter.name}
|
|
60
|
+
</span>
|
|
61
|
+
|
|
62
|
+
{!isGlobal || authorized ? (
|
|
63
|
+
<ConfirmModal
|
|
64
|
+
icon="trash"
|
|
65
|
+
trigger={
|
|
66
|
+
<Icon
|
|
67
|
+
className="selectable"
|
|
68
|
+
color="grey"
|
|
69
|
+
size="small"
|
|
70
|
+
name="trash alternate outline"
|
|
71
|
+
/>
|
|
72
|
+
}
|
|
73
|
+
header={
|
|
74
|
+
<FormattedMessage id="search.filters.actions.delete.confirmation.header" />
|
|
75
|
+
}
|
|
76
|
+
content={
|
|
77
|
+
<FormattedMessage
|
|
78
|
+
id="search.filters.actions.delete.confirmation.content"
|
|
79
|
+
values={{
|
|
80
|
+
name: (
|
|
81
|
+
<b>
|
|
82
|
+
<i>{userFilter.name}</i>
|
|
83
|
+
</b>
|
|
84
|
+
),
|
|
85
|
+
}}
|
|
86
|
+
/>
|
|
87
|
+
}
|
|
88
|
+
onConfirm={() => handleDelete()}
|
|
89
|
+
/>
|
|
90
|
+
) : null}
|
|
91
|
+
</Label>
|
|
92
|
+
);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
UserFilter.propTypes = {
|
|
96
|
+
userFilter: PropTypes.object,
|
|
97
|
+
disabled: PropTypes.bool,
|
|
98
|
+
mutate: PropTypes.func,
|
|
99
|
+
selectedUserFilter: PropTypes.func,
|
|
100
|
+
resetFilters: PropTypes.func,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export default UserFilter;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { Label, Icon } from "semantic-ui-react";
|
|
5
|
+
import { FormattedMessage } from "react-intl";
|
|
6
|
+
import { useAuthorized } from "@truedat/core/hooks";
|
|
7
|
+
import { useSearchContext } from "@truedat/core/search/SearchContext";
|
|
8
|
+
import { useUserFiltersDelete } from "../hooks/useUserFilters";
|
|
9
|
+
import { ConfirmModal } from "../components/ConfirmModal";
|
|
10
|
+
|
|
11
|
+
export const DeleteModal = ({ userFilter, userFiltersType, mutate }) => {
|
|
12
|
+
const { trigger: deleteUserFilter } = useUserFiltersDelete(
|
|
13
|
+
userFilter.id,
|
|
14
|
+
userFiltersType
|
|
15
|
+
);
|
|
16
|
+
const handleDelete = () => {
|
|
17
|
+
deleteUserFilter().then(() => {
|
|
18
|
+
mutate();
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
return (
|
|
22
|
+
<ConfirmModal
|
|
23
|
+
icon="trash"
|
|
24
|
+
trigger={
|
|
25
|
+
<Icon
|
|
26
|
+
className="selectable"
|
|
27
|
+
color="grey"
|
|
28
|
+
size="small"
|
|
29
|
+
name="trash alternate outline"
|
|
30
|
+
/>
|
|
31
|
+
}
|
|
32
|
+
header={
|
|
33
|
+
<FormattedMessage id="search.filters.actions.delete.confirmation.header" />
|
|
34
|
+
}
|
|
35
|
+
content={
|
|
36
|
+
<FormattedMessage
|
|
37
|
+
id="search.filters.actions.delete.confirmation.content"
|
|
38
|
+
values={{
|
|
39
|
+
name: (
|
|
40
|
+
<b>
|
|
41
|
+
<i>{userFilter.name}</i>
|
|
42
|
+
</b>
|
|
43
|
+
),
|
|
44
|
+
}}
|
|
45
|
+
/>
|
|
46
|
+
}
|
|
47
|
+
onConfirm={() => {
|
|
48
|
+
handleDelete();
|
|
49
|
+
}}
|
|
50
|
+
/>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
DeleteModal.propTypes = {
|
|
55
|
+
userFilter: PropTypes.object,
|
|
56
|
+
userFiltersType: PropTypes.string,
|
|
57
|
+
mutate: PropTypes.func,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const UserFilters = ({
|
|
61
|
+
mutate,
|
|
62
|
+
userFilters,
|
|
63
|
+
disabled,
|
|
64
|
+
setSelectedUserFilter,
|
|
65
|
+
selectedUserFilter,
|
|
66
|
+
}) => {
|
|
67
|
+
const authorized = useAuthorized();
|
|
68
|
+
const { userFiltersType, resetFilters, setAllActiveFilters } =
|
|
69
|
+
useSearchContext();
|
|
70
|
+
|
|
71
|
+
const sortedUserFilters = _.orderBy(
|
|
72
|
+
["is_global", "id"],
|
|
73
|
+
["desc", "asc"]
|
|
74
|
+
)(userFilters);
|
|
75
|
+
|
|
76
|
+
return _.isEmpty(userFilters) ? null : (
|
|
77
|
+
<div className="selectedFilters">
|
|
78
|
+
{sortedUserFilters.map((userFilter, key) => {
|
|
79
|
+
const isGlobal = _.prop("is_global")(userFilter);
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<Label
|
|
83
|
+
basic={selectedUserFilter == userFilter.name ? false : true}
|
|
84
|
+
circular
|
|
85
|
+
className={isGlobal ? "global" : null}
|
|
86
|
+
key={key}
|
|
87
|
+
>
|
|
88
|
+
<span
|
|
89
|
+
onClick={
|
|
90
|
+
disabled
|
|
91
|
+
? null
|
|
92
|
+
: (e) => {
|
|
93
|
+
e.preventDefault();
|
|
94
|
+
e.stopPropagation();
|
|
95
|
+
if (selectedUserFilter == userFilter.name) {
|
|
96
|
+
resetFilters();
|
|
97
|
+
setSelectedUserFilter(null);
|
|
98
|
+
} else {
|
|
99
|
+
setAllActiveFilters(
|
|
100
|
+
_.propOr({}, "filters")(userFilter)
|
|
101
|
+
);
|
|
102
|
+
setSelectedUserFilter(userFilter.name);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
className="userFilter"
|
|
107
|
+
>
|
|
108
|
+
{userFilter.name}
|
|
109
|
+
</span>
|
|
110
|
+
|
|
111
|
+
{!isGlobal || authorized ? (
|
|
112
|
+
<DeleteModal
|
|
113
|
+
userFilter={userFilter}
|
|
114
|
+
userFiltersType={userFiltersType}
|
|
115
|
+
mutate={mutate}
|
|
116
|
+
/>
|
|
117
|
+
) : null}
|
|
118
|
+
</Label>
|
|
119
|
+
);
|
|
120
|
+
})}
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
UserFilters.propTypes = {
|
|
126
|
+
selectedUserFilter: PropTypes.string,
|
|
127
|
+
userFilters: PropTypes.array,
|
|
128
|
+
disabled: PropTypes.bool,
|
|
129
|
+
userFilterScope: PropTypes.string,
|
|
130
|
+
mutate: PropTypes.func,
|
|
131
|
+
applyUserFilter: PropTypes.func,
|
|
132
|
+
deleteUserFilter: PropTypes.func,
|
|
133
|
+
resetFilters: PropTypes.func,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export default UserFilters;
|