Merge pull request #1587 from opf/fix/details-tab-properties-13694

Fix/details tab properties 13694
pull/1589/head
manwithtwowatches 11 years ago
commit 4419c9f87d
  1. 19
      app/assets/javascripts/angular/work_packages/controllers/work-package-details-controller.js
  2. 2
      config/locales/js-de.yml
  3. 2
      config/locales/js-en.yml
  4. 187
      karma/tests/controllers/work-package-details-controller-test.js
  5. 109
      public/templates/tabs/overview.html
  6. 2
      public/templates/work_packages/tabs/overview.html

@ -31,8 +31,7 @@ angular.module('openproject.workPackages.controllers')
.constant('DEFAULT_WORK_PACKAGE_PROPERTIES', [ .constant('DEFAULT_WORK_PACKAGE_PROPERTIES', [
'status', 'assignee', 'responsible', 'status', 'assignee', 'responsible',
'date', 'percentageDone', 'priority', 'date', 'percentageDone', 'priority',
'author', 'dueDate', 'estimatedTime', 'estimatedTime', 'versionName'
'startDate', 'versionName'
]) ])
.constant('USER_TYPE', 'user') .constant('USER_TYPE', 'user')
@ -94,17 +93,21 @@ angular.module('openproject.workPackages.controllers')
function getFormattedPropertyValue(property) { function getFormattedPropertyValue(property) {
if (property === 'date') { if (property === 'date') {
if (workPackage.props.startDate && workPackage.props.dueDate) { return getDateProperty();
return WorkPackagesHelper.formatWorkPackageProperty(workPackage.props['startDate'], 'startDate') +
' - ' +
WorkPackagesHelper.formatWorkPackageProperty(workPackage.props['dueDate'], 'dueDate');
}
} else { } else {
return WorkPackagesHelper.formatWorkPackageProperty(workPackage.props[property], property); return WorkPackagesHelper.formatWorkPackageProperty(workPackage.props[property], property);
} }
} }
function getDateProperty() {
if (workPackage.props.startDate || workPackage.props.dueDate) {
var displayedStartDate = WorkPackagesHelper.formatWorkPackageProperty(workPackage.props.startDate, 'startDate') || I18n.t('js.label_no_start_date'),
displayedEndDate = WorkPackagesHelper.formatWorkPackageProperty(workPackage.props.dueDate, 'dueDate') || I18n.t('js.label_no_due_date');
return displayedStartDate + ' - ' + displayedEndDate;
}
}
function addFormattedValueToPresentProperties(property, label, value, format) { function addFormattedValueToPresentProperties(property, label, value, format) {
var propertyData = { var propertyData = {
property: property, property: property,

@ -93,6 +93,8 @@ de:
label_move_column_right: "Spalte nach rechts verschieben" label_move_column_right: "Spalte nach rechts verschieben"
label_next: "Weiter" label_next: "Weiter"
label_no_data: "Nichts anzuzeigen" label_no_data: "Nichts anzuzeigen"
label_no_due_date: "kein Abgabedatum"
label_no_start_date: "kein Startdatum"
label_none: "kein" label_none: "kein"
label_not_contains: "enthält nicht" label_not_contains: "enthält nicht"
label_not_equals: "ist nicht" label_not_equals: "ist nicht"

@ -93,6 +93,8 @@ en:
label_move_column_right: "Move column right" label_move_column_right: "Move column right"
label_next: "Next" label_next: "Next"
label_no_data: "No data to display" label_no_data: "No data to display"
label_no_due_date: "no end date"
label_no_start_date: "no start date"
label_none: "none" label_none: "none"
label_not_contains: "doesn't contain" label_not_contains: "doesn't contain"
label_not_equals: "is not" label_not_equals: "is not"

@ -31,33 +31,45 @@
describe('WorkPackageDetailsController', function() { describe('WorkPackageDetailsController', function() {
var scope; var scope;
var buildController; var buildController;
var I18n = { t: angular.identity },
WorkPackagesHelper = {
formatWorkPackageProperty: angular.identity
},
workPackage = {
props: {
status: 'open',
versionName: null
},
embedded: {
activities: []
},
};
function buildWorkPackageWithId(id) {
angular.extend(workPackage.props, {id: id});
return workPackage;
}
beforeEach(module('openproject.api', 'openproject.services', 'openproject.workPackages.controllers')); beforeEach(module('openproject.api', 'openproject.services', 'openproject.workPackages.controllers'));
beforeEach(inject(function($rootScope, $controller, $timeout) { beforeEach(inject(function($rootScope, $controller, $timeout) {
scope = $rootScope.$new();
var workPackageId = 99; var workPackageId = 99;
buildController = function() { buildController = function() {
scope = $rootScope.$new();
ctrl = $controller("WorkPackageDetailsController", { ctrl = $controller("WorkPackageDetailsController", {
$scope: scope, $scope: scope,
$stateParams: { workPackageId: workPackageId }, $stateParams: { workPackageId: workPackageId },
I18n: I18n,
ConfigurationService: { ConfigurationService: {
commentsSortedInDescendingOrder: function() { commentsSortedInDescendingOrder: function() {
return false; return false;
} }
}, },
workPackage: { workPackage: buildWorkPackageWithId(workPackageId),
props: {
id: workPackageId
},
embedded: {
activities: []
}
}
}); });
// $timeout.flush(); $timeout.flush();
}; };
})); }));
@ -68,4 +80,157 @@ describe('WorkPackageDetailsController', function() {
}); });
}); });
describe('work package properties', function() {
function fetchPresentPropertiesWithName(propertyName) {
return scope.presentWorkPackageProperties.filter(function(propertyData) {
return propertyData.property === propertyName;
});
}
describe('when the property has a value', function() {
var propertyName = 'status';
beforeEach(function() {
buildController();
});
it('adds properties to present properties', function() {
expect(fetchPresentPropertiesWithName(propertyName)).to.have.length(1);
});
});
describe('when the property is among the first 3 properties', function() {
var propertyName = 'responsible';
beforeEach(function() {
buildController();
});
it('is added to present properties even if it is empty', function() {
expect(fetchPresentPropertiesWithName(propertyName)).to.have.length(1);
});
});
describe('when the property is among the second group of 3 properties', function() {
var propertyName = 'priority',
label = 'Priority';
beforeEach(function() {
sinon.stub(I18n, 't')
.withArgs('js.work_packages.properties.' + propertyName)
.returns(label);
buildController();
});
afterEach(function() {
I18n.t.restore();
});
describe('and none of these 3 properties is present', function() {
beforeEach(function() {
buildController();
});
it('is added to the empty properties', function() {
expect(scope.emptyWorkPackageProperties.indexOf(label)).to.be.greaterThan(-1);
});
});
describe('and at least one of these 3 properties is present', function() {
beforeEach(function() {
workPackage.props.percentageDone = '20';
buildController();
});
it('is added to the present properties', function() {
expect(fetchPresentPropertiesWithName(propertyName)).to.have.length(1);
});
});
});
describe('when the property is not among the first 6 properties', function() {
var propertyName = 'versionName',
label = 'Version';
beforeEach(function() {
sinon.stub(I18n, 't')
.withArgs('js.work_packages.properties.' + propertyName)
.returns(label);
buildController();
});
afterEach(function() {
I18n.t.restore();
});
it('adds properties that without values to empty properties', function() {
expect(scope.emptyWorkPackageProperties.indexOf(label)).to.be.greaterThan(-1);
});
});
describe('date property', function() {
var startDate = '2014-07-09',
dueDate = '2014-07-10',
placeholder = 'placeholder';
describe('when only the due date is present', function() {
beforeEach(function() {
sinon.stub(I18n, 't')
.withArgs('js.label_no_start_date')
.returns(placeholder);
workPackage.props.startDate = null;
workPackage.props.dueDate = dueDate;
buildController();
});
afterEach(function() {
I18n.t.restore();
});
it('renders the due date and a placeholder for the start date as date property', function() {
expect(fetchPresentPropertiesWithName('date')[0].value).to.equal(placeholder + ' - Jul 10, 2014');
});
});
describe('when only the start date is present', function() {
beforeEach(function() {
sinon.stub(I18n, 't')
.withArgs('js.label_no_due_date')
.returns(placeholder);
workPackage.props.startDate = startDate;
workPackage.props.dueDate = null;
buildController();
});
afterEach(function() {
I18n.t.restore();
});
it('renders the start date and a placeholder for the due date as date property', function() {
expect(fetchPresentPropertiesWithName('date')[0].value).to.equal('Jul 9, 2014 - ' + placeholder);
});
});
describe('when both - start and due date are present', function() {
beforeEach(function() {
workPackage.props.startDate = startDate;
workPackage.props.dueDate = dueDate;
buildController();
});
it('combines them and renders them as date property', function() {
expect(fetchPresentPropertiesWithName('date')[0].value).to.equal('Jul 9, 2014 - Jul 10, 2014');
});
});
});
});
}); });

@ -1,109 +0,0 @@
<div class="detail-panel-description">
<h3>Description</h3>
<div class="detail-panel-description-content">
{{ workPackage.props.description }}
</div>
</div>
<div class="panel-toggler" ng-click="toggleStates.hideFullDescription = !toggleStates.hideFullDescription">
<fieldset>
<legend align="center">
<span ng-if="!toggleStates.hideFullDescription">
<i class="icon-arrow-right5-2"></i>
Hide full description
</span>
<span ng-if="toggleStates.hideFullDescription">
<i class="icon-arrow-right5-3"></i>
Show full description
</span>
</legend>
</fieldset>
</div>
<div class="detail-panel-attributes" slide-toggle collapsed="toggleStates.hideFullDescription">
<ul>
<li><label>Status</label>{{ workPackage.props.status }}</li>
<li><label>Priortiy</label>{{ workPackage.props.priority }}</li>
<li><label>Date</label>{{ workPackage.props.startDate }} - {{ workPackage.props.dueDate }}</li>
<li>
<label>Responsible</label>
<img class="avatar" ng-src="{{ responsible.props.avatar }}" ng-show="{{ !!responsible }}" />
<span class="user" ng-show="{{ !!responsible }}">
<a ng-href="{{ userPath(responsible.props.id) }}">
{{ responsible.props.firstName }} {{ responsible.props.lastName }}
aaa
</a>
</span>
<span class="user" ng-hide="{{ !!responsible }}"> - </span>
<!-- <span class="role">{{ responsible.props.role }}</span> -->
</li>
<li>
<label>Assignee</label>
<img class="avatar" ng-src="{{ assignee.props.avatar }}" ng-show="{{ !!assignee }}" />
<span class="user" ng-show="{{ !!assignee }}">
<a ng-href="{{ userPath(assignee.props.id) }}">
{{ assignee.props.firstName }} {{ assignee.props.lastName }}
</a>
</span>
<span class="user" ng-hide="{{ !!assignee }}"> - </span>
<!-- <span class="role">{{ assignee.props.roles }}</span> -->
</li>
<li><label>% Done</label>{{ workPackage.props.percentageDone }} %</li>
</ul>
</div>
<div class="panel-toggler" ng-click="toggleStates.hideAllAttributes = !toggleStates.hideAllAttributes">
<fieldset>
<legend align="center">
<span ng-if="!toggleStates.hideAllAttributes">
<i class="icon-arrow-right5-2"></i>
Hide all attributes
</span>
<span ng-if="toggleStates.hideAllAttributes">
<i class="icon-arrow-right5-3"></i>
Show all attributes
</span>
</legend>
</fieldset>
</div>
<div class="detail-panel-latest-activity" slide-toggle collapsed="toggleStates.hideAllAttributes">
<h3>Latest activity</h3>
<ul>
<li>
<div class="comments-number"><a href="#1">#1</a>
<div class="comments-icons"><i class="icon-quote"></i><i class="icon-edit"></i></div>
</div>
<img class="avatar" src="images/avatar_logout.png" />
<span class="user"><a href="#">Christoph Zierz</a></span>
<span class="date">commented on 06/05/2014 16:42 Uhr</span>
<span class="comment">Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis . ..
</span>
</li>
<li>
<div class="comments-number"><a href="#1">#2</a>
<div class="comments-icons"><i class="icon-quote"></i><i class="icon-edit"></i></div>
</div>
<img class="avatar" src="images/avatar_logout.png" />
<span class="user"><a href="#">Niels Lindenthal</a></span>
<span class="date">commented on 08/05/2014 16:42 Uhr</span>
<span class="comment">
<ul>
<li>Status changed from scheduled to closed</li>
<li>Assignee deleted (Michael Frister)</li>
<li>% done changed from 0 to 100</li>
</ul>
</span>
</li>
</ul>
</div>
<div class="comments-form">
<h3>Add your comments here</h3>
<form>
<textarea placeholder="Add comments here" rows="4"></textarea>
</form>
<button class="button">Add comment</button>
</div>

@ -15,7 +15,7 @@
<label ng-bind="propertyData.label"/> <label ng-bind="propertyData.label"/>
<span ng-switch="propertyData.format"> <span ng-switch="propertyData.format">
<user-field ng-switch-when="user" user="propertyData.value"></user-field> <user-field ng-switch-when="user" user="propertyData.value"></user-field>
<span ng-switch-default ng-bind="propertyData.value"/> <span ng-switch-default ng-bind="propertyData.value || '-'"/>
</span> </span>
</li> </li>
</ul> </ul>

Loading…
Cancel
Save