1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-11 04:36:48 +00:00

feat(storages): the upload dialog closes once an upload starts

The job panel follows an ISO upload, so the dialog closes when the first
chunk is accepted and its progress bar goes; the dialog opens again with
the error if the upload stops. The browser still sends the file, so the
page asks before it is left while an upload runs. The storage page no
longer includes the please-wait dialog, which nothing on it opened.
This commit is contained in:
catborise 2026-10-16 12:06:54 +03:00
parent 06f03d65fc
commit 4629e0557f
3 changed files with 10 additions and 16 deletions

View file

@ -604,7 +604,7 @@ When the restored version predates the worker, `supervisorctl` reports that `web
- Cloning a VM or a volume and creating a VM run as jobs: the page returns at once and the job panel follows them. The API's VM create answers 202 with the job and needs a new `submission_key` per request. The create form no longer takes a console password; set it on the VM page.
- Taking and reverting a snapshot run as jobs, like deleting an external snapshot: the page returns at once and the job panel follows them. Deleting an internal snapshot stays immediate.
- Migrating a VM runs as a job: the page returns at once, the job panel shows its progress, and a running migration can be cancelled there (the VM keeps running on its source host). The 540 s limit is gone. The API's migrate answers 202 with the job and needs a new `submission_key` per request.
- Uploading an ISO is tracked as a job: the storage page's job panel shows it and can cancel it, and the page no longer reloads when it ends. An upload left idle for an hour is ended and its partial file deleted.
- Uploading an ISO is tracked as a job: the storage page's job panel shows it and can cancel it, and the page no longer reloads when it ends. The upload dialog closes once the upload starts; the browser still sends the file, so stay on the page until it ends. An upload left idle for an hour is ended and its partial file deleted.
- Manual installs that keep their own `settings.py` copy the SQLite `OPTIONS` and `TEST` entries from `settings.py.template` and add `"operations"` to `INSTALLED_APPS`.
- The SQLite database must be on a local file system (WAL).
- Outside compose, stop the Docker container with `docker stop -t 95` so the worker can finish running jobs.

View file

@ -28,11 +28,6 @@
<span class="spinner-border spinner-border-sm" aria-hidden="true"></span>
<span id="upload-status-text">{% trans "Starting upload..." %}</span>
</div>
<div id="upload-progress-container" class="mt-3" style="display: none;">
<div class="progress">
<div id="upload-progress-bar" class="progress-bar" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">0%</div>
</div>
</div>
<div id="upload-error-message" class="alert alert-danger mt-3" style="display: none;"></div>
</div>
<div class="modal-footer">

View file

@ -13,7 +13,6 @@
{% block page_heading_extra %}{% include 'create_stg_vol_block.html' %}{% endblock page_heading_extra %}
{% block content %}
{% include 'pleasewaitdialog.html' %}
<div id="job-panel" aria-live="polite"></div>
<div class="row">
<div class="col-lg-12">
@ -229,6 +228,10 @@
var pendingUpload = null;
var uploadInProgress = false;
// the browser sends the file: leaving the page stops the upload
window.addEventListener('beforeunload', function(e) {
if (uploadInProgress) { e.preventDefault(); e.returnValue = ''; }
});
$('#isoUploadForm').on('submit', function(e) {
e.preventDefault();
if (uploadInProgress) return;
@ -265,14 +268,11 @@
var retryCount = 0;
uploadInProgress = true;
var progressBar = $('#upload-progress-bar');
var progressContainer = $('#upload-progress-container');
var uploadDialog = bootstrap.Modal.getOrCreateInstance(document.getElementById('IsoUpload'));
var uploadStatus = $('#upload-status');
var uploadStatusText = $('#upload-status-text');
var uploadButton = $('#isoUploadForm button[type="submit"]');
progressContainer.show();
progressBar.width('0%').attr('aria-valuenow', 0).text('0%');
errorMessage.hide();
uploadStatusText.text("{% trans 'Starting upload...'|escapejs %}");
uploadStatus.removeClass('d-none').addClass('d-flex');
@ -305,14 +305,14 @@
contentType: false,
success: function(data) {
if (chunkIndex === 0) {
// the job panel follows the upload from here
window.resourceJobPanel.track(data.job);
uploadStatusText.text("{% trans 'Uploading; the job panel shows its progress. Stay on this page until it ends.'|escapejs %}");
uploadDialog.hide();
}
retryCount = 0;
chunkIndex++;
pendingUpload.chunkIndex = chunkIndex;
var percentComplete = Math.round((chunkIndex / totalChunks) * 100);
progressBar.width(percentComplete + '%').attr('aria-valuenow', percentComplete).text(percentComplete + '%');
uploadStatusText.text("{% trans 'Uploading...'|escapejs %} " + percentComplete + '%');
if (chunkIndex < totalChunks) {
uploadChunk();
@ -320,7 +320,6 @@
pendingUpload = null;
uploadInProgress = false;
uploadStatus.removeClass('d-flex').addClass('d-none');
progressContainer.hide();
uploadButton.prop('disabled', false);
}
},
@ -339,7 +338,7 @@
}
var errorText = jqXHR.responseJSON && jqXHR.responseJSON.error ? jqXHR.responseJSON.error : "{% trans 'An error occurred during upload.'|escapejs %}";
errorMessage.text(errorText).show();
progressContainer.hide();
uploadDialog.show();
}
});
}