Skip to content

Commit e27a4d1

Browse files
committed
custom_fields: add filtering and search on compose fields
1 parent de9aac9 commit e27a4d1

File tree

3 files changed

+179
-72
lines changed

3 files changed

+179
-72
lines changed

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ export class ComposeFields extends Component {
1111
const { composeSections } = this.props;
1212

1313
this.state = { sections: composeSections, tempFields: [] };
14+
this.fieldsCfg = this.getFieldsConfig(composeSections);
15+
this.sectionsList = composeSections.map((section) => section.section);
1416
}
1517

1618
getFieldsConfig = (sectionCfg) => {
@@ -57,7 +59,9 @@ export class ComposeFields extends Component {
5759
const sectionToUpdate = this.getSectionOfField(field);
5860
for (const section of sections) {
5961
if (section.section === sectionToUpdate) {
60-
section["fields"] = [...section.fields, field];
62+
section["fields"] = [...section.fields, field].sort((a, b) =>
63+
a.key.localeCompare(b.key)
64+
);
6165
}
6266
}
6367
this.setState({ sections: [...sections], tempFields: [...prevTempFields, field] });
@@ -67,7 +71,6 @@ export class ComposeFields extends Component {
6771
const { templateLoaders, record } = this.props;
6872
const { sections } = this.state;
6973

70-
const fields = this.getFieldsConfig(sections);
7174
return (
7275
<AccordionField key="compose fields" label="Domain specific fields" active>
7376
{sections.map(({ fields, paths, ...sectionConfig }) => (
@@ -83,9 +86,10 @@ export class ComposeFields extends Component {
8386
))}
8487
<Extensions
8588
fieldPath="custom_fields"
86-
{...fields}
89+
{...this.fieldsCfg}
8790
templateLoaders={templateLoaders}
8891
addFieldCallback={this.addFieldCallback}
92+
sections={this.sectionsList}
8993
record={record}
9094
/>
9195
</AccordionField>

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

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

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

11-
import {
12-
Button,
13-
Icon,
14-
Modal,
15-
Item,
16-
Divider,
17-
Label,
18-
Grid,
19-
Segment,
20-
} from "semantic-ui-react";
12+
import { Button, Icon, Modal, Divider } from "semantic-ui-react";
2113

2214
import PropTypes from "prop-types";
2315

@@ -31,7 +23,6 @@ export class Extensions extends Component {
3123
fields: [],
3224
};
3325
}
34-
3526
handleModalOpen = () => {
3627
this.setState({ modalOpen: true });
3728
};
@@ -69,8 +60,8 @@ export class Extensions extends Component {
6960
if (withClose) {
7061
this.handleModalClosed();
7162
}
63+
this.setState({ selectedField: undefined, selectedFieldTarget: undefined });
7264
addFieldCallback(field);
73-
console.log(`${fieldPath}.${selectedField.field}`);
7465
};
7566

7667
render() {
@@ -81,10 +72,10 @@ export class Extensions extends Component {
8172
record,
8273
templateLoaders,
8374
addFieldCallback,
75+
sections,
8476
...fieldsList
8577
} = this.props;
8678
const { modalOpen, fields } = this.state;
87-
console.warn(fieldsList, "---------------%%%%%%%%%%%%%%%%%%");
8879

8980
return (
9081
<>
@@ -95,60 +86,13 @@ export class Extensions extends Component {
9586
</Button>
9687
<Modal open={modalOpen}>
9788
<Modal.Header>Add domain specific fields</Modal.Header>
98-
<Segment as={Modal.Content} attached="bottom ml-0">
99-
test
100-
</Segment>
101-
<Modal.Content scrolling>
102-
<Item.Group divided relaxed>
103-
{Object.entries(fieldsList).map(([key, value]) => {
104-
const names = key.split(":");
105-
const isDisabled = fields
106-
.map((field) => field.key)
107-
.includes(`${fieldPath}.${key}`);
108-
109-
return (
110-
<Item
111-
key={key}
112-
className={
113-
isDisabled ? "pr-10 pl-10 disabled" : "clickable pr-10 pl-10"
114-
}
115-
fieldName={key}
116-
field={fieldsList[key]}
117-
onClick={(e) =>
118-
!isDisabled ? this.handleSelectField(e, key, value) : {}
119-
}
120-
>
121-
<Item.Content>
122-
<Item.Header className={isDisabled ? "text-muted mb-5" : "mb-5"}>
123-
{value.label}
124-
</Item.Header>
125-
<Item.Description>
126-
<Grid>
127-
<Grid.Column width={12}>{value.note}</Grid.Column>
128-
</Grid>
129-
</Item.Description>
130-
<Item.Extra>
131-
<Label>
132-
<Icon name={value.section.icon} />
133-
{value.section.section}: {names[0]}
134-
</Label>
135-
{value.multiple_values === true && (
136-
<Label basic>
137-
<Icon name="list ol" /> Multiple value field
138-
</Label>
139-
)}
140-
{value.type === "text" && (
141-
<Label basic>
142-
<Icon name="text cursor" /> Text field
143-
</Label>
144-
)}
145-
</Item.Extra>
146-
</Item.Content>
147-
</Item>
148-
);
149-
})}
150-
</Item.Group>
151-
</Modal.Content>
89+
<ListAndFilterCustomFields
90+
fieldPath={fieldPath}
91+
handleSelectField={this.handleSelectField}
92+
alreadyAddedFields={fields}
93+
fieldsList={fieldsList}
94+
sections={sections}
95+
/>
15296
<Modal.Actions>
15397
<Button
15498
onClick={this.handleModalClosed}
@@ -157,11 +101,11 @@ export class Extensions extends Component {
157101
labelPosition="left"
158102
content="Cancel"
159103
/>
160-
<Button icon labelPosition="left">
104+
<Button icon labelPosition="left" onClick={this.handleAddField}>
161105
<Icon name="plus" />
162106
Add field and continue
163107
</Button>
164-
<Button onClick={() => this.handleAddField(true)}>
108+
<Button icon labelPosition="left" onClick={() => this.handleAddField(true)}>
165109
<Icon name="plus" />
166110
Add field and close
167111
</Button>
@@ -179,9 +123,11 @@ Extensions.propTypes = {
179123
label: PropTypes.string,
180124
templateLoaders: PropTypes.array.isRequired,
181125
addFieldCallback: PropTypes.func.isRequired,
126+
sections: PropTypes.array,
182127
};
183128

184129
Extensions.defaultProps = {
185130
icon: undefined,
186131
label: undefined,
132+
sections: undefined,
187133
};
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
import React, { Component } from "react";
2+
import PropTypes from "prop-types";
3+
import {
4+
Dropdown,
5+
Grid,
6+
Icon,
7+
Input,
8+
Item,
9+
Label,
10+
List,
11+
Modal,
12+
Segment,
13+
} from "semantic-ui-react";
14+
15+
export class ListAndFilterCustomFields extends Component {
16+
constructor(props) {
17+
super(props);
18+
const { fieldsList } = props;
19+
this.state = { filteredFieldsList: fieldsList };
20+
}
21+
22+
resetFilter = () => {
23+
const { fieldsList } = this.props;
24+
this.setState({ filteredFieldsList: fieldsList });
25+
};
26+
handleSearch = (e, { value }) => {
27+
const { fieldsList } = this.props;
28+
if (value) {
29+
const filteredResults = Object.fromEntries(
30+
Object.entries(fieldsList).filter(([key, val]) => {
31+
return val.label.toLowerCase().includes(value.toLowerCase());
32+
})
33+
);
34+
35+
this.setState({ filteredFieldsList: filteredResults });
36+
} else {
37+
this.resetFilter();
38+
}
39+
};
40+
41+
handleDomainFilter = (e, { value }) => {
42+
const { fieldsList } = this.props;
43+
if (value) {
44+
const filteredResults = Object.fromEntries(
45+
Object.entries(fieldsList).filter(([key, val]) => val.section.section === value)
46+
);
47+
48+
this.setState({ filteredFieldsList: filteredResults });
49+
} else {
50+
this.resetFilter();
51+
}
52+
};
53+
54+
render() {
55+
const { filteredFieldsList } = this.state;
56+
const { alreadyAddedFields, fieldPath, handleSelectField, sections } = this.props;
57+
const dropdownOptions = sections.map((section) => ({
58+
key: section,
59+
text: section,
60+
value: section,
61+
}));
62+
63+
return (
64+
<>
65+
<Segment as={Modal.Content} attached="bottom ml-0">
66+
<Grid>
67+
<Grid.Column width={10}>
68+
<Input
69+
fluid
70+
icon="search"
71+
placeholder="Search..."
72+
onChange={this.handleSearch}
73+
/>
74+
</Grid.Column>
75+
<Grid.Column width={6}>
76+
<span className="flex align-items-center">
77+
in:{" "}
78+
<Dropdown
79+
className="ml-5"
80+
fluid
81+
inline
82+
clearable
83+
selection
84+
placeholder="All domains"
85+
options={dropdownOptions}
86+
onChange={this.handleDomainFilter}
87+
/>
88+
</span>
89+
</Grid.Column>
90+
</Grid>
91+
</Segment>
92+
<Modal.Content scrolling>
93+
<Item.Group divided relaxed>
94+
{Object.entries(filteredFieldsList).map(([key, value]) => {
95+
const names = key.split(":");
96+
97+
const isDisabled = alreadyAddedFields
98+
.map((field) => field.key)
99+
.includes(`${fieldPath}.${key}`);
100+
101+
return (
102+
<Item
103+
key={key}
104+
className={
105+
isDisabled ? "pr-10 pl-10 disabled" : "clickable pr-10 pl-10"
106+
}
107+
fieldName={key}
108+
field={filteredFieldsList[key]}
109+
onClick={(e) => (!isDisabled ? handleSelectField(e, key, value) : {})}
110+
>
111+
<Item.Content>
112+
<Item.Header className={isDisabled ? "text-muted mb-5" : "mb-5"}>
113+
{value.label}
114+
</Item.Header>
115+
<Item.Description>
116+
<Grid>
117+
<Grid.Column width={12}>{value.note}</Grid.Column>
118+
</Grid>
119+
</Item.Description>
120+
<Item.Extra>
121+
<Label>
122+
<Icon name={value.section.icon} />
123+
{value.section.section}: {names[0]}
124+
</Label>
125+
{value.multiple_values === true && (
126+
<Label basic>
127+
<Icon name="list ol" /> Multiple value field
128+
</Label>
129+
)}
130+
{value.type === "text" && (
131+
<Label basic>
132+
<Icon name="text cursor" /> Text field
133+
</Label>
134+
)}
135+
</Item.Extra>
136+
</Item.Content>
137+
</Item>
138+
);
139+
})}{" "}
140+
</Item.Group>
141+
</Modal.Content>
142+
</>
143+
);
144+
}
145+
}
146+
147+
ListAndFilterCustomFields.propTypes = {
148+
alreadyAddedFields: PropTypes.array.isRequired,
149+
fieldsList: PropTypes.array.isRequired,
150+
fieldPath: PropTypes.string.isRequired,
151+
handleSelectField: PropTypes.func.isRequired,
152+
sections: PropTypes.array,
153+
};
154+
155+
ListAndFilterCustomFields.defaultProps = {
156+
sections: undefined,
157+
};

0 commit comments

Comments
 (0)