@truedat/dq 4.56.8 → 4.58.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.
- package/CHANGELOG.md +6 -0
- package/package.json +7 -6
- package/src/components/NewRuleImplementation.js +67 -3
- package/src/components/RuleImplementation.js +1 -3
- package/src/components/ruleImplementationForm/InformationForm.js +9 -4
- package/src/components/ruleImplementationForm/RuleImplementationForm.js +8 -3
- package/src/components/ruleImplementationForm/RuleImplementationRawForm.js +20 -6
- package/src/hooks/index.js +1 -0
- package/src/hooks/useConcept.js +13 -0
- package/src/messages/en.js +2 -0
- package/src/messages/es.js +2 -0
- package/src/reducers/dqMessage.js +12 -0
- package/src/reducers/ruleImplementationRedirect.js +10 -1
- package/src/sagas/__tests__/createRuleImplementation.spec.js +39 -1
- package/src/sagas/createRuleImplementation.js +31 -3
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/dq",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.58.0",
|
|
4
4
|
"description": "Truedat Web Data Quality Module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"jsnext:main": "src/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@testing-library/jest-dom": "^5.16.5",
|
|
35
35
|
"@testing-library/react": "^12.0.0",
|
|
36
36
|
"@testing-library/user-event": "^13.2.1",
|
|
37
|
-
"@truedat/test": "4.
|
|
37
|
+
"@truedat/test": "4.58.0",
|
|
38
38
|
"babel-jest": "^28.1.0",
|
|
39
39
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
|
40
40
|
"babel-plugin-lodash": "^3.3.4",
|
|
@@ -92,8 +92,8 @@
|
|
|
92
92
|
},
|
|
93
93
|
"dependencies": {
|
|
94
94
|
"@apollo/client": "^3.7.1",
|
|
95
|
-
"@truedat/core": "4.
|
|
96
|
-
"@truedat/df": "4.
|
|
95
|
+
"@truedat/core": "4.58.0",
|
|
96
|
+
"@truedat/df": "4.58.0",
|
|
97
97
|
"graphql": "^15.5.3",
|
|
98
98
|
"moment": "^2.29.4",
|
|
99
99
|
"path-to-regexp": "^1.7.0",
|
|
@@ -108,12 +108,13 @@
|
|
|
108
108
|
"redux-saga-routines": "^3.2.3",
|
|
109
109
|
"reselect": "^4.1.7",
|
|
110
110
|
"semantic-ui-calendar-react": "^0.15.3",
|
|
111
|
-
"semantic-ui-react": "^2.1.4"
|
|
111
|
+
"semantic-ui-react": "^2.1.4",
|
|
112
|
+
"swr": "^1.3.0"
|
|
112
113
|
},
|
|
113
114
|
"peerDependencies": {
|
|
114
115
|
"react": ">= 16.8.6 < 17",
|
|
115
116
|
"react-dom": ">= 16.8.6 < 17",
|
|
116
117
|
"semantic-ui-react": ">= 2.0.3 < 2.2"
|
|
117
118
|
},
|
|
118
|
-
"gitHead": "
|
|
119
|
+
"gitHead": "3987557a127b4e999021e0d7179ad7a6375bfe01"
|
|
119
120
|
}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
2
|
import React, { useState } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
|
+
import queryString from "query-string";
|
|
4
5
|
import { connect } from "react-redux";
|
|
5
|
-
import { Divider, Header, Grid } from "semantic-ui-react";
|
|
6
6
|
import { FormattedMessage } from "react-intl";
|
|
7
|
+
import { useLocation } from "react-router-dom";
|
|
8
|
+
import { Divider, Loader, Header, Grid } from "semantic-ui-react";
|
|
9
|
+
import { linkTo } from "@truedat/core/routes";
|
|
7
10
|
import { Loading } from "@truedat/core/components";
|
|
8
11
|
import { useOperators } from "@truedat/core/hooks";
|
|
9
12
|
import { getFieldType } from "@truedat/core/services/fieldType";
|
|
13
|
+
import { useConcept } from "../hooks/useConcept";
|
|
10
14
|
import {
|
|
11
15
|
createRuleImplementation,
|
|
12
16
|
updateRuleImplementation,
|
|
@@ -245,6 +249,10 @@ const withConditionDefaultAlias = (conditions, structures) =>
|
|
|
245
249
|
})(conditions);
|
|
246
250
|
|
|
247
251
|
export const NewRuleImplementation = ({
|
|
252
|
+
conceptDomainId,
|
|
253
|
+
conceptDomainIds,
|
|
254
|
+
conceptId,
|
|
255
|
+
conceptVersionId,
|
|
248
256
|
clone = false,
|
|
249
257
|
createRuleImplementation,
|
|
250
258
|
updateRuleImplementation,
|
|
@@ -353,7 +361,7 @@ export const NewRuleImplementation = ({
|
|
|
353
361
|
minimum: null,
|
|
354
362
|
goal: null,
|
|
355
363
|
rule_id: _.propOr(null, "id")(rule),
|
|
356
|
-
domain_id:
|
|
364
|
+
domain_id: conceptDomainId || rule?.domain_id || null,
|
|
357
365
|
rule: rule,
|
|
358
366
|
}
|
|
359
367
|
);
|
|
@@ -536,6 +544,13 @@ export const NewRuleImplementation = ({
|
|
|
536
544
|
clone || !edition
|
|
537
545
|
? createRuleImplementation({
|
|
538
546
|
rule_implementation,
|
|
547
|
+
redirectUrl: conceptId
|
|
548
|
+
? linkTo.CONCEPT_LINKS_IMPLEMENTATIONS({
|
|
549
|
+
business_concept_id: conceptId,
|
|
550
|
+
id: conceptVersionId,
|
|
551
|
+
})
|
|
552
|
+
: null,
|
|
553
|
+
conceptId,
|
|
539
554
|
})
|
|
540
555
|
: updateRuleImplementation({
|
|
541
556
|
rule_implementation: {
|
|
@@ -569,6 +584,8 @@ export const NewRuleImplementation = ({
|
|
|
569
584
|
<RuleImplementationRawForm
|
|
570
585
|
mode={clone ? "clone" : edition ? "edition" : ""}
|
|
571
586
|
implementationKey={ruleImplementation.implementationKey}
|
|
587
|
+
conceptDomainId={conceptDomainId}
|
|
588
|
+
domainIds={conceptDomainIds}
|
|
572
589
|
rawContent={ruleImplementation.rawContent}
|
|
573
590
|
setImplementationKey={setImplementationKey}
|
|
574
591
|
setImplementationRawContent={setImplementationRawContent}
|
|
@@ -581,6 +598,8 @@ export const NewRuleImplementation = ({
|
|
|
581
598
|
addPopulation={addPopulation}
|
|
582
599
|
addValidation={addValidation}
|
|
583
600
|
addSegment={addSegment}
|
|
601
|
+
conceptDomainId={conceptDomainId}
|
|
602
|
+
domainIds={conceptDomainIds}
|
|
584
603
|
onSubmit={doSubmit}
|
|
585
604
|
onChange={onChange}
|
|
586
605
|
operators={operators}
|
|
@@ -604,6 +623,8 @@ export const NewRuleImplementation = ({
|
|
|
604
623
|
};
|
|
605
624
|
|
|
606
625
|
NewRuleImplementation.propTypes = {
|
|
626
|
+
conceptId: PropTypes.number,
|
|
627
|
+
conceptVersionId: PropTypes.number,
|
|
607
628
|
clone: PropTypes.bool,
|
|
608
629
|
createRuleImplementation: PropTypes.func.isRequired,
|
|
609
630
|
edition: PropTypes.bool,
|
|
@@ -613,6 +634,8 @@ NewRuleImplementation.propTypes = {
|
|
|
613
634
|
structuresFields: PropTypes.object,
|
|
614
635
|
structuresSiblings: PropTypes.object,
|
|
615
636
|
updateRuleImplementation: PropTypes.func,
|
|
637
|
+
conceptDomainId: PropTypes.number,
|
|
638
|
+
conceptDomainIds: PropTypes.array,
|
|
616
639
|
};
|
|
617
640
|
|
|
618
641
|
const mapStateToProps = (state) => ({
|
|
@@ -626,13 +649,54 @@ const mapStateToProps = (state) => ({
|
|
|
626
649
|
structuresSiblings: state.structuresSiblings,
|
|
627
650
|
});
|
|
628
651
|
|
|
629
|
-
export const
|
|
652
|
+
export const ImplementationOperatorLoader = (props) => {
|
|
630
653
|
const { data, error, loading } = useOperators();
|
|
631
654
|
if (error) return null;
|
|
632
655
|
if (loading) return <Loading />;
|
|
633
656
|
return <NewRuleImplementation operators={data} {...props} />;
|
|
634
657
|
};
|
|
635
658
|
|
|
659
|
+
export const ImplementationConceptLoader = (props) => {
|
|
660
|
+
const conceptId = props.conceptId;
|
|
661
|
+
const conceptVersionId = props.conceptVersionId;
|
|
662
|
+
|
|
663
|
+
const { concept, error, loading } = useConcept(conceptId, conceptVersionId);
|
|
664
|
+
// TODO: if error??;
|
|
665
|
+
const domainId = concept?.data?.domain?.id;
|
|
666
|
+
const sharedTo = concept?.data?._embedded?.shared_to;
|
|
667
|
+
|
|
668
|
+
const conceptDomainIds = _.flow(
|
|
669
|
+
_.map(({ id: id }) => id),
|
|
670
|
+
_.concat(domainId)
|
|
671
|
+
)(sharedTo);
|
|
672
|
+
|
|
673
|
+
return loading ? (
|
|
674
|
+
<Loader />
|
|
675
|
+
) : (
|
|
676
|
+
<ImplementationOperatorLoader
|
|
677
|
+
{...props}
|
|
678
|
+
conceptDomainId={domainId}
|
|
679
|
+
conceptDomainIds={conceptDomainIds}
|
|
680
|
+
conceptId={conceptId}
|
|
681
|
+
conceptVersionId={conceptVersionId}
|
|
682
|
+
/>
|
|
683
|
+
);
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
export const ImplementationLoader = (props) => {
|
|
687
|
+
const { search } = useLocation();
|
|
688
|
+
const { business_concept_id, id } = queryString.parse(search);
|
|
689
|
+
return id && business_concept_id ? (
|
|
690
|
+
<ImplementationConceptLoader
|
|
691
|
+
{...props}
|
|
692
|
+
conceptId={business_concept_id}
|
|
693
|
+
conceptVersionId={id}
|
|
694
|
+
/>
|
|
695
|
+
) : (
|
|
696
|
+
<ImplementationOperatorLoader {...props} />
|
|
697
|
+
);
|
|
698
|
+
};
|
|
699
|
+
|
|
636
700
|
export default connect(mapStateToProps, {
|
|
637
701
|
createRuleImplementation,
|
|
638
702
|
updateRuleImplementation,
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
|
-
import { useIntl } from "react-intl";
|
|
5
4
|
import { connect } from "react-redux";
|
|
6
|
-
import { Header,
|
|
5
|
+
import { Header, Grid, Icon } from "semantic-ui-react";
|
|
7
6
|
import ImplementationActions from "./ImplementationActions";
|
|
8
7
|
import ImplementationResultBar from "./ImplementationResultBar";
|
|
9
8
|
import RuleImplementationTabs from "./RuleImplementationTabs";
|
|
10
9
|
import Subscription from "./Subscription";
|
|
11
10
|
|
|
12
11
|
export const RuleImplementation = ({ children, ruleImplementation }) => {
|
|
13
|
-
const { formatMessage } = useIntl();
|
|
14
12
|
const deletedAt = _.prop("deleted_at")(ruleImplementation);
|
|
15
13
|
|
|
16
14
|
return (
|
|
@@ -27,6 +27,8 @@ export const InformationForm = ({
|
|
|
27
27
|
ruleImplementation,
|
|
28
28
|
setIsValid,
|
|
29
29
|
onDomainsLoad,
|
|
30
|
+
conceptDomainId,
|
|
31
|
+
domainIds,
|
|
30
32
|
}) => {
|
|
31
33
|
const { formatMessage } = useIntl();
|
|
32
34
|
|
|
@@ -35,7 +37,7 @@ export const InformationForm = ({
|
|
|
35
37
|
|
|
36
38
|
setIsValid(_.isEmpty(valid));
|
|
37
39
|
};
|
|
38
|
-
const domainId = ruleImplementation?.domain_id;
|
|
40
|
+
const domainId = conceptDomainId || ruleImplementation?.domain_id;
|
|
39
41
|
const domainActions = ["publishImplementation", "manageSegments"];
|
|
40
42
|
|
|
41
43
|
return (
|
|
@@ -82,12 +84,13 @@ export const InformationForm = ({
|
|
|
82
84
|
</label>
|
|
83
85
|
<DomainSelector
|
|
84
86
|
action={
|
|
85
|
-
|
|
86
|
-
? "
|
|
87
|
+
conceptDomainId
|
|
88
|
+
? "manageLinkedImplementations"
|
|
87
89
|
: "manageRulelessImplementations"
|
|
88
90
|
}
|
|
89
|
-
value={
|
|
91
|
+
value={domainId}
|
|
90
92
|
domainActions={domainActions}
|
|
93
|
+
domainIds={domainIds}
|
|
91
94
|
onLoad={(data) => onDomainsLoad(data.domains)}
|
|
92
95
|
onChange={(_e, { value }) => onChange("domain_id", value)}
|
|
93
96
|
labels
|
|
@@ -120,6 +123,8 @@ InformationForm.propTypes = {
|
|
|
120
123
|
setImplementationKey: PropTypes.func,
|
|
121
124
|
setIsValid: PropTypes.func,
|
|
122
125
|
onDomainsLoad: PropTypes.func,
|
|
126
|
+
conceptDomainId: PropTypes.array,
|
|
127
|
+
domainIds: PropTypes.array,
|
|
123
128
|
};
|
|
124
129
|
|
|
125
130
|
export default InformationForm;
|
|
@@ -41,12 +41,15 @@ RuleImplementationStep.propTypes = {
|
|
|
41
41
|
activeStep: PropTypes.string,
|
|
42
42
|
name: PropTypes.string,
|
|
43
43
|
icon: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
|
44
|
+
disabled: PropTypes.bool,
|
|
44
45
|
};
|
|
45
46
|
|
|
46
47
|
export const RuleImplementationForm = ({
|
|
47
48
|
addPopulation,
|
|
48
49
|
addSegment,
|
|
49
50
|
addValidation,
|
|
51
|
+
conceptDomainId,
|
|
52
|
+
domainIds,
|
|
50
53
|
isSubmitting,
|
|
51
54
|
onChange,
|
|
52
55
|
onSubmit,
|
|
@@ -342,6 +345,8 @@ export const RuleImplementationForm = ({
|
|
|
342
345
|
onChange,
|
|
343
346
|
ruleImplementation,
|
|
344
347
|
setImplementationKey,
|
|
348
|
+
conceptDomainId,
|
|
349
|
+
domainIds,
|
|
345
350
|
setIsValid: setContentIsValid,
|
|
346
351
|
onDomainsLoad: (domains) => {
|
|
347
352
|
setDomains(domains);
|
|
@@ -505,6 +510,8 @@ RuleImplementationForm.propTypes = {
|
|
|
505
510
|
addValidation: PropTypes.func,
|
|
506
511
|
addSegment: PropTypes.func,
|
|
507
512
|
authManageSegments: PropTypes.bool,
|
|
513
|
+
conceptDomainId: PropTypes.number,
|
|
514
|
+
domainIds: PropTypes.array,
|
|
508
515
|
isAdmin: PropTypes.bool,
|
|
509
516
|
isSubmitting: PropTypes.bool,
|
|
510
517
|
onChange: PropTypes.func,
|
|
@@ -519,9 +526,7 @@ RuleImplementationForm.propTypes = {
|
|
|
519
526
|
};
|
|
520
527
|
|
|
521
528
|
const mapStateToProps = ({ ruleImplementationCreating }) => {
|
|
522
|
-
return {
|
|
523
|
-
isSubmitting: ruleImplementationCreating,
|
|
524
|
-
};
|
|
529
|
+
return { isSubmitting: ruleImplementationCreating };
|
|
525
530
|
};
|
|
526
531
|
|
|
527
532
|
export default connect(mapStateToProps)(RuleImplementationForm);
|
|
@@ -2,7 +2,7 @@ import _ from "lodash/fp";
|
|
|
2
2
|
import React, { useState, useEffect } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import { connect } from "react-redux";
|
|
5
|
-
import { useHistory } from "react-router-dom";
|
|
5
|
+
import { useHistory, useLocation } from "react-router-dom";
|
|
6
6
|
import { FormattedMessage, useIntl } from "react-intl";
|
|
7
7
|
import { gql, useQuery } from "@apollo/client";
|
|
8
8
|
import { Loading } from "@truedat/core/components";
|
|
@@ -26,6 +26,12 @@ const DomainActionsLoader = ({ id, actions, onLoad }) => {
|
|
|
26
26
|
return null;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
DomainActionsLoader.propTypes = {
|
|
30
|
+
id: PropTypes.number,
|
|
31
|
+
actions: PropTypes.array,
|
|
32
|
+
onLoad: PropTypes.func,
|
|
33
|
+
};
|
|
34
|
+
|
|
29
35
|
const Help = ({ message }) => {
|
|
30
36
|
const { formatMessage } = useIntl();
|
|
31
37
|
return (
|
|
@@ -45,6 +51,8 @@ Help.propTypes = {
|
|
|
45
51
|
};
|
|
46
52
|
|
|
47
53
|
export const RuleImplementationRawForm = ({
|
|
54
|
+
conceptDomainId,
|
|
55
|
+
domainIds,
|
|
48
56
|
implementationKey,
|
|
49
57
|
isSubmitting,
|
|
50
58
|
onChange,
|
|
@@ -57,9 +65,11 @@ export const RuleImplementationRawForm = ({
|
|
|
57
65
|
sources,
|
|
58
66
|
sourcesLoading,
|
|
59
67
|
}) => {
|
|
60
|
-
const domainActions = ["publishImplementation"];
|
|
61
68
|
const { formatMessage } = useIntl();
|
|
62
69
|
const history = useHistory();
|
|
70
|
+
|
|
71
|
+
const domainActions = ["publishImplementation"];
|
|
72
|
+
|
|
63
73
|
const [isContentValid, setIsContentValid] = useState();
|
|
64
74
|
|
|
65
75
|
const [domains, setDomains] = useState();
|
|
@@ -172,7 +182,8 @@ export const RuleImplementationRawForm = ({
|
|
|
172
182
|
|
|
173
183
|
const doCancel = () => history.goBack();
|
|
174
184
|
const errors = getErrors();
|
|
175
|
-
const domainId =
|
|
185
|
+
const domainId =
|
|
186
|
+
conceptDomainId || ruleImplementation?.domain_id || rule?.domain_id;
|
|
176
187
|
return (
|
|
177
188
|
<Form className="rule">
|
|
178
189
|
<Form.Radio
|
|
@@ -202,12 +213,13 @@ export const RuleImplementationRawForm = ({
|
|
|
202
213
|
<Form.Field>
|
|
203
214
|
<DomainSelector
|
|
204
215
|
action={
|
|
205
|
-
|
|
206
|
-
? "
|
|
216
|
+
conceptDomainId
|
|
217
|
+
? "manageLinkedRawImplementations"
|
|
207
218
|
: "manageRawRulelessImplementations"
|
|
208
219
|
}
|
|
209
|
-
value={
|
|
220
|
+
value={domainId}
|
|
210
221
|
domainActions={domainActions}
|
|
222
|
+
domainIds={domainIds}
|
|
211
223
|
onLoad={(data) => setDomains(data.domains)}
|
|
212
224
|
onChange={(_e, { value }) => onChange("domain_id", value)}
|
|
213
225
|
labels
|
|
@@ -371,6 +383,8 @@ export const RuleImplementationRawForm = ({
|
|
|
371
383
|
};
|
|
372
384
|
|
|
373
385
|
RuleImplementationRawForm.propTypes = {
|
|
386
|
+
conceptDomainId: PropTypes.number,
|
|
387
|
+
domainIds: PropTypes.array,
|
|
374
388
|
implementationKey: PropTypes.string,
|
|
375
389
|
isSubmitting: PropTypes.bool,
|
|
376
390
|
onChange: PropTypes.func,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./useConcept";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { compile } from "path-to-regexp";
|
|
2
|
+
import useSWR from "swr";
|
|
3
|
+
import { API_BUSINESS_CONCEPT_VERSION } from "@truedat/bg/concepts/api";
|
|
4
|
+
import { apiJson } from "@truedat/core/services/api";
|
|
5
|
+
|
|
6
|
+
const toApiPath = compile(API_BUSINESS_CONCEPT_VERSION);
|
|
7
|
+
|
|
8
|
+
export const useConcept = (business_concept_id, id) => {
|
|
9
|
+
const url = toApiPath({ business_concept_id, id });
|
|
10
|
+
const { data, error } = useSWR(url, apiJson);
|
|
11
|
+
const concept = data?.data;
|
|
12
|
+
return { concept, error, loading: !error && !data };
|
|
13
|
+
};
|
package/src/messages/en.js
CHANGED
|
@@ -3,6 +3,7 @@ export default {
|
|
|
3
3
|
"alert.createExecutionGroup.success.content":
|
|
4
4
|
"{count} implementations queued for execution",
|
|
5
5
|
"alert.createExecutionGroup.success.header": "Executions scheduled",
|
|
6
|
+
"alert.createImplementationConcept.failed.header": "Error linking to concept",
|
|
6
7
|
"alert.createImplementationStructure.failed.header":
|
|
7
8
|
"Error linking to structure",
|
|
8
9
|
"alert.createRule.failed.header": "Error creating rule",
|
|
@@ -15,6 +16,7 @@ export default {
|
|
|
15
16
|
"alert.updateRuleImplementation.failed.header":
|
|
16
17
|
"Error updating implementation",
|
|
17
18
|
"concepts.rules.empty": "This concept has no quality rules",
|
|
19
|
+
"concepts.implementations.empty": "This concept has no implementations",
|
|
18
20
|
"createImplementationStructure.error.implementation_id.has already been taken":
|
|
19
21
|
"A link with same structure and type already exists",
|
|
20
22
|
"createRule.error.domain_id.required": "Domain is required",
|
package/src/messages/es.js
CHANGED
|
@@ -3,6 +3,7 @@ export default {
|
|
|
3
3
|
"alert.createExecutionGroup.success.content":
|
|
4
4
|
"Se ha solicitado la ejecución de {count} implementaciones",
|
|
5
5
|
"alert.createExecutionGroup.success.header": "Ejecuciones programadas",
|
|
6
|
+
"alert.createImplementationConcept.failed.header": "Error al vincular con el concepto",
|
|
6
7
|
"alert.createImplementationStructure.failed.header":
|
|
7
8
|
"Error al vincular con estructura",
|
|
8
9
|
"alert.createRule.failed.header": "Error creando regla",
|
|
@@ -15,6 +16,7 @@ export default {
|
|
|
15
16
|
"alert.updateRuleImplementation.failed.header":
|
|
16
17
|
"Error actualizando implementación",
|
|
17
18
|
"concepts.rules.empty": "Ese concepto no tiene reglas de calidad",
|
|
19
|
+
"concepts.implementations.empty": "Ese concepto no tiene implementaciones",
|
|
18
20
|
"createImplementationStructure.error.implementation_id.has already been taken":
|
|
19
21
|
"Una relación con misma estructura y tipo ya existe",
|
|
20
22
|
"createRule.error.domain_id.required": "Dominio es requerido",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
2
|
import { dismissAlert } from "@truedat/core/routines";
|
|
3
3
|
import {
|
|
4
|
+
createRuleImplementation,
|
|
4
5
|
uploadRules,
|
|
5
6
|
uploadImplementations,
|
|
6
7
|
uploadResults,
|
|
@@ -14,6 +15,17 @@ const dqMessage = (state = initialState, { type, payload }) => {
|
|
|
14
15
|
switch (type) {
|
|
15
16
|
case dismissAlert.TRIGGER:
|
|
16
17
|
return initialState;
|
|
18
|
+
case createRuleImplementation.FAILURE:
|
|
19
|
+
if (payload.status != 500 && payload.message) {
|
|
20
|
+
return {
|
|
21
|
+
error: true,
|
|
22
|
+
header: "alert.createImplementationConcept.failed.header",
|
|
23
|
+
icon: "attention",
|
|
24
|
+
text: "",
|
|
25
|
+
};
|
|
26
|
+
} else {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
17
29
|
case uploadRules.SUCCESS:
|
|
18
30
|
const messages = _.has("errors")(payload.data)
|
|
19
31
|
? _.flow(
|
|
@@ -26,10 +26,19 @@ export const ruleImplementationRedirect = (
|
|
|
26
26
|
return initialState;
|
|
27
27
|
case createRuleImplementation.SUCCESS: {
|
|
28
28
|
const id = payload?.data?.id;
|
|
29
|
-
return
|
|
29
|
+
return payload?.redirectUrl
|
|
30
|
+
? payload.redirectUrl
|
|
31
|
+
: id
|
|
30
32
|
? linkTo.IMPLEMENTATION({ implementation_id: id })
|
|
31
33
|
: linkTo.IMPLEMENTATIONS();
|
|
32
34
|
}
|
|
35
|
+
case createRuleImplementation.FAILURE: {
|
|
36
|
+
return payload?.implementation_id
|
|
37
|
+
? linkTo.IMPLEMENTATION_CONCEPT_LINKS({
|
|
38
|
+
implementation_id: payload?.implementation_id,
|
|
39
|
+
})
|
|
40
|
+
: state;
|
|
41
|
+
}
|
|
33
42
|
case createImplementationStructure.SUCCESS: {
|
|
34
43
|
return payload?.redirectUrl;
|
|
35
44
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { testSaga } from "redux-saga-test-plan";
|
|
2
2
|
import { apiJsonPost, JSON_OPTS } from "@truedat/core/services/api";
|
|
3
|
+
import { API_RELATIONS } from "@truedat/lm/api";
|
|
3
4
|
import {
|
|
4
5
|
createRuleImplementationRequestSaga,
|
|
5
6
|
createRuleImplementationSaga,
|
|
@@ -53,8 +54,20 @@ describe("sagas: createRuleImplementationSaga", () => {
|
|
|
53
54
|
],
|
|
54
55
|
rule_id: 1,
|
|
55
56
|
};
|
|
57
|
+
|
|
58
|
+
const relation = {
|
|
59
|
+
context: {},
|
|
60
|
+
source_id: 2,
|
|
61
|
+
source_type: "implementation_ref",
|
|
62
|
+
target_id: 1,
|
|
63
|
+
target_type: "business_concept",
|
|
64
|
+
tag_ids: [],
|
|
65
|
+
};
|
|
66
|
+
|
|
56
67
|
const data = { rule_implementation };
|
|
68
|
+
const relationData = { relation };
|
|
57
69
|
const url = API_RULE_IMPLEMENTATIONS;
|
|
70
|
+
const relationsUrl = API_RELATIONS;
|
|
58
71
|
const payload = { rule_implementation };
|
|
59
72
|
|
|
60
73
|
it("should encode request content and put a success action when a response is returned", () => {
|
|
@@ -67,7 +80,7 @@ describe("sagas: createRuleImplementationSaga", () => {
|
|
|
67
80
|
.next(rule_implementation)
|
|
68
81
|
.call(apiJsonPost, url, data, JSON_OPTS)
|
|
69
82
|
.next({ data })
|
|
70
|
-
.put(createRuleImplementation.success(data))
|
|
83
|
+
.put(createRuleImplementation.success({ data, redirectUrl: undefined }))
|
|
71
84
|
.next()
|
|
72
85
|
.put(clearStructure.trigger())
|
|
73
86
|
.next()
|
|
@@ -97,4 +110,29 @@ describe("sagas: createRuleImplementationSaga", () => {
|
|
|
97
110
|
.isDone();
|
|
98
111
|
}).not.toThrow();
|
|
99
112
|
});
|
|
113
|
+
|
|
114
|
+
it("should encode request and call relation if have conceptId and redirectUrl", () => {
|
|
115
|
+
const redirectUrl = "/concepts/1/versions/2/links/implementations";
|
|
116
|
+
const payload = { rule_implementation, conceptId: 1, redirectUrl };
|
|
117
|
+
|
|
118
|
+
expect(() => {
|
|
119
|
+
testSaga(createRuleImplementationSaga, { payload })
|
|
120
|
+
.next()
|
|
121
|
+
.put(createRuleImplementation.request())
|
|
122
|
+
.next()
|
|
123
|
+
.call(encodeRawContent, rule_implementation)
|
|
124
|
+
.next(rule_implementation)
|
|
125
|
+
.call(apiJsonPost, url, data, JSON_OPTS)
|
|
126
|
+
.next({ data })
|
|
127
|
+
// .call(apiJsonPost, relationsUrl, relationData, JSON_OPTS)
|
|
128
|
+
.next()
|
|
129
|
+
.put(createRuleImplementation.success({ data, redirectUrl }))
|
|
130
|
+
.next()
|
|
131
|
+
.put(clearStructure.trigger())
|
|
132
|
+
.next()
|
|
133
|
+
.put(createRuleImplementation.fulfill())
|
|
134
|
+
.next()
|
|
135
|
+
.isDone();
|
|
136
|
+
}).not.toThrow();
|
|
137
|
+
});
|
|
100
138
|
});
|
|
@@ -1,23 +1,51 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
1
2
|
import { call, put, takeLatest } from "redux-saga/effects";
|
|
2
3
|
import { apiJsonPost, JSON_OPTS } from "@truedat/core/services/api";
|
|
4
|
+
import { API_RELATIONS } from "@truedat/lm/api";
|
|
3
5
|
import { createRuleImplementation, clearStructure } from "../routines";
|
|
4
6
|
import { API_RULE_IMPLEMENTATIONS } from "../api";
|
|
5
7
|
import { encodeRawContent } from "../services/encodeRawContent";
|
|
6
8
|
|
|
7
9
|
export function* createRuleImplementationSaga({ payload }) {
|
|
8
10
|
try {
|
|
9
|
-
const { rule_implementation } = payload;
|
|
11
|
+
const { rule_implementation, redirectUrl, conceptId } = payload;
|
|
10
12
|
const url = API_RULE_IMPLEMENTATIONS;
|
|
11
13
|
yield put(createRuleImplementation.request());
|
|
12
14
|
const encoded = yield call(encodeRawContent, rule_implementation);
|
|
13
15
|
const requestData = { rule_implementation: encoded };
|
|
14
16
|
const { data } = yield call(apiJsonPost, url, requestData, JSON_OPTS);
|
|
15
|
-
|
|
17
|
+
if (conceptId && redirectUrl) {
|
|
18
|
+
const relationsUrl = API_RELATIONS;
|
|
19
|
+
const relation = {
|
|
20
|
+
context: {},
|
|
21
|
+
source_id: data?.data?.implementation_ref,
|
|
22
|
+
source_type: "implementation_ref",
|
|
23
|
+
target_id: conceptId,
|
|
24
|
+
target_type: "business_concept",
|
|
25
|
+
tag_ids: [],
|
|
26
|
+
};
|
|
27
|
+
const relationData = { relation };
|
|
28
|
+
yield call(apiJsonPost, relationsUrl, relationData, JSON_OPTS);
|
|
29
|
+
}
|
|
30
|
+
yield put(createRuleImplementation.success({ data, redirectUrl }));
|
|
16
31
|
yield put(clearStructure.trigger());
|
|
17
32
|
} catch (error) {
|
|
18
33
|
if (error.response) {
|
|
19
34
|
const { status, data } = error.response;
|
|
20
|
-
|
|
35
|
+
const responseURL = error.response?.request?.responseURL;
|
|
36
|
+
if (_.includes("/api/relations")(responseURL)) {
|
|
37
|
+
const { relation } = JSON.parse(error.config.data);
|
|
38
|
+
yield put(
|
|
39
|
+
createRuleImplementation.failure({
|
|
40
|
+
status,
|
|
41
|
+
data,
|
|
42
|
+
message: "ruleImplementation.linkConcept.failed",
|
|
43
|
+
implementation_id: relation.source_id,
|
|
44
|
+
})
|
|
45
|
+
);
|
|
46
|
+
} else {
|
|
47
|
+
yield put(createRuleImplementation.failure({ status, data }));
|
|
48
|
+
}
|
|
21
49
|
} else {
|
|
22
50
|
yield put(createRuleImplementation.failure(error.message));
|
|
23
51
|
}
|