blob: 2d1a2cc46429b4879e059a2b734133400c85b943 [file] [log] [blame]
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import app from '../../../../app';
import FauxtonAPI from '../../../../core/api';
import ReactComponents from '../../../components/react-components';
import DesignDocSelector from './DesignDocSelector';
import ReduceEditor from './ReduceEditor';
const getDocUrl = app.helpers.getDocUrl;
const {CodeEditorPanel, ConfirmButton, LoadLines} = ReactComponents;
export default class IndexEditor extends Component {
constructor(props) {
super(props);
this.saveView = this.saveView.bind(this);
this.viewChange = this.viewChange.bind(this);
this.updateMapCode = this.updateMapCode.bind(this);
}
// the code editor is a standalone component, so if the user goes from one edit view page to another, we need to
// force an update of the editor panel
componentDidUpdate(prevProps) {
if (this.props.map !== prevProps.map && this.mapEditor) {
this.mapEditor.update();
}
}
isPartitionedView() {
if (this.props.designDocId === 'new-doc') {
return this.props.newDesignDocPartitioned;
}
return this.props.designDocPartitioned;
}
isCustomReduceSupported() {
if (this.props.isDbPartitioned && this.props.reduce && !this.props.reduce.startsWith('_')) {
const isDDocPartitioned = this.props.designDocId === 'new-doc' ? this.props.newDesignDocPartitioned : this.props.designDocPartitioned;
return isDDocPartitioned ? false : true;
}
return true;
}
saveView(el) {
el.preventDefault();
if (!this.designDocSelector.validate()) {
return;
}
if (!this.isCustomReduceSupported()) {
FauxtonAPI.addNotification({
msg: 'Partitioned views do not support custom reduce functions.',
type: 'error',
clear: true
});
return;
}
const encodedPartKey = this.isPartitionedView() && this.props.partitionKey ? encodeURIComponent(this.props.partitionKey) : '';
const url = FauxtonAPI.urls('view', 'showView', this.props.database.safeID(), encodedPartKey,
this.props.saveDesignDoc.safeID(), encodeURIComponent(this.props.viewName));
this.props.saveView({
database: this.props.database,
isNewView: this.props.isNewView,
viewName: this.props.viewName,
designDoc: this.props.saveDesignDoc,
designDocId: this.props.designDocId,
isNewDesignDoc: this.props.isNewDesignDoc,
originalViewName: this.props.originalViewName,
originalDesignDocName: this.props.originalDesignDocName,
map: this.mapEditor.getValue(),
reduce: this.reduceEditor.getReduceValue(),
designDocs: this.props.designDocs
}, url);
}
viewChange(el) {
this.props.changeViewName(el.target.value);
}
updateMapCode(code) {
this.props.updateMapCode(code);
}
getCancelLink() {
const encodedDatabase = encodeURIComponent(this.props.database.id);
const encodedPartitionKey = this.props.partitionKey ? encodeURIComponent(this.props.partitionKey) : '';
const encodedDDoc = encodeURIComponent(this.props.designDocId);
const encodedView = encodeURIComponent(this.props.viewName);
if (this.props.designDocId === 'new-doc' || this.props.isNewView) {
return '#' + FauxtonAPI.urls('allDocs', 'app', encodedDatabase, encodedPartitionKey);
}
return '#' + FauxtonAPI.urls('view', 'showView', encodedDatabase, encodedPartitionKey, encodedDDoc, encodedView);
}
render() {
if (this.props.isLoading) {
return (
<div className="define-view">
<LoadLines />
</div>
);
}
const pageHeader = (this.props.isNewView) ? 'New View' : 'Edit View';
const btnLabel = (this.props.isNewView) ? 'Create Document and then Build Index' : 'Save Document and then Build Index';
return (
<div className="define-view" >
<form className="form-horizontal view-query-save" onSubmit={this.saveView}>
<h3 className="simple-header">{pageHeader}</h3>
<div className="new-ddoc-section">
<DesignDocSelector
ref={(el) => { this.designDocSelector = el; }}
designDocList={this.props.designDocList}
isDbPartitioned={this.props.isDbPartitioned}
selectedDesignDocName={this.props.designDocId}
selectedDesignDocPartitioned={this.props.designDocPartitioned}
newDesignDocName={this.props.newDesignDocName}
newDesignDocPartitioned={this.props.newDesignDocPartitioned}
onSelectDesignDoc={this.props.selectDesignDoc}
onChangeNewDesignDocName={this.props.updateNewDesignDocName}
onChangeNewDesignDocPartitioned={this.props.updateNewDesignDocPartitioned}
docLink={getDocUrl('DESIGN_DOCS')} />
</div>
<div className="control-group">
<label htmlFor="index-name">
<span>Index name</span>
<a
className="help-link"
data-bypass="true"
href={getDocUrl('VIEW_FUNCS')}
target="_blank"
rel="noopener noreferrer">
<i className="icon-question-sign"></i>
</a>
</label>
<input
type="text"
id="index-name"
value={this.props.viewName}
onChange={this.viewChange}
placeholder="Index name" />
</div>
<CodeEditorPanel
id={'map-function'}
ref={(el) => { this.mapEditor = el; }}
title={"Map function"}
docLink={getDocUrl('MAP_FUNCS')}
blur={this.updateMapCode}
allowZenMode={false}
defaultCode={this.props.map} />
<ReduceEditor
ref={(el) => { this.reduceEditor = el; }}
customReducerSupported={this.isCustomReduceSupported()}
{...this.props} />
<div className="padded-box">
<div className="control-group">
<ConfirmButton id="save-view" text={btnLabel} />
<a href={this.getCancelLink()} className="index-cancel-link">Cancel</a>
</div>
</div>
</form>
</div>
);
}
}
IndexEditor.propTypes = {
isLoading:PropTypes.bool.isRequired,
isNewView: PropTypes.bool.isRequired,
database: PropTypes.object.isRequired,
isDbPartitioned: PropTypes.bool.isRequired,
designDocId: PropTypes.string.isRequired,
newDesignDocName: PropTypes.string.isRequired,
viewName: PropTypes.string.isRequired,
isNewDesignDoc: PropTypes.bool.isRequired,
originalViewName: PropTypes.string,
originalDesignDocName: PropTypes.string,
designDocs: PropTypes.object,
saveDesignDoc: PropTypes.object,
partitionKey: PropTypes.string,
updateNewDesignDocName: PropTypes.func.isRequired,
changeViewName: PropTypes.func.isRequired,
updateMapCode: PropTypes.func.isRequired
};