@truedat/qx 7.0.8 → 7.1.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.
Files changed (169) hide show
  1. package/package.json +13 -4
  2. package/src/api.js +29 -20
  3. package/src/components/QxRoutes.js +18 -16
  4. package/src/components/__tests__/__fixtures__/helper.js +187 -0
  5. package/src/components/common/TestFormWrapper.js +38 -0
  6. package/src/components/common/__tests__/ResourceSelector.spec.js +18 -7
  7. package/src/components/common/__tests__/__snapshots__/ResourceSelector.spec.js.snap +0 -12
  8. package/src/components/common/expressions/__tests__/Condition.spec.js +4 -1
  9. package/src/components/common/expressions/__tests__/FunctionArgs.spec.js +18 -5
  10. package/src/components/common/expressions/__tests__/ShapeSelector.spec.js +4 -4
  11. package/src/components/common/expressions/__tests__/__snapshots__/FunctionArgs.spec.js.snap +10 -2
  12. package/src/components/common/resourceSelectors/__tests__/DataStructureSelector.spec.js +6 -3
  13. package/src/components/common/resourceSelectors/__tests__/__snapshots__/DataStructureSelector.spec.js.snap +0 -12
  14. package/src/components/dataViews/__tests__/DataViewEditor.spec.js +83 -53
  15. package/src/components/dataViews/__tests__/DataViews.spec.js +14 -1
  16. package/src/components/dataViews/__tests__/__snapshots__/DataViewEditor.spec.js.snap +93 -4
  17. package/src/components/dataViews/queryableProperties/__tests__/SelectField.spec.js +13 -6
  18. package/src/components/functions/__tests__/FunctionEditor.spec.js +2 -34
  19. package/src/components/functions/__tests__/FunctionParams.spec.js +4 -17
  20. package/src/components/functions/__tests__/Functions.spec.js +2 -34
  21. package/src/components/functions/__tests__/__snapshots__/FunctionEditor.spec.js.snap +48 -48
  22. package/src/components/functions/__tests__/__snapshots__/FunctionParams.spec.js.snap +4 -4
  23. package/src/components/functions/__tests__/__snapshots__/Functions.spec.js.snap +4 -4
  24. package/src/components/qualityControls/ControlProperties.js +43 -0
  25. package/src/components/qualityControls/ControlPropertiesView.js +109 -0
  26. package/src/components/qualityControls/EditQualityControl.js +5 -21
  27. package/src/components/qualityControls/IconPopup.js +28 -0
  28. package/src/components/qualityControls/NewDraftQualityControl.js +4 -13
  29. package/src/components/qualityControls/NewQualityControl.js +10 -25
  30. package/src/components/qualityControls/QualityBadge.js +33 -0
  31. package/src/components/qualityControls/QualityControl.js +11 -53
  32. package/src/components/qualityControls/QualityControlActions.js +133 -46
  33. package/src/components/qualityControls/QualityControlEditor.js +114 -135
  34. package/src/components/qualityControls/QualityControlHeader.js +29 -7
  35. package/src/components/qualityControls/QualityControlHistory.js +6 -12
  36. package/src/components/qualityControls/QualityControlQueryModal.js +8 -5
  37. package/src/components/qualityControls/QualityControlRoutes.js +51 -96
  38. package/src/components/qualityControls/QualityControlRow.js +21 -2
  39. package/src/components/qualityControls/QualityControlScores.js +140 -0
  40. package/src/components/qualityControls/QualityControlTabs.js +24 -23
  41. package/src/components/qualityControls/QualityControls.js +142 -59
  42. package/src/components/qualityControls/QualityControlsLabelResults.js +51 -0
  43. package/src/components/qualityControls/QualityControlsTable.js +69 -43
  44. package/src/components/qualityControls/ScoreCriteria.js +40 -0
  45. package/src/components/qualityControls/{ResultCriteria.js → ScoreCriteriaView.js} +26 -42
  46. package/src/components/qualityControls/__tests__/ControlProperties.spec.js +86 -0
  47. package/src/components/qualityControls/__tests__/ControlPropertiesView.spec.js +86 -0
  48. package/src/components/qualityControls/__tests__/EditQualityControl.spec.js +219 -0
  49. package/src/components/qualityControls/__tests__/IconPopup.spec.js +33 -0
  50. package/src/components/qualityControls/__tests__/NewDraftQualityControl.spec.js +253 -0
  51. package/src/components/qualityControls/__tests__/NewQualityControl.spec.js +384 -0
  52. package/src/components/qualityControls/__tests__/QualityBadge.spec.js +30 -0
  53. package/src/components/qualityControls/__tests__/QualityControl.spec.js +47 -0
  54. package/src/components/qualityControls/__tests__/QualityControlActions.spec.js +192 -0
  55. package/src/components/qualityControls/__tests__/QualityControlCrumbs.spec.js +18 -0
  56. package/src/components/qualityControls/__tests__/QualityControlEditor.spec.js +296 -0
  57. package/src/components/qualityControls/__tests__/QualityControlHeader.spec.js +68 -0
  58. package/src/components/qualityControls/__tests__/QualityControlHistory.spec.js +21 -0
  59. package/src/components/qualityControls/__tests__/QualityControlQueryModal.spec.js +77 -0
  60. package/src/components/qualityControls/__tests__/QualityControlRow.spec.js +91 -0
  61. package/src/components/qualityControls/__tests__/QualityControlScores.spec.js +139 -0
  62. package/src/components/qualityControls/__tests__/QualityControlTabs.spec.js +20 -0
  63. package/src/components/qualityControls/__tests__/QualityControls.spec.js +202 -0
  64. package/src/components/qualityControls/__tests__/QualityControlsLabelResults.spec.js +83 -0
  65. package/src/components/qualityControls/__tests__/QualityControlsTable.spec.js +38 -0
  66. package/src/components/qualityControls/__tests__/ScoreCriteria.spec.js +77 -0
  67. package/src/components/qualityControls/__tests__/ScoreCriteriaView.spec.js +62 -0
  68. package/src/components/qualityControls/__tests__/__fixtures__/qualityControlHelper.js +281 -0
  69. package/src/components/qualityControls/__tests__/__snapshots__/ControlProperties.spec.js.snap +151 -0
  70. package/src/components/qualityControls/__tests__/__snapshots__/ControlPropertiesView.spec.js.snap +290 -0
  71. package/src/components/qualityControls/__tests__/__snapshots__/EditQualityControl.spec.js.snap +672 -0
  72. package/src/components/qualityControls/__tests__/__snapshots__/IconPopup.spec.js.snap +10 -0
  73. package/src/components/qualityControls/__tests__/__snapshots__/NewDraftQualityControl.spec.js.snap +648 -0
  74. package/src/components/qualityControls/__tests__/__snapshots__/NewQualityControl.spec.js.snap +336 -0
  75. package/src/components/qualityControls/__tests__/__snapshots__/QualityBadge.spec.js.snap +11 -0
  76. package/src/components/qualityControls/__tests__/__snapshots__/QualityControl.spec.js.snap +255 -0
  77. package/src/components/qualityControls/__tests__/__snapshots__/QualityControlActions.spec.js.snap +85 -0
  78. package/src/components/qualityControls/__tests__/__snapshots__/QualityControlCrumbs.spec.js.snap +25 -0
  79. package/src/components/qualityControls/__tests__/__snapshots__/QualityControlEditor.spec.js.snap +930 -0
  80. package/src/components/qualityControls/__tests__/__snapshots__/QualityControlHeader.spec.js.snap +127 -0
  81. package/src/components/qualityControls/__tests__/__snapshots__/QualityControlHistory.spec.js.snap +75 -0
  82. package/src/components/qualityControls/__tests__/__snapshots__/QualityControlQueryModal.spec.js.snap +27 -0
  83. package/src/components/qualityControls/__tests__/__snapshots__/QualityControlRow.spec.js.snap +113 -0
  84. package/src/components/qualityControls/__tests__/__snapshots__/QualityControlScores.spec.js.snap +161 -0
  85. package/src/components/qualityControls/__tests__/__snapshots__/QualityControlTabs.spec.js.snap +28 -0
  86. package/src/components/qualityControls/__tests__/__snapshots__/QualityControls.spec.js.snap +219 -0
  87. package/src/components/qualityControls/__tests__/__snapshots__/QualityControlsLabelResults.spec.js.snap +11 -0
  88. package/src/components/qualityControls/__tests__/__snapshots__/QualityControlsTable.spec.js.snap +121 -0
  89. package/src/components/qualityControls/__tests__/__snapshots__/ScoreCriteria.spec.js.snap +186 -0
  90. package/src/components/qualityControls/__tests__/__snapshots__/ScoreCriteriaView.spec.js.snap +76 -0
  91. package/src/components/qualityControls/__tests__/qualityByControlMode.spec.js +248 -0
  92. package/src/components/qualityControls/controlProperties/ErrorCount.js +56 -0
  93. package/src/components/qualityControls/controlProperties/Ratio.js +79 -0
  94. package/src/components/qualityControls/controlProperties/__tests__/ErrorCount.spec.js +82 -0
  95. package/src/components/qualityControls/controlProperties/__tests__/Ratio.spec.js +115 -0
  96. package/src/components/qualityControls/controlProperties/__tests__/__snapshots__/ErrorCount.spec.js.snap +62 -0
  97. package/src/components/qualityControls/controlProperties/__tests__/__snapshots__/Ratio.spec.js.snap +143 -0
  98. package/src/components/qualityControls/qualityByControlMode.js +62 -0
  99. package/src/components/qualityControls/qualityControlScoresColumns.js +52 -0
  100. package/src/components/qualityControls/{resultCriterias → scoreCriterias}/Deviation.js +6 -6
  101. package/src/components/qualityControls/{resultCriterias/ErrorsNumber.js → scoreCriterias/ErrorCount.js} +7 -7
  102. package/src/components/qualityControls/{resultCriterias → scoreCriterias}/Percentage.js +6 -6
  103. package/src/components/qualityControls/scoreCriterias/__tests__/Deviation.spec.js +75 -0
  104. package/src/components/qualityControls/scoreCriterias/__tests__/ErrorCount.spec.js +63 -0
  105. package/src/components/qualityControls/scoreCriterias/__tests__/Percentage.spec.js +61 -0
  106. package/src/components/qualityControls/scoreCriterias/__tests__/__snapshots__/Deviation.spec.js.snap +58 -0
  107. package/src/components/qualityControls/scoreCriterias/__tests__/__snapshots__/ErrorCount.spec.js.snap +58 -0
  108. package/src/components/qualityControls/scoreCriterias/__tests__/__snapshots__/Percentage.spec.js.snap +58 -0
  109. package/src/components/{executions/ExecutionGroupsHeader.js → scores/MyScoreGroups.js} +5 -3
  110. package/src/components/scores/QualityBar.js +73 -0
  111. package/src/components/scores/Score.js +32 -0
  112. package/src/components/scores/ScoreContext.js +3 -0
  113. package/src/components/scores/ScoreCrumbs.js +40 -0
  114. package/src/components/scores/ScoreDetails.js +67 -0
  115. package/src/components/scores/ScoreEvents.js +59 -0
  116. package/src/components/scores/ScoreGroup.js +83 -0
  117. package/src/components/scores/ScoreGroupBreadcrumbs.js +25 -0
  118. package/src/components/{qualityControls/ExecutionForm.js → scores/ScoreGroupForm.js} +11 -13
  119. package/src/components/scores/ScoreGroupLink.js +18 -0
  120. package/src/components/scores/ScoreGroupMessage.js +25 -0
  121. package/src/components/{qualityControls/ExecutionPopup.js → scores/ScoreGroupPopup.js} +13 -22
  122. package/src/components/scores/ScoreGroupsTable.js +113 -0
  123. package/src/components/scores/ScoreRoutes.js +32 -0
  124. package/src/components/{executions/ExecutionStatusDecorator.js → scores/ScoreStatusDecorator.js} +10 -8
  125. package/src/components/scores/ScoreTabs.js +32 -0
  126. package/src/components/scores/__tests__/MyScoreGroups.spec.js +31 -0
  127. package/src/components/scores/__tests__/QualityBar.spec.js +55 -0
  128. package/src/components/scores/__tests__/Score.spec.js +41 -0
  129. package/src/components/scores/__tests__/ScoreCrumbs.spec.js +39 -0
  130. package/src/components/scores/__tests__/ScoreDetails.spec.js +38 -0
  131. package/src/components/scores/__tests__/ScoreEvents.spec.js +24 -0
  132. package/src/components/scores/__tests__/ScoreGroup.spec.js +43 -0
  133. package/src/components/scores/__tests__/ScoreGroupBreadcrumbs.spec.js +16 -0
  134. package/src/components/scores/__tests__/ScoreGroupForm.spec.js +78 -0
  135. package/src/components/scores/__tests__/ScoreGroupLink.spec.js +16 -0
  136. package/src/components/scores/__tests__/ScoreGroupMessage.spec.js +20 -0
  137. package/src/components/scores/__tests__/ScoreGroupPopup.spec.js +59 -0
  138. package/src/components/scores/__tests__/ScoreGroupsTable.spec.js +40 -0
  139. package/src/components/scores/__tests__/ScoreStatusDecorator.spec.js +21 -0
  140. package/src/components/scores/__tests__/ScoreTabs.spec.js +27 -0
  141. package/src/components/scores/__tests__/__fixtures__/scoreHelper.js +182 -0
  142. package/src/components/scores/__tests__/__snapshots__/MyScoreGroups.spec.js.snap +154 -0
  143. package/src/components/scores/__tests__/__snapshots__/QualityBar.spec.js.snap +24 -0
  144. package/src/components/scores/__tests__/__snapshots__/Score.spec.js.snap +92 -0
  145. package/src/components/scores/__tests__/__snapshots__/ScoreCrumbs.spec.js.snap +39 -0
  146. package/src/components/scores/__tests__/__snapshots__/ScoreDetails.spec.js.snap +156 -0
  147. package/src/components/scores/__tests__/__snapshots__/ScoreEvents.spec.js.snap +167 -0
  148. package/src/components/scores/__tests__/__snapshots__/ScoreGroup.spec.js.snap +103 -0
  149. package/src/components/scores/__tests__/__snapshots__/ScoreGroupBreadcrumbs.spec.js.snap +29 -0
  150. package/src/components/scores/__tests__/__snapshots__/ScoreGroupForm.spec.js.snap +145 -0
  151. package/src/components/scores/__tests__/__snapshots__/ScoreGroupLink.spec.js.snap +15 -0
  152. package/src/components/scores/__tests__/__snapshots__/ScoreGroupMessage.spec.js.snap +43 -0
  153. package/src/components/scores/__tests__/__snapshots__/ScoreGroupPopup.spec.js.snap +11 -0
  154. package/src/components/scores/__tests__/__snapshots__/ScoreGroupsTable.spec.js.snap +147 -0
  155. package/src/components/scores/__tests__/__snapshots__/ScoreStatusDecorator.spec.js.snap +71 -0
  156. package/src/components/scores/__tests__/__snapshots__/ScoreTabs.spec.js.snap +43 -0
  157. package/src/components/scores/index.js +15 -0
  158. package/src/hooks/useQualityControls.js +3 -9
  159. package/src/hooks/useScoreGroups.js +23 -0
  160. package/src/hooks/useScores.js +22 -0
  161. package/src/styles/Expression.less +16 -0
  162. package/src/styles/scores.less +63 -0
  163. package/src/components/executions/ExecutionGroupBreadcrumbs.js +0 -25
  164. package/src/components/executions/ExecutionGroupContent.js +0 -42
  165. package/src/components/executions/ExecutionGroupLink.js +0 -18
  166. package/src/components/executions/ExecutionGroupMessage.js +0 -27
  167. package/src/components/executions/ExecutionGroupsTable.js +0 -101
  168. package/src/components/executions/executionGroupDetail.js +0 -87
  169. package/src/components/qualityControls/ResultType.js +0 -57
@@ -1,12 +1,28 @@
1
1
  import _ from "lodash/fp";
2
2
  import React from "react";
3
3
  import PropTypes from "prop-types";
4
- import { Table } from "semantic-ui-react";
4
+ import { Checkbox, Table } from "semantic-ui-react";
5
5
  import { columnDecorator } from "@truedat/core/services";
6
6
 
7
- export default function QualityControlRow({ columns, qualityControl }) {
7
+ export default function QualityControlRow({
8
+ columns,
9
+ qualityControl,
10
+ withCheck = false,
11
+ onChange,
12
+ checked,
13
+ }) {
8
14
  return _.isEmpty(columns) || _.isEmpty(qualityControl) ? null : (
9
15
  <Table.Row>
16
+ {withCheck ? (
17
+ <Table.Cell collapsing width="1" textAlign="center">
18
+ <Checkbox
19
+ id={`row-checkbox-${qualityControl.id}`}
20
+ checked={checked}
21
+ onChange={onChange}
22
+ />
23
+ </Table.Cell>
24
+ ) : null}
25
+
10
26
  {columns.map((column, i) => (
11
27
  <Table.Cell
12
28
  key={i}
@@ -21,4 +37,7 @@ export default function QualityControlRow({ columns, qualityControl }) {
21
37
  QualityControlRow.propTypes = {
22
38
  columns: PropTypes.array,
23
39
  qualityControl: PropTypes.object,
40
+ withCheck: PropTypes.bool,
41
+ onChange: PropTypes.func,
42
+ checked: PropTypes.bool,
24
43
  };
@@ -0,0 +1,140 @@
1
+ import _ from "lodash/fp";
2
+ import React, { useContext } from "react";
3
+ import { useIntl } from "react-intl";
4
+ import { useParams, Link } from "react-router-dom";
5
+ import { Button, Table, Label, Message, Icon } from "semantic-ui-react";
6
+ import { ConfirmModal, Loading } from "@truedat/core/components";
7
+ import { columnDecorator } from "@truedat/core/services";
8
+ import { linkTo } from "@truedat/core/routes";
9
+ import { useQualityControlScores, useScoreDelete } from "../../hooks/useScores";
10
+ import QxContext from "../QxContext";
11
+ import columns from "./qualityControlScoresColumns";
12
+
13
+ const VALID_DELETE_STATUSES = ["PENDING", "SUCCEEDED", "FAILED"];
14
+
15
+ export default function QualityControlScores() {
16
+ const { id } = useParams();
17
+ const { formatMessage } = useIntl();
18
+ const {
19
+ data,
20
+ loading: loadingQualityScores,
21
+ mutate,
22
+ } = useQualityControlScores(id);
23
+ const { trigger: deleteScore, loading: deletingScore } = useScoreDelete();
24
+ const {
25
+ qualityControl,
26
+ actions,
27
+ loading: loadingQualityControl,
28
+ } = useContext(QxContext);
29
+
30
+ const canDeleteScore = _.includes("delete_score")(actions);
31
+
32
+ const loading =
33
+ loadingQualityScores || loadingQualityControl || deletingScore;
34
+ const scores = data?.data;
35
+
36
+ const versionsMap = _.flow(
37
+ _.prop("versions"),
38
+ _.map((qcv) => [qcv.version_id, qcv]),
39
+ _.fromPairs
40
+ )(qualityControl);
41
+
42
+ const scoreRows = _.flow(
43
+ _.groupBy("quality_control_version_id"),
44
+ _.toPairs,
45
+ _.orderBy(([id, _info]) => id, "desc"),
46
+ _.map(([id, info]) => [versionsMap[parseInt(id)], info]),
47
+ _.mapValues(([qcv, info]) =>
48
+ info.map((score, indexWithinVersion) => ({
49
+ ...score,
50
+ quality_control: qcv,
51
+ firstInVersion: indexWithinVersion == 0,
52
+ }))
53
+ ),
54
+ _.reduce((acc, versionScores) => [...acc, ...versionScores], [])
55
+ )(scores);
56
+
57
+ return loading ? (
58
+ <Loading />
59
+ ) : _.isEmpty(scores) ? (
60
+ <Message
61
+ header={formatMessage({
62
+ id: "scores.empty",
63
+ })}
64
+ />
65
+ ) : (
66
+ <Table>
67
+ <Table.Header>
68
+ <Table.Row>
69
+ {columns.map(({ name }, idx) => (
70
+ <Table.HeaderCell
71
+ key={idx}
72
+ content={formatMessage({ id: `scores.props.${name}` })}
73
+ />
74
+ ))}
75
+ {canDeleteScore ? <Table.HeaderCell /> : null}
76
+ </Table.Row>
77
+ </Table.Header>
78
+ <Table.Body>
79
+ {scoreRows.map((score, key) => {
80
+ const active =
81
+ score.quality_control.version === qualityControl.version;
82
+ const tagLabel = score.firstInVersion
83
+ ? `${formatMessage({
84
+ id: "quality_control.props.version",
85
+ })}: ${score.quality_control.version}`
86
+ : null;
87
+ return (
88
+ <React.Fragment key={key}>
89
+ {tagLabel ? (
90
+ <Table.Row>
91
+ <Table.Cell>
92
+ <Label
93
+ as={Link}
94
+ to={linkTo.QUALITY_CONTROL_HISTORY({ id })}
95
+ active={active}
96
+ ribbon
97
+ >
98
+ {tagLabel}
99
+ </Label>
100
+ </Table.Cell>
101
+ </Table.Row>
102
+ ) : null}
103
+ <Table.Row warning={active}>
104
+ {columns.map((column, key) => (
105
+ <Table.Cell
106
+ key={key}
107
+ textAlign={column.textAlign}
108
+ content={columnDecorator(column)(score)}
109
+ />
110
+ ))}
111
+
112
+ {canDeleteScore ? (
113
+ <Table.Cell onClick={(e) => e.stopPropagation()}>
114
+ {_.includes(score.status)(VALID_DELETE_STATUSES) ? (
115
+ <ConfirmModal
116
+ icon="trash"
117
+ trigger={
118
+ <Button icon basic color="red">
119
+ <Icon name="trash alternate outline" color="red" />
120
+ </Button>
121
+ }
122
+ header={formatMessage({
123
+ id: "score.actions.delete.confirmation.header",
124
+ })}
125
+ content={formatMessage({
126
+ id: "score.actions.delete.confirmation.content",
127
+ })}
128
+ onConfirm={() => deleteScore(score).then(mutate)}
129
+ />
130
+ ) : null}
131
+ </Table.Cell>
132
+ ) : null}
133
+ </Table.Row>
134
+ </React.Fragment>
135
+ );
136
+ })}
137
+ </Table.Body>
138
+ </Table>
139
+ );
140
+ }
@@ -1,34 +1,35 @@
1
1
  import React from "react";
2
2
  import { Menu } from "semantic-ui-react";
3
- import { Link, useRouteMatch, useParams } from "react-router-dom";
3
+ import { Link, useLocation, useParams } from "react-router-dom";
4
4
  import { FormattedMessage } from "react-intl";
5
- import {
6
- QUALITY_CONTROL,
7
- QUALITY_CONTROL_HISTORY,
8
- linkTo,
9
- } from "@truedat/core/routes";
5
+ import { linkTo } from "@truedat/core/routes";
10
6
 
11
7
  export default function QualityControlTabs() {
12
- const match = useRouteMatch();
13
- const { id } = useParams();
8
+ const { pathname } = useLocation();
9
+ const urlParams = useParams();
10
+
11
+ const tabs = [
12
+ {
13
+ url: linkTo.QUALITY_CONTROL(urlParams),
14
+ text: "quality_control.tabs.quality_control",
15
+ },
16
+ {
17
+ url: linkTo.QUALITY_CONTROL_HISTORY(urlParams),
18
+ text: "quality_control.tabs.history",
19
+ },
20
+ {
21
+ url: linkTo.QUALITY_CONTROL_SCORES(urlParams),
22
+ text: "quality_control.tabs.scores",
23
+ },
24
+ ];
14
25
 
15
26
  return (
16
27
  <Menu attached="top" pointing secondary tabular>
17
- <Menu.Item
18
- active={match.path === QUALITY_CONTROL}
19
- as={Link}
20
- to={linkTo.QUALITY_CONTROL({ id })}
21
- >
22
- <FormattedMessage id="quality_control.tabs.quality_control" />
23
- </Menu.Item>
24
-
25
- <Menu.Item
26
- active={match.path === QUALITY_CONTROL_HISTORY}
27
- as={Link}
28
- to={linkTo.QUALITY_CONTROL_HISTORY({ id })}
29
- >
30
- <FormattedMessage id="quality_control.tabs.history" />
31
- </Menu.Item>
28
+ {tabs.map(({ url, text }, key) => (
29
+ <Menu.Item key={key} active={pathname === url} as={Link} to={url}>
30
+ <FormattedMessage id={text} />
31
+ </Menu.Item>
32
+ ))}
32
33
  </Menu>
33
34
  );
34
35
  }
@@ -1,5 +1,5 @@
1
1
  import _ from "lodash/fp";
2
- import React, { useEffect } from "react";
2
+ import React, { useState } from "react";
3
3
  import { useIntl, FormattedMessage } from "react-intl";
4
4
  import { Link, useHistory } from "react-router-dom";
5
5
  import {
@@ -10,15 +10,17 @@ import {
10
10
  Icon,
11
11
  Segment,
12
12
  Grid,
13
+ Dimmer,
14
+ Loader,
13
15
  } from "semantic-ui-react";
14
16
  import { linkTo, QUALITY_CONTROL_NEW } from "@truedat/core/routes";
15
17
  import useAuthorizedAction from "@truedat/core/hooks/useAuthorizedAction";
16
- import Loading from "@truedat/core/components/Loading";
17
18
  import { useSearchContext } from "@truedat/core/search/SearchContext";
18
19
  import SearchWidget from "@truedat/core/search/SearchWidget";
19
- import { useExecutionGroupsCreate } from "../../hooks/useExecutionGroups";
20
- import ExecutionPopup from "./ExecutionPopup";
20
+ import { useScoreGroupCreate } from "@truedat/qx/hooks/useScoreGroups";
21
+ import { ScoreGroupPopup } from "../scores";
21
22
  import QualityControlsTable from "./QualityControlsTable";
23
+ import QualityControlsLabelResults from "./QualityControlsLabelResults";
22
24
 
23
25
  export const QualityControls = () => {
24
26
  const { formatMessage } = useIntl();
@@ -30,39 +32,111 @@ export const QualityControls = () => {
30
32
  const canCreate = _.prop("has_any_domain")(data);
31
33
 
32
34
  const {
35
+ count,
33
36
  query,
34
37
  searchMust,
35
- loadingFilters: loading,
36
38
  hiddenFilters,
37
39
  toggleHiddenFilterValue,
38
40
  searchData,
39
41
  defaultFilters,
42
+ removeHiddenFilter,
43
+ loading,
40
44
  } = useSearchContext();
41
45
 
42
- const canExecuteQualityControl = _.matches({ executable: [true] })(
43
- hiddenFilters
46
+ const [selectedQualityControls, setSelectedQualityControls] = useState([]);
47
+ const [executeQualityControlOn, setExecuteMode] = useState(
48
+ _.matches({ active: [true] })(hiddenFilters)
44
49
  );
45
50
 
46
- const status = _.prop("status")(defaultFilters);
47
-
48
51
  const qualityControls = searchData?.data;
49
52
  const qualityControlsActions = searchData?.actions;
53
+ const status = _.prop("status")(defaultFilters);
50
54
 
51
- const { trigger: triggerCreateExecutionGroup } = useExecutionGroupsCreate();
55
+ const allChecked = () => {
56
+ const ids = _.map(_.prop("version_id"))(qualityControls);
57
+ return (
58
+ _.negate(_.isEmpty)(selectedQualityControls) &&
59
+ _.every((id) => _.includes(id)(selectedQualityControls))(ids)
60
+ );
61
+ };
52
62
 
53
- const handleSubmit = (df_content) => {
54
- triggerCreateExecutionGroup({
55
- query,
56
- must: searchMust,
57
- df_content,
58
- }).then(({ data }) => {
63
+ const addAll = (_e, target) => {
64
+ const checkedAll = _.prop("checked")(target);
65
+ const ids = _.map(_.prop("version_id"))(qualityControls);
66
+ checkedAll
67
+ ? setSelectedQualityControls(
68
+ _.flow(_.concat(ids), _.uniq)(selectedQualityControls)
69
+ )
70
+ : setSelectedQualityControls(
71
+ _.flow(_.difference(selectedQualityControls), _.uniq)(ids)
72
+ );
73
+ };
74
+ const isRowChecked = (qualityControl) => {
75
+ const id = _.prop("version_id")(qualityControl);
76
+ return _.some((selectedId) => _.eq(id, selectedId))(
77
+ selectedQualityControls
78
+ );
79
+ };
80
+
81
+ const checkRow = (qualityControl) => {
82
+ const id = _.prop("version_id")(qualityControl);
83
+ const exists = _.some((selectedId) => _.eq(id, selectedId))(
84
+ selectedQualityControls
85
+ );
86
+ exists
87
+ ? setSelectedQualityControls(
88
+ _.flow(
89
+ _.remove((selectedId) => _.eq(id, selectedId)),
90
+ _.uniq
91
+ )(selectedQualityControls)
92
+ )
93
+ : setSelectedQualityControls(
94
+ _.flow(_.concat(id), _.uniq)(selectedQualityControls)
95
+ );
96
+ };
97
+
98
+ const { trigger: triggerCreateScoreGroup, loading: groupCreating } =
99
+ useScoreGroupCreate();
100
+
101
+ const showActiveInfo = () => {
102
+ toggleHiddenFilterValue({
103
+ filter: "for_execution",
104
+ value: true,
105
+ });
106
+ };
107
+
108
+ const hideActiveInfo = () => {
109
+ removeHiddenFilter({ filter: "for_execution" });
110
+ };
111
+
112
+ const handleExecuteChange = (checked) => {
113
+ setExecuteMode(checked);
114
+ checked ? showActiveInfo() : hideActiveInfo();
115
+ };
116
+
117
+ const handleSubmit = ({ content, df_type }) => {
118
+ const score_group = {
119
+ dynamic_content: content,
120
+ df_type,
121
+ };
122
+ const body = _.isEmpty(selectedQualityControls)
123
+ ? {
124
+ score_group,
125
+ search: { query, must: searchMust },
126
+ }
127
+ : {
128
+ score_group,
129
+ ids: selectedQualityControls,
130
+ };
131
+
132
+ triggerCreateScoreGroup(body).then(({ data }) => {
59
133
  const id = _.prop("data.id")(data);
60
- history.push(linkTo.QUALITY_CONTROLS_EXECUTION_GROUP({ id }));
134
+ history.push(linkTo.SCORE_GROUP({ id }));
61
135
  });
62
136
  };
63
137
 
64
138
  return (
65
- <Segment loading={false}>
139
+ <Segment>
66
140
  <Header as="h2">
67
141
  <Icon circular name="archive" />
68
142
  <Header.Content>
@@ -76,53 +150,62 @@ export const QualityControls = () => {
76
150
  <Grid.Column width={8}>
77
151
  <SearchWidget />
78
152
  </Grid.Column>
79
-
80
153
  <Grid.Column width={8}>
81
154
  <Container textAlign="right">
82
- {loading ? (
83
- <Loading />
84
- ) : (
85
- <>
86
- {status === "published" &&
87
- _.size(qualityControls) > 0 &&
88
- qualityControlsActions?.execute ? (
89
- <>
90
- <Checkbox
91
- id="execute_checkbox"
92
- className="bgOrange"
93
- toggle
94
- onChange={() =>
95
- toggleHiddenFilterValue({
96
- filter: "executable",
97
- value: true,
98
- })
99
- }
100
- checked={canExecuteQualityControl}
101
- style={{ top: "6px", marginRight: "7.5px" }}
102
- />
103
- <ExecutionPopup
104
- disabled={!canExecuteQualityControl}
105
- onSubmit={handleSubmit}
106
- executionGroupType={"quality_control"}
107
- />
108
- </>
109
- ) : null}
110
- {canCreate ? (
111
- <Button
112
- primary
113
- as={Link}
114
- to={QUALITY_CONTROL_NEW}
115
- content={formatMessage({
116
- id: "quality_controls.actions.create",
117
- })}
155
+ <>
156
+ {status === "published" &&
157
+ _.size(qualityControls) > 0 &&
158
+ qualityControlsActions?.execute ? (
159
+ <>
160
+ <Checkbox
161
+ id="execute_checkbox"
162
+ className="bgOrange"
163
+ toggle
164
+ onChange={() =>
165
+ handleExecuteChange(!executeQualityControlOn)
166
+ }
167
+ checked={executeQualityControlOn}
168
+ style={{ top: "6px", marginRight: "7.5px" }}
118
169
  />
119
- ) : null}
120
- </>
121
- )}
170
+ <ScoreGroupPopup
171
+ loading={groupCreating}
172
+ disabled={!executeQualityControlOn}
173
+ onSubmit={handleSubmit}
174
+ count={_.size(selectedQualityControls) || count}
175
+ />
176
+ </>
177
+ ) : null}
178
+ {canCreate ? (
179
+ <Button
180
+ primary
181
+ as={Link}
182
+ to={QUALITY_CONTROL_NEW}
183
+ content={formatMessage({
184
+ id: "quality_controls.actions.create",
185
+ })}
186
+ />
187
+ ) : null}
188
+ </>
122
189
  </Container>
123
190
  </Grid.Column>
124
191
  </Grid>
125
- <QualityControlsTable />
192
+ <QualityControlsLabelResults
193
+ executeQualityControlOn={executeQualityControlOn}
194
+ qualityControlsToExecute={_.size(selectedQualityControls)}
195
+ />
196
+ <Dimmer.Dimmable dimmed={loading}>
197
+ <Dimmer active={loading} inverted>
198
+ <Loader />
199
+ </Dimmer>
200
+
201
+ <QualityControlsTable
202
+ addAll={addAll}
203
+ checkedAll={allChecked()}
204
+ checkRow={checkRow}
205
+ executeQualityControlOn={executeQualityControlOn}
206
+ isRowChecked={isRowChecked}
207
+ />
208
+ </Dimmer.Dimmable>
126
209
  </Segment>
127
210
  );
128
211
  };
@@ -0,0 +1,51 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import { FormattedMessage } from "react-intl";
4
+ import { Label } from "semantic-ui-react";
5
+ import { useSearchContext } from "@truedat/core/search/SearchContext";
6
+
7
+ export const QualityControlsLabelResults = ({
8
+ executeQualityControlOn,
9
+ qualityControlsToExecute,
10
+ }) => {
11
+ const { loading, count } = useSearchContext();
12
+
13
+ return (
14
+ <>
15
+ <Label className="quality-controls-label-results">
16
+ {loading ? (
17
+ <FormattedMessage id="quality_controls.searching" />
18
+ ) : (
19
+ <FormattedMessage
20
+ id="quality_controls.retrieved.results"
21
+ values={{ count }}
22
+ />
23
+ )}
24
+ </Label>
25
+
26
+ {!loading && executeQualityControlOn ? (
27
+ <Label className="quality-controls-label-results">
28
+ <FormattedMessage
29
+ id="quality_controls.execute.filtered"
30
+ values={{
31
+ count:
32
+ qualityControlsToExecute == 0
33
+ ? count
34
+ : qualityControlsToExecute,
35
+ }}
36
+ />
37
+ </Label>
38
+ ) : null}
39
+ </>
40
+ );
41
+ };
42
+
43
+ QualityControlsLabelResults.propTypes = {
44
+ executeQualityControlOn: PropTypes.oneOfType([
45
+ PropTypes.string,
46
+ PropTypes.bool,
47
+ ]),
48
+ qualityControlsToExecute: PropTypes.number,
49
+ };
50
+
51
+ export default QualityControlsLabelResults;
@@ -3,7 +3,7 @@ import React from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { Link } from "react-router-dom";
5
5
  import { useIntl, FormattedMessage } from "react-intl";
6
- import { Table, Header, Icon } from "semantic-ui-react";
6
+ import { Checkbox, Table, Header, Icon } from "semantic-ui-react";
7
7
  import { linkTo } from "@truedat/core/routes";
8
8
  import Moment from "react-moment";
9
9
 
@@ -24,7 +24,54 @@ DateDecorator.propTypes = {
24
24
  date: PropTypes.string,
25
25
  };
26
26
 
27
- export default function QualityControlsTable() {
27
+ export const columns = [
28
+ {
29
+ name: "name",
30
+ fieldSelector: _.pick(["id", "name"]),
31
+ fieldDecorator: ({ id, name }) => (
32
+ <Link to={linkTo.QUALITY_CONTROL({ id })}>{name}</Link>
33
+ ),
34
+ },
35
+ {
36
+ name: "df_type",
37
+ sort: { name: "df_type" },
38
+ width: 2,
39
+ },
40
+ {
41
+ name: "control_mode",
42
+ sort: { name: "control_mode" },
43
+ fieldSelector: ({ control_mode }) =>
44
+ control_mode
45
+ ? translateDecorator(`quality_control.control_mode.${control_mode}`)
46
+ : "-",
47
+ width: 2,
48
+ },
49
+ {
50
+ name: "status",
51
+ sort: { name: "status" },
52
+ fieldSelector: ({ status }) =>
53
+ translateDecorator(`quality_control.status.${status}`),
54
+ width: 2,
55
+ },
56
+ {
57
+ name: "updated_at",
58
+ sort: { name: "updated_at" },
59
+ fieldSelector: ({ updated_at }) => ({
60
+ date: updated_at,
61
+ }),
62
+ width: 2,
63
+ fieldDecorator: DateDecorator,
64
+ textAlign: "center",
65
+ },
66
+ ];
67
+
68
+ export default function QualityControlsTable({
69
+ addAll,
70
+ checkedAll,
71
+ checkRow,
72
+ executeQualityControlOn,
73
+ isRowChecked,
74
+ }) {
28
75
  const {
29
76
  searchData,
30
77
  loading,
@@ -36,53 +83,21 @@ export default function QualityControlsTable() {
36
83
 
37
84
  const qualityControls = searchData?.data;
38
85
 
39
- const columns = [
40
- {
41
- name: "name",
42
- fieldSelector: _.pick(["id", "name"]),
43
- fieldDecorator: ({ id, name }) => (
44
- <Link to={linkTo.QUALITY_CONTROL({ id })}>{name}</Link>
45
- ),
46
- },
47
- {
48
- name: "df_type",
49
- sort: { name: "df_type" },
50
- width: 2,
51
- },
52
- {
53
- name: "result_type",
54
- sort: { name: "result_type" },
55
- fieldSelector: ({ result_type }) =>
56
- result_type
57
- ? translateDecorator(`quality_control.result_type.${result_type}`)
58
- : "-",
59
- width: 2,
60
- },
61
- {
62
- name: "status",
63
- sort: { name: "status" },
64
- fieldSelector: ({ status }) =>
65
- translateDecorator(`quality_control.status.${status}`),
66
- width: 2,
67
- },
68
- {
69
- name: "updated_at",
70
- sort: { name: "updated_at" },
71
- fieldSelector: ({ updated_at }) => ({
72
- date: updated_at,
73
- }),
74
- width: 2,
75
- fieldDecorator: DateDecorator,
76
- textAlign: "center",
77
- },
78
- ];
79
-
80
86
  return (
81
87
  <>
82
88
  {!_.isEmpty(qualityControls) && (
83
89
  <Table sortable>
84
90
  <Table.Header>
85
91
  <Table.Row>
92
+ {executeQualityControlOn ? (
93
+ <Table.HeaderCell textAlign="center">
94
+ <Checkbox
95
+ id="selectQualityControl"
96
+ onChange={addAll}
97
+ checked={checkedAll}
98
+ />
99
+ </Table.HeaderCell>
100
+ ) : null}
86
101
  {columns
87
102
  ? columns.map((column, key) => (
88
103
  <Table.HeaderCell
@@ -112,8 +127,11 @@ export default function QualityControlsTable() {
112
127
  {qualityControls.map((qc, i) => (
113
128
  <QualityControlRow
114
129
  key={i}
130
+ checked={isRowChecked && isRowChecked(qc)}
115
131
  qualityControl={qc}
116
132
  columns={columns}
133
+ onChange={() => checkRow && checkRow(qc)}
134
+ withCheck={executeQualityControlOn}
117
135
  />
118
136
  ))}
119
137
  </Table.Body>
@@ -130,3 +148,11 @@ export default function QualityControlsTable() {
130
148
  </>
131
149
  );
132
150
  }
151
+
152
+ QualityControlsTable.propTypes = {
153
+ addAll: PropTypes.func,
154
+ checkedAll: PropTypes.bool,
155
+ checkRow: PropTypes.func,
156
+ executeQualityControlOn: PropTypes.bool,
157
+ isRowChecked: PropTypes.func,
158
+ };