@truedat/df 5.17.2 → 5.18.0
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 +4 -4
- package/src/components/DynamicFormViewer.js +39 -2
- package/src/messages/en.js +1 -0
- package/src/messages/es.js +1 -0
- package/src/templates/components/Template.js +64 -16
- package/src/templates/components/TemplateFilters.js +56 -0
- package/src/templates/components/TemplateRoutes.js +17 -11
- package/src/templates/components/Templates.js +45 -21
- package/src/templates/components/TemplatesContext.js +66 -0
- package/src/templates/components/TemplatesTable.js +113 -0
- package/src/templates/components/__tests__/TemplatesTable.spec.js +29 -0
- package/src/templates/components/__tests__/__snapshots__/Template.spec.js.snap +54 -16
- package/src/templates/components/__tests__/__snapshots__/TemplatesTable.spec.js.snap +3 -0
- package/src/templates/components/templateForm/FieldForm.js +2 -0
- package/src/templates/components/templateForm/TemplateForm.js +14 -9
- package/src/templates/components/templateForm/TemplateFormActions.js +21 -38
- package/src/templates/components/templateForm/__tests__/TemplateForm.spec.js +2 -1
- package/src/templates/components/templateForm/__tests__/TemplateFormActions.spec.js +0 -2
- package/src/templates/components/templateForm/__tests__/__snapshots__/TemplateForm.spec.js.snap +38 -12
- package/src/templates/components/templateForm/__tests__/__snapshots__/TemplateFormActions.spec.js.snap +34 -109
- package/src/templates/components/TemplateCards.js +0 -57
- package/src/templates/components/TemplateTabs.js +0 -40
- package/src/templates/components/__tests__/TemplateCards.spec.js +0 -34
- package/src/templates/components/__tests__/__snapshots__/TemplateCards.spec.js.snap +0 -62
- package/src/templates/components/scopes.js +0 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/df",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.18.0",
|
|
4
4
|
"description": "Truedat Web Data Quality Module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"jsnext:main": "src/index.js",
|
|
@@ -87,8 +87,8 @@
|
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
89
|
"@apollo/client": "^3.7.1",
|
|
90
|
-
"@truedat/auth": "5.
|
|
91
|
-
"@truedat/core": "5.
|
|
90
|
+
"@truedat/auth": "5.18.0",
|
|
91
|
+
"@truedat/core": "5.18.0",
|
|
92
92
|
"decode-uri-component": "^0.2.2",
|
|
93
93
|
"path-to-regexp": "^1.7.0",
|
|
94
94
|
"prop-types": "^15.8.1",
|
|
@@ -109,5 +109,5 @@
|
|
|
109
109
|
"react-dom": ">= 16.8.6 < 17",
|
|
110
110
|
"semantic-ui-react": ">= 2.0.3 < 2.2"
|
|
111
111
|
},
|
|
112
|
-
"gitHead": "
|
|
112
|
+
"gitHead": "2cd5914eafeae16400d4ccccfabc00cd2c84c80f"
|
|
113
113
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
1
2
|
import React from "react";
|
|
2
3
|
import PropTypes from "prop-types";
|
|
3
4
|
import { useIntl } from "react-intl";
|
|
4
|
-
import { Message } from "semantic-ui-react";
|
|
5
|
+
import { Message, Segment } from "semantic-ui-react";
|
|
6
|
+
import { useTemplate } from "@truedat/core/hooks";
|
|
7
|
+
import Loading from "@truedat/core/components/Loading";
|
|
5
8
|
import { parseGroups } from "../utils";
|
|
6
9
|
import FieldGroupDetail from "./FieldGroupDetail";
|
|
7
10
|
|
|
@@ -50,4 +53,38 @@ DynamicFormViewer.propTypes = {
|
|
|
50
53
|
editFunctions: PropTypes.func,
|
|
51
54
|
};
|
|
52
55
|
|
|
53
|
-
|
|
56
|
+
const DynamicFormViewerWithHook = (props) => {
|
|
57
|
+
const { data, loading } = useTemplate({
|
|
58
|
+
name: props.template,
|
|
59
|
+
domainIds: props.domainIds,
|
|
60
|
+
});
|
|
61
|
+
const newProps = {
|
|
62
|
+
...props,
|
|
63
|
+
template: data?.template,
|
|
64
|
+
};
|
|
65
|
+
return loading ? (
|
|
66
|
+
<Segment>
|
|
67
|
+
<Loading />
|
|
68
|
+
</Segment>
|
|
69
|
+
) : (
|
|
70
|
+
<DynamicFormViewer {...newProps} />
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
DynamicFormViewerWithHook.propTypes = {
|
|
75
|
+
template: PropTypes.string,
|
|
76
|
+
domainIds: PropTypes.arrayOf(PropTypes.number),
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const DynamicFormViewerFetcher = (props) =>
|
|
80
|
+
_.isString(props?.template) ? (
|
|
81
|
+
<DynamicFormViewerWithHook {...props} />
|
|
82
|
+
) : (
|
|
83
|
+
<DynamicFormViewer {...props} />
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
DynamicFormViewerFetcher.propTypes = {
|
|
87
|
+
template: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export default DynamicFormViewerFetcher;
|
package/src/messages/en.js
CHANGED
|
@@ -162,6 +162,7 @@ export default {
|
|
|
162
162
|
"template.scope.qe": "Quality Executions",
|
|
163
163
|
"template.scope.remediation": "Remediation plan",
|
|
164
164
|
"template.scope.ri": "Quality Implementation",
|
|
165
|
+
"template.scope.quality_control": "Quality Control",
|
|
165
166
|
"template.widget.copy.char.separator.format": "Char separation format",
|
|
166
167
|
"template.widget.copy.fixed.column": "Fixed width column format",
|
|
167
168
|
"template.widget.copy.without.fixed.column": "Format without char separation",
|
package/src/messages/es.js
CHANGED
|
@@ -163,6 +163,7 @@ export default {
|
|
|
163
163
|
"template.scope.qe": "Ejecuciones de calidad",
|
|
164
164
|
"template.scope.remediation": "Plan de remediación",
|
|
165
165
|
"template.scope.ri": "Implementación de calidad",
|
|
166
|
+
"template.scope.quality_control": "Control de calidad",
|
|
166
167
|
"template.widget.copy.char.separator.format":
|
|
167
168
|
"Formato de separación por caracter",
|
|
168
169
|
"template.widget.copy.fixed.column": "Formato de columna de ancho fijo",
|
|
@@ -1,30 +1,72 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
2
|
import React from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
|
-
import {
|
|
4
|
+
import { FormattedMessage } from "react-intl";
|
|
5
|
+
import {
|
|
6
|
+
Button,
|
|
7
|
+
Header,
|
|
8
|
+
Icon,
|
|
9
|
+
Segment,
|
|
10
|
+
Grid,
|
|
11
|
+
Container,
|
|
12
|
+
} from "semantic-ui-react";
|
|
5
13
|
import { connect } from "react-redux";
|
|
14
|
+
import { ConfirmModal } from "@truedat/core/components";
|
|
6
15
|
import { deleteTemplate, updateTemplate } from "../routines";
|
|
7
16
|
import TemplateCrumbs from "./TemplateCrumbs";
|
|
8
17
|
import TemplateForm from "./templateForm/TemplateForm";
|
|
9
18
|
|
|
10
|
-
export const Template = ({
|
|
19
|
+
export const Template = ({
|
|
20
|
+
template,
|
|
21
|
+
updateTemplate,
|
|
22
|
+
deleteTemplate,
|
|
23
|
+
templateDeleting,
|
|
24
|
+
templateSaving,
|
|
25
|
+
}) =>
|
|
11
26
|
_.isUndefined(template.id) ? null : (
|
|
12
27
|
<>
|
|
13
28
|
<TemplateCrumbs name={template?.label} />
|
|
14
29
|
<Segment>
|
|
15
|
-
<
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
<Grid>
|
|
31
|
+
<Grid.Column width={8}>
|
|
32
|
+
<Header as="h2">
|
|
33
|
+
<Icon name="file code outline" circular />
|
|
34
|
+
<Header.Content>
|
|
35
|
+
{template?.label}
|
|
36
|
+
<Header.Subheader>{template?.name}</Header.Subheader>
|
|
37
|
+
</Header.Content>
|
|
38
|
+
</Header>
|
|
39
|
+
</Grid.Column>
|
|
40
|
+
<Grid.Column width={8}>
|
|
41
|
+
<Container textAlign="right">
|
|
42
|
+
{template.id && (
|
|
43
|
+
<ConfirmModal
|
|
44
|
+
icon="trash"
|
|
45
|
+
trigger={
|
|
46
|
+
<Button
|
|
47
|
+
negative
|
|
48
|
+
icon="trash"
|
|
49
|
+
loading={templateDeleting}
|
|
50
|
+
disabled={templateSaving || templateDeleting}
|
|
51
|
+
/>
|
|
52
|
+
}
|
|
53
|
+
header={
|
|
54
|
+
<FormattedMessage id="template.actions.delete.confirmation.header" />
|
|
55
|
+
}
|
|
56
|
+
content={
|
|
57
|
+
<FormattedMessage
|
|
58
|
+
id="template.actions.delete.confirmation.content"
|
|
59
|
+
values={{ name: <i>{template.name}</i> }}
|
|
60
|
+
/>
|
|
61
|
+
}
|
|
62
|
+
onConfirm={() => deleteTemplate(template)}
|
|
63
|
+
/>
|
|
64
|
+
)}
|
|
65
|
+
</Container>
|
|
66
|
+
</Grid.Column>
|
|
67
|
+
</Grid>
|
|
68
|
+
|
|
69
|
+
<TemplateForm template={template} onSubmit={updateTemplate} editMode />
|
|
28
70
|
</Segment>
|
|
29
71
|
</>
|
|
30
72
|
);
|
|
@@ -33,9 +75,15 @@ Template.propTypes = {
|
|
|
33
75
|
deleteTemplate: PropTypes.func,
|
|
34
76
|
template: PropTypes.object,
|
|
35
77
|
updateTemplate: PropTypes.func,
|
|
78
|
+
templateDeleting: PropTypes.bool,
|
|
79
|
+
templateSaving: PropTypes.bool,
|
|
36
80
|
};
|
|
37
81
|
|
|
38
|
-
const mapStateToProps = ({ template }) => ({
|
|
82
|
+
const mapStateToProps = ({ template, templateDeleting, templateSaving }) => ({
|
|
83
|
+
template,
|
|
84
|
+
templateDeleting,
|
|
85
|
+
templateSaving,
|
|
86
|
+
});
|
|
39
87
|
|
|
40
88
|
export default connect(mapStateToProps, { updateTemplate, deleteTemplate })(
|
|
41
89
|
Template
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { Input, Dropdown } from "semantic-ui-react";
|
|
4
|
+
import { useIntl, FormattedMessage } from "react-intl";
|
|
5
|
+
import { lowerDeburrTrim } from "@truedat/core/services/sort";
|
|
6
|
+
import { useTemplatesContext } from "./TemplatesContext";
|
|
7
|
+
|
|
8
|
+
export default function TemplateFilters() {
|
|
9
|
+
const { formatMessage } = useIntl();
|
|
10
|
+
const { query, setQuery, scope, scopes, setScope } = useTemplatesContext();
|
|
11
|
+
return (
|
|
12
|
+
<Input
|
|
13
|
+
value={query}
|
|
14
|
+
onChange={(_e, data) => setQuery(lowerDeburrTrim(data.value))}
|
|
15
|
+
icon={{ name: "search", link: true }}
|
|
16
|
+
iconPosition="left"
|
|
17
|
+
action={
|
|
18
|
+
<Dropdown
|
|
19
|
+
button
|
|
20
|
+
className="icon"
|
|
21
|
+
floating
|
|
22
|
+
icon="filter"
|
|
23
|
+
labeled
|
|
24
|
+
scrolling
|
|
25
|
+
text={formatMessage({
|
|
26
|
+
id: scope ? `template.scope.${scope}` : "templates.all_scopes",
|
|
27
|
+
})}
|
|
28
|
+
upward={false}
|
|
29
|
+
>
|
|
30
|
+
<Dropdown.Menu>
|
|
31
|
+
<Dropdown.Item onClick={() => setScope()}>
|
|
32
|
+
<em>
|
|
33
|
+
<FormattedMessage id="templates.all_scopes" />
|
|
34
|
+
</em>
|
|
35
|
+
</Dropdown.Item>
|
|
36
|
+
{_.flow(
|
|
37
|
+
_.defaultTo([]),
|
|
38
|
+
_.map((scope) => (
|
|
39
|
+
<Dropdown.Item
|
|
40
|
+
key={scope}
|
|
41
|
+
text={formatMessage({
|
|
42
|
+
id: `template.scope.${scope}`,
|
|
43
|
+
})}
|
|
44
|
+
onClick={() => setScope(scope)}
|
|
45
|
+
/>
|
|
46
|
+
))
|
|
47
|
+
)(scopes)}
|
|
48
|
+
</Dropdown.Menu>
|
|
49
|
+
</Dropdown>
|
|
50
|
+
}
|
|
51
|
+
placeholder={formatMessage({
|
|
52
|
+
id: "templates.search.placeholder",
|
|
53
|
+
})}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -2,17 +2,13 @@ import React from "react";
|
|
|
2
2
|
import { Route, Switch } from "react-router-dom";
|
|
3
3
|
import { Unauthorized } from "@truedat/core/components";
|
|
4
4
|
import { useAuthorized } from "@truedat/core/hooks";
|
|
5
|
-
import {
|
|
6
|
-
TEMPLATE,
|
|
7
|
-
TEMPLATES,
|
|
8
|
-
TEMPLATES_NEW,
|
|
9
|
-
TEMPLATE_SCOPE,
|
|
10
|
-
} from "@truedat/core/routes";
|
|
5
|
+
import { TEMPLATE, TEMPLATES, TEMPLATES_NEW } from "@truedat/core/routes";
|
|
11
6
|
import NewTemplate from "./NewTemplate";
|
|
12
7
|
import Templates from "./Templates";
|
|
13
8
|
import Template from "./Template";
|
|
14
9
|
import TemplatesLoader from "./TemplatesLoader";
|
|
15
10
|
import TemplateLoader from "./TemplateLoader";
|
|
11
|
+
import TemplatesContextProvider from "./TemplatesContext";
|
|
16
12
|
|
|
17
13
|
export const TemplateRoutes = () => {
|
|
18
14
|
const authorized = useAuthorized();
|
|
@@ -21,11 +17,21 @@ export const TemplateRoutes = () => {
|
|
|
21
17
|
path={TEMPLATES}
|
|
22
18
|
render={() =>
|
|
23
19
|
authorized ? (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
<TemplatesContextProvider
|
|
21
|
+
initialSortColumn="updated_at"
|
|
22
|
+
initialSortDirection="descending"
|
|
23
|
+
>
|
|
28
24
|
<Switch>
|
|
25
|
+
<Route
|
|
26
|
+
path={TEMPLATES}
|
|
27
|
+
render={() => (
|
|
28
|
+
<>
|
|
29
|
+
<TemplatesLoader />
|
|
30
|
+
<Templates />
|
|
31
|
+
</>
|
|
32
|
+
)}
|
|
33
|
+
exact
|
|
34
|
+
/>
|
|
29
35
|
<Route
|
|
30
36
|
path={TEMPLATES_NEW}
|
|
31
37
|
render={() => <NewTemplate />}
|
|
@@ -41,7 +47,7 @@ export const TemplateRoutes = () => {
|
|
|
41
47
|
)}
|
|
42
48
|
/>
|
|
43
49
|
</Switch>
|
|
44
|
-
|
|
50
|
+
</TemplatesContextProvider>
|
|
45
51
|
) : (
|
|
46
52
|
<Unauthorized />
|
|
47
53
|
)
|
|
@@ -1,25 +1,49 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { Header, Icon, Segment } from "semantic-ui-react";
|
|
3
2
|
import { FormattedMessage } from "react-intl";
|
|
4
|
-
import
|
|
5
|
-
|
|
3
|
+
import {
|
|
4
|
+
Header,
|
|
5
|
+
Icon,
|
|
6
|
+
Segment,
|
|
7
|
+
Grid,
|
|
8
|
+
Container,
|
|
9
|
+
Button,
|
|
10
|
+
} from "semantic-ui-react";
|
|
11
|
+
import { Link } from "react-router-dom";
|
|
12
|
+
import { TEMPLATES_NEW } from "@truedat/core/routes";
|
|
13
|
+
import TemplateFilters from "./TemplateFilters";
|
|
14
|
+
import TemplatesTable from "./TemplatesTable";
|
|
6
15
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
export default function Templates() {
|
|
17
|
+
return (
|
|
18
|
+
<Segment>
|
|
19
|
+
<Header as="h2">
|
|
20
|
+
<Icon name="file code outline" circular />
|
|
21
|
+
<Header.Content>
|
|
22
|
+
<FormattedMessage id="templates.header" />
|
|
23
|
+
<Header.Subheader>
|
|
24
|
+
<FormattedMessage id="templates.subheader" />
|
|
25
|
+
</Header.Subheader>
|
|
26
|
+
</Header.Content>
|
|
27
|
+
</Header>
|
|
28
|
+
|
|
29
|
+
<Grid>
|
|
30
|
+
<Grid.Column width={8}>
|
|
31
|
+
<TemplateFilters />
|
|
32
|
+
</Grid.Column>
|
|
24
33
|
|
|
25
|
-
|
|
34
|
+
<Grid.Column width={8}>
|
|
35
|
+
<Container textAlign="right">
|
|
36
|
+
<Button
|
|
37
|
+
primary
|
|
38
|
+
as={Link}
|
|
39
|
+
to={TEMPLATES_NEW}
|
|
40
|
+
content={<FormattedMessage id="templates.actions.create" />}
|
|
41
|
+
/>
|
|
42
|
+
</Container>
|
|
43
|
+
</Grid.Column>
|
|
44
|
+
</Grid>
|
|
45
|
+
|
|
46
|
+
<TemplatesTable />
|
|
47
|
+
</Segment>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React, { useState, useContext, createContext } from "react";
|
|
3
|
+
import { useSelector } from "react-redux";
|
|
4
|
+
import { matchSorter } from "match-sorter";
|
|
5
|
+
|
|
6
|
+
export const TemplatesContext = createContext();
|
|
7
|
+
export const useTemplatesContext = () => useContext(TemplatesContext);
|
|
8
|
+
|
|
9
|
+
const HIDDEN_SCOPES = ["cx", "ca"];
|
|
10
|
+
const isHiddenScope = (scope) => _.includes(scope)(HIDDEN_SCOPES);
|
|
11
|
+
|
|
12
|
+
export default function TemplatesContextProvider(props) {
|
|
13
|
+
const children = _.prop("children")(props);
|
|
14
|
+
const initialSortColumn = _.prop("initialSortColumn")(props);
|
|
15
|
+
const initialSortDirection = _.prop("initialSortDirection")(props);
|
|
16
|
+
|
|
17
|
+
const { templates, templatesLoading: loading } = useSelector(
|
|
18
|
+
_.pick(["templates", "templatesLoading"])
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const [query, setQuery] = useState("");
|
|
22
|
+
const [scope, setScope] = useState();
|
|
23
|
+
|
|
24
|
+
const [sortColumn, setSortColumn] = useState(initialSortColumn);
|
|
25
|
+
const [sortDirection, setSortDirection] = useState(initialSortDirection);
|
|
26
|
+
|
|
27
|
+
const parsedTemplates = _.flow(
|
|
28
|
+
_.reject(({ scope }) => isHiddenScope(scope)),
|
|
29
|
+
_.filter((template) => !scope || scope == template.scope),
|
|
30
|
+
(items) =>
|
|
31
|
+
matchSorter(items, query, {
|
|
32
|
+
keys: ["name", "label"],
|
|
33
|
+
threshold: matchSorter.rankings.CONTAINS,
|
|
34
|
+
}),
|
|
35
|
+
_.orderBy([sortColumn], [sortDirection == "ascending" ? "asc" : "desc"])
|
|
36
|
+
)(templates);
|
|
37
|
+
|
|
38
|
+
const scopes = _.flow(
|
|
39
|
+
_.map("scope"),
|
|
40
|
+
_.uniq,
|
|
41
|
+
_.reject(isHiddenScope)
|
|
42
|
+
)(templates);
|
|
43
|
+
|
|
44
|
+
const context = {
|
|
45
|
+
loading,
|
|
46
|
+
templates: parsedTemplates,
|
|
47
|
+
|
|
48
|
+
query,
|
|
49
|
+
setQuery,
|
|
50
|
+
|
|
51
|
+
scope,
|
|
52
|
+
setScope,
|
|
53
|
+
scopes,
|
|
54
|
+
|
|
55
|
+
sortColumn,
|
|
56
|
+
sortDirection,
|
|
57
|
+
setSortColumn,
|
|
58
|
+
setSortDirection,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<TemplatesContext.Provider value={context}>
|
|
63
|
+
{children}
|
|
64
|
+
</TemplatesContext.Provider>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { FormattedMessage } from "react-intl";
|
|
4
|
+
import { Link } from "react-router-dom";
|
|
5
|
+
import { Table, Header, Icon } from "semantic-ui-react";
|
|
6
|
+
import { linkTo } from "@truedat/core/routes";
|
|
7
|
+
import { sortColumn as sortHandler } from "@truedat/core/services/sort";
|
|
8
|
+
import { columnDecorator } from "@truedat/core/services";
|
|
9
|
+
import {
|
|
10
|
+
TranslateDecorator,
|
|
11
|
+
DateDecorator,
|
|
12
|
+
} from "@truedat/core/services/columnDecorators";
|
|
13
|
+
|
|
14
|
+
import { useTemplatesContext } from "./TemplatesContext";
|
|
15
|
+
|
|
16
|
+
export default function TemplatesTable() {
|
|
17
|
+
const {
|
|
18
|
+
templates,
|
|
19
|
+
sortColumn,
|
|
20
|
+
sortDirection,
|
|
21
|
+
setSortColumn,
|
|
22
|
+
setSortDirection,
|
|
23
|
+
} = useTemplatesContext();
|
|
24
|
+
|
|
25
|
+
const columns = [
|
|
26
|
+
{
|
|
27
|
+
name: "name",
|
|
28
|
+
sort: { name: "name" },
|
|
29
|
+
fieldSelector: _.pick(["id", "name"]),
|
|
30
|
+
fieldDecorator: ({ id, name }) => (
|
|
31
|
+
<Link to={linkTo.TEMPLATE({ templateId: id })}>{name}</Link>
|
|
32
|
+
),
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: "label",
|
|
36
|
+
sort: { name: "label" },
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "scope",
|
|
40
|
+
sort: { name: "scope" },
|
|
41
|
+
fieldSelector: ({ scope }) => ({ id: `template.scope.${scope}` }),
|
|
42
|
+
fieldDecorator: TranslateDecorator,
|
|
43
|
+
width: 2,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "updated_at",
|
|
47
|
+
sort: { name: "updated_at" },
|
|
48
|
+
fieldSelector: ({ updated_at }) => ({
|
|
49
|
+
date: updated_at,
|
|
50
|
+
}),
|
|
51
|
+
width: 2,
|
|
52
|
+
fieldDecorator: DateDecorator,
|
|
53
|
+
textAlign: "center",
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
return _.isEmpty(templates) ? (
|
|
58
|
+
<Header as="h4">
|
|
59
|
+
<Icon name="search" />
|
|
60
|
+
<Header.Content>
|
|
61
|
+
<FormattedMessage id="templates.search.results.empty" />
|
|
62
|
+
</Header.Content>
|
|
63
|
+
</Header>
|
|
64
|
+
) : (
|
|
65
|
+
<Table sortable>
|
|
66
|
+
<Table.Header>
|
|
67
|
+
<Table.Row>
|
|
68
|
+
{columns.map((column, key) => (
|
|
69
|
+
<Table.HeaderCell
|
|
70
|
+
key={key}
|
|
71
|
+
width={column.width}
|
|
72
|
+
content={
|
|
73
|
+
<FormattedMessage
|
|
74
|
+
id={`template.form.${column.header || column.name}`}
|
|
75
|
+
defaultMessage={column.name}
|
|
76
|
+
/>
|
|
77
|
+
}
|
|
78
|
+
sorted={
|
|
79
|
+
_.path("sort.name")(column) === sortColumn
|
|
80
|
+
? sortDirection
|
|
81
|
+
: null
|
|
82
|
+
}
|
|
83
|
+
className={_.path("sort.name")(column) ? "" : "disabled"}
|
|
84
|
+
onClick={() =>
|
|
85
|
+
sortHandler(
|
|
86
|
+
column,
|
|
87
|
+
() => {},
|
|
88
|
+
setSortDirection,
|
|
89
|
+
setSortColumn,
|
|
90
|
+
sortDirection,
|
|
91
|
+
sortColumn
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
/>
|
|
95
|
+
))}
|
|
96
|
+
</Table.Row>
|
|
97
|
+
</Table.Header>
|
|
98
|
+
<Table.Body>
|
|
99
|
+
{templates.map((t, i) => (
|
|
100
|
+
<Table.Row key={i}>
|
|
101
|
+
{columns.map((column, i) => (
|
|
102
|
+
<Table.Cell
|
|
103
|
+
key={i}
|
|
104
|
+
textAlign={column.textAlign}
|
|
105
|
+
content={columnDecorator(column)(t)}
|
|
106
|
+
/>
|
|
107
|
+
))}
|
|
108
|
+
</Table.Row>
|
|
109
|
+
))}
|
|
110
|
+
</Table.Body>
|
|
111
|
+
</Table>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { shallowWithIntl } from "@truedat/test/intl-stub";
|
|
3
|
+
import TemplatesTable from "../TemplatesTable";
|
|
4
|
+
import { TemplatesContext } from "../TemplatesContext";
|
|
5
|
+
|
|
6
|
+
describe("<TemplatesTable />", () => {
|
|
7
|
+
const templates = [
|
|
8
|
+
{
|
|
9
|
+
scope: "bg",
|
|
10
|
+
name: "testbg",
|
|
11
|
+
label: "testbg",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
scope: "dq",
|
|
15
|
+
name: "testdq",
|
|
16
|
+
label: "testdq",
|
|
17
|
+
},
|
|
18
|
+
];
|
|
19
|
+
const context = { templates };
|
|
20
|
+
|
|
21
|
+
it("matches the latest snapshot", () => {
|
|
22
|
+
const wrapper = shallowWithIntl(
|
|
23
|
+
<TemplatesContext.Provider values={context}>
|
|
24
|
+
<TemplatesTable />
|
|
25
|
+
</TemplatesContext.Provider>
|
|
26
|
+
);
|
|
27
|
+
expect(wrapper).toMatchSnapshot();
|
|
28
|
+
});
|
|
29
|
+
});
|