blob: 5882f9563cb7e51d76171957e4f74202ab410770 [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 app from "../../app";
import React from "react";
import ReactDOM from "react-dom";
import Stores from "./stores";
import Resources from "./resources";
import Actions from "./actions";
import Components from "../components/react-components";
const {TabElement, TabElementWrapper, Polling} = Components;
const activeTasksStore = Stores.activeTasksStore;
export const ActiveTasksController = React.createClass({
getStoreState () {
return {
collection: activeTasksStore.getCollection(),
searchTerm: activeTasksStore.getSearchTerm(),
selectedRadio: activeTasksStore.getSelectedRadio(),
sortByHeader: activeTasksStore.getSortByHeader(),
headerIsAscending: activeTasksStore.getHeaderIsAscending()
};
},
getInitialState () {
return this.getStoreState();
},
componentDidMount () {
Actions.init(new Resources.AllTasks());
activeTasksStore.on('change', this.onChange, this);
},
componentWillUnmount () {
activeTasksStore.off('change', this.onChange, this);
},
onChange () {
this.setState(this.getStoreState());
},
setNewSearchTerm (searchTerm) {
Actions.setSearchTerm(searchTerm);
},
switchTab (newRadioButton) { //tabs buttons
Actions.switchTab(newRadioButton);
},
tableHeaderOnClick (headerClicked) {
Actions.sortByColumnHeader(headerClicked);
},
render () {
const {collection, searchTerm, selectedRadio, sortByHeader, headerIsAscending} = this.state;
const setSearchTerm = this.setNewSearchTerm;
const onTableHeaderClick = this.tableHeaderOnClick;
return (
<div id="active-tasks-page" className="scrollable">
<div className="inner">
<ActiveTasksFilterTabs
searchTerm={searchTerm}
selectedRadio={selectedRadio}
onSearch={setSearchTerm}
onRadioClick={this.switchTab}/>
<ActiveTaskTable
collection={collection}
searchTerm={searchTerm}
selectedRadio={selectedRadio}
onTableHeaderClick={onTableHeaderClick}
sortByHeader={sortByHeader}
headerIsAscending={headerIsAscending} />
</div>
</div>
);
}
});
var ActiveTasksFilterTabs = React.createClass({
getDefaultProps () {
return {
radioNames : [
'All Tasks',
'Replication',
'Database Compaction',
'Indexer',
'View Compaction'
]
};
},
checked (radioName) {
return this.props.selectedRadio === radioName;
},
onRadioClick (e) {
var radioName = e.target.value;
this.props.onRadioClick(radioName);
},
createFilterTabs () {
return (
this.props.radioNames.map((radioName, i) => {
const checked = this.checked(radioName);
return (
<TabElement
key={i}
selected={checked}
text={radioName}
onChange={this.onRadioClick} />
);
})
);
},
searchTermChange (e) {
var searchTerm = e.target.value;
this.props.onSearch(searchTerm);
},
render () {
const filterTabs = this.createFilterTabs();
return (
<TabElementWrapper>
{filterTabs}
<li className="component-tab-list-element">
<input
id="active-tasks-search-box"
className="searchbox"
type="text"
name="search"
placeholder="Search for databases..."
value={this.props.searchTerm}
onChange={this.searchTermChange} />
</li>
</TabElementWrapper>
);
}
});
var ActiveTaskTable = React.createClass({
render () {
var collection = this.props.collection;
var selectedRadio = this.props.selectedRadio;
var searchTerm = this.props.searchTerm;
var sortByHeader = this.props.sortByHeader;
var onTableHeaderClick = this.props.onTableHeaderClick;
var headerIsAscending = this.props.headerIsAscending;
return (
<div id="dashboard-lower-content">
<table id="active-tasks-table" className="table table-bordered table-striped active-tasks">
<ActiveTasksTableHeader
onTableHeaderClick={onTableHeaderClick}
sortByHeader={sortByHeader}
headerIsAscending={headerIsAscending}/>
<ActiveTasksTableBody
collection={collection}
selectedRadio={selectedRadio}
searchTerm={searchTerm}/>
</table>
</div>
);
}
});
var ActiveTasksTableHeader = React.createClass({
getDefaultProps () {
return {
headerNames : [
['type', 'Type'],
['database', 'Database'],
['started-on', 'Started on'],
['updated-on', 'Updated on'],
['pid', 'PID'],
['progress', 'Status']
]
};
},
createTableHeadingFields () {
var onTableHeaderClick = this.props.onTableHeaderClick;
var sortByHeader = this.props.sortByHeader;
var headerIsAscending = this.props.headerIsAscending;
return this.props.headerNames.map(function (header) {
return <TableHeader
headerName={header[0]}
displayName={header[1]}
key={header[0]}
onTableHeaderClick={onTableHeaderClick}
sortByHeader={sortByHeader}
headerIsAscending={headerIsAscending} />;
});
},
render () {
return (
<thead>
<tr>{this.createTableHeadingFields()}</tr>
</thead>
);
}
});
var TableHeader = React.createClass({
arrow () {
var sortBy = this.props.sortByHeader;
var currentName = this.props.headerName;
var headerIsAscending = this.props.headerIsAscending;
var arrow = headerIsAscending ? 'icon icon-caret-up' : 'icon icon-caret-down';
if (sortBy === currentName) {
return <i className={arrow}></i>;
}
},
onTableHeaderClick (e) {
var headerSelected = e.target.value;
this.props.onTableHeaderClick(headerSelected);
},
render () {
var arrow = this.arrow();
var th_class = 'header-field ' + this.props.headerName;
return (
<td className={th_class + " tableheader"} value={this.props.headerName}>
<input
type="radio"
name="header-field"
id={this.props.headerName}
value={this.props.headerName}
className="header-field radio"
onChange={this.onTableHeaderClick} />
<label
className="header-field label-text active-tasks-header noselect"
htmlFor={this.props.headerName}>
{this.props.displayName} {arrow}
</label>
</td>
);
}
});
var ActiveTasksTableBody = React.createClass({
getStoreState () {
return {
filteredTable: activeTasksStore.getFilteredTable(this.props.collection)
};
},
getInitialState () {
return this.getStoreState();
},
componentWillReceiveProps () {
this.setState({
filteredTable: activeTasksStore.getFilteredTable(this.props.collection)
});
},
createRows () {
var isThereASearchTerm = this.props.searchTerm.trim() === "";
if (this.state.filteredTable.length === 0) {
return isThereASearchTerm ? this.noActiveTasks() : this.noActiveTasksMatchFilter();
}
return _.map(this.state.filteredTable, function (item, key) {
return <ActiveTaskTableBodyContents key={key} item={item} />;
});
},
noActiveTasks () {
var type = this.props.selectedRadio;
if (type === "All Tasks") {
type = "";
}
return (
<tr className="no-matching-database-on-search">
<td colSpan="6">No active {type} tasks.</td>
</tr>
);
},
noActiveTasksMatchFilter () {
var type = this.props.selectedRadio;
if (type === "All Tasks") {
type = "";
}
return (
<tr className="no-matching-database-on-search">
<td colSpan="6">No active {type} tasks match with filter: "{this.props.searchTerm}"</td>
</tr>
);
},
render () {
return (
<tbody className="js-tasks-go-here">
{this.createRows()}
</tbody>
);
}
});
var ActiveTaskTableBodyContents = React.createClass({
getInfo (item) {
return {
type : item.type,
objectField: activeTasksHelpers.getDatabaseFieldMessage(item),
started_on: activeTasksHelpers.getTimeInfo(item.started_on),
updated_on: activeTasksHelpers.getTimeInfo(item.updated_on),
pid: item.pid.replace(/[<>]/g, ''),
progress: activeTasksHelpers.getProgressMessage(item),
};
},
multilineMessage (messageArray, optionalClassName) {
if (!optionalClassName) {
optionalClassName = '';
}
var cssClasses = 'multiline-active-tasks-message ' + optionalClassName;
return messageArray.map(function (msgLine, iterator) {
return <p key={iterator} className={cssClasses}>{msgLine}</p>;
});
},
render () {
var rowData = this.getInfo(this.props.item);
var objectFieldMsg = this.multilineMessage(rowData.objectField, 'to-from-database');
var startedOnMsg = this.multilineMessage(rowData.started_on, 'time');
var updatedOnMsg = this.multilineMessage(rowData.updated_on, 'time');
var progressMsg = this.multilineMessage(rowData.progress);
return (
<tr>
<td>{rowData.type}</td>
<td>{objectFieldMsg}</td>
<td>{startedOnMsg}</td>
<td>{updatedOnMsg}</td>
<td>{rowData.pid}</td>
<td>{progressMsg}</td>
</tr>
);
}
});
export const ActiveTasksPollingWidgetController = React.createClass({
getStoreState () {
return {
collection: activeTasksStore.getBackboneCollection()
};
},
getInitialState () {
return this.getStoreState();
},
componentDidMount () {
activeTasksStore.on('change', this.onChange, this);
},
onChange () {
this.setState(this.getStoreState());
},
runPollingUpdate () {
Actions.runPollingUpdate(this.state.collection);
},
getPluralForLabel () {
return this.state.pollingInterval === "1" ? '' : 's';
},
render () {
return (
<div className="active-tasks__polling-wrapper">
<Polling
min={1}
max={30}
stepSize={1}
startValue={15}
valueUnits={"second"}
onPoll={this.runPollingUpdate}
/>
</div>
);
}
});
var activeTasksHelpers = {
getTimeInfo (timeStamp) {
var timeMessage = [
app.helpers.formatDate(timeStamp),
app.helpers.getDateFromNow(timeStamp)
];
return timeMessage;
},
getDatabaseFieldMessage (item) {
var type = item.type;
var databaseFieldMessage = [];
if (type === 'replication') {
databaseFieldMessage.push('From: ' + item.source);
databaseFieldMessage.push('To: ' + item.target);
} else if (type === 'indexer') {
databaseFieldMessage.push(item.database);
databaseFieldMessage.push('(View: ' + item.design_document + ')');
} else {
databaseFieldMessage.push(item.database);
}
return databaseFieldMessage;
},
getProgressMessage (item) {
var progressMessage = [];
var type = item.type;
if (_.has(item, 'progress')) {
progressMessage.push('Progress: ' + item.progress + '%');
}
if (type === 'indexer') {
progressMessage.push(
'Processed ' + item.changes_done + ' of ' + item.total_changes + ' changes.'
);
} else if (type === 'replication') {
progressMessage.push(item.docs_written + ' docs written.');
if (_.has(item, 'changes_pending')) {
progressMessage.push(item.changes_pending + ' pending changes.');
}
}
if (_.has(item, 'changes_done')) {
progressMessage.push(item.changes_done + ' Changes done.');
}
return progressMessage;
},
getSourceSequence (item) {
return item.source_seq;
}
};
export default {
ActiveTasksController: ActiveTasksController,
ActiveTasksFilterTabs: ActiveTasksFilterTabs,
ActiveTaskTable: ActiveTaskTable,
ActiveTasksTableHeader: ActiveTasksTableHeader,
TableHeader: TableHeader,
ActiveTasksTableBody: ActiveTasksTableBody,
ActiveTaskTableBodyContents: ActiveTaskTableBodyContents,
ActiveTasksPollingWidgetController: ActiveTasksPollingWidgetController
};