@truedat/qx 5.17.1 → 5.17.3

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.
Files changed (43) hide show
  1. package/package.json +3 -3
  2. package/src/api.js +24 -1
  3. package/src/components/QxRoutes.js +12 -5
  4. package/src/components/common/ClauseViewer.js +129 -0
  5. package/src/components/common/ResourceSelector.js +7 -2
  6. package/src/components/common/expressions/Clauses.js +15 -3
  7. package/src/components/common/expressions/Condition.js +8 -6
  8. package/src/components/common/expressions/ShapeSelector.js +18 -8
  9. package/src/components/common/expressions/__tests__/ShapeSelector.spec.js +2 -2
  10. package/src/components/dataViews/DataViewEditor.js +4 -3
  11. package/src/components/dataViews/__tests__/__snapshots__/DataViewEditor.spec.js.snap +2 -2
  12. package/src/components/dataViews/queryableFunctions.js +15 -9
  13. package/src/components/functions/FunctionEditor.js +3 -2
  14. package/src/components/functions/__tests__/__snapshots__/FunctionEditor.spec.js.snap +4 -4
  15. package/src/components/qualityControls/EditQualityControl.js +73 -0
  16. package/src/components/qualityControls/NewDraftQualityControl.js +77 -0
  17. package/src/components/qualityControls/NewQualityControl.js +81 -0
  18. package/src/components/qualityControls/QualityControl.js +93 -0
  19. package/src/components/qualityControls/QualityControlActions.js +67 -0
  20. package/src/components/qualityControls/QualityControlCrumbs.js +23 -0
  21. package/src/components/qualityControls/QualityControlEditor.js +271 -0
  22. package/src/components/qualityControls/QualityControlHeader.js +64 -0
  23. package/src/components/qualityControls/QualityControlHistory.js +81 -0
  24. package/src/components/qualityControls/QualityControlRoutes.js +84 -0
  25. package/src/components/qualityControls/QualityControlRow.js +24 -0
  26. package/src/components/qualityControls/QualityControlTabs.js +34 -0
  27. package/src/components/qualityControls/QualityControls.js +67 -0
  28. package/src/components/qualityControls/QualityControlsTable.js +139 -0
  29. package/src/components/qualityControls/ResultCriteria.js +120 -0
  30. package/src/components/qualityControls/ResultType.js +57 -0
  31. package/src/components/qualityControls/resultCriterias/Deviation.js +89 -0
  32. package/src/components/qualityControls/resultCriterias/ErrorsNumber.js +88 -0
  33. package/src/components/qualityControls/resultCriterias/Percentage.js +89 -0
  34. package/src/components/search/FilterDropdown.js +76 -0
  35. package/src/components/search/FilterItem.js +49 -0
  36. package/src/components/search/FilterMultilevelDropdown.js +200 -0
  37. package/src/components/search/HierarchyFilterDropdown.js +116 -0
  38. package/src/components/search/QualityControlFilters.js +60 -0
  39. package/src/components/search/QualityControlSelectedFilters.js +56 -0
  40. package/src/components/search/QualityControlsSearch.js +30 -0
  41. package/src/components/search/SearchContext.js +180 -0
  42. package/src/hooks/useQualityControls.js +74 -0
  43. package/src/styles/Expression.less +39 -4
@@ -0,0 +1,56 @@
1
+ import _ from "lodash/fp";
2
+ import React from "react";
3
+ import { FormattedMessage } from "react-intl";
4
+ import FilterDropdown from "./FilterDropdown";
5
+ import FilterMultilevelDropdown from "./FilterMultilevelDropdown";
6
+ import HierarchyFilterDropdown from "./HierarchyFilterDropdown";
7
+
8
+ import SearchContext, { useSearchContext } from "./SearchContext";
9
+
10
+ export default function QualityControlSelectedFilters() {
11
+ const context = useSearchContext();
12
+ const {
13
+ selectedFilters,
14
+ resetFilters,
15
+ filterTypes,
16
+ activeFilterName,
17
+ activeFilterValues,
18
+ } = context;
19
+
20
+ return (
21
+ <>
22
+ <div className="selectedFilters">
23
+ {_.isEmpty(selectedFilters) ? null : (
24
+ <>
25
+ <div className="appliedFilters">
26
+ <FormattedMessage id="search.applied_filters" />
27
+ </div>
28
+ {selectedFilters.map((filter) => {
29
+ const filterType = _.prop(filter)(filterTypes);
30
+ const options = _.isEqual(filter, activeFilterName)
31
+ ? activeFilterValues
32
+ : null;
33
+ return (
34
+ <SearchContext.Provider
35
+ value={{ ...context, filter, options }}
36
+ key={filter}
37
+ >
38
+ {filterType === "domain" ? (
39
+ <FilterMultilevelDropdown />
40
+ ) : filterType === "hierarchy" ? (
41
+ <HierarchyFilterDropdown />
42
+ ) : (
43
+ <FilterDropdown />
44
+ )}
45
+ </SearchContext.Provider>
46
+ );
47
+ })}
48
+ <a className="resetFilters" onClick={() => resetFilters()}>
49
+ <FormattedMessage id="search.clear_filters" />
50
+ </a>
51
+ </>
52
+ )}
53
+ </div>
54
+ </>
55
+ );
56
+ }
@@ -0,0 +1,30 @@
1
+ import React from "react";
2
+ import { Input } from "semantic-ui-react";
3
+ import { useIntl } from "react-intl";
4
+ import QualityControlFilters from "./QualityControlFilters";
5
+ import QualityControlSelectedFilters from "./QualityControlSelectedFilters";
6
+
7
+ import { useSearchContext } from "./SearchContext";
8
+
9
+ export default function QualityControlsSearch() {
10
+ const { formatMessage } = useIntl();
11
+
12
+ const { query, setQuery, loadingFilters: loading } = useSearchContext();
13
+
14
+ return (
15
+ <>
16
+ <Input
17
+ value={query}
18
+ onChange={(_e, data) => setQuery(data.value)}
19
+ icon={{ name: "search", link: true }}
20
+ iconPosition="left"
21
+ action={<QualityControlFilters />}
22
+ placeholder={formatMessage({
23
+ id: "implementations.search.placeholder",
24
+ })}
25
+ loading={loading}
26
+ />
27
+ <QualityControlSelectedFilters />
28
+ </>
29
+ );
30
+ }
@@ -0,0 +1,180 @@
1
+ import _ from "lodash/fp";
2
+ import React, {
3
+ useState,
4
+ useEffect,
5
+ useContext,
6
+ createContext,
7
+ useMemo,
8
+ } from "react";
9
+ import { useIntl } from "react-intl";
10
+ import {
11
+ toFilterValues,
12
+ formatFilterValues,
13
+ } from "@truedat/core/services/filters";
14
+ import { makeOption } from "@truedat/core/services/i18n";
15
+
16
+ import {
17
+ useQualityControlsSearch,
18
+ useQualityControlsFilters,
19
+ } from "../../hooks/useQualityControls";
20
+
21
+ const SearchContext = createContext();
22
+
23
+ export const SearchContextProvider = (props) => {
24
+ const children = _.prop("children")(props);
25
+ const initialSortColumn = _.prop("initialSortColumn")(props);
26
+ const initialSortDirection = _.prop("initialSortDirection")(props);
27
+ const { formatMessage } = useIntl();
28
+
29
+ const [loadingSearch, setLoadingSearch] = useState(true);
30
+ const [qualityControls, setQualityControls] = useState([]);
31
+
32
+ const [filtersPayload, setFiltersPayload] = useState([]);
33
+ const [loadingFilters, setLoadingFilters] = useState(true);
34
+ const [query, setQuery] = useState("");
35
+ const [activeFilterName, setActiveFilterName] = useState([]);
36
+ const [allActiveFilters, setAllActiveFilters] = useState({});
37
+
38
+ const [sortColumn, setSortColumn] = useState(initialSortColumn);
39
+ const [sortDirection, setSortDirection] = useState(initialSortDirection);
40
+
41
+ //STATE FUNCTIONS
42
+ const addFilter = ({ filter }) => {
43
+ setAllActiveFilters({ ...allActiveFilters, [filter]: [] });
44
+ setActiveFilterName(filter);
45
+ };
46
+ const resetFilters = () => setAllActiveFilters({});
47
+
48
+ const openFilter = ({ filter }) => setActiveFilterName(filter);
49
+ const closeFilter = () => {
50
+ setActiveFilterName(null);
51
+ setAllActiveFilters(_.pickBy(_.negate(_.isEmpty))(allActiveFilters));
52
+ };
53
+ const removeFilter = ({ filter }) => {
54
+ setAllActiveFilters(_.omit(filter)(allActiveFilters));
55
+ setActiveFilterName(activeFilterName == filter ? null : activeFilterName);
56
+ };
57
+
58
+ const toggleFilterValue = ({ filter, value }) => {
59
+ const values = _.propOr([], filter)(allActiveFilters);
60
+ const newValue = _.isArray(value)
61
+ ? value
62
+ : _.includes(value)(values)
63
+ ? _.without([value])(values)
64
+ : _.union([value])(values);
65
+
66
+ setAllActiveFilters({ ...allActiveFilters, [filter]: newValue });
67
+ };
68
+
69
+ //CALCULATIONS ON STATE
70
+ const selectedFilters = _.keys(allActiveFilters);
71
+
72
+ const filters = _.flow(
73
+ _.propOr({}, "data"),
74
+ _.omitBy(_.flow(_.propOr([], "values"), (values) => _.size(values) < 2))
75
+ )(filtersPayload);
76
+
77
+ // getAvailableFilters selector
78
+ const availableFilters = _.flow(_.keys, _.without(selectedFilters))(filters);
79
+
80
+ // getFilterTypes selector
81
+ const filterTypes = _.mapValues("type")(filters);
82
+
83
+ const translations = (formatMessage) => ({
84
+ "status.raw": (v) => formatMessage({ id: v, defaultMessage: v }),
85
+ });
86
+ const activeFilterValues = _.flow(
87
+ _.propOr({ values: [] }, activeFilterName),
88
+ ({ values, type }) => ({
89
+ values: _.flow(
90
+ _.concat(_.prop(activeFilterName)(allActiveFilters)),
91
+ _.uniq
92
+ )(values),
93
+ type,
94
+ }),
95
+ formatFilterValues,
96
+ _.map(makeOption(translations(formatMessage), activeFilterName))
97
+ )(filters);
98
+ const activeFilterSelectedValues = _.flow(
99
+ _.propOr([], activeFilterName),
100
+ toFilterValues
101
+ )(allActiveFilters);
102
+
103
+ const searchMust = useMemo(
104
+ () => _.pickBy(_.negate(_.isEmpty))(allActiveFilters),
105
+ [allActiveFilters]
106
+ );
107
+ const filterMust = useMemo(
108
+ () =>
109
+ _.flow(
110
+ _.pickBy(_.negate(_.isEmpty)),
111
+ _.omit(activeFilterName)
112
+ )(allActiveFilters),
113
+ [allActiveFilters, activeFilterName]
114
+ );
115
+
116
+ const sort = useMemo(
117
+ () =>
118
+ sortColumn
119
+ ? {
120
+ [sortColumn]: sortDirection === "ascending" ? "asc" : "desc",
121
+ }
122
+ : null,
123
+ [sortColumn, sortDirection]
124
+ );
125
+
126
+ const { trigger: triggerFilters } = useQualityControlsFilters();
127
+ useEffect(() => {
128
+ setLoadingFilters(true);
129
+ triggerFilters({ query, must: filterMust }).then(({ data }) => {
130
+ setFiltersPayload(data);
131
+ setLoadingFilters(false);
132
+ });
133
+ }, [query, filterMust, triggerFilters]);
134
+
135
+ const { trigger: triggerSearch } = useQualityControlsSearch();
136
+ useEffect(() => {
137
+ setLoadingSearch(true);
138
+ triggerSearch({ query, must: searchMust, sort }).then(({ data }) => {
139
+ setQualityControls(data?.data);
140
+ setLoadingSearch(false);
141
+ });
142
+ }, [query, searchMust, sort, triggerSearch]);
143
+
144
+ const context = {
145
+ disabled: false,
146
+ loadingFilters,
147
+
148
+ availableFilters,
149
+ selectedFilters,
150
+ filterTypes,
151
+
152
+ activeFilterName,
153
+ activeFilterSelectedValues,
154
+ activeFilterValues,
155
+ query,
156
+
157
+ addFilter,
158
+ resetFilters,
159
+ openFilter,
160
+ closeFilter,
161
+ removeFilter,
162
+ toggleFilterValue,
163
+ setQuery,
164
+
165
+ qualityControls,
166
+ loadingSearch,
167
+
168
+ sortColumn,
169
+ sortDirection,
170
+ setSortColumn,
171
+ setSortDirection,
172
+ };
173
+
174
+ return (
175
+ <SearchContext.Provider value={context}>{children}</SearchContext.Provider>
176
+ );
177
+ };
178
+
179
+ export const useSearchContext = () => useContext(SearchContext);
180
+ export default SearchContext;
@@ -0,0 +1,74 @@
1
+ import { compile } from "path-to-regexp";
2
+ import useSWR from "swr";
3
+ import useSWRMutations from "swr/mutation";
4
+ import {
5
+ apiJson,
6
+ apiJsonPost,
7
+ apiJsonPatch,
8
+ apiJsonDelete,
9
+ } from "@truedat/core/services/api";
10
+ import {
11
+ API_QUALITY_CONTROLS,
12
+ API_QUALITY_CONTROL,
13
+ // API_QUALITY_CONTROL_VERSIONS,
14
+ // API_QUALITY_CONTROL_PUBLISHED,
15
+ API_QUALITY_CONTROL_DRAFT,
16
+ API_QUALITY_CONTROL_STATUS,
17
+ API_QUALITY_CONTROL_DOMAINS,
18
+ API_QUALITY_CONTROL_SEARCH,
19
+ API_QUALITY_CONTROL_FILTERS,
20
+ } from "../api";
21
+
22
+ export const useQualityControls = () => {
23
+ const { data, error, mutate } = useSWR(API_QUALITY_CONTROLS, apiJson);
24
+ return { data: data?.data, error, loading: !error && !data, mutate };
25
+ };
26
+ export const useQualityControl = (id) => {
27
+ const url = compile(API_QUALITY_CONTROL)({ id });
28
+ const { data, error, mutate } = useSWR(url, apiJson);
29
+ return { data: data?.data, error, loading: !error && !data, mutate };
30
+ };
31
+
32
+ export const useQualityControlCreate = () => {
33
+ return useSWRMutations(API_QUALITY_CONTROLS, (url, { arg }) =>
34
+ apiJsonPost(url, arg)
35
+ );
36
+ };
37
+
38
+ export const useQualityControlCreateDraft = (id) => {
39
+ const url = compile(API_QUALITY_CONTROL_DRAFT)({ id });
40
+ return useSWRMutations(url, (url, { arg }) => apiJsonPost(url, arg));
41
+ };
42
+
43
+ export const useQualityControlUpdateDraft = (id) => {
44
+ const url = compile(API_QUALITY_CONTROL_DRAFT)({ id });
45
+ return useSWRMutations(url, (url, { arg }) => apiJsonPatch(url, arg));
46
+ };
47
+
48
+ export const useQualityControlUpdateStatus = (id) => {
49
+ const url = compile(API_QUALITY_CONTROL_STATUS)({ id });
50
+ return useSWRMutations(url, (url, { arg }) => apiJsonPatch(url, arg));
51
+ };
52
+
53
+ export const useQualityControlUpdateDomains = (id) => {
54
+ const url = compile(API_QUALITY_CONTROL_DOMAINS)({ id });
55
+ return useSWRMutations(url, (url, { arg }) => apiJsonPatch(url, arg));
56
+ };
57
+
58
+ export const useQualityControlDelete = (qualityControl) => {
59
+ const id = qualityControl?.id || 0;
60
+ const url = compile(API_QUALITY_CONTROL)({ id });
61
+ return useSWRMutations(url, (url, { arg }) => apiJsonDelete(url, arg));
62
+ };
63
+
64
+ export const useQualityControlsSearch = () => {
65
+ return useSWRMutations(API_QUALITY_CONTROL_SEARCH, (url, { arg }) =>
66
+ apiJsonPost(url, arg)
67
+ );
68
+ };
69
+
70
+ export const useQualityControlsFilters = () => {
71
+ return useSWRMutations(API_QUALITY_CONTROL_FILTERS, (url, { arg }) =>
72
+ apiJsonPost(url, arg)
73
+ );
74
+ };
@@ -45,6 +45,12 @@
45
45
  justify-content: center;
46
46
  }
47
47
 
48
+ .shape-icon {
49
+ font-size: 12px;
50
+ font-weight: bold;
51
+ font-family: monospace;
52
+ }
53
+
48
54
  .function-params-label {
49
55
  display: flex;
50
56
  flex: 1;
@@ -153,10 +159,6 @@ ul.function-tree {
153
159
  }
154
160
 
155
161
 
156
-
157
-
158
-
159
-
160
162
  .join_type{
161
163
  display:inline-flex;
162
164
  left: 25%;
@@ -249,4 +251,37 @@ ul.function-tree {
249
251
  .join-type-dropdown-item {
250
252
  display: flex !important;
251
253
  align-items: center;
254
+ }
255
+
256
+ .float-right {
257
+ float: right;
258
+ }
259
+
260
+ .text-align-left {
261
+ text-align: left;
262
+ }
263
+
264
+ .display-flex {
265
+ display: flex;
266
+ }
267
+
268
+ .clause-viewer-function {
269
+ padding-left: 8px;
270
+ margin-top: 2px;
271
+ }
272
+ .divider-compact {
273
+ font-size: smaller !important;
274
+ margin: 5px !important;
275
+ }
276
+ .no-margin {
277
+ margin: 0px !important;
278
+ }
279
+ .font-big {
280
+ font-size: x-large;
281
+ margin: 4px;
282
+ }
283
+ .condition-function-viewer {
284
+ display: flex;
285
+ justify-content: center;
286
+ align-items: center;
252
287
  }