@truedat/lm 5.13.0 → 5.13.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/package.json +3 -3
- package/src/components/ImplementationRelationForm.js +34 -61
- package/src/components/StructureRelationForm.js +72 -113
- package/src/components/__tests__/ImplementationRelationForm.spec.js +136 -24
- package/src/components/__tests__/StructureRelationForm.spec.js +120 -80
- package/src/components/__tests__/__snapshots__/ImplementationRelationForm.spec.js.snap +221 -26
- package/src/components/__tests__/__snapshots__/StructureRelationForm.spec.js.snap +250 -36
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/lm",
|
|
3
|
-
"version": "5.13.
|
|
3
|
+
"version": "5.13.2",
|
|
4
4
|
"description": "Truedat Link Manager",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"jsnext:main": "src/index.js",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
]
|
|
87
87
|
},
|
|
88
88
|
"dependencies": {
|
|
89
|
-
"@truedat/core": "5.13.
|
|
89
|
+
"@truedat/core": "5.13.2",
|
|
90
90
|
"path-to-regexp": "^1.7.0",
|
|
91
91
|
"prop-types": "^15.8.1",
|
|
92
92
|
"react-graph-vis": "1.0.6",
|
|
@@ -107,5 +107,5 @@
|
|
|
107
107
|
"react-dom": ">= 16.8.6 < 17",
|
|
108
108
|
"semantic-ui-react": ">= 2.0.3 < 2.2"
|
|
109
109
|
},
|
|
110
|
-
"gitHead": "
|
|
110
|
+
"gitHead": "f702ebedee85733e60b46b26fd468a18e93b8c20"
|
|
111
111
|
}
|
|
@@ -3,41 +3,35 @@ import React, { useState } from "react";
|
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import { connect } from "react-redux";
|
|
5
5
|
import { useIntl } from "react-intl";
|
|
6
|
-
import {
|
|
7
|
-
Button,
|
|
8
|
-
Checkbox,
|
|
9
|
-
Form,
|
|
10
|
-
Grid,
|
|
11
|
-
Header,
|
|
12
|
-
Segment,
|
|
13
|
-
} from "semantic-ui-react";
|
|
6
|
+
import { Button, Form, Grid, Header, Segment } from "semantic-ui-react";
|
|
14
7
|
import { HistoryBackButton } from "@truedat/core/components";
|
|
15
8
|
import { linkTo } from "@truedat/core/routes";
|
|
9
|
+
import { makeTagOptionsSelector } from "@truedat/core/selectors";
|
|
16
10
|
import { linkConcept } from "../routines";
|
|
17
11
|
import RelationTagsLoader from "./RelationTagsLoader";
|
|
18
12
|
|
|
13
|
+
const TagTypeDropdownSelector = React.lazy(() =>
|
|
14
|
+
import("@truedat/lm/components/TagTypeDropdownSelector")
|
|
15
|
+
);
|
|
16
|
+
|
|
19
17
|
const ConceptSelector = React.lazy(() =>
|
|
20
18
|
import("@truedat/bg/concepts/relations/components/ConceptSelector")
|
|
21
19
|
);
|
|
22
20
|
|
|
21
|
+
const filters = {
|
|
22
|
+
current: [true],
|
|
23
|
+
status: ["pending_approval", "draft", "rejected", "published"],
|
|
24
|
+
};
|
|
25
|
+
|
|
23
26
|
export const ImplementationRelationForm = ({
|
|
24
27
|
conceptLinking,
|
|
25
28
|
implementation,
|
|
26
29
|
tagOptions,
|
|
27
30
|
linkConcept,
|
|
31
|
+
selectedRelationTags,
|
|
28
32
|
}) => {
|
|
29
33
|
const { formatMessage } = useIntl();
|
|
30
|
-
const [selectedTag, setSelectedTag] = useState([]);
|
|
31
34
|
const [selectedConcept, setSelectedConcept] = useState(null);
|
|
32
|
-
const submitDisabled = conceptLinking || !selectedConcept;
|
|
33
|
-
|
|
34
|
-
const handleTagOnChange = (e, { value }) => {
|
|
35
|
-
const newSelectedTag = _.cond([
|
|
36
|
-
[_.includes(value), _.without([value])],
|
|
37
|
-
[_.stubTrue, _.concat(value)],
|
|
38
|
-
])(selectedTag);
|
|
39
|
-
setSelectedTag(newSelectedTag);
|
|
40
|
-
};
|
|
41
35
|
|
|
42
36
|
const handleConceptSelected = (selectedConcept) =>
|
|
43
37
|
setSelectedConcept(selectedConcept);
|
|
@@ -53,7 +47,7 @@ export const ImplementationRelationForm = ({
|
|
|
53
47
|
source_type: "implementation_ref",
|
|
54
48
|
target_id: selectedConcept.business_concept_id,
|
|
55
49
|
target_type: "business_concept",
|
|
56
|
-
tag_ids:
|
|
50
|
+
tag_ids: selectedRelationTags ? selectedRelationTags : [],
|
|
57
51
|
context: {},
|
|
58
52
|
};
|
|
59
53
|
linkConcept(conceptLink);
|
|
@@ -72,44 +66,29 @@ export const ImplementationRelationForm = ({
|
|
|
72
66
|
/>
|
|
73
67
|
|
|
74
68
|
{!_.isEmpty(tagOptions) ? (
|
|
75
|
-
<Form.Field
|
|
76
|
-
<
|
|
77
|
-
{formatMessage({ id: "conceptRelations.relationType" })}
|
|
78
|
-
</label>
|
|
79
|
-
{tagOptions.map((tagOption, key) => (
|
|
80
|
-
<div key={key} style={{ margin: "6px 0" }}>
|
|
81
|
-
<Checkbox
|
|
82
|
-
toggle
|
|
83
|
-
label={formatMessage({
|
|
84
|
-
id: `conceptRelations.relationType.${tagOption.text}`,
|
|
85
|
-
defaultMessage: tagOption.text,
|
|
86
|
-
})}
|
|
87
|
-
name={tagOption.text}
|
|
88
|
-
value={tagOption.id}
|
|
89
|
-
onChange={handleTagOnChange}
|
|
90
|
-
/>
|
|
91
|
-
</div>
|
|
92
|
-
))}
|
|
69
|
+
<Form.Field className="concept-relation-form">
|
|
70
|
+
<TagTypeDropdownSelector options={tagOptions} />
|
|
93
71
|
</Form.Field>
|
|
94
72
|
) : null}
|
|
95
73
|
<ConceptSelector
|
|
96
74
|
selectedConcept={selectedConcept}
|
|
97
75
|
handleConceptSelected={handleConceptSelected}
|
|
76
|
+
defaultFilters={filters}
|
|
98
77
|
/>
|
|
99
78
|
|
|
100
79
|
<div className="actions">
|
|
101
|
-
<HistoryBackButton
|
|
102
|
-
content={formatMessage({ id: "actions.cancel" })}
|
|
103
|
-
disabled={conceptLinking}
|
|
104
|
-
/>
|
|
105
|
-
|
|
106
80
|
<Button
|
|
107
81
|
primary
|
|
108
82
|
content={formatMessage({ id: "actions.create" })}
|
|
109
|
-
disabled={
|
|
83
|
+
disabled={!selectedConcept}
|
|
110
84
|
loading={conceptLinking}
|
|
111
85
|
onClick={handleSubmit}
|
|
112
86
|
/>
|
|
87
|
+
|
|
88
|
+
<HistoryBackButton
|
|
89
|
+
content={formatMessage({ id: "actions.cancel" })}
|
|
90
|
+
disabled={conceptLinking}
|
|
91
|
+
/>
|
|
113
92
|
</div>
|
|
114
93
|
</Grid.Column>
|
|
115
94
|
</Grid>
|
|
@@ -122,26 +101,20 @@ ImplementationRelationForm.propTypes = {
|
|
|
122
101
|
tagOptions: PropTypes.array,
|
|
123
102
|
conceptLinking: PropTypes.bool,
|
|
124
103
|
linkConcept: PropTypes.func,
|
|
104
|
+
selectedRelationTags: PropTypes.array,
|
|
125
105
|
};
|
|
126
106
|
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
(tag) =>
|
|
138
|
-
_.path("value.target_type")(tag) == "implementations" ||
|
|
139
|
-
!_.path("value.target_type")
|
|
140
|
-
),
|
|
141
|
-
tagsToOptions
|
|
142
|
-
)(state.relationTags),
|
|
143
|
-
});
|
|
107
|
+
const makeMapStateToProps = () => {
|
|
108
|
+
const getTagOptions = makeTagOptionsSelector("implementations");
|
|
109
|
+
const mapStateToProps = (state) => ({
|
|
110
|
+
tagOptions: getTagOptions(state),
|
|
111
|
+
conceptLinking: state.conceptLinking,
|
|
112
|
+
implementation: state.ruleImplementation,
|
|
113
|
+
selectedRelationTags: state.selectedRelationTags,
|
|
114
|
+
});
|
|
115
|
+
return mapStateToProps;
|
|
116
|
+
};
|
|
144
117
|
|
|
145
|
-
export default connect(
|
|
118
|
+
export default connect(makeMapStateToProps, { linkConcept })(
|
|
146
119
|
ImplementationRelationForm
|
|
147
120
|
);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
|
-
import React from "react";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
|
-
import { FormattedMessage
|
|
4
|
+
import { FormattedMessage } from "react-intl";
|
|
5
5
|
import { connect } from "react-redux";
|
|
6
|
-
import {
|
|
7
|
-
import { Button, Grid, Header, Form, Checkbox } from "semantic-ui-react";
|
|
6
|
+
import { Button, Grid, Header, Form } from "semantic-ui-react";
|
|
8
7
|
import { HistoryBackButton } from "@truedat/core/components";
|
|
8
|
+
import { makeTagOptionsSelector } from "@truedat/core/selectors";
|
|
9
9
|
import { linkTo } from "@truedat/core/routes";
|
|
10
10
|
import { linkConcept } from "../routines";
|
|
11
11
|
import RelationTagsLoader from "./RelationTagsLoader";
|
|
@@ -14,139 +14,98 @@ const ConceptSelector = React.lazy(() =>
|
|
|
14
14
|
import("@truedat/bg/concepts/relations/components/ConceptSelector")
|
|
15
15
|
);
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
selectedConcept: null,
|
|
21
|
-
};
|
|
22
|
-
handleTagOnChange = (e, { value }) => {
|
|
23
|
-
const { selectedTag } = this.state;
|
|
24
|
-
|
|
25
|
-
const newSelectedTag = _.cond([
|
|
26
|
-
[_.includes(value), _.without([value])],
|
|
27
|
-
[_.stubTrue, _.concat(value)],
|
|
28
|
-
])(selectedTag);
|
|
17
|
+
const TagTypeDropdownSelector = React.lazy(() =>
|
|
18
|
+
import("@truedat/lm/components/TagTypeDropdownSelector")
|
|
19
|
+
);
|
|
29
20
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
21
|
+
const filters = {
|
|
22
|
+
current: [true],
|
|
23
|
+
status: ["pending_approval", "draft", "rejected", "published"],
|
|
24
|
+
};
|
|
34
25
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
export const StructureRelationForm = ({
|
|
27
|
+
structure,
|
|
28
|
+
tagOptions,
|
|
29
|
+
linkConcept,
|
|
30
|
+
selectedRelationTags,
|
|
31
|
+
conceptLinking,
|
|
32
|
+
}) => {
|
|
33
|
+
const [selectedConcept, setSelectedConcept] = useState(null);
|
|
38
34
|
|
|
39
|
-
|
|
35
|
+
const handleConceptSelected = (selectedConcept) =>
|
|
36
|
+
setSelectedConcept(selectedConcept);
|
|
40
37
|
|
|
38
|
+
const handleSubmit = () => {
|
|
39
|
+
const redirectUrl = linkTo.STRUCTURE_LINKS({ id: structure.id });
|
|
41
40
|
const conceptLink = {
|
|
42
41
|
redirectUrl,
|
|
43
42
|
source_id: selectedConcept.business_concept_id,
|
|
44
43
|
source_type: "business_concept",
|
|
45
44
|
target_id: structure.id,
|
|
46
45
|
target_type: "data_structure",
|
|
47
|
-
tag_ids:
|
|
46
|
+
tag_ids: selectedRelationTags ? selectedRelationTags : [],
|
|
48
47
|
context: {},
|
|
49
48
|
};
|
|
50
49
|
linkConcept(conceptLink);
|
|
51
50
|
};
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
52
|
+
return (
|
|
53
|
+
<Grid>
|
|
54
|
+
<Grid.Column width={16}>
|
|
55
|
+
<RelationTagsLoader />
|
|
56
|
+
<Header
|
|
57
|
+
as="h4"
|
|
58
|
+
content={<FormattedMessage id="structures.relation.new.header" />}
|
|
59
|
+
/>
|
|
60
|
+
|
|
61
|
+
{!_.isEmpty(tagOptions) ? (
|
|
62
|
+
<Form.Field className="concept-relation-form">
|
|
63
|
+
<TagTypeDropdownSelector options={tagOptions} />
|
|
64
|
+
</Form.Field>
|
|
65
|
+
) : null}
|
|
66
|
+
|
|
67
|
+
<ConceptSelector
|
|
68
|
+
selectedConcept={selectedConcept}
|
|
69
|
+
handleConceptSelected={handleConceptSelected}
|
|
70
|
+
defaultFilters={filters}
|
|
71
|
+
/>
|
|
72
|
+
|
|
73
|
+
<div className="actions">
|
|
74
|
+
<Button
|
|
75
|
+
primary
|
|
76
|
+
content={<FormattedMessage id="actions.create" />}
|
|
77
|
+
disabled={!selectedConcept}
|
|
78
|
+
loading={conceptLinking}
|
|
79
|
+
onClick={handleSubmit}
|
|
69
80
|
/>
|
|
70
81
|
|
|
71
|
-
|
|
72
|
-
<
|
|
73
|
-
<label>
|
|
74
|
-
<FormattedMessage id="conceptRelations.relationType" />
|
|
75
|
-
</label>
|
|
76
|
-
|
|
77
|
-
{tagOptions.map((tagOption, key) => (
|
|
78
|
-
<div
|
|
79
|
-
key={key}
|
|
80
|
-
style={{
|
|
81
|
-
margin: "6px 0",
|
|
82
|
-
}}
|
|
83
|
-
>
|
|
84
|
-
<Checkbox
|
|
85
|
-
toggle
|
|
86
|
-
label={formatMessage({
|
|
87
|
-
id: `conceptRelations.relationType.${tagOption.text}`,
|
|
88
|
-
defaultMessage: tagOption.text,
|
|
89
|
-
})}
|
|
90
|
-
name={tagOption.text}
|
|
91
|
-
value={tagOption.value}
|
|
92
|
-
onChange={this.handleTagOnChange}
|
|
93
|
-
/>
|
|
94
|
-
</div>
|
|
95
|
-
))}
|
|
96
|
-
</Form.Field>
|
|
97
|
-
)}
|
|
98
|
-
|
|
99
|
-
<ConceptSelector
|
|
100
|
-
loadConcepts={false}
|
|
101
|
-
selectedConcept={selectedConcept}
|
|
102
|
-
handleConceptSelected={this.handleConceptSelected}
|
|
82
|
+
<HistoryBackButton
|
|
83
|
+
content={<FormattedMessage id="actions.cancel" />}
|
|
103
84
|
/>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
<Button
|
|
110
|
-
primary
|
|
111
|
-
content={<FormattedMessage id="actions.create" />}
|
|
112
|
-
disabled={submitDisabled}
|
|
113
|
-
loading={conceptLinking}
|
|
114
|
-
onClick={this.handleSubmit}
|
|
115
|
-
/>
|
|
116
|
-
</div>
|
|
117
|
-
</Grid.Column>
|
|
118
|
-
</Grid>
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
85
|
+
</div>
|
|
86
|
+
</Grid.Column>
|
|
87
|
+
</Grid>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
122
90
|
|
|
123
91
|
StructureRelationForm.propTypes = {
|
|
124
92
|
conceptLinking: PropTypes.bool,
|
|
125
|
-
intl: PropTypes.object,
|
|
126
93
|
linkConcept: PropTypes.func,
|
|
127
94
|
structure: PropTypes.object,
|
|
128
95
|
tagOptions: PropTypes.array,
|
|
129
96
|
};
|
|
130
97
|
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
_.path("value.target_type")(tag) == "data_field" ||
|
|
142
|
-
!_.path("value.target_type")
|
|
143
|
-
),
|
|
144
|
-
tagsToOptions
|
|
145
|
-
)(relationTags),
|
|
146
|
-
structure,
|
|
147
|
-
});
|
|
98
|
+
const makeMapStateToProps = () => {
|
|
99
|
+
const getTagOptions = makeTagOptionsSelector("data_field");
|
|
100
|
+
const mapStateToProps = (state) => ({
|
|
101
|
+
conceptLinking: state.conceptLinking,
|
|
102
|
+
tagOptions: getTagOptions(state),
|
|
103
|
+
selectedRelationTags: state.selectedRelationTags,
|
|
104
|
+
structure: state.structure,
|
|
105
|
+
});
|
|
106
|
+
return mapStateToProps;
|
|
107
|
+
};
|
|
148
108
|
|
|
149
|
-
export default
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
)(StructureRelationForm);
|
|
109
|
+
export default connect(makeMapStateToProps, { linkConcept })(
|
|
110
|
+
StructureRelationForm
|
|
111
|
+
);
|
|
@@ -1,33 +1,145 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from "react";
|
|
2
2
|
import { render } from "@truedat/test/render";
|
|
3
|
+
import { linkTo } from "@truedat/core/routes";
|
|
4
|
+
import userEvent from "@testing-library/user-event";
|
|
5
|
+
import { waitFor } from "@testing-library/react";
|
|
3
6
|
import { ImplementationRelationForm } from "../ImplementationRelationForm";
|
|
7
|
+
import en from "../../messages/en";
|
|
4
8
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
const linkConcept = jest.fn();
|
|
10
|
+
|
|
11
|
+
const domain = {
|
|
12
|
+
external_id: "foo domain",
|
|
13
|
+
id: 381,
|
|
14
|
+
name: "foo domain",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const tagOptions = [
|
|
18
|
+
{ id: 1, text: "relates_to", value: 0 },
|
|
19
|
+
{ id: 2, text: "text", value: 1 },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
const concepts = [
|
|
23
|
+
{
|
|
24
|
+
_actions: { can_create_structure_link: true },
|
|
25
|
+
business_concept_id: 2,
|
|
26
|
+
domain: domain,
|
|
27
|
+
id: 12355,
|
|
28
|
+
name: "foo concept",
|
|
29
|
+
status: "published",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
_actions: { can_create_structure_link: true },
|
|
33
|
+
business_concept_id: 123,
|
|
34
|
+
domain: domain,
|
|
35
|
+
id: 12290,
|
|
36
|
+
name: "bar concept",
|
|
37
|
+
status: "draft",
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
const props = {
|
|
42
|
+
implementation: { rule_id: 2, id: 4, implementation_ref: 1 },
|
|
43
|
+
tagOptions,
|
|
44
|
+
conceptLinking: false,
|
|
45
|
+
linkConcept,
|
|
46
|
+
selectedRelationTags: [1],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const renderOpts = {
|
|
50
|
+
messages: {
|
|
51
|
+
en: {
|
|
52
|
+
...en,
|
|
53
|
+
"implementations.relation.new.header": "header",
|
|
54
|
+
"conceptRelations.relationType": "relationType",
|
|
55
|
+
"actions.cancel": "Cancel",
|
|
56
|
+
"actions.create": "Create",
|
|
57
|
+
"conceptRelations.relationType.text": "text",
|
|
58
|
+
"concepts.props.name": "Name",
|
|
59
|
+
"concepts.props.domain": "Domain",
|
|
60
|
+
"concepts.props.status": "Status",
|
|
61
|
+
"search.save_filters": "Save Filters",
|
|
62
|
+
"search.clear_filters": "Clear Filters",
|
|
63
|
+
"search.applied_filters": "Applied Filters",
|
|
64
|
+
"conceptRelations.relatedConcept": "Related Concept",
|
|
65
|
+
"concepts.search.placeholder": "Search",
|
|
15
66
|
},
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
67
|
+
},
|
|
68
|
+
state: {
|
|
69
|
+
concepts,
|
|
70
|
+
conceptActiveFilters: { filter: "some" },
|
|
71
|
+
},
|
|
72
|
+
fallback: "lazy",
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
describe("<ImplementationRelationForm />", () => {
|
|
76
|
+
it("matches the latest snapshot", async () => {
|
|
77
|
+
const { container, getByText } = render(
|
|
78
|
+
<ImplementationRelationForm {...props} />,
|
|
79
|
+
|
|
29
80
|
renderOpts
|
|
30
81
|
);
|
|
82
|
+
|
|
83
|
+
await waitFor(() => {
|
|
84
|
+
expect(getByText(/relates_to/)).toBeInTheDocument();
|
|
85
|
+
});
|
|
31
86
|
expect(container).toMatchSnapshot();
|
|
32
87
|
});
|
|
88
|
+
|
|
89
|
+
it("disables submit and shows loading state if concept is linking", async () => {
|
|
90
|
+
const newProps = {
|
|
91
|
+
...props,
|
|
92
|
+
conceptLinking: true,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const { queryByText, queryByRole, getByText, findByRole, findByText } =
|
|
96
|
+
render(<ImplementationRelationForm {...newProps} />, renderOpts);
|
|
97
|
+
|
|
98
|
+
await waitFor(() => {
|
|
99
|
+
expect(getByText(/relates_to/)).toBeInTheDocument();
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
expect(queryByRole("button", { name: /Create/ })).toBeDisabled();
|
|
103
|
+
userEvent.click(await findByText(/relates_to/));
|
|
104
|
+
userEvent.click(await queryByText(/bar concept/));
|
|
105
|
+
|
|
106
|
+
await waitFor(() => {
|
|
107
|
+
expect(queryByRole("button", { name: /Create/ })).toBeEnabled();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
userEvent.click(await findByRole("button", { name: /Create/ }));
|
|
111
|
+
|
|
112
|
+
await waitFor(() => {
|
|
113
|
+
expect(queryByRole("button", { name: /Create/ })).toHaveClass("loading");
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("submits the selected relation", async () => {
|
|
118
|
+
const { queryByText, getByText, findByRole, findByText } = render(
|
|
119
|
+
<ImplementationRelationForm {...props} />,
|
|
120
|
+
renderOpts
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
await waitFor(() => {
|
|
124
|
+
expect(getByText(/relates_to/)).toBeInTheDocument();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
userEvent.click(await findByText(/relates_to/));
|
|
128
|
+
userEvent.click(await queryByText(/bar concept/));
|
|
129
|
+
|
|
130
|
+
userEvent.click(await findByRole("button", { name: /Create/ }));
|
|
131
|
+
|
|
132
|
+
const expectedRelation = {
|
|
133
|
+
redirectUrl: linkTo.IMPLEMENTATION_CONCEPT_LINKS({
|
|
134
|
+
implementation_id: 4,
|
|
135
|
+
}),
|
|
136
|
+
source_id: 1,
|
|
137
|
+
source_type: "implementation_ref",
|
|
138
|
+
target_id: 123,
|
|
139
|
+
target_type: "business_concept",
|
|
140
|
+
tag_ids: [1],
|
|
141
|
+
context: {},
|
|
142
|
+
};
|
|
143
|
+
expect(linkConcept.mock.calls[0][0]).toEqual(expectedRelation);
|
|
144
|
+
});
|
|
33
145
|
});
|
|
@@ -1,108 +1,148 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { render } from "@truedat/test/render";
|
|
3
3
|
import { linkTo } from "@truedat/core/routes";
|
|
4
|
+
import userEvent from "@testing-library/user-event";
|
|
5
|
+
import { waitFor } from "@testing-library/react";
|
|
4
6
|
import { StructureRelationForm } from "../StructureRelationForm";
|
|
7
|
+
import en from "../../messages/en";
|
|
8
|
+
|
|
9
|
+
const linkConcept = jest.fn();
|
|
10
|
+
|
|
11
|
+
const domain = {
|
|
12
|
+
external_id: "foo domain",
|
|
13
|
+
id: 381,
|
|
14
|
+
name: "foo domain",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const concepts = [
|
|
18
|
+
{
|
|
19
|
+
_actions: { can_create_structure_link: true },
|
|
20
|
+
business_concept_id: 2,
|
|
21
|
+
domain: domain,
|
|
22
|
+
id: 12355,
|
|
23
|
+
name: "foo concept",
|
|
24
|
+
status: "published",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
_actions: { can_create_structure_link: true },
|
|
28
|
+
business_concept_id: 123,
|
|
29
|
+
domain: domain,
|
|
30
|
+
id: 12290,
|
|
31
|
+
name: "bar concept",
|
|
32
|
+
status: "draft",
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
const tagOptions = [
|
|
37
|
+
{ id: 1, text: "relates_to", value: 0 },
|
|
38
|
+
{ id: 2, text: "text", value: 1 },
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
const structure = {
|
|
42
|
+
group: "s_group",
|
|
43
|
+
system: { name: "sys_name" },
|
|
44
|
+
name: "s_name",
|
|
45
|
+
id: 3,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const props = {
|
|
49
|
+
tagOptions,
|
|
50
|
+
structure,
|
|
51
|
+
linkConcept,
|
|
52
|
+
selectedRelationTags: [1],
|
|
53
|
+
};
|
|
54
|
+
const messages = {
|
|
55
|
+
en: {
|
|
56
|
+
...en,
|
|
57
|
+
"structures.relation.new.header": "Header",
|
|
58
|
+
"actions.create": "Create",
|
|
59
|
+
"actions.cancel": "Cancel",
|
|
60
|
+
"concepts.props.name": "Name",
|
|
61
|
+
"concepts.props.domain": "Domain",
|
|
62
|
+
"concepts.props.status": "Status",
|
|
63
|
+
"search.save_filters": "Save Filters",
|
|
64
|
+
"search.clear_filters": "Clear Filters",
|
|
65
|
+
"search.applied_filters": "Applied Filters",
|
|
66
|
+
"conceptRelations.relatedConcept": "Related Concept",
|
|
67
|
+
"concepts.search.placeholder": "Search",
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const renderOpts = {
|
|
72
|
+
messages,
|
|
73
|
+
state: {
|
|
74
|
+
structure,
|
|
75
|
+
concepts,
|
|
76
|
+
conceptActiveFilters: { filter: "some" },
|
|
77
|
+
},
|
|
78
|
+
fallback: "lazy",
|
|
79
|
+
};
|
|
5
80
|
|
|
6
81
|
describe("<StructureRelationForm />", () => {
|
|
7
|
-
it("matches the latest snapshot", () => {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
linkConcept: jest.fn()
|
|
13
|
-
};
|
|
14
|
-
const wrapper = shallowWithIntl(<StructureRelationForm {...props} />);
|
|
15
|
-
expect(wrapper).toMatchSnapshot();
|
|
16
|
-
});
|
|
82
|
+
it("matches the latest snapshot", async () => {
|
|
83
|
+
const { container, getByText } = render(
|
|
84
|
+
<StructureRelationForm {...props} />,
|
|
85
|
+
renderOpts
|
|
86
|
+
);
|
|
17
87
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
conceptLinking: true
|
|
24
|
-
};
|
|
25
|
-
const wrapper = shallowWithIntl(<StructureRelationForm {...props} />);
|
|
26
|
-
const submitButton = wrapper.find(".actions").find("Button[primary=true]");
|
|
27
|
-
expect(submitButton.prop("loading")).toBe(true);
|
|
28
|
-
expect(submitButton.prop("disabled")).toBe(true);
|
|
88
|
+
await waitFor(() => {
|
|
89
|
+
expect(getByText(/relates_to/)).toBeInTheDocument();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
expect(container).toMatchSnapshot();
|
|
29
93
|
});
|
|
30
94
|
|
|
31
|
-
it("
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
{ text: "relates to", value: 1 }
|
|
36
|
-
],
|
|
37
|
-
structureField: {},
|
|
38
|
-
structure: {},
|
|
39
|
-
linkConcept: jest.fn()
|
|
95
|
+
it("disables submit and shows loading state if concept is linking", async () => {
|
|
96
|
+
const newProps = {
|
|
97
|
+
...props,
|
|
98
|
+
conceptLinking: true,
|
|
40
99
|
};
|
|
41
|
-
const wrapper = shallowWithIntl(<StructureRelationForm {...props} />);
|
|
42
100
|
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
const expectedState = { selectedTag, selectedConcept };
|
|
101
|
+
const { queryByText, queryByRole, getByText, findByRole, findByText } =
|
|
102
|
+
render(<StructureRelationForm {...newProps} />, renderOpts);
|
|
46
103
|
|
|
47
|
-
|
|
48
|
-
.
|
|
49
|
-
|
|
50
|
-
.prop("onChange")(null, { value: selectedTag });
|
|
104
|
+
await waitFor(() => {
|
|
105
|
+
expect(getByText(/relates_to/)).toBeInTheDocument();
|
|
106
|
+
});
|
|
51
107
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
108
|
+
expect(queryByRole("button", { name: /Create/ })).toBeDisabled();
|
|
109
|
+
userEvent.click(await findByText(/relates_to/));
|
|
110
|
+
userEvent.click(await queryByText(/bar concept/));
|
|
55
111
|
|
|
56
|
-
|
|
57
|
-
|
|
112
|
+
await waitFor(() => {
|
|
113
|
+
expect(queryByRole("button", { name: /Create/ })).toBeEnabled();
|
|
114
|
+
});
|
|
58
115
|
|
|
59
|
-
|
|
60
|
-
const linkConcept = jest.fn();
|
|
61
|
-
const props = {
|
|
62
|
-
linkConcept,
|
|
63
|
-
tagOptions: [
|
|
64
|
-
{ text: "-", value: 0 },
|
|
65
|
-
{ text: "relates to", value: 2 }
|
|
66
|
-
],
|
|
67
|
-
structure: {
|
|
68
|
-
group: "s_group",
|
|
69
|
-
system: { name: "sys_name" },
|
|
70
|
-
name: "s_name",
|
|
71
|
-
id: 3
|
|
72
|
-
},
|
|
73
|
-
structureField: { id: 545, name: "f_name" }
|
|
74
|
-
};
|
|
75
|
-
const wrapper = shallowWithIntl(<StructureRelationForm {...props} />);
|
|
116
|
+
userEvent.click(await findByRole("button", { name: /Create/ }));
|
|
76
117
|
|
|
77
|
-
|
|
118
|
+
await waitFor(() => {
|
|
119
|
+
expect(queryByRole("button", { name: /Create/ })).toHaveClass("loading");
|
|
120
|
+
});
|
|
121
|
+
});
|
|
78
122
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
123
|
+
it("submits the selected relation", async () => {
|
|
124
|
+
const { queryByText, getByText, findByRole, findByText } = render(
|
|
125
|
+
<StructureRelationForm {...props} />,
|
|
126
|
+
renderOpts
|
|
127
|
+
);
|
|
83
128
|
|
|
84
|
-
|
|
85
|
-
.
|
|
86
|
-
|
|
87
|
-
.prop("onChange")(null, { value: 2 });
|
|
129
|
+
await waitFor(() => {
|
|
130
|
+
expect(getByText(/relates_to/)).toBeInTheDocument();
|
|
131
|
+
});
|
|
88
132
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
.prop("handleConceptSelected")(selectedConcept);
|
|
133
|
+
userEvent.click(await findByText(/relates_to/));
|
|
134
|
+
userEvent.click(await queryByText(/bar concept/));
|
|
92
135
|
|
|
93
|
-
|
|
94
|
-
.find("Button")
|
|
95
|
-
.find({ primary: true })
|
|
96
|
-
.prop("onClick")();
|
|
136
|
+
userEvent.click(await findByRole("button", { name: /Create/ }));
|
|
97
137
|
|
|
98
138
|
const expectedRelation = {
|
|
99
|
-
redirectUrl: linkTo.
|
|
139
|
+
redirectUrl: linkTo.STRUCTURE_LINKS({ id: 3 }),
|
|
100
140
|
source_id: 123,
|
|
101
141
|
source_type: "business_concept",
|
|
102
142
|
target_id: 3,
|
|
103
143
|
target_type: "data_structure",
|
|
104
|
-
tag_ids: [
|
|
105
|
-
context: {}
|
|
144
|
+
tag_ids: [1],
|
|
145
|
+
context: {},
|
|
106
146
|
};
|
|
107
147
|
expect(linkConcept.mock.calls[0][0]).toEqual(expectedRelation);
|
|
108
148
|
});
|
|
@@ -4,7 +4,7 @@ exports[`<ImplementationRelationForm /> matches the latest snapshot 1`] = `
|
|
|
4
4
|
<div>
|
|
5
5
|
<div
|
|
6
6
|
class="ui bottom attached segment"
|
|
7
|
-
style="
|
|
7
|
+
style=""
|
|
8
8
|
>
|
|
9
9
|
<div
|
|
10
10
|
class="ui grid"
|
|
@@ -19,49 +19,244 @@ exports[`<ImplementationRelationForm /> matches the latest snapshot 1`] = `
|
|
|
19
19
|
header
|
|
20
20
|
</h4>
|
|
21
21
|
<div
|
|
22
|
-
class="field"
|
|
23
|
-
style="margin-bottom: 10px;"
|
|
22
|
+
class="field concept-relation-form"
|
|
24
23
|
>
|
|
25
|
-
<label>
|
|
26
|
-
relationType
|
|
27
|
-
</label>
|
|
28
24
|
<div
|
|
29
|
-
|
|
25
|
+
class="field"
|
|
30
26
|
>
|
|
27
|
+
<b>
|
|
28
|
+
<label>
|
|
29
|
+
Relation types
|
|
30
|
+
</label>
|
|
31
|
+
</b>
|
|
32
|
+
<div>
|
|
33
|
+
<div
|
|
34
|
+
aria-expanded="false"
|
|
35
|
+
class="ui selection dropdown concept-link-dropdown"
|
|
36
|
+
role="listbox"
|
|
37
|
+
tabindex="0"
|
|
38
|
+
>
|
|
39
|
+
<i
|
|
40
|
+
aria-hidden="true"
|
|
41
|
+
class="dropdown icon"
|
|
42
|
+
/>
|
|
43
|
+
<div
|
|
44
|
+
class="menu transition"
|
|
45
|
+
>
|
|
46
|
+
<div
|
|
47
|
+
aria-checked="false"
|
|
48
|
+
aria-selected="true"
|
|
49
|
+
class="selected item"
|
|
50
|
+
role="option"
|
|
51
|
+
style="pointer-events: all;"
|
|
52
|
+
>
|
|
53
|
+
<span
|
|
54
|
+
class="text"
|
|
55
|
+
>
|
|
56
|
+
relates_to
|
|
57
|
+
</span>
|
|
58
|
+
</div>
|
|
59
|
+
<div
|
|
60
|
+
aria-checked="false"
|
|
61
|
+
aria-selected="false"
|
|
62
|
+
class="item"
|
|
63
|
+
role="option"
|
|
64
|
+
style="pointer-events: all;"
|
|
65
|
+
>
|
|
66
|
+
<span
|
|
67
|
+
class="text"
|
|
68
|
+
>
|
|
69
|
+
text
|
|
70
|
+
</span>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
<label>
|
|
78
|
+
Related Concept
|
|
79
|
+
</label>
|
|
80
|
+
<div
|
|
81
|
+
class="ui segment"
|
|
82
|
+
>
|
|
83
|
+
<div
|
|
84
|
+
class="ui action left icon input"
|
|
85
|
+
>
|
|
86
|
+
<input
|
|
87
|
+
placeholder="Search"
|
|
88
|
+
type="text"
|
|
89
|
+
value=""
|
|
90
|
+
/>
|
|
91
|
+
<i
|
|
92
|
+
aria-hidden="true"
|
|
93
|
+
class="search link icon"
|
|
94
|
+
/>
|
|
31
95
|
<div
|
|
32
|
-
|
|
96
|
+
aria-expanded="false"
|
|
97
|
+
class="ui button floating labeled scrolling dropdown icon"
|
|
98
|
+
role="listbox"
|
|
99
|
+
tabindex="0"
|
|
33
100
|
>
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
101
|
+
<div
|
|
102
|
+
aria-atomic="true"
|
|
103
|
+
aria-live="polite"
|
|
104
|
+
class="divider text"
|
|
105
|
+
role="alert"
|
|
106
|
+
>
|
|
107
|
+
Filters
|
|
108
|
+
</div>
|
|
109
|
+
<i
|
|
110
|
+
aria-hidden="true"
|
|
111
|
+
class="filter icon"
|
|
112
|
+
/>
|
|
113
|
+
<div
|
|
114
|
+
class="menu transition"
|
|
115
|
+
>
|
|
116
|
+
<div
|
|
117
|
+
class="item"
|
|
118
|
+
role="option"
|
|
119
|
+
>
|
|
120
|
+
<em>
|
|
121
|
+
(reset filters)
|
|
122
|
+
</em>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
<div
|
|
128
|
+
class="selectedFilters"
|
|
129
|
+
>
|
|
130
|
+
<div
|
|
131
|
+
class="appliedFilters"
|
|
132
|
+
>
|
|
133
|
+
Applied Filters
|
|
134
|
+
</div>
|
|
135
|
+
<div
|
|
136
|
+
aria-expanded="false"
|
|
137
|
+
class="ui floating item scrolling dropdown"
|
|
138
|
+
role="listbox"
|
|
139
|
+
tabindex="0"
|
|
140
|
+
>
|
|
141
|
+
<div
|
|
142
|
+
class="ui label"
|
|
143
|
+
>
|
|
144
|
+
filter
|
|
145
|
+
<i
|
|
146
|
+
aria-hidden="true"
|
|
147
|
+
class="delete icon"
|
|
148
|
+
/>
|
|
149
|
+
</div>
|
|
150
|
+
<div
|
|
151
|
+
class="menu transition dimmable"
|
|
41
152
|
/>
|
|
42
|
-
<label>
|
|
43
|
-
text
|
|
44
|
-
</label>
|
|
45
153
|
</div>
|
|
154
|
+
<a
|
|
155
|
+
class="resetFilters"
|
|
156
|
+
>
|
|
157
|
+
Clear Filters
|
|
158
|
+
</a>
|
|
159
|
+
<a
|
|
160
|
+
class="resetFilters"
|
|
161
|
+
>
|
|
162
|
+
Save Filters
|
|
163
|
+
</a>
|
|
46
164
|
</div>
|
|
165
|
+
<table
|
|
166
|
+
class="ui small selectable table"
|
|
167
|
+
>
|
|
168
|
+
<thead
|
|
169
|
+
class=""
|
|
170
|
+
>
|
|
171
|
+
<tr
|
|
172
|
+
class=""
|
|
173
|
+
>
|
|
174
|
+
<th
|
|
175
|
+
class=""
|
|
176
|
+
>
|
|
177
|
+
Name
|
|
178
|
+
</th>
|
|
179
|
+
<th
|
|
180
|
+
class=""
|
|
181
|
+
>
|
|
182
|
+
Domain
|
|
183
|
+
</th>
|
|
184
|
+
<th
|
|
185
|
+
class=""
|
|
186
|
+
>
|
|
187
|
+
Status
|
|
188
|
+
</th>
|
|
189
|
+
</tr>
|
|
190
|
+
</thead>
|
|
191
|
+
<tbody
|
|
192
|
+
class=""
|
|
193
|
+
>
|
|
194
|
+
<tr
|
|
195
|
+
class=""
|
|
196
|
+
>
|
|
197
|
+
<td
|
|
198
|
+
class=""
|
|
199
|
+
>
|
|
200
|
+
foo concept
|
|
201
|
+
</td>
|
|
202
|
+
<td
|
|
203
|
+
class=""
|
|
204
|
+
>
|
|
205
|
+
foo domain
|
|
206
|
+
</td>
|
|
207
|
+
<td
|
|
208
|
+
class=""
|
|
209
|
+
>
|
|
210
|
+
<div
|
|
211
|
+
class="ui green label"
|
|
212
|
+
>
|
|
213
|
+
published
|
|
214
|
+
</div>
|
|
215
|
+
</td>
|
|
216
|
+
</tr>
|
|
217
|
+
<tr
|
|
218
|
+
class=""
|
|
219
|
+
>
|
|
220
|
+
<td
|
|
221
|
+
class=""
|
|
222
|
+
>
|
|
223
|
+
bar concept
|
|
224
|
+
</td>
|
|
225
|
+
<td
|
|
226
|
+
class=""
|
|
227
|
+
>
|
|
228
|
+
foo domain
|
|
229
|
+
</td>
|
|
230
|
+
<td
|
|
231
|
+
class=""
|
|
232
|
+
>
|
|
233
|
+
<div
|
|
234
|
+
class="ui olive label"
|
|
235
|
+
>
|
|
236
|
+
draft
|
|
237
|
+
</div>
|
|
238
|
+
</td>
|
|
239
|
+
</tr>
|
|
240
|
+
</tbody>
|
|
241
|
+
</table>
|
|
47
242
|
</div>
|
|
48
243
|
<div
|
|
49
244
|
class="actions"
|
|
50
245
|
>
|
|
51
|
-
<a
|
|
52
|
-
class="ui secondary button"
|
|
53
|
-
href="/"
|
|
54
|
-
role="button"
|
|
55
|
-
>
|
|
56
|
-
cancel
|
|
57
|
-
</a>
|
|
58
246
|
<button
|
|
59
247
|
class="ui primary disabled button"
|
|
60
248
|
disabled=""
|
|
61
249
|
tabindex="-1"
|
|
62
250
|
>
|
|
63
|
-
|
|
251
|
+
Create
|
|
64
252
|
</button>
|
|
253
|
+
<a
|
|
254
|
+
class="ui secondary button"
|
|
255
|
+
href="/"
|
|
256
|
+
role="button"
|
|
257
|
+
>
|
|
258
|
+
Cancel
|
|
259
|
+
</a>
|
|
65
260
|
</div>
|
|
66
261
|
</div>
|
|
67
262
|
</div>
|
|
@@ -1,46 +1,260 @@
|
|
|
1
1
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
2
|
|
|
3
3
|
exports[`<StructureRelationForm /> matches the latest snapshot 1`] = `
|
|
4
|
-
<
|
|
5
|
-
<
|
|
6
|
-
|
|
4
|
+
<div>
|
|
5
|
+
<div
|
|
6
|
+
class="ui grid"
|
|
7
|
+
style=""
|
|
7
8
|
>
|
|
8
|
-
<Connect(RelationTagsLoader) />
|
|
9
|
-
<Header
|
|
10
|
-
as="h4"
|
|
11
|
-
content={
|
|
12
|
-
<Memo(MemoizedFormattedMessage)
|
|
13
|
-
id="structures.relation.new.header"
|
|
14
|
-
/>
|
|
15
|
-
}
|
|
16
|
-
/>
|
|
17
|
-
<lazy
|
|
18
|
-
handleConceptSelected={[Function]}
|
|
19
|
-
loadConcepts={false}
|
|
20
|
-
selectedConcept={null}
|
|
21
|
-
/>
|
|
22
9
|
<div
|
|
23
|
-
|
|
10
|
+
class="sixteen wide column"
|
|
24
11
|
>
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
12
|
+
<h4
|
|
13
|
+
class="ui header"
|
|
14
|
+
>
|
|
15
|
+
Header
|
|
16
|
+
</h4>
|
|
17
|
+
<div
|
|
18
|
+
class="field concept-relation-form"
|
|
19
|
+
>
|
|
20
|
+
<div
|
|
21
|
+
class="field"
|
|
22
|
+
>
|
|
23
|
+
<b>
|
|
24
|
+
<label>
|
|
25
|
+
Relation types
|
|
26
|
+
</label>
|
|
27
|
+
</b>
|
|
28
|
+
<div>
|
|
29
|
+
<div
|
|
30
|
+
aria-expanded="false"
|
|
31
|
+
class="ui selection dropdown concept-link-dropdown"
|
|
32
|
+
role="listbox"
|
|
33
|
+
tabindex="0"
|
|
34
|
+
>
|
|
35
|
+
<i
|
|
36
|
+
aria-hidden="true"
|
|
37
|
+
class="dropdown icon"
|
|
38
|
+
/>
|
|
39
|
+
<div
|
|
40
|
+
class="menu transition"
|
|
41
|
+
>
|
|
42
|
+
<div
|
|
43
|
+
aria-checked="false"
|
|
44
|
+
aria-selected="true"
|
|
45
|
+
class="selected item"
|
|
46
|
+
role="option"
|
|
47
|
+
style="pointer-events: all;"
|
|
48
|
+
>
|
|
49
|
+
<span
|
|
50
|
+
class="text"
|
|
51
|
+
>
|
|
52
|
+
relates_to
|
|
53
|
+
</span>
|
|
54
|
+
</div>
|
|
55
|
+
<div
|
|
56
|
+
aria-checked="false"
|
|
57
|
+
aria-selected="false"
|
|
58
|
+
class="item"
|
|
59
|
+
role="option"
|
|
60
|
+
style="pointer-events: all;"
|
|
61
|
+
>
|
|
62
|
+
<span
|
|
63
|
+
class="text"
|
|
64
|
+
>
|
|
65
|
+
text
|
|
66
|
+
</span>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
<label>
|
|
74
|
+
Related Concept
|
|
75
|
+
</label>
|
|
76
|
+
<div
|
|
77
|
+
class="ui segment"
|
|
78
|
+
>
|
|
79
|
+
<div
|
|
80
|
+
class="ui action left icon input"
|
|
81
|
+
>
|
|
82
|
+
<input
|
|
83
|
+
placeholder="Search"
|
|
84
|
+
type="text"
|
|
85
|
+
value=""
|
|
29
86
|
/>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
as="button"
|
|
34
|
-
content={
|
|
35
|
-
<Memo(MemoizedFormattedMessage)
|
|
36
|
-
id="actions.create"
|
|
87
|
+
<i
|
|
88
|
+
aria-hidden="true"
|
|
89
|
+
class="search link icon"
|
|
37
90
|
/>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
91
|
+
<div
|
|
92
|
+
aria-expanded="false"
|
|
93
|
+
class="ui button floating labeled scrolling dropdown icon"
|
|
94
|
+
role="listbox"
|
|
95
|
+
tabindex="0"
|
|
96
|
+
>
|
|
97
|
+
<div
|
|
98
|
+
aria-atomic="true"
|
|
99
|
+
aria-live="polite"
|
|
100
|
+
class="divider text"
|
|
101
|
+
role="alert"
|
|
102
|
+
>
|
|
103
|
+
Filters
|
|
104
|
+
</div>
|
|
105
|
+
<i
|
|
106
|
+
aria-hidden="true"
|
|
107
|
+
class="filter icon"
|
|
108
|
+
/>
|
|
109
|
+
<div
|
|
110
|
+
class="menu transition"
|
|
111
|
+
>
|
|
112
|
+
<div
|
|
113
|
+
class="item"
|
|
114
|
+
role="option"
|
|
115
|
+
>
|
|
116
|
+
<em>
|
|
117
|
+
(reset filters)
|
|
118
|
+
</em>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
<div
|
|
124
|
+
class="selectedFilters"
|
|
125
|
+
>
|
|
126
|
+
<div
|
|
127
|
+
class="appliedFilters"
|
|
128
|
+
>
|
|
129
|
+
Applied Filters
|
|
130
|
+
</div>
|
|
131
|
+
<div
|
|
132
|
+
aria-expanded="false"
|
|
133
|
+
class="ui floating item scrolling dropdown"
|
|
134
|
+
role="listbox"
|
|
135
|
+
tabindex="0"
|
|
136
|
+
>
|
|
137
|
+
<div
|
|
138
|
+
class="ui label"
|
|
139
|
+
>
|
|
140
|
+
filter
|
|
141
|
+
<i
|
|
142
|
+
aria-hidden="true"
|
|
143
|
+
class="delete icon"
|
|
144
|
+
/>
|
|
145
|
+
</div>
|
|
146
|
+
<div
|
|
147
|
+
class="menu transition dimmable"
|
|
148
|
+
/>
|
|
149
|
+
</div>
|
|
150
|
+
<a
|
|
151
|
+
class="resetFilters"
|
|
152
|
+
>
|
|
153
|
+
Clear Filters
|
|
154
|
+
</a>
|
|
155
|
+
<a
|
|
156
|
+
class="resetFilters"
|
|
157
|
+
>
|
|
158
|
+
Save Filters
|
|
159
|
+
</a>
|
|
160
|
+
</div>
|
|
161
|
+
<table
|
|
162
|
+
class="ui small selectable table"
|
|
163
|
+
>
|
|
164
|
+
<thead
|
|
165
|
+
class=""
|
|
166
|
+
>
|
|
167
|
+
<tr
|
|
168
|
+
class=""
|
|
169
|
+
>
|
|
170
|
+
<th
|
|
171
|
+
class=""
|
|
172
|
+
>
|
|
173
|
+
Name
|
|
174
|
+
</th>
|
|
175
|
+
<th
|
|
176
|
+
class=""
|
|
177
|
+
>
|
|
178
|
+
Domain
|
|
179
|
+
</th>
|
|
180
|
+
<th
|
|
181
|
+
class=""
|
|
182
|
+
>
|
|
183
|
+
Status
|
|
184
|
+
</th>
|
|
185
|
+
</tr>
|
|
186
|
+
</thead>
|
|
187
|
+
<tbody
|
|
188
|
+
class=""
|
|
189
|
+
>
|
|
190
|
+
<tr
|
|
191
|
+
class=""
|
|
192
|
+
>
|
|
193
|
+
<td
|
|
194
|
+
class=""
|
|
195
|
+
>
|
|
196
|
+
foo concept
|
|
197
|
+
</td>
|
|
198
|
+
<td
|
|
199
|
+
class=""
|
|
200
|
+
>
|
|
201
|
+
foo domain
|
|
202
|
+
</td>
|
|
203
|
+
<td
|
|
204
|
+
class=""
|
|
205
|
+
>
|
|
206
|
+
<div
|
|
207
|
+
class="ui green label"
|
|
208
|
+
>
|
|
209
|
+
published
|
|
210
|
+
</div>
|
|
211
|
+
</td>
|
|
212
|
+
</tr>
|
|
213
|
+
<tr
|
|
214
|
+
class=""
|
|
215
|
+
>
|
|
216
|
+
<td
|
|
217
|
+
class=""
|
|
218
|
+
>
|
|
219
|
+
bar concept
|
|
220
|
+
</td>
|
|
221
|
+
<td
|
|
222
|
+
class=""
|
|
223
|
+
>
|
|
224
|
+
foo domain
|
|
225
|
+
</td>
|
|
226
|
+
<td
|
|
227
|
+
class=""
|
|
228
|
+
>
|
|
229
|
+
<div
|
|
230
|
+
class="ui olive label"
|
|
231
|
+
>
|
|
232
|
+
draft
|
|
233
|
+
</div>
|
|
234
|
+
</td>
|
|
235
|
+
</tr>
|
|
236
|
+
</tbody>
|
|
237
|
+
</table>
|
|
238
|
+
</div>
|
|
239
|
+
<div
|
|
240
|
+
class="actions"
|
|
241
|
+
>
|
|
242
|
+
<button
|
|
243
|
+
class="ui primary disabled button"
|
|
244
|
+
disabled=""
|
|
245
|
+
tabindex="-1"
|
|
246
|
+
>
|
|
247
|
+
Create
|
|
248
|
+
</button>
|
|
249
|
+
<a
|
|
250
|
+
class="ui secondary button"
|
|
251
|
+
href="/"
|
|
252
|
+
role="button"
|
|
253
|
+
>
|
|
254
|
+
Cancel
|
|
255
|
+
</a>
|
|
256
|
+
</div>
|
|
43
257
|
</div>
|
|
44
|
-
</
|
|
45
|
-
</
|
|
258
|
+
</div>
|
|
259
|
+
</div>
|
|
46
260
|
`;
|