1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-07-21 14:19:43 +02:00

Provide per section attachments

Upload and delete attachments on a per section basis.
This commit is contained in:
Harvey Kandola 2019-04-18 13:31:48 +01:00
parent 166aeba09b
commit 61d0086337
13 changed files with 248 additions and 116 deletions

View file

@ -0,0 +1,108 @@
// Copyright 2016 Documize Inc. <legal@documize.com>. All rights reserved.
//
// This software (Documize Community Edition) is licensed under
// GNU AGPL v3 http://www.gnu.org/licenses/agpl-3.0.en.html
//
// You can operate outside the AGPL restrictions by purchasing
// Documize Enterprise Edition and obtaining a commercial license
// by contacting <sales@documize.com>.
//
// https://documize.com
import { inject as service } from '@ember/service';
import { computed } from '@ember/object';
import Modals from '../../mixins/modal';
import Notifier from '../../mixins/notifier';
import Component from '@ember/component';
export default Component.extend(Modals, Notifier, {
appMeta: service(),
session: service(),
editMode: false,
downloadQuery: '',
uploadId: computed('page', function () {
let page = this.get('page');
return `page-uploader-${page.id}`;
}),
uploadLabel: 'Upload Attachments',
uploaderReady: false,
didReceiveAttrs() {
this._super(...arguments);
// For authenticated users we send server auth token.
let qry = '';
if (this.get('session.hasSecureToken')) {
qry = '?secure=' + this.get('session.secureToken');
} else if (this.get('session.authenticated')) {
qry = '?token=' + this.get('session.authToken');
}
this.set('downloadQuery', qry);
},
didRender() {
this._super(...arguments);
// We don't setup uploader if not edit mode.
if (!this.get('editMode') || this.get('uploaderReady')) {
return;
}
let self = this;
let documentId = this.get('document.id');
let pageId = this.get('page.id');
let url = this.get('appMeta.endpoint');
let uploadUrl = `${url}/documents/${documentId}/attachments?page=${pageId}`;
let uploadId = this.get('uploadId');
// Handle upload clicks on button and anything inside that button.
let sel = ['#' + uploadId, '#' + uploadId + ' > div'];
for (var i=0; i < 2; i++) {
let dzone = new Dropzone(sel[i], {
headers: {
'Authorization': 'Bearer ' + self.get('session.authToken')
},
url: uploadUrl,
method: "post",
paramName: 'attachment',
clickable: true,
maxFilesize: 250,
parallelUploads: 5,
uploadMultiple: false,
addRemoveLinks: false,
autoProcessQueue: true,
init: function () {
this.on("success", function (/*file, response*/ ) {
});
this.on("queuecomplete", function () {
self.notifySuccess('Uploaded file');
self.get('onAttachmentUpload')();
});
this.on("addedfile", function ( /*file*/ ) {
});
this.on("error", function (error, msg) {
self.notifyError(msg);
self.notifyError(error);
});
}
});
dzone.on("complete", function (file) {
dzone.removeFile(file);
});
}
this.set('uploaderReady', true);
},
actions: {
onDelete(attachment) {
this.notifySuccess('File deleted');
this.get('onAttachmentDelete')(attachment.id);
}
}
});

View file

@ -10,7 +10,7 @@
// https://documize.com // https://documize.com
import $ from 'jquery'; import $ from 'jquery';
import { empty, notEmpty } from '@ember/object/computed'; import { empty } from '@ember/object/computed';
import { computed } from '@ember/object'; import { computed } from '@ember/object';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import Modals from '../../mixins/modal'; import Modals from '../../mixins/modal';
@ -26,17 +26,12 @@ export default Component.extend(Modals, Notifier, {
showLinkModal: false, showLinkModal: false,
files: null, files: null,
downloadQuery: '', downloadQuery: '',
hasAttachments: notEmpty('files'),
hasNameError: empty('page.title'), hasNameError: empty('page.title'),
hasDescError: empty('page.excerpt'), hasDescError: empty('page.excerpt'),
pageId: computed('page', function () { pageId: computed('page', function () {
let page = this.get('page'); let page = this.get('page');
return `page-editor-${page.id}`; return `page-editor-${page.id}`;
}), }),
uploadId: computed('page', function () {
let page = this.get('page');
return `page-uploader-${page.id}`;
}),
previewText: 'Preview', previewText: 'Preview',
pageTitle: '', pageTitle: '',
@ -70,67 +65,6 @@ export default Component.extend(Modals, Notifier, {
}); });
}, },
didInsertElement() {
this._super(...arguments);
let self = this;
let documentId = this.get('document.id');
let pageId = this.get('page.id');
let url = this.get('appMeta.endpoint');
let uploadUrl = `${url}/documents/${documentId}/attachments?page=${pageId}`;
let uploadId = this.get('uploadId');
// Handle upload clicks on button and anything inside that button.
let sel = ['#' + uploadId, '#' + uploadId + ' > div'];
for (var i=0; i < 2; i++) {
let dzone = new Dropzone(sel[i], {
headers: {
'Authorization': 'Bearer ' + self.get('session.authToken')
},
url: uploadUrl,
method: "post",
paramName: 'attachment',
clickable: true,
maxFilesize: 250,
parallelUploads: 5,
uploadMultiple: false,
addRemoveLinks: false,
autoProcessQueue: true,
init: function () {
this.on("success", function (/*file, response*/ ) {
});
this.on("queuecomplete", function () {
self.notifySuccess('Uploaded file');
self.getAttachments();
});
this.on("addedfile", function ( /*file*/ ) {
});
this.on("error", function (error, msg) {
self.notifyError(msg);
self.notifyError(error);
});
}
});
dzone.on("complete", function (file) {
dzone.removeFile(file);
});
}
// For authenticated users we send server auth token.
let qry = '';
if (this.get('session.hasSecureToken')) {
qry = '?secure=' + this.get('session.secureToken');
} else if (this.get('session.authenticated')) {
qry = '?token=' + this.get('session.authToken');
}
this.set('downloadQuery', qry);
},
willDestroyElement() { willDestroyElement() {
this._super(...arguments); this._super(...arguments);
this.set('showLinkModal', false); this.set('showLinkModal', false);
@ -142,12 +76,6 @@ export default Component.extend(Modals, Notifier, {
} }
}, },
getAttachments() {
this.get('documentSvc').getAttachments(this.get('document.id')).then((files) => {
this.set('files', files);
});
},
actions: { actions: {
onAction() { onAction() {
if (this.get('busy') || _.isEmpty(this.get('pageTitle'))) { if (this.get('busy') || _.isEmpty(this.get('pageTitle'))) {

View file

@ -36,7 +36,7 @@ export default Model.extend({
}), }),
tocIndent: computed('level', function () { tocIndent: computed('level', function () {
return (this.get('level') - 1) * 20; return (this.get('level') - 1) * 10;
}), }),
tocIndentCss: computed('tocIndent', function () { tocIndentCss: computed('tocIndent', function () {

View file

@ -222,6 +222,20 @@ export default Controller.extend(Notifier, {
this.get('router').transitionTo('document.settings', {queryParams: {tab: 'general'}}); this.get('router').transitionTo('document.settings', {queryParams: {tab: 'general'}});
}, },
onAttachmentUpload() {
this.get('documentService').getAttachments(this.get('document.id')).then((files) => {
this.set('attachments', files);
});
},
onAttachmentDelete(attachmentId) {
this.get('documentService').deleteAttachment(this.get('document.id'), attachmentId).then(() => {
this.get('documentService').getAttachments(this.get('document.id')).then((files) => {
this.set('attachments', files);
});
});
},
refresh(reloadPage) { refresh(reloadPage) {
return new EmberPromise((resolve) => { return new EmberPromise((resolve) => {
this.get('documentService').fetchDocumentData(this.get('document.id')).then((data) => { this.get('documentService').fetchDocumentData(this.get('document.id')).then((data) => {
@ -232,6 +246,7 @@ export default Controller.extend(Notifier, {
this.set('roles', data.roles); this.set('roles', data.roles);
this.set('links', data.links); this.set('links', data.links);
this.set('versions', data.versions); this.set('versions', data.versions);
this.set('attachments', data.attachments);
this.get('documentService').fetchPages(this.get('document.id'), this.get('session.user.id')).then((data) => { this.get('documentService').fetchPages(this.get('document.id'), this.get('session.user.id')).then((data) => {
this.set('pages', data); this.set('pages', data);

View file

@ -121,6 +121,7 @@
sections=sections sections=sections
document=document document=document
permissions=permissions permissions=permissions
attachments=attachments
currentPageId=currentPageId currentPageId=currentPageId
refresh=(action "refresh") refresh=(action "refresh")
onSavePage=(action "onSavePage") onSavePage=(action "onSavePage")
@ -130,5 +131,7 @@
onInsertSection=(action "onInsertSection") onInsertSection=(action "onInsertSection")
onSavePageAsBlock=(action "onSavePageAsBlock") onSavePageAsBlock=(action "onSavePageAsBlock")
onPageLevelChange=(action "onPageLevelChange") onPageLevelChange=(action "onPageLevelChange")
onPageSequenceChange=(action "onPageSequenceChange")}} onPageSequenceChange=(action "onPageSequenceChange")
onAttachmentUpload=(action "onAttachmentUpload")
onAttachmentDelete=(action "onAttachmentDelete")}}
{{/layout/master-content}} {{/layout/master-content}}

View file

@ -4,10 +4,6 @@
box-shadow: 0 0 0 0.75pt map-get($gray-shades, 200),0 0 3pt 0.75pt map-get($gray-shades, 200); box-shadow: 0 0 0 0.75pt map-get($gray-shades, 200),0 0 3pt 0.75pt map-get($gray-shades, 200);
border: 1px solid map-get($gray-shades, 200); border: 1px solid map-get($gray-shades, 200);
} }
> .attachments {
}
} }
.content-linker-modal-container { .content-linker-modal-container {

View file

@ -4,10 +4,6 @@
} }
} }
.dz-preview, .dz-processing {
display: none !important;
}
.document-sidebar-attachment { .document-sidebar-attachment {
> .files { > .files {
margin: 0; margin: 0;
@ -44,3 +40,40 @@
} }
} }
} }
.dz-preview, .dz-processing {
display: none !important;
}
.section-attachments {
margin: 1.5rem 0 0 0;
padding: 0;
> .file {
list-style-type: none;
margin: 0;
padding: 0;
width: 100%;
font-size: 1rem;
position: relative;
> a {
display: inline-block;
font-size: 1rem;
vertical-align: text-top;
margin-right: 10px;
width: 90%;
@extend .text-truncate;
color: map-get($green-shades, 800);
&:hover {
color: map-get($green-shades, 900);
}
}
> .menu {
position: absolute;
right: -10px;
top: 0;
}
}
}

View file

@ -1 +1,7 @@
{{component editorType document=document folder=folder page=page meta=meta onCancel=(action "onCancel") onAction=(action "onAction")}} {{component editorType
document=document
folder=folder
page=page
meta=meta
attachments=attachments
onCancel=(action "onCancel") onAction=(action "onAction")}}

View file

@ -6,6 +6,7 @@
folder=folder folder=folder
page=editPage page=editPage
meta=editMeta meta=editMeta
attachments=attachments
onCancel=(action "onCancelEdit") onCancel=(action "onCancelEdit")
onAction=(action "onSavePage")}} onAction=(action "onSavePage")}}
</div> </div>
@ -35,4 +36,9 @@
{{section/base-renderer page=page}} {{section/base-renderer page=page}}
</div> </div>
{{/if}} {{/if}}
{{document/section-attachment uploadLabel="Upload Attachments"
editMode=editMode page=page document=document files=attachments
onAttachmentUpload=(action onAttachmentUpload)
onAttachmentDelete=(action onAttachmentDelete)}}
</div> </div>

View file

@ -0,0 +1,39 @@
{{#if editMode}}
{{ui/ui-spacer size=200}}
{{ui/ui-button color=constants.Color.Gray label=uploadLabel id=uploadId}}
{{/if}}
<ul class="section-attachments">
{{#each files key="id" as |file|}}
{{#if (eq file.pageId page.id)}}
<li class="file">
<a href="{{appMeta.endpoint}}/public/attachment/{{appMeta.orgId}}/{{file.id}}{{downloadQuery}}">
{{file.filename}}
</a>
{{#if editMode}}
<div class="menu">
{{#ui/ui-toolbar dark=false light=false raised=false large=false bordered=false}}
{{#ui/ui-toolbar-icon icon=constants.Icon.Delete color=constants.Color.Red}}
{{#attach-popover class="ember-attacher-popper" hideOn="escapekey, clickout" showOn="click" isShown=false}}
<div class="form">
<p>Are you sure you want to delete this file?</p>
{{ui/ui-spacer size=100}}
{{ui/ui-button
light=false
label=constants.Label.Delete
color=constants.Color.Red
onClick=(action "onDelete" file)}}
</div>
{{/attach-popover}}
{{/ui/ui-toolbar-icon}}
{{/ui/ui-toolbar}}
</div>
{{/if}}
</li>
{{/if}}
{{/each}}
</ul>
{{#ui/ui-dialog title="Delete Attachment" confirmCaption="Delete" buttonColor=constants.Color.Red show=showDialog onAction=(action "onDelete")}}
<p>Are you sure you want to delete this attachment?</p>
{{/ui/ui-dialog}}

View file

@ -11,31 +11,32 @@
<div class="document-sidebar-attachment"> <div class="document-sidebar-attachment">
<ul class="files"> <ul class="files">
{{#each files key="id" as |file|}} {{#each files key="id" as |file|}}
<li class="file"> {{#if (eq file.pageId '')}}
<a href="{{appMeta.endpoint}}/public/attachment/{{appMeta.orgId}}/{{file.id}}{{downloadQuery}}"> <li class="file">
{{file.filename}} <a href="{{appMeta.endpoint}}/public/attachment/{{appMeta.orgId}}/{{file.id}}{{downloadQuery}}">
</a> {{file.filename}}
{{#if canEdit}} </a>
<div class="menu"> {{#if canEdit}}
{{#ui/ui-toolbar dark=false light=false raised=false large=false bordered=false}} <div class="menu">
{{#ui/ui-toolbar-icon icon=constants.Icon.Delete color=constants.Color.Red}} {{#ui/ui-toolbar dark=false light=false raised=false large=false bordered=false}}
{{#attach-popover class="ember-attacher-popper" hideOn="escapekey, clickout" showOn="click" isShown=false}} {{#ui/ui-toolbar-icon icon=constants.Icon.Delete color=constants.Color.Red}}
<div class="form"> {{#attach-popover class="ember-attacher-popper" hideOn="escapekey, clickout" showOn="click" isShown=false}}
<p>Are you sure you want to delete this file?</p> <div class="form">
{{ui/ui-spacer size=100}} <p>Are you sure you want to delete this file?</p>
{{ui/ui-button {{ui/ui-spacer size=100}}
light=false {{ui/ui-button
label=constants.Label.Delete light=false
color=constants.Color.Red label=constants.Label.Delete
onClick=(action "onDelete" file)}} color=constants.Color.Red
</div> onClick=(action "onDelete" file)}}
{{/attach-popover}} </div>
{{/ui/ui-toolbar-icon}} {{/attach-popover}}
{{/ui/ui-toolbar-icon}}
{{/ui/ui-toolbar}} {{/ui/ui-toolbar}}
</div> </div>
{{/if}} {{/if}}
</li> </li>
{{/if}}
{{/each}} {{/each}}
</ul> </ul>
</div> </div>

View file

@ -12,13 +12,16 @@
document=document document=document
pending=item.pending pending=item.pending
permissions=permissions permissions=permissions
attachments=attachments
refresh=(action refresh) refresh=(action refresh)
onAttachmentUpload=(action onAttachmentUpload)
onAttachmentDelete=(action onAttachmentDelete)
onSavePage=(action "onSavePage") onSavePage=(action "onSavePage")
onCopyPage=(action "onCopyPage") onCopyPage=(action "onCopyPage")
onMovePage=(action "onMovePage") onMovePage=(action "onMovePage")
onDeletePage=(action "onDeletePage") onDeletePage=(action "onDeletePage")
onSavePageAsBlock=(action "onSavePageAsBlock") onSavePageAsBlock=(action "onSavePageAsBlock")
onPageLevelChange=(action onPageLevelChange) onPageLevelChange=(action onPageLevelChange)
onPageSequenceChange=(action onPageSequenceChange) onPageSequenceChange=(action onPageSequenceChange)
onShowSectionWizard=(action "onShowSectionWizard")}} onShowSectionWizard=(action "onShowSectionWizard")}}
{{/each}} {{/each}}

View file

@ -41,12 +41,6 @@
<div class="canvas"> <div class="canvas">
{{yield}} {{yield}}
</div> </div>
<div class="attachments">
{{ui/ui-spacer size=100}}
{{ui/ui-button color=constants.Color.Gray label="Upload" id=uploadId}}
{{ui/ui-spacer size=100}}
</div>
</div> </div>
</div> </div>