@truedat/cx 4.41.2 → 4.41.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/CHANGELOG.md +11 -0
- package/package.json +4 -4
- package/src/jobs/components/Job.js +11 -11
- package/src/jobs/components/JobRoutes.js +2 -2
- package/src/jobs/components/JobRow.js +7 -3
- package/src/jobs/components/Jobs.js +16 -28
- package/src/jobs/components/JobsTable.js +80 -92
- package/src/jobs/components/JobsView.js +23 -0
- package/src/jobs/components/SourceJobs.js +29 -0
- package/src/jobs/components/__tests__/JobRow.spec.js +44 -23
- package/src/jobs/components/__tests__/Jobs.spec.js +33 -8
- package/src/jobs/components/__tests__/JobsTable.spec.js +50 -81
- package/src/jobs/components/__tests__/JobsView.spec.js +39 -0
- package/src/jobs/components/__tests__/SourceJobs.spec.js +38 -0
- package/src/jobs/components/__tests__/__snapshots__/Job.spec.js.snap +3 -4
- package/src/jobs/components/__tests__/__snapshots__/JobRow.spec.js.snap +40 -32
- package/src/jobs/components/__tests__/__snapshots__/Jobs.spec.js.snap +136 -35
- package/src/jobs/components/__tests__/__snapshots__/JobsTable.spec.js.snap +104 -227
- package/src/jobs/components/__tests__/__snapshots__/JobsView.spec.js.snap +167 -0
- package/src/jobs/components/__tests__/__snapshots__/SourceJobs.spec.js.snap +115 -0
- package/src/jobs/components/index.js +1 -3
- package/src/jobs/selectors/index.js +4 -2
- package/src/jobs/selectors/{getJobColumns.js → jobColumnsSelector.js} +11 -27
- package/src/jobs/selectors/jobRowsSelector.js +14 -0
- package/src/jobs/selectors/sourceJobColumnsSelector.js +35 -0
- package/src/messages/en.js +9 -1
- package/src/messages/es.js +9 -1
- package/src/reducers/cxMessage.js +15 -1
- package/src/sources/api/fragments.js +48 -0
- package/src/sources/api/mutations.js +51 -0
- package/src/sources/api/queries.js +52 -0
- package/src/sources/api.js +1 -2
- package/src/sources/components/EditSource.js +5 -29
- package/src/sources/components/JobForm.js +2 -2
- package/src/sources/components/NewJob.js +10 -23
- package/src/sources/components/Source.js +12 -76
- package/src/sources/components/SourceActions.js +13 -21
- package/src/sources/components/SourceBreadcrumbs.js +1 -1
- package/src/sources/components/SourceConfiguration.js +60 -0
- package/src/sources/components/SourceDetail.js +90 -0
- package/src/sources/components/SourceForm.js +50 -53
- package/src/sources/components/SourceHeader.js +29 -0
- package/src/sources/components/SourceRoutes.js +25 -89
- package/src/sources/components/SourceSelector.js +53 -44
- package/src/sources/components/SourceTabs.js +54 -0
- package/src/sources/components/Sources.js +7 -20
- package/src/sources/components/SourcesTable.js +3 -4
- package/src/sources/components/__tests__/EditSource.spec.js +1 -2
- package/src/sources/components/__tests__/Source.spec.js +1 -1
- package/src/sources/components/__tests__/SourceActions.spec.js +3 -1
- package/src/sources/components/__tests__/SourceDetail.spec.js +45 -0
- package/src/sources/components/__tests__/SourceForm.spec.js +16 -31
- package/src/sources/components/__tests__/SourceHeader.spec.js +16 -0
- package/src/sources/components/__tests__/SourceSelector.spec.js +44 -0
- package/src/sources/components/__tests__/SourceTabs.spec.js +21 -0
- package/src/sources/components/__tests__/Sources.spec.js +5 -2
- package/src/sources/components/__tests__/__snapshots__/EditSource.spec.js.snap +12 -35
- package/src/sources/components/__tests__/__snapshots__/NewSource.spec.js.snap +1 -1
- package/src/sources/components/__tests__/__snapshots__/Source.spec.js.snap +23 -65
- package/src/sources/components/__tests__/__snapshots__/SourceActions.spec.js.snap +1 -1
- package/src/sources/components/__tests__/__snapshots__/SourceDetail.spec.js.snap +154 -0
- package/src/sources/components/__tests__/__snapshots__/SourceForm.spec.js.snap +37 -14
- package/src/sources/components/__tests__/__snapshots__/SourceHeader.spec.js.snap +85 -0
- package/src/sources/components/__tests__/__snapshots__/SourceSelector.spec.js.snap +68 -0
- package/src/sources/components/__tests__/__snapshots__/SourceTabs.spec.js.snap +22 -0
- package/src/sources/components/__tests__/__snapshots__/Sources.spec.js.snap +2 -2
- package/src/sources/components/__tests__/__snapshots__/SourcesTable.spec.js.snap +5 -5
- package/src/sources/components/index.js +1 -4
- package/src/sources/reducers/__tests__/sourceRedirect.spec.js +26 -21
- package/src/sources/reducers/__tests__/sourceUpdateStatus.spec.js +9 -9
- package/src/sources/reducers/index.js +1 -12
- package/src/sources/reducers/sourceRedirect.js +20 -10
- package/src/sources/reducers/sourceUpdateStatus.js +5 -5
- package/src/sources/routines.js +0 -3
- package/src/sources/sagas/__tests__/createSource.spec.js +35 -20
- package/src/sources/sagas/__tests__/deleteSource.spec.js +29 -14
- package/src/sources/sagas/__tests__/disableSource.spec.js +2 -8
- package/src/sources/sagas/__tests__/enableSource.spec.js +2 -8
- package/src/sources/sagas/__tests__/updateSource.spec.js +33 -15
- package/src/sources/sagas/createSource.js +24 -14
- package/src/sources/sagas/deleteSource.js +14 -15
- package/src/sources/sagas/disableSource.js +1 -17
- package/src/sources/sagas/enableSource.js +1 -17
- package/src/sources/sagas/index.js +0 -9
- package/src/sources/sagas/updateSource.js +18 -15
- package/src/sources/components/DynamicSourceForm.js +0 -60
- package/src/sources/components/SourceLoader.js +0 -59
- package/src/sources/components/SourcesLoader.js +0 -39
- package/src/sources/components/__tests__/DynamicSourceForm.spec.js +0 -89
- package/src/sources/components/__tests__/SourceLoader.spec.js +0 -54
- package/src/sources/components/__tests__/SourcesLoader.spec.js +0 -53
- package/src/sources/components/__tests__/__snapshots__/DynamicSourceForm.spec.js.snap +0 -8
- package/src/sources/components/__tests__/__snapshots__/SourceLoader.spec.js.snap +0 -3
- package/src/sources/components/__tests__/__snapshots__/SourcesLoader.spec.js.snap +0 -3
- package/src/sources/reducers/__tests__/source.spec.js +0 -44
- package/src/sources/reducers/__tests__/sourceLoading.spec.js +0 -30
- package/src/sources/reducers/__tests__/sources.spec.js +0 -37
- package/src/sources/reducers/__tests__/sourcesLoading.spec.js +0 -30
- package/src/sources/reducers/source.js +0 -35
- package/src/sources/reducers/sourceLoading.js +0 -16
- package/src/sources/reducers/sources.js +0 -28
- package/src/sources/reducers/sourcesLoading.js +0 -16
- package/src/sources/sagas/__tests__/fetchSource.spec.js +0 -71
- package/src/sources/sagas/__tests__/fetchSources.spec.js +0 -69
- package/src/sources/sagas/__tests__/updateSourceConfig.spec.js +0 -73
- package/src/sources/sagas/fetchSource.js +0 -30
- package/src/sources/sagas/fetchSources.js +0 -26
- package/src/sources/sagas/updateSourceConfig.js +0 -29
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React, { useState, useEffect } from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { connect } from "react-redux";
|
|
5
|
+
import { updateSource } from "../routines";
|
|
6
|
+
|
|
7
|
+
const DynamicFormViewer = React.lazy(() =>
|
|
8
|
+
import("@truedat/df/components/DynamicFormViewer")
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
export const SourceConfiguration = ({
|
|
12
|
+
source,
|
|
13
|
+
updateSource,
|
|
14
|
+
sourceUpdateStatus,
|
|
15
|
+
}) => {
|
|
16
|
+
const [editingField, setEditingField] = useState();
|
|
17
|
+
const [sourceConfig, setSourceConfig] = useState();
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (source) {
|
|
20
|
+
setSourceConfig(source?.config);
|
|
21
|
+
}
|
|
22
|
+
}, [source]);
|
|
23
|
+
const template = source?.template;
|
|
24
|
+
const editFunctions = {
|
|
25
|
+
onChange: (e, { name, value }) => {
|
|
26
|
+
e && e.preventDefault();
|
|
27
|
+
setSourceConfig({ ...sourceConfig, [name]: value });
|
|
28
|
+
},
|
|
29
|
+
onCancel: () => setSourceConfig(source?.config),
|
|
30
|
+
onSubmit: (field) =>
|
|
31
|
+
updateSource({
|
|
32
|
+
source: {
|
|
33
|
+
id: source?.id,
|
|
34
|
+
config: _.pick(field)(sourceConfig),
|
|
35
|
+
merge: true,
|
|
36
|
+
},
|
|
37
|
+
}),
|
|
38
|
+
editingField,
|
|
39
|
+
setEditingField,
|
|
40
|
+
updateStatus: sourceUpdateStatus,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return _.isEmpty(source) ? null : (
|
|
44
|
+
<DynamicFormViewer
|
|
45
|
+
template={template}
|
|
46
|
+
content={sourceConfig}
|
|
47
|
+
editFunctions={editFunctions}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
SourceConfiguration.propTypes = {
|
|
53
|
+
source: PropTypes.object.isRequired,
|
|
54
|
+
sourceUpdateStatus: PropTypes.string,
|
|
55
|
+
updateSource: PropTypes.func.isRequired,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const mapStateToProps = ({ sourceUpdateStatus }) => ({ sourceUpdateStatus });
|
|
59
|
+
|
|
60
|
+
export default connect(mapStateToProps, { updateSource })(SourceConfiguration);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { Switch, Route } from "react-router-dom";
|
|
4
|
+
import { Segment } from "semantic-ui-react";
|
|
5
|
+
import {
|
|
6
|
+
SOURCE_EDIT,
|
|
7
|
+
SOURCE_JOB,
|
|
8
|
+
SOURCE_JOBS_NEW,
|
|
9
|
+
SOURCE_JOBS,
|
|
10
|
+
SOURCE,
|
|
11
|
+
} from "@truedat/core/routes";
|
|
12
|
+
import Job from "../../jobs/components/Job";
|
|
13
|
+
import JobLoader from "../../jobs/components/JobLoader";
|
|
14
|
+
import SourceJobs from "../../jobs/components/SourceJobs";
|
|
15
|
+
import EditSource from "./EditSource";
|
|
16
|
+
import NewJob from "./NewJob";
|
|
17
|
+
import SourceConfiguration from "./SourceConfiguration";
|
|
18
|
+
import SourceTabs from "./SourceTabs";
|
|
19
|
+
|
|
20
|
+
export const SourceDetail = ({ source }) => (
|
|
21
|
+
<Switch>
|
|
22
|
+
<Route
|
|
23
|
+
path={SOURCE_JOBS_NEW}
|
|
24
|
+
exact
|
|
25
|
+
render={() => (
|
|
26
|
+
<>
|
|
27
|
+
<SourceTabs source={source} />
|
|
28
|
+
<Segment attached="bottom">
|
|
29
|
+
<NewJob source={source} />
|
|
30
|
+
</Segment>
|
|
31
|
+
</>
|
|
32
|
+
)}
|
|
33
|
+
/>
|
|
34
|
+
<Route
|
|
35
|
+
path={SOURCE_JOB}
|
|
36
|
+
exact
|
|
37
|
+
render={() => (
|
|
38
|
+
<>
|
|
39
|
+
<JobLoader />
|
|
40
|
+
<SourceTabs source={source} />
|
|
41
|
+
<Segment attached="bottom">
|
|
42
|
+
<Job />
|
|
43
|
+
</Segment>
|
|
44
|
+
</>
|
|
45
|
+
)}
|
|
46
|
+
/>
|
|
47
|
+
<Route
|
|
48
|
+
path={SOURCE_JOBS}
|
|
49
|
+
exact
|
|
50
|
+
render={() => (
|
|
51
|
+
<>
|
|
52
|
+
<SourceTabs source={source} />
|
|
53
|
+
<Segment attached="bottom">
|
|
54
|
+
<SourceJobs source={source} />
|
|
55
|
+
</Segment>
|
|
56
|
+
</>
|
|
57
|
+
)}
|
|
58
|
+
/>
|
|
59
|
+
<Route
|
|
60
|
+
path={SOURCE_EDIT}
|
|
61
|
+
exact
|
|
62
|
+
render={() => (
|
|
63
|
+
<>
|
|
64
|
+
<SourceTabs source={source} />
|
|
65
|
+
<Segment attached="bottom">
|
|
66
|
+
<EditSource source={source} />
|
|
67
|
+
</Segment>
|
|
68
|
+
</>
|
|
69
|
+
)}
|
|
70
|
+
/>
|
|
71
|
+
<Route
|
|
72
|
+
path={SOURCE}
|
|
73
|
+
exact
|
|
74
|
+
render={() => (
|
|
75
|
+
<>
|
|
76
|
+
<SourceTabs source={source} />
|
|
77
|
+
<Segment attached="bottom">
|
|
78
|
+
<SourceConfiguration source={source} />
|
|
79
|
+
</Segment>
|
|
80
|
+
</>
|
|
81
|
+
)}
|
|
82
|
+
/>
|
|
83
|
+
</Switch>
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
SourceDetail.propTypes = {
|
|
87
|
+
source: PropTypes.object.isRequired,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export default SourceDetail;
|
|
@@ -2,13 +2,16 @@ import _ from "lodash/fp";
|
|
|
2
2
|
import React from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import { Button, Form, Label } from "semantic-ui-react";
|
|
5
|
-
import { compose } from "redux";
|
|
6
|
-
import { connect } from "react-redux";
|
|
7
5
|
import { injectIntl, FormattedMessage } from "react-intl";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { useQuery } from "@apollo/client";
|
|
7
|
+
import { HistoryBackButton, Loading } from "@truedat/core/components";
|
|
8
|
+
import { accentInsensitivePathOrder } from "@truedat/core/services/sort";
|
|
10
9
|
import { applyTemplate, validateContent } from "@truedat/df/utils";
|
|
11
|
-
import
|
|
10
|
+
import { TEMPLATES_QUERY } from "../api/queries";
|
|
11
|
+
|
|
12
|
+
const DynamicForm = React.lazy(() =>
|
|
13
|
+
import("@truedat/df/components/DynamicForm")
|
|
14
|
+
);
|
|
12
15
|
|
|
13
16
|
const staticFields = ["external_id"];
|
|
14
17
|
|
|
@@ -29,13 +32,10 @@ const isValid = _.conforms({
|
|
|
29
32
|
|
|
30
33
|
export class SourceForm extends React.Component {
|
|
31
34
|
static propTypes = {
|
|
32
|
-
applyTemplate: PropTypes.func,
|
|
33
35
|
intl: PropTypes.object,
|
|
34
36
|
source: PropTypes.object,
|
|
35
|
-
template: PropTypes.object,
|
|
36
37
|
templates: PropTypes.array,
|
|
37
|
-
|
|
38
|
-
selectTemplate: PropTypes.func,
|
|
38
|
+
templatesLoading: PropTypes.bool,
|
|
39
39
|
onSubmit: PropTypes.func,
|
|
40
40
|
};
|
|
41
41
|
|
|
@@ -47,7 +47,8 @@ export class SourceForm extends React.Component {
|
|
|
47
47
|
if (!_.isEmpty(source)) {
|
|
48
48
|
const template = _.find(_.propEq("name")(source.type))(templates);
|
|
49
49
|
this.setState({
|
|
50
|
-
|
|
50
|
+
id: source.id,
|
|
51
|
+
external_id: source.externalId,
|
|
51
52
|
type: source.type,
|
|
52
53
|
content: applyTemplate(template)(source.config),
|
|
53
54
|
template: template,
|
|
@@ -55,22 +56,15 @@ export class SourceForm extends React.Component {
|
|
|
55
56
|
}
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
componentDidUpdate() {
|
|
59
|
-
const { applyTemplate, template } = this.props;
|
|
60
|
-
const { type, content } = this.state;
|
|
61
|
-
|
|
62
|
-
if (_.has("name")(template) && !_.propEq("name", type)(template))
|
|
63
|
-
this.setState({
|
|
64
|
-
type: _.prop("name")(template),
|
|
65
|
-
content: applyTemplate(content),
|
|
66
|
-
contentErrors: validateContent(template)(content),
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
59
|
handleTemplateSelected = (e, data) => {
|
|
71
60
|
const { value } = data;
|
|
72
|
-
const
|
|
73
|
-
|
|
61
|
+
const content = this.state.content;
|
|
62
|
+
const template = _.find(_.propEq("name", value))(this.props.templates);
|
|
63
|
+
this.setState({
|
|
64
|
+
type: value,
|
|
65
|
+
template: template,
|
|
66
|
+
content: applyTemplate(template)(content),
|
|
67
|
+
});
|
|
74
68
|
};
|
|
75
69
|
|
|
76
70
|
handleChange = (e, { name, value }) => {
|
|
@@ -82,7 +76,7 @@ export class SourceForm extends React.Component {
|
|
|
82
76
|
};
|
|
83
77
|
|
|
84
78
|
handleContentChange = (content) => {
|
|
85
|
-
const contentErrors = validateContent(this.
|
|
79
|
+
const contentErrors = validateContent(this.state.template)(content);
|
|
86
80
|
this.setState({ content, contentErrors });
|
|
87
81
|
};
|
|
88
82
|
|
|
@@ -90,9 +84,13 @@ export class SourceForm extends React.Component {
|
|
|
90
84
|
|
|
91
85
|
handleSubmit = (e) => {
|
|
92
86
|
e.preventDefault();
|
|
93
|
-
const {
|
|
87
|
+
const { onSubmit } = this.props;
|
|
94
88
|
const source = _.pick(["id", "external_id", "type"])(this.state);
|
|
95
|
-
const
|
|
89
|
+
const template = this.state.template;
|
|
90
|
+
const config = _.flow(
|
|
91
|
+
_.prop("content"),
|
|
92
|
+
applyTemplate(template)
|
|
93
|
+
)(this.state);
|
|
96
94
|
onSubmit({ source: { ...source, config: config } });
|
|
97
95
|
};
|
|
98
96
|
|
|
@@ -100,18 +98,16 @@ export class SourceForm extends React.Component {
|
|
|
100
98
|
const {
|
|
101
99
|
intl: { formatMessage },
|
|
102
100
|
source,
|
|
103
|
-
|
|
101
|
+
templatesLoading,
|
|
104
102
|
templates,
|
|
105
|
-
template,
|
|
106
103
|
} = this.props;
|
|
107
104
|
|
|
108
|
-
const { external_id, content, type } = this.state;
|
|
105
|
+
const { external_id, content, template, type } = this.state;
|
|
109
106
|
|
|
110
|
-
const typeOptions =
|
|
111
|
-
key:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}));
|
|
107
|
+
const typeOptions = _.flow(
|
|
108
|
+
_.map(({ id, label, name }) => ({ key: id, value: name, text: label })),
|
|
109
|
+
_.sortBy(accentInsensitivePathOrder("text"))
|
|
110
|
+
)(templates);
|
|
115
111
|
|
|
116
112
|
return (
|
|
117
113
|
<Form>
|
|
@@ -142,23 +138,22 @@ export class SourceForm extends React.Component {
|
|
|
142
138
|
selection
|
|
143
139
|
required
|
|
144
140
|
options={typeOptions}
|
|
145
|
-
loading={
|
|
141
|
+
loading={templatesLoading}
|
|
146
142
|
onChange={this.handleTemplateSelected}
|
|
147
|
-
value={_.prop("
|
|
143
|
+
value={_.prop("name")(template)}
|
|
148
144
|
disabled={!_.isEmpty(source)}
|
|
149
145
|
/>
|
|
150
146
|
</Form.Field>
|
|
151
147
|
|
|
152
|
-
{type &&
|
|
148
|
+
{type && !templatesLoading && (
|
|
153
149
|
<Form.Field>
|
|
154
150
|
<label className="label">
|
|
155
151
|
<FormattedMessage id="source.config.label" />
|
|
156
152
|
</label>
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
dfContent={content}
|
|
153
|
+
<DynamicForm
|
|
154
|
+
onChange={this.handleContentChange}
|
|
155
|
+
content={content}
|
|
156
|
+
template={template}
|
|
162
157
|
/>
|
|
163
158
|
</Form.Field>
|
|
164
159
|
)}
|
|
@@ -180,14 +175,16 @@ export class SourceForm extends React.Component {
|
|
|
180
175
|
}
|
|
181
176
|
}
|
|
182
177
|
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
178
|
+
export const SourceFormLoader = (props) => {
|
|
179
|
+
const { loading, error, data } = useQuery(TEMPLATES_QUERY, {
|
|
180
|
+
variables: { scope: "cx" },
|
|
181
|
+
});
|
|
182
|
+
if (error) return null;
|
|
183
|
+
if (loading) return <Loading />;
|
|
184
|
+
const templates = data?.templates || [];
|
|
185
|
+
return (
|
|
186
|
+
<SourceForm templatesLoading={loading} templates={templates} {...props} />
|
|
187
|
+
);
|
|
188
|
+
};
|
|
189
189
|
|
|
190
|
-
export default
|
|
191
|
-
injectIntl,
|
|
192
|
-
connect(mapStateToProps, { selectTemplate })
|
|
193
|
-
)(SourceForm);
|
|
190
|
+
export default injectIntl(SourceFormLoader);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { Header, Icon, Grid } from "semantic-ui-react";
|
|
5
|
+
import SourceActions from "./SourceActions";
|
|
6
|
+
|
|
7
|
+
export const SourceHeader = ({ source }) =>
|
|
8
|
+
_.isEmpty(source) ? null : (
|
|
9
|
+
<Grid>
|
|
10
|
+
<Grid.Column width={8}>
|
|
11
|
+
<Header as="h2">
|
|
12
|
+
<Icon circular name="plug" />
|
|
13
|
+
<Header.Content>
|
|
14
|
+
{source.externalId}
|
|
15
|
+
<Header.Subheader>{source.type}</Header.Subheader>
|
|
16
|
+
</Header.Content>
|
|
17
|
+
</Header>
|
|
18
|
+
</Grid.Column>
|
|
19
|
+
<Grid.Column width={8} textAlign="right">
|
|
20
|
+
<SourceActions source={source} />
|
|
21
|
+
</Grid.Column>
|
|
22
|
+
</Grid>
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
SourceHeader.propTypes = {
|
|
26
|
+
source: PropTypes.object.isRequired,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export default SourceHeader;
|
|
@@ -1,108 +1,44 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
2
|
import React from "react";
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { Route, Switch } from "react-router-dom";
|
|
7
|
-
import { Unauthorized } from "@truedat/core/components";
|
|
3
|
+
import { Route, Switch, useParams } from "react-router-dom";
|
|
4
|
+
import { useQuery } from "@apollo/client";
|
|
5
|
+
import { Unauthorized, Loading } from "@truedat/core/components";
|
|
8
6
|
import { useAuthorized } from "@truedat/core/hooks";
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
SOURCES,
|
|
12
|
-
SOURCES_NEW,
|
|
13
|
-
SOURCE_EDIT,
|
|
14
|
-
SOURCE_JOBS_NEW,
|
|
15
|
-
} from "@truedat/core/routes";
|
|
7
|
+
import { SOURCE, SOURCES, SOURCES_NEW } from "@truedat/core/routes";
|
|
8
|
+
import { SOURCE_QUERY } from "../api/queries";
|
|
16
9
|
import NewSource from "./NewSource";
|
|
17
|
-
import NewJob from "./NewJob";
|
|
18
|
-
import EditSource from "./EditSource";
|
|
19
|
-
import Sources from "./Sources";
|
|
20
|
-
import SourceLoader from "./SourceLoader";
|
|
21
10
|
import Source from "./Source";
|
|
11
|
+
import Sources from "./Sources";
|
|
22
12
|
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
13
|
+
export const SourceLoader = () => {
|
|
14
|
+
const { sourceId } = useParams();
|
|
15
|
+
const { loading, error, data } = useQuery(SOURCE_QUERY, {
|
|
16
|
+
variables: { sourceId },
|
|
17
|
+
});
|
|
18
|
+
if (error) return null;
|
|
19
|
+
if (loading) return <Loading />;
|
|
20
|
+
const source = data?.source;
|
|
21
|
+
return _.isEmpty(source) ? null : <Source source={source} />;
|
|
22
|
+
};
|
|
26
23
|
|
|
27
|
-
const
|
|
28
|
-
|
|
24
|
+
export const AuthorizedSourcesRoutes = () => (
|
|
25
|
+
<Switch>
|
|
26
|
+
<Route exact path={SOURCES_NEW} render={() => <NewSource />} />
|
|
27
|
+
<Route exact path={SOURCES} render={() => <Sources />} />
|
|
28
|
+
<Route path={SOURCE} render={() => <SourceLoader />} />
|
|
29
|
+
</Switch>
|
|
29
30
|
);
|
|
30
31
|
|
|
31
|
-
export const SourceRoutes = (
|
|
32
|
+
export const SourceRoutes = () => {
|
|
32
33
|
const authorized = useAuthorized();
|
|
33
34
|
return (
|
|
34
35
|
<Route
|
|
35
36
|
path={SOURCES}
|
|
36
37
|
render={() =>
|
|
37
|
-
authorized ?
|
|
38
|
-
<Switch>
|
|
39
|
-
<Route
|
|
40
|
-
exact
|
|
41
|
-
path={SOURCE_JOBS_NEW}
|
|
42
|
-
render={() => (
|
|
43
|
-
<>
|
|
44
|
-
<SourceLoader />
|
|
45
|
-
<NewJob />
|
|
46
|
-
</>
|
|
47
|
-
)}
|
|
48
|
-
/>
|
|
49
|
-
<Route
|
|
50
|
-
exact
|
|
51
|
-
path={SOURCES_NEW}
|
|
52
|
-
render={() => (
|
|
53
|
-
<>
|
|
54
|
-
<TemplatesLoader scope="cx" />
|
|
55
|
-
<TemplateLoader />
|
|
56
|
-
<NewSource />
|
|
57
|
-
</>
|
|
58
|
-
)}
|
|
59
|
-
/>
|
|
60
|
-
<Route
|
|
61
|
-
exact
|
|
62
|
-
path={SOURCE_EDIT}
|
|
63
|
-
render={() => (
|
|
64
|
-
<>
|
|
65
|
-
<TemplatesLoader scope="cx" />
|
|
66
|
-
<SourceLoader />
|
|
67
|
-
{!_.isEmpty(source) &&
|
|
68
|
-
!sourceLoading &&
|
|
69
|
-
!templatesLoading && <EditSource />}
|
|
70
|
-
</>
|
|
71
|
-
)}
|
|
72
|
-
/>
|
|
73
|
-
<Route
|
|
74
|
-
exact
|
|
75
|
-
path={SOURCE}
|
|
76
|
-
render={() => (
|
|
77
|
-
<>
|
|
78
|
-
<SourceLoader />
|
|
79
|
-
<Segment>
|
|
80
|
-
<TemplatesLoader scope="cx" />
|
|
81
|
-
{!templatesLoading && <Source />}
|
|
82
|
-
</Segment>
|
|
83
|
-
</>
|
|
84
|
-
)}
|
|
85
|
-
/>
|
|
86
|
-
<Route exact path={SOURCES} render={() => <Sources />} />
|
|
87
|
-
</Switch>
|
|
88
|
-
) : (
|
|
89
|
-
<Unauthorized />
|
|
90
|
-
)
|
|
38
|
+
authorized ? <AuthorizedSourcesRoutes /> : <Unauthorized />
|
|
91
39
|
}
|
|
92
40
|
/>
|
|
93
41
|
);
|
|
94
42
|
};
|
|
95
43
|
|
|
96
|
-
|
|
97
|
-
source: PropTypes.object,
|
|
98
|
-
sourceLoading: PropTypes.bool,
|
|
99
|
-
templatesLoading: PropTypes.bool,
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const mapStateToProps = ({ source, sourceLoading, templatesLoading }) => ({
|
|
103
|
-
source,
|
|
104
|
-
sourceLoading,
|
|
105
|
-
templatesLoading,
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
export default connect(mapStateToProps)(SourceRoutes);
|
|
44
|
+
export default SourceRoutes;
|
|
@@ -1,62 +1,71 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
|
-
import { connect } from "react-redux";
|
|
5
4
|
import { useIntl } from "react-intl";
|
|
6
5
|
import { Form } from "semantic-ui-react";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
);
|
|
6
|
+
import { useQuery } from "@apollo/client";
|
|
7
|
+
import { accentInsensitivePathOrder } from "@truedat/core/services/sort";
|
|
8
|
+
import { SOURCE_OPTIONS_QUERY } from "../api/queries";
|
|
11
9
|
|
|
12
10
|
export const SourceSelector = ({
|
|
13
|
-
value,
|
|
14
|
-
onChange,
|
|
15
|
-
onBlur,
|
|
16
|
-
error,
|
|
17
11
|
disabled,
|
|
18
|
-
|
|
12
|
+
error,
|
|
13
|
+
label,
|
|
14
|
+
onBlur,
|
|
15
|
+
onChange,
|
|
16
|
+
placeholder,
|
|
17
|
+
required,
|
|
18
|
+
value,
|
|
19
|
+
variables,
|
|
19
20
|
}) => {
|
|
20
21
|
const { formatMessage } = useIntl();
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
const {
|
|
23
|
+
loading,
|
|
24
|
+
error: queryError,
|
|
25
|
+
data,
|
|
26
|
+
} = useQuery(SOURCE_OPTIONS_QUERY, { variables });
|
|
27
|
+
if (queryError) return null;
|
|
28
|
+
const options = loading
|
|
29
|
+
? []
|
|
30
|
+
: _.flow(
|
|
31
|
+
_.prop("sources"),
|
|
32
|
+
_.sortBy(accentInsensitivePathOrder("externalId")),
|
|
33
|
+
_.map(({ id, externalId }) => ({
|
|
34
|
+
key: id,
|
|
35
|
+
value: id,
|
|
36
|
+
text: externalId,
|
|
37
|
+
}))
|
|
38
|
+
)(data);
|
|
29
39
|
return (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
<Form.Dropdown
|
|
41
|
+
disabled={disabled}
|
|
42
|
+
error={error}
|
|
43
|
+
label={label}
|
|
44
|
+
loading={loading}
|
|
45
|
+
onBlur={onBlur}
|
|
46
|
+
onChange={onChange}
|
|
47
|
+
options={options}
|
|
48
|
+
placeholder={
|
|
49
|
+
placeholder || formatMessage({ id: "source.search.placeholder" })
|
|
50
|
+
}
|
|
51
|
+
required={required}
|
|
52
|
+
search
|
|
53
|
+
selection
|
|
54
|
+
value={value}
|
|
55
|
+
/>
|
|
44
56
|
);
|
|
45
57
|
};
|
|
46
58
|
|
|
47
59
|
SourceSelector.propTypes = {
|
|
48
|
-
onChange: PropTypes.func.isRequired,
|
|
49
|
-
value: PropTypes.string,
|
|
50
|
-
onBlur: PropTypes.func,
|
|
51
|
-
error: PropTypes.bool,
|
|
52
60
|
disabled: PropTypes.bool,
|
|
53
|
-
|
|
61
|
+
error: PropTypes.bool,
|
|
62
|
+
label: PropTypes.node,
|
|
63
|
+
onBlur: PropTypes.func,
|
|
64
|
+
onChange: PropTypes.func,
|
|
65
|
+
placeholder: PropTypes.string,
|
|
66
|
+
required: PropTypes.bool,
|
|
67
|
+
value: PropTypes.string,
|
|
68
|
+
variables: PropTypes.object,
|
|
54
69
|
};
|
|
55
70
|
|
|
56
|
-
|
|
57
|
-
sources: _.map((source) => ({ name: source.external_id, id: source.id }))(
|
|
58
|
-
sources
|
|
59
|
-
),
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
export default connect(mapStateToProps)(SourceSelector);
|
|
71
|
+
export default SourceSelector;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { Link } from "react-router-dom";
|
|
4
|
+
import { FormattedMessage } from "react-intl";
|
|
5
|
+
import { Menu } from "semantic-ui-react";
|
|
6
|
+
import { usePath } from "@truedat/core/hooks";
|
|
7
|
+
import {
|
|
8
|
+
linkTo,
|
|
9
|
+
SOURCE_EDIT,
|
|
10
|
+
SOURCE_JOB,
|
|
11
|
+
SOURCE_JOBS_NEW,
|
|
12
|
+
SOURCE_JOBS,
|
|
13
|
+
SOURCE,
|
|
14
|
+
} from "@truedat/core/routes";
|
|
15
|
+
|
|
16
|
+
export const SourceTabs = ({ source }) => {
|
|
17
|
+
const path = usePath();
|
|
18
|
+
const { id } = source;
|
|
19
|
+
return (
|
|
20
|
+
<>
|
|
21
|
+
<Menu attached="top" secondary pointing tabular>
|
|
22
|
+
<Menu.Item
|
|
23
|
+
active={path === SOURCE || path === SOURCE_EDIT}
|
|
24
|
+
as={Link}
|
|
25
|
+
to={linkTo.SOURCE({ sourceId: id })}
|
|
26
|
+
>
|
|
27
|
+
<FormattedMessage id="source.config.label" />
|
|
28
|
+
</Menu.Item>
|
|
29
|
+
<Menu.Item
|
|
30
|
+
active={path === SOURCE_JOBS || path === SOURCE_JOB}
|
|
31
|
+
as={Link}
|
|
32
|
+
to={linkTo.SOURCE_JOBS({ sourceId: id })}
|
|
33
|
+
>
|
|
34
|
+
<FormattedMessage id="navigation.admin.jobs" />
|
|
35
|
+
</Menu.Item>
|
|
36
|
+
{source?.active ? (
|
|
37
|
+
<Menu.Item
|
|
38
|
+
active={path === SOURCE_JOBS_NEW}
|
|
39
|
+
as={Link}
|
|
40
|
+
to={linkTo.SOURCE_JOBS_NEW({ sourceId: id })}
|
|
41
|
+
>
|
|
42
|
+
<FormattedMessage id="jobs.actions.create" />
|
|
43
|
+
</Menu.Item>
|
|
44
|
+
) : null}
|
|
45
|
+
</Menu>
|
|
46
|
+
</>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
SourceTabs.propTypes = {
|
|
51
|
+
source: PropTypes.object.isRequired,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default SourceTabs;
|