labo-components
Version:
235 lines (213 loc) • 10 kB
JSX
import React from 'react';
import PropTypes from 'prop-types';
import ReactTooltip from 'react-tooltip';
import ProjectAPI from '../../../../api/ProjectAPI';
import Project from '../../../../model/Project';
import IDUtil from '../../../../util/IDUtil';
import CollectionUtil from "../../../../util/CollectionUtil";
import QueryUtil from "../../../../util/QueryUtil";
import FlexRouter from '../../../../util/FlexRouter';
import SortTable from '../../SortTable';
import CopyToClipboard from '../../../helpers/CopyToClipboard';
import MessageHelper from '../../../helpers/MessageHelper';
import LocalStorageHandler from '../../../../util/LocalStorageHandler';
import ComponentUtil from '../../../../util/ComponentUtil';
class ProjectQueriesTable extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
queries: [],
selectedQueries: this.props.selection ? this.props.selection : [],
filter: {
keywords: '',
currentUser: false
}
};
PropTypes.checkPropTypes(ProjectQueriesTable.propTypes, this.props, 'prop', this.constructor.name);
}
componentDidMount() {
this.loadTableData(this.props.project);
if(this.props.project) {
LocalStorageHandler.storeJSONInLocalStorage('stored-active-project', this.props.project);
}
}
componentDidUpdate() {
if (this.lastFilter !== this.state.filter) {
this.lastFilter = this.state.filter;
this.loadTableData(this.props.project);
}
}
//whenever the keywords change
keywordsChange = e => this.setState({
filter: Object.assign({}, this.state.filter, {
keywords: e.target.value
})
});
onChange = () => this.props.onChange ? this.props.onChange() : false;
//load the query data and apply the current filter
loadTableData = project => this.setState({
queries: this.filterQueries(
project && project.queries ? project.queries : [],
this.state.filter
)
}, () => this.onChange());
//Filter query list by given filter
filterQueries(namedQueries, filter) {
// filter on keywords in name or tool
if (filter.keywords) {
filter.keywords.split(' ').forEach(k => { //FIXME this seems wrong, the filter will only apply the last keyword filter...
namedQueries = namedQueries.filter(query => query.name.toLowerCase().includes(k.toLowerCase()));
});
}
//generate a collectionConfig and assign it to each named query (FIXME this)
namedQueries.forEach(nq => {
if(nq.query.collectionId && nq.query.dateRange && nq.query.dateRange.field) {
CollectionUtil.generateCollectionConfig(
this.props.user.id, //FIXME this should be the client ID! (will break for personal collection queries only)
this.props.user,
nq.query.collectionId,
config => nq.collectionConfig = config, //assign the config to the named query
true
);
}
});
return namedQueries;
}
viewQuery = namedQuery => {
if(!namedQuery) return;
const selectedQuery = this.state.queries.filter(nq => nq.name === namedQuery.name);
if(selectedQuery.length > 0) {
FlexRouter.gotoSingleSearch(selectedQuery[0].id);
}
};
deleteQueries = namedQueries => {
const msg = namedQueries.length > 1 ?
'Are you sure you want to delete ' + namedQueries.length + ' queries?' :
'Are you sure you want to delete query: ' + namedQueries[0].name + '?'
;
if (ComponentUtil.userConfirm(msg)) {
this.deleteProjectQueries(this.props.user.id, this.props.project, namedQueries);
}
};
//separated the API, so it can be mocked for the unit-test
deleteProjectQueries = (userId, project, queriesToDelete) => {
project.queries = project.queries.filter(nq => {
return !queriesToDelete.map(nq1 => nq1.id).includes(nq.id)
});
QueryUtil.deleteQueries(queriesToDelete, userId, project.id, queriesDeleted => {
if (queriesDeleted) {
LocalStorageHandler.updateStoredQueries(project, queriesToDelete); //update the stored queries
LocalStorageHandler.storeJSONInLocalStorage(
'stored-active-project',
project.toLocalStorageObject()
); //update the stored project
this.loadTableData(project); //reload the table
this.props.handleDeleteQueries ? this.props.handleDeleteQueries() : null; //optional callback
} else {
alert('An error occurred while deleting these queries');
}
});
};
onSelectQuery = item => this.setState({selectedQueries: item});
sortQueries = (queries, sort) => queries.sort(function (a, b) {
const textA = a.name.toUpperCase();
const textB = b.name.toUpperCase();
if (sort.order === 'asc') {
return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;
} else {
return (textA > textB) ? -1 : (textA < textB) ? 1 : 0;
}
});
render() {
const bulkActions = this.props.handleCompareLink ?
[
{ title: 'Delete', onApply: () => this.deleteQueries(this.state.selectedQueries) },
{ title: 'Compare', onApply: () => this.props.handleCompareLink(this.state.selectedQueries)}
]
: [
{ title: 'Delete', onApply: () => this.deleteQueries(this.state.selectedQueries) }
];
return (
<div className={IDUtil.cssClassName('project-queries-table')}>
<div className="tools">
<div className="left">
<h3>Filters</h3>
<div className="filter-container">
<input
className="search"
type="text"
placeholder="Search"
value={this.state.filter.keywords}
onChange={this.keywordsChange}/>
</div>
</div>
</div>
<SortTable
items={this.state.queries}
head={[
{ field: 'name', content: 'Name', sortable: true },
{ field: 'query', content: 'Query', sortable: true },
{ field: '', content: '', sortable: false },
{ field: '', content: '', sortable: false }
]}
row={namedQuery => [ //must be a proper named query (Project.queries)
{
props: { className: 'primary' },
content: <a onClick={this.viewQuery.bind(this, namedQuery)}>{namedQuery.name}</a>
},
{ content:
<div>
<a data-tip data-for={'__qtt__' + namedQuery.id} data-class="bg__custom-queryTooltip">
<CopyToClipboard textToSave={namedQuery.query.queryDetailsToClipboard(namedQuery.name)} />
</a>
<ReactTooltip
id={'__qtt__' + namedQuery.id}
getContent={() => MessageHelper.renderQueryForTooltip(
namedQuery.query,
namedQuery.collectionConfig
)}>
</ReactTooltip>
<span className="bg__searchTerm">{namedQuery.query.toHumanReadableString()}</span>
</div>
},
{
content: (
<a className="btn blank warning" onClick={() => this.deleteQueries([namedQuery])}>
Delete
</a>
)
},
{
content: (
<a onClick={this.viewQuery.bind(this, namedQuery)} className="btn">
Open
</a>
)
}
]}
onSelectQuery={this.onSelectQuery}
onSort={this.sortQueries}
loading={this.state.loading}
bulkActions={bulkActions}
defaultSort={{
field: 'name',
order: 'asc'
}}
selection={this.state.selectedQueries}
keepSelectionWhenDone={this.props.keepSelectionWhenDone}/>
</div>
)
}
}
ProjectQueriesTable.propTypes = {
project : Project.getPropTypes(true),
user: PropTypes.shape({ // current user object used for defining access roles per project
id: PropTypes.string.isRequired
}).isRequired,
handleCompareLink : PropTypes.func, // only passed via the QueryComparisonRecipe
handleDeleteQueries : PropTypes.func, // only passed via the QueryComparisonRecipe
onChange : PropTypes.func, // whenever something is deleted pass it on to the owner, so they can adapt (e.g. displaying query counts)
selection: PropTypes.array,
keepSelectionWhenDone: PropTypes.bool //whether to keep selections when done
};
export default ProjectQueriesTable;