kopia lustrzana https://github.com/OpenDroneMap/WebODM
Task moving functionality working
rodzic
9a70c07aca
commit
9bb8b1bed5
|
@ -310,9 +310,6 @@ class Task(models.Model):
|
||||||
self.move_assets(self.__original_project_id, self.project.id)
|
self.move_assets(self.__original_project_id, self.project.id)
|
||||||
self.__original_project_id = self.project.id
|
self.__original_project_id = self.project.id
|
||||||
|
|
||||||
# Autovalidate on save
|
|
||||||
self.full_clean()
|
|
||||||
|
|
||||||
super(Task, self).save(*args, **kwargs)
|
super(Task, self).save(*args, **kwargs)
|
||||||
|
|
||||||
def assets_path(self, *args):
|
def assets_path(self, *args):
|
||||||
|
|
|
@ -123,7 +123,7 @@ def build_plugins():
|
||||||
|
|
||||||
# Check for webpack.config.js (if we need to build it)
|
# Check for webpack.config.js (if we need to build it)
|
||||||
if plugin.path_exists("public/webpack.config.js"):
|
if plugin.path_exists("public/webpack.config.js"):
|
||||||
if settings.DEV and webpack_watch_process_count() <= 2:
|
if settings.DEV and webpack_watch_process_count() <= 2 and settings.DEV_WATCH_PLUGINS:
|
||||||
logger.info("Running webpack with watcher for {}".format(plugin.get_name()))
|
logger.info("Running webpack with watcher for {}".format(plugin.get_name()))
|
||||||
subprocess.Popen(['webpack-cli', '--watch'], cwd=plugin.get_path("public"))
|
subprocess.Popen(['webpack-cli', '--watch'], cwd=plugin.get_path("public"))
|
||||||
elif not plugin.path_exists("public/build"):
|
elif not plugin.path_exists("public/build"):
|
||||||
|
|
|
@ -95,6 +95,10 @@ class FormDialog extends React.Component {
|
||||||
hide(){
|
hide(){
|
||||||
this.setState({showModal: false});
|
this.setState({showModal: false});
|
||||||
if (this.props.onHide) this.props.onHide();
|
if (this.props.onHide) this.props.onHide();
|
||||||
|
if (this.serverRequest){
|
||||||
|
this.serverRequest.abort();
|
||||||
|
this.serverRequest = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSave(e){
|
handleSave(e){
|
||||||
|
@ -105,13 +109,20 @@ class FormDialog extends React.Component {
|
||||||
let formData = {};
|
let formData = {};
|
||||||
if (this.props.getFormData) formData = this.props.getFormData();
|
if (this.props.getFormData) formData = this.props.getFormData();
|
||||||
|
|
||||||
this.props.saveAction(formData).fail(e => {
|
this.serverRequest = this.props.saveAction(formData);
|
||||||
this.setState({error: e.message || (e.responseJSON || {}).detail || e.responseText || _("Could not apply changes")});
|
if (this.serverRequest){
|
||||||
}).always(() => {
|
this.serverRequest.fail(e => {
|
||||||
|
this.setState({error: e.message || (e.responseJSON || {}).detail || e.responseText || _("Could not apply changes")});
|
||||||
|
}).always(() => {
|
||||||
|
this.setState({saving: false});
|
||||||
|
this.serverRequest = null;
|
||||||
|
}).done(() => {
|
||||||
|
this.hide();
|
||||||
|
});
|
||||||
|
}else{
|
||||||
this.setState({saving: false});
|
this.setState({saving: false});
|
||||||
}).done(() => {
|
|
||||||
this.hide();
|
this.hide();
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDelete(){
|
handleDelete(){
|
||||||
|
|
|
@ -27,7 +27,7 @@ class MoveTaskDialog extends React.Component {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
projectId: props.task.project.id,
|
projectId: props.task.project,
|
||||||
projects: [],
|
projects: [],
|
||||||
loading: true
|
loading: true
|
||||||
};
|
};
|
||||||
|
@ -37,7 +37,7 @@ class MoveTaskDialog extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
getFormData(){
|
getFormData(){
|
||||||
return this.state;
|
return {project: this.state.projectId};
|
||||||
}
|
}
|
||||||
|
|
||||||
onShow(){
|
onShow(){
|
||||||
|
@ -82,20 +82,22 @@ class MoveTaskDialog extends React.Component {
|
||||||
getFormData={this.getFormData}
|
getFormData={this.getFormData}
|
||||||
onShow={this.onShow}
|
onShow={this.onShow}
|
||||||
ref={(domNode) => { this.dialog = domNode; }}>
|
ref={(domNode) => { this.dialog = domNode; }}>
|
||||||
{!this.state.loading ?
|
<div style={{minHeight: '50px'}}>
|
||||||
<div className="form-group">
|
{!this.state.loading ?
|
||||||
<label className="col-sm-2 control-label">{_("Project")}</label>
|
<div className="form-group">
|
||||||
<div className="col-sm-10">
|
<label className="col-sm-2 control-label">{_("Project")}</label>
|
||||||
<select className="form-control"
|
<div className="col-sm-10">
|
||||||
value={this.state.projectId}
|
<select className="form-control"
|
||||||
onChange={this.handleProjectChange}>
|
value={this.state.projectId}
|
||||||
{this.state.projects.map(p =>
|
onChange={this.handleProjectChange}>
|
||||||
<option value={p.id} key={p.id}>{p.name}</option>
|
{this.state.projects.map(p =>
|
||||||
)}
|
<option value={p.id} key={p.id}>{p.name}</option>
|
||||||
</select>
|
)}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
: <i className="fa fa-circle-notch fa-spin fa-fw name-loading"></i>}
|
||||||
</div>
|
</div>
|
||||||
: <i className="fa fa-circle-notch fa-spin fa-fw name-loading"></i>}
|
|
||||||
</FormDialog>
|
</FormDialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,12 @@ class ProjectList extends Paginated {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleTaskMoved = (task) => {
|
||||||
|
if (this["projectListItem_" + task.project]){
|
||||||
|
this["projectListItem_" + task.project].newTaskAdded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (this.state.loading){
|
if (this.state.loading){
|
||||||
return (<div className="project-list text-center"><i className="fa fa-sync fa-spin fa-2x fa-fw"></i></div>);
|
return (<div className="project-list text-center"><i className="fa fa-sync fa-spin fa-2x fa-fw"></i></div>);
|
||||||
|
@ -95,9 +101,11 @@ class ProjectList extends Paginated {
|
||||||
<ul className={"list-group project-list " + (this.state.refreshing ? "refreshing" : "")}>
|
<ul className={"list-group project-list " + (this.state.refreshing ? "refreshing" : "")}>
|
||||||
{this.state.projects.map(p => (
|
{this.state.projects.map(p => (
|
||||||
<ProjectListItem
|
<ProjectListItem
|
||||||
|
ref={(domNode) => { this["projectListItem_" + p.id] = domNode }}
|
||||||
key={p.id}
|
key={p.id}
|
||||||
data={p}
|
data={p}
|
||||||
onDelete={this.handleDelete}
|
onDelete={this.handleDelete}
|
||||||
|
onTaskMoved={this.handleTaskMoved}
|
||||||
history={this.props.history} />
|
history={this.props.history} />
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -20,7 +20,8 @@ class ProjectListItem extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
history: PropTypes.object.isRequired,
|
history: PropTypes.object.isRequired,
|
||||||
data: PropTypes.object.isRequired, // project json
|
data: PropTypes.object.isRequired, // project json
|
||||||
onDelete: PropTypes.func
|
onDelete: PropTypes.func,
|
||||||
|
onTaskMoved: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(props){
|
constructor(props){
|
||||||
|
@ -305,8 +306,9 @@ class ProjectListItem extends React.Component {
|
||||||
this.refresh();
|
this.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
taskMoved(){
|
taskMoved(task){
|
||||||
this.refresh();
|
this.refresh();
|
||||||
|
if (this.props.onTaskMoved) this.props.onTaskMoved(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDelete(){
|
handleDelete(){
|
||||||
|
@ -575,7 +577,7 @@ class ProjectListItem extends React.Component {
|
||||||
ref={this.setRef("taskList")}
|
ref={this.setRef("taskList")}
|
||||||
source={`/api/projects/${data.id}/tasks/?ordering=-created_at`}
|
source={`/api/projects/${data.id}/tasks/?ordering=-created_at`}
|
||||||
onDelete={this.taskDeleted}
|
onDelete={this.taskDeleted}
|
||||||
onMove={this.taskMoved}
|
onTaskMoved={this.taskMoved}
|
||||||
hasPermission={this.hasPermission}
|
hasPermission={this.hasPermission}
|
||||||
history={this.props.history}
|
history={this.props.history}
|
||||||
/> : ""}
|
/> : ""}
|
||||||
|
|
|
@ -10,7 +10,7 @@ class TaskList extends React.Component {
|
||||||
history: PropTypes.object.isRequired,
|
history: PropTypes.object.isRequired,
|
||||||
source: PropTypes.string.isRequired, // URL where to load task list
|
source: PropTypes.string.isRequired, // URL where to load task list
|
||||||
onDelete: PropTypes.func,
|
onDelete: PropTypes.func,
|
||||||
onMove: PropTypes.func,
|
onTaskMoved: PropTypes.func,
|
||||||
hasPermission: PropTypes.func.isRequired
|
hasPermission: PropTypes.func.isRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,11 +71,9 @@ class TaskList extends React.Component {
|
||||||
if (this.props.onDelete) this.props.onDelete(id);
|
if (this.props.onDelete) this.props.onDelete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
moveTask(id){
|
moveTask = (task) => {
|
||||||
this.setState({
|
this.refresh();
|
||||||
tasks: this.state.tasks.filter(t => t.id !== id)
|
if (this.props.onTaskMoved) this.props.onTaskMoved(task);
|
||||||
});
|
|
||||||
if (this.props.onMove) this.props.onMove(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -85,7 +83,7 @@ class TaskList extends React.Component {
|
||||||
}else if (this.state.error){
|
}else if (this.state.error){
|
||||||
message = (<span>{interpolate(_("Error: %(error)s"), {error: this.state.error})} <a href="javascript:void(0);" onClick={this.retry}>{_("Try again")}</a></span>);
|
message = (<span>{interpolate(_("Error: %(error)s"), {error: this.state.error})} <a href="javascript:void(0);" onClick={this.retry}>{_("Try again")}</a></span>);
|
||||||
}else if (this.state.tasks.length === 0){
|
}else if (this.state.tasks.length === 0){
|
||||||
message = (<span>{_("This project has no tasks. Create one by uploading some images!")}</span>);
|
message = (<span></span>);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -370,6 +370,18 @@ class TaskListItem extends React.Component {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
moveTaskAction = (formData) => {
|
||||||
|
if (formData.project !== this.state.task.project){
|
||||||
|
return $.ajax({
|
||||||
|
url: `/api/projects/${this.state.task.project}/tasks/${this.state.task.id}/`,
|
||||||
|
contentType: 'application/json',
|
||||||
|
data: JSON.stringify(formData),
|
||||||
|
dataType: 'json',
|
||||||
|
type: 'PATCH'
|
||||||
|
}).done(this.props.onMove);
|
||||||
|
}else return false;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const task = this.state.task;
|
const task = this.state.task;
|
||||||
const name = task.name !== null ? task.name : interpolate(_("Task #%(number)s"), { number: task.id });
|
const name = task.name !== null ? task.name : interpolate(_("Task #%(number)s"), { number: task.id });
|
||||||
|
@ -626,10 +638,9 @@ class TaskListItem extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ability to change options
|
// Ability to change options
|
||||||
const canAddDelPerms = this.props.hasPermission("add") && this.props.hasPermission("delete");
|
|
||||||
const editable = [statusCodes.FAILED, statusCodes.COMPLETED, statusCodes.CANCELED].indexOf(task.status) !== -1;
|
const editable = [statusCodes.FAILED, statusCodes.COMPLETED, statusCodes.CANCELED].indexOf(task.status) !== -1;
|
||||||
|
|
||||||
if (canAddDelPerms){
|
if (this.props.hasPermission("change")){
|
||||||
if (editable || (!task.processing_node)){
|
if (editable || (!task.processing_node)){
|
||||||
taskActions.push(<li key="edit"><a href="javascript:void(0)" onClick={this.startEditing}><i className="glyphicon glyphicon-pencil"></i>{_("Edit")}</a></li>);
|
taskActions.push(<li key="edit"><a href="javascript:void(0)" onClick={this.startEditing}><i className="glyphicon glyphicon-pencil"></i>{_("Edit")}</a></li>);
|
||||||
}
|
}
|
||||||
|
@ -661,7 +672,7 @@ class TaskListItem extends React.Component {
|
||||||
task={task}
|
task={task}
|
||||||
ref={(domNode) => { this.moveTaskDialog = domNode; }}
|
ref={(domNode) => { this.moveTaskDialog = domNode; }}
|
||||||
onHide={() => this.setState({showMoveDialog: false})}
|
onHide={() => this.setState({showMoveDialog: false})}
|
||||||
saveAction={() => {}}
|
saveAction={this.moveTaskAction}
|
||||||
/>
|
/>
|
||||||
: ""}
|
: ""}
|
||||||
<div className="row">
|
<div className="row">
|
||||||
|
|
|
@ -32,6 +32,7 @@ services:
|
||||||
- WO_DEBUG
|
- WO_DEBUG
|
||||||
- WO_BROKER
|
- WO_BROKER
|
||||||
- WO_DEV
|
- WO_DEV
|
||||||
|
- WO_DEV_WATCH_PLUGINS
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
oom_score_adj: 0
|
oom_score_adj: 0
|
||||||
broker:
|
broker:
|
||||||
|
|
|
@ -82,6 +82,10 @@ case $key in
|
||||||
export WO_DEBUG=YES
|
export WO_DEBUG=YES
|
||||||
shift # past argument
|
shift # past argument
|
||||||
;;
|
;;
|
||||||
|
--dev-watch-plugins)
|
||||||
|
export WO_DEV_WATCH_PLUGINS=YES
|
||||||
|
shift # past argument
|
||||||
|
;;
|
||||||
--dev)
|
--dev)
|
||||||
export WO_DEBUG=YES
|
export WO_DEBUG=YES
|
||||||
export WO_DEV=YES
|
export WO_DEV=YES
|
||||||
|
@ -148,6 +152,7 @@ usage(){
|
||||||
echo " --ssl-insecure-port-redirect <port> Insecure port number to redirect from when SSL is enabled (default: $DEFAULT_SSL_INSECURE_PORT_REDIRECT)"
|
echo " --ssl-insecure-port-redirect <port> Insecure port number to redirect from when SSL is enabled (default: $DEFAULT_SSL_INSECURE_PORT_REDIRECT)"
|
||||||
echo " --debug Enable debug for development environments (default: disabled)"
|
echo " --debug Enable debug for development environments (default: disabled)"
|
||||||
echo " --dev Enable development mode. In development mode you can make modifications to WebODM source files and changes will be reflected live. (default: disabled)"
|
echo " --dev Enable development mode. In development mode you can make modifications to WebODM source files and changes will be reflected live. (default: disabled)"
|
||||||
|
echo " --dev-watch-plugins Automatically build plugins while in dev mode. (default: disabled)"
|
||||||
echo " --broker Set the URL used to connect to the celery broker (default: $DEFAULT_BROKER)"
|
echo " --broker Set the URL used to connect to the celery broker (default: $DEFAULT_BROKER)"
|
||||||
echo " --detached Run WebODM in detached mode. This means WebODM will run in the background, without blocking the terminal (default: disabled)"
|
echo " --detached Run WebODM in detached mode. This means WebODM will run in the background, without blocking the terminal (default: disabled)"
|
||||||
exit
|
exit
|
||||||
|
|
|
@ -52,6 +52,7 @@ WORKER_RUNNING = sys.argv[2:3] == ["worker"]
|
||||||
# SECURITY WARNING: don't run with debug turned on a public facing server!
|
# SECURITY WARNING: don't run with debug turned on a public facing server!
|
||||||
DEBUG = os.environ.get('WO_DEBUG', 'YES') == 'YES' or TESTING
|
DEBUG = os.environ.get('WO_DEBUG', 'YES') == 'YES' or TESTING
|
||||||
DEV = os.environ.get('WO_DEV', 'NO') == 'YES' and not TESTING
|
DEV = os.environ.get('WO_DEV', 'NO') == 'YES' and not TESTING
|
||||||
|
DEV_WATCH_PLUGINS = DEV and os.environ.get('WO_DEV_WATCH_PLUGINS', 'NO') == 'YES'
|
||||||
SESSION_COOKIE_SECURE = CSRF_COOKIE_SECURE = os.environ.get('WO_SSL', 'NO') == 'YES'
|
SESSION_COOKIE_SECURE = CSRF_COOKIE_SECURE = os.environ.get('WO_SSL', 'NO') == 'YES'
|
||||||
INTERNAL_IPS = ['127.0.0.1']
|
INTERNAL_IPS = ['127.0.0.1']
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue