Skip to content

Commit de9aac9

Browse files
committed
custom_fields: compose fields from given list
1 parent c607c1a commit de9aac9

File tree

5 files changed

+352
-24
lines changed

5 files changed

+352
-24
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import React, { Component } from "react";
2+
import PropTypes from "prop-types";
3+
import { Divider } from "semantic-ui-react";
4+
import { AccordionField } from "../../AccordionField";
5+
import { FieldLabel } from "../../FieldLabel";
6+
import { Extensions } from "./Extensions";
7+
8+
export class ComposeFields extends Component {
9+
constructor(props) {
10+
super(props);
11+
const { composeSections } = this.props;
12+
13+
this.state = { sections: composeSections, tempFields: [] };
14+
}
15+
16+
getFieldsConfig = (sectionCfg) => {
17+
const cfg = {};
18+
for (const section of sectionCfg) {
19+
for (const fieldCfg of section.fieldsConfig) {
20+
const { field, props, ui_widget, ...otherCfg } = fieldCfg;
21+
cfg[field] = { ui_widget: ui_widget, section: section, ...props, ...otherCfg };
22+
}
23+
}
24+
25+
return cfg;
26+
};
27+
28+
getFieldsWithValues = (sectionFields) => {
29+
const { record } = this.props;
30+
const { tempFields } = this.state;
31+
const filledFields = [];
32+
for (const field of sectionFields) {
33+
if (
34+
Object.keys(record.custom_fields).includes(
35+
field.key.replace("custom_fields.", "")
36+
) ||
37+
tempFields.includes(field)
38+
) {
39+
filledFields.push(field);
40+
}
41+
}
42+
return filledFields;
43+
};
44+
45+
getSectionOfField = (field) => {
46+
const { sections } = this.state;
47+
for (const section of sections) {
48+
if (section.fields.map((field) => field.key).includes(field.key)) {
49+
return section.section;
50+
}
51+
}
52+
};
53+
54+
addFieldCallback = (field) => {
55+
const { sections: prevSections, tempFields: prevTempFields } = this.state;
56+
const sections = [...prevSections];
57+
const sectionToUpdate = this.getSectionOfField(field);
58+
for (const section of sections) {
59+
if (section.section === sectionToUpdate) {
60+
section["fields"] = [...section.fields, field];
61+
}
62+
}
63+
this.setState({ sections: [...sections], tempFields: [...prevTempFields, field] });
64+
};
65+
66+
render() {
67+
const { templateLoaders, record } = this.props;
68+
const { sections } = this.state;
69+
70+
const fields = this.getFieldsConfig(sections);
71+
return (
72+
<AccordionField key="compose fields" label="Domain specific fields" active>
73+
{sections.map(({ fields, paths, ...sectionConfig }) => (
74+
<div key={sectionConfig.section} className="rel-mb-2">
75+
<FieldLabel
76+
htmlFor={sectionConfig.section}
77+
icon={sectionConfig.icon}
78+
label={sectionConfig.section}
79+
/>
80+
<Divider fitted className="rel-mb-1" />
81+
<div className="rel-ml-1">{this.getFieldsWithValues(fields)}</div>
82+
</div>
83+
))}
84+
<Extensions
85+
fieldPath="custom_fields"
86+
{...fields}
87+
templateLoaders={templateLoaders}
88+
addFieldCallback={this.addFieldCallback}
89+
record={record}
90+
/>
91+
</AccordionField>
92+
);
93+
}
94+
}
95+
96+
ComposeFields.propTypes = {
97+
templateLoaders: PropTypes.array.isRequired,
98+
composeSections: PropTypes.array.isRequired,
99+
record: PropTypes.object.isRequired,
100+
};

src/lib/forms/widgets/custom_fields/CustomFields.js

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,54 +7,90 @@
77

88
import React, { Component } from "react";
99
import PropTypes from "prop-types";
10+
import { ComposeFields } from "./ComposeFields";
1011
import { AccordionField } from "../../AccordionField";
1112
import { loadWidgetsFromConfig } from "../loader";
1213

1314
export class CustomFields extends Component {
14-
state = { sections: [] };
15+
constructor(props) {
16+
super(props);
17+
this.state = { sections: undefined, composeSections: undefined };
18+
}
1519

1620
componentDidMount() {
21+
this.populateConfig();
22+
}
23+
24+
populateConfig = async () => {
1725
const { includesPaths, fieldPathPrefix } = this.props;
18-
// use of `Promise.then()` as eslint is giving an error when calling setState() directly
19-
// in the componentDidMount() method
20-
this.loadCustomFieldsWidgets()
21-
.then((sections) => {
22-
sections = sections.map((sectionCfg) => {
23-
const paths = includesPaths(sectionCfg.fields, fieldPathPrefix);
24-
return { ...sectionCfg, paths };
25-
});
26-
this.setState({ sections });
27-
})
28-
.catch((error) => {
29-
console.error("Couldn't load custom fields widgets.", error);
26+
try {
27+
const { sectionsConfig, composeSectionConfig } =
28+
await this.loadCustomFieldsWidgets();
29+
const sections = sectionsConfig.map((sectionCfg) => {
30+
const paths = includesPaths(sectionCfg.fields, fieldPathPrefix);
31+
return { ...sectionCfg, paths };
3032
});
31-
}
33+
34+
const composeSections = composeSectionConfig.map((sectionCfg) => {
35+
const paths = includesPaths(sectionCfg.fields, fieldPathPrefix);
36+
return { ...sectionCfg, paths };
37+
});
38+
39+
this.setState({ sections: sections, composeSections: composeSections });
40+
} catch (error) {
41+
console.error("Couldn't load custom fields widgets.", error);
42+
}
43+
};
3244

3345
async loadCustomFieldsWidgets() {
34-
const { config, fieldPathPrefix, templateLoaders } = this.props;
46+
const { config, fieldPathPrefix, templateLoaders, record } = this.props;
3547

3648
const sections = [];
49+
const composeFieldSections = [];
3750
for (const sectionCfg of config) {
3851
// Path to end user's folder defining custom fields ui widgets
3952
const fields = await loadWidgetsFromConfig({
4053
templateLoaders: templateLoaders,
4154
fieldPathPrefix: fieldPathPrefix,
4255
fields: sectionCfg.fields,
56+
record: record,
4357
});
44-
sections.push({ ...sectionCfg, fields });
58+
if (sectionCfg.compose_fields) {
59+
composeFieldSections.push({
60+
...sectionCfg,
61+
fields: fields,
62+
fieldsConfig: sectionCfg.fields,
63+
});
64+
} else {
65+
sections.push({ ...sectionCfg, fields });
66+
}
4567
}
46-
return sections;
68+
return { sectionsConfig: sections, composeSectionConfig: composeFieldSections };
4769
}
4870

4971
render() {
50-
const { sections } = this.state;
72+
const { sections, composeSections } = this.state;
73+
const { templateLoaders, record } = this.props;
5174
return (
5275
<>
53-
{sections.map(({ section, fields, paths }) => (
54-
<AccordionField key={section} includesPaths={paths} label={section} active>
55-
{fields}
56-
</AccordionField>
57-
))}
76+
{sections &&
77+
sections.map(({ fields, paths, ...sectionConfig }) => (
78+
<AccordionField
79+
key={sectionConfig.section}
80+
includesPaths={paths}
81+
label={sectionConfig.section}
82+
active
83+
>
84+
{fields}
85+
</AccordionField>
86+
))}
87+
{composeSections && composeSections && (
88+
<ComposeFields
89+
templateLoaders={templateLoaders}
90+
composeSections={composeSections}
91+
record={record}
92+
/>
93+
)}
5894
</>
5995
);
6096
}
@@ -76,6 +112,7 @@ CustomFields.propTypes = {
76112
templateLoaders: PropTypes.array.isRequired,
77113
fieldPathPrefix: PropTypes.string.isRequired,
78114
includesPaths: PropTypes.func,
115+
record: PropTypes.object.isRequired,
79116
};
80117

81118
CustomFields.defaultProps = {

0 commit comments

Comments
 (0)