mirror of
https://github.com/wekan/wekan.git
synced 2025-04-22 13:07:17 -04:00
Merge pull request #4641 from mfilser/attachment_upload_progress_bar
Attachment upload progress bar + multiple files upload
This commit is contained in:
commit
f320069ec8
12 changed files with 139 additions and 60 deletions
|
@ -1,3 +1,7 @@
|
|||
.attachment-upload {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
.attachments-galery {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
|
|
@ -1,10 +1,25 @@
|
|||
template(name="cardAttachmentsPopup")
|
||||
ul.pop-over-list
|
||||
li
|
||||
input.js-attach-file.hide(type="file" name="file" multiple)
|
||||
a.js-computer-upload {{_ 'computer'}}
|
||||
li
|
||||
a.js-upload-clipboard-image {{_ 'clipboard'}}
|
||||
if $gt uploads.length 0
|
||||
.attachment-upload {{_ 'uploading'}}
|
||||
table
|
||||
tr
|
||||
th.upload-file-name-descr {{_ 'name'}}
|
||||
th.upload-progress-descr {{_ 'progress'}}
|
||||
th.upload-remaining-descr {{_ 'remaining_time'}}
|
||||
th.upload-speed-descr {{_ 'speed'}}
|
||||
each upload in uploads
|
||||
tr
|
||||
td.upload-file-name-value {{upload.file.name}}
|
||||
td.upload-progress-value {{upload.progress.get}}%
|
||||
td.upload-remaining-value {{getEstimateTime upload}}
|
||||
td.upload-speed-value {{getEstimateSpeed upload}}
|
||||
else
|
||||
ul.pop-over-list
|
||||
li
|
||||
input.js-attach-file.hide(type="file" name="file" multiple)
|
||||
a.js-computer-upload {{_ 'computer'}}
|
||||
li
|
||||
a.js-upload-clipboard-image {{_ 'clipboard'}}
|
||||
|
||||
template(name="previewClipboardImagePopup")
|
||||
p <kbd>Ctrl</kbd>+<kbd>V</kbd> {{_ "paste-or-dragdrop"}}
|
||||
|
@ -37,11 +52,9 @@ template(name="attachmentsGalery")
|
|||
source(src="{{link}}" type="video/mp4")
|
||||
else
|
||||
span.attachment-thumbnail-ext= extension
|
||||
else
|
||||
+spinner
|
||||
p.attachment-details
|
||||
= name
|
||||
span.file-size ({{fileSize size}} KB)
|
||||
span.file-size ({{fileSize size}})
|
||||
span.attachment-details-actions
|
||||
a.js-download(href="{{link}}?download=true", download="{{name}}")
|
||||
i.fa.fa-download
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
const filesize = require('filesize');
|
||||
const prettyMilliseconds = require('pretty-ms');
|
||||
|
||||
Template.attachmentsGalery.events({
|
||||
'click .js-add-attachment': Popup.open('cardAttachments'),
|
||||
// If we let this event bubble, FlowRouter will handle it and empty the page
|
||||
|
@ -13,37 +16,68 @@ Template.attachmentsGalery.helpers({
|
|||
return Meteor.user().isBoardAdmin();
|
||||
},
|
||||
fileSize(size) {
|
||||
return Math.round(size / 1024);
|
||||
const ret = filesize(size);
|
||||
return ret;
|
||||
},
|
||||
});
|
||||
|
||||
Template.cardAttachmentsPopup.onCreated(function() {
|
||||
this.uploads = new ReactiveVar([]);
|
||||
});
|
||||
|
||||
Template.cardAttachmentsPopup.helpers({
|
||||
getEstimateTime(upload) {
|
||||
const ret = prettyMilliseconds(upload.estimateTime.get());
|
||||
return ret;
|
||||
},
|
||||
getEstimateSpeed(upload) {
|
||||
const ret = filesize(upload.estimateSpeed.get(), {round: 0}) + "/s";
|
||||
return ret;
|
||||
},
|
||||
uploads() {
|
||||
return Template.instance().uploads.get();
|
||||
}
|
||||
});
|
||||
|
||||
Template.cardAttachmentsPopup.events({
|
||||
'change .js-attach-file'(event) {
|
||||
'change .js-attach-file'(event, templateInstance) {
|
||||
const card = this;
|
||||
if (event.currentTarget.files && event.currentTarget.files[0]) {
|
||||
const fileId = Random.id();
|
||||
const config = {
|
||||
file: event.currentTarget.files[0],
|
||||
fileId: fileId,
|
||||
meta: Utils.getCommonAttachmentMetaFrom(card),
|
||||
chunkSize: 'dynamic',
|
||||
};
|
||||
config.meta.fileId = fileId;
|
||||
const uploader = Attachments.insert(
|
||||
config,
|
||||
false,
|
||||
);
|
||||
uploader.on('uploaded', (error, fileRef) => {
|
||||
if (!error) {
|
||||
if (fileRef.isImage) {
|
||||
card.setCover(fileRef._id);
|
||||
const files = event.currentTarget.files;
|
||||
if (files) {
|
||||
let uploads = [];
|
||||
for (const file of files) {
|
||||
const fileId = Random.id();
|
||||
const config = {
|
||||
file: file,
|
||||
fileId: fileId,
|
||||
meta: Utils.getCommonAttachmentMetaFrom(card),
|
||||
chunkSize: 'dynamic',
|
||||
};
|
||||
config.meta.fileId = fileId;
|
||||
const uploader = Attachments.insert(
|
||||
config,
|
||||
false,
|
||||
);
|
||||
uploader.on('start', function() {
|
||||
uploads.push(this);
|
||||
templateInstance.uploads.set(uploads);
|
||||
});
|
||||
uploader.on('uploaded', (error, fileRef) => {
|
||||
if (!error) {
|
||||
if (fileRef.isImage) {
|
||||
card.setCover(fileRef._id);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
uploader.on('end', (error, fileRef) => {
|
||||
Popup.back();
|
||||
});
|
||||
uploader.start();
|
||||
});
|
||||
uploader.on('end', (error, fileRef) => {
|
||||
uploads = uploads.filter(_upload => _upload.config.fileId != fileRef._id);
|
||||
templateInstance.uploads.set(uploads);
|
||||
if (uploads.length == 0 ) {
|
||||
Popup.back();
|
||||
}
|
||||
});
|
||||
uploader.start();
|
||||
}
|
||||
}
|
||||
},
|
||||
'click .js-computer-upload'(event, templateInstance) {
|
||||
|
|
|
@ -88,7 +88,7 @@ template(name="filesReport")
|
|||
each att in results
|
||||
tr
|
||||
td {{ att.name }}
|
||||
td.right {{fileSize att.size }}
|
||||
td.right {{ fileSize att.size }}
|
||||
td {{ att.type }}
|
||||
td {{ att._id }}
|
||||
td {{ att.meta.boardId }}
|
||||
|
|
|
@ -4,6 +4,7 @@ import { CardSearchPagedComponent } from '/client/lib/cardSearch';
|
|||
import SessionData from '/models/usersessiondata';
|
||||
import { QueryParams } from '/config/query-classes';
|
||||
import { OPERATOR_LIMIT } from '/config/search-const';
|
||||
const filesize = require('filesize');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
subscription: null,
|
||||
|
@ -114,7 +115,8 @@ class AdminReport extends BlazeComponent {
|
|||
}
|
||||
|
||||
fileSize(size) {
|
||||
return Math.round(size / 1024);
|
||||
const ret = filesize(size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
abbreviate(text) {
|
||||
|
|
|
@ -52,7 +52,7 @@ template(name="moveBoardAttachments")
|
|||
th {{_ 'name'}}
|
||||
th {{_ 'path'}}
|
||||
th {{_ 'version-name'}}
|
||||
th {{_ 'size'}} (B)
|
||||
th {{_ 'size'}}
|
||||
th GridFsFileId
|
||||
th {{_ 'storage'}}
|
||||
th {{_ 'action'}}
|
||||
|
@ -68,7 +68,7 @@ template(name="moveAttachment")
|
|||
td {{ name }}
|
||||
td {{ version.path }}
|
||||
td {{ version.versionName }}
|
||||
td {{ version.size }}
|
||||
td {{ fileSize version.size }}
|
||||
td {{ version.meta.gridFsFileId }}
|
||||
td {{ version.storageName }}
|
||||
td
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Attachments, { fileStoreStrategyFactory } from '/models/attachments';
|
||||
const filesize = require('filesize');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
subscription: null,
|
||||
|
@ -108,6 +109,10 @@ BlazeComponent.extendComponent({
|
|||
}).register('moveBoardAttachments');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
fileSize(size) {
|
||||
const ret = filesize(size);
|
||||
return ret;
|
||||
},
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
|
|
|
@ -58,38 +58,38 @@ template(name='statistics')
|
|||
td {{numFormat statistics.os.loadavg.[0]}}, {{numFormat statistics.os.loadavg.[1]}}, {{numFormat statistics.os.loadavg.[2]}}
|
||||
tr
|
||||
th {{_ 'OS_Totalmem'}}
|
||||
td {{bytesToSize statistics.os.totalmem}}
|
||||
td {{fileSize statistics.os.totalmem}}
|
||||
tr
|
||||
th {{_ 'OS_Freemem'}}
|
||||
td {{bytesToSize statistics.os.freemem}}
|
||||
td {{fileSize statistics.os.freemem}}
|
||||
tr
|
||||
th {{_ 'OS_Cpus'}}
|
||||
td {{statistics.os.cpus.length}}
|
||||
unless isSandstorm
|
||||
tr
|
||||
th {{_ 'Node_heap_total_heap_size'}}
|
||||
td {{bytesToSize statistics.nodeHeapStats.totalHeapSize}}
|
||||
td {{fileSize statistics.nodeHeapStats.totalHeapSize}}
|
||||
tr
|
||||
th {{_ 'Node_heap_total_heap_size_executable'}}
|
||||
td {{bytesToSize statistics.nodeHeapStats.totalHeapSizeExecutable}}
|
||||
td {{fileSize statistics.nodeHeapStats.totalHeapSizeExecutable}}
|
||||
tr
|
||||
th {{_ 'Node_heap_total_physical_size'}}
|
||||
td {{bytesToSize statistics.nodeHeapStats.totalPhysicalSize}}
|
||||
td {{fileSize statistics.nodeHeapStats.totalPhysicalSize}}
|
||||
tr
|
||||
th {{_ 'Node_heap_total_available_size'}}
|
||||
td {{bytesToSize statistics.nodeHeapStats.totalAvailableSize}}
|
||||
td {{fileSize statistics.nodeHeapStats.totalAvailableSize}}
|
||||
tr
|
||||
th {{_ 'Node_heap_used_heap_size'}}
|
||||
td {{bytesToSize statistics.nodeHeapStats.usedHeapSize}}
|
||||
td {{fileSize statistics.nodeHeapStats.usedHeapSize}}
|
||||
tr
|
||||
th {{_ 'Node_heap_heap_size_limit'}}
|
||||
td {{bytesToSize statistics.nodeHeapStats.heapSizeLimit}}
|
||||
td {{fileSize statistics.nodeHeapStats.heapSizeLimit}}
|
||||
tr
|
||||
th {{_ 'Node_heap_malloced_memory'}}
|
||||
td {{bytesToSize statistics.nodeHeapStats.mallocedMemory}}
|
||||
td {{fileSize statistics.nodeHeapStats.mallocedMemory}}
|
||||
tr
|
||||
th {{_ 'Node_heap_peak_malloced_memory'}}
|
||||
td {{bytesToSize statistics.nodeHeapStats.peakMallocedMemory}}
|
||||
td {{fileSize statistics.nodeHeapStats.peakMallocedMemory}}
|
||||
tr
|
||||
th {{_ 'Node_heap_does_zap_garbage'}}
|
||||
td {{statistics.nodeHeapStats.doesZapGarbage}}
|
||||
|
@ -101,13 +101,13 @@ template(name='statistics')
|
|||
td {{statistics.nodeHeapStats.numberOfDetachedContexts}}
|
||||
tr
|
||||
th {{_ 'Node_memory_usage_rss'}}
|
||||
td {{bytesToSize statistics.nodeMemoryUsage.rss}}
|
||||
td {{fileSize statistics.nodeMemoryUsage.rss}}
|
||||
tr
|
||||
th {{_ 'Node_memory_usage_heap_total'}}
|
||||
td {{bytesToSize statistics.nodeMemoryUsage.heapTotal}}
|
||||
td {{fileSize statistics.nodeMemoryUsage.heapTotal}}
|
||||
tr
|
||||
th {{_ 'Node_memory_usage_heap_used'}}
|
||||
td {{bytesToSize statistics.nodeMemoryUsage.heapUsed}}
|
||||
td {{fileSize statistics.nodeMemoryUsage.heapUsed}}
|
||||
tr
|
||||
th {{_ 'Node_memory_usage_external'}}
|
||||
td {{bytesToSize statistics.nodeMemoryUsage.external}}
|
||||
td {{fileSize statistics.nodeMemoryUsage.external}}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { TAPi18n } from '/imports/i18n';
|
||||
const filesize = require('filesize');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
|
@ -39,12 +40,8 @@ BlazeComponent.extendComponent({
|
|||
return parseFloat(number).toFixed(2);
|
||||
},
|
||||
|
||||
bytesToSize(bytes) {
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
||||
if (bytes === 0) {
|
||||
return '0 Byte';
|
||||
}
|
||||
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10);
|
||||
return `${Math.round(bytes / Math.pow(1024, i), 2)} ${sizes[i]}`;
|
||||
fileSize(size) {
|
||||
const ret = filesize(size);
|
||||
return ret;
|
||||
},
|
||||
}).register('statistics');
|
||||
|
|
|
@ -1181,5 +1181,9 @@
|
|||
"storage": "Storage",
|
||||
"action": "Action",
|
||||
"board-title": "Board Title",
|
||||
"attachmentRenamePopup-title": "Rename"
|
||||
"attachmentRenamePopup-title": "Rename",
|
||||
"uploading": "Uploading",
|
||||
"remaining_time": "Remaining time",
|
||||
"speed": "Speed",
|
||||
"progress": "Progress"
|
||||
}
|
||||
|
|
18
package-lock.json
generated
18
package-lock.json
generated
|
@ -1791,6 +1791,11 @@
|
|||
"token-types": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"filesize": {
|
||||
"version": "8.0.7",
|
||||
"resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz",
|
||||
"integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ=="
|
||||
},
|
||||
"find-up": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
||||
|
@ -3624,6 +3629,11 @@
|
|||
"parse5": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"parse-ms": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz",
|
||||
"integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA=="
|
||||
},
|
||||
"path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
|
@ -3671,6 +3681,14 @@
|
|||
"resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz",
|
||||
"integrity": "sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ=="
|
||||
},
|
||||
"pretty-ms": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz",
|
||||
"integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==",
|
||||
"requires": {
|
||||
"parse-ms": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
"exceljs": "^4.2.1",
|
||||
"fibers": "^5.0.0",
|
||||
"file-type": "^16.5.4",
|
||||
"filesize": "^8.0.7",
|
||||
"i18next": "^21.6.16",
|
||||
"i18next-sprintf-postprocessor": "^0.2.2",
|
||||
"jquery": "^2.2.4",
|
||||
|
@ -55,6 +56,7 @@
|
|||
"os": "^0.1.2",
|
||||
"page": "^1.11.6",
|
||||
"papaparse": "^5.3.1",
|
||||
"pretty-ms": "^7.0.1",
|
||||
"qs": "^6.10.1",
|
||||
"simpl-schema": "^1.12.0",
|
||||
"source-map-support": "^0.5.20",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue