Add work package edit actions toolbar (save & cancel)

Saving the work package does not work as of yet.
pull/3701/head
Alex Dik 9 years ago committed by Jens Ulferts
parent 880cd83485
commit 40167485a9
  1. 6
      app/assets/stylesheets/layout/_work_package.sass
  2. 4
      frontend/app/templates/work_packages.list.details.html
  3. 6
      frontend/app/templates/work_packages.show.html
  4. 6
      frontend/app/templates/work_packages/work_package_details_toolbar.html
  5. 40
      frontend/app/templates/work_packages/work_package_edit_actions.html
  6. 6
      frontend/app/work_packages/controllers/work-package-show-controller.js
  7. 4
      frontend/app/work_packages/directives/index.js
  8. 5
      frontend/app/work_packages/directives/inplace_editor/inplace-editor-edit-pane-directive.js
  9. 29
      frontend/app/work_packages/directives/work-package-details-toolbar-directive.js
  10. 43
      frontend/app/work_packages/directives/work-package-edit-actions-directive.js
  11. 8
      frontend/app/work_packages/services/editable-fields-state.js
  12. 6
      frontend/tests/integration/pages/work-package-show-page.js
  13. 44
      frontend/tests/integration/specs/work-packages/work-package-edit-spec.js
  14. 8
      frontend/tests/unit/tests/work_packages/services/editable-fields-state-test.js

@ -178,6 +178,12 @@
.work-packages--attachments .work-packages--attachments
margin-bottom: 25px margin-bottom: 25px
.work-packages--edit-actions
@extend .work-packages--details-toolbar
.work-packages--left-panel &
position: static
.work-package--attachments--files .work-package--attachments--files
margin-bottom: 1rem margin-bottom: 1rem

@ -54,6 +54,6 @@
</div> </div>
<div class="bottom-toolbar"> <div class="bottom-toolbar">
<work-package-details-toolbar work-package='workPackage'> <work-package-details-toolbar work-package='workPackage'></work-package-details-toolbar>
</work-package-details-toolbar> <work-package-edit-actions work-package="workPackage"></work-package-edit-actions>
</div> </div>

@ -15,7 +15,8 @@
</li> </li>
<li class="toolbar-item"> <li class="toolbar-item">
<button class="button" <button class="button"
ng-click="editWorkPackage()" ng-class="{'-active': editAll.state}"
ng-click="editAll.toggleState()"
title="{{I18n.t('js.button_edit')}}"> title="{{I18n.t('js.button_edit')}}">
<i class="button--icon icon-edit"></i> <i class="button--icon icon-edit"></i>
</button> </button>
@ -168,6 +169,9 @@
</div> </div>
<work-package-attachments edit data-ng-show="!vm.hideEmptyFields || vm.filesExist" work-package="vm.workPackage"></work-package-attachments> <work-package-attachments edit data-ng-show="!vm.hideEmptyFields || vm.filesExist" work-package="vm.workPackage"></work-package-attachments>
<work-package-edit-actions work-package="vm.workPackage"></work-package-edit-actions>
</div> </div>
</div> </div>
<div class="work-packages--right-panel"> <div class="work-packages--right-panel">

@ -1,7 +1,5 @@
<div class="work-packages--details-toolbar"> <div class="work-packages--details-toolbar" ng-hide="editAll.state">
<button class="button" <button class="button" accesskey="3" ng-click="editAll.start()">
accesskey="3"
ng-click="editWorkPackage()">
<i class="button--icon icon-edit"></i> <i class="button--icon icon-edit"></i>
<span class="button--text" ng-bind="::I18n.t('js.button_edit')"></span> <span class="button--text" ng-bind="::I18n.t('js.button_edit')"></span>
</button> </button>

@ -0,0 +1,40 @@
<!--
~ -- 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.
~ ++
-->
<div class="work-packages--edit-actions" ng-show="efs.editAll.state">
<button class="button" accesskey="3" ng-click="efs.editAll.stop()">
<i class="button--icon icon-save1"></i>
<span class="button--text" ng-bind="::I18n.t('js.button_save')"></span>
</button>
<button class="button" accesskey="7" ng-click="efs.editAll.stop()">
<i class="button--icon icon-cancel"></i>
<span class="button--text" ng-bind="::I18n.t('js.button_cancel')"></span>
</button>
</div>

@ -64,6 +64,8 @@ module.exports = function($scope,
$scope.can = AuthorisationService.can; $scope.can = AuthorisationService.can;
$scope.cannot = AuthorisationService.cannot; $scope.cannot = AuthorisationService.cannot;
$scope.editAll = EditableFieldsState.editAll;
$scope.$on('$stateChangeSuccess', function(event, toState){ $scope.$on('$stateChangeSuccess', function(event, toState){
latestTab.registerState(toState.name); latestTab.registerState(toState.name);
}); });
@ -389,10 +391,6 @@ module.exports = function($scope,
$scope.workPackage $scope.workPackage
); );
$scope.editWorkPackage = function() {
EditableFieldsState.editAll.toggleState();
};
// Stuff copied from DetailsTabOverviewController // Stuff copied from DetailsTabOverviewController
var vm = this; var vm = this;

@ -85,9 +85,11 @@ angular.module('openproject.workPackages.directives')
'HookService', 'HookService',
'WorkPackageService', 'WorkPackageService',
'WorkPackageAuthorization', 'WorkPackageAuthorization',
'EditableFieldsState',
require('./work-package-details-toolbar-directive') require('./work-package-details-toolbar-directive')
]) ])
.directive('workPackageEditActions', [
require('./work-package-edit-actions-directive')
])
.directive('workPackageDynamicAttribute', ['$compile', require( .directive('workPackageDynamicAttribute', ['$compile', require(
'./work-package-dynamic-attribute-directive')]) './work-package-dynamic-attribute-directive')])
.directive('workPackageGroupHeader', require( .directive('workPackageGroupHeader', require(

@ -194,13 +194,8 @@ module.exports = function(
} }
$scope.$watch('editableFieldsState.editAll.state', function(state) { $scope.$watch('editableFieldsState.editAll.state', function(state) {
var field = $scope.fieldController.field;
$scope.fieldController.isEditing = state; $scope.fieldController.isEditing = state;
$scope.fieldController.lockFocus = true; $scope.fieldController.lockFocus = true;
if (EditableFieldsState.editAll.isFocusField(field)) {
vm.markActive();
}
}); });
}, },
link: function(scope, element, attrs, fieldController) { link: function(scope, element, attrs, fieldController) {

@ -26,15 +26,15 @@
// See doc/COPYRIGHT.rdoc for more details. // See doc/COPYRIGHT.rdoc for more details.
//++ //++
module.exports = function(PERMITTED_MORE_MENU_ACTIONS, module.exports = function(
$state, PERMITTED_MORE_MENU_ACTIONS,
$window, $state,
$location, $window,
I18n, $location,
HookService, I18n,
WorkPackageService, HookService,
WorkPackageAuthorization, WorkPackageService,
EditableFieldsState) { WorkPackageAuthorization) {
function getPermittedActions(authorization, permittedMoreMenuActions) { function getPermittedActions(authorization, permittedMoreMenuActions) {
var permittedActions = authorization.permittedActions(permittedMoreMenuActions); var permittedActions = authorization.permittedActions(permittedMoreMenuActions);
@ -76,7 +76,12 @@ module.exports = function(PERMITTED_MORE_MENU_ACTIONS,
scope: { scope: {
workPackage: '=' workPackage: '='
}, },
link: function(scope, element, attributes) {
controller: ['$scope', 'EditableFieldsState', function ($scope, EditableFieldsState) {
$scope.editAll = EditableFieldsState.editAll;
}],
link: function(scope) {
var authorization = new WorkPackageAuthorization(scope.workPackage); var authorization = new WorkPackageAuthorization(scope.workPackage);
scope.I18n = I18n; scope.I18n = I18n;
@ -84,10 +89,6 @@ module.exports = function(PERMITTED_MORE_MENU_ACTIONS,
getPermittedPluginActions(authorization)); getPermittedPluginActions(authorization));
scope.actionsAvailable = Object.keys(scope.permittedActions).length > 0; scope.actionsAvailable = Object.keys(scope.permittedActions).length > 0;
scope.editWorkPackage = function() {
EditableFieldsState.editAll.toggleState();
};
scope.triggerMoreMenuAction = function(action, link) { scope.triggerMoreMenuAction = function(action, link) {
switch (action) { switch (action) {
case 'delete': case 'delete':

@ -0,0 +1,43 @@
// -- 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.
// ++
module.exports = function () {
return {
restrict: 'E',
templateUrl: '/templates/work_packages/work_package_edit_actions.html',
scope: {
workPackage: '='
},
controller: ['$scope', 'I18n', 'EditableFieldsState',
function ($scope, I18n, EditableFieldsState) {
$scope.I18n = I18n;
$scope.efs = EditableFieldsState;
}]
};
};

@ -39,6 +39,14 @@ module.exports = function() {
focusField: 'subject', focusField: 'subject',
state: false, state: false,
start: function () {
return this.state = true;
},
stop: function () {
return this.state = false;
},
toggleState: function () { toggleState: function () {
return this.state = !this.state; return this.state = !this.state;
}, },

@ -32,7 +32,11 @@ module.exports = function WorkPackageShowPage() {
this.editButton = $('.button[title="Edit"]'); this.editButton = $('.button[title="Edit"]');
this.focusElement = $('#work-package-subject .focus-input'); this.focusElement = $('#work-package-subject .focus-input');
this.editableFields = $$('.focus-input');
this.editActions = {
container: $('.work-packages--edit-actions'),
cancel: $('.work-packages--edit-actions .button:last-child')
};
this.get = function() { this.get = function() {
browser.get('/work_packages/' + wpId + '/activity'); browser.get('/work_packages/' + wpId + '/activity');

@ -37,23 +37,37 @@ describe('Work package edit', function() {
}; };
beforeEach(function () { describe('when clicking edit button on show page', function () {
page.get(); beforeEach(function () {
page.editButton.isPresent().then(function () { page.get();
page.editButton.click(); page.editButton.isPresent().then(function () {
}) page.editButton.click();
}); })
});
it('should focus the subject field when used', function() { it('should focus the subject field when used', function() {
page.focusElement.getId().then(expectFocusEquals); page.focusElement.getId().then(expectFocusEquals);
}); });
it('should show multiple editable input fields', function() { it('should show multiple editable input fields', function() {
expect($$('.focus-input').count()).to.eventually.be.above(1); expect(page.editableFields.count()).to.eventually.be.above(1);
}); });
it('should reset previously edited fields without focusing one', function() {
page.editButton.click();
page.editButton.getId().then(expectFocusEquals);
expect(page.editableFields.count()).to.eventually.equal(0);
});
it('should show the edit actions', function () {
expect(page.editActions.container.isDisplayed()).to.eventually.be.true;
});
it('should reset previously edited fields without focusing one', function() { describe('when triggering the edit actions', function () {
page.editButton.click(); it('should cancel editing when the cancel button is clicked', function () {
page.editButton.getId().then(expectFocusEquals); page.editActions.cancel.click();
expect(page.editableFields.count()).to.eventually.equal(0);
});
});
}); });
}); });

@ -41,6 +41,14 @@ describe('EditableFieldsState service', function () {
expect(EditableFieldsState.state === eAll.toggleState()).to.be.false; expect(EditableFieldsState.state === eAll.toggleState()).to.be.false;
}); });
it('turns on editing on start', function () {
expect(eAll.start()).to.be.true;
});
it('turns off editing on stop', function () {
expect(eAll.stop()).to.be.false;
});
it('matches its focused field', function () { it('matches its focused field', function () {
expect(eAll.isFocusField(eAll.focusField)).to.be.true; expect(eAll.isFocusField(eAll.focusField)).to.be.true;
}); });

Loading…
Cancel
Save