Edit functionality working, fixed restart lock issue

pull/97/head
Piero Toffanin 2017-02-10 12:28:32 -05:00
rodzic 65b640c0c7
commit 49f3ca6937
4 zmienionych plików z 57 dodań i 17 usunięć

Wyświetl plik

@ -237,7 +237,7 @@ class Task(models.Model):
try: try:
info = self.processing_node.get_task_info(self.uuid) info = self.processing_node.get_task_info(self.uuid)
uuid_still_exists = info['uuid'] == self.uuid uuid_still_exists = info['uuid'] == self.uuid
except ProcessingError: except ProcessingException:
pass pass
if uuid_still_exists: if uuid_still_exists:
@ -257,7 +257,7 @@ class Task(models.Model):
self.pending_action = None self.pending_action = None
self.save() self.save()
else: else:
raise ProcessingError("Cannot restart a task that has no processing node or UUID") raise ProcessingError("Cannot restart a task that has no processing node")
elif self.pending_action == pending_actions.REMOVE: elif self.pending_action == pending_actions.REMOVE:
logger.info("Removing {}".format(self)) logger.info("Removing {}".format(self))

Wyświetl plik

@ -13,7 +13,8 @@ class EditTaskDialog extends React.Component {
show: React.PropTypes.bool, show: React.PropTypes.bool,
task: React.PropTypes.object.isRequired, task: React.PropTypes.object.isRequired,
onHide: React.PropTypes.func, onHide: React.PropTypes.func,
onShow: React.PropTypes.func onShow: React.PropTypes.func,
saveAction: React.PropTypes.func.isRequired
}; };
constructor(props){ constructor(props){
@ -61,7 +62,9 @@ class EditTaskDialog extends React.Component {
save(taskInfo){ save(taskInfo){
if (this.state.editTaskFormLoaded){ if (this.state.editTaskFormLoaded){
console.log(taskInfo); return this.props.saveAction(taskInfo);
}else{
return $.Deferred().reject(new Error("The form has not loaded, please wait."));
} }
} }

Wyświetl plik

@ -30,7 +30,7 @@ class EditTaskForm extends React.Component {
this.state = { this.state = {
error: "", error: "",
name: props.task !== null ? props.task.name : "", name: props.task !== null ? (props.task.name || "") : "",
advancedOptions: props.task !== null ? props.task.options.length > 0 : false, advancedOptions: props.task !== null ? props.task.options.length > 0 : false,
loadedProcessingNodes: false, loadedProcessingNodes: false,
selectedNode: null, selectedNode: null,
@ -175,7 +175,8 @@ class EditTaskForm extends React.Component {
} }
getOptions(){ getOptions(){
return Object.values(this.options) if (!this.state.advancedOptions) return [];
else return Object.values(this.options)
.map(option => { .map(option => {
return { return {
name: option.props.name, name: option.props.name,
@ -200,10 +201,10 @@ class EditTaskForm extends React.Component {
options.forEach(opt => { options.forEach(opt => {
if (!opt.defaultValue){ if (!opt.defaultValue){
let taskOpt; let taskOpt;
if (task){ if (task && Array.isArray(task.options)){
taskOpt = task.options.find(to => to.name == opt.name); taskOpt = task.options.find(to => to.name == opt.name);
} }
if (taskOpt){ if (taskOpt){
opt.defaultValue = opt.value; opt.defaultValue = opt.value;
opt.value = taskOpt.value; opt.value = taskOpt.value;

Wyświetl plik

@ -27,6 +27,8 @@ class TaskListItem extends React.Component {
this.toggleExpanded = this.toggleExpanded.bind(this); this.toggleExpanded = this.toggleExpanded.bind(this);
this.consoleOutputUrl = this.consoleOutputUrl.bind(this); this.consoleOutputUrl = this.consoleOutputUrl.bind(this);
this.stopEditing = this.stopEditing.bind(this); this.stopEditing = this.stopEditing.bind(this);
this.startEditing = this.startEditing.bind(this);
this.updateTask = this.updateTask.bind(this);
} }
shouldRefresh(){ shouldRefresh(){
@ -173,10 +175,38 @@ class TaskListItem extends React.Component {
} }
} }
startEditing(){
this.setState({editing: true});
}
stopEditing(){ stopEditing(){
this.setState({editing: false}); this.setState({editing: false});
} }
updateTask(taskInfo){
let d = $.Deferred();
taskInfo.uuid = ""; // TODO: we could reuse the UUID so that images don't need to be re-uploaded! This needs changes on node-odm as well.
taskInfo.processing_node = taskInfo.selectedNode.id;
delete(taskInfo.selectedNode);
$.ajax({
url: `/api/projects/${this.state.task.project}/tasks/${this.state.task.id}/`,
contentType: 'application/json',
data: JSON.stringify(taskInfo),
dataType: 'json',
type: 'PATCH'
}).done((json) => {
this.setState({task: json});
d.resolve();
}).fail(() => {
d.reject(new Error("Could not update task information. Plese try again."));
});
return d;
}
render() { render() {
const task = this.state.task; const task = this.state.task;
const name = task.name !== null ? task.name : `Task #${task.id}`; const name = task.name !== null ? task.name : `Task #${task.id}`;
@ -204,6 +234,14 @@ class TaskListItem extends React.Component {
}); });
} }
// Ability to change options
if ([statusCodes.FAILED, statusCodes.COMPLETED, statusCodes.CANCELED].indexOf(task.status) !== -1 ||
(!task.processing_node)){
addActionButton("Edit", "btn-primary", "glyphicon glyphicon-pencil", () => {
this.startEditing();
});
}
if ([statusCodes.QUEUED, statusCodes.RUNNING, null].indexOf(task.status) !== -1 && if ([statusCodes.QUEUED, statusCodes.RUNNING, null].indexOf(task.status) !== -1 &&
task.processing_node){ task.processing_node){
addActionButton("Cancel", "btn-primary", "glyphicon glyphicon-remove-circle", this.genActionApiCall("cancel")); addActionButton("Cancel", "btn-primary", "glyphicon glyphicon-remove-circle", this.genActionApiCall("cancel"));
@ -220,13 +258,6 @@ class TaskListItem extends React.Component {
)); ));
} }
// Ability to change options
if ([statusCodes.FAILED, statusCodes.COMPLETED, statusCodes.CANCELED, null].indexOf(task.status) !== -1){
addActionButton("Edit", "btn-primary", "glyphicon glyphicon-pencil", () => {
this.setState({editing: !this.state.editing});
});
}
addActionButton("Delete", "btn-danger", "glyphicon glyphicon-trash", this.genActionApiCall("remove", { addActionButton("Delete", "btn-danger", "glyphicon glyphicon-trash", this.genActionApiCall("remove", {
confirm: "All information related to this task, including images, maps and models will be deleted. Continue?" confirm: "All information related to this task, including images, maps and models will be deleted. Continue?"
})); }));
@ -288,12 +319,14 @@ class TaskListItem extends React.Component {
let statusLabel = ""; let statusLabel = "";
let statusIcon = statusCodes.icon(task.status); let statusIcon = statusCodes.icon(task.status);
let showEditLink = false;
if (task.last_error){ if (task.last_error){
statusLabel = getStatusLabel(task.last_error, "error"); statusLabel = getStatusLabel(task.last_error, "error");
}else if (!task.processing_node){ }else if (!task.processing_node){
statusLabel = getStatusLabel("Processing node not set"); statusLabel = getStatusLabel("Set a processing node");
statusIcon = "fa fa-hourglass-3"; statusIcon = "fa fa-hourglass-3";
showEditLink = true;
}else{ }else{
statusLabel = getStatusLabel(status, task.status == 40 ? "done" : ""); statusLabel = getStatusLabel(status, task.status == 40 ? "done" : "");
} }
@ -311,7 +344,9 @@ class TaskListItem extends React.Component {
<i className="fa fa-clock-o"></i> {this.hoursMinutesSecs(this.state.time)} <i className="fa fa-clock-o"></i> {this.hoursMinutesSecs(this.state.time)}
</div> </div>
<div className="col-md-3"> <div className="col-md-3">
{statusLabel} {showEditLink ?
<a href="javascript:void(0);" onClick={this.startEditing}>{statusLabel}</a>
: statusLabel}
</div> </div>
<div className="col-md-1 text-right"> <div className="col-md-1 text-right">
<div className="status-icon"> <div className="status-icon">
@ -326,6 +361,7 @@ class TaskListItem extends React.Component {
task={this.state.task} task={this.state.task}
show={true} show={true}
onHide={this.stopEditing} onHide={this.stopEditing}
saveAction={this.updateTask}
/> : /> :
""} ""}
</div> </div>