Skip to content

Commit ee0a38a

Browse files
kpshervaslint
authored andcommitted
custom_fields: add remove discovered field button
* chore: renaming to improve readability
1 parent 4830790 commit ee0a38a

File tree

7 files changed

+114
-51
lines changed

7 files changed

+114
-51
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/forms/widgets/custom_fields/Extensions.js renamed to src/lib/forms/widgets/custom_fields/AddDiscoverableFieldsModal.js

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
// under the terms of the MIT License; see LICENSE file for more details.
77

88
import React, { Component } from "react";
9+
import { RemoveField } from "./RemoveField";
910
import { ListAndFilterCustomFields } from "./ListAndFilterCustomFields";
1011
import { importWidget } from "../loader";
1112

1213
import { Button, Icon, Modal, Divider } from "semantic-ui-react";
1314

1415
import PropTypes from "prop-types";
1516

16-
export class Extensions extends Component {
17+
export class AddDiscoverableFieldsModal extends Component {
1718
constructor(props) {
1819
super(props);
1920
const { existingFields } = props;
@@ -61,20 +62,26 @@ export class Extensions extends Component {
6162
} = this.state;
6263
const { fieldPath, templateLoaders, addFieldCallback } = this.props;
6364
this.setState({ loading: true });
65+
selectedField["props"]["label"] = (
66+
<RemoveField
67+
fieldPath={`${fieldPath}.${selectedField.field}`}
68+
removeFieldCallback={this.handleRemoveField}
69+
field={{ key: `${fieldPath}.${selectedField.field}` }}
70+
label={selectedField.props.label}
71+
/>
72+
);
73+
6474
const field = await importWidget(templateLoaders, {
6575
...selectedField,
6676
fieldPath: `${fieldPath}.${selectedField.field}`,
6777
});
68-
69-
const performCallback = (selectedFieldTarget) => {
78+
const performCallback = () => {
7079
const { addFields } = this.state;
71-
72-
if (withClose) {
73-
addFieldCallback(addFields);
74-
this.setState({ addFields: [], existingFields: [] });
75-
this.handleModalClosed();
76-
}
80+
addFieldCallback(addFields);
81+
this.setState({ addFields: [] });
82+
this.handleModalClosed();
7783
};
84+
7885
selectedFieldTarget.classList.toggle("selected-background");
7986
this.setState(
8087
{
@@ -84,7 +91,7 @@ export class Extensions extends Component {
8491
selectedFieldTarget: undefined,
8592
loading: false,
8693
},
87-
() => performCallback(selectedFieldTarget)
94+
() => (withClose ? performCallback() : null)
8895
);
8996
};
9097

@@ -96,6 +103,13 @@ export class Extensions extends Component {
96103
this.handleModalClosed();
97104
};
98105

106+
handleRemoveField = (field) => {
107+
const { existingFields: prevExisting } = this.state;
108+
const { removeFieldCallback } = this.props;
109+
const updatedFields = prevExisting.filter((n) => field.key !== n);
110+
this.setState({ existingFields: [...updatedFields] });
111+
removeFieldCallback(field);
112+
};
99113
render() {
100114
const {
101115
fieldPath, // injected by the custom field loader via the `field` config property
@@ -104,14 +118,14 @@ export class Extensions extends Component {
104118
record,
105119
templateLoaders,
106120
addFieldCallback,
121+
removeFieldCallback,
107122
sections,
108-
existingFields: selected,
123+
existingFields: _,
109124
...fieldsList
110125
} = this.props;
111-
const { modalOpen, existingFields, loading } = this.state;
126+
const { modalOpen, existingFields, loading, selectedField } = this.state;
112127
return (
113128
<>
114-
<Divider />
115129
<Button icon labelPosition="left" onClick={this.handleModalOpen}>
116130
<Icon name="plus" />
117131
Add field
@@ -137,7 +151,7 @@ export class Extensions extends Component {
137151
icon
138152
labelPosition="left"
139153
onClick={() => this.handleAddField(false)}
140-
disabled={loading}
154+
disabled={loading || !selectedField}
141155
loading={loading}
142156
>
143157
<Icon name="plus" />
@@ -147,7 +161,7 @@ export class Extensions extends Component {
147161
icon
148162
labelPosition="left"
149163
onClick={() => this.handleAddField(true)}
150-
disabled={loading}
164+
disabled={loading || !selectedField}
151165
loading={loading}
152166
>
153167
<Icon name="plus" />
@@ -160,18 +174,19 @@ export class Extensions extends Component {
160174
}
161175
}
162176

163-
Extensions.propTypes = {
177+
AddDiscoverableFieldsModal.propTypes = {
164178
fieldPath: PropTypes.string.isRequired,
165179
record: PropTypes.object.isRequired,
166180
icon: PropTypes.string,
167181
label: PropTypes.string,
168182
templateLoaders: PropTypes.array.isRequired,
169183
addFieldCallback: PropTypes.func.isRequired,
184+
removeFieldCallback: PropTypes.func.isRequired,
170185
sections: PropTypes.array,
171186
existingFields: PropTypes.array.isRequired,
172187
};
173188

174-
Extensions.defaultProps = {
189+
AddDiscoverableFieldsModal.defaultProps = {
175190
icon: undefined,
176191
label: undefined,
177192
sections: undefined,

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

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77

88
import React, { Component } from "react";
99
import PropTypes from "prop-types";
10-
import { ComposeFields } from "./ComposeFields";
10+
import { DiscoverFieldsSection } from "./DiscoverFieldsSection";
1111
import { AccordionField } from "../../AccordionField";
1212
import { loadWidgetsFromConfig } from "../loader";
1313

1414
export class CustomFields extends Component {
1515
constructor(props) {
1616
super(props);
17-
this.state = { sections: undefined, composeSections: undefined };
17+
this.state = { sections: undefined, discoverFieldsSections: undefined };
1818
}
1919

2020
componentDidMount() {
@@ -24,19 +24,22 @@ export class CustomFields extends Component {
2424
populateConfig = async () => {
2525
const { includesPaths, fieldPathPrefix } = this.props;
2626
try {
27-
const { sectionsConfig, composeSectionConfig } =
27+
const { sectionsConfig, discoverFieldsConfig } =
2828
await this.loadCustomFieldsWidgets();
2929
const sections = sectionsConfig.map((sectionCfg) => {
3030
const paths = includesPaths(sectionCfg.fields, fieldPathPrefix);
3131
return { ...sectionCfg, paths };
3232
});
3333

34-
const composeSections = composeSectionConfig.map((sectionCfg) => {
34+
const discoverFieldsSections = discoverFieldsConfig.map((sectionCfg) => {
3535
const paths = includesPaths(sectionCfg.fields, fieldPathPrefix);
3636
return { ...sectionCfg, paths };
3737
});
3838

39-
this.setState({ sections: sections, composeSections: composeSections });
39+
this.setState({
40+
sections: sections,
41+
discoverFieldsSections: discoverFieldsSections,
42+
});
4043
} catch (error) {
4144
console.error("Couldn't load custom fields widgets.", error);
4245
}
@@ -46,7 +49,7 @@ export class CustomFields extends Component {
4649
const { config, fieldPathPrefix, templateLoaders, record } = this.props;
4750

4851
const sections = [];
49-
const composeFieldSections = [];
52+
const discoverFieldsSections = []; // finds sections with discoverable fields
5053
for (const sectionCfg of config) {
5154
// Path to end user's folder defining custom fields ui widgets
5255
const fields = await loadWidgetsFromConfig({
@@ -55,8 +58,8 @@ export class CustomFields extends Component {
5558
fields: sectionCfg.fields,
5659
record: record,
5760
});
58-
if (sectionCfg.compose_fields) {
59-
composeFieldSections.push({
61+
if (sectionCfg.discoverable_fields) {
62+
discoverFieldsSections.push({
6063
...sectionCfg,
6164
fields: fields,
6265
fieldsConfig: sectionCfg.fields,
@@ -65,11 +68,11 @@ export class CustomFields extends Component {
6568
sections.push({ ...sectionCfg, fields });
6669
}
6770
}
68-
return { sectionsConfig: sections, composeSectionConfig: composeFieldSections };
71+
return { sectionsConfig: sections, discoverFieldsConfig: discoverFieldsSections };
6972
}
7073

7174
render() {
72-
const { sections, composeSections } = this.state;
75+
const { sections, discoverFieldsSections } = this.state;
7376
const { templateLoaders, record } = this.props;
7477
return (
7578
<>
@@ -84,10 +87,10 @@ export class CustomFields extends Component {
8487
{fields}
8588
</AccordionField>
8689
))}
87-
{composeSections && composeSections && (
88-
<ComposeFields
90+
{discoverFieldsSections && (
91+
<DiscoverFieldsSection
8992
templateLoaders={templateLoaders}
90-
composeSections={composeSections}
93+
sections={discoverFieldsSections}
9194
record={record}
9295
/>
9396
)}

src/lib/forms/widgets/custom_fields/ComposeFields.js renamed to src/lib/forms/widgets/custom_fields/DiscoverFieldsSection.js

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,22 @@ import PropTypes from "prop-types";
44
import { Divider } from "semantic-ui-react";
55
import { AccordionField } from "../../AccordionField";
66
import { FieldLabel } from "../../FieldLabel";
7-
import { Extensions } from "./Extensions";
7+
import { AddDiscoverableFieldsModal } from "./AddDiscoverableFieldsModal";
8+
import isEmpty from "lodash/isEmpty";
89

9-
export class ComposeFields extends Component {
10+
export class DiscoverFieldsSection extends Component {
1011
constructor(props) {
1112
super(props);
12-
const { composeSections, record } = props;
13-
const filled =
14-
record.custom_fields && typeof record.custom_fields === "object"
15-
? Object.keys(record.custom_fields).map((key) => `custom_fields.${key}`)
16-
: [];
17-
this.state = { sections: composeSections, tempFields: [], recordFields: filled };
18-
this.fieldsCfg = this.getFieldsConfig(composeSections);
19-
this.sectionsList = composeSections.map((section) => section.section);
13+
const { sections, record } = props; // sections = fields grouping, usually by domain
14+
console.warn(props);
15+
let filled = [];
16+
if (record && !isEmpty(record.custom_fields)) {
17+
filled = Object.keys(record.custom_fields).map((key) => `custom_fields.${key}`);
18+
}
19+
20+
this.state = { sections: sections, tempFields: [], recordFields: filled };
21+
this.fieldsCfg = this.getFieldsConfig(sections);
22+
this.sectionsList = sections.map((section) => section.section);
2023
}
2124

2225
getFieldsConfig = (sectionCfg) => {
@@ -32,12 +35,8 @@ export class ComposeFields extends Component {
3235
};
3336

3437
getFieldsWithValues = (sectionFields) => {
35-
const { record } = this.props;
3638
const { tempFields, recordFields } = this.state;
3739
const filledFields = [];
38-
if (!record.custom_fields) {
39-
return [];
40-
}
4140
for (const field of sectionFields) {
4241
if (recordFields.includes(field.key) || tempFields.includes(field)) {
4342
filledFields.push(field);
@@ -75,6 +74,23 @@ export class ComposeFields extends Component {
7574
});
7675
};
7776

77+
removeFieldCallback = (field) => {
78+
const { sections: prevSections, tempFields: prevTempFields } = this.state;
79+
const sections = [...prevSections];
80+
let tempFields = [...prevTempFields];
81+
const sectionToUpdate = this.getSectionOfField(field);
82+
for (const section of sections) {
83+
if (section.section === sectionToUpdate) {
84+
section["fields"] = section.fields.filter((n) => field.key !== n.key);
85+
tempFields = tempFields.filter((n) => field.key !== n.key);
86+
}
87+
}
88+
this.setState({
89+
sections: [...sections],
90+
tempFields: [...tempFields],
91+
});
92+
};
93+
7894
render() {
7995
const { templateLoaders, record } = this.props;
8096
const { sections, tempFields, recordFields } = this.state;
@@ -84,7 +100,7 @@ export class ComposeFields extends Component {
84100
];
85101

86102
return (
87-
<AccordionField key="compose fields" label="Domain specific fields" active>
103+
<AccordionField key="discover-fields" label="Domain specific fields" active>
88104
{sections.map(({ fields, paths, ...sectionConfig }) => {
89105
const recordCustomFields = this.getFieldsWithValues(fields);
90106
if (_isEmpty(recordCustomFields)) {
@@ -102,11 +118,12 @@ export class ComposeFields extends Component {
102118
</div>
103119
);
104120
})}
105-
<Extensions
121+
<AddDiscoverableFieldsModal
106122
fieldPath="custom_fields"
107123
{...this.fieldsCfg}
108124
templateLoaders={templateLoaders}
109125
addFieldCallback={this.addFieldCallback}
126+
removeFieldCallback={this.removeFieldCallback}
110127
sections={this.sectionsList}
111128
record={record}
112129
existingFields={existingFields}
@@ -116,8 +133,8 @@ export class ComposeFields extends Component {
116133
}
117134
}
118135

119-
ComposeFields.propTypes = {
136+
DiscoverFieldsSection.propTypes = {
120137
templateLoaders: PropTypes.array.isRequired,
121-
composeSections: PropTypes.array.isRequired,
138+
sections: PropTypes.array.isRequired,
122139
record: PropTypes.object.isRequired,
123140
};

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ export class ListAndFilterCustomFields extends Component {
9999
<Item.Group divided relaxed>
100100
{Object.entries(filteredFieldsList).map(([key, value]) => {
101101
const names = key.split(":");
102-
103102
const isDisabled = alreadyAddedFields.includes(`${fieldPath}.${key}`);
104103

105104
return (
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React, { Component } from "react";
2+
import PropTypes from "prop-types";
3+
import { Button, Icon, Popup } from "semantic-ui-react";
4+
import { FieldLabel } from "../../FieldLabel";
5+
6+
export class RemoveField extends Component {
7+
render() {
8+
const { removeFieldCallback, fieldPath, field, label } = this.props;
9+
return (
10+
<>
11+
<FieldLabel htmlFor={fieldPath} label={label} className="mr-10" />
12+
<Popup
13+
content="Remove empty fields from the form"
14+
trigger={
15+
<Button icon size="mini" onClick={() => removeFieldCallback(field)}>
16+
<Icon name="trash alternate outline" />
17+
</Button>
18+
}
19+
/>
20+
</>
21+
);
22+
}
23+
}
24+
25+
RemoveField.propTypes = {
26+
field: PropTypes.object.isRequired,
27+
fieldPath: PropTypes.string.isRequired,
28+
label: PropTypes.string.isRequired,
29+
removeFieldCallback: PropTypes.func.isRequired,
30+
};
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
export { CustomFields } from "./CustomFields";
2-
export { Extensions } from "./Extensions";

0 commit comments

Comments
 (0)