@truedat/core 5.0.1 → 5.0.2
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 +8 -0
- package/package.json +3 -3
- package/src/components/AdminMenu.js +3 -1
- package/src/components/CSVFileModal.js +63 -0
- package/src/components/DescriptionInput.js +39 -0
- package/src/components/__tests__/__snapshots__/AdminMenu.spec.js.snap +13 -0
- package/src/components/index.js +6 -2
- package/src/messages/en.js +1 -0
- package/src/messages/es.js +1 -0
- package/src/routes.js +8 -0
- package/src/services/message.js +21 -0
- package/src/services/swr.js +43 -0
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/core",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2",
|
|
4
4
|
"description": "Truedat Web Core",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"jsnext:main": "src/index.js",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"@testing-library/jest-dom": "^5.16.5",
|
|
36
36
|
"@testing-library/react": "^12.0.0",
|
|
37
37
|
"@testing-library/user-event": "^13.2.1",
|
|
38
|
-
"@truedat/test": "5.0.
|
|
38
|
+
"@truedat/test": "5.0.2",
|
|
39
39
|
"babel-jest": "^28.1.0",
|
|
40
40
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
|
41
41
|
"babel-plugin-lodash": "^3.3.4",
|
|
@@ -117,5 +117,5 @@
|
|
|
117
117
|
"react-dom": ">= 16.8.6 < 17",
|
|
118
118
|
"semantic-ui-react": ">= 2.0.3 < 2.2"
|
|
119
119
|
},
|
|
120
|
-
"gitHead": "
|
|
120
|
+
"gitHead": "627767d6f31541ef09a077d7e535fb488a05700c"
|
|
121
121
|
}
|
|
@@ -2,8 +2,9 @@ import React from "react";
|
|
|
2
2
|
import { useAuthorized } from "../hooks";
|
|
3
3
|
import {
|
|
4
4
|
CONFIGURATIONS,
|
|
5
|
-
|
|
5
|
+
HIERARCHIES,
|
|
6
6
|
I18N_MESSAGES,
|
|
7
|
+
JOBS,
|
|
7
8
|
RELATION_TAGS,
|
|
8
9
|
SOURCES,
|
|
9
10
|
SUBSCRIPTIONS,
|
|
@@ -13,6 +14,7 @@ import Submenu from "./Submenu";
|
|
|
13
14
|
|
|
14
15
|
const items = [
|
|
15
16
|
{ name: "templates", routes: [TEMPLATES] },
|
|
17
|
+
{ name: "hierarchies", routes: [HIERARCHIES] },
|
|
16
18
|
{ name: "relations", routes: [RELATION_TAGS] },
|
|
17
19
|
{ name: "subscriptions", routes: [SUBSCRIPTIONS] },
|
|
18
20
|
{ name: "sources", routes: [SOURCES] },
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { Button } from "semantic-ui-react";
|
|
5
|
+
import { useIntl } from "react-intl";
|
|
6
|
+
import { UploadModal } from "./UploadModal";
|
|
7
|
+
|
|
8
|
+
const CSVFileModal = ({ onSubmit, param }) => {
|
|
9
|
+
const { formatMessage } = useIntl();
|
|
10
|
+
const [processing, setProcessing] = useState(false);
|
|
11
|
+
|
|
12
|
+
const processCSV = (str, delim = ",") => {
|
|
13
|
+
const breakLine = "\n";
|
|
14
|
+
const lines = _.split(breakLine)(str);
|
|
15
|
+
const headers = _.flow(_.head, _.split(delim))(lines);
|
|
16
|
+
const rows = _.tail(lines);
|
|
17
|
+
|
|
18
|
+
const csvMap = rows.map((row) => {
|
|
19
|
+
const values = _.split(delim)(row);
|
|
20
|
+
return headers.reduce(
|
|
21
|
+
(map, header, pos) => _.set(header, values[pos])(map),
|
|
22
|
+
{}
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return csvMap;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const onload = _.flow(_.pathOr("", "target.result"), processCSV, onSubmit);
|
|
30
|
+
|
|
31
|
+
const reader = new FileReader();
|
|
32
|
+
// eslint-disable-next-line fp/no-mutation
|
|
33
|
+
reader.onload = onload;
|
|
34
|
+
|
|
35
|
+
const process = (data) => {
|
|
36
|
+
setProcessing(true);
|
|
37
|
+
const file = data.get(param);
|
|
38
|
+
reader.readAsText(file);
|
|
39
|
+
setProcessing(false);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<UploadModal
|
|
44
|
+
icon="upload"
|
|
45
|
+
trigger={
|
|
46
|
+
<Button secondary floated="right" icon="upload" loading={processing} />
|
|
47
|
+
}
|
|
48
|
+
header={formatMessage({ id: "uploadModal.actions.upload" })}
|
|
49
|
+
content={formatMessage({
|
|
50
|
+
id: "uploadModal.actions.upload.confirmation.content",
|
|
51
|
+
})}
|
|
52
|
+
param={param}
|
|
53
|
+
handleSubmit={process}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
CSVFileModal.propTypes = {
|
|
59
|
+
onSubmit: PropTypes.func,
|
|
60
|
+
param: PropTypes.object,
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export default CSVFileModal;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { useIntl } from "react-intl";
|
|
4
|
+
import { Input } from "semantic-ui-react";
|
|
5
|
+
|
|
6
|
+
const DescriptionInput = ({ value, onChange, disabled = false }) => {
|
|
7
|
+
const { formatMessage } = useIntl();
|
|
8
|
+
const [editionMode, setEditMode] = useState();
|
|
9
|
+
return !editionMode ? (
|
|
10
|
+
<div
|
|
11
|
+
onClick={() => setEditMode(true && !disabled)}
|
|
12
|
+
onFocus={() => setEditMode(true && !disabled)}
|
|
13
|
+
className={disabled ? "description disabled" : "description"}
|
|
14
|
+
>
|
|
15
|
+
{!value || typeof value !== "string"
|
|
16
|
+
? disabled
|
|
17
|
+
? ""
|
|
18
|
+
: formatMessage({ id: "hierarchy.add_description" })
|
|
19
|
+
: value}
|
|
20
|
+
</div>
|
|
21
|
+
) : (
|
|
22
|
+
<Input
|
|
23
|
+
style={{ width: "100%" }}
|
|
24
|
+
onBlur={() => setEditMode(false)}
|
|
25
|
+
placeholder={formatMessage({ id: "hierarchy.add_description" })}
|
|
26
|
+
onChange={onChange}
|
|
27
|
+
value={value == null ? "" : value}
|
|
28
|
+
autoFocus
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
DescriptionInput.propTypes = {
|
|
34
|
+
value: PropTypes.string,
|
|
35
|
+
onChange: PropTypes.func,
|
|
36
|
+
disabled: PropTypes.bool,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default DescriptionInput;
|
|
@@ -43,6 +43,19 @@ exports[`<AdminMenu /> matches the latest snapshot 1`] = `
|
|
|
43
43
|
Templates
|
|
44
44
|
</span>
|
|
45
45
|
</a>
|
|
46
|
+
<a
|
|
47
|
+
aria-checked="false"
|
|
48
|
+
class="item"
|
|
49
|
+
href="/hierarchies"
|
|
50
|
+
name="hierarchies"
|
|
51
|
+
role="option"
|
|
52
|
+
>
|
|
53
|
+
<span
|
|
54
|
+
class="text"
|
|
55
|
+
>
|
|
56
|
+
Hierarchies
|
|
57
|
+
</span>
|
|
58
|
+
</a>
|
|
46
59
|
<a
|
|
47
60
|
aria-checked="false"
|
|
48
61
|
class="item"
|
package/src/components/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import ActiveRoute from "./ActiveRoute";
|
|
2
2
|
import AdminMenu from "./AdminMenu";
|
|
3
|
-
import MembersMenu from "./MembersMenu";
|
|
4
3
|
import Alert from "./Alert";
|
|
5
4
|
import Authorized from "./Authorized";
|
|
6
5
|
import AvailableFilters from "./AvailableFilters";
|
|
@@ -9,12 +8,14 @@ import CatalogMenu from "./CatalogMenu";
|
|
|
9
8
|
import Comments from "./Comments";
|
|
10
9
|
import CommentsLoader from "./CommentsLoader";
|
|
11
10
|
import ConfirmModal from "./ConfirmModal";
|
|
11
|
+
import CSVFileModal from "./CSVFileModal";
|
|
12
12
|
import CursorPagination from "./CursorPagination";
|
|
13
13
|
import DashboardMenu from "./DashboardMenu";
|
|
14
14
|
import Date from "./Date";
|
|
15
15
|
import DateFilter from "./DateFilter";
|
|
16
16
|
import DateRangeFilter from "./DateRangeFilter";
|
|
17
17
|
import DateTime from "./DateTime";
|
|
18
|
+
import DescriptionInput from "./DescriptionInput";
|
|
18
19
|
import DomainSelector from "./DomainSelector";
|
|
19
20
|
import DropdownMenuItem from "./DropdownMenuItem";
|
|
20
21
|
import ErrorBoundary from "./ErrorBoundary";
|
|
@@ -26,6 +27,7 @@ import HistoryBackButton from "./HistoryBackButton";
|
|
|
26
27
|
import IngestMenu from "./IngestMenu";
|
|
27
28
|
import LineageMenu from "./LineageMenu";
|
|
28
29
|
import Loading from "./Loading";
|
|
30
|
+
import MembersMenu from "./MembersMenu";
|
|
29
31
|
import OptionGroup from "./OptionGroup";
|
|
30
32
|
import OptionModal from "./OptionModal";
|
|
31
33
|
import Pagination from "./Pagination";
|
|
@@ -50,7 +52,6 @@ import UploadModal from "./UploadModal";
|
|
|
50
52
|
export {
|
|
51
53
|
ActiveRoute,
|
|
52
54
|
AdminMenu,
|
|
53
|
-
MembersMenu,
|
|
54
55
|
Alert,
|
|
55
56
|
Authorized,
|
|
56
57
|
AvailableFilters,
|
|
@@ -59,12 +60,14 @@ export {
|
|
|
59
60
|
Comments,
|
|
60
61
|
CommentsLoader,
|
|
61
62
|
ConfirmModal,
|
|
63
|
+
CSVFileModal,
|
|
62
64
|
CursorPagination,
|
|
63
65
|
DashboardMenu,
|
|
64
66
|
Date,
|
|
65
67
|
DateFilter,
|
|
66
68
|
DateRangeFilter,
|
|
67
69
|
DateTime,
|
|
70
|
+
DescriptionInput,
|
|
68
71
|
DomainSelector,
|
|
69
72
|
DropdownMenuItem,
|
|
70
73
|
ErrorBoundary,
|
|
@@ -76,6 +79,7 @@ export {
|
|
|
76
79
|
IngestMenu,
|
|
77
80
|
LineageMenu,
|
|
78
81
|
Loading,
|
|
82
|
+
MembersMenu,
|
|
79
83
|
OptionGroup,
|
|
80
84
|
OptionModal,
|
|
81
85
|
Pagination,
|
package/src/messages/en.js
CHANGED
|
@@ -107,6 +107,7 @@ export default {
|
|
|
107
107
|
"sidemenu.grant_request_approvals": "Approve Grant Requests",
|
|
108
108
|
"sidemenu.grant_requests": "Grant Requests",
|
|
109
109
|
"sidemenu.grants": "Grants",
|
|
110
|
+
"sidemenu.hierarchies": "Hierarchies",
|
|
110
111
|
"sidemenu.hide": "Collapse sidebar",
|
|
111
112
|
"sidemenu.i18nMessages": "Translations",
|
|
112
113
|
"sidemenu.implementations": "Implementations",
|
package/src/messages/es.js
CHANGED
|
@@ -110,6 +110,7 @@ export default {
|
|
|
110
110
|
"sidemenu.grant_request_approvals": "Aprobar Peticiones de Accesos",
|
|
111
111
|
"sidemenu.grant_requests": "Peticiones de Accesos",
|
|
112
112
|
"sidemenu.grants": "Accesos",
|
|
113
|
+
"sidemenu.hierarchies": "Jerarquías",
|
|
113
114
|
"sidemenu.hide": "Ocultar",
|
|
114
115
|
"sidemenu.i18nMessages": "Traducciones",
|
|
115
116
|
"sidemenu.implementations": "Implementaciones",
|
package/src/routes.js
CHANGED
|
@@ -62,6 +62,10 @@ export const GROUP = "/groups/:id";
|
|
|
62
62
|
export const GROUPS = "/groups";
|
|
63
63
|
export const GROUP_CREATE = "/groups/new";
|
|
64
64
|
export const GROUP_EDIT = "/groups/:id/edit";
|
|
65
|
+
export const HIERARCHIES = "/hierarchies";
|
|
66
|
+
export const HIERARCHY = "/hierarchies/:hierarchyId";
|
|
67
|
+
export const HIERARCHY_EDIT = "/hierarchies/:hierarchyId/edit";
|
|
68
|
+
export const HIERARCHY_CREATE = "/hierarchies/new";
|
|
65
69
|
export const I18N = "/i18n";
|
|
66
70
|
export const I18N_MESSAGES = "/i18n/messages";
|
|
67
71
|
export const I18N_MESSAGES_NEW = "/i18n/messages/new";
|
|
@@ -261,6 +265,10 @@ const routes = {
|
|
|
261
265
|
GROUPS,
|
|
262
266
|
GROUP_CREATE,
|
|
263
267
|
GROUP_EDIT,
|
|
268
|
+
HIERARCHIES,
|
|
269
|
+
HIERARCHY,
|
|
270
|
+
HIERARCHY_EDIT,
|
|
271
|
+
HIERARCHY_CREATE,
|
|
264
272
|
I18N,
|
|
265
273
|
I18N_MESSAGES,
|
|
266
274
|
I18N_MESSAGES_NEW,
|
package/src/services/message.js
CHANGED
|
@@ -14,6 +14,9 @@ export const defaultMessage = (state, type, payload) => {
|
|
|
14
14
|
if (type === "LOG_ERROR/TRIGGER" && _.has("graphQLErrors")(payload))
|
|
15
15
|
return graphQLErrors(payload);
|
|
16
16
|
|
|
17
|
+
if (type === "LOG_ERROR/TRIGGER" && _.has("swrErrors")(payload))
|
|
18
|
+
return swrErrors(payload);
|
|
19
|
+
|
|
17
20
|
if (_.endsWith("/TRIGGER")(type)) return state;
|
|
18
21
|
|
|
19
22
|
if (_.endsWith("/FAILURE")(type)) {
|
|
@@ -27,6 +30,24 @@ export const defaultMessage = (state, type, payload) => {
|
|
|
27
30
|
return state;
|
|
28
31
|
};
|
|
29
32
|
|
|
33
|
+
const swrErrors = ({ swrErrors, prefix }) => {
|
|
34
|
+
const errors = _.flow(
|
|
35
|
+
_.toPairs,
|
|
36
|
+
_.flatMap(([field, errors]) =>
|
|
37
|
+
_.map((v) => `${prefix}.${field}.${v}`)(errors)
|
|
38
|
+
),
|
|
39
|
+
_.map((name) => ({ name }))
|
|
40
|
+
)(swrErrors);
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
error: true,
|
|
44
|
+
header: "Error",
|
|
45
|
+
icon: "attention",
|
|
46
|
+
errorList: errors,
|
|
47
|
+
text: "List of errors",
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
|
|
30
51
|
export const graphQLErrors = (payload) => {
|
|
31
52
|
const errorList = _.map(_.pick(["path", "field", "message"]))(
|
|
32
53
|
payload.graphQLErrors
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import { unauthorized, logError } from "../routines";
|
|
3
|
+
|
|
4
|
+
function isNumeric(str) {
|
|
5
|
+
if (typeof str != "string") return false;
|
|
6
|
+
return !isNaN(str) && !isNaN(parseInt(str));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const getPrefix = _.flow(
|
|
10
|
+
_.replace("/api/", ""),
|
|
11
|
+
_.split("/"),
|
|
12
|
+
_.reject(isNumeric),
|
|
13
|
+
_.join(".")
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
const createErrorMiddleware = ({ dispatch }) => {
|
|
17
|
+
return (useSWRNext) => {
|
|
18
|
+
return (key, fetcher, config) => {
|
|
19
|
+
return useSWRNext(key, fetcher, {
|
|
20
|
+
...config,
|
|
21
|
+
onError: (error) => {
|
|
22
|
+
config.onError(error);
|
|
23
|
+
const statusCode = _.pathOr(null, "response.status")(error);
|
|
24
|
+
const swrErrors = _.pathOr(null, "response.data.errors")(error);
|
|
25
|
+
|
|
26
|
+
if (statusCode === 401) {
|
|
27
|
+
dispatch(unauthorized());
|
|
28
|
+
} else if (swrErrors !== null) {
|
|
29
|
+
const prefix = getPrefix(key);
|
|
30
|
+
dispatch(logError({ swrErrors, prefix }));
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const createSwrConfig = (store) => {
|
|
39
|
+
const errorMiddleware = createErrorMiddleware(store);
|
|
40
|
+
return {
|
|
41
|
+
use: [errorMiddleware],
|
|
42
|
+
};
|
|
43
|
+
};
|