Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/internal-packages/indexes/lib/action/index-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ const IndexActions = Reflux.createActions([
'loadIndexes',
'sortIndexes',
'triggerIndexCreation',
'updateField',
'updateOption',
'updateStatus'
'updateStatus',
'addIndexField',
'updateFieldName',
'updateFieldType',
'removeIndexField'
]);

module.exports = IndexActions;
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class CreateIndexButton extends React.Component {
className="btn btn-default btn-sm"
type="button"
onClick={this.clickCreateHandler.bind(this)}>
Add Index
Create Index
</button>
<CreateIndexModal
open={this.state.showModal}
Expand Down
133 changes: 92 additions & 41 deletions src/internal-packages/indexes/lib/component/create-index-field.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,73 +2,114 @@ const React = require('react');
const ButtonToolbar = require('react-bootstrap').ButtonToolbar;
const DropdownButton = require('react-bootstrap').DropdownButton;
const MenuItem = require('react-bootstrap').MenuItem;
const StatusStore = require('../store/ddl-status-store');
const Action = require('../action/index-actions');

// const debug = require('debug')('mongodb-compass:indexes:create-index-field');

/**
* Current allowed types for indexes.
*/
const INDEX_TYPES = ['1 (asc)', '-1 (desc)', '2dsphere'];

/**
* Default values for field name and type as presented in the UI
*/
const DEFAULT_FIELD = {
name: 'Select a field name',
type: 'Select a type'
};

/**
* Component for the index field form.
*/
class CreateIndexField extends React.Component {

/**
* The component constructor.
*
* @param {Object} props - The properties.
*/
constructor(props) {
super(props);
this.state = {
// default titles shown in dropdown
field: 'Add a Field',
type: '1 (asc)'
hasStartedValidating: false,
isNameValid: true,
isTypeValid: true
};
}

componentDidMount() {
this._unsubscribeStatusStore = StatusStore.listen(this.statusChanged.bind(this));
}

componentWillReceiveProps() {
this.validate(false);
}

componentWillUnmount() {
this._unsubscribeStatusStore();
}

/**
* Create React dropdown items for each element in the given array.
*
* @param {Array} arr - The array of options.
* Create React dropdown items for each element in the fields array.
*
* @returns {Array} The React components for each item in the field and type dropdowns.
*/
getDropdownOptions(arr) {
return arr.map((elem, index) => (<MenuItem key={index} eventKey={elem}>{elem}</MenuItem>));
getDropdownFields() {
return this.props.fields.map((elem, index) => (
<MenuItem key={index}
disabled={this.props.disabledFields.some(field => (field === elem))}
eventKey={elem}>{elem}
</MenuItem>));
}

/**
* Set state to selected field on field change.
* Create React dropdown items for each element in the INDEX_TYPES array.
*
* @param {string} field - The selected field.
* @returns {Array} The React components for each item in the field and type dropdowns.
*/
handleFieldSelect(field) {
this.setState({field: field});
getDropdownTypes() {
return INDEX_TYPES.map((elem, index) => (<MenuItem key={index} eventKey={elem}>{elem}</MenuItem>));
}

/**
* Fire add field action to add field and type to add index form.
* Set state to selected field on field change.
*
* @param {Object} evt - The click event.
* @param {string} name - The selected name.
*/
handleSubmit(evt) {
evt.preventDefault();
evt.stopPropagation();
if (this.state.field !== 'Add a Field') {
Action.updateField(this.state.field, this.state.type, 'add');
this.setState({field: 'Add a Field', type: '1 (asc)'});
}
selectName(name) {
Action.updateFieldName(this.props.idx, name);
}

/**
* Set state to selected type on type change.
*
* @param {string} type - The selected type.
*/
handleTypeSelect(type) {
this.setState({type: type});
selectType(type) {
Action.updateFieldType(this.props.idx, type);
}

/**
* Remove this index field
*
* @param {object} evt The click event.
*/
remove(evt) {
evt.preventDefault();
evt.stopPropagation();
Action.removeIndexField(this.props.idx);
}

statusChanged() {
this.validate(true);
}

validate(force) {
if (!force && !this.state.hasStartedValidating) {
return;
}
this.setState({
hasStartedValidating: true,
isTypeValid: this.props.field.type !== '',
isNameValid: this.props.field.name !== ''
});
}

/**
Expand All @@ -77,35 +118,41 @@ class CreateIndexField extends React.Component {
* @returns {React.Component} The index field form.
*/
render() {
const fieldName = this.props.field.name || DEFAULT_FIELD.name;
const fieldType = this.props.field.type || DEFAULT_FIELD.type;

const hasNameError = this.state.isNameValid ? '' : 'has-error';
const hasTypeError = this.state.isTypeValid ? '' : 'has-error';

return (
<div className="form-inline row create-index-field">
<div className="col-md-6">
<ButtonToolbar>
<DropdownButton
title={this.state.field}
title={fieldName}
id="field-name-select-dropdown"
className="create-index-field-dropdown-name"
onSelect={this.handleFieldSelect.bind(this)}>
{this.getDropdownOptions(this.props.fields)}
className={`create-index-field-dropdown-name ${hasNameError}`}
onSelect={this.selectName.bind(this)}>
{this.getDropdownFields(this.props.fields)}
</DropdownButton>
</ButtonToolbar>
</div>
<div className="col-md-4">
<ButtonToolbar>
<DropdownButton
title={this.state.type}
title={fieldType}
id="field-type-select-dropdown"
className="create-index-field-dropdown-type"
onSelect={this.handleTypeSelect.bind(this)}>
{this.getDropdownOptions(INDEX_TYPES)}
className={`create-index-field-dropdown-type ${hasTypeError}`}
onSelect={this.selectType.bind(this)}>
{this.getDropdownTypes(INDEX_TYPES)}
</DropdownButton>
</ButtonToolbar>
</div>
<div className="col-md-2">
<button
onClick={this.handleSubmit.bind(this)}
className="btn btn-success btn-circle create-index-field-button">
<i className="fa fa-plus" aria-hidden="true"></i>
<button disabled={this.props.isRemovable}
className="btn btn-success btn-circle"
onClick={this.remove.bind(this)}>
<i className="fa fa-minus" aria-hidden="true"></i>
</button>
</div>
</div>
Expand All @@ -116,7 +163,11 @@ class CreateIndexField extends React.Component {
CreateIndexField.displayName = 'CreateIndexField';

CreateIndexField.propTypes = {
fields: React.PropTypes.array.isRequired
fields: React.PropTypes.array.isRequired,
field: React.PropTypes.object.isRequired,
idx: React.PropTypes.number.isRequired,
disabledFields: React.PropTypes.array.isRequired,
isRemovable: React.PropTypes.bool.isRequired
};

module.exports = CreateIndexField;
46 changes: 36 additions & 10 deletions src/internal-packages/indexes/lib/component/create-index-modal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@ const React = require('react');
const Modal = require('react-bootstrap').Modal;
const CreateIndexStore = require('../store/create-index-store');
const DDLStatusStore = require('../store/ddl-status-store');
const SelectedIndexField = require('./selected-index-field');
const CreateIndexCheckbox = require('./create-index-checkbox');
const CreateIndexField = require('./create-index-field');
const CreateIndexTextField = require('./create-index-text-field');
const OptionsToggleBar = require('./options-toggle-bar');
const Action = require('../action/index-actions');

// const debug = require('debug')('mongodb-compass:ddl:index');
const _ = require('lodash');

/**
* The index options and parameters to display.
Expand Down Expand Up @@ -98,11 +96,22 @@ class CreateIndexModal extends React.Component {
*
* @returns {Array} The React components for each field, or null if none are selected.
*/
getSelectedFields() {
getIndexFields() {
if (!this.state.fields.length) {
return null;
}
return this.state.fields.map((field, idx) => <SelectedIndexField key={idx} field={field} />);

const disabledFields = _.pluck(this.state.fields, 'name');

return this.state.fields.map((field, idx) => {
return (<CreateIndexField
fields={this.state.schemaFields}
key={idx}
idx={idx}
field={field}
disabledFields={disabledFields}
isRemovable={!(this.state.fields.length > 1)} />);
});
}

/**
Expand Down Expand Up @@ -171,6 +180,17 @@ class CreateIndexModal extends React.Component {
this.setState({showOptions: !this.state.showOptions});
}

/**
* Fire add field action to add field and type to add index form.
*
* @param {Object} evt - The click event.
*/
handleSubmit(evt) {
evt.preventDefault();
evt.stopPropagation();
Action.addIndexField();
}

/**
* Render the create and cancel buttons.
*
Expand Down Expand Up @@ -210,7 +230,7 @@ class CreateIndexModal extends React.Component {

<div className="create-index-modal-content">
<Modal.Header>
<Modal.Title>Index Create</Modal.Title>
<Modal.Title>Create Index</Modal.Title>
</Modal.Header>

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

<div className="create-index-fields">
<p className="create-index-description">Add fields and types</p>
<CreateIndexField
fields={this.state.schemaFields} />
{this.getSelectedFields()}
<p className="create-index-description">Configure the index definition</p>
{this.getIndexFields()}

<div>
<button
onClick={this.handleSubmit.bind(this)}
className="create-index-field-add btn btn-sm btn-block btn-success">
Add another field
</button>
</div>
</div>

<OptionsToggleBar
Expand Down

This file was deleted.

Loading