@truedat/dd 5.9.4 → 5.9.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dd",
3
- "version": "5.9.4",
3
+ "version": "5.9.5",
4
4
  "description": "Truedat Web Data Dictionary",
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": "5.9.4",
37
+ "@truedat/test": "5.9.5",
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",
@@ -62,7 +62,8 @@
62
62
  "@truedat/test/setup"
63
63
  ],
64
64
  "moduleNameMapper": {
65
- "\\.(css|less|png)$": "identity-obj-proxy",
65
+ "\\.(css|less)$": "identity-obj-proxy",
66
+ "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/src/__mocks__/fileMock.js",
66
67
  "^@truedat/([^/]+)$": "<rootDir>/../$1/src/index",
67
68
  "^@truedat/([^/]+)/(.*)$": "<rootDir>/../$1/src/$2"
68
69
  },
@@ -87,9 +88,9 @@
87
88
  },
88
89
  "dependencies": {
89
90
  "@apollo/client": "^3.7.1",
90
- "@truedat/auth": "5.9.4",
91
- "@truedat/core": "5.9.4",
92
- "@truedat/df": "5.9.4",
91
+ "@truedat/auth": "5.9.5",
92
+ "@truedat/core": "5.9.5",
93
+ "@truedat/df": "5.9.5",
93
94
  "lodash": "^4.17.21",
94
95
  "moment": "^2.29.4",
95
96
  "path-to-regexp": "^1.7.0",
@@ -114,5 +115,5 @@
114
115
  "react-dom": ">= 16.8.6 < 17",
115
116
  "semantic-ui-react": ">= 2.0.3 < 2.2"
116
117
  },
117
- "gitHead": "63e5534704106cdab8d4294b1b1f52ac7fc36e02"
118
+ "gitHead": "e5921f6b5e5a2142ac6be90ad269d5e1fecb1e2c"
118
119
  }
@@ -0,0 +1 @@
1
+ module.exports = "test-file-stub";
@@ -1,9 +1,11 @@
1
1
  import _ from "lodash/fp";
2
- import React, { useEffect } from "react";
2
+ import React, { useEffect, useState } from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { connect } from "react-redux";
5
- import { Grid, Segment } from "semantic-ui-react";
5
+ import { Grid, Header, Image, Segment } from "semantic-ui-react";
6
6
  import { useParams, useLocation } from "react-router-dom";
7
+ import searchImage from "assets/searching.png";
8
+ import { FormattedMessage, useIntl } from "react-intl";
7
9
  import { saveNavFilter as saveNavFilterRoutine } from "../routines";
8
10
  import FilteredNav from "./FilteredNav";
9
11
  import StructureCrumbs from "./StructureCrumbs";
@@ -18,6 +20,20 @@ const isBucketFilter = _.flow(
18
20
  _.any((entry) => entry.startsWith("metadata", "note"))
19
21
  );
20
22
 
23
+ const EmptyImage = () => (
24
+ <div
25
+ style={{
26
+ textAlign: "center",
27
+ paddingBottom: "100px",
28
+ }}
29
+ >
30
+ <Image className="search" src={searchImage} />
31
+ <span className="system-structures-search__text">
32
+ <FormattedMessage id="sytems.structures.select_message" />
33
+ </span>
34
+ </div>
35
+ );
36
+
21
37
  export const BucketView = ({
22
38
  showGrantRequestCart,
23
39
  saveNavFilter,
@@ -26,13 +42,20 @@ export const BucketView = ({
26
42
  const params = useParams();
27
43
  const { id: structureId } = params;
28
44
  const location = useLocation();
45
+ const [navFilterOneProp, setNavFilterOneProp] = useState({});
46
+ const { formatMessage } = useIntl();
47
+
48
+ const getNavFilterURLParams = _.flow(
49
+ _.path("search"),
50
+ (search) => new URLSearchParams(search).entries(),
51
+ (entries) => Object.fromEntries(entries),
52
+ _.pick(["propertyPath", "propertyValue"])
53
+ );
29
54
 
30
55
  useEffect(() => {
56
+ _.flow(getNavFilterURLParams, setNavFilterOneProp)(location);
31
57
  _.flow(
32
- _.path("search"),
33
- (search) => new URLSearchParams(search).entries(),
34
- (entries) => Object.fromEntries(entries),
35
- _.pick(["propertyPath", "propertyValue"]),
58
+ getNavFilterURLParams,
36
59
  _.values,
37
60
  (keyValue) => Object.fromEntries(new Map([keyValue]).entries()),
38
61
  saveNavFilter
@@ -64,7 +87,19 @@ export const BucketView = ({
64
87
  <StructureTabPaneRoutes />
65
88
  </>
66
89
  ) : (
67
- <p> {JSON.stringify(navFilter)} </p>
90
+ <>
91
+ <Header as="h1">
92
+ <FormattedMessage id="bucketView.header" />
93
+ </Header>
94
+ <Header as="h2">
95
+ {navFilterOneProp?.propertyPath
96
+ ? `${formatMessage({
97
+ id: navFilterOneProp.propertyPath,
98
+ })} > ${navFilterOneProp?.propertyValue}`
99
+ : null}
100
+ </Header>
101
+ <EmptyImage />
102
+ </>
68
103
  )}
69
104
  </Segment>
70
105
  </Grid.Column>
@@ -9,6 +9,15 @@ import { FormattedNumber } from "react-intl";
9
9
  import { CardGroupsAccordion } from "@truedat/core/components";
10
10
  import { linkTo } from "@truedat/core/routes";
11
11
 
12
+ const moveMissingBucketToTheEnd = (buckets) =>
13
+ _.sortBy(({ key }) => (key === "_missing" ? 1 : 0))(buckets);
14
+
15
+ const orderBuckets = (buckets) =>
16
+ _.flow(
17
+ _.orderBy([({ key }) => key.toLowerCase()], ["asc"]),
18
+ moveMissingBucketToTheEnd
19
+ )(buckets);
20
+
12
21
  export const CatalogCustomViewCards = ({ structureFilters }) => {
13
22
  const { propertyPath } = useParams();
14
23
  const groups = [];
@@ -27,7 +36,7 @@ export const CatalogCustomViewCards = ({ structureFilters }) => {
27
36
  name={name}
28
37
  structures_count={structures_count}
29
38
  />
30
- ))(structureFilters[propertyPath]?.buckets)}
39
+ ))(orderBuckets(structureFilters[propertyPath]?.buckets))}
31
40
  </Card.Group>
32
41
  );
33
42
  };
@@ -27,6 +27,9 @@ const filterQueryParams = _.flow(
27
27
  );
28
28
 
29
29
  export const SystemCrumb = ({ id, name, navFilter }) => {
30
+ const [propertyPath, propertyValue] = !_.isEmpty(navFilter)
31
+ ? _.toPairs(navFilter)[0]
32
+ : [null, null];
30
33
  return (
31
34
  <>
32
35
  {_.isEmpty(navFilter) || navFilter?.system_id ? (
@@ -38,13 +41,23 @@ export const SystemCrumb = ({ id, name, navFilter }) => {
38
41
  {name}
39
42
  </Breadcrumb.Section>
40
43
  ) : (
41
- <Breadcrumb.Section
42
- as={Link}
43
- to={`${linkTo.BUCKET_VIEW()}?${filterQueryParams(navFilter)}`}
44
- active={false}
45
- >
46
- {JSON.stringify(navFilter)}
47
- </Breadcrumb.Section>
44
+ <>
45
+ <Breadcrumb.Section
46
+ as={Link}
47
+ to={`${linkTo.BUCKETS_VIEW({ propertyPath })}`}
48
+ active={false}
49
+ >
50
+ <FormattedMessage id={propertyPath} />
51
+ </Breadcrumb.Section>
52
+ <Breadcrumb.Divider icon="right angle" />
53
+ <Breadcrumb.Section
54
+ as={Link}
55
+ to={`${linkTo.BUCKET_VIEW()}?${filterQueryParams(navFilter)}`}
56
+ active={false}
57
+ >
58
+ {propertyValue}
59
+ </Breadcrumb.Section>
60
+ </>
48
61
  )}
49
62
  <Breadcrumb.Divider icon="right angle" />
50
63
  </>
@@ -53,6 +66,7 @@ export const SystemCrumb = ({ id, name, navFilter }) => {
53
66
 
54
67
  SystemCrumb.propTypes = {
55
68
  id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
69
+ navFilter: PropTypes.object,
56
70
  name: PropTypes.string,
57
71
  };
58
72
 
@@ -23,6 +23,11 @@ const filterQueryParams = _.flow(
23
23
  (queryParams) => new URLSearchParams(queryParams)
24
24
  );
25
25
 
26
+ const bucketToBreadcrumbs = ({ navFilter, formatMessage }) => {
27
+ const [propertyPath, propertyValue] = _.toPairs(navFilter)[0];
28
+ return `${formatMessage({ id: propertyPath })} > ${propertyValue}`;
29
+ };
30
+
26
31
  export const StructureItem = ({
27
32
  name,
28
33
  id,
@@ -53,7 +58,11 @@ export const StructureItem = ({
53
58
  >
54
59
  <List.Icon name={getIcon(formatMessage, type)} verticalAlign="middle" />
55
60
  <List.Content>
56
- <List.Description>{name}</List.Description>
61
+ <List.Description>
62
+ {type == "bucket"
63
+ ? bucketToBreadcrumbs({ navFilter, formatMessage })
64
+ : name}
65
+ </List.Description>
57
66
  </List.Content>
58
67
  </List.Item>
59
68
  );
@@ -51,9 +51,7 @@ export const StructureView = ({
51
51
  )}
52
52
  </Grid.Row>
53
53
  </Grid>
54
- ) : (
55
- <p>NADA</p>
56
- )}
54
+ ) : null}
57
55
  </Segment>
58
56
  );
59
57
  };
@@ -2,10 +2,11 @@ import _ from "lodash/fp";
2
2
  import React 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, useRouteMatch } from "react-router-dom";
6
6
  import { Header, Icon, Segment, Divider } from "semantic-ui-react";
7
7
  import { FormattedMessage } from "react-intl";
8
8
  import { linkTo } from "@truedat/core/routes";
9
+ import { BUCKETS_VIEW } from "@truedat/core/routes";
9
10
  import { structureRowsSelector } from "../selectors";
10
11
  import StructureSelectedFilters from "./StructureSelectedFilters";
11
12
  import StructuresOptions from "./StructuresOptions";
@@ -15,17 +16,33 @@ import StructuresSearchResults from "./StructuresSearchResults";
15
16
  import SystemCards from "./SystemCards";
16
17
  import CatalogCustomViewCards from "./CatalogCustomViewCards";
17
18
 
18
- export const StructuresHeader = () => (
19
- <Header as="h2">
20
- <Icon circular name="block layout" />
21
- <Header.Content>
22
- <FormattedMessage id="structures.header" />
23
- <Header.Subheader>
24
- <FormattedMessage id="structures.subheader" />
25
- </Header.Subheader>
26
- </Header.Content>
27
- </Header>
28
- );
19
+ const StructuresHeader = () => {
20
+ const match = useRouteMatch(BUCKETS_VIEW);
21
+
22
+ return (
23
+ <Header as="h2">
24
+ <Icon circular name="block layout" />
25
+ <Header.Content>
26
+ <FormattedMessage
27
+ id={
28
+ !match?.params?.propertyPath
29
+ ? "structures.header"
30
+ : "bucketsView.header"
31
+ }
32
+ />
33
+ <Header.Subheader>
34
+ <FormattedMessage
35
+ id={
36
+ !match?.params?.propertyPath
37
+ ? "structures.subheader"
38
+ : match?.params?.propertyPath
39
+ }
40
+ />
41
+ </Header.Subheader>
42
+ </Header.Content>
43
+ </Header>
44
+ );
45
+ };
29
46
 
30
47
  const StructuresViewContent = ({
31
48
  actions = {},
@@ -4,6 +4,7 @@ import PropTypes from "prop-types";
4
4
  import { connect } from "react-redux";
5
5
  import { Grid, Segment } from "semantic-ui-react";
6
6
  import { useParams } from "react-router-dom";
7
+ import { withRouter } from "react-router-dom";
7
8
  import { getSystem, getSystemTemplate } from "../selectors";
8
9
  import { saveNavFilter as saveNavFilterRoutine } from "../routines";
9
10
  import FilteredNav from "./FilteredNav";
@@ -54,13 +55,17 @@ SystemStructures.propTypes = {
54
55
  systemTemplate: PropTypes.object,
55
56
  };
56
57
 
57
- const mapStateToProps = (state) => ({
58
- navFilter: state?.navFilter,
59
- system: getSystem(state),
60
- systemStructuresLoading: _.prop("systemStructuresLoading")(state),
61
- systemTemplate: getSystemTemplate(state),
62
- });
58
+ const mapStateToProps = (state, props) => {
59
+ return {
60
+ navFilter: state?.navFilter,
61
+ system: getSystem(state, props.match.params.id),
62
+ systemStructuresLoading: _.prop("systemStructuresLoading")(state),
63
+ systemTemplate: getSystemTemplate(state),
64
+ };
65
+ };
63
66
 
64
- export default connect(mapStateToProps, {
65
- saveNavFilter: saveNavFilterRoutine,
66
- })(SystemStructures);
67
+ export default withRouter(
68
+ connect(mapStateToProps, {
69
+ saveNavFilter: saveNavFilterRoutine,
70
+ })(SystemStructures)
71
+ );
@@ -3,6 +3,7 @@ import { render } from "@truedat/test/render";
3
3
  import { waitFor } from "@testing-library/react";
4
4
  import { MemoryRouter } from "react-router-dom";
5
5
  import { BucketView } from "../BucketView";
6
+ import en from "../../messages/en";
6
7
 
7
8
  const state = {
8
9
  authentication: { role: "admin" },
@@ -24,6 +25,12 @@ describe("<BucketView />", () => {
24
25
  const navFilter = {};
25
26
  const renderOpts = {
26
27
  state,
28
+ messages: {
29
+ en: {
30
+ ...en,
31
+ "metadata.region": "metadata.region",
32
+ },
33
+ },
27
34
  };
28
35
 
29
36
  render(
@@ -9,6 +9,8 @@ export default {
9
9
  "alert.updateReferenceDataset.success.header": "Dataset updated",
10
10
  "alert.updateTag.failed.header": "Error editing structure tag",
11
11
  "alert.updateSystem.failed.header": "Error updating system",
12
+ "bucketView.header": "Catalog view",
13
+ "bucketsView.header": "Catalog views",
12
14
  "createTag.error.name.has already been taken":
13
15
  "A Structure Tag with this name already exists",
14
16
  "execution.pending.content":
@@ -11,6 +11,8 @@ export default {
11
11
  "Dataset actualizado correctamente",
12
12
  "alert.updateTag.failed.header": "Error al editar Etiqueta",
13
13
  "alert.updateSystem.failed.header": "Error actualizando sistema",
14
+ "bucketView.header": "Catalog view",
15
+ "bucketsView.header": "Catalog views",
14
16
  "createTag.error.name.has already been taken":
15
17
  "Ya existe una Etiqueta de Estructura con ese nombre",
16
18
  "execution.pending.content":
@@ -7,7 +7,7 @@ describe("selectors: getSystem", () => {
7
7
  const systems = [system1, system2];
8
8
  const systemId = 1;
9
9
  const state = { systems, systemId };
10
- const res = getSystem(state);
10
+ const res = getSystem(state, systemId);
11
11
  expect(res).toBe(system1);
12
12
  });
13
13
  });
@@ -29,7 +29,7 @@ export const getStructureParent = createSelector(
29
29
  (structure, structureParents, navFilter) =>
30
30
  _.isEmpty(structureParents)
31
31
  ? !_.isEmpty(structure) && isBucketFilter(navFilter)
32
- ? { type: "bucket", name: JSON.stringify(navFilter) }
32
+ ? { type: "bucket" }
33
33
  : _.has("system")(structure)
34
34
  ? rootNavItem(structure)
35
35
  : {}
@@ -2,6 +2,6 @@ import _ from "lodash/fp";
2
2
  import { createSelector } from "reselect";
3
3
 
4
4
  export const getSystem = createSelector(
5
- [_.prop("systems"), _.prop("systemId")],
6
- (systems, systemId) => _.find(_.propEq("id", systemId))(systems)
5
+ [(state) => state?.systems, (_, systemId) => systemId],
6
+ (systems, systemId) => _.find(({ id }) => id == systemId)(systems)
7
7
  );