blob: eb005fb3b45608c3b46e0b3a7d6ac3cd5b0730bc [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 { Button } from 'react-bootstrap';
import ReactSelect from "react-select";
import "../../../../../assets/js/plugins/prettify";
import app from "../../../../app";
import FauxtonAPI from "../../../../core/api";
import ReactComponents from "../../../components/react-components";
import ExecutionStats from './ExecutionStats';
const PaddedBorderedBox = ReactComponents.PaddedBorderedBox;
const CodeEditorPanel = ReactComponents.CodeEditorPanel;
const getDocUrl = app.helpers.getDocUrl;
export default class MangoQueryEditor extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
prettyPrint();
this.props.loadQueryHistory({ databaseName: this.props.databaseName });
// Clear results list in case it was populated by other pages
this.props.clearResults();
// Add key binding to run query when doing Ctrl-Enter
const editor = this.codeEditor.codeEditor.editor;
const runQueryCmdName = "runQuery";
if (!editor.commands.byName[runQueryCmdName]) {
editor.commands.addCommand({
name: runQueryCmdName,
bindKey: {win: 'Ctrl-Enter', mac: 'Command-Option-Enter'},
exec: () => {
this.runQuery({preventDefault: () => {}});
},
readOnly: true
});
}
}
componentDidUpdate (prevProps) {
prettyPrint();
if (prevProps.history != this.props.history) {
// Explicitly set value because updating 'CodeEditorPanel.defaultCode' won't change the editor once it's already loaded.
this.setEditorValue(this.props.history[0].value);
}
}
setEditorValue (newValue = '') {
return this.codeEditor.getEditor().setValue(newValue);
}
getEditorValue () {
return this.codeEditor.getValue();
}
editorHasErrors () {
return this.codeEditor.getEditor().hasErrors();
}
onHistorySelected(selectedItem) {
this.setEditorValue(selectedItem.value);
}
editor() {
return (
<div className="mango-editor-wrapper">
<form className="form-horizontal" onSubmit={(ev) => {this.runQuery(ev);}}>
<div className="padded-box">
<ReactSelect
className="mango-select"
options={this.props.history}
ref={node => this.history = node}
placeholder="Query history"
searchable={false}
clearable={false}
autosize={false}
onChange={(elem) => {this.onHistorySelected(elem);}}
/>
</div>
<PaddedBorderedBox>
<CodeEditorPanel
id="query-field"
ref={node => this.codeEditor = node}
title={this.props.editorTitle}
docLink={getDocUrl('MANGO_SEARCH')}
defaultCode={this.props.queryFindCode} />
</PaddedBorderedBox>
<div className="padded-box">
<div className="actions-panel">
<Button type="submit" id="create-index-btn" variant="cf-primary" className="btn-space">Run Query</Button>
<Button type="button" id="explain-btn" variant="cf-secondary" className="btn-space"
onClick={(ev) => {this.runExplain(ev);} }>Explain</Button>
<div className="right-side-actions">
<Button variant="cf-secondary" className="edit-link" onClick={(ev) => {this.manageIndexes(ev);}}>Manage Indexes</Button>
</div>
</div>
<div>
<ExecutionStats {...this.props} />
</div>
</div>
</form>
</div>
);
}
render () {
if (this.props.isLoading) {
return (
<div className="mango-editor-wrapper">
<ReactComponents.LoadLines />
</div>
);
}
return this.editor();
}
notifyOnQueryError() {
if (this.editorHasErrors()) {
FauxtonAPI.addNotification({
msg: 'Please fix the Javascript errors and try again.',
type: 'error',
clear: true
});
return true;
}
return false;
}
manageIndexes(event) {
event.preventDefault();
this.props.manageIndexes();
const encodedPartKey = this.props.partitionKey ? encodeURIComponent(this.props.partitionKey) : '';
const manageIndexURL = '#' + FauxtonAPI.urls('mango', 'index-app',
encodeURIComponent(this.props.databaseName), encodedPartKey);
FauxtonAPI.navigate(manageIndexURL);
}
runExplain(event) {
event.preventDefault();
if (this.notifyOnQueryError()) {
return;
}
this.props.runExplainQuery({
databaseName: this.props.databaseName,
partitionKey: this.props.partitionKey,
queryCode: this.getEditorValue()
});
}
runQuery (event) {
event.preventDefault();
if (this.notifyOnQueryError()) {
return;
}
this.props.clearResults();
this.props.runQuery({
databaseName: this.props.databaseName,
partitionKey: this.props.partitionKey,
queryCode: JSON.parse(this.getEditorValue()),
fetchParams: {...this.props.fetchParams, skip: 0}
});
}
}
MangoQueryEditor.propTypes = {
description: PropTypes.string.isRequired,
editorTitle: PropTypes.string.isRequired,
queryFindCode: PropTypes.string.isRequired,
queryFindCodeChanged: PropTypes.bool,
databaseName: PropTypes.string.isRequired,
partitionKey: PropTypes.string,
runExplainQuery: PropTypes.func.isRequired,
runQuery: PropTypes.func.isRequired,
manageIndexes: PropTypes.func.isRequired,
loadQueryHistory: PropTypes.func.isRequired,
clearResults: PropTypes.func.isRequired
};