aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/apps
diff options
context:
space:
mode:
authorStas Vilchik <vilchiks@gmail.com>2016-05-13 11:57:27 +0200
committerStas Vilchik <vilchiks@gmail.com>2016-05-13 11:57:27 +0200
commit9a74d1aeb8d8bdbcf5c5b2a98fb2b2eefd1414a7 (patch)
tree502787d1156ea973de182fbc68ad48a3b6f43891 /server/sonar-web/src/main/js/apps
parentecd8c71b84b8691dd9c1d40f349f5b11a35c28cf (diff)
downloadsonarqube-9a74d1aeb8d8bdbcf5c5b2a98fb2b2eefd1414a7.tar.gz
sonarqube-9a74d1aeb8d8bdbcf5c5b2a98fb2b2eefd1414a7.zip
SONAR-7431 Keep filters state in url on background page (#965)
Diffstat (limited to 'server/sonar-web/src/main/js/apps')
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/app.js22
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/background-tasks.css (renamed from server/sonar-web/src/main/js/apps/background-tasks/styles/background-tasks.css)0
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js223
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/CurrentsFilter.js6
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/DateFilter.js6
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/Header.js6
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/Search.js124
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/Stats.js18
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/StatusFilter.js6
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/Task.js85
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/TaskCancelButton.js6
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.js6
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.js6
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/TaskExecutionTime.js8
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/TaskLogsLink.js6
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/TaskStatus.js6
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/Tasks.js41
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/components/TypesFilter.js6
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/constants.js3
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/containers/BackgroundTasksAppContainer.js40
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/containers/SearchContainer.js62
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/containers/StatsContainer.js48
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/containers/TasksContainer.js45
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/store/actions.js210
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/store/reducers.js97
-rw-r--r--server/sonar-web/src/main/js/apps/background-tasks/utils.js (renamed from server/sonar-web/src/main/js/apps/background-tasks/helpers.js)55
26 files changed, 480 insertions, 661 deletions
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/app.js b/server/sonar-web/src/main/js/apps/background-tasks/app.js
index d1626102c8f..c5ed780faa5 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/app.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/app.js
@@ -19,22 +19,24 @@
*/
import React from 'react';
import ReactDOM from 'react-dom';
-import { Provider } from 'react-redux';
+import { Router, Route, Redirect, useRouterHistory } from 'react-router';
+import { createHistory } from 'history';
-import BackgroundTasksAppContainer from './containers/BackgroundTasksAppContainer';
-import rootReducer from './store/reducers';
-import configureStore from '../../components/store/configureStore';
-
-import './styles/background-tasks.css';
+import BackgroundTasksApp from './components/BackgroundTasksApp';
window.sonarqube.appStarted.then(options => {
const el = document.querySelector(options.el);
- const store = configureStore(rootReducer);
+ const history = useRouterHistory(createHistory)({
+ basename: window.baseUrl + (options.component ? '/project/background_tasks' : '/background_tasks')
+ });
+
+ const App = props => <BackgroundTasksApp {...props} component={options.component}/>;
ReactDOM.render((
- <Provider store={store}>
- <BackgroundTasksAppContainer options={options}/>
- </Provider>
+ <Router history={history}>
+ <Redirect from="/index" to="/"/>
+ <Route path="/" component={App}/>
+ </Router>
), el);
});
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/styles/background-tasks.css b/server/sonar-web/src/main/js/apps/background-tasks/background-tasks.css
index 2bad2aba5a0..2bad2aba5a0 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/styles/background-tasks.css
+++ b/server/sonar-web/src/main/js/apps/background-tasks/background-tasks.css
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js b/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js
index 382e5e32983..0ca7ebb5cac 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.js
@@ -17,59 +17,210 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import moment from 'moment';
-import React, { Component } from 'react';
+import React from 'react';
+import shallowCompare from 'react-addons-shallow-compare';
+import debounce from 'lodash/debounce';
+import { PropTypes as RouterPropTypes } from 'react-router';
-import { DATE } from './../constants';
+import { DEFAULT_FILTERS, DEBOUNCE_DELAY, STATUSES, CURRENTS } from './../constants';
import Header from './Header';
import Footer from './Footer';
-import StatsContainer from '../containers/StatsContainer';
-import SearchContainer from '../containers/SearchContainer';
-import TasksContainer from '../containers/TasksContainer';
+import Stats from '../components/Stats';
+import Search from '../components/Search';
+import Tasks from '../components/Tasks';
+import { getTypes, getActivity, getStatus, cancelAllTasks, cancelTask as cancelTaskAPI } from '../../../api/ce';
+import { updateTask, mapFiltersToParameters } from '../utils';
+import '../background-tasks.css';
+
+export default class BackgroundTasksApp extends React.Component {
+ static contextTypes = {
+ router: React.PropTypes.object.isRequired
+ };
+
+ static propTypes = {
+ component: React.PropTypes.object,
+ location: RouterPropTypes.location.isRequired
+ };
+
+ state = {
+ loading: true,
+ tasks: [],
+
+ // filters
+ query: '',
+
+ // stats
+ pendingCount: 0,
+ failingCount: 0
+ };
+
+ componentWillMount () {
+ this.loadTasksDebounced = debounce(this.loadTasks.bind(this), DEBOUNCE_DELAY);
+ }
-export default class BackgroundTasksApp extends Component {
componentDidMount () {
- this.props.initApp(this.props.options.component);
+ this.mounted = true;
+
+ getTypes().then(types => {
+ this.setState({ types });
+ this.loadTasks();
+ });
}
- getComponentFilter () {
- if (this.props.options.component) {
- return { componentId: this.props.options.component.id };
- } else {
- return {};
+ shouldComponentUpdate (nextProps, nextState) {
+ return shallowCompare(this, nextProps, nextState);
+ }
+
+ componentDidUpdate (prevProps) {
+ if (prevProps.component !== this.props.component ||
+ prevProps.location !== this.props.location) {
+ this.loadTasksDebounced();
}
}
- getDateFilter () {
- const DATE_FORMAT = 'YYYY-MM-DD';
- const filter = {};
- switch (this.state.dateFilter) {
- case DATE.TODAY:
- filter.minSubmittedAt = moment().startOf('day').format(DATE_FORMAT);
- break;
- case DATE.CUSTOM:
- if (this.state.minDate) {
- filter.minSubmittedAt = moment(this.state.minDate).format(DATE_FORMAT);
- }
- if (this.state.maxDate) {
- filter.maxExecutedAt = moment(this.state.maxDate).format(DATE_FORMAT);
- }
- break;
- default:
-
- // do nothing
+ componentWillUnmount () {
+ this.mounted = false;
+ }
+
+ loadTasks () {
+ this.setState({ loading: true });
+
+ const status = this.props.location.query.status || DEFAULT_FILTERS.status;
+ const taskType = this.props.location.query.taskType || DEFAULT_FILTERS.taskType;
+ const currents = this.props.location.query.currents || DEFAULT_FILTERS.currents;
+ const minSubmittedAt = this.props.location.query.minSubmittedAt || DEFAULT_FILTERS.minSubmittedAt;
+ const maxExecutedAt = this.props.location.query.maxExecutedAt || DEFAULT_FILTERS.maxExecutedAt;
+ const query = this.props.location.query.query || DEFAULT_FILTERS.query;
+
+ const filters = { status, taskType, currents, minSubmittedAt, maxExecutedAt, query };
+ const parameters = mapFiltersToParameters(filters);
+
+ if (this.props.component) {
+ parameters.componentId = this.props.component.id;
}
- return filter;
+
+ Promise.all([
+ getActivity(parameters),
+ getStatus(parameters.componentId)
+ ]).then(responses => {
+ if (this.mounted) {
+ const [activity, status] = responses;
+ const tasks = activity.tasks;
+
+ const pendingCount = status.pending;
+ const failingCount = status.failing;
+
+ this.setState({
+ tasks,
+ pendingCount,
+ failingCount,
+ loading: false
+ });
+ }
+ });
+ }
+
+ handleFilterUpdate (nextState) {
+ const nextQuery = { ...this.props.location.query, ...nextState };
+
+ // remove defaults
+ Object.keys(DEFAULT_FILTERS).forEach(key => {
+ if (nextQuery[key] === DEFAULT_FILTERS[key]) {
+ delete nextQuery[key];
+ }
+ });
+
+ this.context.router.push({
+ pathname: '/',
+ query: nextQuery
+ });
+ }
+
+ handleCancelTask (task) {
+ this.setState({ loading: true });
+
+ cancelTaskAPI(task.id).then(nextTask => {
+ if (this.mounted) {
+ const tasks = updateTask(this.state.tasks, nextTask);
+ this.setState({ tasks, loading: false });
+ }
+ });
+ }
+
+ handleFilterTask (task) {
+ this.handleFilterUpdate({ query: task.componentKey });
+ }
+
+ handleShowFailing () {
+ this.handleFilterUpdate({
+ ...DEFAULT_FILTERS,
+ status: STATUSES.FAILED,
+ currents: CURRENTS.ONLY_CURRENTS
+ });
+ }
+
+ handleCancelAllPending () {
+ this.setState({ loading: true });
+
+ cancelAllTasks().then(() => {
+ if (this.mounted) {
+ this.loadTasks();
+ }
+ });
}
render () {
+ const { component } = this.props;
+ const { loading, types, tasks, pendingCount, failingCount } = this.state;
+
+ if (!types) {
+ return (
+ <div className="page">
+ <i className="spinner"/>
+ </div>
+ );
+ }
+
+ const status = this.props.location.query.status || DEFAULT_FILTERS.status;
+ const taskType = this.props.location.query.taskType || DEFAULT_FILTERS.taskType;
+ const currents = this.props.location.query.currents || DEFAULT_FILTERS.currents;
+ const minSubmittedAt = this.props.location.query.minSubmittedAt || '';
+ const maxExecutedAt = this.props.location.query.maxExecutedAt || '';
+ const query = this.props.location.query.query || '';
+
return (
<div className="page">
<Header/>
- <StatsContainer/>
- <SearchContainer/>
- <TasksContainer/>
- <Footer tasks={this.props.tasks}/>
+
+ <Stats
+ component={component}
+ pendingCount={pendingCount}
+ failingCount={failingCount}
+ onShowFailing={this.handleShowFailing.bind(this)}
+ onCancelAllPending={this.handleCancelAllPending.bind(this)}/>
+
+ <Search
+ loading={loading}
+ component={component}
+ status={status}
+ currents={currents}
+ minSubmittedAt={minSubmittedAt}
+ maxExecutedAt={maxExecutedAt}
+ query={query}
+ taskType={taskType}
+ types={types}
+ onFilterUpdate={this.handleFilterUpdate.bind(this)}
+ onReload={this.loadTasksDebounced}/>
+
+ <Tasks
+ loading={loading}
+ component={component}
+ types={types}
+ tasks={tasks}
+ onCancelTask={this.handleCancelTask.bind(this)}
+ onFilterTask={this.handleFilterTask.bind(this)}/>
+
+ <Footer tasks={tasks}/>
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/CurrentsFilter.js b/server/sonar-web/src/main/js/apps/background-tasks/components/CurrentsFilter.js
index 2468594bbd9..be19157bb88 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/CurrentsFilter.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/CurrentsFilter.js
@@ -22,7 +22,7 @@ import React from 'react';
import Checkbox from '../../../components/shared/checkbox';
import { CURRENTS } from '../constants';
-export default function CurrentsFilter ({ value, onChange }) {
+const CurrentsFilter = ({ value, onChange }) => {
function handleChange (value) {
const newValue = value ? CURRENTS.ONLY_CURRENTS : CURRENTS.ALL;
onChange(newValue);
@@ -48,4 +48,6 @@ export default function CurrentsFilter ({ value, onChange }) {
style={{ cursor: 'pointer' }}>Yes</label>
</div>
);
-}
+};
+
+export default CurrentsFilter;
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/DateFilter.js b/server/sonar-web/src/main/js/apps/background-tasks/components/DateFilter.js
index 83e90c9caf3..ace8d6e428d 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/DateFilter.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/DateFilter.js
@@ -64,14 +64,14 @@ export default class DateFilter extends Component {
}
render () {
- const { minSubmittedAt, maxExecutedAt } = this.props.value;
+ const { minSubmittedAt, maxExecutedAt } = this.props;
return (
<div>
<input
className="input-small"
value={minSubmittedAt}
- onChange={this.handleChange.bind(this)}
+ onChange={() => true}
ref="minDate"
type="text"
placeholder="From"/>
@@ -79,7 +79,7 @@ export default class DateFilter extends Component {
<input
className="input-small"
value={maxExecutedAt}
- onChange={this.handleChange.bind(this)}
+ onChange={() => true}
ref="maxDate"
type="text"
placeholder="To"/>
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/Header.js b/server/sonar-web/src/main/js/apps/background-tasks/components/Header.js
index 3fbf337976e..8cc1f251797 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/Header.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/Header.js
@@ -21,7 +21,7 @@ import React from 'react';
import { translate } from '../../../helpers/l10n';
-export default function Header () {
+const Header = () => {
return (
<header className="page-header">
<h1 className="page-title">
@@ -32,4 +32,6 @@ export default function Header () {
</p>
</header>
);
-}
+};
+
+export default Header;
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/Search.js b/server/sonar-web/src/main/js/apps/background-tasks/components/Search.js
index fda9220cfff..bfffb1021e4 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/Search.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/Search.js
@@ -23,53 +23,88 @@ import StatusFilter from './StatusFilter';
import TypesFilter from './TypesFilter';
import CurrentsFilter from './CurrentsFilter';
import DateFilter from './DateFilter';
+import { DEFAULT_FILTERS } from './../constants';
import { translate } from '../../../helpers/l10n';
-export default React.createClass({
+export default class Search extends React.Component {
+ static propTypes = {
+ loading: React.PropTypes.bool.isRequired,
+ status: React.PropTypes.any.isRequired,
+ taskType: React.PropTypes.any.isRequired,
+ currents: React.PropTypes.any.isRequired,
+ query: React.PropTypes.string.isRequired,
+ onFilterUpdate: React.PropTypes.func.isRequired,
+ onReload: React.PropTypes.func.isRequired
+ };
- onSearchFormSubmit(e) {
+ handleStatusChange (status) {
+ this.props.onFilterUpdate({ status });
+ }
+
+ handleTypeChange (taskType) {
+ this.props.onFilterUpdate({ taskType });
+ }
+
+ handleCurrentsChange (currents) {
+ this.props.onFilterUpdate({ currents });
+ }
+
+ handleDateChange (date) {
+ this.props.onFilterUpdate(date);
+ }
+
+ handleQueryChange (query) {
+ this.props.onFilterUpdate({ query });
+ }
+
+ handleReload (e) {
+ e.target.blur();
+ this.props.onReload();
+ }
+
+ handleReset (e) {
e.preventDefault();
- this.onSearch();
- },
+ e.target.blur();
+ this.props.onFilterUpdate(DEFAULT_FILTERS);
+ }
- onSearch() {
- const searchInput = this.refs.searchInput;
- const query = searchInput.value;
- this.props.onSearch(query);
- },
+ renderSearchBox () {
+ const { component, query } = this.props;
- renderSearchBox() {
- if (this.props.component) {
+ if (component) {
// do not render search form on the project-level page
return null;
}
+
return (
<li>
<h6 className="bt-search-form-label">
Search by Task or Component
</h6>
- <input onChange={this.onSearch}
- value={this.props.query}
- ref="searchInput"
- className="js-search input-large"
- type="search"
- placeholder="Search"/>
+ <input
+ onChange={e => this.handleQueryChange(e.target.value)}
+ value={query}
+ ref="searchInput"
+ className="js-search input-large"
+ type="search"
+ placeholder="Search"/>
</li>
);
- },
-
- refresh(e) {
- e.preventDefault();
- this.props.onRefresh();
- },
+ }
- handleReset(e) {
- e.preventDefault();
- this.props.onReset();
- },
+ render () {
+ const {
+ loading,
+ component,
+ types,
+ status,
+ taskType,
+ currents,
+ minSubmittedAt,
+ maxExecutedAt
+ } = this.props;
- render() {
return (
<section className="big-spacer-top big-spacer-bottom">
<ul className="bt-search-form">
@@ -78,28 +113,28 @@ export default React.createClass({
Status
</h6>
<StatusFilter
- value={this.props.status}
- onChange={this.props.onStatusChange}/>
+ value={status}
+ onChange={this.handleStatusChange.bind(this)}/>
</li>
- {this.props.types.length > 1 && (
+ {types.length > 1 && (
<li>
<h6 className="bt-search-form-label">
Type
</h6>
<TypesFilter
- value={this.props.taskType}
- onChange={this.props.onTypeChange}
- types={this.props.types}/>
+ value={taskType}
+ types={types}
+ onChange={this.handleTypeChange.bind(this)}/>
</li>
)}
- {!this.props.component && (
+ {!component && (
<li>
<h6 className="bt-search-form-label">
Only Latest Analysis
</h6>
<CurrentsFilter
- value={this.props.currents}
- onChange={this.props.onCurrentsChange}/>
+ value={currents}
+ onChange={this.handleCurrentsChange.bind(this)}/>
</li>
)}
<li>
@@ -107,8 +142,9 @@ export default React.createClass({
Date
</h6>
<DateFilter
- value={this.props.date}
- onChange={this.props.onDateChange}/>
+ minSubmittedAt={minSubmittedAt}
+ maxExecutedAt={maxExecutedAt}
+ onChange={this.handleDateChange.bind(this)}/>
</li>
{this.renderSearchBox()}
@@ -116,15 +152,15 @@ export default React.createClass({
<li className="bt-search-form-right">
<button
ref="reloadButton"
- onClick={this.refresh}
- disabled={this.props.fetching}>
+ onClick={this.handleReload.bind(this)}
+ disabled={loading}>
{translate('reload')}
</button>
{' '}
<button
ref="resetButton"
- onClick={this.handleReset}
- disabled={this.props.fetching}>
+ onClick={this.handleReset.bind(this)}
+ disabled={loading}>
{translate('reset_verb')}
</button>
</li>
@@ -132,4 +168,4 @@ export default React.createClass({
</section>
);
}
-});
+}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/Stats.js b/server/sonar-web/src/main/js/apps/background-tasks/components/Stats.js
index 450a5098671..6fe1e555236 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/Stats.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/Stats.js
@@ -17,18 +17,32 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import React, { Component } from 'react';
+import React from 'react';
+import shallowCompare from 'react-addons-shallow-compare';
import { translate } from '../../../helpers/l10n';
-export default class Stats extends Component {
+export default class Stats extends React.Component {
+ static propTypes = {
+ failingCount: React.PropTypes.number,
+ pendingCount: React.PropTypes.number,
+ onShowFailing: React.PropTypes.func.isRequired,
+ onCancelAllPending: React.PropTypes.func.isRequired
+ };
+
+ shouldComponentUpdate (nextProps, nextState) {
+ return shallowCompare(this, nextProps, nextState);
+ }
+
handleCancelAllPending (e) {
e.preventDefault();
+ e.target.blur();
this.props.onCancelAllPending();
}
handleShowFailing (e) {
e.preventDefault();
+ e.target.blur();
this.props.onShowFailing();
}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/StatusFilter.js b/server/sonar-web/src/main/js/apps/background-tasks/components/StatusFilter.js
index c156d0fb1c6..5228ad42f16 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/StatusFilter.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/StatusFilter.js
@@ -23,7 +23,7 @@ import Select from 'react-select';
import { STATUSES } from '../constants';
import { translate } from '../../../helpers/l10n';
-export default function StatusFilter ({ value, onChange }) {
+const StatusFilter = ({ value, onChange }) => {
const options = [
{ value: STATUSES.ALL, label: translate('background_task.status.ALL') },
{ value: STATUSES.ALL_EXCEPT_PENDING, label: translate('background_task.status.ALL_EXCEPT_PENDING') },
@@ -43,4 +43,6 @@ export default function StatusFilter ({ value, onChange }) {
clearable={false}
searchable={false}/>
);
-}
+};
+
+export default StatusFilter;
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/Task.js b/server/sonar-web/src/main/js/apps/background-tasks/components/Task.js
index 87ce4286d0b..4ef215963b0 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/Task.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/Task.js
@@ -18,6 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
+import shallowCompare from 'react-addons-shallow-compare';
import TaskStatus from './TaskStatus';
import TaskComponent from './TaskComponent';
@@ -28,43 +29,61 @@ import TaskCancelButton from './TaskCancelButton';
import TaskLogsLink from './TaskLogsLink';
import { STATUSES } from './../constants';
-export default function Task ({ task, index, tasks, component, types, onCancelTask, onFilterTask }) {
- function handleFilterTask (task, e) {
+export default class Task extends React.Component {
+ static propTypes = {
+ task: React.PropTypes.object.isRequired,
+ index: React.PropTypes.number.isRequired,
+ tasks: React.PropTypes.array.isRequired,
+ component: React.PropTypes.object,
+ types: React.PropTypes.array.isRequired,
+ onCancelTask: React.PropTypes.func.isRequired,
+ onFilterTask: React.PropTypes.func.isRequired
+ };
+
+ shouldComponentUpdate (nextProps, nextState) {
+ return shallowCompare(this, nextProps, nextState);
+ }
+
+ handleFilterTask (task, e) {
e.preventDefault();
- onFilterTask(task);
+ this.props.onFilterTask(task);
}
- const prevTask = index > 0 ? tasks[index - 1] : null;
+ render () {
+ const { task, index, tasks, component, types, onCancelTask } = this.props;
- return (
- <tr>
- <TaskStatus task={task}/>
- <TaskComponent task={task} types={types}/>
- <TaskDay task={task} prevTask={prevTask}/>
- <TaskDate date={task.submittedAt} baseDate={task.submittedAt} format="LTS"/>
- <TaskDate date={task.startedAt} baseDate={task.submittedAt} format="LTS"/>
- <TaskDate date={task.executedAt} baseDate={task.submittedAt} format="LTS"/>
- <TaskExecutionTime task={task}/>
+ const prevTask = index > 0 ? tasks[index - 1] : null;
- <td className="thin nowrap text-right">
- {task.logs && (
- <TaskLogsLink task={task}/>
- )}
- {task.status === STATUSES.PENDING && (
- <TaskCancelButton task={task} onCancelTask={onCancelTask}/>
- )}
- </td>
+ return (
+ <tr>
+ <TaskStatus task={task}/>
+ <TaskComponent task={task} types={types}/>
+ <TaskDay task={task} prevTask={prevTask}/>
+ <TaskDate date={task.submittedAt} baseDate={task.submittedAt} format="LTS"/>
+ <TaskDate date={task.startedAt} baseDate={task.submittedAt} format="LTS"/>
+ <TaskDate date={task.executedAt} baseDate={task.submittedAt} format="LTS"/>
+ <TaskExecutionTime task={task}/>
- <td className="thin nowrap">
- {!component && (
- <a
- onClick={handleFilterTask.bind(this, task)}
- className="icon-filter icon-half-transparent spacer-left"
- href="#"
- title={`Show only "${task.componentName}" tasks`}
- data-toggle="tooltip"/>
- )}
- </td>
- </tr>
- );
+ <td className="thin nowrap text-right">
+ {task.logs && (
+ <TaskLogsLink task={task}/>
+ )}
+ {task.status === STATUSES.PENDING && (
+ <TaskCancelButton task={task} onCancelTask={onCancelTask}/>
+ )}
+ </td>
+
+ <td className="thin nowrap">
+ {!component && (
+ <a
+ onClick={this.handleFilterTask.bind(this, task)}
+ className="icon-filter icon-half-transparent spacer-left"
+ href="#"
+ title={`Show only "${task.componentName}" tasks`}
+ data-toggle="tooltip"/>
+ )}
+ </td>
+ </tr>
+ );
+ }
}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskCancelButton.js b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskCancelButton.js
index f5b793db0fb..d6469deba43 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskCancelButton.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskCancelButton.js
@@ -20,7 +20,7 @@
import React from 'react';
import { translate } from '../../../helpers/l10n';
-export default function TaskCancelButton ({ task, onCancelTask }) {
+const TaskCancelButton = ({ task, onCancelTask }) => {
function handleClick (e) {
e.preventDefault();
onCancelTask(task);
@@ -34,4 +34,6 @@ export default function TaskCancelButton ({ task, onCancelTask }) {
data-toggle="tooltip"
href="#"/>
);
-}
+};
+
+export default TaskCancelButton;
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.js b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.js
index d191442ff4a..581f5250d18 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDate.js
@@ -20,7 +20,7 @@
import moment from 'moment';
import React from 'react';
-export default function TaskDate ({ date, baseDate, format }) {
+const TaskDate = ({ date, baseDate, format }) => {
const m = moment(date);
const baseM = moment(baseDate);
const diff = (date && baseDate) ? m.diff(baseM, 'days') : 0;
@@ -34,4 +34,6 @@ export default function TaskDate ({ date, baseDate, format }) {
{date ? moment(date).format(format) : ''}
</td>
);
-}
+};
+
+export default TaskDate;
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.js b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.js
index 663cffa59be..60972ebf86a 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskDay.js
@@ -24,7 +24,7 @@ function isAnotherDay (a, b) {
return !moment(a).isSame(moment(b), 'day');
}
-export default function TaskDay ({ task, prevTask }) {
+const TaskDay = ({ task, prevTask }) => {
const shouldDisplay = !prevTask || isAnotherDay(task.submittedAt, prevTask.submittedAt);
return (
@@ -32,4 +32,6 @@ export default function TaskDay ({ task, prevTask }) {
{shouldDisplay ? moment(task.submittedAt).format('LL') : ''}
</td>
);
-}
+};
+
+export default TaskDay;
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskExecutionTime.js b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskExecutionTime.js
index 07e830d148a..98173c1af04 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskExecutionTime.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskExecutionTime.js
@@ -18,12 +18,14 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
-import { formatDuration } from './../helpers';
+import { formatDuration } from '../utils';
-export default function TaskExecutionTime ({ task }) {
+const TaskExecutionTime = ({ task }) => {
return (
<td className="thin nowrap text-right">
{formatDuration(task.executionTimeMs)}
</td>
);
-}
+};
+
+export default TaskExecutionTime;
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskLogsLink.js b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskLogsLink.js
index 2f5893e8bed..e05dfb1f2cb 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskLogsLink.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskLogsLink.js
@@ -20,7 +20,7 @@
import React from 'react';
import { translate } from '../../../helpers/l10n';
-export default function TaskLogsLink ({ task }) {
+const TaskLogsLink = ({ task }) => {
const url = `${window.baseUrl}/api/ce/logs?taskId=${task.id}`;
return (
@@ -30,4 +30,6 @@ export default function TaskLogsLink ({ task }) {
{translate('background_tasks.logs')}
</a>
);
-}
+};
+
+export default TaskLogsLink;
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskStatus.js b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskStatus.js
index 060e397a137..69e4ad97cf1 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/TaskStatus.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/TaskStatus.js
@@ -23,7 +23,7 @@ import { STATUSES } from './../constants';
import PendingIcon from '../../../components/shared/pending-icon';
import { translate } from '../../../helpers/l10n';
-export default function TaskStatus ({ task }) {
+const TaskStatus = ({ task }) => {
let inner;
switch (task.status) {
@@ -47,4 +47,6 @@ export default function TaskStatus ({ task }) {
}
return <td className="thin spacer-right">{inner}</td>;
-}
+};
+
+export default TaskStatus;
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/Tasks.js b/server/sonar-web/src/main/js/apps/background-tasks/components/Tasks.js
index c086e2a110d..0cb1ddf0822 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/Tasks.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/Tasks.js
@@ -18,14 +18,36 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import React from 'react';
+import shallowCompare from 'react-addons-shallow-compare';
+import classNames from 'classnames';
import Task from './Task';
import { translate } from '../../../helpers/l10n';
-export default function Tasks ({ tasks, component, types, onCancelTask, onFilterTask }) {
- return (
- <table className="data zebra zebra-hover background-tasks">
- <thead>
+export default class Tasks extends React.Component {
+ static propTypes = {
+ tasks: React.PropTypes.array.isRequired,
+ component: React.PropTypes.object,
+ types: React.PropTypes.array.isRequired,
+ loading: React.PropTypes.bool.isRequired,
+ onCancelTask: React.PropTypes.func.isRequired,
+ onFilterTask: React.PropTypes.func.isRequired
+ };
+
+ shouldComponentUpdate (nextProps, nextState) {
+ return shallowCompare(this, nextProps, nextState);
+ }
+
+ render () {
+ const { tasks, component, types, loading, onCancelTask, onFilterTask } = this.props;
+
+ const className = classNames('data zebra zebra-hover background-tasks', {
+ 'new-loading': loading
+ });
+
+ return (
+ <table className={className}>
+ <thead>
<tr>
<th>&nbsp;</th>
<th>&nbsp;</th>
@@ -36,8 +58,8 @@ export default function Tasks ({ tasks, component, types, onCancelTask, onFilter
<th>{translate('background_tasks.table.duration')}</th>
<th>&nbsp;</th>
</tr>
- </thead>
- <tbody>
+ </thead>
+ <tbody>
{tasks.map((task, index, tasks) => (
<Task
key={task.id}
@@ -49,7 +71,8 @@ export default function Tasks ({ tasks, component, types, onCancelTask, onFilter
onCancelTask={onCancelTask}
onFilterTask={onFilterTask}/>
))}
- </tbody>
- </table>
- );
+ </tbody>
+ </table>
+ );
+ }
}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/TypesFilter.js b/server/sonar-web/src/main/js/apps/background-tasks/components/TypesFilter.js
index 5e6696a468b..825ba90fb6a 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/components/TypesFilter.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/components/TypesFilter.js
@@ -23,7 +23,7 @@ import Select from 'react-select';
import { ALL_TYPES } from '../constants';
import { translate } from '../../../helpers/l10n';
-export default function TypesFilter ({ value, onChange, types }) {
+const TypesFilter = ({ value, onChange, types }) => {
const options = types.map(t => {
return {
value: t,
@@ -45,4 +45,6 @@ export default function TypesFilter ({ value, onChange, types }) {
clearable={false}
searchable={false}/>
);
-}
+};
+
+export default TypesFilter;
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/constants.js b/server/sonar-web/src/main/js/apps/background-tasks/constants.js
index 7915c37540a..ed5f571d2a8 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/constants.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/constants.js
@@ -44,7 +44,8 @@ export const DEFAULT_FILTERS = {
status: STATUSES.ALL_EXCEPT_PENDING,
taskType: ALL_TYPES,
currents: CURRENTS.ALL,
- date: {},
+ minSubmittedAt: '',
+ maxExecutedAt: '',
query: ''
};
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/containers/BackgroundTasksAppContainer.js b/server/sonar-web/src/main/js/apps/background-tasks/containers/BackgroundTasksAppContainer.js
deleted file mode 100644
index 478c53f2dfc..00000000000
--- a/server/sonar-web/src/main/js/apps/background-tasks/containers/BackgroundTasksAppContainer.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { connect } from 'react-redux';
-
-import Main from '../components/BackgroundTasksApp';
-import { initApp } from '../store/actions';
-
-function mapStateToProps (state) {
- return {
- tasks: state.tasks
- };
-}
-
-function mapDispatchToProps (dispatch) {
- return {
- initApp: component => dispatch(initApp(component))
- };
-}
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(Main);
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/containers/SearchContainer.js b/server/sonar-web/src/main/js/apps/background-tasks/containers/SearchContainer.js
deleted file mode 100644
index 6314eab7cee..00000000000
--- a/server/sonar-web/src/main/js/apps/background-tasks/containers/SearchContainer.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { connect } from 'react-redux';
-
-import Search from '../components/Search';
-import { filterTasks, search } from '../store/actions';
-import { STATUSES, CURRENTS, DEFAULT_FILTERS } from '../constants';
-
-function mapStateToProps (state) {
- return {
- fetching: state.fetching,
- status: state.status,
- currents: state.currents,
- date: state.date,
- query: state.query,
- taskType: state.taskType,
- types: state.types,
- component: state.component
- };
-}
-
-function updateStatusQuery (status) {
- if (status === STATUSES.PENDING) {
- return { status, currents: CURRENTS.ALL };
- } else {
- return { status };
- }
-}
-
-function mapDispatchToProps (dispatch) {
- return {
- onRefresh: () => dispatch(filterTasks()),
- onReset: () => dispatch(filterTasks(DEFAULT_FILTERS)),
- onStatusChange: status => dispatch(filterTasks(updateStatusQuery(status))),
- onTypeChange: taskType => dispatch(filterTasks({ taskType })),
- onCurrentsChange: currents => dispatch(filterTasks({ currents, status: STATUSES.ALL_EXCEPT_PENDING })),
- onDateChange: date => dispatch(filterTasks({ date })),
- onSearch: query => dispatch(search(query))
- };
-}
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(Search);
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/containers/StatsContainer.js b/server/sonar-web/src/main/js/apps/background-tasks/containers/StatsContainer.js
deleted file mode 100644
index 510295faf54..00000000000
--- a/server/sonar-web/src/main/js/apps/background-tasks/containers/StatsContainer.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { connect } from 'react-redux';
-
-import Stats from '../components/Stats';
-import { filterTasks, cancelAllPending } from '../store/actions';
-import { STATUSES, CURRENTS, DEFAULT_FILTERS } from '../constants';
-
-function mapStateToProps (state) {
- return {
- pendingCount: state.pendingCount,
- failingCount: state.failingCount,
- component: state.component
- };
-}
-
-function mapDispatchToProps (dispatch) {
- return {
- onShowFailing: () => dispatch(filterTasks({
- ...DEFAULT_FILTERS,
- status: STATUSES.FAILED,
- currents: CURRENTS.ONLY_CURRENTS
- })),
- onCancelAllPending: () => dispatch(cancelAllPending())
- };
-}
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(Stats);
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/containers/TasksContainer.js b/server/sonar-web/src/main/js/apps/background-tasks/containers/TasksContainer.js
deleted file mode 100644
index 783b304934e..00000000000
--- a/server/sonar-web/src/main/js/apps/background-tasks/containers/TasksContainer.js
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { connect } from 'react-redux';
-
-import Tasks from '../components/Tasks';
-import { cancelTask, filterTasks } from '../store/actions';
-import { DEFAULT_FILTERS } from '../constants';
-
-function mapStateToProps (state) {
- return {
- fetching: state.fetching,
- tasks: state.tasks,
- component: state.component,
- types: state.types
- };
-}
-
-function mapDispatchToProps (dispatch) {
- return {
- onCancelTask: task => dispatch(cancelTask(task)),
- onFilterTask: task => dispatch(filterTasks(Object.assign({}, DEFAULT_FILTERS, { query: task.componentKey })))
- };
-}
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(Tasks);
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/store/actions.js b/server/sonar-web/src/main/js/apps/background-tasks/store/actions.js
deleted file mode 100644
index 095f659f0ca..00000000000
--- a/server/sonar-web/src/main/js/apps/background-tasks/store/actions.js
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import _ from 'underscore';
-import { getTypes, getActivity, getStatus, cancelAllTasks, cancelTask as cancelTaskAPI } from '../../../api/ce';
-
-import { STATUSES, ALL_TYPES, CURRENTS, DEBOUNCE_DELAY } from '../constants';
-
-export const INIT = 'INIT';
-export const REQUEST_TASKS = 'REQUEST_TASKS';
-export const RECEIVE_TASKS = 'RECEIVE_TASKS';
-export const UPDATE_QUERY = 'UPDATE_QUERY';
-export const RECEIVE_STATS = 'RECEIVE_STATS';
-export const CANCEL_ALL_PENDING = 'CANCEL_ALL_PENDING';
-export const CANCEL_TASK = 'CANCEL_TASK';
-export const FINISH_CANCEL_TASK = 'FINISH_CANCEL_TASK';
-
-export function init (component, types) {
- return {
- type: INIT,
- component,
- types
- };
-}
-
-export function requestTasks (filters) {
- return {
- type: REQUEST_TASKS,
- ...filters
- };
-}
-
-export function receiveTasks (tasks) {
- return {
- type: RECEIVE_TASKS,
- tasks
- };
-}
-
-export function updateQuery (query) {
- return {
- type: UPDATE_QUERY,
- query
- };
-}
-
-export function receiveStats ({ pendingCount, failingCount }) {
- return {
- type: RECEIVE_STATS,
- pendingCount,
- failingCount
- };
-}
-
-export function cancelAllPendingAction () {
- return {
- type: CANCEL_ALL_PENDING
- };
-}
-
-export function cancelTaskAction (task) {
- return {
- type: CANCEL_TASK,
- task
- };
-}
-
-export function finishCancelTaskAction (task) {
- return {
- type: FINISH_CANCEL_TASK,
- task
- };
-}
-
-function mapFiltersToParameters (filters = {}) {
- const parameters = {};
-
- if (filters.status === STATUSES.ALL) {
- parameters.status = [
- STATUSES.PENDING,
- STATUSES.IN_PROGRESS,
- STATUSES.SUCCESS,
- STATUSES.FAILED,
- STATUSES.CANCELED
- ].join();
- } else if (filters.status === STATUSES.ALL_EXCEPT_PENDING) {
- parameters.status = [
- STATUSES.IN_PROGRESS,
- STATUSES.SUCCESS,
- STATUSES.FAILED,
- STATUSES.CANCELED
- ].join();
- } else {
- parameters.status = filters.status;
- }
-
- if (filters.taskType !== ALL_TYPES) {
- parameters.type = filters.taskType;
- }
-
- if (filters.currents !== CURRENTS.ALL) {
- parameters.onlyCurrents = true;
- }
-
- if (filters.date.minSubmittedAt) {
- parameters.minSubmittedAt = filters.date.minSubmittedAt;
- }
-
- if (filters.date.maxExecutedAt) {
- parameters.maxExecutedAt = filters.date.maxExecutedAt;
- }
-
- if (filters.query) {
- parameters.componentQuery = filters.query;
- }
-
- if (filters.lastPage !== 1) {
- parameters.p = filters.lastPage;
- }
-
- return parameters;
-}
-
-function fetchTasks (filters) {
- return (dispatch, getState) => {
- const { component } = getState();
- const parameters = mapFiltersToParameters(filters);
-
- if (component) {
- parameters.componentId = component.id;
- }
-
- dispatch(requestTasks(filters));
-
- return Promise.all([
- getActivity(parameters),
- getStatus(parameters.componentId)
- ]).then(responses => {
- const [activity, status] = responses;
- const tasks = activity.tasks;
-
- dispatch(receiveTasks(tasks));
-
- const pendingCount = status.pending;
- const failingCount = status.failing;
-
- dispatch(receiveStats({ pendingCount, failingCount }));
- });
- };
-}
-
-export function filterTasks (overriddenFilters) {
- return (dispatch, getState) => {
- const { status, taskType, currents, date, query } = getState();
- const filters = { status, taskType, currents, date, query };
- const finalFilters = { ...filters, ...overriddenFilters };
-
- dispatch(fetchTasks(finalFilters));
- };
-}
-
-const debouncedFilter = _.debounce((dispatch, overriddenFilters) => {
- dispatch(filterTasks(overriddenFilters));
-}, DEBOUNCE_DELAY);
-
-export function search (query) {
- return dispatch => {
- dispatch(updateQuery(query));
- debouncedFilter(dispatch, { query });
- };
-}
-
-export function cancelAllPending () {
- return dispatch => {
- dispatch(cancelAllPendingAction());
- cancelAllTasks().then(() => dispatch(filterTasks()));
- };
-}
-
-export function cancelTask (task) {
- return dispatch => {
- dispatch(cancelTaskAction(task));
- cancelTaskAPI(task.id).then(nextTask => dispatch(finishCancelTaskAction(nextTask)));
- };
-}
-
-export function initApp (component) {
- return dispatch => {
- getTypes().then(types => {
- dispatch(init(component, types));
- dispatch(filterTasks());
- });
- };
-}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/store/reducers.js b/server/sonar-web/src/main/js/apps/background-tasks/store/reducers.js
deleted file mode 100644
index 5ac2f53ee93..00000000000
--- a/server/sonar-web/src/main/js/apps/background-tasks/store/reducers.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import {
- INIT,
- REQUEST_TASKS,
- RECEIVE_TASKS,
- UPDATE_QUERY,
- RECEIVE_STATS,
- CANCEL_ALL_PENDING,
- FINISH_CANCEL_TASK
-} from './actions';
-import { DEFAULT_FILTERS } from '../constants';
-
-export const initialState = {
- fetching: false,
- tasks: [],
-
- types: [],
-
- // filters
- ...DEFAULT_FILTERS,
-
- // stats
- pendingCount: 0,
- failingCount: 0
-};
-
-function updateTask (tasks, newTask) {
- return tasks.map(task => task.id === newTask.id ? newTask : task);
-}
-
-export default function (state = initialState, action = {}) {
- switch (action.type) {
- case INIT:
- return {
- ...state,
- component: action.component,
- types: action.types
- };
- case REQUEST_TASKS:
- return {
- ...state,
- fetching: true,
- status: action.status,
- currents: action.currents,
- date: action.date,
- query: action.query,
- taskType: action.taskType
- };
- case RECEIVE_TASKS:
- return {
- ...state,
- fetching: false,
- tasks: action.tasks
- };
- case UPDATE_QUERY:
- return {
- ...state,
- query: action.query
- };
- case RECEIVE_STATS:
- return {
- ...state,
- pendingCount: action.pendingCount,
- failingCount: action.failingCount
- };
- case CANCEL_ALL_PENDING:
- return {
- ...state,
- fetching: true
- };
- case FINISH_CANCEL_TASK:
- return {
- ...state,
- tasks: updateTask(state.tasks, action.task)
- };
- default:
- return state;
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/background-tasks/helpers.js b/server/sonar-web/src/main/js/apps/background-tasks/utils.js
index a3c797b6985..97207fa9864 100644
--- a/server/sonar-web/src/main/js/apps/background-tasks/helpers.js
+++ b/server/sonar-web/src/main/js/apps/background-tasks/utils.js
@@ -17,6 +17,61 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { STATUSES, ALL_TYPES, CURRENTS } from './constants';
+
+export function updateTask (tasks, newTask) {
+ return tasks.map(task => task.id === newTask.id ? newTask : task);
+}
+
+export function mapFiltersToParameters (filters = {}) {
+ const parameters = {};
+
+ if (filters.status === STATUSES.ALL) {
+ parameters.status = [
+ STATUSES.PENDING,
+ STATUSES.IN_PROGRESS,
+ STATUSES.SUCCESS,
+ STATUSES.FAILED,
+ STATUSES.CANCELED
+ ].join();
+ } else if (filters.status === STATUSES.ALL_EXCEPT_PENDING) {
+ parameters.status = [
+ STATUSES.IN_PROGRESS,
+ STATUSES.SUCCESS,
+ STATUSES.FAILED,
+ STATUSES.CANCELED
+ ].join();
+ } else {
+ parameters.status = filters.status;
+ }
+
+ if (filters.taskType !== ALL_TYPES) {
+ parameters.type = filters.taskType;
+ }
+
+ if (filters.currents !== CURRENTS.ALL) {
+ parameters.onlyCurrents = true;
+ }
+
+ if (filters.minSubmittedAt) {
+ parameters.minSubmittedAt = filters.minSubmittedAt;
+ }
+
+ if (filters.maxExecutedAt) {
+ parameters.maxExecutedAt = filters.maxExecutedAt;
+ }
+
+ if (filters.query) {
+ parameters.componentQuery = filters.query;
+ }
+
+ if (filters.lastPage !== 1) {
+ parameters.p = filters.lastPage;
+ }
+
+ return parameters;
+}
+
const ONE_SECOND = 1000;
const ONE_MINUTE = 60 * ONE_SECOND;