@truedat/bg 7.1.3 → 7.1.4

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/bg",
3
- "version": "7.1.3",
3
+ "version": "7.1.4",
4
4
  "description": "Truedat Web Business Glossary",
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": "7.1.3",
37
+ "@truedat/test": "7.1.4",
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",
@@ -86,9 +86,9 @@
86
86
  ]
87
87
  },
88
88
  "dependencies": {
89
- "@truedat/core": "7.1.3",
90
- "@truedat/df": "7.1.3",
91
- "@truedat/lm": "7.1.3",
89
+ "@truedat/core": "7.1.4",
90
+ "@truedat/df": "7.1.4",
91
+ "@truedat/lm": "7.1.4",
92
92
  "decode-uri-component": "^0.2.2",
93
93
  "file-saver": "^2.0.5",
94
94
  "moment": "^2.29.4",
@@ -111,5 +111,5 @@
111
111
  "react-dom": ">= 16.8.6 < 17",
112
112
  "semantic-ui-react": ">= 2.0.3 < 2.2"
113
113
  },
114
- "gitHead": "10542097513c7492b7bde1eed3de39746c39b908"
114
+ "gitHead": "4b951559f6e84f85ed054bf9afe8699dc57f7b8f"
115
115
  }
@@ -1,19 +1,16 @@
1
- import _ from "lodash/fp";
2
1
  import React from "react";
3
2
  import PropTypes from "prop-types";
4
3
  import { Breadcrumb } from "semantic-ui-react";
5
- import { useActiveRoute } from "@truedat/core/hooks";
6
- import { connect } from "react-redux";
7
4
  import { Link, useHistory } from "react-router-dom";
8
5
  import { FormattedMessage, useIntl } from "react-intl";
9
- import {
10
- CONCEPTS_BULK_UPDATE,
11
- CONCEPTS,
12
- CONCEPTS_PENDING,
13
- linkTo,
14
- } from "@truedat/core/routes";
15
-
16
- export const ConceptCrumbs = ({
6
+ import { connect } from "react-redux";
7
+
8
+ import { useActiveRoute } from "@truedat/core/hooks";
9
+ import { CONCEPTS_BULK_UPDATE, linkTo } from "@truedat/core/routes";
10
+ import { getConceptVersionPath } from "../selectors/getConceptVersionPath";
11
+
12
+ const ConceptCrumbs = ({
13
+ conceptVersionPath,
17
14
  name: defaultName,
18
15
  status,
19
16
  conceptAction,
@@ -22,61 +19,107 @@ export const ConceptCrumbs = ({
22
19
  i18n_content,
23
20
  }) => {
24
21
  const { locale } = useIntl();
22
+ const history = useHistory();
23
+ const bulkUpdateActive = useActiveRoute(CONCEPTS_BULK_UPDATE);
25
24
 
26
- const i18n_lang_content = _.get(locale)(i18n_content);
27
-
28
- const name = _.isUndefined(i18n_lang_content)
29
- ? defaultName
30
- : i18n_lang_content?.name;
25
+ const name = i18n_content?.[locale]?.name ?? defaultName;
31
26
 
32
- const bulkUpdateActive = useActiveRoute(CONCEPTS_BULK_UPDATE);
33
- const history = useHistory();
34
27
  const fromStatus = () =>
35
28
  status === "published"
36
- ? history.push(CONCEPTS)
37
- : history.push(CONCEPTS_PENDING);
29
+ ? history.push(linkTo.CONCEPTS)
30
+ : history.push(linkTo.CONCEPTS_PENDING);
31
+
38
32
  const goBack = () => (bulkUpdateActive ? history.goBack() : fromStatus());
39
- return name || conceptAction ? (
33
+
34
+ const additionalCrumbs = [];
35
+
36
+ if (id) {
37
+ if (conceptAction) {
38
+ additionalCrumbs.push({
39
+ id: null,
40
+ path: linkTo.CONCEPT_VERSION({ business_concept_id, id }),
41
+ label: name,
42
+ });
43
+ } else {
44
+ additionalCrumbs.push({
45
+ id: null,
46
+ path: null,
47
+ label: name,
48
+ });
49
+ }
50
+ }
51
+
52
+ if (conceptAction) {
53
+ additionalCrumbs.push({
54
+ id: conceptAction,
55
+ path: null,
56
+ });
57
+ }
58
+
59
+ const allCrumbs = [...conceptVersionPath, ...additionalCrumbs];
60
+
61
+ if (allCrumbs.length === 0) {
62
+ return null;
63
+ }
64
+
65
+ return (
40
66
  <Breadcrumb>
41
- <Breadcrumb.Section onClick={goBack} active={false}>
42
- <FormattedMessage id="concepts.crumbs.top" />
43
- </Breadcrumb.Section>
44
- {name && (
45
- <>
46
- <Breadcrumb.Divider icon="right angle" />
47
- {conceptAction ? (
48
- <Breadcrumb.Section
49
- as={Link}
50
- to={linkTo.CONCEPT_VERSION({ business_concept_id, id })}
51
- active={false}
52
- >
53
- {name}
67
+ {allCrumbs.map((crumb, index) => {
68
+ const isLast = index === allCrumbs.length - 1;
69
+
70
+ const crumbLabel = crumb.id ? (
71
+ <FormattedMessage id={crumb.id} />
72
+ ) : (
73
+ crumb.label
74
+ );
75
+
76
+ const sectionProps = crumb.path
77
+ ? { to: crumb.path, as: Link }
78
+ : {
79
+ as: "span",
80
+ onClick: index === 0 ? goBack : undefined,
81
+ style: { cursor: index === 0 ? "pointer" : "default" },
82
+ };
83
+
84
+ return (
85
+ <React.Fragment key={index}>
86
+ <Breadcrumb.Section active={isLast} {...sectionProps}>
87
+ {crumbLabel}
54
88
  </Breadcrumb.Section>
55
- ) : (
56
- <Breadcrumb.Section active>{name}</Breadcrumb.Section>
57
- )}
58
- </>
59
- )}
60
-
61
- {conceptAction && (
62
- <>
63
- <Breadcrumb.Divider icon="right angle" />
64
- <Breadcrumb.Section active>
65
- <FormattedMessage id={conceptAction} />
66
- </Breadcrumb.Section>
67
- </>
68
- )}
89
+ {!isLast && <Breadcrumb.Divider icon="right angle" />}
90
+ </React.Fragment>
91
+ );
92
+ })}
69
93
  </Breadcrumb>
70
- ) : null;
94
+ );
71
95
  };
72
96
 
73
97
  ConceptCrumbs.propTypes = {
74
- business_concept_id: PropTypes.string,
98
+ conceptVersionPath: PropTypes.arrayOf(
99
+ PropTypes.shape({
100
+ id: PropTypes.string,
101
+ path: PropTypes.string,
102
+ })
103
+ ),
75
104
  name: PropTypes.string,
105
+ status: PropTypes.string,
76
106
  conceptAction: PropTypes.string,
107
+ business_concept_id: PropTypes.number,
77
108
  id: PropTypes.number,
78
- status: PropTypes.string,
109
+ i18n_content: PropTypes.object,
110
+ };
111
+
112
+ const mapStateToProps = (state) => {
113
+ const { concept } = state;
114
+
115
+ return {
116
+ conceptVersionPath: getConceptVersionPath(state),
117
+ name: concept.name,
118
+ status: concept.status,
119
+ business_concept_id: concept.business_concept_id,
120
+ id: concept.id,
121
+ i18n_content: concept.i18n_content,
122
+ };
79
123
  };
80
124
 
81
- const mapStateToProps = ({ concept }) => ({ ...concept });
82
125
  export default connect(mapStateToProps)(ConceptCrumbs);
@@ -14,7 +14,12 @@ import {
14
14
  CONCEPTS_NEW,
15
15
  CONCEPTS_PENDING,
16
16
  CONCEPTS_DEPRECATED,
17
- CONCEPTS_SUBSCOPED,
17
+ CONCEPTS_SUBSCOPE,
18
+ CONCEPTS_SIDEMENU_MANAGEMENT_LINKS,
19
+ CONCEPTS_SIDEMENU_MANAGEMENT_UPLOADS,
20
+ CONCEPTS_SIDEMENU_SUBSCOPE,
21
+ CONCEPTS_SIDEMENU_SUBSCOPE_PENDING,
22
+ CONCEPTS_SIDEMENU_SUBSCOPE_DEPRECATED,
18
23
  CONCEPTS,
19
24
  } from "@truedat/core/routes";
20
25
  import { useIntl } from "react-intl";
@@ -42,212 +47,243 @@ const RelationsGraphLoader = React.lazy(() =>
42
47
  import("@truedat/lm/components/RelationsGraphLoader")
43
48
  );
44
49
 
45
- export const ConceptRoutes = ({ concept, conceptLoaded, templatesLoaded }) => {
50
+ const ConceptRoutes = ({ concept, conceptLoaded, templatesLoaded }) => {
46
51
  const { formatMessage } = useIntl();
47
52
  const authorized = useAuthorized([
48
53
  "business_glossary_view",
49
54
  "business_glossary_management",
50
55
  ]);
56
+ if (!authorized) {
57
+ return <Unauthorized />;
58
+ }
59
+
51
60
  const pendingConceptsDefaultFilters = {
52
61
  status: ["pending_approval", "draft", "rejected"],
53
62
  };
63
+
54
64
  const archivedConceptsDefaultFilters = {
55
65
  status: ["deprecated"],
56
66
  };
57
67
 
68
+ const renderConceptsComponent = (props, filters, key) => {
69
+ const subscope = _.get("match.params.subscope", props) || "";
70
+ const baseId = `concepts.${subscope || "default"}.${key}`;
71
+
72
+ const showCreate = key === "pending";
73
+ const showUpload = key === "pending";
74
+
75
+ return (
76
+ <Concepts
77
+ defaultFilters={{
78
+ ...filters,
79
+ "template.subscope": subscope ? [subscope] : undefined,
80
+ }}
81
+ header={formatMessage({ id: `${baseId}.header` })}
82
+ subheader={formatMessage({ id: `${baseId}.subheader` })}
83
+ icon={formatMessage({
84
+ id: `concepts.${subscope}.icon`,
85
+ defaultMessage: "tags",
86
+ })}
87
+ create={showCreate}
88
+ upload={showUpload}
89
+ />
90
+ );
91
+ };
92
+
58
93
  return (
59
- <>
94
+ <Switch>
60
95
  <Route
61
96
  exact
62
97
  path={CONCEPTS_BULK_UPLOAD_EVENTS}
63
- render={() =>
64
- authorized ? <ConceptsUploadEvents /> : <Unauthorized />
65
- }
98
+ render={() => <ConceptsUploadEvents />}
99
+ />
100
+ <Route
101
+ exact
102
+ path={CONCEPTS_SIDEMENU_MANAGEMENT_UPLOADS}
103
+ render={() => <ConceptsUploadEvents />}
104
+ />
105
+
106
+ <Route
107
+ exact
108
+ path={CONCEPTS_SIDEMENU_MANAGEMENT_LINKS}
109
+ render={() => (
110
+ <>
111
+ <RelationTagsLoader />
112
+ <ConceptsLinksManagement
113
+ header={formatMessage({ id: "concepts.header.linksManager" })}
114
+ subheader={formatMessage({
115
+ id: "concepts.subheader.linksManager",
116
+ })}
117
+ icon={formatMessage({
118
+ id: "concepts.header.linksManager.icon",
119
+ defaultMessage: "linkify",
120
+ })}
121
+ />
122
+ </>
123
+ )}
66
124
  />
125
+
67
126
  <Route
68
127
  exact
69
128
  path={CONCEPT_LINKS_MANAGEMENT}
70
- render={() =>
71
- authorized ? (
72
- <>
73
- <RelationTagsLoader />
74
- <ConceptsLinksManagement
75
- header={formatMessage({
76
- id: "concepts.header.linksManager",
77
- })}
78
- subheader={formatMessage({
79
- id: "concepts.subheader.linksManager",
80
- })}
81
- icon={formatMessage({
82
- id: "concepts.header.linksManager.icon",
83
- defaultMessage: "linkify",
84
- })}
85
- />
86
- </>
87
- ) : (
88
- <Unauthorized />
89
- )
90
- }
129
+ render={() => (
130
+ <>
131
+ <RelationTagsLoader />
132
+ <ConceptsLinksManagement
133
+ header={formatMessage({ id: "concepts.header.linksManager" })}
134
+ subheader={formatMessage({
135
+ id: "concepts.subheader.linksManager",
136
+ })}
137
+ icon={formatMessage({
138
+ id: "concepts.header.linksManager.icon",
139
+ defaultMessage: "linkify",
140
+ })}
141
+ />
142
+ </>
143
+ )}
91
144
  />
92
145
 
93
146
  <Route
94
147
  exact
95
148
  path={CONCEPTS_PENDING}
96
- render={() =>
149
+ render={(routeProps) =>
97
150
  authorized ? (
98
- <>
99
- <Concepts
100
- defaultFilters={pendingConceptsDefaultFilters}
101
- header={formatMessage({ id: "concepts.header.manage" })}
102
- subheader={formatMessage({ id: "concepts.subheader.manage" })}
103
- icon={formatMessage({
104
- id: "concepts.header.manage.icon",
105
- defaultMessage: "edit",
106
- })}
107
- create
108
- upload
109
- />
110
- </>
151
+ renderConceptsComponent(
152
+ routeProps,
153
+ pendingConceptsDefaultFilters,
154
+ "pending"
155
+ )
111
156
  ) : (
112
157
  <Unauthorized />
113
158
  )
114
159
  }
115
160
  />
161
+
116
162
  <Route
117
163
  exact
118
164
  path={CONCEPTS_DEPRECATED}
119
- render={() =>
120
- authorized ? (
121
- <>
122
- <Concepts
123
- defaultFilters={archivedConceptsDefaultFilters}
124
- header={formatMessage({ id: "concepts.header.deprecated" })}
125
- subheader={formatMessage({
126
- id: "concepts.subheader.deprecated",
127
- })}
128
- icon={formatMessage({
129
- id: "concepts.header.deprecated.icon",
130
- defaultMessage: "archive",
131
- })}
132
- update={false}
133
- />
134
- </>
135
- ) : (
136
- <Unauthorized />
165
+ render={(routeProps) =>
166
+ renderConceptsComponent(
167
+ routeProps,
168
+ archivedConceptsDefaultFilters,
169
+ "deprecated"
137
170
  )
138
171
  }
139
172
  />
173
+
140
174
  <Route
141
175
  exact
142
- path={CONCEPTS_SUBSCOPED}
143
- render={(props) => {
144
- const subscope = _.prop("match.params.subscope")(props);
145
- const defaultFilters = {
146
- status: ["published"],
147
- ...(subscope ? { "template.subscope": [subscope] } : {}),
148
- };
149
- return authorized ? (
150
- <>
151
- <Concepts
152
- header={subscope}
153
- icon={formatMessage({
154
- id: "concepts.header.icon",
155
- defaultMessage: "tags",
156
- })}
157
- defaultFilters={defaultFilters}
158
- />
159
- </>
160
- ) : (
161
- <Unauthorized />
162
- );
163
- }}
176
+ path={CONCEPTS_SUBSCOPE}
177
+ render={(routeProps) =>
178
+ renderConceptsComponent(routeProps, { status: ["published"] }, "main")
179
+ }
164
180
  />
165
-
166
181
  <Route
167
- path={CONCEPTS}
168
- render={() =>
169
- authorized ? (
170
- <Switch>
171
- <Route
172
- exact
173
- path={CONCEPTS}
174
- render={() => (
175
- <>
176
- <Concepts
177
- defaultFilters={{
178
- status: ["published"],
179
- "template.subscope": "",
180
- }}
181
- header={formatMessage({ id: "concepts.header" })}
182
- subheader={formatMessage({
183
- id: "concepts.subheader.view",
184
- })}
185
- icon={formatMessage({
186
- id: "concepts.header.icon",
187
- defaultMessage: "tags",
188
- })}
189
- />
190
- </>
191
- )}
192
- />
193
- <Route
194
- exact
195
- path={CONCEPTS_BULK_UPDATE}
196
- render={() => (
197
- <>
198
- <ConceptCrumbs conceptAction="actions.update" />
199
- <TemplatesLoader scope="bg" />
200
- {templatesLoaded && <ConceptsBulkUpdate />}
201
- </>
202
- )}
203
- />
204
- <Route
205
- exact
206
- path={CONCEPTS_NEW}
207
- render={() => (
208
- <>
209
- <ConceptCrumbs conceptAction="concepts.actions.create" />
210
- <ConceptCreate />
211
- </>
212
- )}
213
- />
214
- <Route
215
- exact
216
- path={CONCEPT_EDIT}
217
- render={() => (
218
- <>
219
- <ConceptCrumbs conceptAction="concepts.actions.edit" />
220
- <TemplatesLoader scope="bg" />
221
- <ConceptLoader />
222
- {conceptLoaded && templatesLoaded ? <ConceptEdit /> : null}
223
- </>
224
- )}
225
- />
226
- <Route
227
- path={CONCEPT_VERSION}
228
- render={() => (
229
- <>
230
- <ConceptLoader />
231
- <RelationTagsLoader />
232
- {conceptLoaded ? (
233
- <>
234
- <ConceptSubscriptionLoader />
235
- <RelationsGraphLoader
236
- resource_id={concept?.business_concept_id}
237
- />
238
- <Concept />
239
- </>
240
- ) : null}
241
- </>
242
- )}
243
- />
244
- </Switch>
245
- ) : (
246
- <Unauthorized />
182
+ exact
183
+ path={CONCEPTS_SIDEMENU_SUBSCOPE}
184
+ render={(routeProps) =>
185
+ renderConceptsComponent(routeProps, { status: ["published"] }, "main")
186
+ }
187
+ />
188
+ <Route
189
+ exact
190
+ path={CONCEPTS_SIDEMENU_SUBSCOPE_PENDING}
191
+ render={(routeProps) =>
192
+ renderConceptsComponent(
193
+ routeProps,
194
+ { status: ["pending_approval", "draft", "rejected"] },
195
+ "pending"
196
+ )
197
+ }
198
+ />
199
+ <Route
200
+ exact
201
+ path={CONCEPTS_SIDEMENU_SUBSCOPE_DEPRECATED}
202
+ render={(routeProps) =>
203
+ renderConceptsComponent(
204
+ routeProps,
205
+ { status: ["deprecated"] },
206
+ "deprecated"
247
207
  )
248
208
  }
249
209
  />
250
- </>
210
+ <Route
211
+ exact
212
+ path={CONCEPT_EDIT}
213
+ render={() => (
214
+ <>
215
+ <ConceptCrumbs conceptAction="concepts.actions.edit" />
216
+ <TemplatesLoader scope="bg" />
217
+ <ConceptLoader />
218
+ {conceptLoaded && templatesLoaded ? <ConceptEdit /> : null}
219
+ </>
220
+ )}
221
+ />
222
+ <Route
223
+ path={CONCEPT_VERSION}
224
+ render={() => (
225
+ <>
226
+ <ConceptLoader />
227
+ <RelationTagsLoader />
228
+ {conceptLoaded && (
229
+ <>
230
+ <ConceptSubscriptionLoader />
231
+ <RelationsGraphLoader
232
+ resource_id={concept?.business_concept_id}
233
+ />
234
+ <Concept />
235
+ </>
236
+ )}
237
+ </>
238
+ )}
239
+ />
240
+ <Route
241
+ exact
242
+ path={CONCEPTS_NEW}
243
+ render={() => (
244
+ <>
245
+ <ConceptCrumbs conceptAction="concepts.actions.create" />
246
+ <ConceptCreate />
247
+ </>
248
+ )}
249
+ />
250
+ <Route
251
+ exact
252
+ path={CONCEPTS_BULK_UPDATE}
253
+ render={() => (
254
+ <>
255
+ <ConceptCrumbs conceptAction="actions.update" />
256
+ <TemplatesLoader scope="bg" />
257
+ {templatesLoaded && <ConceptsBulkUpdate />}
258
+ </>
259
+ )}
260
+ />
261
+ <Route
262
+ exact
263
+ path={CONCEPTS_NEW}
264
+ render={() => (
265
+ <>
266
+ <ConceptCrumbs conceptAction="concepts.actions.create" />
267
+ <ConceptCreate />
268
+ </>
269
+ )}
270
+ />
271
+ <Route
272
+ exact
273
+ path={CONCEPTS}
274
+ render={() => (
275
+ <Concepts
276
+ defaultFilters={{ status: ["published"], "template.subscope": "" }}
277
+ header={formatMessage({ id: "concepts.header" })}
278
+ subheader={formatMessage({ id: "concepts.subheader.view" })}
279
+ icon={formatMessage({
280
+ id: "concepts.header.icon",
281
+ defaultMessage: "tags",
282
+ })}
283
+ />
284
+ )}
285
+ />
286
+ </Switch>
251
287
  );
252
288
  };
253
289
 
@@ -257,10 +293,10 @@ ConceptRoutes.propTypes = {
257
293
  templatesLoaded: PropTypes.bool,
258
294
  };
259
295
 
260
- const mapStateToProps = ({ concept, templatesLoading, templates }) => ({
261
- conceptLoaded: !_.isEmpty(concept),
262
- templatesLoaded: !templatesLoading && !_.isEmpty(templates),
263
- concept,
296
+ const mapStateToProps = (state) => ({
297
+ concept: state.concept,
298
+ conceptLoaded: !_.isEmpty(state.concept),
299
+ templatesLoaded: !state.templatesLoading && !_.isEmpty(state.templates),
264
300
  });
265
301
 
266
302
  export default connect(mapStateToProps)(ConceptRoutes);
@@ -1,7 +1,6 @@
1
1
  import React from "react";
2
2
  import PropTypes from "prop-types";
3
3
  import { Header, Icon, Segment } from "semantic-ui-react";
4
- import ConceptCrumbs from "./ConceptCrumbs";
5
4
  import ConceptsPanel from "./ConceptsPanel";
6
5
 
7
6
  export const Concepts = ({
@@ -13,7 +12,6 @@ export const Concepts = ({
13
12
  }) => {
14
13
  return (
15
14
  <>
16
- <ConceptCrumbs />
17
15
  <Segment>
18
16
  <Header as="h2">
19
17
  <Icon circular name={icon} />