@truedat/core 4.36.3 → 4.36.7

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,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.36.6] 2022-01-07
4
+
5
+ ### Fixed
6
+
7
+ - [TD-4100] Move dependency from devDepencies to dependencies
8
+
9
+ ## [4.36.5] 2022-01-07
10
+
11
+ ### Added
12
+
13
+ - [TD-4100] Long Alert error message CSV download link
14
+
3
15
  ## [4.35.8] 2022-01-07
4
16
 
5
17
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/core",
3
- "version": "4.36.3",
3
+ "version": "4.36.7",
4
4
  "description": "Truedat Web Core",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -86,6 +86,7 @@
86
86
  "is-hotkey": "^0.1.6",
87
87
  "is-url": "^1.2.4",
88
88
  "prop-types": "^15.7.2",
89
+ "react-csv": "^2.2.2",
89
90
  "react-dropzone": "^4.2.13",
90
91
  "react-intl": "^5.20.10",
91
92
  "react-moment": "^0.9.7",
@@ -103,5 +104,5 @@
103
104
  "react-dom": ">= 16.8.6 < 17",
104
105
  "semantic-ui-react": ">= 0.88.2 < 2.1"
105
106
  },
106
- "gitHead": "ec1b0afc195462b78b1e9145cf705d9edd87a58b"
107
+ "gitHead": "f5b0b7da7d61e1e8fff39337fe411f4174055b73"
107
108
  }
@@ -1,11 +1,12 @@
1
1
  import _ from "lodash/fp";
2
- import React from "react";
2
+ import React, { useState } from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { useIntl } from "react-intl";
5
5
  import { connect } from "react-redux";
6
6
  import { Message } from "semantic-ui-react";
7
7
  import { dismissAlert } from "../routines";
8
8
  import { getMessage } from "../selectors";
9
+ import { AlertExporter } from "./AlertExporter";
9
10
 
10
11
  const existingList = (list) => list && !_.isEmpty(list);
11
12
 
@@ -40,6 +41,8 @@ export const Alert = ({
40
41
  color,
41
42
  fields,
42
43
  messages,
44
+ downloadable = false,
45
+ initialMaxListItems = Infinity,
43
46
  },
44
47
  dismissAlert,
45
48
  }) => {
@@ -48,6 +51,9 @@ export const Alert = ({
48
51
  const formattedMessages = _.map((e) => formatMessages(e, formatMessage))(
49
52
  messages
50
53
  );
54
+ const list = _.isEmpty(errors) ? formattedMessages : errors;
55
+ const [maxListItems, setMaxListItems] = useState(initialMaxListItems);
56
+
51
57
  const message_content =
52
58
  content && !existingList(errors) && !existingList(formattedMessages)
53
59
  ? formatMessage(
@@ -55,18 +61,28 @@ export const Alert = ({
55
61
  { text, ...fields }
56
62
  )
57
63
  : undefined;
58
- const list = _.isEmpty(errors) ? formattedMessages : errors;
59
64
  return content || header ? (
60
- <Message
61
- error={error}
62
- header={formatMessage({ id: header, defaultMessage: header }, fields)}
63
- content={message_content}
64
- list={list}
65
- icon={icon}
66
- color={color}
67
- onDismiss={dismissAlert}
68
- visible
69
- />
65
+ <>
66
+ {list.length > maxListItems ? (
67
+ <a
68
+ style={{ cursor: "pointer" }}
69
+ onClick={() => setMaxListItems(maxListItems + initialMaxListItems)}
70
+ >
71
+ {formatMessage({ id: "alert.show.more" })}
72
+ </a>
73
+ ) : null}
74
+ {downloadable ? AlertExporter({ list, messages }) : null}
75
+ <Message
76
+ error={error}
77
+ header={formatMessage({ id: header, defaultMessage: header }, fields)}
78
+ content={message_content}
79
+ list={list.length >= maxListItems ? list.slice(0, maxListItems) : list}
80
+ icon={icon}
81
+ color={color}
82
+ onDismiss={dismissAlert}
83
+ visible
84
+ />
85
+ </>
70
86
  ) : null;
71
87
  };
72
88
 
@@ -0,0 +1,73 @@
1
+ /* eslint-disable fp/no-mutation */
2
+ /* eslint-disable fp/no-let */
3
+ import _ from "lodash/fp";
4
+ import React from "react";
5
+ import PropTypes from "prop-types";
6
+ import { useIntl } from "react-intl";
7
+ import { CSVLink } from "react-csv";
8
+
9
+ export const AlertExporter = ({ list, messages }) => {
10
+ const fullTranslations = joinTranslations({ list, messages });
11
+ const { formatMessage } = useIntl();
12
+ return (
13
+ <CSVLink
14
+ style={{ float: "right" }}
15
+ headers={generateCsvHeaders(fullTranslations)}
16
+ data={fullTranslations}
17
+ filename="errors.csv"
18
+ target="_blank"
19
+ >
20
+ {formatMessage({ id: "alert.export.csv" })}
21
+ </CSVLink>
22
+ );
23
+ };
24
+
25
+ AlertExporter.propTypes = {
26
+ list: PropTypes.array,
27
+ messages: PropTypes.array,
28
+ };
29
+
30
+ const joinTranslations = ({ list, messages }) => {
31
+ const renderedMessages = _.map((rm) => ({
32
+ renderedMessage: rm,
33
+ }))(list);
34
+ const full_messages = _.flow(
35
+ _.zip(renderedMessages),
36
+ _.map(
37
+ _.reduce(function (acc, ob) {
38
+ return _.assign(acc)(ob);
39
+ }, {})
40
+ )
41
+ )(messages);
42
+ return full_messages;
43
+ };
44
+
45
+ const flattenObj = (ob) => {
46
+ let result = {};
47
+ for (const i in ob) {
48
+ if (typeof ob[i] === "object" && !Array.isArray(ob[i])) {
49
+ const temp = flattenObj(ob[i]);
50
+ for (const j in temp) {
51
+ result[i + "." + j] = temp[j];
52
+ }
53
+ } else {
54
+ result[i] = ob[i];
55
+ }
56
+ }
57
+ return result;
58
+ };
59
+
60
+ const getAllUniqueKeys = _.flow(
61
+ _.map(flattenObj),
62
+ _.map(Object.keys),
63
+ _.flattenDeep,
64
+ _.uniq
65
+ );
66
+
67
+ const generateCsvHeaders = _.flow(
68
+ getAllUniqueKeys,
69
+ _.map((key) => ({
70
+ label: key.toUpperCase(),
71
+ key,
72
+ }))
73
+ );
@@ -25,9 +25,10 @@ describe("<Alert />", () => {
25
25
 
26
26
  it("contains a formatted message with properties", () => {
27
27
  const wrapper = shallow(<Alert {...props} />);
28
- expect(wrapper.find("Message")).toHaveLength(1);
29
- expect(wrapper.prop("content")).toEqual("content.message.id");
30
- expect(wrapper.prop("header")).toEqual("header.message.id");
28
+ const message = wrapper.find("Message");
29
+ expect(message).toHaveLength(1);
30
+ expect(message.prop("content")).toEqual("content.message.id");
31
+ expect(message.prop("header")).toEqual("header.message.id");
31
32
  });
32
33
 
33
34
  it("contains a list of messages", () => {
@@ -1,13 +1,15 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`<Alert /> matches the latest snapshot 1`] = `
4
- <Message
5
- content="content.message.id"
6
- error={true}
7
- header="header.message.id"
8
- icon="warning"
9
- list={Array []}
10
- onDismiss={[MockFunction]}
11
- visible={true}
12
- />
4
+ <Fragment>
5
+ <Message
6
+ content="content.message.id"
7
+ error={true}
8
+ header="header.message.id"
9
+ icon="warning"
10
+ list={Array []}
11
+ onDismiss={[MockFunction]}
12
+ visible={true}
13
+ />
14
+ </Fragment>
13
15
  `;
package/src/routes.js CHANGED
@@ -88,6 +88,8 @@ export const RULE_EDIT = "/rules/:id/edit";
88
88
  export const RULE_IMPLEMENTATION =
89
89
  "/rules/:id/implementations/:implementation_id";
90
90
  export const RULE_IMPLEMENTATIONS = "/rules/:id/implementations";
91
+ export const RULE_IMPLEMENTATION_EVENTS =
92
+ "/rules/:id/implementations/:implementation_id/events";
91
93
  export const RULE_IMPLEMENTATION_NEW = "/rules/:id/implementations/new";
92
94
  export const RULE_IMPLEMENTATION_EDIT =
93
95
  "/rules/:id/implementations/:implementation_id/edit";
@@ -231,6 +233,7 @@ const routes = {
231
233
  ROLES_NEW,
232
234
  ROLES,
233
235
  RULE_EDIT,
236
+ RULE_IMPLEMENTATION_EVENTS,
234
237
  RULE_IMPLEMENTATION_CLONE,
235
238
  RULE_IMPLEMENTATION_EDIT,
236
239
  RULE_IMPLEMENTATION_MOVE,