@truedat/core 4.41.2 → 4.42.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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.41.3] 2022-04-01
4
+
5
+ ### Changed
6
+
7
+ - [TD-4670] `RouteListener` now dismisses alerts when any change of URL path
8
+ occurs
9
+
3
10
  ## [4.41.2] 2022-03-30
4
11
 
5
12
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/core",
3
- "version": "4.41.2",
3
+ "version": "4.42.0",
4
4
  "description": "Truedat Web Core",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -32,7 +32,7 @@
32
32
  "@babel/plugin-transform-modules-commonjs": "^7.15.0",
33
33
  "@babel/preset-env": "^7.15.0",
34
34
  "@babel/preset-react": "^7.14.5",
35
- "@truedat/test": "4.41.2",
35
+ "@truedat/test": "4.42.0",
36
36
  "babel-jest": "^27.0.6",
37
37
  "babel-plugin-dynamic-import-node": "^2.3.3",
38
38
  "babel-plugin-lodash": "^3.3.4",
@@ -106,5 +106,5 @@
106
106
  "react-dom": ">= 16.8.6 < 17",
107
107
  "semantic-ui-react": ">= 0.88.2 < 2.1"
108
108
  },
109
- "gitHead": "de1e8cd9c744c0dae85be4585fccc1c50fdf6a07"
109
+ "gitHead": "824b94750e130d145f856f6e16eac97e351f6be8"
110
110
  }
@@ -20,6 +20,8 @@ const formatErrorMessages = (error, formatMessage) => {
20
20
  if (_.has("name")(error))
21
21
  return formatMessage({ id: error.name, defaultMessage: error.name });
22
22
 
23
+ if (_.isString(error?.message)) return error.message;
24
+
23
25
  return formatMessage({
24
26
  id: "error.unknown",
25
27
  defaultMessage: "Unexpected error",
@@ -11,10 +11,7 @@ export class RouteListener extends React.Component {
11
11
  componentDidUpdate(prevProps) {
12
12
  const prevPath = prevProps.location.pathname;
13
13
  const currentPath = this.props.location.pathname;
14
- if (
15
- !_.isEmpty(this.props.message) &&
16
- prevPath.split("/")[1] !== currentPath.split("/")[1]
17
- ) {
14
+ if (!_.isEmpty(this.props.message) && prevPath !== currentPath) {
18
15
  this.props.dismissAlert();
19
16
  }
20
17
  }
@@ -27,10 +24,10 @@ export class RouteListener extends React.Component {
27
24
  RouteListener.propTypes = {
28
25
  location: PropTypes.object,
29
26
  message: PropTypes.object,
30
- dismissAlert: PropTypes.func
27
+ dismissAlert: PropTypes.func,
31
28
  };
32
29
 
33
- const mapStateToProps = state => ({ message: getMessage(state) });
30
+ const mapStateToProps = (state) => ({ message: getMessage(state) });
34
31
 
35
32
  const mapDispatchToProps = { dismissAlert };
36
33
 
@@ -5,7 +5,7 @@ import { RouteListener } from "../RouteListener";
5
5
  describe("<RouteListener />", () => {
6
6
  const props = {
7
7
  message: {},
8
- location: { pathname: "/test" }
8
+ location: { pathname: "/test" },
9
9
  };
10
10
 
11
11
  it("matches the latest snapshot", () => {
@@ -20,7 +20,7 @@ describe("<RouteListener />", () => {
20
20
  );
21
21
  wrapper.setProps({
22
22
  message: { not: "empty" },
23
- location: { pathname: "/different" }
23
+ location: { pathname: "/different" },
24
24
  });
25
25
  expect(dismissAlert.mock.calls.length).toBe(1);
26
26
  });
@@ -31,19 +31,7 @@ describe("<RouteListener />", () => {
31
31
  <RouteListener dismissAlert={dismissAlert} {...props} />
32
32
  );
33
33
  wrapper.setProps({
34
- location: { pathname: "/different" }
35
- });
36
- expect(dismissAlert.mock.calls.length).toBe(0);
37
- });
38
-
39
- it("when changing subpath location with message will not call dismissAlert", () => {
40
- const dismissAlert = jest.fn();
41
- const wrapper = shallow(
42
- <RouteListener dismissAlert={dismissAlert} {...props} />
43
- );
44
- wrapper.setProps({
45
- message: { not: "empty" },
46
- location: { pathname: "/test/different" }
34
+ location: { pathname: "/different" },
47
35
  });
48
36
  expect(dismissAlert.mock.calls.length).toBe(0);
49
37
  });
@@ -1,7 +1,7 @@
1
1
  import _ from "lodash/fp";
2
2
  import { useRouteMatch } from "react-router-dom";
3
3
 
4
- export const usePath = props => {
4
+ export const usePath = (props) => {
5
5
  const match = useRouteMatch(props);
6
6
  return _.prop("path")(match);
7
7
  };
package/src/routes.js CHANGED
@@ -124,12 +124,13 @@ export const SEARCH_CONCEPTS = "/search/concepts";
124
124
  export const SEARCH_INGESTS = "/search/ingests";
125
125
  export const SEARCH_RESULTS = "/search/results";
126
126
  export const SEARCH_STRUCTURES = "/search/structures";
127
- export const SOURCE = "/sources/:external_id";
127
+ export const SOURCE = "/sources/:sourceId";
128
128
  export const SOURCES = "/sources";
129
129
  export const SOURCES_NEW = "/sources/new";
130
- export const SOURCE_EDIT = "/sources/:external_id/edit";
131
- export const SOURCE_JOBS = "/sources/:external_id/jobs";
132
- export const SOURCE_JOBS_NEW = "/sources/:external_id/jobs/new";
130
+ export const SOURCE_EDIT = "/sources/:sourceId/edit";
131
+ export const SOURCE_JOB = "/sources/:sourceId/jobs/:id";
132
+ export const SOURCE_JOBS = "/sources/:sourceId/jobs";
133
+ export const SOURCE_JOBS_NEW = "/sources/:sourceId/jobs/new";
133
134
  export const STRUCTURE = "/structures/:id";
134
135
  export const STRUCTURES = "/structures";
135
136
  export const STRUCTURES_BULK_UPDATE = "/structures/bulk_update";
@@ -276,6 +277,7 @@ const routes = {
276
277
  SEARCH,
277
278
  SOURCES_NEW,
278
279
  SOURCE_EDIT,
280
+ SOURCE_JOB,
279
281
  SOURCE_JOBS_NEW,
280
282
  SOURCE_JOBS,
281
283
  SOURCE,
@@ -1,4 +1,4 @@
1
- import { errorsFailure, toErrorList } from "../message";
1
+ import { errorsFailure, graphQLErrors, toErrorList } from "../message";
2
2
 
3
3
  describe("services: message", () => {
4
4
  describe("toErrorList", () => {
@@ -9,7 +9,7 @@ describe("services: message", () => {
9
9
  expect.arrayContaining([
10
10
  { name: "foo.name.unique" },
11
11
  { name: "foo.name.missing" },
12
- { name: "foo.bar.baz" }
12
+ { name: "foo.bar.baz" },
13
13
  ])
14
14
  );
15
15
  });
@@ -20,7 +20,21 @@ describe("services: message", () => {
20
20
 
21
21
  it("should transform the action name to a message key with camel case action name", () => {
22
22
  expect(failure).toMatchObject({
23
- header: "alert.fooBarBaz.failed.header"
23
+ header: "alert.fooBarBaz.failed.header",
24
+ });
25
+ });
26
+ });
27
+
28
+ describe("graphQLErrors", () => {
29
+ it("should extract error messages from a GraphQL error response", () => {
30
+ const errors = [
31
+ { path: "foo", message: "foo1" },
32
+ { path: "bar", message: "bar1" },
33
+ ];
34
+ const response = { graphQLErrors: errors };
35
+ expect(graphQLErrors(response)).toMatchObject({
36
+ error: true,
37
+ errorList: expect.arrayContaining(errors),
24
38
  });
25
39
  });
26
40
  });
@@ -4,9 +4,6 @@ import React from "react";
4
4
  export const columnDecoratorComponent = (column) => (obj) => {
5
5
  const { fieldSelector, fieldDecorator, name } = column || {};
6
6
 
7
- if (_.isFunction(fieldSelector)) {
8
- fieldSelector(obj);
9
- }
10
7
  const field = _.isFunction(fieldSelector)
11
8
  ? fieldSelector(obj)
12
9
  : _.path(_.defaultTo(name)(fieldSelector))(obj);
@@ -6,11 +6,14 @@ const isErrorsFailure = (status, data) =>
6
6
  const isPhoenixFailure = (status, data) =>
7
7
  status === 422 && _.conformsTo({ errors: _.isObject })(data);
8
8
 
9
- const isDefaultFailure = status => {
9
+ const isDefaultFailure = (status) => {
10
10
  return !!status;
11
11
  };
12
12
 
13
13
  export const defaultMessage = (state, type, payload) => {
14
+ if (type === "LOG_ERROR/TRIGGER" && _.has("graphQLErrors")(payload))
15
+ return graphQLErrors(payload);
16
+
14
17
  if (_.endsWith("/TRIGGER")(type)) return state;
15
18
 
16
19
  if (_.endsWith("/FAILURE")(type)) {
@@ -24,13 +27,24 @@ export const defaultMessage = (state, type, payload) => {
24
27
  return state;
25
28
  };
26
29
 
27
- export const toErrorList = prefix =>
30
+ export const graphQLErrors = (payload) => {
31
+ const errorList = _.map(_.pick(["path", "message"]))(payload.graphQLErrors);
32
+ return {
33
+ error: true,
34
+ header: "Error",
35
+ icon: "attention",
36
+ errorList: errorList,
37
+ text: "List of errors",
38
+ };
39
+ };
40
+
41
+ export const toErrorList = (prefix) =>
28
42
  _.flow(
29
43
  _.toPairs,
30
44
  _.flatMap(([field, errors]) =>
31
- _.map(v => `${prefix}.${field}.${v}`)(errors)
45
+ _.map((v) => `${prefix}.${field}.${v}`)(errors)
32
46
  ),
33
- _.map(name => ({ name }))
47
+ _.map((name) => ({ name }))
34
48
  );
35
49
 
36
50
  export const phoenixFailure = (type, errors) => {
@@ -41,7 +55,7 @@ export const phoenixFailure = (type, errors) => {
41
55
  header: `alert.${action}.failed.header`,
42
56
  icon: "attention",
43
57
  errorList: errorList,
44
- text: "List of errors"
58
+ text: "List of errors",
45
59
  };
46
60
  };
47
61
 
@@ -52,7 +66,7 @@ export const errorsFailure = (type, errors) => {
52
66
  header: `alert.${action}.failed.header`,
53
67
  icon: "attention",
54
68
  errorList: errors,
55
- text: "List of errors"
69
+ text: "List of errors",
56
70
  };
57
71
  };
58
72
 
@@ -62,6 +76,6 @@ export const defaultFailure = (type, payload) => {
62
76
  header: `alert.status.${payload.status}.header`,
63
77
  content: `alert.status.${payload.status}.content`,
64
78
  icon: "attention",
65
- text: type.replace("/FAILURE", "")
79
+ text: type.replace("/FAILURE", ""),
66
80
  };
67
81
  };