@truedat/dq 4.58.3 → 4.58.5

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.
@@ -0,0 +1,314 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`<NewBasicRuleImplementation /> matches the latest snapshot 1`] = `
4
+ <div>
5
+ <div
6
+ class="ui divided grid full-height"
7
+ style=""
8
+ >
9
+ <div
10
+ class="eleven wide column"
11
+ >
12
+ <div
13
+ class="row"
14
+ >
15
+ <h2
16
+ class="ui header"
17
+ >
18
+ <div
19
+ class="content"
20
+ >
21
+ New Implementation
22
+ </div>
23
+ </h2>
24
+ <div
25
+ class="ui hidden divider"
26
+ />
27
+ </div>
28
+ <div
29
+ class="stretched row"
30
+ >
31
+ <form
32
+ class="ui form rule"
33
+ >
34
+ <div
35
+ class="field"
36
+ >
37
+ <label>
38
+ Implementation Key
39
+ <i
40
+ aria-hidden="true"
41
+ class="question circle outline icon rule-form-popup"
42
+ />
43
+ </label>
44
+ <div
45
+ class="required field"
46
+ >
47
+ <div
48
+ class="ui input"
49
+ >
50
+ <input
51
+ autocomplete="off"
52
+ name="implementation_key"
53
+ placeholder="Rule Implementation Key"
54
+ required=""
55
+ type="text"
56
+ value=""
57
+ />
58
+ </div>
59
+ </div>
60
+ </div>
61
+ <div
62
+ class="field"
63
+ />
64
+ <div
65
+ class="ui segment"
66
+ >
67
+ <div
68
+ class="field"
69
+ >
70
+ <label
71
+ class="rule-form-label"
72
+ >
73
+ Result Type
74
+ <span>
75
+ *
76
+ </span>
77
+ <i
78
+ aria-hidden="true"
79
+ class="question circle outline icon rule-form-popup"
80
+ />
81
+ </label>
82
+ <div
83
+ class="inline fields"
84
+ >
85
+ <div
86
+ class="field"
87
+ >
88
+ <div
89
+ class="ui checked radio checkbox"
90
+ >
91
+ <input
92
+ checked=""
93
+ class="hidden"
94
+ name="result_type"
95
+ readonly=""
96
+ tabindex="0"
97
+ type="radio"
98
+ value="percentage"
99
+ />
100
+ <label>
101
+ Percentage
102
+ </label>
103
+ </div>
104
+ </div>
105
+ <div
106
+ class="field"
107
+ >
108
+ <div
109
+ class="ui radio checkbox"
110
+ >
111
+ <input
112
+ class="hidden"
113
+ name="result_type"
114
+ readonly=""
115
+ tabindex="0"
116
+ type="radio"
117
+ value="deviation"
118
+ />
119
+ <label>
120
+ Deviation
121
+ </label>
122
+ </div>
123
+ </div>
124
+ <div
125
+ class="field"
126
+ >
127
+ <div
128
+ class="ui radio checkbox"
129
+ >
130
+ <input
131
+ class="hidden"
132
+ name="result_type"
133
+ readonly=""
134
+ tabindex="0"
135
+ type="radio"
136
+ value="errors_number"
137
+ />
138
+ <label>
139
+ Error count
140
+ </label>
141
+ </div>
142
+ </div>
143
+ </div>
144
+ </div>
145
+ <div
146
+ class="field"
147
+ >
148
+ <label
149
+ class="rule-form-label"
150
+ >
151
+ Threshold
152
+ <span>
153
+ *
154
+ </span>
155
+ <i
156
+ aria-hidden="true"
157
+ class="question circle outline icon rule-form-popup"
158
+ />
159
+ <div
160
+ class="ui left pointing label"
161
+ >
162
+ Required field is empty
163
+ </div>
164
+ </label>
165
+ <div
166
+ class="field"
167
+ >
168
+ <div
169
+ class="ui input"
170
+ >
171
+ <input
172
+ autocomplete="off"
173
+ name="minimum"
174
+ placeholder="Threshold value"
175
+ type="text"
176
+ value=""
177
+ />
178
+ </div>
179
+ </div>
180
+ </div>
181
+ <div
182
+ class="field"
183
+ >
184
+ <label
185
+ class="rule-form-label"
186
+ >
187
+ Goal
188
+ <span>
189
+ *
190
+ </span>
191
+ <i
192
+ aria-hidden="true"
193
+ class="question circle outline icon rule-form-popup"
194
+ />
195
+ <div
196
+ class="ui left pointing label"
197
+ >
198
+ Required field is empty
199
+ </div>
200
+ </label>
201
+ <div
202
+ class="field"
203
+ >
204
+ <div
205
+ class="ui input"
206
+ >
207
+ <input
208
+ autocomplete="off"
209
+ name="goal"
210
+ placeholder="Goal value"
211
+ type="text"
212
+ value=""
213
+ />
214
+ </div>
215
+ </div>
216
+ </div>
217
+ </div>
218
+ <div
219
+ class="required field"
220
+ >
221
+ <label>
222
+ Template
223
+ <div
224
+ class="ui left pointing label"
225
+ >
226
+ Empty required field
227
+ </div>
228
+ </label>
229
+ <div
230
+ class="field"
231
+ >
232
+ <div
233
+ aria-busy="false"
234
+ aria-expanded="false"
235
+ class="ui search selection dropdown"
236
+ name="template"
237
+ role="combobox"
238
+ >
239
+ <input
240
+ aria-autocomplete="list"
241
+ autocomplete="off"
242
+ class="search"
243
+ tabindex="0"
244
+ type="text"
245
+ value=""
246
+ />
247
+ <div
248
+ aria-atomic="true"
249
+ aria-live="polite"
250
+ class="divider default text"
251
+ role="alert"
252
+ >
253
+ Select a template...
254
+ </div>
255
+ <i
256
+ aria-hidden="true"
257
+ class="dropdown icon"
258
+ />
259
+ <div
260
+ class="menu transition"
261
+ role="listbox"
262
+ >
263
+ <div
264
+ aria-checked="false"
265
+ aria-selected="true"
266
+ class="selected item"
267
+ role="option"
268
+ style="pointer-events: all;"
269
+ >
270
+ <span
271
+ class="text"
272
+ >
273
+ template1
274
+ </span>
275
+ </div>
276
+ <div
277
+ aria-checked="false"
278
+ aria-selected="false"
279
+ class="item"
280
+ role="option"
281
+ style="pointer-events: all;"
282
+ >
283
+ <span
284
+ class="text"
285
+ >
286
+ template2
287
+ </span>
288
+ </div>
289
+ </div>
290
+ </div>
291
+ </div>
292
+ </div>
293
+ <button
294
+ class="ui primary disabled right floated button"
295
+ disabled=""
296
+ tabindex="-1"
297
+ type="submit"
298
+ >
299
+ Save
300
+ </button>
301
+ <button
302
+ class="ui secondary right floated button"
303
+ >
304
+ Cancel
305
+ </button>
306
+ </form>
307
+ </div>
308
+ </div>
309
+ <div
310
+ class="five wide column"
311
+ />
312
+ </div>
313
+ </div>
314
+ `;
@@ -65,6 +65,7 @@ exports[`<RuleImplementationsActions /> matches the latest snapshot 1`] = `
65
65
  to="/implementations/new"
66
66
  />
67
67
  <RuleImplementationsOptions
68
+ canCreateBasicImplementations={false}
68
69
  canUploadResults={true}
69
70
  loading={false}
70
71
  />
@@ -22,13 +22,14 @@ const DomainActionsLoader = ({ id, actions, onLoad }) => {
22
22
  };
23
23
 
24
24
  export const InformationForm = ({
25
- setImplementationKey,
25
+ conceptDomainId,
26
+ domainIds,
27
+ isModification,
26
28
  onChange,
29
+ onDomainsLoad,
27
30
  ruleImplementation,
31
+ setImplementationKey,
28
32
  setIsValid,
29
- onDomainsLoad,
30
- conceptDomainId,
31
- domainIds,
32
33
  }) => {
33
34
  const { formatMessage } = useIntl();
34
35
 
@@ -106,25 +107,27 @@ export const InformationForm = ({
106
107
  <LimitsForm onChange={onChange} ruleImplementation={ruleImplementation} />
107
108
  <SelectableDynamicForm
108
109
  scope="ri"
109
- domainIds={_.isNil(domainId) ? null : [domainId]}
110
- required
111
110
  content={ruleImplementation?.dfContent}
111
+ domainIds={_.isNil(domainId) ? null : [domainId]}
112
+ isModification={isModification}
112
113
  name={ruleImplementation?.dfName}
113
114
  onChange={handleContentChange}
114
115
  onNameChange={(dfName) => onChange("dfName", dfName)}
116
+ required
115
117
  />
116
118
  </>
117
119
  );
118
120
  };
119
121
 
120
122
  InformationForm.propTypes = {
123
+ conceptDomainId: PropTypes.array,
124
+ domainIds: PropTypes.array,
125
+ isModification: PropTypes.bool,
121
126
  onChange: PropTypes.func,
127
+ onDomainsLoad: PropTypes.func,
122
128
  ruleImplementation: PropTypes.object,
123
129
  setImplementationKey: PropTypes.func,
124
130
  setIsValid: PropTypes.func,
125
- onDomainsLoad: PropTypes.func,
126
- conceptDomainId: PropTypes.array,
127
- domainIds: PropTypes.array,
128
131
  };
129
132
 
130
133
  export default InformationForm;
@@ -0,0 +1,206 @@
1
+ import _ from "lodash/fp";
2
+ import React, { useState, useEffect } from "react";
3
+ import PropTypes from "prop-types";
4
+ import { connect } from "react-redux";
5
+ import { useHistory } from "react-router-dom";
6
+ import { useIntl } from "react-intl";
7
+ import { useQuery } from "@apollo/client";
8
+ import { Button, Form, Icon, Popup } from "semantic-ui-react";
9
+ import { DomainSelector } from "@truedat/core/components";
10
+ import { DOMAIN_QUERY } from "@truedat/core/api/queries";
11
+ import LimitsForm from "./LimitsForm";
12
+ import { areLimitsValid } from "./limitsValidation";
13
+
14
+ const SelectableDynamicForm = React.lazy(() =>
15
+ import("@truedat/df/components/SelectableDynamicForm")
16
+ );
17
+
18
+ const DomainActionsLoader = ({ id, actions, onLoad }) => {
19
+ useQuery(DOMAIN_QUERY, {
20
+ fetchPolicy: "cache-and-network",
21
+ variables: { id, actions },
22
+ onCompleted: onLoad,
23
+ });
24
+ return null;
25
+ };
26
+
27
+ DomainActionsLoader.propTypes = {
28
+ id: PropTypes.number,
29
+ actions: PropTypes.array,
30
+ onLoad: PropTypes.func,
31
+ };
32
+
33
+ const Help = ({ message }) => {
34
+ const { formatMessage } = useIntl();
35
+ return (
36
+ <Popup
37
+ trigger={
38
+ <Icon className="rule-form-popup" name="question circle outline" />
39
+ }
40
+ content={formatMessage({ id: message })}
41
+ on="click"
42
+ hideOnScroll
43
+ />
44
+ );
45
+ };
46
+
47
+ Help.propTypes = {
48
+ message: PropTypes.string,
49
+ };
50
+
51
+ export const RuleImplementationBasicForm = ({
52
+ implementationKey,
53
+ isModification,
54
+ isSubmitting,
55
+ onChange,
56
+ onSubmit,
57
+ rule,
58
+ ruleImplementation,
59
+ setImplementationKey,
60
+ }) => {
61
+ const { formatMessage } = useIntl();
62
+ const history = useHistory();
63
+
64
+ const domainActions = ["publishImplementation"];
65
+
66
+ const [isContentValid, setIsContentValid] = useState();
67
+
68
+ const [domains, setDomains] = useState();
69
+ const [canPublish, setCanPublish] = useState(false);
70
+
71
+ useEffect(() => {
72
+ const currentDomainActions = _.flow(
73
+ _.find((domain) => domain.id === String(ruleImplementation.domain_id)),
74
+ _.pathOr([], "actions")
75
+ )(domains);
76
+
77
+ _.flow(
78
+ _.any((action) => action == "publishImplementation"),
79
+ setCanPublish
80
+ )(currentDomainActions);
81
+
82
+ return () => {
83
+ setCanPublish(false);
84
+ };
85
+ }, [domains, ruleImplementation.domain_id]);
86
+
87
+ const handleContentChange = ({ content, valid }) => {
88
+ onChange("dfContent", content);
89
+ setIsContentValid(_.isEmpty(valid));
90
+ };
91
+
92
+ const doSubmit = (params) => {
93
+ if (isValidForm()) {
94
+ onSubmit(params);
95
+ }
96
+ };
97
+
98
+ const isValidForm = () =>
99
+ ruleImplementation?.dfName &&
100
+ !_.isEmpty(ruleImplementation?.dfName) &&
101
+ isContentValid &&
102
+ (!_.isEmpty(rule) || _.prop("domain_id")(ruleImplementation)) &&
103
+ areLimitsValid(ruleImplementation);
104
+
105
+ const doCancel = () => history.goBack();
106
+
107
+ const domainId = ruleImplementation?.domain_id || rule?.domain_id;
108
+
109
+ return (
110
+ <Form className="rule">
111
+ <Form.Field>
112
+ <label>
113
+ {formatMessage({ id: "ruleImplementation.props.name" })}
114
+ <Help message="datasetForm.implementation_key.tooltip" />
115
+ </label>
116
+ <Form.Input
117
+ autoComplete="off"
118
+ name="implementation_key"
119
+ onChange={(_e, { value }) => setImplementationKey(value)}
120
+ placeholder={formatMessage({
121
+ id: "ruleImplementation.props.name.placeholder",
122
+ })}
123
+ required
124
+ value={implementationKey}
125
+ />
126
+ </Form.Field>
127
+ {_.isEmpty(rule) && !ruleImplementation?.rule_id ? (
128
+ <Form.Field>
129
+ <DomainSelector
130
+ action={
131
+ ruleImplementation.rule_id
132
+ ? "manageBasicImplementations"
133
+ : "manageBasicRulelessImplementations"
134
+ }
135
+ value={domainId}
136
+ domainActions={domainActions}
137
+ onLoad={(data) => setDomains(data.domains)}
138
+ onChange={(_e, { value }) => onChange("domain_id", value)}
139
+ labels
140
+ />
141
+ </Form.Field>
142
+ ) : (
143
+ <DomainActionsLoader
144
+ id={domainId}
145
+ actions={domainActions}
146
+ onLoad={(data) => setDomains([data.domain])}
147
+ />
148
+ )}
149
+ <LimitsForm onChange={onChange} ruleImplementation={ruleImplementation} />
150
+ <SelectableDynamicForm
151
+ scope="ri"
152
+ content={ruleImplementation?.dfContent}
153
+ domainIds={_.isNil(domainId) ? null : [domainId]}
154
+ isModification={isModification}
155
+ name={ruleImplementation?.dfName}
156
+ onChange={handleContentChange}
157
+ onNameChange={(dfName) => onChange("dfName", dfName)}
158
+ required
159
+ />
160
+ {canPublish ? (
161
+ <Button
162
+ floated="right"
163
+ disabled={!isValidForm()}
164
+ type="submit"
165
+ primary
166
+ loading={isSubmitting}
167
+ onClick={() => doSubmit({ status: "published" })}
168
+ content={formatMessage({ id: "actions.publish" })}
169
+ />
170
+ ) : null}
171
+ <Button
172
+ floated="right"
173
+ disabled={!isValidForm()}
174
+ type="submit"
175
+ primary
176
+ loading={isSubmitting}
177
+ onClick={() => doSubmit({ status: "draft" })}
178
+ content={formatMessage({ id: "actions.save" })}
179
+ />
180
+ <Button
181
+ content={formatMessage({ id: "actions.cancel" })}
182
+ floated="right"
183
+ onClick={() => doCancel()}
184
+ secondary
185
+ />
186
+ </Form>
187
+ );
188
+ };
189
+
190
+ RuleImplementationBasicForm.propTypes = {
191
+ implementationKey: PropTypes.string,
192
+ isModification: PropTypes.bool,
193
+ isSubmitting: PropTypes.bool,
194
+ onChange: PropTypes.func,
195
+ onSubmit: PropTypes.func.isRequired,
196
+ rule: PropTypes.object,
197
+ ruleImplementation: PropTypes.object,
198
+ setImplementationKey: PropTypes.func,
199
+ };
200
+
201
+ const mapStateToProps = ({ rule, ruleImplementationCreating }) => ({
202
+ isSubmitting: ruleImplementationCreating,
203
+ rule,
204
+ });
205
+
206
+ export default connect(mapStateToProps)(RuleImplementationBasicForm);
@@ -50,6 +50,7 @@ export const RuleImplementationForm = ({
50
50
  addValidation,
51
51
  conceptDomainId,
52
52
  domainIds,
53
+ isModification,
53
54
  isSubmitting,
54
55
  onChange,
55
56
  onSubmit,
@@ -342,16 +343,17 @@ export const RuleImplementationForm = ({
342
343
  {activeStep == "information" && (
343
344
  <InformationForm
344
345
  {...{
345
- onChange,
346
- ruleImplementation,
347
- setImplementationKey,
348
346
  conceptDomainId,
349
347
  domainIds,
350
- setIsValid: setContentIsValid,
348
+ isModification,
349
+ onChange,
351
350
  onDomainsLoad: (domains) => {
352
351
  setDomains(domains);
353
352
  setIsLoadingDomains(false);
354
353
  },
354
+ ruleImplementation,
355
+ setImplementationKey,
356
+ setIsValid: setContentIsValid,
355
357
  }}
356
358
  />
357
359
  )}
@@ -507,12 +509,13 @@ export const RuleImplementationForm = ({
507
509
 
508
510
  RuleImplementationForm.propTypes = {
509
511
  addPopulation: PropTypes.func,
510
- addValidation: PropTypes.func,
511
512
  addSegment: PropTypes.func,
513
+ addValidation: PropTypes.func,
512
514
  authManageSegments: PropTypes.bool,
513
515
  conceptDomainId: PropTypes.number,
514
516
  domainIds: PropTypes.array,
515
517
  isAdmin: PropTypes.bool,
518
+ isModification: PropTypes.bool,
516
519
  isSubmitting: PropTypes.bool,
517
520
  onChange: PropTypes.func,
518
521
  onSubmit: PropTypes.func.isRequired,
@@ -54,6 +54,7 @@ export const RuleImplementationRawForm = ({
54
54
  conceptDomainId,
55
55
  domainIds,
56
56
  implementationKey,
57
+ isModification,
57
58
  isSubmitting,
58
59
  onChange,
59
60
  onSubmit,
@@ -235,12 +236,13 @@ export const RuleImplementationRawForm = ({
235
236
  <LimitsForm onChange={onChange} ruleImplementation={ruleImplementation} />
236
237
  <SelectableDynamicForm
237
238
  scope="ri"
238
- domainIds={_.isNil(domainId) ? null : [domainId]}
239
- required
240
239
  content={ruleImplementation?.dfContent}
240
+ domainIds={_.isNil(domainId) ? null : [domainId]}
241
+ isModification={isModification}
241
242
  name={ruleImplementation?.dfName}
242
243
  onChange={handleContentChange}
243
244
  onNameChange={(dfName) => onChange("dfName", dfName)}
245
+ required
244
246
  />
245
247
  <Form.Dropdown
246
248
  label={
@@ -386,6 +388,7 @@ RuleImplementationRawForm.propTypes = {
386
388
  conceptDomainId: PropTypes.number,
387
389
  domainIds: PropTypes.array,
388
390
  implementationKey: PropTypes.string,
391
+ isModification: PropTypes.bool,
389
392
  isSubmitting: PropTypes.bool,
390
393
  onChange: PropTypes.func,
391
394
  onSubmit: PropTypes.func.isRequired,