@truedat/dq 4.34.0 → 4.34.2

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 CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## [Unreleased]
4
+
5
+ - [TD-4314] Add BulkLoad for `rules`
6
+ - [TD-4301] Add BulkLoad for `implementations`
7
+
3
8
  ## [4.34.0] 2021-12-02
4
9
 
5
10
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dq",
3
- "version": "4.34.0",
3
+ "version": "4.34.2",
4
4
  "description": "Truedat Web Data Quality Module",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -82,8 +82,8 @@
82
82
  },
83
83
  "dependencies": {
84
84
  "@apollo/client": "^3.4.10",
85
- "@truedat/core": "4.34.0",
86
- "@truedat/df": "4.34.0",
85
+ "@truedat/core": "4.34.2",
86
+ "@truedat/df": "4.34.2",
87
87
  "axios": "^0.19.2",
88
88
  "graphql": "^15.5.3",
89
89
  "path-to-regexp": "^1.7.0",
@@ -103,5 +103,5 @@
103
103
  "react-dom": ">= 16.8.6 < 17",
104
104
  "semantic-ui-react": ">= 0.88.2 < 2.1"
105
105
  },
106
- "gitHead": "b1fe4f405c612bd342510cf34e8e9d89de0280fb"
106
+ "gitHead": "8b28a5faca902e9cab3e8b5ab2bc1f8626e3ec7b"
107
107
  }
package/src/api.js CHANGED
@@ -4,6 +4,7 @@ const API_EXECUTION_GROUPS = "/api/execution_groups";
4
4
  const API_RULE = "/api/rules/:id";
5
5
  const API_RULES = "/api/rules";
6
6
  const API_RULES_SEARCH = "/api/rules/search";
7
+ const API_RULES_UPLOAD = "/api/rules/upload";
7
8
  const API_RULE_FILTERS_SEARCH = "/api/rule_filters/search";
8
9
  const API_RULE_IMPLEMENTATION = "/api/rule_implementations/:id";
9
10
  const API_RULE_IMPLEMENTATIONS = "/api/rule_implementations";
@@ -13,6 +14,7 @@ const API_RULE_IMPLEMENTATIONS_FROM_RULE =
13
14
  const API_RULE_IMPLEMENTATIONS_SEARCH = "/api/rule_implementations/search";
14
15
  const API_RULE_IMPLEMENTATION_FILTERS_SEARCH =
15
16
  "/api/rule_implementation_filters/search";
17
+ const API_RULE_IMPLEMENTATIONS_UPLOAD = "/api/rule_implementations/upload";
16
18
  const API_RULE_RESULT = "/api/rule_results/:id";
17
19
  const API_SUBSCRIPTIONS_SEARCH = "/api/subscriptions/user/me/search";
18
20
  const API_SUBSCRIPTION = "/api/subscriptions/:id";
@@ -25,6 +27,7 @@ export {
25
27
  API_RULE,
26
28
  API_RULES,
27
29
  API_RULES_SEARCH,
30
+ API_RULES_UPLOAD,
28
31
  API_RULE_FILTERS_SEARCH,
29
32
  API_RULE_IMPLEMENTATION,
30
33
  API_RULE_IMPLEMENTATIONS,
@@ -32,8 +35,9 @@ export {
32
35
  API_RULE_IMPLEMENTATIONS_FROM_RULE,
33
36
  API_RULE_IMPLEMENTATIONS_SEARCH,
34
37
  API_RULE_IMPLEMENTATION_FILTERS_SEARCH,
38
+ API_RULE_IMPLEMENTATIONS_UPLOAD,
35
39
  API_RULE_RESULT,
36
40
  API_SUBSCRIPTIONS_SEARCH,
37
41
  API_SUBSCRIPTION,
38
- API_SUBSCRIPTIONS
42
+ API_SUBSCRIPTIONS,
39
43
  };
@@ -0,0 +1,63 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import { connect } from "react-redux";
4
+ import { Button } from "semantic-ui-react";
5
+ import { FormattedMessage, useIntl } from "react-intl";
6
+ import { UploadModal } from "@truedat/core/components";
7
+ import { API_RULE_IMPLEMENTATIONS_UPLOAD } from "../api";
8
+ import { uploadImplementations } from "../routines";
9
+
10
+ const uploadAction = {
11
+ method: "POST",
12
+ href: API_RULE_IMPLEMENTATIONS_UPLOAD,
13
+ };
14
+
15
+ export const ImplementationsUploadButton = ({
16
+ uploadImplementations,
17
+ loading,
18
+ }) => {
19
+ const { formatMessage } = useIntl();
20
+ return (
21
+ <UploadModal
22
+ icon="upload"
23
+ trigger={
24
+ <Button
25
+ secondary
26
+ floated="right"
27
+ icon="upload"
28
+ loading={loading}
29
+ data-tooltip={formatMessage({
30
+ id: "ruleImplementations.actions.upload.tooltip",
31
+ })}
32
+ />
33
+ }
34
+ header={
35
+ <FormattedMessage id="ruleImplementations.actions.upload.confirmation.header" />
36
+ }
37
+ content={
38
+ <FormattedMessage id="ruleImplementations.actions.upload.confirmation.content" />
39
+ }
40
+ param={"implementations"}
41
+ handleSubmit={(data) =>
42
+ uploadImplementations({
43
+ action: "upload",
44
+ data,
45
+ ...uploadAction,
46
+ })
47
+ }
48
+ />
49
+ );
50
+ };
51
+
52
+ ImplementationsUploadButton.propTypes = {
53
+ uploadImplementations: PropTypes.func,
54
+ loading: PropTypes.bool,
55
+ };
56
+
57
+ const mapStateToProps = ({ uploadImplementationsFile: { loading } }) => ({
58
+ loading,
59
+ });
60
+
61
+ export default connect(mapStateToProps, { uploadImplementations })(
62
+ ImplementationsUploadButton
63
+ );
@@ -4,7 +4,7 @@ import PropTypes from "prop-types";
4
4
  import { connect } from "react-redux";
5
5
  import { Button, Checkbox } from "semantic-ui-react";
6
6
  import { useIntl } from "react-intl";
7
- import { downloadImplementations } from "../routines";
7
+ import { downloadImplementations, uploadImplementations } from "../routines";
8
8
  import { getImplementationsExecution } from "../selectors";
9
9
  import {
10
10
  addImplementationFilter,
@@ -12,6 +12,8 @@ import {
12
12
  removeImplementationFilter,
13
13
  createExecutionGroup,
14
14
  } from "../routines";
15
+ import ImplementationsUploadButton from "./ImplementationsUploadButton";
16
+
15
17
  import ExecutionPopup from "./ExecutionPopup";
16
18
 
17
19
  const staticHeaderLabels = [
@@ -53,6 +55,7 @@ export const RuleImplementationsActions = ({
53
55
  ruleImplementationCount,
54
56
  ruleImplementationsDownloading,
55
57
  ruleImplementationsLoading,
58
+ upload,
56
59
  }) => {
57
60
  const { formatMessage } = useIntl();
58
61
 
@@ -126,6 +129,8 @@ export const RuleImplementationsActions = ({
126
129
  loading={ruleImplementationsDownloading}
127
130
  />
128
131
  )}
132
+ {upload && <ImplementationsUploadButton />}
133
+ <ImplementationsUploadButton />
129
134
  </div>
130
135
  );
131
136
  };
@@ -145,6 +150,7 @@ RuleImplementationsActions.propTypes = {
145
150
  toggleImplementationFilterValue: PropTypes.func,
146
151
  ruleImplementationsDownloading: PropTypes.bool,
147
152
  ruleImplementationsLoading: PropTypes.bool,
153
+ upload: PropTypes.bool,
148
154
  };
149
155
 
150
156
  const mapStateToProps = (state) => ({
@@ -161,4 +167,4 @@ export default connect(mapStateToProps, {
161
167
  toggleImplementationFilterValue,
162
168
  removeImplementationFilter,
163
169
  createExecutionGroup,
164
- })(RuleImplementationsActions);
170
+ })(RuleImplementationsActions, uploadImplementations);
@@ -5,26 +5,33 @@ import { Link } from "react-router-dom";
5
5
  import { Button } from "semantic-ui-react";
6
6
  import { FormattedMessage } from "react-intl";
7
7
  import { RULE_NEW } from "@truedat/core/routes";
8
+ import { uploadRules } from "../routines";
9
+ import RulesUploadButton from "./RulesUploadButton";
8
10
 
9
- export const RulesActions = ({ userRulesPermissions }) => (
11
+ export const RulesActions = ({ userRulesPermissions, upload }) => (
10
12
  <div style={{ float: "right" }}>
11
13
  {userRulesPermissions.manage_quality_rules && (
12
- <Button
13
- primary
14
- as={Link}
15
- to={RULE_NEW}
16
- content={<FormattedMessage id="quality.actions.create" />}
17
- />
14
+ <>
15
+ <Button
16
+ primary
17
+ as={Link}
18
+ to={RULE_NEW}
19
+ content={<FormattedMessage id="quality.actions.create" />}
20
+ />
21
+ {upload && <RulesUploadButton />}
22
+ <RulesUploadButton />
23
+ </>
18
24
  )}
19
25
  </div>
20
26
  );
21
27
 
22
28
  RulesActions.propTypes = {
23
- userRulesPermissions: PropTypes.object
29
+ userRulesPermissions: PropTypes.object,
30
+ upload: PropTypes.bool,
24
31
  };
25
32
 
26
33
  const mapStateToProps = ({ userRulesPermissions }) => ({
27
- userRulesPermissions
34
+ userRulesPermissions,
28
35
  });
29
36
 
30
- export default connect(mapStateToProps)(RulesActions);
37
+ export default connect(mapStateToProps)(RulesActions, uploadRules);
@@ -0,0 +1,58 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import { connect } from "react-redux";
4
+ import { Button } from "semantic-ui-react";
5
+ import { FormattedMessage, useIntl } from "react-intl";
6
+ import { UploadModal } from "@truedat/core/components";
7
+ import { API_RULES_UPLOAD } from "../api";
8
+ import { uploadRules } from "../routines";
9
+
10
+ const uploadAction = {
11
+ method: "POST",
12
+ href: API_RULES_UPLOAD,
13
+ };
14
+
15
+ export const RulesUploadButton = ({ uploadRules, loading }) => {
16
+ const { formatMessage } = useIntl();
17
+ return (
18
+ <UploadModal
19
+ icon="upload"
20
+ trigger={
21
+ <Button
22
+ secondary
23
+ floated="right"
24
+ icon="upload"
25
+ loading={loading}
26
+ data-tooltip={formatMessage({
27
+ id: "rules.actions.upload.tooltip",
28
+ })}
29
+ />
30
+ }
31
+ header={
32
+ <FormattedMessage id="rules.actions.upload.confirmation.header" />
33
+ }
34
+ content={
35
+ <FormattedMessage id="rules.actions.upload.confirmation.content" />
36
+ }
37
+ param={"rules"}
38
+ handleSubmit={(data) =>
39
+ uploadRules({
40
+ action: "upload",
41
+ data,
42
+ ...uploadAction,
43
+ })
44
+ }
45
+ />
46
+ );
47
+ };
48
+
49
+ RulesUploadButton.propTypes = {
50
+ uploadRules: PropTypes.func,
51
+ loading: PropTypes.bool,
52
+ };
53
+
54
+ const mapStateToProps = ({ uploadRulesFile: { loading } }) => ({
55
+ loading,
56
+ });
57
+
58
+ export default connect(mapStateToProps, { uploadRules })(RulesUploadButton);
@@ -36,5 +36,6 @@ exports[`<RuleImplementationsActions /> matches the latest snapshot 1`] = `
36
36
  onClick={[Function]}
37
37
  secondary={true}
38
38
  />
39
+ <Connect(ImplementationsUploadButton) />
39
40
  </div>
40
41
  `;
@@ -455,6 +455,8 @@ export default {
455
455
  "ruleImplementations.actions.create": "New Implementation",
456
456
  "ruleImplementations.actions.edit": "Edit Implementation",
457
457
  "ruleImplementations.actions.popup.deprecated": "Deprecated Implementations",
458
+ "ruleImplementations.actions.upload.tooltip": "Upload Implementations",
459
+ "ruleImplementations.actions.upload.confirmation.header": "Confirm bulk upload",
458
460
  "ruleImplementations.header": "Quality Implementations",
459
461
  "ruleImplementations.props.business_concept": "Concept",
460
462
  "ruleImplementations.props.status": "Status",
@@ -490,6 +492,11 @@ export default {
490
492
  "ruleImplementations.summary.headers.implementation": "Rule Implementation",
491
493
  "ruleImplementations.summary.headers.population": "Population",
492
494
  "ruleImplementations.summary.headers.validations": "Validation",
495
+ "ruleImplementations.upload.success.errors": "Error in {implementation_key} attribute: {key} message: {message} ",
496
+ "ruleImplementations.upload.success.header": "Upload success! Loaded {count_ids} omitted {count_errors}:",
497
+ "ruleImplementations.upload.failed.header": "Error uploading file. No rules have been created.",
498
+ "ruleImplementations.upload.failed.misssing_required_columns":
499
+ "Faltan columnas obligatorias en el fichero. Esperado [{expected}]. Recibido [{found}].",
493
500
  "ruleResult.props.header.information": "Information",
494
501
  "ruleResult.props.header.details": "Details",
495
502
  "ruleResult.props.date": "Date",
@@ -506,10 +513,17 @@ export default {
506
513
  "rules.actions.delete.confirmation.content":
507
514
  "The rule {name} will be deleted. ¿Are you sure?",
508
515
  "rules.actions.delete.confirmation.header": "Delete Quality Rule",
516
+ "rules.actions.upload.confirmation.header": "Confirm bulk upload",
517
+ "rules.actions.upload.tooltip": "Upload Rules",
509
518
  "rules.crumbs.top": "Rules",
510
519
  "rules.retrieved.results": "{count} rules found",
511
520
  "rules.search.placeholder": "Search rules...",
512
521
  "rules.searching": "Searching...",
522
+ "rules.upload.success.errors": "Error in {rule_name} attribute: {key} message: {message} ",
523
+ "rules.upload.success.header": "Upload success! Loaded {count_ids} omitted {count_errors}:",
524
+ "rules.upload.failed.header": "Error uploading file. No rules have been created.",
525
+ "rules.upload.failed.misssing_required_columns":
526
+ "Missing required columns. Expected [{expected}]. Found [{found}].",
513
527
  "structureFields.dropdown.label": "Select Field",
514
528
  "structureFields.dropdown.placeholder": "Fields",
515
529
  "summary.link.and": "and",
@@ -234,6 +234,8 @@ export default {
234
234
  "ruleImplementation.actions.restore.confirmation.header":
235
235
  "Restaurar Implementación",
236
236
  "ruleImplementation.actions.restore": "Restaurar Implementación",
237
+ "ruleImplementations.actions.upload.tooltip": "Subir Implementaciones",
238
+ "ruleImplementations.actions.upload.confirmation.header": "Subir ficheros de implementaciones",
237
239
  "ruleImplementation.column.placeholder": "Seleccionar columna",
238
240
  "ruleImplementation.column": "Columna",
239
241
  "ruleImplementation.delete.folder": '"Eliminado"',
@@ -507,6 +509,13 @@ export default {
507
509
  "Implementación de una Regla",
508
510
  "ruleImplementations.summary.headers.population": "Población",
509
511
  "ruleImplementations.summary.headers.validations": "Validaciones",
512
+ "ruleImplementations.upload.success.errors": "Error en {name} atributo: {key} mensaje: {message} ",
513
+ "ruleImplementations.upload.success.header": "¡Fichero subido correctamente! subidos {count_ids} errores {count_errors}:",
514
+ "ruleImplementations.upload.failed.header": "Error al subir el fichero. No se ha realizado ninguna inserción.",
515
+ "ruleImplementations.upload.failed.misssing_required_columns":
516
+ "Faltan columnas obligatorias en el fichero. Esperado [{expected}]. Recibido [{found}].",
517
+
518
+
510
519
  "ruleResult.props.date": "Fecha",
511
520
  "ruleResult.props.details": "Detalles",
512
521
  "ruleResult.props.errors": "Errores",
@@ -519,10 +528,17 @@ export default {
519
528
  "rules.actions.delete.confirmation.content":
520
529
  "Se va a eliminar la regla {name}. ¿Está seguro?",
521
530
  "rules.actions.delete.confirmation.header": "Eliminar regla de calidad",
531
+ "rules.actions.upload.confirmation.header": "Subir ficheros de reglas",
532
+ "rules.actions.upload.tooltip": "Subir reglas",
522
533
  "rules.crumbs.top": "Reglas",
523
534
  "rules.retrieved.results": "{count} reglas encontradas",
524
535
  "rules.search.placeholder": "Buscar reglas...",
525
536
  "rules.searching": "Buscando...",
537
+ "rules.upload.success.errors": "Error en {rule_name} atributo: {key} mensaje: {message} ",
538
+ "rules.upload.success.header": "¡Fichero subido correctamente! subidos {count_ids} errores {count_errors}:",
539
+ "rules.upload.failed.header": "Error al subir el fichero. No se ha realizado ninguna inserción.",
540
+ "rules.upload.failed.misssing_required_columns":
541
+ "Faltan columnas obligatorias en el fichero. Esperado [{expected}]. Recibido [{found}].",
526
542
  "ruleSubscription.actions.remove": "Eliminar",
527
543
  "structureFields.dropdown.label": "Seleccionar Campo",
528
544
  "structureFields.dropdown.placeholder": "Campos",
@@ -1,5 +1,104 @@
1
+ import _ from "lodash/fp";
2
+ import { dismissAlert } from "@truedat/core/routines";
3
+ import { uploadRules, uploadImplementations } from "../routines";
4
+
1
5
  const initialState = {};
2
6
 
3
- const dqMessage = () => initialState;
7
+ const dqMessage = (state = initialState, { type, payload }) => {
8
+ switch (type) {
9
+ case dismissAlert.TRIGGER:
10
+ return initialState;
11
+ case uploadRules.SUCCESS:
12
+ const messages = _.has("errors")(payload.data)
13
+ ? _.flow(
14
+ _.propOr([], "errors"),
15
+ _.map((error) => ({
16
+ id: "rules.upload.success.errors",
17
+ fields: {
18
+ rule_name: error.rule_name,
19
+ key: Object.keys(error.message)[0],
20
+ message: error.message[Object.keys(error.message)[0]][0],
21
+ },
22
+ defaultMessage: "rules.upload.success.errors.default",
23
+ }))
24
+ )(payload.data)
25
+ : "";
26
+ return {
27
+ error: false,
28
+ header: "rules.upload.success.header",
29
+ icon: "check",
30
+ color: payload.data.errors.length >= 1 ? "orange" : "green",
31
+ text: "",
32
+ messages,
33
+ fields: {
34
+ count_ids: payload.data.ids.length,
35
+ count_errors: payload.data.errors.length,
36
+ },
37
+ };
38
+ case uploadRules.FAILURE:
39
+ if (payload.status != 500 && !_.path("data.errors")(payload)) {
40
+ return {
41
+ error: true,
42
+ header: "rules.upload.failed.header",
43
+ content: `rules.upload.failed.${
44
+ _.path("data.error.error")(payload) || _.path("data.error")(payload)
45
+ }`,
46
+ icon: "attention",
47
+ text: "",
48
+ fields: _.path("data.error")(payload),
49
+ };
50
+ } else {
51
+ return null;
52
+ }
53
+
54
+ case uploadImplementations.SUCCESS:
55
+ const messagesImp = _.has("errors")(payload.data)
56
+ ? _.flow(
57
+ _.propOr([], "errors"),
58
+ _.map((error) => ({
59
+ id: "ruleImplementations.upload.success.errors",
60
+ fields: {
61
+ name: error.implementation_key,
62
+ key: Object.keys(error.message)[0],
63
+ message: error.message[Object.keys(error.message)[0]][0],
64
+ },
65
+ defaultMessage:
66
+ "ruleImplementations.upload.success.errors.default",
67
+ }))
68
+ )(payload.data)
69
+ : "";
70
+
71
+ return {
72
+ error: false,
73
+ header: "ruleImplementations.upload.success.header",
74
+ icon: "check",
75
+ color: payload.data.errors.length >= 1 ? "orange" : "green",
76
+ text: "",
77
+ messages: messagesImp,
78
+ fields: {
79
+ count_ids: payload.data.ids.length,
80
+ count_errors: payload.data.errors.length,
81
+ },
82
+ };
83
+ case uploadImplementations.FAILURE:
84
+ if (payload.status != 500 && !_.path("data.errors")(payload)) {
85
+ return {
86
+ error: true,
87
+ header: "ruleImplementations.upload.failed.header",
88
+ content: `ruleImplementations.upload.failed.${
89
+ _.path("data.error.error")(payload) || _.path("data.error")(payload)
90
+ }`,
91
+ icon: "attention",
92
+ text: "",
93
+ fields: _.path("data.error")(payload),
94
+ };
95
+ } else {
96
+ return null;
97
+ }
98
+
99
+ default:
100
+ return state;
101
+ }
102
+ };
4
103
 
5
104
  export { dqMessage };
@@ -37,6 +37,8 @@ import { ruleUpdating } from "./ruleUpdating";
37
37
  import { rules } from "./rules";
38
38
  import { rulesLoading } from "./rulesLoading";
39
39
  import { rulesPageSize } from "./rulesPageSize";
40
+ import { uploadImplementationsFile } from "./uploadImplementationsFile";
41
+ import { uploadRulesFile } from "./uploadRulesFile";
40
42
  import { userRulePermissions } from "./userRulePermissions";
41
43
  import { userRulesPermissions } from "./userRulesPermissions";
42
44
  import { userImplementationsPermissions } from "./userImplementationsPermissions";
@@ -81,6 +83,8 @@ export {
81
83
  rules,
82
84
  rulesLoading,
83
85
  rulesPageSize,
86
+ uploadRulesFile,
87
+ uploadImplementationsFile,
84
88
  userRulePermissions,
85
89
  userRulesPermissions,
86
90
  userImplementationsPermissions,
@@ -5,13 +5,14 @@ import {
5
5
  createRuleImplementation,
6
6
  updateRuleImplementation,
7
7
  deleteRuleResult,
8
+ uploadImplementations,
8
9
  } from "../routines";
9
10
 
10
11
  const initialState = "";
11
12
 
12
13
  export const ruleImplementationRedirect = (
13
14
  state = initialState,
14
- { type, payload }
15
+ { type, payload, meta }
15
16
  ) => {
16
17
  switch (type) {
17
18
  case clearRedirect.TRIGGER:
@@ -29,6 +30,10 @@ export const ruleImplementationRedirect = (
29
30
  const { id: implementation_id, rule_id: id } = data;
30
31
  return linkTo.RULE_IMPLEMENTATION({ id, implementation_id });
31
32
  }
33
+ case uploadImplementations.SUCCESS: {
34
+ const { redirectUrl } = meta;
35
+ return redirectUrl;
36
+ }
32
37
  case deleteRuleResult.SUCCESS: {
33
38
  const { rule_implementation_id: implementation_id, rule_id: id } =
34
39
  payload;
@@ -11,6 +11,7 @@ import {
11
11
  updateRule,
12
12
  deleteRule,
13
13
  setRuleImplementationStatus,
14
+ uploadRules,
14
15
  } from "../routines";
15
16
 
16
17
  const initialState = "";
@@ -37,6 +38,10 @@ export const ruleRedirect = (state = initialState, { type, payload, meta }) => {
37
38
  const { rule_id } = payload;
38
39
  return _.isNil(rule_id) ? state : linkTo.RULE({ id: rule_id });
39
40
  }
41
+ case uploadRules.SUCCESS: {
42
+ const { redirectUrl } = meta;
43
+ return redirectUrl;
44
+ }
40
45
  case deleteSubscription.SUCCESS: {
41
46
  const { rule_id } = payload;
42
47
  return _.isNil(rule_id) ? state : linkTo.RULE({ id: rule_id });
@@ -0,0 +1,28 @@
1
+ import { uploadImplementations } from "../routines";
2
+
3
+ const initialState = {
4
+ loading: false,
5
+ error: {},
6
+ };
7
+
8
+ export const uploadImplementationsFile = (
9
+ state = initialState,
10
+ { type, payload }
11
+ ) => {
12
+ switch (type) {
13
+ case uploadImplementations.TRIGGER:
14
+ return state;
15
+ case uploadImplementations.REQUEST:
16
+ return { ...state, loading: true };
17
+ case uploadImplementations.SUCCESS:
18
+ return state;
19
+ case uploadImplementations.FAILURE:
20
+ return { ...state, error: payload };
21
+ case uploadImplementations.FULFILL:
22
+ return { ...state, loading: false };
23
+ default:
24
+ return state;
25
+ }
26
+ };
27
+
28
+ export default uploadImplementationsFile;
@@ -0,0 +1,25 @@
1
+ import { uploadRules } from "../routines";
2
+
3
+ const initialState = {
4
+ loading: false,
5
+ error: {},
6
+ };
7
+
8
+ export const uploadRulesFile = (state = initialState, { type, payload }) => {
9
+ switch (type) {
10
+ case uploadRules.TRIGGER:
11
+ return state;
12
+ case uploadRules.REQUEST:
13
+ return { ...state, loading: true };
14
+ case uploadRules.SUCCESS:
15
+ return state;
16
+ case uploadRules.FAILURE:
17
+ return { ...state, error: payload };
18
+ case uploadRules.FULFILL:
19
+ return { ...state, loading: false };
20
+ default:
21
+ return state;
22
+ }
23
+ };
24
+
25
+ export default uploadRulesFile;
package/src/routines.js CHANGED
@@ -45,6 +45,8 @@ export const sortRules = createRoutine("SORT_RULES");
45
45
  export const selectRulePage = createRoutine("SELECT_RULE_PAGE");
46
46
  export const toggleRuleFilterValue = createRoutine("TOGGLE_RULE_FILTER_VALUE");
47
47
  export const updateDeletionQuery = createRoutine("UPDATE_DELETION_QUERY");
48
+ export const uploadRules = createRoutine("UPLOAD_RULES");
49
+ export const uploadImplementations = createRoutine("UPLOAD_IMPLEMENTATIONS");
48
50
  export const clearStructure = createRoutine("CLEAR_STRUCTURE");
49
51
  export const setImplementationFilterValues = createRoutine(
50
52
  "SET_IMPLEMENTATION_FILTER_VALUES"
@@ -14,6 +14,8 @@ import { fetchRuleImplementationsRequestSaga } from "./fetchRuleImplementations"
14
14
  import { fetchRuleRequestSaga } from "./fetchRule";
15
15
  import { fetchRulesRequestSaga } from "./fetchRules";
16
16
  import { searchRuleImplementationsRequestSaga } from "./searchRuleImplementations";
17
+ import { uploadImplementationsRequestsSaga } from "./uploadImplementations";
18
+ import { uploadRulesRequestsSaga } from "./uploadRules";
17
19
  import { updateRuleImplementationRequestSaga } from "./updateRuleImplementation";
18
20
  import { updateRuleRequestSaga } from "./updateRule";
19
21
 
@@ -34,6 +36,8 @@ export {
34
36
  fetchRuleRequestSaga,
35
37
  fetchRulesRequestSaga,
36
38
  searchRuleImplementationsRequestSaga,
39
+ uploadRulesRequestsSaga,
40
+ uploadImplementationsRequestsSaga,
37
41
  updateRuleImplementationRequestSaga,
38
42
  updateRuleRequestSaga,
39
43
  };
@@ -55,6 +59,8 @@ export default [
55
59
  fetchRuleRequestSaga(),
56
60
  fetchRulesRequestSaga(),
57
61
  searchRuleImplementationsRequestSaga(),
62
+ uploadRulesRequestsSaga(),
63
+ uploadImplementationsRequestsSaga(),
58
64
  updateRuleImplementationRequestSaga(),
59
65
  updateRuleRequestSaga(),
60
66
  ];
@@ -0,0 +1,28 @@
1
+ import { call, put, takeLatest } from "redux-saga/effects";
2
+ import { IMPLEMENTATIONS } from "@truedat/core/routes";
3
+ import { apiJsonPost, UPLOAD_JSON_OPTS } from "@truedat/core/services/api";
4
+ import { uploadImplementations } from "../routines";
5
+
6
+ export function* uploadImplementationsSaga({ payload }) {
7
+ try {
8
+ const { action, method, href, ...rest } = payload;
9
+ const meta = { action, method, href, redirectUrl: IMPLEMENTATIONS };
10
+ yield put(uploadImplementations.request({ method, href, ...rest }));
11
+ const body = rest || {};
12
+ const { data } = yield call(apiJsonPost, href, body.data, UPLOAD_JSON_OPTS);
13
+ yield put({ meta, ...uploadImplementations.success(data) });
14
+ } catch (error) {
15
+ if (error.response) {
16
+ const { status, data } = error.response;
17
+ yield put(uploadImplementations.failure({ status, data }));
18
+ } else {
19
+ yield put(uploadImplementations.failure(error.message));
20
+ }
21
+ } finally {
22
+ yield put(uploadImplementations.fulfill());
23
+ }
24
+ }
25
+
26
+ export function* uploadImplementationsRequestsSaga() {
27
+ yield takeLatest(uploadImplementations.TRIGGER, uploadImplementationsSaga);
28
+ }
@@ -0,0 +1,28 @@
1
+ import { call, put, takeLatest } from "redux-saga/effects";
2
+ import { RULES } from "@truedat/core/routes";
3
+ import { apiJsonPost, UPLOAD_JSON_OPTS } from "@truedat/core/services/api";
4
+ import { uploadRules } from "../routines";
5
+
6
+ export function* uploadRulesSaga({ payload }) {
7
+ try {
8
+ const { action, method, href, ...rest } = payload;
9
+ const meta = { action, method, href, redirectUrl: RULES };
10
+ yield put(uploadRules.request({ method, href, ...rest }));
11
+ const body = rest || {};
12
+ const { data } = yield call(apiJsonPost, href, body.data, UPLOAD_JSON_OPTS);
13
+ yield put({ meta, ...uploadRules.success(data) });
14
+ } catch (error) {
15
+ if (error.response) {
16
+ const { status, data } = error.response;
17
+ yield put(uploadRules.failure({ status, data }));
18
+ } else {
19
+ yield put(uploadRules.failure(error.message));
20
+ }
21
+ } finally {
22
+ yield put(uploadRules.fulfill());
23
+ }
24
+ }
25
+
26
+ export function* uploadRulesRequestsSaga() {
27
+ yield takeLatest(uploadRules.TRIGGER, uploadRulesSaga);
28
+ }