@truedat/dd 5.9.3 → 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.3",
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.3",
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.3",
91
- "@truedat/core": "5.9.3",
92
- "@truedat/df": "5.9.3",
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": "703abeeedf1ca0f6ecbc09c9633178e9dcd83e20"
118
+ "gitHead": "e5921f6b5e5a2142ac6be90ad269d5e1fecb1e2c"
118
119
  }
@@ -0,0 +1 @@
1
+ module.exports = "test-file-stub";
@@ -382,7 +382,7 @@ export const DATA_STRUCTURE_VERSION_QUERY = gql`
382
382
  min
383
383
  null_count
384
384
  most_frequent
385
- value
385
+ total_count
386
386
  }
387
387
  source {
388
388
  id
@@ -428,7 +428,6 @@ export const DATA_STRUCTURE_VERSION_QUERY = gql`
428
428
  patterns
429
429
  total_count
430
430
  unique_count
431
- value
432
431
  }
433
432
  note(select_fields: $note_fields)
434
433
  }
@@ -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
  );