@truedat/bg 4.48.9 → 4.48.12

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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.48.12] 2022-07-22
4
+
5
+ ### Changed
6
+
7
+ - [TD-3584] Allow longer domain descriptions
8
+
9
+ ## [4.48.10] 2022-07-19
10
+
11
+ ### Added
12
+
13
+ - [TD-4975] Structures tab in Domain's view
14
+
3
15
  ## [4.48.4] 2022-07-11
4
16
 
5
17
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/bg",
3
- "version": "4.48.9",
3
+ "version": "4.48.12",
4
4
  "description": "Truedat Web Business Glossary",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -86,8 +86,8 @@
86
86
  ]
87
87
  },
88
88
  "dependencies": {
89
- "@truedat/core": "4.48.9",
90
- "@truedat/df": "4.48.9",
89
+ "@truedat/core": "4.48.12",
90
+ "@truedat/df": "4.48.12",
91
91
  "file-saver": "^2.0.5",
92
92
  "moment": "^2.24.0",
93
93
  "path-to-regexp": "^1.7.0",
@@ -107,5 +107,5 @@
107
107
  "react-dom": ">= 16.8.6 < 17",
108
108
  "semantic-ui-react": ">= 0.88.2 < 2.1"
109
109
  },
110
- "gitHead": "82d6ab8fb0b3000bf4b8975670d3e5cf15b14487"
110
+ "gitHead": "4a36e50c99882caf8be2d2d59e13e4fde1759302"
111
111
  }
@@ -8,15 +8,17 @@ import {
8
8
  DOMAIN,
9
9
  DOMAIN_CONCEPTS,
10
10
  DOMAIN_MEMBERS,
11
+ DOMAIN_STRUCTURES,
11
12
  linkTo,
12
13
  } from "@truedat/core/routes";
13
14
  import DomainConcepts from "../../concepts/components/DomainConcepts";
14
15
  import DomainActions from "./DomainActions";
15
- import DomainCrumbs from "./DomainCrumbs";
16
16
  import DomainCards from "./DomainCards";
17
+ import DomainCrumbs from "./DomainCrumbs";
17
18
  import DomainDetail from "./DomainDetail";
18
19
  import DomainMembers from "./DomainMembers";
19
20
  import DomainSearch from "./DomainSearch";
21
+ import DomainStructures from "./DomainStructures";
20
22
  import DomainTabs from "./DomainTabs";
21
23
 
22
24
  export const Domain = ({ hasChildren, domain, domainLoading }) => {
@@ -58,6 +60,11 @@ export const Domain = ({ hasChildren, domain, domainLoading }) => {
58
60
  render={() => <DomainConcepts />}
59
61
  exact
60
62
  />
63
+ <Route
64
+ path={DOMAIN_STRUCTURES}
65
+ render={() => <DomainStructures />}
66
+ exact
67
+ />
61
68
  </Switch>
62
69
  </Segment>
63
70
  </Segment>
@@ -1,261 +1,242 @@
1
1
  import _ from "lodash/fp";
2
2
  import React from "react";
3
3
  import PropTypes from "prop-types";
4
- import {
5
- Accordion,
6
- Button,
7
- Form,
8
- Icon,
9
- Label,
10
- Segment
11
- } from "semantic-ui-react";
12
- import { compose } from "redux";
4
+ import { Button, Form } from "semantic-ui-react";
13
5
  import { connect } from "react-redux";
14
- import { injectIntl } from "react-intl";
6
+ import { useIntl } from "react-intl";
7
+ import { useForm, Controller } from "react-hook-form";
15
8
  import { HistoryBackButton } from "@truedat/core/components";
9
+ import { accentInsensitiveOrder } from "@truedat/core/services/sort";
16
10
  import {
17
11
  getDomainGroups,
18
12
  getDomainTypes,
19
- domainParentOptionsSelector
13
+ domainParentOptionsSelector,
20
14
  } from "../selectors";
21
15
 
22
16
  const toOption = (t, i) => ({ key: i, text: t, value: t });
23
17
 
24
- const domainStringOptions = (collection, value) =>
18
+ const buildOptions = (collection, value) =>
25
19
  _.flow(
26
20
  _.concat(value),
27
21
  _.filter(_.isString),
28
22
  _.uniq,
29
- _.sortBy(_.lowerCase),
23
+ _.sortBy(accentInsensitiveOrder),
30
24
  _.map.convert({ cap: false })(toOption)
31
25
  )(collection);
32
26
 
33
- export class DomainForm extends React.Component {
34
- static propTypes = {
35
- domain: PropTypes.object,
36
- isSubmitting: PropTypes.bool,
37
- domainGroups: PropTypes.array,
38
- domainParentOptions: PropTypes.array,
39
- domainTypes: PropTypes.array,
40
- handleSubmit: PropTypes.func.isRequired,
41
- intl: PropTypes.object
42
- };
43
-
44
- constructor(props) {
45
- super(props);
46
- const defaults = {
47
- description: "",
48
- external_id: "",
49
- name: "",
50
- parent_id: null,
51
- type: "",
52
- domain_group: null
53
- };
54
-
55
- const domain_group = _.path("domain.domain_group.name")(props);
56
- const domain = Object.assign({}, defaults, {
57
- ...(props.domain || {}),
58
- domain_group
59
- });
60
- const touched = false;
61
- this.state = {
62
- domain,
63
- touched,
64
- default_group: _.path("domain.domain_group")(props)
65
- };
66
- this.handleChange = this.handleChange.bind(this);
67
- this.handleSubmit = this.handleSubmit.bind(this);
68
- }
69
-
70
- handleChange(event, data) {
71
- const { name, value } = data;
72
- const domain = Object.assign({}, this.state.domain, { [name]: value });
73
- this.setState({ domain, touched: true });
74
- event.preventDefault();
75
- }
76
-
77
- handleSelectionClick = () => {
78
- const { activeSelection } = this.state;
79
- this.setState({ activeSelection: !activeSelection });
80
- };
81
-
82
- handleSubmit(event) {
83
- const { domain } = this.state;
84
- this.props.handleSubmit({ domain });
85
- event.preventDefault();
86
- }
87
-
88
- validForm() {
89
- const { domain } = this.state;
90
- return _.flow(
91
- _.pick(["name", "external_id", "description"]),
92
- _.toPairs,
93
- _.every(([, v]) => _.negate(_.isEmpty)(v) && _.negate(_.isNil)(v))
94
- )(domain);
95
- }
27
+ const DEFAULTS = {
28
+ description: "",
29
+ external_id: "",
30
+ name: "",
31
+ parent_id: null,
32
+ type: "",
33
+ domain_group: null,
34
+ };
96
35
 
97
- clearableGroup() {
98
- const { default_group } = this.state;
99
- return _.isNil(default_group) || _.prop("status")(default_group) == "root";
100
- }
36
+ export const DomainForm = ({
37
+ domain = {},
38
+ isSubmitting,
39
+ domainGroups,
40
+ domainParentOptions,
41
+ domainTypes,
42
+ onSubmit,
43
+ }) => {
44
+ const { formatMessage } = useIntl();
45
+ // const domainGroup = domain?.domain_group;
46
+ const { handleSubmit, control, formState, watch } = useForm({
47
+ mode: "all",
48
+ defaultValues: {
49
+ ...DEFAULTS,
50
+ ...domain,
51
+ domain_group: domain?.domain_group?.name || null,
52
+ },
53
+ });
54
+ const [group, type] = watch(["domain_group", "type"]);
55
+ const domainGroupOptions = buildOptions(domainGroups, group);
56
+ const domainTypeOptions = buildOptions(domainTypes, type);
57
+ const groupClearable =
58
+ domain?.domain_group?.status === "root" || !domain?.domain_group;
101
59
 
102
- clearGroup() {
103
- const { domain } = this.state;
104
- this.setState({
105
- ...this.state,
106
- domain: { ...domain, domain_group: null },
107
- touched: true
108
- });
109
- }
110
- render() {
111
- const {
112
- isSubmitting,
113
- domainGroups,
114
- domainTypes,
115
- domainParentOptions,
116
- intl
117
- } = this.props;
118
- const { formatMessage } = intl;
119
- const { activeSelection, domain } = this.state;
120
- return (
121
- <Form onSubmit={this.handleSubmit}>
122
- <Form.Input
123
- name="name"
124
- label={formatMessage({ id: "domain.props.name" })}
125
- onChange={this.handleChange}
126
- value={domain.name}
127
- placeholder={formatMessage({ id: "domain.props.name.placeholder" })}
128
- autoComplete="off"
129
- required
130
- />
131
- <Form.Input
132
- name="external_id"
133
- label={formatMessage({ id: "domain.props.external_id" })}
134
- onChange={this.handleChange}
135
- value={domain.external_id || ""}
136
- placeholder={formatMessage({
137
- id: "domain.props.external_id.placeholder"
138
- })}
139
- autoComplete="off"
140
- required
60
+ const { errors, isDirty, isValid } = formState;
61
+ return (
62
+ <Form onSubmit={handleSubmit(onSubmit)}>
63
+ <Controller
64
+ control={control}
65
+ name="name"
66
+ rules={{
67
+ required: formatMessage(
68
+ { id: "form.validation.required" },
69
+ { prop: formatMessage({ id: "domain.props.name" }) }
70
+ ),
71
+ }}
72
+ render={({ field: { onBlur, onChange, value } }) => (
73
+ <Form.Input
74
+ id="name"
75
+ autoComplete="off"
76
+ error={errors?.name?.message}
77
+ label={{
78
+ children: formatMessage({ id: "domain.props.name" }),
79
+ htmlFor: "name",
80
+ }}
81
+ name="name"
82
+ onBlur={onBlur}
83
+ onChange={(_e, { value }) => onChange(value)}
84
+ placeholder={formatMessage({ id: "domain.props.name.placeholder" })}
85
+ required
86
+ value={value}
87
+ />
88
+ )}
89
+ />
90
+ <Controller
91
+ control={control}
92
+ name="external_id"
93
+ rules={{
94
+ required: formatMessage(
95
+ { id: "form.validation.required" },
96
+ { prop: formatMessage({ id: "domain.props.external_id" }) }
97
+ ),
98
+ }}
99
+ render={({ field: { onBlur, onChange, value } }) => (
100
+ <Form.Input
101
+ id="external_id"
102
+ autoComplete="off"
103
+ error={errors?.external_id?.message}
104
+ label={{
105
+ children: formatMessage({ id: "domain.props.external_id" }),
106
+ htmlFor: "external_id",
107
+ }}
108
+ name="external_id"
109
+ onBlur={onBlur}
110
+ onChange={(_e, { value }) => onChange(value)}
111
+ placeholder={formatMessage({
112
+ id: "domain.props.external_id.placeholder",
113
+ })}
114
+ required
115
+ value={value}
116
+ />
117
+ )}
118
+ />
119
+ {_.isEmpty(domainParentOptions) ? null : (
120
+ <Controller
121
+ control={control}
122
+ name="parent_id"
123
+ render={({ field: { onBlur, onChange, value } }) => (
124
+ <Form.Dropdown
125
+ name="parent_id"
126
+ label={formatMessage({ id: "domain.props.parent" })}
127
+ basic
128
+ search
129
+ selection
130
+ clearable
131
+ options={domainParentOptions}
132
+ onBlur={onBlur}
133
+ onChange={(_e, { value }) => onChange(value)}
134
+ placeholder={formatMessage({ id: "domain.selector.placeholder" })}
135
+ value={value || ""}
136
+ />
137
+ )}
141
138
  />
142
- {!_.isEmpty(domainParentOptions) && (
139
+ )}
140
+ <Controller
141
+ control={control}
142
+ name="domain_group"
143
+ render={({ field: { onBlur, onChange, value } }) => (
143
144
  <Form.Dropdown
144
- name="parent_id"
145
- label={formatMessage({ id: "domain.props.parent" })}
145
+ name="domain_group"
146
+ label={formatMessage({ id: "domain.props.domain_group" })}
146
147
  basic
147
- clearable
148
- onChange={this.handleChange}
149
- value={domain.parent_id}
150
- placeholder={formatMessage({ id: "domain.selector.placeholder" })}
151
- options={domainParentOptions}
152
148
  search
153
149
  selection
150
+ clearable={groupClearable}
151
+ options={domainGroupOptions}
152
+ onBlur={onBlur}
153
+ onChange={(_e, { value }) => onChange(value)}
154
+ placeholder={formatMessage({
155
+ id: "domain.props.domain_group.placeholder",
156
+ })}
157
+ value={value || ""}
158
+ allowAdditions
159
+ additionLabel={
160
+ <i style={{ color: "red" }}>
161
+ {formatMessage({ id: "domain.label.domain_group" })}
162
+ </i>
163
+ }
154
164
  />
155
165
  )}
156
- <Segment>
157
- <Form.Group inline>
158
- <label>{formatMessage({ id: "domain.props.domain_group" })}</label>
159
- {_.prop("domain_group")(domain) && (
160
- <Label size={"medium"}>
161
- {_.flow(
162
- _.prop("domain_group"),
163
- _.truncate({ length: 90 })
164
- )(domain)}
165
- {this.clearableGroup() && (
166
- <Icon name="delete" onClick={() => this.clearGroup()} />
167
- )}
168
- </Label>
169
- )}
170
- </Form.Group>
171
- <Accordion>
172
- <Accordion.Title
173
- active={activeSelection}
174
- onClick={this.handleSelectionClick}
175
- >
176
- <Icon name="dropdown" />
177
- {formatMessage({ id: "domain.domain_group.select" })}{" "}
178
- </Accordion.Title>
179
-
180
- <Accordion.Content active={activeSelection}>
181
- <Form.Dropdown
182
- name="domain_group"
183
- label={formatMessage({ id: "domain.props.domain_group" })}
184
- basic
185
- clearable={this.clearableGroup()}
186
- onChange={this.handleChange}
187
- value={domain.domain_group || ""}
188
- placeholder={formatMessage({
189
- id: "domain.props.domain_group.placeholder"
190
- })}
191
- options={domainStringOptions(domainGroups, domain.domain_group)}
192
- search
193
- selection
194
- allowAdditions
195
- onAddItem={this.handleAddItem}
196
- additionLabel={
197
- <i style={{ color: "red" }}>
198
- {formatMessage({
199
- id: "domain.label.domain_group"
200
- })}
201
- </i>
202
- }
203
- />
204
- </Accordion.Content>
205
- </Accordion>
206
- </Segment>
207
- <Form.Dropdown
208
- name="type"
209
- label={formatMessage({ id: "domain.props.type" })}
210
- basic
211
- clearable
212
- onChange={this.handleChange}
213
- value={domain.type}
214
- placeholder={formatMessage({ id: "domain.props.type.placeholder" })}
215
- options={domainStringOptions(domainTypes, domain.type)}
216
- search
217
- selection
218
- allowAdditions
219
- onAddItem={this.handleAddItem}
220
- additionLabel={<i style={{ color: "red" }}>New Domain Type: </i>}
221
- />
222
- <Form.TextArea
223
- name="description"
224
- label={formatMessage({ id: "domain.props.description" })}
225
- onChange={this.handleChange}
226
- value={domain.description}
227
- placeholder={formatMessage({
228
- id: "domain.props.description.placeholder"
229
- })}
230
- autoComplete="off"
231
- maxLength={255}
232
- required
233
- />
234
- <div className="actions">
235
- <HistoryBackButton
236
- content={formatMessage({ id: "actions.cancel" })}
237
- disabled={isSubmitting}
166
+ />
167
+ <Controller
168
+ control={control}
169
+ name="type"
170
+ render={({ field: { onBlur, onChange, value } }) => (
171
+ <Form.Dropdown
172
+ name="type"
173
+ label={formatMessage({ id: "domain.props.type" })}
174
+ basic
175
+ search
176
+ selection
177
+ clearable
178
+ options={domainTypeOptions}
179
+ onBlur={onBlur}
180
+ onChange={(_e, { value }) => onChange(value)}
181
+ placeholder={formatMessage({ id: "domain.props.type.placeholder" })}
182
+ value={value || ""}
183
+ allowAdditions
184
+ additionLabel={<i style={{ color: "red" }}>New Domain Type: </i>}
238
185
  />
239
- <Button
240
- type="submit"
241
- primary
242
- loading={isSubmitting}
243
- disabled={isSubmitting || !this.state.touched || !this.validForm()}
244
- content={formatMessage({ id: "actions.save" })}
186
+ )}
187
+ />
188
+ <Controller
189
+ control={control}
190
+ name="description"
191
+ render={({ field: { onBlur, onChange, value } }) => (
192
+ <Form.TextArea
193
+ autoComplete="off"
194
+ error={errors?.description?.message}
195
+ label={formatMessage({ id: "domain.props.description" })}
196
+ name="description"
197
+ onBlur={onBlur}
198
+ onChange={(_e, { value }) => onChange(value)}
199
+ placeholder={formatMessage({
200
+ id: "domain.props.description.placeholder",
201
+ })}
202
+ value={value}
245
203
  />
246
- </div>
247
- </Form>
248
- );
249
- }
250
- }
204
+ )}
205
+ />
206
+ <div className="actions">
207
+ <Button
208
+ floated="right"
209
+ type="submit"
210
+ primary
211
+ loading={isSubmitting}
212
+ disabled={isSubmitting || !isDirty || !isValid}
213
+ content={formatMessage({ id: "actions.save" })}
214
+ />
215
+ <HistoryBackButton
216
+ content={formatMessage({ id: "actions.cancel" })}
217
+ disabled={isSubmitting}
218
+ />
219
+ </div>
220
+ </Form>
221
+ );
222
+ };
223
+
224
+ DomainForm.propTypes = {
225
+ domain: PropTypes.object,
226
+ isSubmitting: PropTypes.bool,
227
+ domainGroups: PropTypes.array,
228
+ domainParentOptions: PropTypes.array,
229
+ domainTypes: PropTypes.array,
230
+ onSubmit: PropTypes.func.isRequired,
231
+ };
251
232
 
252
233
  const mapStateToProps = (state, ownProps) => ({
253
234
  domainTypes: getDomainTypes(state),
254
235
  domainGroups: getDomainGroups(state),
255
- domainParentOptions: _.path("domain.id")(ownProps)
236
+ domainParentOptions: ownProps.domain?.id
256
237
  ? domainParentOptionsSelector(state)
257
238
  : [],
258
- isSubmitting: state.domainCreating || state.domainUpdating
239
+ isSubmitting: state.domainCreating || state.domainUpdating,
259
240
  });
260
241
 
261
- export default compose(injectIntl, connect(mapStateToProps))(DomainForm);
242
+ export default connect(mapStateToProps)(DomainForm);
@@ -12,6 +12,7 @@ import {
12
12
  DOMAIN_MEMBERS,
13
13
  DOMAIN_MEMBERS_NEW,
14
14
  DOMAIN_NEW,
15
+ DOMAIN_STRUCTURES,
15
16
  } from "@truedat/core/routes";
16
17
  import AddDomainMember from "./AddMember";
17
18
  import Domain from "./Domain";
@@ -26,6 +27,28 @@ const RolesLoader = React.lazy(() =>
26
27
  import("@truedat/auth/roles/components/RolesLoader")
27
28
  );
28
29
 
30
+ const DomainRoutes = () => (
31
+ <>
32
+ <Route component={DomainLoader} />
33
+ <Route component={DomainMembersLoader} />
34
+ <Route exact path={DOMAIN} component={Domain} />
35
+ <Route exact path={DOMAIN_CONCEPTS} component={Domain} />
36
+ <Route exact path={DOMAIN_STRUCTURES} component={Domain} />
37
+ <Route exact path={DOMAIN_MEMBERS} component={Domain} />
38
+ <Route exact path={DOMAIN_EDIT} render={() => <EditDomain />} />
39
+ <Route exact path={DOMAIN_NEW} component={NewDomain} />
40
+ <Route
41
+ path={DOMAIN_MEMBERS_NEW}
42
+ render={() => (
43
+ <>
44
+ <Route component={RolesLoader} />
45
+ <Route path={DOMAIN_MEMBERS_NEW} component={AddDomainMember} exact />
46
+ </>
47
+ )}
48
+ />
49
+ </>
50
+ );
51
+
29
52
  const AuthorizedRoutes = () => (
30
53
  <>
31
54
  <Route component={DomainsLoader} />
@@ -33,38 +56,12 @@ const AuthorizedRoutes = () => (
33
56
  <Switch>
34
57
  <Route path={DOMAINS_SEARCH} component={Domains} exact />
35
58
  <Route path={DOMAINS_NEW} component={NewDomain} exact />
36
- <Route
37
- path={DOMAIN}
38
- render={() => (
39
- <>
40
- <Route component={DomainLoader} />
41
- <Route component={DomainMembersLoader} />
42
- <Route path={DOMAIN} component={Domain} exact />
43
- <Route path={DOMAIN_CONCEPTS} component={Domain} exact />
44
- <Route path={DOMAIN_MEMBERS} component={Domain} exact />
45
- <Route path={DOMAIN_EDIT} component={EditDomain} exact />
46
- <Route path={DOMAIN_NEW} component={NewDomain} exact />
47
- <Route
48
- path={DOMAIN_MEMBERS_NEW}
49
- render={() => (
50
- <>
51
- <Route component={RolesLoader} />
52
- <Route
53
- path={DOMAIN_MEMBERS_NEW}
54
- component={AddDomainMember}
55
- exact
56
- />
57
- </>
58
- )}
59
- />
60
- </>
61
- )}
62
- />
59
+ <Route path={DOMAIN} render={() => <DomainRoutes />} />
63
60
  </Switch>
64
61
  </>
65
62
  );
66
63
 
67
- const DomainRoutes = () => {
64
+ const DomainsRoutes = () => {
68
65
  const authorized = useAuthorized(["taxonomy", "taxonomy_membership"]);
69
66
  return (
70
67
  <Route
@@ -74,4 +71,4 @@ const DomainRoutes = () => {
74
71
  );
75
72
  };
76
73
 
77
- export default DomainRoutes;
74
+ export default DomainsRoutes;
@@ -0,0 +1,27 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import { connect } from "react-redux";
4
+ import StructureFiltersLoader from "@truedat/dd/components/StructureFiltersLoader";
5
+ import StructuresLoader from "@truedat/dd/components/StructuresLoader";
6
+ import StructuresView from "@truedat/dd/components/StructuresView";
7
+
8
+ export const DomainStructures = ({ domain = {} }) => {
9
+ const defaultFilters = {
10
+ taxonomy: [domain.id],
11
+ };
12
+ return (
13
+ <>
14
+ <StructureFiltersLoader defaultFilters={defaultFilters} />
15
+ <StructuresLoader defaultFilters={defaultFilters} />
16
+ <StructuresView embedded />
17
+ </>
18
+ );
19
+ };
20
+
21
+ DomainStructures.propTypes = {
22
+ domain: PropTypes.object.isRequired,
23
+ };
24
+
25
+ export const mapStateToProps = ({ domain }) => ({ domain });
26
+
27
+ export default connect(mapStateToProps)(DomainStructures);
@@ -10,6 +10,7 @@ import {
10
10
  DOMAIN,
11
11
  DOMAIN_CONCEPTS,
12
12
  DOMAIN_MEMBERS,
13
+ DOMAIN_STRUCTURES,
13
14
  linkTo,
14
15
  } from "@truedat/core/routes";
15
16
 
@@ -42,6 +43,15 @@ const DomainTabs = ({ domain }) => {
42
43
  >
43
44
  <FormattedMessage id="tabs.concepts" />
44
45
  </Menu.Item>
46
+
47
+ <Menu.Item
48
+ active={path === DOMAIN_STRUCTURES}
49
+ as={Link}
50
+ to={linkTo.DOMAIN_STRUCTURES({ id })}
51
+ replace
52
+ >
53
+ <FormattedMessage id="tabs.structures" />
54
+ </Menu.Item>
45
55
  </Menu>
46
56
  );
47
57
  };