Skip to content

Commit

Permalink
[#2102] See number of processed projects in overview
Browse files Browse the repository at this point in the history
  • Loading branch information
KasperBrandt committed Apr 15, 2016
1 parent 9b7ee98 commit eef346f
Show file tree
Hide file tree
Showing 5 changed files with 168 additions and 15 deletions.
1 change: 1 addition & 0 deletions akvo/rest/serializers/iati_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class IatiExportSerializer(BaseRSRSerializer):

user_name = serializers.Field(source='user.get_full_name')
status_label = serializers.Field(source='show_status')
processed_projects = serializers.Field(source='processed_projects')

class Meta:
model = IatiExport
Expand Down
7 changes: 7 additions & 0 deletions akvo/rsr/models/iati_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,10 @@ def create_iati_file(self):
else:
# No projects, so update the status to 'Cancelled'
self.update_status(4)

def processed_projects(self):
"""
Find the number of processed projects of this IATI export. Generally, for completed
exports, this number will be the same as the number of total projects.
"""
return self.iati_activity_exports.filter(status=2).count()
84 changes: 77 additions & 7 deletions akvo/rsr/static/scripts-src/my-iati.js
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ function loadComponents() {

return (
React.DOM.tr(null,
React.DOM.td(null, React.DOM.input( {type:"checkbox", onClick:this.switchAction} )),
React.DOM.td(null, React.DOM.input( {type:"checkbox", onClick:this.switchAction, checked:this.props.selected} )),
React.DOM.td(null, this.props.project.id),
React.DOM.td(null,
this.props.project.title || '\<' + cap(i18n.untitled) + ' ' + i18n.project + '\>',React.DOM.br(null),
Expand All @@ -304,9 +304,11 @@ function loadComponents() {
if (this.props.projects.length > 0) {
// In case there are projets, show a table overview of the projects.
projects = this.props.projects.map(function(project) {
var selected = thisTable.props.selectedProjects.indexOf(project.id) > -1;
return React.createElement(ProjectRow, {
key: project.id,
project: project,
selected: selected,
switchProject: thisTable.props.switchProject
});
});
Expand Down Expand Up @@ -422,6 +424,7 @@ function loadComponents() {
// Show a table of projects when the data has been loaded
initOrTable = React.createElement(ProjectsTable, {
projects: this.state.allProjects.results,
selectedProjects: this.state.selectedProjects,
switchProject: this.switchProject
});
}
Expand Down Expand Up @@ -498,11 +501,19 @@ function loadComponents() {
}
},

renderNumberOfProjects: function() {
if (this.props.exp.status !== 2) {
return this.props.exp.projects.length;
} else {
return this.props.exp.projects.length + ' (' + this.props.exp.processed_projects + ' ' + i18n.processed + ')';
}
},

render: function() {
return (
React.DOM.tr( {className:this.renderRowClass()},
React.DOM.td(null, this.props.exp.status_label),
React.DOM.td(null, this.props.exp.projects.length),
React.DOM.td(null, this.renderNumberOfProjects()),
React.DOM.td(null, this.props.exp.user_name),
React.DOM.td(null, displayDate(this.props.exp.created_at)),
React.DOM.td(null, 'v' + this.props.exp.version),
Expand Down Expand Up @@ -566,6 +577,7 @@ function loadComponents() {
exports: null,
initializing: true,
refreshing: false,
refreshingIn: 0,
actionInProgress: false
};
},
Expand All @@ -584,13 +596,19 @@ function loadComponents() {
initializing: false,
exports: response
});
if (thisApp.pendingOrInProgress()) {
thisApp.startCountDown();
}
}

function refreshingSuccess(response) {
thisApp.setState({
refreshing: false,
exports: response
});
if (thisApp.pendingOrInProgress()) {
thisApp.startCountDown();
}
}

if (!first_time) {
Expand All @@ -599,7 +617,26 @@ function loadComponents() {
} else {
apiCall('GET', url, {}, firstTimeSuccess);
}
},
},

startCountDown: function() {
// Set the countdown for refreshing the table to start at 10 seconds
this.setState({refreshingIn: 10});

// Start ticking down
var thisApp = this,
intervalId = setInterval(tick, 1000);

function tick() {
var newRefreshing = thisApp.state.refreshingIn - 1;
thisApp.setState({refreshingIn: newRefreshing});
if (newRefreshing === 0) {
// Once done, reload the exports
clearInterval(intervalId);
thisApp.loadExports(false);
}
}
},

publicFile: function() {
if (this.state.exports === null) {
Expand All @@ -624,6 +661,21 @@ function loadComponents() {
}
return null;
},

pendingOrInProgress: function() {
// Check to see whether there is at least one export pending or in progress.
if (!this.state.initializing) {
for (var i = 0; i < this.state.exports.results.length; i++) {
var exp = this.state.exports.results[i];
if (exp.status < 3) {
return true;
}
}
return false;
} else {
return false;
}
},

setPublic: function(exportId) {
// Basically what we do is to set this export to public first, and then set all
Expand Down Expand Up @@ -672,23 +724,41 @@ function loadComponents() {
this.setState({actionInProgress: true});
apiCall('PATCH', exportUrl.replace('{iati_export}', exportId), publicData, exportUpdated);
},

renderRefreshing: function() {
if (this.state.refreshing) {
return (
React.DOM.span( {className:"small"},
React.DOM.i( {className:"fa fa-spin fa-spinner"} ), " ", cap(i18n.refreshing) + ' ' + i18n.iati_exports + '...'
)
);
} else if (this.pendingOrInProgress()) {
return (
React.DOM.span( {className:"small"},
React.DOM.i( {className:"fa fa-spin fa-spinner"} ), " ", cap(i18n.pending_or_progress) + '. ' + cap(i18n.refreshing) + ' ' + i18n.in + ' ' + this.state.refreshingIn + ' ' + i18n.seconds + '...'
)
);
} else {
return (
React.DOM.span(null )
);
}
},

render: function() {
var initOrTable,
refreshing,
exportCount,
exportCountString,
lastExportDescription;

refreshing = this.state.refreshing ? React.DOM.span( {className:"small"}, React.DOM.i( {className:"fa fa-spin fa-spinner"} ),' ' + cap(i18n.refreshing) + ' ' + i18n.iati_exports + '...') : React.DOM.span(null );
exportCount = !this.state.initializing ? this.state.exports.count : null;
exportCountString = (exportCount !== null && exportCount > 0) ? ' ' + this.state.exports.count + ' ' : ' ';

if (this.state.initializing) {
// Only show a message that data is being loading when initializing
initOrTable = React.DOM.span( {className:"small"}, React.DOM.i( {className:"fa fa-spin fa-spinner"}),' ' + cap(i18n.loading) + ' ' + i18n.last + ' ' + i18n.iati_exports + '...');
} else {
// Show a table of existing imports (max 10) when the data has been loaded
// Show a table of existing imports when the data has been loaded
initOrTable = React.createElement(ExportsTable, {
exports: this.state.exports,
refreshing: this.state.refreshing,
Expand All @@ -709,7 +779,7 @@ function loadComponents() {
React.DOM.div(null,
React.DOM.h4( {className:"topMargin"}, cap(i18n.last) + exportCountString + i18n.iati_exports),
lastExportDescription,
refreshing,
this.renderRefreshing(),
initOrTable
)
);
Expand Down
84 changes: 77 additions & 7 deletions akvo/rsr/static/scripts-src/my-iati.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ function loadComponents() {

return (
<tr>
<td><input type="checkbox" onClick={this.switchAction} /></td>
<td><input type="checkbox" onClick={this.switchAction} checked={this.props.selected} /></td>
<td>{this.props.project.id}</td>
<td>
{this.props.project.title || '\<' + cap(i18n.untitled) + ' ' + i18n.project + '\>'}<br/>
Expand All @@ -304,9 +304,11 @@ function loadComponents() {
if (this.props.projects.length > 0) {
// In case there are projets, show a table overview of the projects.
projects = this.props.projects.map(function(project) {
var selected = thisTable.props.selectedProjects.indexOf(project.id) > -1;
return React.createElement(ProjectRow, {
key: project.id,
project: project,
selected: selected,
switchProject: thisTable.props.switchProject
});
});
Expand Down Expand Up @@ -422,6 +424,7 @@ function loadComponents() {
// Show a table of projects when the data has been loaded
initOrTable = React.createElement(ProjectsTable, {
projects: this.state.allProjects.results,
selectedProjects: this.state.selectedProjects,
switchProject: this.switchProject
});
}
Expand Down Expand Up @@ -498,11 +501,19 @@ function loadComponents() {
}
},

renderNumberOfProjects: function() {
if (this.props.exp.status !== 2) {
return this.props.exp.projects.length;
} else {
return this.props.exp.projects.length + ' (' + this.props.exp.processed_projects + ' ' + i18n.processed + ')';
}
},

render: function() {
return (
<tr className={this.renderRowClass()}>
<td>{this.props.exp.status_label}</td>
<td>{this.props.exp.projects.length}</td>
<td>{this.renderNumberOfProjects()}</td>
<td>{this.props.exp.user_name}</td>
<td>{displayDate(this.props.exp.created_at)}</td>
<td>{'v' + this.props.exp.version}</td>
Expand Down Expand Up @@ -566,6 +577,7 @@ function loadComponents() {
exports: null,
initializing: true,
refreshing: false,
refreshingIn: 0,
actionInProgress: false
};
},
Expand All @@ -584,13 +596,19 @@ function loadComponents() {
initializing: false,
exports: response
});
if (thisApp.pendingOrInProgress()) {
thisApp.startCountDown();
}
}

function refreshingSuccess(response) {
thisApp.setState({
refreshing: false,
exports: response
});
if (thisApp.pendingOrInProgress()) {
thisApp.startCountDown();
}
}

if (!first_time) {
Expand All @@ -599,7 +617,26 @@ function loadComponents() {
} else {
apiCall('GET', url, {}, firstTimeSuccess);
}
},
},

startCountDown: function() {
// Set the countdown for refreshing the table to start at 10 seconds
this.setState({refreshingIn: 10});

// Start ticking down
var thisApp = this,
intervalId = setInterval(tick, 1000);

function tick() {
var newRefreshing = thisApp.state.refreshingIn - 1;
thisApp.setState({refreshingIn: newRefreshing});
if (newRefreshing === 0) {
// Once done, reload the exports
clearInterval(intervalId);
thisApp.loadExports(false);
}
}
},

publicFile: function() {
if (this.state.exports === null) {
Expand All @@ -624,6 +661,21 @@ function loadComponents() {
}
return null;
},

pendingOrInProgress: function() {
// Check to see whether there is at least one export pending or in progress.
if (!this.state.initializing) {
for (var i = 0; i < this.state.exports.results.length; i++) {
var exp = this.state.exports.results[i];
if (exp.status < 3) {
return true;
}
}
return false;
} else {
return false;
}
},

setPublic: function(exportId) {
// Basically what we do is to set this export to public first, and then set all
Expand Down Expand Up @@ -672,23 +724,41 @@ function loadComponents() {
this.setState({actionInProgress: true});
apiCall('PATCH', exportUrl.replace('{iati_export}', exportId), publicData, exportUpdated);
},

renderRefreshing: function() {
if (this.state.refreshing) {
return (
<span className="small">
<i className="fa fa-spin fa-spinner" /> {cap(i18n.refreshing) + ' ' + i18n.iati_exports + '...'}
</span>
);
} else if (this.pendingOrInProgress()) {
return (
<span className="small">
<i className="fa fa-spin fa-spinner" /> {cap(i18n.pending_or_progress) + '. ' + cap(i18n.refreshing) + ' ' + i18n.in + ' ' + this.state.refreshingIn + ' ' + i18n.seconds + '...'}
</span>
);
} else {
return (
<span />
);
}
},

render: function() {
var initOrTable,
refreshing,
exportCount,
exportCountString,
lastExportDescription;

refreshing = this.state.refreshing ? <span className="small"><i className="fa fa-spin fa-spinner" />{' ' + cap(i18n.refreshing) + ' ' + i18n.iati_exports + '...'}</span> : <span />;
exportCount = !this.state.initializing ? this.state.exports.count : null;
exportCountString = (exportCount !== null && exportCount > 0) ? ' ' + this.state.exports.count + ' ' : ' ';

if (this.state.initializing) {
// Only show a message that data is being loading when initializing
initOrTable = <span className="small"><i className="fa fa-spin fa-spinner"/>{' ' + cap(i18n.loading) + ' ' + i18n.last + ' ' + i18n.iati_exports + '...'}</span>;
} else {
// Show a table of existing imports (max 10) when the data has been loaded
// Show a table of existing imports when the data has been loaded
initOrTable = React.createElement(ExportsTable, {
exports: this.state.exports,
refreshing: this.state.refreshing,
Expand All @@ -709,7 +779,7 @@ function loadComponents() {
<div>
<h4 className="topMargin">{cap(i18n.last) + exportCountString + i18n.iati_exports}</h4>
{lastExportDescription}
{refreshing}
{this.renderRefreshing()}
{initOrTable}
</div>
);
Expand Down
Loading

0 comments on commit eef346f

Please sign in to comment.