Merge pull request #3495 from ulferts/fix/attachment_on_wp_create

Fix/attachment on wp create
pull/3505/head
Jan Sandbrink 9 years ago
commit 0cafe9afd0
  1. 5
      app/assets/stylesheets/content/_links.sass
  2. 2
      frontend/app/templates/work_packages/attachments-edit.html
  3. 60
      frontend/app/templates/work_packages/attachments.html
  4. 20
      frontend/app/work_packages/directives/work-package-attachments-directive.js
  5. 118
      frontend/tests/unit/tests/work_packages/directives/work-package-attachments-directive-test.js

@ -59,6 +59,11 @@ a
&.work_package.closed, &.work_package.closed:hover
text-decoration: line-through
&.-no-decoration
color: inherit
&:hover
text-decoration: none
a.icon, a.icon-context
color: $content-icon-link-color

@ -12,7 +12,7 @@
data-ngf-select
class="work-package--attachments--drop-box"
data-ngf-multiple="true"
data-ngf-change="instantUpload()"
data-ngf-change="uploadFilteredFiles($files)"
data-ngf-max-size="{{::maximumFileSize}}">
<p class="work-package--attachments--label">{{ ::I18n.t('js.label_drop_files') }}</p>
<p class="work-package--attachments--hint">{{ ::I18n.t('js.label_drop_files_hint') }}</p>

@ -6,20 +6,58 @@
</h3>
</div>
</div>
<div data-ngf-drop data-ng-model="files" data-ng-model-rejected="rejectedFiles" data-ngf-select class="work-package--attachments--drop-box"
data-ngf-multiple="true" data-ngf-allow-dir="true" data-ngf-keep-distinct data-ngf-max-size="{{::maximumFileSize}}"
data-ng-disabled="fetchingConfiguration" data-ngf-keep="true">
<div data-ngf-drop
data-ng-model="files"
data-ng-model-rejected="rejectedFiles"
data-ngf-select
class="work-package--attachments--drop-box"
data-ngf-multiple="true"
data-ngf-allow-dir="true"
data-ngf-keep-distinct
data-ngf-max-size="{{::maximumFileSize}}"
data-ng-disabled="fetchingConfiguration"
data-ngf-keep="true"
data-ngf-change="filterFiles($files)">
<p data-ng-hide="fetchingConfiguration" class="work-package--attachments--label">{{ ::I18n.t('js.label_drop_files') }}</p>
<p data-ng-hide="fetchingConfiguration" class="work-package--attachments--hint">{{ ::I18n.t('js.label_drop_files_hint') }}</p>
<p data-ng-show="fetchingConfiguration" class="work-package--attachments--label">{{ ::I18n.t('js.label_wait') }}</p>
</div>
<div class="work-package--attachments--files" data-ng-show="files.length > 0">
<h4>{{::I18n.t('js.label_files_to_upload')}}</h4>
<ul>
<li data-ng-repeat="file in files">
<attachment-icon type="file.type"></attachment-icon> <span class="filename">{{::file.name}}</span> <span class="filesize">({{::size(file.size)}})</span>
<a data-ng-click="remove(file)" class="button -with-icon icon-delete -tiny" title="{{::I18n.t('js.label_remove_file')}}">{{::I18n.t('js.label_remove_file')}}</a>
</li>
</ul>
<div class="work-package--attachments--files"
data-ng-show="files.length > 0">
<div class="work-package--details--long-field">
<span class="inplace-edit--read"
data-ng-repeat="attachment in files">
<span class="inplace-editing--trigger-container">
<span class="inplace-editing--trigger-link"
ng-class="{'-focus': focussing(attachment)}">
<span class="inplace-editing--container">
<span class="inplace-edit--read-value" >
<attachment-icon type="attachment.contentType"></attachment-icon>
<a class="work-package--attachments--filename -no-decoration"
href=""
data-ng-focus="focus(attachment)"
data-ng-blur="focus(null)"
ng-click="true">
{{::attachment.name}}
</a>
<span class="work-package--attachments--filesize">({{::size(attachment.size)}})</span>
</span>
<a href=''
class="inplace-edit--icon-wrapper"
data-ng-focus="focus(attachment)"
data-ng-blur="focus(null)"
data-ng-click="remove(attachment)"
data-confirm-popup="{{I18n.t('js.text_attachment_destroy_confirmation')}}">
<icon-wrapper icon-name="delete"
data-icon-title="{{::I18n.t('js.label_remove_file',
{ fileName: attachment.name })}}">
</icon-wrapper>
</a>
</span>
</span>
</span>
</span>
</div>
</div>
</div>

@ -69,10 +69,6 @@ module.exports = function(
scope.rejectedFiles = [];
scope.size = ConversionService.fileSize;
scope.instantUpload = function() {
scope.$emit('uploadPendingAttachments', workPackage);
};
var currentlyRemoving = [];
scope.remove = function(file) {
currentlyRemoving.push(file);
@ -99,6 +95,22 @@ module.exports = function(
};
scope.$on('uploadPendingAttachments', upload);
scope.filterFiles = function(files) {
// Directories cannot be uploaded and as such, should not become files in
// the sense of this directive. The files within the direcotories will
// be taken though.
_.remove(files, function(file) {
return file.type === 'directory';
});
};
scope.uploadFilteredFiles = function(files) {
scope.filterFiles(files);
scope.$emit('uploadPendingAttachments', workPackage);
};
scope.$watch('rejectedFiles', function(rejectedFiles) {
if (rejectedFiles.length === 0) {
return;

@ -0,0 +1,118 @@
//-- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2015 the OpenProject Foundation (OPF)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License version 3.
//
// OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
// Copyright (C) 2006-2013 Jean-Philippe Lang
// Copyright (C) 2010-2013 the ChiliProject Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// See doc/COPYRIGHT.rdoc for more details.
//++
describe('WorkPackageAttachmentsDirective', function() {
var compile, element, rootScope, scope, isolatedScope, workPackage = {};
beforeEach(angular.mock.module('openproject.workPackages.directives'));
beforeEach(module('openproject.templates'));
var loadPromise,
workPackageAttachmentsService = {
load: function() {
return loadPromise;
}
},
apiPromise,
configurationService = {
api: function() {
return apiPromise;
}
};
beforeEach(module('openproject.workPackages.services', function($provide) {
$provide.constant('WorkPackageAttachmentsService', workPackageAttachmentsService);
}));
beforeEach(module('openproject.config', function($provide) {
$provide.constant('ConfigurationService', configurationService);
}));
beforeEach(inject(function($rootScope, $compile, $q) {
apiPromise = $q(function(resolve) {
return resolve('');
});
loadPromise = $q(function(resolve) {
return resolve([]);
});
var html = '<work-package-attachments edit work-package="workPackage">' +
'</work-package-attachments>';
element = angular.element(html);
rootScope = $rootScope;
scope = $rootScope.$new();
scope.workPackage = workPackage;
compile = function() {
$compile(element)(scope);
scope.$digest();
};
}));
describe('filterFiles', function() {
beforeEach(function() {
compile();
isolatedScope = element.isolateScope();
});
it('filters out attachments of type directory', function() {
var files = [{type: 'directory'}, {type: 'file'}];
isolatedScope.filterFiles(files, {}, {}, false);
expect(files).to.eql([{type: 'file'}]);
});
});
describe('uploadFilteredFiles', function() {
var files = [{type: 'directory'}, {type: 'file'}],
dumbPromise = {
then: function(call) { return call(); }
};
beforeEach(function() {
compile();
isolatedScope = element.isolateScope();
});
it('triggers uploading of non directory files', function() {
//need to have files to be able to trigger uploads
isolatedScope.files = files;
var uploadStub = workPackageAttachmentsService.upload = sinon.stub().returns(dumbPromise);
isolatedScope.uploadFilteredFiles(files, {}, {}, true);
expect(uploadStub.calledWith(workPackage, [{type: 'file'}])).to.be.true;
});
});
});
Loading…
Cancel
Save