@truedat/dq 4.44.2 → 4.44.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 (48) hide show
  1. package/CHANGELOG.md +8 -1
  2. package/package.json +5 -5
  3. package/src/components/EditRule.js +1 -1
  4. package/src/components/ExecutionForm.js +68 -78
  5. package/src/components/ExecutionPopup.js +10 -6
  6. package/src/components/NewRule.js +1 -1
  7. package/src/components/NewRuleImplementation.js +91 -111
  8. package/src/components/RemediationForm.js +32 -43
  9. package/src/components/RuleForm.js +102 -103
  10. package/src/components/RuleImplementation.js +29 -13
  11. package/src/components/RuleImplementationActions.js +11 -21
  12. package/src/components/RuleImplementationsActions.js +1 -1
  13. package/src/components/RuleResultsRoutes.js +41 -56
  14. package/src/components/RuleRoutes.js +40 -56
  15. package/src/components/RulesRoutes.js +0 -5
  16. package/src/components/__tests__/ExecutionForm.spec.js +7 -1
  17. package/src/components/__tests__/ExecutionPopup.spec.js +3 -2
  18. package/src/components/__tests__/ImplementationResultBar.spec.js +44 -63
  19. package/src/components/__tests__/InformationSummary.spec.js +2 -6
  20. package/src/components/__tests__/NewRuleImplementation.spec.js +4 -6
  21. package/src/components/__tests__/RemediationForm.spec.js +47 -58
  22. package/src/components/__tests__/RuleForm.spec.js +80 -207
  23. package/src/components/__tests__/RuleImplementation.spec.js +45 -22
  24. package/src/components/__tests__/RuleImplementationsActions.spec.js +0 -1
  25. package/src/components/__tests__/RuleImplementationsOptions.spec.js +1 -10
  26. package/src/components/__tests__/RuleResultsUpload.spec.js +1 -5
  27. package/src/components/__tests__/RuleSummary.spec.js +6 -11
  28. package/src/components/__tests__/__snapshots__/EditRule.spec.js.snap +1 -1
  29. package/src/components/__tests__/__snapshots__/ExecutionForm.spec.js.snap +1 -2
  30. package/src/components/__tests__/__snapshots__/NewRule.spec.js.snap +1 -1
  31. package/src/components/__tests__/__snapshots__/RemediationForm.spec.js.snap +2 -3
  32. package/src/components/__tests__/__snapshots__/RuleForm.spec.js.snap +699 -385
  33. package/src/components/__tests__/__snapshots__/RuleImplementation.spec.js.snap +71 -5
  34. package/src/components/__tests__/__snapshots__/RuleImplementationsActions.spec.js.snap +1 -1
  35. package/src/components/index.js +0 -2
  36. package/src/components/ruleImplementationForm/InformationForm.js +40 -76
  37. package/src/components/ruleImplementationForm/RuleImplementationForm.js +40 -40
  38. package/src/components/ruleImplementationForm/RuleImplementationRawForm.js +63 -101
  39. package/src/components/ruleImplementationForm/__tests__/LimitsForm.spec.js +9 -35
  40. package/src/components/ruleImplementationForm/__tests__/RuleImplementationForm.spec.js +23 -50
  41. package/src/components/ruleImplementationForm/__tests__/RuleImplementationRawForm.spec.js +2 -2
  42. package/src/components/ruleImplementationForm/__tests__/__snapshots__/RuleImplementationForm.spec.js.snap +86 -19
  43. package/src/components/ruleImplementationForm/__tests__/__snapshots__/RuleImplementationRawForm.spec.js.snap +7 -1
  44. package/src/messages/en.js +3 -6
  45. package/src/messages/es.js +3 -6
  46. package/src/components/DynamicRuleForm.js +0 -78
  47. package/src/components/__tests__/DynamicRuleForm.spec.js +0 -51
  48. package/src/components/__tests__/__snapshots__/DynamicRuleForm.spec.js.snap +0 -3
@@ -6,20 +6,16 @@ import { applyTemplate, validateContent } from "@truedat/df/utils";
6
6
  import { connect } from "react-redux";
7
7
  import { useParams } from "react-router-dom";
8
8
  import { Button, Form } from "semantic-ui-react";
9
+ import { TemplateSelector } from "@truedat/core/components";
9
10
  import { createRemediation, updateRemediation } from "../routines";
10
11
 
11
12
  const DynamicForm = React.lazy(() =>
12
13
  import("@truedat/df/components/DynamicForm")
13
14
  );
14
15
 
15
- const TemplateSelector = React.lazy(() =>
16
- import("@truedat/df/templates/components/TemplateSelector")
17
- );
18
-
19
16
  export const RemediationForm = ({
20
17
  createRemediation,
21
18
  updateRemediation,
22
- templates,
23
19
  remediation,
24
20
  onSave,
25
21
  latestResultId,
@@ -36,8 +32,18 @@ export const RemediationForm = ({
36
32
  const isValidContent = _.flow(validateContent(template), _.isEmpty);
37
33
  const isValid = _.has("name")(template) && isValidContent(content);
38
34
 
39
- const handleTemplateSelected = (e, { value }) => {
40
- setTemplate(_.find({ id: value }, templates));
35
+ const handleTemplatesLoaded = ({ templates }) => {
36
+ const name = remediation?.df_name;
37
+ const template = name
38
+ ? _.find(_.propEq("name", name))(templates)
39
+ : _.size(templates) == 1
40
+ ? templates[0]
41
+ : null;
42
+ setTemplate(template);
43
+ };
44
+
45
+ const handleTemplateSelected = (e, { template }) => {
46
+ setTemplate(template);
41
47
  };
42
48
 
43
49
  const handleContentChange = (content) => {
@@ -63,41 +69,29 @@ export const RemediationForm = ({
63
69
  };
64
70
 
65
71
  useEffect(() => {
66
- _.flow(
67
- _.cond([
68
- [(templates) => _.size(templates) === 1, _.head],
69
- [
70
- () => !_.isEmpty(remediation),
71
- _.find(_.propEq("name")(remediation?.df_name)),
72
- ],
73
- ]),
74
- (template) => {
75
- setTemplate(template);
76
- return template;
77
- },
78
- (template) => applyTemplate(template)(remediation?.df_content),
79
- setContent
80
- )(templates);
81
- }, [remediation, templates]);
72
+ const content =
73
+ template && remediation?.df_content
74
+ ? applyTemplate(template)(remediation.df_content)
75
+ : null;
76
+ setContent(content);
77
+ }, [remediation, template]);
82
78
 
83
79
  return (
84
80
  <Form aria-label="remediation-form">
85
- {_.size(templates) > 1 && (
86
- <TemplateSelector
87
- name="template"
88
- selectedValue={_.prop("id")(template)}
89
- onChange={handleTemplateSelected}
90
- />
91
- )}
92
-
93
- {!template ? null : (
81
+ <TemplateSelector
82
+ scope="remediation"
83
+ selectedValue={template?.id}
84
+ onChange={handleTemplateSelected}
85
+ onLoad={handleTemplatesLoaded}
86
+ required
87
+ />
88
+ {template ? (
94
89
  <DynamicForm
95
90
  template={template}
96
91
  onChange={handleContentChange}
97
92
  content={content || {}}
98
93
  />
99
- )}
100
-
94
+ ) : null}
101
95
  <Button
102
96
  primary
103
97
  disabled={!isValid}
@@ -112,18 +106,13 @@ export const RemediationForm = ({
112
106
 
113
107
  RemediationForm.propTypes = {
114
108
  createRemediation: PropTypes.func.isRequired,
115
- updateRemediation: PropTypes.func,
116
- templates: PropTypes.array,
117
- remediation: PropTypes.object,
118
- onSave: PropTypes.func,
119
109
  latestResultId: PropTypes.number,
110
+ onSave: PropTypes.func,
111
+ remediation: PropTypes.object,
112
+ updateRemediation: PropTypes.func,
120
113
  };
121
114
 
122
- const mapStateToProps = ({ templates }) => ({
123
- templates,
124
- });
125
-
126
- export default connect(mapStateToProps, {
115
+ export default connect(null, {
127
116
  createRemediation,
128
117
  updateRemediation,
129
118
  })(RemediationForm);
@@ -1,7 +1,7 @@
1
1
  import _ from "lodash/fp";
2
2
  import React from "react";
3
3
  import PropTypes from "prop-types";
4
- import { injectIntl } from "react-intl";
4
+ import { FormattedMessage, injectIntl } from "react-intl";
5
5
  import { connect } from "react-redux";
6
6
  import { withRouter } from "react-router-dom";
7
7
  import { compose } from "redux";
@@ -16,11 +16,10 @@ import {
16
16
  Popup,
17
17
  Icon,
18
18
  } from "semantic-ui-react";
19
- import { HistoryBackButton } from "@truedat/core/components";
19
+ import { HistoryBackButton, TemplateSelector } from "@truedat/core/components";
20
20
  import { applyTemplate } from "@truedat/df/utils";
21
21
  import { selectDomain } from "@truedat/df/routines";
22
22
  import { getDomainSelectorOptions } from "@truedat/bg/selectors";
23
- import DynamicRuleForm from "./DynamicRuleForm";
24
23
 
25
24
  const DomainDropdownSelector = React.lazy(() =>
26
25
  import("@truedat/bg/taxonomy/components/DomainDropdownSelector")
@@ -34,6 +33,10 @@ const ConceptSelector = React.lazy(() =>
34
33
  import("@truedat/bg/concepts/relations/components/ConceptSelector")
35
34
  );
36
35
 
36
+ const DynamicForm = React.lazy(() =>
37
+ import("@truedat/df/components/DynamicForm")
38
+ );
39
+
37
40
  export const FieldLabelWrapping = ({
38
41
  children,
39
42
  label,
@@ -44,8 +47,8 @@ export const FieldLabelWrapping = ({
44
47
  <Form.Field>
45
48
  <label className="rule-form-label">
46
49
  {label}
47
- {required && <span>*</span>}
48
- {tooltip && (
50
+ {required ? <span>*</span> : null}
51
+ {tooltip ? (
49
52
  <Popup
50
53
  trigger={
51
54
  <Icon className="rule-form-popup" name="question circle outline" />
@@ -54,9 +57,9 @@ export const FieldLabelWrapping = ({
54
57
  on="click"
55
58
  hideOnScroll
56
59
  />
57
- )}
58
- {messages.map((msg, idx) => (
59
- <Label key={idx} pointing="left">
60
+ ) : null}
61
+ {messages.map((msg, key) => (
62
+ <Label key={key} pointing="left">
60
63
  {msg}
61
64
  </Label>
62
65
  ))}
@@ -88,11 +91,12 @@ export class RuleForm extends React.Component {
88
91
  type_params: {},
89
92
  df_name: "",
90
93
  df_content: {},
94
+ template: null,
95
+ templatesLoading: true,
91
96
  };
92
97
 
93
98
  componentDidMount() {
94
99
  const { rule, concept, selectDomain } = this.props;
95
- const isConceptPreselected = concept !== undefined;
96
100
  const description = rule ? _.propOr({}, "description")(rule) : {};
97
101
  if (rule) {
98
102
  !_.isNil(rule.domain_id) && selectDomain({ id: rule.domain_id });
@@ -102,35 +106,45 @@ export class RuleForm extends React.Component {
102
106
  name: rule?.current_business_concept_version?.name,
103
107
  business_concept_id: rule.business_concept_id,
104
108
  },
105
- isConceptPreselected,
106
109
  });
107
- } else if (_.negate(_.isEmpty)(concept)) {
110
+ } else if (!_.isEmpty(concept)) {
108
111
  !_.isNil(concept.domain.id) && selectDomain({ id: concept.domain.id });
109
- this.setState({
110
- concept,
111
- isConceptPreselected,
112
- });
112
+ this.setState({ concept });
113
113
  }
114
114
 
115
115
  this.updateDescription(description);
116
116
  }
117
117
 
118
- componentDidUpdate(prevProps) {
119
- const { applyTemplate, selectDomain, template, rule } = this.props;
120
- const { domain_id } = this.state;
118
+ updateRule = (rule) => {
119
+ this.setState({ ...rule });
120
+ };
121
121
 
122
- if (!_.isEmpty(template) && !_.eq(prevProps.template, template)) {
123
- this.setState({
124
- type: _.prop("name")(template),
125
- df_content: applyTemplate(rule?.df_content, domain_id),
126
- });
127
- selectDomain({ id: domain_id });
128
- }
129
- }
122
+ handleTemplateChange = (template) => {
123
+ const { domain_id, df_content } = this.state;
124
+ this.setState({
125
+ template,
126
+ df_name: template?.name || null,
127
+ df_content: template
128
+ ? applyTemplate(template)(df_content, domain_id)
129
+ : null,
130
+ });
131
+ };
130
132
 
131
- updateRule = (rule) => this.setState({ ...rule });
133
+ handleTemplatesLoaded = ({ templates }) => {
134
+ const name = this.props.rule?.df_name;
135
+ const template = name
136
+ ? _.find(_.propEq("name", name))(templates)
137
+ : _.size(templates) == 1
138
+ ? templates[0]
139
+ : null;
140
+ this.setState({ template, templatesLoading: false });
141
+ };
142
+
143
+ handleTemplateSelected = (e, { template }) => {
144
+ this.setState({ template });
145
+ };
132
146
 
133
- handleDfContentChange = (df_content) => this.setState({ df_content });
147
+ handleContentChange = (df_content) => this.setState({ df_content });
134
148
 
135
149
  messagesInformed = (messages) => _.some(_.negate(_.isNil))(messages);
136
150
 
@@ -165,49 +179,37 @@ export class RuleForm extends React.Component {
165
179
  handleSubmit = (e) => {
166
180
  e.preventDefault();
167
181
  if (this.messagesInformed(this.generateValidationMessages())) return;
168
- const { applyTemplate, template, handleSubmit, match, editMode } =
169
- this.props;
170
-
171
- const fieldsToOmit = ["concept"];
172
- if (editMode) fieldsToOmit.push("rule_type_id");
173
- const rule = _.flow(this.withConceptId, _.omit(fieldsToOmit))(this.state);
174
- const df_content = applyTemplate(rule?.df_content, rule?.domain_id);
182
+ const { onSubmit, match } = this.props;
183
+ // eslint-disable-next-line no-unused-vars
184
+ const { template, concept, templatesLoading, ...rule } = this.state;
185
+ const df_content = template
186
+ ? applyTemplate(template)(rule?.df_content, rule?.domain_id)
187
+ : null;
175
188
 
176
- handleSubmit({
177
- rule: {
178
- ...rule,
179
- df_name: template.name,
180
- df_content,
181
- },
189
+ onSubmit({
190
+ rule: { ...rule, df_content },
182
191
  ids: match.params,
183
192
  });
184
193
  };
185
194
 
186
- withConceptId = (rule) => {
187
- const business_concept_id = _.negate(_.isNil)(
188
- _.path("concept.business_concept_id")(rule)
189
- )
190
- ? _.path("concept.business_concept_id")(rule).toString()
191
- : null;
192
- return { ...rule, business_concept_id };
193
- };
194
-
195
195
  handleConceptSelected = (concept) => {
196
- this.setState({ concept });
196
+ this.setState({
197
+ concept,
198
+ business_concept_id: concept?.business_concept_id || null,
199
+ });
197
200
  concept && this.handleSelectionClick();
198
201
  };
199
202
 
200
203
  handleDomainSelected = (e, { value }) => {
201
204
  const domain_id = value;
202
-
203
205
  const { selectDomain, editMode } = this.props;
204
206
  !_.isString(domain_id) && selectDomain({ id: domain_id });
205
- const concept =
206
- this.state.isConceptPreselected && !editMode ? this.state.concept : null;
207
- this.setState({
208
- concept,
209
- domain_id,
210
- });
207
+
208
+ this.setState(
209
+ editMode
210
+ ? { concept: null, business_concept_id: null, domain_id }
211
+ : { domain_id }
212
+ );
211
213
  };
212
214
 
213
215
  handleSelectionClick = () => {
@@ -237,10 +239,9 @@ export class RuleForm extends React.Component {
237
239
  render() {
238
240
  const {
239
241
  isSubmitting,
240
- templatesLoaded,
241
242
  intl: { formatMessage },
242
243
  } = this.props;
243
- const rule = this.state;
244
+ const { template, ...rule } = this.state;
244
245
  const { domain_id } = rule;
245
246
  const { concept, domainOptions } = this.props;
246
247
  const messages = this.generateValidationMessages();
@@ -270,6 +271,7 @@ export class RuleForm extends React.Component {
270
271
  required
271
272
  >
272
273
  <Form.Input
274
+ aria-label={formatMessage({ id: "rule.props.name.placeholder" })}
273
275
  name="name"
274
276
  onChange={this.handleChange}
275
277
  value={rule.name}
@@ -288,30 +290,30 @@ export class RuleForm extends React.Component {
288
290
  onChange={this.handleEditorChange}
289
291
  />
290
292
  )}
291
- <FieldLabelWrapping
292
- label={formatMessage({ id: "domain.selector.label" })}
293
- messages={_.prop("domain")(messages)}
294
- required
295
- >
296
- <DomainDropdownSelector
297
- name="domain"
298
- domainOptions={
299
- domainOptions
300
- ? getDomainSelectorOptions({ domains: domainOptions })
301
- : null
302
- }
303
- hideLabel
304
- invalid={!_.isFinite(this.state.domain_id)}
305
- onChange={this.handleDomainSelected}
306
- value={this.state.domain_id}
307
- />
308
- </FieldLabelWrapping>
293
+ </FieldLabelWrapping>
294
+ <FieldLabelWrapping
295
+ label={formatMessage({ id: "domain.selector.label" })}
296
+ messages={_.prop("domain")(messages)}
297
+ required
298
+ >
299
+ <DomainDropdownSelector
300
+ name="domain"
301
+ domainOptions={
302
+ domainOptions
303
+ ? getDomainSelectorOptions({ domains: domainOptions })
304
+ : null
305
+ }
306
+ hideLabel
307
+ invalid={!_.isFinite(this.state.domain_id)}
308
+ onChange={this.handleDomainSelected}
309
+ value={this.state.domain_id}
310
+ />
309
311
  </FieldLabelWrapping>
310
312
  {_.isEmpty(concept) && (
311
313
  <Segment disabled={_.isNil(domain_id)}>
312
314
  <Form.Group inline>
313
315
  <label className="rule-form-label">
314
- {formatMessage({ id: "rule.form.concept.label" })}
316
+ <FormattedMessage id="rule.form.concept.label" />
315
317
  </label>
316
318
  {_.path("concept.name")(rule) && (
317
319
  <Label size={"medium"}>
@@ -329,34 +331,37 @@ export class RuleForm extends React.Component {
329
331
 
330
332
  <Accordion>
331
333
  <Accordion.Title
332
- active={rule.activeSelection && !_.isNil(domain_id)}
334
+ active={rule.activeSelection && !!domain_id}
333
335
  onClick={this.handleSelectionClick}
334
336
  >
335
337
  <Icon name="dropdown" />
336
- {formatMessage({ id: "rule.form.accordion.select" })}{" "}
338
+ <FormattedMessage id="rule.form.accordion.select" />
337
339
  </Accordion.Title>
338
- <Accordion.Content
339
- active={rule.activeSelection && !_.isNil(domain_id)}
340
- >
340
+ <Accordion.Content active={rule.activeSelection && !!domain_id}>
341
341
  <ConceptSelector
342
342
  showTitle={false}
343
343
  defaultFilters={defaultFilters}
344
344
  handleConceptSelected={this.handleConceptSelected}
345
- businessConceptId={_.path("concept.business_concept_id")(
346
- rule
347
- )}
345
+ businessConceptId={rule?.concept?.business_concept_id}
348
346
  />
349
347
  </Accordion.Content>
350
348
  </Accordion>
351
349
  </Segment>
352
350
  )}
353
- {!_.isNil(rule.df_content) && templatesLoaded && (
354
- <DynamicRuleForm
355
- name="dynamicForm"
356
- handleContentChange={this.handleDfContentChange}
357
- dfContent={rule.df_content}
351
+ <TemplateSelector
352
+ scope="dq"
353
+ selectedValue={template?.id}
354
+ onChange={this.handleTemplateSelected}
355
+ onLoad={this.handleTemplatesLoaded}
356
+ required
357
+ />
358
+ {template ? (
359
+ <DynamicForm
360
+ onChange={this.handleContentChange}
361
+ content={rule.df_content}
362
+ template={template}
358
363
  />
359
- )}
364
+ ) : null}
360
365
  <div className="actions">
361
366
  <HistoryBackButton
362
367
  content={formatMessage({ id: "actions.cancel" })}
@@ -385,25 +390,19 @@ export class RuleForm extends React.Component {
385
390
 
386
391
  RuleForm.propTypes = {
387
392
  concept: PropTypes.object,
388
- applyTemplate: PropTypes.func,
389
- handleSubmit: PropTypes.func.isRequired,
393
+ domainOptions: PropTypes.array,
390
394
  editMode: PropTypes.bool,
395
+ intl: PropTypes.object,
391
396
  isSubmitting: PropTypes.bool,
392
- templatesLoaded: PropTypes.bool,
397
+ match: PropTypes.object,
398
+ onSubmit: PropTypes.func.isRequired,
393
399
  rule: PropTypes.object,
394
400
  selectDomain: PropTypes.func,
395
- template: PropTypes.object,
396
- match: PropTypes.object,
397
- intl: PropTypes.object,
398
- domainOptions: PropTypes.array,
399
401
  };
400
402
 
401
403
  const mapStateToProps = (state) => ({
402
404
  isSubmitting: state.ruleCreating || state.ruleUpdating,
403
405
  concept: state.concept,
404
- templatesLoaded: !state.templatesLoading && !_.isEmpty(state.templates),
405
- template: state.template,
406
- applyTemplate: applyTemplate(state.template),
407
406
  domainOptions: _.pathOr(null, "conceptRulesActions.domain_ids")(state),
408
407
  });
409
408
 
@@ -8,9 +8,10 @@ import { Header, Label, Menu, Grid, Icon } from "semantic-ui-react";
8
8
  import { ConfirmModal, GroupActions } from "@truedat/core/components";
9
9
  import { useAuthorized } from "@truedat/core/hooks";
10
10
  import { linkTo } from "@truedat/core/routes";
11
- import { setRuleImplementationStatus } from "../routines";
11
+ import { createExecutionGroup, setRuleImplementationStatus } from "../routines";
12
12
  import RuleImplementationTabs from "./RuleImplementationTabs";
13
13
  import ImplementationResultBar from "./ImplementationResultBar";
14
+ import ExecutionPopup from "./ExecutionPopup";
14
15
 
15
16
  const getAvailableActions = (props, formatMessage) => {
16
17
  const contentActions = _.isEmpty(props?.ruleImplementation)
@@ -73,7 +74,7 @@ const getAvailableActions = (props, formatMessage) => {
73
74
  to: linkTo.IMPLEMENTATION_EDIT({
74
75
  implementation_id: _.path("ruleImplementation.id")(props),
75
76
  }),
76
- filter: props.editPermission,
77
+ filter: props.canEdit,
77
78
  selected: false,
78
79
  active: false,
79
80
  },
@@ -157,10 +158,12 @@ OptionModal.propTypes = {
157
158
 
158
159
  export const RuleImplementation = ({
159
160
  children,
161
+ createExecutionGroup,
162
+ canExecute,
160
163
  setRuleImplementationStatus,
161
164
  ruleImplementation,
162
- editPermission,
163
- managePermission,
165
+ canEdit,
166
+ canManage,
164
167
  }) => {
165
168
  const authorized = useAuthorized();
166
169
  const { formatMessage } = useIntl();
@@ -172,10 +175,16 @@ export const RuleImplementation = ({
172
175
  authorized,
173
176
  ruleImplementation,
174
177
  setRuleImplementationStatus,
175
- editPermission,
178
+ canEdit,
176
179
  },
177
180
  formatMessage
178
181
  );
182
+
183
+ const handleSubmit = (df_content) => {
184
+ const query = { filters: { id: [ruleImplementation?.id] } };
185
+ createExecutionGroup({ ...query, df_content });
186
+ };
187
+
179
188
  return (
180
189
  <>
181
190
  <Grid>
@@ -190,6 +199,9 @@ export const RuleImplementation = ({
190
199
  </Grid.Column>
191
200
  <Grid.Column width={8} textAlign="right">
192
201
  <>
202
+ {canExecute && ruleImplementation.executable ? (
203
+ <ExecutionPopup onSubmit={handleSubmit} count={1} />
204
+ ) : null}
193
205
  {deletedAt && (
194
206
  <Label
195
207
  className="alert warning"
@@ -199,7 +211,7 @@ export const RuleImplementation = ({
199
211
  icon={{ name: "warning circle", color: "red" }}
200
212
  />
201
213
  )}
202
- {managePermission && !_.isEmpty(availableActions) && (
214
+ {canManage && !_.isEmpty(availableActions) && (
203
215
  <GroupActions availableActions={availableActions} />
204
216
  )}
205
217
  </>
@@ -212,20 +224,24 @@ export const RuleImplementation = ({
212
224
  };
213
225
 
214
226
  RuleImplementation.propTypes = {
227
+ createExecutionGroup: PropTypes.func,
228
+ canExecute: PropTypes.bool,
215
229
  ruleImplementation: PropTypes.object.isRequired,
216
230
  setRuleImplementationStatus: PropTypes.func,
217
231
  ruleImplementation: PropTypes.object,
218
- editPermission: PropTypes.bool,
219
- managePermission: PropTypes.bool,
232
+ canEdit: PropTypes.bool,
233
+ canManage: PropTypes.bool,
220
234
  children: PropTypes.node,
221
235
  };
222
236
 
223
237
  const mapStateToProps = ({ ruleImplementation, implementationActions }) => ({
224
238
  ruleImplementation,
225
- editPermission: !!_.pathOr(false, "edit")(implementationActions),
226
- managePermission: !!_.pathOr(false, "manage")(implementationActions),
239
+ canExecute: !!implementationActions?.execute,
240
+ canEdit: !!implementationActions?.edit,
241
+ canManage: !!implementationActions?.manage,
227
242
  });
228
243
 
229
- export default connect(mapStateToProps, { setRuleImplementationStatus })(
230
- RuleImplementation
231
- );
244
+ export default connect(mapStateToProps, {
245
+ createExecutionGroup,
246
+ setRuleImplementationStatus,
247
+ })(RuleImplementation);
@@ -1,34 +1,31 @@
1
- import _ from "lodash/fp";
2
1
  import React from "react";
3
2
  import PropTypes from "prop-types";
4
- import { FormattedMessage } from "react-intl";
3
+ import { useIntl } from "react-intl";
5
4
  import { connect } from "react-redux";
6
5
  import { Link, useParams } from "react-router-dom";
7
6
  import { Button } from "semantic-ui-react";
8
7
  import { linkTo } from "@truedat/core/routes";
9
8
 
10
- const RuleImplementationActions = ({
11
- manageRuleImplementationAction,
12
- manageRawRuleImplementationAction,
13
- }) => {
9
+ const RuleImplementationActions = ({ canCreate, canCreateRaw }) => {
10
+ const { formatMessage } = useIntl();
14
11
  const params = useParams();
15
12
  return (
16
13
  <>
17
- {manageRawRuleImplementationAction && (
14
+ {canCreateRaw && (
18
15
  <Button
19
16
  as={Link}
20
17
  to={linkTo.RULE_IMPLEMENTATION_NEW_RAW(params)}
21
18
  className="primary_action"
22
- content={<FormattedMessage id="quality.rule.actions.create_raw" />}
19
+ content={formatMessage({ id: "quality.rule.actions.create_raw" })}
23
20
  />
24
21
  )}
25
- {manageRuleImplementationAction && (
22
+ {canCreate && (
26
23
  <Button
27
24
  primary
28
25
  as={Link}
29
26
  to={linkTo.RULE_IMPLEMENTATION_NEW(params)}
30
27
  className="primary_action"
31
- content={<FormattedMessage id="quality.rule.actions.create" />}
28
+ content={formatMessage({ id: "quality.rule.actions.create" })}
32
29
  />
33
30
  )}
34
31
  </>
@@ -36,20 +33,13 @@ const RuleImplementationActions = ({
36
33
  };
37
34
 
38
35
  RuleImplementationActions.propTypes = {
39
- manageRuleImplementationAction: PropTypes.bool,
40
- manageRawRuleImplementationAction: PropTypes.bool,
36
+ canCreate: PropTypes.bool,
37
+ canCreateRaw: PropTypes.bool,
41
38
  };
42
39
 
43
40
  const mapStateToProps = ({ userRulePermissions }) => ({
44
- userRulePermissions: userRulePermissions,
45
- manageRuleImplementationAction: _.propOr(
46
- false,
47
- "manage_quality_rule_implementations"
48
- )(userRulePermissions),
49
- manageRawRuleImplementationAction: _.propOr(
50
- false,
51
- "manage_raw_quality_rule_implementations"
52
- )(userRulePermissions),
41
+ canCreate: !!userRulePermissions?.manage_quality_rule_implementations,
42
+ canCreateRaw: !!userRulePermissions?.manage_raw_quality_rule_implementations,
53
43
  });
54
44
 
55
45
  export default connect(mapStateToProps)(RuleImplementationActions);
@@ -81,7 +81,7 @@ export const RuleImplementationsActions = ({
81
81
  ? ruleImplementationCount
82
82
  : selectedImplementations.length
83
83
  }
84
- handleSubmit={handleSubmit}
84
+ onSubmit={handleSubmit}
85
85
  />
86
86
  </>
87
87
  )}