Add compact feature

pull/1628/head
Piero Toffanin 2025-03-11 15:11:48 -04:00
rodzic bf1118fbb3
commit 78a2c1ca18
7 zmienionych plików z 59 dodań i 10 usunięć

Wyświetl plik

@ -153,6 +153,10 @@ class TaskViewSet(viewsets.ViewSet):
def remove(self, *args, **kwargs):
return self.set_pending_action(pending_actions.REMOVE, *args, perms=('delete_project', ), **kwargs)
@action(detail=True, methods=['post'])
def compact(self, *args, **kwargs):
return self.set_pending_action(pending_actions.COMPACT, *args, perms=('delete_project', ), **kwargs)
@action(detail=True, methods=['get'])
def output(self, request, pk=None, project_pk=None):
"""

Wyświetl plik

@ -235,6 +235,7 @@ class Task(models.Model):
(pending_actions.RESTART, 'RESTART'),
(pending_actions.RESIZE, 'RESIZE'),
(pending_actions.IMPORT, 'IMPORT'),
(pending_actions.COMPACT, 'COMPACT'),
)
TASK_PROGRESS_LAST_VALUE = 0.85
@ -808,6 +809,14 @@ class Task(models.Model):
# Stop right here!
return
elif self.pending_action == pending_actions.COMPACT:
logger.info("Compacting {}".format(self))
time.sleep(2) # Purely to make sure the user sees the "compacting..." message in the UI since this is so fast
self.compact()
self.pending_action = None
self.save()
return
if self.processing_node:
# Need to update status (first time, queued or running?)
if self.uuid and self.status in [None, status_codes.QUEUED, status_codes.RUNNING]:
@ -1142,6 +1151,18 @@ class Task(models.Model):
plugin_signals.task_removed.send_robust(sender=self.__class__, task_id=task_id)
def compact(self):
# Remove all images
images_path = self.task_path()
images = [os.path.join(images_path, i) for i in self.scan_images()]
for im in images:
try:
os.unlink(im)
except Exception as e:
logger.warning(e)
self.update_size(commit=True)
def set_failure(self, error_message):
logger.error("FAILURE FOR {}: {}".format(self, error_message))
self.last_error = error_message
@ -1157,7 +1178,8 @@ class Task(models.Model):
def check_if_canceled(self):
# Check if task has been canceled/removed
if Task.objects.only("pending_action").get(pk=self.id).pending_action in [pending_actions.CANCEL,
pending_actions.REMOVE]:
pending_actions.REMOVE,
pending_actions.COMPACT]:
raise TaskInterruptedException()
def resize_images(self):

Wyświetl plik

@ -3,3 +3,4 @@ REMOVE = 2
RESTART = 3
RESIZE = 4
IMPORT = 5
COMPACT = 6

Wyświetl plik

@ -4,7 +4,8 @@ const CANCEL = 1,
REMOVE = 2,
RESTART = 3,
RESIZE = 4,
IMPORT = 5;
IMPORT = 5,
COMPACT = 6;
let pendingActions = {
[CANCEL]: {
@ -21,6 +22,9 @@ let pendingActions = {
},
[IMPORT]: {
descr: _("Importing...")
},
[COMPACT]: {
descr: _("Compacting...")
}
};
@ -30,6 +34,7 @@ export default {
RESTART: RESTART,
RESIZE: RESIZE,
IMPORT: IMPORT,
COMPACT: COMPACT,
description: function(pendingAction) {
if (pendingActions[pendingAction]) return pendingActions[pendingAction].descr;

Wyświetl plik

@ -239,7 +239,7 @@ class NewTaskPanel extends React.Component {
ref={(domNode) => { if (domNode) this.taskForm = domNode; }}
/>
{this.state.editTaskFormLoaded && this.props.showAlign && this.state.showMapPreview ?
{this.state.editTaskFormLoaded && this.props.showAlign && this.state.showMapPreview && this.state.alignTasks.length > 0 ?
<div>
<div className="form-group">
<label className="col-sm-2 control-label">{_("Alignment")}</label>

Wyświetl plik

@ -462,9 +462,11 @@ class TaskListItem extends React.Component {
const disabled = this.state.actionButtonsDisabled ||
([pendingActions.CANCEL,
pendingActions.REMOVE,
pendingActions.COMPACT,
pendingActions.RESTART].indexOf(task.pending_action) !== -1);
const editable = this.props.hasPermission("change") && [statusCodes.FAILED, statusCodes.COMPLETED, statusCodes.CANCELED].indexOf(task.status) !== -1;
const actionLoading = this.state.actionLoading;
const showAssetButtons = task.status === statusCodes.COMPLETED;
let expanded = "";
if (this.state.expanded){
@ -484,7 +486,7 @@ class TaskListItem extends React.Component {
});
};
if (task.status === statusCodes.COMPLETED){
if (showAssetButtons){
if (task.available_assets.indexOf("orthophoto.tif") !== -1 || task.available_assets.indexOf("dsm.tif") !== -1){
addActionButton(" " + _("View Map"), "btn-primary", "fa fa-globe", () => {
location.href = `/map/project/${task.project}/task/${task.id}/`;
@ -534,7 +536,7 @@ class TaskListItem extends React.Component {
}
actionButtons = (<div className="action-buttons">
{task.status === statusCodes.COMPLETED ?
{showAssetButtons ?
<AssetDownloadButtons task={this.state.task} disabled={disabled} />
: ""}
{actionButtons.map(button => {
@ -672,7 +674,6 @@ class TaskListItem extends React.Component {
</div>
</div>
<div className="row clearfix">
<ErrorMessage bind={[this, 'actionError']} />
{actionButtons}
</div>
<TaskPluginActionButtons task={task} disabled={disabled} />
@ -734,6 +735,10 @@ class TaskListItem extends React.Component {
type = 'neutral';
}
if (task.pending_action === pendingActions.COMPACT){
statusIcon = 'fa fa-cog fa-spin fa-fw';
}
statusLabel = getStatusLabel(status, type, progress);
}
@ -764,9 +769,16 @@ class TaskListItem extends React.Component {
if (this.props.hasPermission("delete")){
taskActions.push(
<li key="sep" role="separator" className="divider"></li>,
<li key="sep" role="separator" className="divider"></li>
);
if (task.status === statusCodes.COMPLETED){
addTaskAction(_("Compact"), "fa fa-database", this.genActionApiCall("compact", {
confirm: _("Compacting will free disk space by permanently deleting the original images used for processing. It will no longer be possible to restart the task. Maps and models will remain in place. Continue?"),
defaultError: _("Cannot compact task.")
}));
}
addTaskAction(_("Delete"), "fa fa-trash", this.genActionApiCall("remove", {
confirm: _("All information related to this task, including images, maps and models will be deleted. Continue?"),
defaultError: _("Cannot delete task.")
@ -816,6 +828,7 @@ class TaskListItem extends React.Component {
: ""}
</div>
</div>
<ErrorMessage bind={[this, 'actionError']} />
{expanded}
</div>
);

Wyświetl plik

@ -71,7 +71,11 @@ class ProcessingNode(models.Model):
self.api_version = info.version
self.queue_count = info.task_queue_count
self.max_images = info.max_images
if isinstance(info.max_images, (int, float)):
self.max_images = max(0, info.max_images)
else:
self.max_images = None
self.engine_version = info.engine_version
self.engine = info.engine