Skip to content

Commit c54c43c

Browse files
Satyapzrq
authored andcommitted
COMPASS-221: DDL: Update Create Index Modal to Match new Designs (#558)
* COMPASS-221 changed heading for field options * COMPASS-221 rough implementation of designs * Quick style fixes * COMPASS-221 mostly done, may need some css clean up * COMPASS-221 added some extra actions * COMPASS-221 implemented add create index from store to ui * COMPASS-221 implemented updating field name and type * COMPASS-221 set initial state for fields * COMPASS-221 implemented remove index field * COMPASS-221 added some error cases * COMPASS-221 clean up a few files after refactoring * COMPASS-221 added some test cases * validation of index fields, button styling * fix index store test. * COMPASS-221 disable fields that are already used * Added bottom margins for each row, truncate long field names in the dropdown, make highlight red same hex as error message * COMPASS-221 made some minor fixes after review
1 parent c768775 commit c54c43c

File tree

8 files changed

+338
-168
lines changed

8 files changed

+338
-168
lines changed

src/internal-packages/indexes/lib/action/index-actions.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ const IndexActions = Reflux.createActions([
77
'loadIndexes',
88
'sortIndexes',
99
'triggerIndexCreation',
10-
'updateField',
1110
'updateOption',
12-
'updateStatus'
11+
'updateStatus',
12+
'addIndexField',
13+
'updateFieldName',
14+
'updateFieldType',
15+
'removeIndexField'
1316
]);
1417

1518
module.exports = IndexActions;

src/internal-packages/indexes/lib/component/create-index-button.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ class CreateIndexButton extends React.Component {
4848
className="btn btn-default btn-sm"
4949
type="button"
5050
onClick={this.clickCreateHandler.bind(this)}>
51-
Add Index
51+
Create Index
5252
</button>
5353
<CreateIndexModal
5454
open={this.state.showModal}

src/internal-packages/indexes/lib/component/create-index-field.jsx

Lines changed: 92 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,73 +2,114 @@ const React = require('react');
22
const ButtonToolbar = require('react-bootstrap').ButtonToolbar;
33
const DropdownButton = require('react-bootstrap').DropdownButton;
44
const MenuItem = require('react-bootstrap').MenuItem;
5+
const StatusStore = require('../store/ddl-status-store');
56
const Action = require('../action/index-actions');
67

8+
// const debug = require('debug')('mongodb-compass:indexes:create-index-field');
9+
710
/**
811
* Current allowed types for indexes.
912
*/
1013
const INDEX_TYPES = ['1 (asc)', '-1 (desc)', '2dsphere'];
1114

15+
/**
16+
* Default values for field name and type as presented in the UI
17+
*/
18+
const DEFAULT_FIELD = {
19+
name: 'Select a field name',
20+
type: 'Select a type'
21+
};
22+
1223
/**
1324
* Component for the index field form.
1425
*/
1526
class CreateIndexField extends React.Component {
1627

17-
/**
18-
* The component constructor.
19-
*
20-
* @param {Object} props - The properties.
21-
*/
2228
constructor(props) {
2329
super(props);
2430
this.state = {
25-
// default titles shown in dropdown
26-
field: 'Add a Field',
27-
type: '1 (asc)'
31+
hasStartedValidating: false,
32+
isNameValid: true,
33+
isTypeValid: true
2834
};
2935
}
3036

37+
componentDidMount() {
38+
this._unsubscribeStatusStore = StatusStore.listen(this.statusChanged.bind(this));
39+
}
40+
41+
componentWillReceiveProps() {
42+
this.validate(false);
43+
}
44+
45+
componentWillUnmount() {
46+
this._unsubscribeStatusStore();
47+
}
48+
3149
/**
32-
* Create React dropdown items for each element in the given array.
33-
*
34-
* @param {Array} arr - The array of options.
50+
* Create React dropdown items for each element in the fields array.
3551
*
3652
* @returns {Array} The React components for each item in the field and type dropdowns.
3753
*/
38-
getDropdownOptions(arr) {
39-
return arr.map((elem, index) => (<MenuItem key={index} eventKey={elem}>{elem}</MenuItem>));
54+
getDropdownFields() {
55+
return this.props.fields.map((elem, index) => (
56+
<MenuItem key={index}
57+
disabled={this.props.disabledFields.some(field => (field === elem))}
58+
eventKey={elem}>{elem}
59+
</MenuItem>));
4060
}
4161

4262
/**
43-
* Set state to selected field on field change.
63+
* Create React dropdown items for each element in the INDEX_TYPES array.
4464
*
45-
* @param {string} field - The selected field.
65+
* @returns {Array} The React components for each item in the field and type dropdowns.
4666
*/
47-
handleFieldSelect(field) {
48-
this.setState({field: field});
67+
getDropdownTypes() {
68+
return INDEX_TYPES.map((elem, index) => (<MenuItem key={index} eventKey={elem}>{elem}</MenuItem>));
4969
}
5070

5171
/**
52-
* Fire add field action to add field and type to add index form.
72+
* Set state to selected field on field change.
5373
*
54-
* @param {Object} evt - The click event.
74+
* @param {string} name - The selected name.
5575
*/
56-
handleSubmit(evt) {
57-
evt.preventDefault();
58-
evt.stopPropagation();
59-
if (this.state.field !== 'Add a Field') {
60-
Action.updateField(this.state.field, this.state.type, 'add');
61-
this.setState({field: 'Add a Field', type: '1 (asc)'});
62-
}
76+
selectName(name) {
77+
Action.updateFieldName(this.props.idx, name);
6378
}
6479

6580
/**
6681
* Set state to selected type on type change.
6782
*
6883
* @param {string} type - The selected type.
6984
*/
70-
handleTypeSelect(type) {
71-
this.setState({type: type});
85+
selectType(type) {
86+
Action.updateFieldType(this.props.idx, type);
87+
}
88+
89+
/**
90+
* Remove this index field
91+
*
92+
* @param {object} evt The click event.
93+
*/
94+
remove(evt) {
95+
evt.preventDefault();
96+
evt.stopPropagation();
97+
Action.removeIndexField(this.props.idx);
98+
}
99+
100+
statusChanged() {
101+
this.validate(true);
102+
}
103+
104+
validate(force) {
105+
if (!force && !this.state.hasStartedValidating) {
106+
return;
107+
}
108+
this.setState({
109+
hasStartedValidating: true,
110+
isTypeValid: this.props.field.type !== '',
111+
isNameValid: this.props.field.name !== ''
112+
});
72113
}
73114

74115
/**
@@ -77,35 +118,41 @@ class CreateIndexField extends React.Component {
77118
* @returns {React.Component} The index field form.
78119
*/
79120
render() {
121+
const fieldName = this.props.field.name || DEFAULT_FIELD.name;
122+
const fieldType = this.props.field.type || DEFAULT_FIELD.type;
123+
124+
const hasNameError = this.state.isNameValid ? '' : 'has-error';
125+
const hasTypeError = this.state.isTypeValid ? '' : 'has-error';
126+
80127
return (
81128
<div className="form-inline row create-index-field">
82129
<div className="col-md-6">
83130
<ButtonToolbar>
84131
<DropdownButton
85-
title={this.state.field}
132+
title={fieldName}
86133
id="field-name-select-dropdown"
87-
className="create-index-field-dropdown-name"
88-
onSelect={this.handleFieldSelect.bind(this)}>
89-
{this.getDropdownOptions(this.props.fields)}
134+
className={`create-index-field-dropdown-name ${hasNameError}`}
135+
onSelect={this.selectName.bind(this)}>
136+
{this.getDropdownFields(this.props.fields)}
90137
</DropdownButton>
91138
</ButtonToolbar>
92139
</div>
93140
<div className="col-md-4">
94141
<ButtonToolbar>
95142
<DropdownButton
96-
title={this.state.type}
143+
title={fieldType}
97144
id="field-type-select-dropdown"
98-
className="create-index-field-dropdown-type"
99-
onSelect={this.handleTypeSelect.bind(this)}>
100-
{this.getDropdownOptions(INDEX_TYPES)}
145+
className={`create-index-field-dropdown-type ${hasTypeError}`}
146+
onSelect={this.selectType.bind(this)}>
147+
{this.getDropdownTypes(INDEX_TYPES)}
101148
</DropdownButton>
102149
</ButtonToolbar>
103150
</div>
104151
<div className="col-md-2">
105-
<button
106-
onClick={this.handleSubmit.bind(this)}
107-
className="btn btn-success btn-circle create-index-field-button">
108-
<i className="fa fa-plus" aria-hidden="true"></i>
152+
<button disabled={this.props.isRemovable}
153+
className="btn btn-success btn-circle"
154+
onClick={this.remove.bind(this)}>
155+
<i className="fa fa-minus" aria-hidden="true"></i>
109156
</button>
110157
</div>
111158
</div>
@@ -116,7 +163,11 @@ class CreateIndexField extends React.Component {
116163
CreateIndexField.displayName = 'CreateIndexField';
117164

118165
CreateIndexField.propTypes = {
119-
fields: React.PropTypes.array.isRequired
166+
fields: React.PropTypes.array.isRequired,
167+
field: React.PropTypes.object.isRequired,
168+
idx: React.PropTypes.number.isRequired,
169+
disabledFields: React.PropTypes.array.isRequired,
170+
isRemovable: React.PropTypes.bool.isRequired
120171
};
121172

122173
module.exports = CreateIndexField;

src/internal-packages/indexes/lib/component/create-index-modal.jsx

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,12 @@ const React = require('react');
33
const Modal = require('react-bootstrap').Modal;
44
const CreateIndexStore = require('../store/create-index-store');
55
const DDLStatusStore = require('../store/ddl-status-store');
6-
const SelectedIndexField = require('./selected-index-field');
76
const CreateIndexCheckbox = require('./create-index-checkbox');
87
const CreateIndexField = require('./create-index-field');
98
const CreateIndexTextField = require('./create-index-text-field');
109
const OptionsToggleBar = require('./options-toggle-bar');
1110
const Action = require('../action/index-actions');
12-
13-
// const debug = require('debug')('mongodb-compass:ddl:index');
11+
const _ = require('lodash');
1412

1513
/**
1614
* The index options and parameters to display.
@@ -98,11 +96,22 @@ class CreateIndexModal extends React.Component {
9896
*
9997
* @returns {Array} The React components for each field, or null if none are selected.
10098
*/
101-
getSelectedFields() {
99+
getIndexFields() {
102100
if (!this.state.fields.length) {
103101
return null;
104102
}
105-
return this.state.fields.map((field, idx) => <SelectedIndexField key={idx} field={field} />);
103+
104+
const disabledFields = _.pluck(this.state.fields, 'name');
105+
106+
return this.state.fields.map((field, idx) => {
107+
return (<CreateIndexField
108+
fields={this.state.schemaFields}
109+
key={idx}
110+
idx={idx}
111+
field={field}
112+
disabledFields={disabledFields}
113+
isRemovable={!(this.state.fields.length > 1)} />);
114+
});
106115
}
107116

108117
/**
@@ -171,6 +180,17 @@ class CreateIndexModal extends React.Component {
171180
this.setState({showOptions: !this.state.showOptions});
172181
}
173182

183+
/**
184+
* Fire add field action to add field and type to add index form.
185+
*
186+
* @param {Object} evt - The click event.
187+
*/
188+
handleSubmit(evt) {
189+
evt.preventDefault();
190+
evt.stopPropagation();
191+
Action.addIndexField();
192+
}
193+
174194
/**
175195
* Render the create and cancel buttons.
176196
*
@@ -210,7 +230,7 @@ class CreateIndexModal extends React.Component {
210230

211231
<div className="create-index-modal-content">
212232
<Modal.Header>
213-
<Modal.Title>Index Create</Modal.Title>
233+
<Modal.Title>Create Index</Modal.Title>
214234
</Modal.Header>
215235

216236
<Modal.Body>
@@ -221,10 +241,16 @@ class CreateIndexModal extends React.Component {
221241
option={'name'} />
222242

223243
<div className="create-index-fields">
224-
<p className="create-index-description">Add fields and types</p>
225-
<CreateIndexField
226-
fields={this.state.schemaFields} />
227-
{this.getSelectedFields()}
244+
<p className="create-index-description">Configure the index definition</p>
245+
{this.getIndexFields()}
246+
247+
<div>
248+
<button
249+
onClick={this.handleSubmit.bind(this)}
250+
className="create-index-field-add btn btn-sm btn-block btn-success">
251+
Add another field
252+
</button>
253+
</div>
228254
</div>
229255

230256
<OptionsToggleBar

src/internal-packages/indexes/lib/component/selected-index-field.jsx

Lines changed: 0 additions & 66 deletions
This file was deleted.

0 commit comments

Comments
 (0)