blob: ec57842c6decd5da797ee075f60e47233b7ecb20 [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 from 'react';
import { Collapse, OverlayTrigger, Popover } from 'react-bootstrap';
import ReactDOM from 'react-dom';
import FauxtonAPI from '../../../../core/api';
export default class IndexSection extends React.Component {
static propTypes = {
urlNamespace: PropTypes.string.isRequired,
indexLabel: PropTypes.string.isRequired,
database: PropTypes.object.isRequired,
designDocName: PropTypes.string.isRequired,
items: PropTypes.array.isRequired,
isExpanded: PropTypes.bool.isRequired,
selectedIndex: PropTypes.string.isRequired,
onDelete: PropTypes.func.isRequired,
onClone: PropTypes.func.isRequired,
showDeleteIndexModal: PropTypes.func.isRequired,
showCloneIndexModal: PropTypes.func.isRequired,
isPartitioned: PropTypes.bool.isRequired,
selectedPartitionKey: PropTypes.string
};
state = {
placement: 'bottom'
};
// this dynamically changes the placement of the menu (top/bottom) to prevent it going offscreen and causing some
// unsightly shifting
setPlacement = (rowId) => {
const rowTop = document.getElementById(rowId).getBoundingClientRect().top;
const toggleHeight = 150; // the height of the menu overlay, arrow, view row
const placement = (rowTop + toggleHeight > window.innerHeight) ? 'top' : 'bottom';
this.setState({ placement: placement });
};
createItems = () => {
// sort the indexes alphabetically
const sortedItems = this.props.items.sort();
return _.map(sortedItems, (indexName, index) => {
let href = FauxtonAPI.urls(this.props.urlNamespace, 'app', encodeURIComponent(this.props.database.id), encodeURIComponent(this.props.designDocName));
if (this.props.selectedPartitionKey) {
href = FauxtonAPI.urls('partitioned_' + this.props.urlNamespace, 'app',
encodeURIComponent(this.props.database.id),
encodeURIComponent(this.props.selectedPartitionKey),
encodeURIComponent(this.props.designDocName));
}
const className = (this.props.selectedIndex === indexName) ? 'active' : '';
return (
<li className={className} key={index}>
<a
id={this.props.designDocName + '_' + indexName}
href={"#/" + href + encodeURIComponent(indexName)}
className="toggle-view">
{indexName}
</a>
<OverlayTrigger
trigger="click"
onEnter={this.setPlacement.bind(this, this.props.designDocName + '_' + indexName)}
placement={this.state.placement}
rootClose={true}
ref={overlay => this.itemOverlay = overlay}
overlay={
<Popover id="index-menu-component-popover">
<ul>
<li onClick={this.indexAction.bind(this, 'edit', { indexName: indexName, onEdit: this.props.onEdit })}>
<span className="fonticon fonticon-file-code-o"></span>
Edit
</li>
<li onClick={this.indexAction.bind(this, 'clone', { indexName: indexName, onClone: this.props.onClone })}>
<span className="fonticon fonticon-files-o"></span>
Clone
</li>
<li onClick={this.indexAction.bind(this, 'delete', { indexName: indexName, onDelete: this.props.onDelete })}>
<span className="fonticon fonticon-trash"></span>
Delete
</li>
</ul>
</Popover>
}>
<span className="index-menu-toggle fonticon fonticon-wrench2"></span>
</OverlayTrigger>
</li>
);
});
};
indexAction = (action, params, e) => {
e.preventDefault();
this.itemOverlay.hide();
switch (action) {
case 'delete':
this.props.showDeleteIndexModal(params.indexName, this.props.designDocName, this.props.indexLabel, params.onDelete);
break;
case 'clone':
this.props.showCloneIndexModal(params.indexName, this.props.designDocName, this.props.indexLabel, params.onClone);
break;
case 'edit':
params.onEdit(this.props.database.id, this.props.selectedPartitionKey, this.props.designDocName, params.indexName);
break;
}
};
toggle = (e) => {
e.preventDefault();
this.props.toggle(this.props.designDocName, this.props.title);
};
render() {
// if this section has no content, omit it to prevent clutter. Otherwise it would show a toggle option that
// would hide/show nothing
if (this.props.items.length === 0) {
return null;
}
let toggleClassNames = 'accordion-header index-group-header';
let toggleBodyClassNames = 'index-list accordion-body collapse';
if (this.props.isExpanded) {
toggleClassNames += ' down';
toggleBodyClassNames += ' in';
}
const title = this.props.title;
const designDocName = this.props.designDocName;
const linkId = "nav-design-function-" + designDocName + this.props.selector;
return (
<li id={linkId}>
<a className={toggleClassNames} data-toggle="collapse" onClick={this.toggle}>
<div className="fonticon-play"></div>
{title}
</a>
<Collapse in={this.props.isExpanded}>
<ul className={toggleBodyClassNames}>
{this.createItems()}
</ul>
</Collapse>
</li>
);
}
}