mirror of
https://github.com/drakkan/sftpgo.git
synced 2024-11-22 15:40:23 +00:00
32a4a753f9
Some checks are pending
Code scanning - action / CodeQL-Build (push) Waiting to run
CI / golangci-lint (push) Waiting to run
CI / Test and deploy (push) Waiting to run
CI / Test build flags (push) Waiting to run
CI / Test with PgSQL/MySQL/Cockroach (push) Waiting to run
CI / Build Linux packages (push) Waiting to run
Docker / Build (push) Waiting to run
Fixes #1773 Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
225 lines
No EOL
8.6 KiB
HTML
225 lines
No EOL
8.6 KiB
HTML
<!--
|
|
Copyright (C) 2023 Nicola Murino
|
|
|
|
This WebUI uses the KeenThemes Mega Bundle, a proprietary theme:
|
|
|
|
https://keenthemes.com/products/templates-mega-bundle
|
|
|
|
KeenThemes HTML/CSS/JS components are allowed for use only within the
|
|
SFTPGo product and restricted to be used in a resealable HTML template
|
|
that can compete with KeenThemes products anyhow.
|
|
|
|
This WebUI is allowed for use only within the SFTPGo product and
|
|
therefore cannot be used in derivative works/products without an
|
|
explicit grant from the SFTPGo Team (support@sftpgo.com).
|
|
-->
|
|
{{- template "base" .}}
|
|
|
|
{{- define "page_body"}}
|
|
<div class="d-flex flex-center flex-column flex-column-fluid p-10 pb-lg-20">
|
|
<div class="mb-12">
|
|
<span>
|
|
<img alt="Logo" src="{{.StaticURL}}{{.Branding.LogoPath}}" class="h-80px" />
|
|
</span>
|
|
<span class="text-gray-800 fs-2 fw-semibold ps-5">
|
|
{{.Branding.ShortName}}
|
|
</span>
|
|
</div>
|
|
<div class="card shadow-sm w-lg-600px">
|
|
<div class="card-header bg-light">
|
|
<h3 data-i18n="title.upload_to_share" class="card-title section-title">Upload one or more files to share</h3>
|
|
</div>
|
|
<div class="card-body">
|
|
{{- template "errmsg" ""}}
|
|
<form id="upload_files_form" action="{{.UploadBasePath}}" method="POST" enctype="multipart/form-data">
|
|
<div class="fv-row">
|
|
<div class="dropzone mh-350px overflow-auto visibility-auto" id="upload_files">
|
|
<div class="dz-message needsclick align-items-center">
|
|
<i class="ki-duotone ki-file-up fs-3x text-primary"><span class="path1"></span><span class="path2"></span></i>
|
|
<div class="ms-4">
|
|
<h3 data-i18n="fs.upload.message" class="fs-5 fw-bold text-gray-900 mb-1">Drop files here or click to upload.</h3>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="d-flex justify-content-end mt-10">
|
|
<button data-i18n="general.submit" type="button" id="upload_files_button" class="btn btn-primary">Submit</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{- end}}
|
|
|
|
{{- define "extra_js"}}
|
|
<script type="text/javascript" {{- if .CSPNonce}} nonce="{{.CSPNonce}}"{{- end}}>
|
|
|
|
function uploadFiles(files) {
|
|
let has_errors = false;
|
|
let index = 0;
|
|
let success = 0;
|
|
let checkedDirs = [];
|
|
$('#errorMsg').addClass("d-none");
|
|
clearLoading();
|
|
KTApp.showPageLoading();
|
|
|
|
function uploadFile() {
|
|
if (index >= files.length || has_errors) {
|
|
KTApp.hidePageLoading();
|
|
if (!has_errors) {
|
|
ModalAlert.fire({
|
|
text: $.t('fs.upload.success'),
|
|
icon: "success",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: 'btn btn-primary'
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed){
|
|
location.reload();
|
|
}
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
|
|
let f = files[index];
|
|
let name = f.name;
|
|
let mkdirParents = "false";
|
|
if (f.fullPath){
|
|
name = f.fullPath;
|
|
let dirName = name.substr(0, name.lastIndexOf("/"));
|
|
if (!checkedDirs.includes(dirName)){
|
|
mkdirParents = "true";
|
|
checkedDirs.push(dirName);
|
|
}
|
|
}
|
|
let uploadPath = '{{.UploadBasePath}}/'+encodeURIComponent(name)+"?mkdir_parents="+mkdirParents;
|
|
let lastModified;
|
|
try {
|
|
lastModified = f.lastModified;
|
|
} catch (e) {
|
|
console.error("unable to get last modified time from file: " + e.message);
|
|
lastModified = "";
|
|
}
|
|
|
|
let info = "";
|
|
if (files.length > 1){
|
|
info = $.t('fs.uploading', {
|
|
idx: index + 1,
|
|
total: files.length
|
|
});
|
|
}
|
|
|
|
setLoadingText(info,f.name);
|
|
|
|
axios.post(uploadPath, f, {
|
|
headers: {
|
|
'X-SFTPGO-MTIME': lastModified,
|
|
'X-CSRF-TOKEN': '{{.CSRFToken}}'
|
|
},
|
|
onUploadProgress: function (progressEvent) {
|
|
if (!progressEvent.total){
|
|
return;
|
|
}
|
|
const percentage = Math.round((100 * progressEvent.loaded) / progressEvent.total);
|
|
if (percentage > 0 && percentage < 100){
|
|
setLoadingText(info,`${f.name} ${percentage}%`);
|
|
}
|
|
},
|
|
validateStatus: function (status) {
|
|
return status == 201;
|
|
}
|
|
}).then(function (response) {
|
|
index++;
|
|
success++;
|
|
uploadFile();
|
|
}).catch(function (error) {
|
|
let errorMessage;
|
|
if (error && error.response) {
|
|
switch (error.response.status) {
|
|
case 403:
|
|
errorMessage = "fs.upload.err_403";
|
|
break;
|
|
case 429:
|
|
errorMessage = "fs.upload.err_429";
|
|
break;
|
|
}
|
|
}
|
|
if (!errorMessage){
|
|
errorMessage = "fs.upload.err_generic";
|
|
}
|
|
index++;
|
|
has_errors = true;
|
|
setI18NData($('#errorTxt'), errorMessage);
|
|
$('#errorMsg').removeClass("d-none");
|
|
uploadFile();
|
|
});
|
|
}
|
|
|
|
uploadFile();
|
|
}
|
|
|
|
KTUtil.onDOMContentLoaded(function () {
|
|
var lastAddedFile = Date.now();
|
|
|
|
function canUpload() {
|
|
// Ugly hack to detect if we are still loading a large file list when the user try to upload files.
|
|
// The Dropzone addedfiles event is fired for directories before the files within them are added to the queue.
|
|
// TODO: investigate if there is a better way.
|
|
if (Date.now() - lastAddedFile < 500) {
|
|
ModalAlert.fire({
|
|
text: $.t('fs.upload_queue_not_ready'),
|
|
icon: "warning",
|
|
confirmButtonText: $.t('general.ok'),
|
|
customClass: {
|
|
confirmButton: "btn btn-primary"
|
|
}
|
|
});
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
var dropzone = new Dropzone("#upload_files", {
|
|
url: "{{.UploadBasePath}}",
|
|
paramName: "filenames",
|
|
createImageThumbnails: false,
|
|
maxFiles: null,
|
|
maxFilesize: null,
|
|
autoQueue: false,
|
|
addRemoveLinks: false,
|
|
autoProcessQueue: false,
|
|
filesizeBase: 1000,
|
|
previewTemplate: `<div class="d-flex align-items-center mb-2">
|
|
<span class="bullet bullet-dot bg-primary me-2"></span>
|
|
<div class="text-break text-wrap text-left"><span class="fs-5 fw-semibold" data-dz-name></span> (<span class="fs-5 fw-semibold" data-custom-size></span>)</div>
|
|
</div>
|
|
<div class="dz-error-message d-none" data-dz-errormessage></div>
|
|
<div class="dz-progress d-none"><span class="dz-upload" data-dz-uploadprogress></span></div>
|
|
`,
|
|
init: function() {
|
|
var dropzone = this;
|
|
$("#upload_files_button").click(function(){
|
|
if (canUpload()){
|
|
uploadFiles(dropzone.getAcceptedFiles());
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
dropzone.on("addedfile", file => {
|
|
for (node of file.previewElement.querySelectorAll("[data-custom-size]")) {
|
|
node.textContent = fileSizeIEC(file.size);
|
|
}
|
|
if (file.fullPath){
|
|
for (var node of file.previewElement.querySelectorAll("[data-dz-name]")) {
|
|
node.textContent = file.fullPath;
|
|
}
|
|
}
|
|
lastAddedFile = Date.now();
|
|
});
|
|
});
|
|
|
|
</script>
|
|
{{- end}} |