Multi-File Storage.

Thanks to mfilser !

Related https://github.com/wekan/wekan/pull/4484

Merge branch 'master' into upgrade-meteor
This commit is contained in:
Lauri Ojansivu 2022-04-22 00:55:42 +03:00
commit 68e8155805
29 changed files with 921 additions and 276 deletions

View file

@ -11,11 +11,6 @@ template(name="adminReports")
i.fa.fa-chain-broken
| {{_ 'broken-cards'}}
li
a.js-report-files(data-id="report-orphaned-files")
i.fa.fa-paperclip
| {{_ 'orphanedFilesReportTitle'}}
li
a.js-report-files(data-id="report-files")
i.fa.fa-paperclip
@ -43,8 +38,6 @@ template(name="adminReports")
+brokenCardsReport
else if showFilesReport.get
+filesReport
else if showOrphanedFilesReport.get
+orphanedFilesReport
else if showRulesReport.get
+rulesReport
else if showBoardsReport.get
@ -64,7 +57,7 @@ template(name="brokenCardsReport")
template(name="rulesReport")
h1 {{_ 'rulesReportTitle'}}
if resultsCount
table.table
table
tr
th Rule Title
th Board Title
@ -83,44 +76,23 @@ template(name="rulesReport")
template(name="filesReport")
h1 {{_ 'filesReportTitle'}}
if resultsCount
table.table
table
tr
th Filename
th.right Size (kB)
th MIME Type
th.center Usage
th MD5 Sum
th ID
th Attachment ID
th Board ID
th Card ID
each att in results
tr
td {{ att.filename }}
td.right {{fileSize att.length }}
td {{ att.contentType }}
td.center {{usageCount att._id.toHexString }}
td {{ att.md5 }}
td {{ att._id.toHexString }}
else
div {{_ 'no-results' }}
template(name="orphanedFilesReport")
h1 {{_ 'orphanedFilesReportTitle'}}
if resultsCount
table.table
tr
th Filename
th.right Size (kB)
th MIME Type
th MD5 Sum
th ID
each att in results
tr
td {{ att.filename }}
td.right {{fileSize att.length }}
td {{ att.contentType }}
td {{ att.md5 }}
td {{ att._id.toHexString }}
td {{ att.name }}
td.right {{fileSize att.size }}
td {{ att.type }}
td {{ att._id }}
td {{ att.meta.boardId }}
td {{ att.meta.cardId }}
else
div {{_ 'no-results' }}

View file

@ -26,7 +26,6 @@ BlazeComponent.extendComponent({
{
'click a.js-report-broken': this.switchMenu,
'click a.js-report-files': this.switchMenu,
'click a.js-report-orphaned-files': this.switchMenu,
'click a.js-report-rules': this.switchMenu,
'click a.js-report-cards': this.switchMenu,
'click a.js-report-boards': this.switchMenu,
@ -66,11 +65,6 @@ BlazeComponent.extendComponent({
this.subscription = Meteor.subscribe('attachmentsList', () => {
this.loading.set(false);
});
} else if ('report-orphaned-files' === targetID) {
this.showOrphanedFilesReport.set(true);
this.subscription = Meteor.subscribe('orphanedAttachments', () => {
this.loading.set(false);
});
} else if ('report-rules' === targetID) {
this.subscription = Meteor.subscribe('rulesReport', () => {
this.showRulesReport.set(true);
@ -104,8 +98,6 @@ class AdminReport extends BlazeComponent {
results() {
// eslint-disable-next-line no-console
// console.log('attachments:', AttachmentStorage.find());
// console.log('attachments.count:', AttachmentStorage.find().count());
return this.collection.find();
}
@ -125,10 +117,6 @@ class AdminReport extends BlazeComponent {
return Math.round(size / 1024);
}
usageCount(key) {
return Attachments.find({ 'copies.attachments.key': key }).count();
}
abbreviate(text) {
if (text.length > 30) {
return `${text.substr(0, 29)}...`;
@ -138,13 +126,9 @@ class AdminReport extends BlazeComponent {
}
(class extends AdminReport {
collection = AttachmentStorage;
collection = Attachments;
}.register('filesReport'));
(class extends AdminReport {
collection = AttachmentStorage;
}.register('orphanedFilesReport'));
(class extends AdminReport {
collection = Rules;

View file

@ -1,3 +0,0 @@
.admin-reports-content
height: auto !important

View file

@ -0,0 +1,84 @@
template(name="attachments")
.setting-content.attachments-content
unless currentUser.isAdmin
| {{_ 'error-notAuthorized'}}
else
.content-body
.side-menu
ul
li
a.js-move-attachments(data-id="move-attachments")
i.fa.fa-arrow-right
| {{_ 'attachment-move'}}
.main-body
if loading.get
+spinner
else if showMoveAttachments.get
+moveAttachments
template(name="moveAttachments")
.move-attachment-buttons
.js-move-attachment
button.js-move-all-attachments-to-fs {{_ 'move-all-attachments-to-fs'}}
.js-move-attachment
button.js-move-all-attachments-to-gridfs {{_ 'move-all-attachments-to-gridfs'}}
each board in getBoardsWithAttachments
+moveBoardAttachments board
template(name="moveBoardAttachments")
hr
.board-description
table
tr
th {{_ 'board'}} ID
th {{_ 'board-title'}}
tr
td {{ _id }}
td {{ title }}
.move-attachment-buttons
.js-move-attachment
button.js-move-all-attachments-of-board-to-fs {{_ 'move-all-attachments-of-board-to-fs'}}
.js-move-attachment
button.js-move-all-attachments-of-board-to-gridfs {{_ 'move-all-attachments-of-board-to-gridfs'}}
.board-attachments
table
tr
th {{_ 'card'}}-Id
th {{_ 'attachment'}}-Id
th {{_ 'name'}}
th {{_ 'path'}}
th {{_ 'version-name'}}
th {{_ 'size'}} (B)
th GridFsFileId
th {{_ 'storage'}}
th {{_ 'action'}}
each attachment in attachments
+moveAttachment attachment
template(name="moveAttachment")
each version in flatVersion
tr
td {{ meta.cardId }}
td {{ _id }}
td {{ name }}
td {{ version.path }}
td {{ version.versionName }}
td {{ version.size }}
td {{ version.meta.gridFsFileId }}
td {{ version.storageName }}
td
if $neq version.storageName "fs"
button.js-move-storage-fs
i.fa.fa-arrow-right
| {{_ 'attachment-move-storage-fs'}}
if $neq version.storageName "gridfs"
if version.storageName
button.js-move-storage-gridfs
i.fa.fa-arrow-right
| {{_ 'attachment-move-storage-gridfs'}}

View file

@ -0,0 +1,123 @@
import Attachments, { fileStoreStrategyFactory } from '/models/attachments';
BlazeComponent.extendComponent({
subscription: null,
showMoveAttachments: new ReactiveVar(false),
sessionId: null,
onCreated() {
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
},
events() {
return [
{
'click a.js-move-attachments': this.switchMenu,
},
];
},
switchMenu(event) {
const target = $(event.target);
if (!target.hasClass('active')) {
this.loading.set(true);
this.showMoveAttachments.set(false);
if (this.subscription) {
this.subscription.stop();
}
$('.side-menu li.active').removeClass('active');
target.parent().addClass('active');
const targetID = target.data('id');
if ('move-attachments' === targetID) {
this.showMoveAttachments.set(true);
this.subscription = Meteor.subscribe('attachmentsList', () => {
this.loading.set(false);
});
}
}
},
}).register('attachments');
BlazeComponent.extendComponent({
getBoardsWithAttachments() {
this.attachments = Attachments.find().get();
this.attachmentsByBoardId = _.chain(this.attachments)
.groupBy(fileObj => fileObj.meta.boardId)
.value();
const ret = Object.keys(this.attachmentsByBoardId)
.map(boardId => {
const boardAttachments = this.attachmentsByBoardId[boardId];
_.each(boardAttachments, _attachment => {
_attachment.flatVersion = Object.keys(_attachment.versions)
.map(_versionName => {
const _version = Object.assign(_attachment.versions[_versionName], {"versionName": _versionName});
_version.storageName = fileStoreStrategyFactory.getFileStrategy(_attachment, _versionName).getStorageName();
return _version;
});
});
const board = Boards.findOne(boardId);
board.attachments = boardAttachments;
return board;
})
return ret;
},
getBoardData(boardid) {
const ret = Boards.findOne(boardId);
return ret;
},
events() {
return [
{
'click button.js-move-all-attachments-to-fs'(event) {
this.attachments.forEach(_attachment => {
Meteor.call('moveAttachmentToStorage', _attachment._id, "fs");
});
},
'click button.js-move-all-attachments-to-gridfs'(event) {
this.attachments.forEach(_attachment => {
Meteor.call('moveAttachmentToStorage', _attachment._id, "gridfs");
});
},
}
]
}
}).register('moveAttachments');
BlazeComponent.extendComponent({
events() {
return [
{
'click button.js-move-all-attachments-of-board-to-fs'(event) {
this.data().attachments.forEach(_attachment => {
Meteor.call('moveAttachmentToStorage', _attachment._id, "fs");
});
},
'click button.js-move-all-attachments-of-board-to-gridfs'(event) {
this.data().attachments.forEach(_attachment => {
Meteor.call('moveAttachmentToStorage', _attachment._id, "gridfs");
});
},
}
]
},
}).register('moveBoardAttachments');
BlazeComponent.extendComponent({
events() {
return [
{
'click button.js-move-storage-fs'(event) {
Meteor.call('moveAttachmentToStorage', this.data()._id, "fs");
},
'click button.js-move-storage-gridfs'(event) {
Meteor.call('moveAttachmentToStorage', this.data()._id, "gridfs");
},
}
]
},
}).register('moveAttachment');

View file

@ -0,0 +1,8 @@
.move-attachment-buttons
display: flex
gap: 10px
.attachments-content
hr
height: 0px
border: 1px solid black

View file

@ -2,8 +2,6 @@
overflow: scroll;
table
border-collapse: collapse;
width: 100%;
color: #000;
td, th
@ -22,14 +20,13 @@ table
.ext-box-left
display: flex;
width: 100%
gap: 10px
span
vertical-align: center;
line-height: 34px;
margin-right: 10px;
input, button
margin: 0 10px 0 0;
padding: 0;
button

View file

@ -7,11 +7,9 @@
display: flex
.setting-content
padding 30px
color: #727479
background: #dedede
width 100%
height calc(100% - 80px)
position: absolute;
.content-title
@ -21,6 +19,7 @@
display flex
padding-top 15px
height 100%
gap: 10px;
.side-menu
background-color: #f7f7f7;
@ -54,7 +53,6 @@
margin-right: 20px
.main-body
padding: 0.1em 1em
-webkit-user-select: text // Safari 3.1+
-moz-user-select: text // Firefox 2+
-ms-user-select: text // IE 10+

View file

@ -16,6 +16,10 @@ template(name="settingHeaderBar")
i.fa(class="fa-list")
span {{_ 'reports'}}
a.setting-header-btn.informations(href="{{pathFor 'attachments'}}")
i.fa(class="fa-paperclip")
span {{_ 'attachments'}}
a.setting-header-btn.informations(href="{{pathFor 'information'}}")
i.fa(class="fa-info-circle")
span {{_ 'info'}}