Merge pull request #4643 from oliverguenther/fix/20417/current-tab-label
[20417] Remove code duplication in details,show and fix tab switchingpull/4653/merge
commit
3a789189cf
@ -1,163 +0,0 @@ |
||||
// -- 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('WorkPackageDetailsController', function() { |
||||
var scope; |
||||
var promise; |
||||
var buildController, ctrl; |
||||
var stateParams = {}; |
||||
var I18n = { t: angular.identity }, |
||||
workPackage = { |
||||
author: { |
||||
props: { |
||||
id: 1, |
||||
status: 'active' |
||||
} |
||||
}, |
||||
id: 99, |
||||
project: { |
||||
props: { |
||||
id: 1 |
||||
} |
||||
}, |
||||
type: { |
||||
name: 'Milestone' |
||||
}, |
||||
href: "it's a me, it's... you know..." |
||||
}; |
||||
|
||||
beforeEach(angular.mock.module('openproject.api', 'openproject.layout', 'openproject.services', |
||||
'openproject.workPackages.controllers', 'openproject.services', 'openproject')); |
||||
|
||||
beforeEach(angular.mock.module('openproject.templates', function($provide) { |
||||
var configurationService = {}; |
||||
|
||||
configurationService.isTimezoneSet = sinon.stub().returns(false); |
||||
|
||||
$provide.constant('ConfigurationService', configurationService); |
||||
})); |
||||
|
||||
beforeEach(angular.mock.module('openproject.templates', function($provide) { |
||||
var state = { go: function() { return false; } }; |
||||
$provide.value('$state', state); |
||||
$provide.constant('$stateParams', stateParams); |
||||
})); |
||||
|
||||
beforeEach(inject(function($rootScope, $controller, $timeout, $httpBackend, WorkPackageService, $q) { |
||||
$httpBackend.when('GET', '/api/v3/work_packages/99').respond(workPackage); |
||||
|
||||
WorkPackageService.getWorkPackage = function() { return $q.when(workPackage) }; |
||||
|
||||
buildController = function(done) { |
||||
var testState = { |
||||
params: { workPackageId: 99 }, |
||||
current: { url: '/activity' } |
||||
}; |
||||
scope = $rootScope.$new(); |
||||
|
||||
ctrl = $controller("WorkPackageDetailsController", { |
||||
$scope: scope, |
||||
$state: testState, |
||||
I18n: I18n, |
||||
ConfigurationService: { |
||||
commentsSortedInDescendingOrder: function() { |
||||
return false; |
||||
} |
||||
}, |
||||
workPackage: workPackage |
||||
}); |
||||
|
||||
$timeout.flush(); |
||||
|
||||
promise = scope.initializedWorkPackage; |
||||
}; |
||||
|
||||
})); |
||||
|
||||
describe('initialisation', function() { |
||||
it('should initialise', function() { |
||||
return buildController(); |
||||
}); |
||||
}); |
||||
|
||||
describe('#scope.canViewWorkPackageWatchers', function() { |
||||
describe('when the work package does not contain the embedded watchers property', function() { |
||||
beforeEach(function() { |
||||
workPackage.watchers = null; |
||||
buildController(); |
||||
}); |
||||
|
||||
it('returns false', function() { |
||||
expect(promise).to.eventually.be.fulfilled.then(function() { |
||||
expect(scope.canViewWorkPackageWatchers()).to.be.false; |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
describe('when the work package contains the embedded watchers property', function() { |
||||
beforeEach(function() { |
||||
workPackage.watchers = []; |
||||
return buildController(); |
||||
}); |
||||
|
||||
it('returns true', function() { |
||||
expect(promise).to.eventually.be.fulfilled.then(function() { |
||||
expect(scope.canViewWorkPackageWatchers()).to.be.true; |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
describe('work package properties', function() { |
||||
describe('relations', function() { |
||||
beforeEach(function() { |
||||
return buildController(); |
||||
}); |
||||
|
||||
it('Relation::Relates', function() { |
||||
expect(promise).to.eventually.be.fulfilled.then(function() { |
||||
expect(scope.relatedTo).to.be.ok; |
||||
}); |
||||
}); |
||||
|
||||
it('is the embedded type', function() { |
||||
expect(promise).to.eventually.be.fulfilled.then(function() { |
||||
expect(scope.type.props.name).to.eql('Milestone'); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
||||
|
||||
describe('showStaticPagePath', function() { |
||||
it('points to old show page', function() { |
||||
expect(promise).to.eventually.be.fulfilled.then(function() { |
||||
expect(scope.showStaticPagePath).to.eql('/work_packages/99'); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
@ -0,0 +1,137 @@ |
||||
//-- 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.
|
||||
//++
|
||||
|
||||
import {WorkPackageResourceInterface} from '../../api/api-v3/hal-resources/work-package-resource.service'; |
||||
import {scopedObservable} from '../../../helpers/angular-rx-utils'; |
||||
import {WorkPackageCacheService} from '../../work-packages/work-package-cache.service'; |
||||
import {KeepTabService} from '../../wp-panels/keep-tab/keep-tab.service'; |
||||
import {wpControllersModule} from '../../../angular-modules'; |
||||
import {WorkPackageEditModeStateService} from '../../wp-edit/wp-edit-mode-state.service'; |
||||
|
||||
export class WorkPackageViewController { |
||||
|
||||
protected $q:ng.IQService; |
||||
protected $state:ng.ui.IStateService; |
||||
protected $rootScope:ng.IRootScopeService; |
||||
protected keepTab:KeepTabService; |
||||
protected wpCacheService:WorkPackageCacheService; |
||||
protected wpEditModeState:WorkPackageEditModeStateService; |
||||
protected WorkPackageService; |
||||
protected PathHelper:op.PathHelper; |
||||
protected I18n:op.I18n; |
||||
|
||||
// Helper promise to detect when the controller has been initialized
|
||||
// (when a WP has loaded).
|
||||
public initialized:ng.IDeferred<any>; |
||||
|
||||
// Static texts
|
||||
public text:any = {}; |
||||
|
||||
// Work package resource to be loaded from the cache
|
||||
public workPackage:WorkPackageResourceInterface; |
||||
public projectIdentifier:string; |
||||
|
||||
protected focusAnchorLabel:string; |
||||
public showStaticPagePath:string; |
||||
|
||||
constructor(public $injector, public $scope, protected workPackageId) { |
||||
this.$inject('$q', '$state', 'keepTab', 'wpCacheService', 'WorkPackageService', |
||||
'wpEditModeState', 'PathHelper', 'I18n'); |
||||
|
||||
this.initialized = this.$q.defer(); |
||||
this.initializeTexts(); |
||||
} |
||||
|
||||
/** |
||||
* Observe changes of work package and re-run initialization. |
||||
* Needs to be run explicitly by descendants. |
||||
*/ |
||||
protected observeWorkPackage() { |
||||
scopedObservable(this.$scope, this.wpCacheService.loadWorkPackage(this.workPackageId)) |
||||
.subscribe((wp:WorkPackageResourceInterface) => { |
||||
this.workPackage = wp; |
||||
this.init(); |
||||
this.initialized.resolve(); |
||||
}); |
||||
} |
||||
|
||||
protected $inject(...args:string[]) { |
||||
args.forEach(field => { |
||||
this[field] = this.$injector.get(field); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* Provide static translations |
||||
*/ |
||||
protected initializeTexts() { |
||||
this.text.tabs = {}; |
||||
['overview', 'activity', 'relations', 'watchers'].forEach(tab => { |
||||
this.text.tabs[tab] = this.I18n.t('js.work_packages.tabs.' + tab); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* Initialize controller after workPackage resource has been loaded. |
||||
*/ |
||||
protected init() { |
||||
// Ensure the schema is being loaded as soon as possible
|
||||
this.workPackage.schema.$load(); |
||||
|
||||
// Set elements
|
||||
this.projectIdentifier = this.workPackage.project.identifier; |
||||
|
||||
// Preselect this work package for future list operations
|
||||
this.showStaticPagePath = this.PathHelper.workPackagePath(this.workPackage); |
||||
this.WorkPackageService.cache().put('preselectedWorkPackageId', this.workPackage.id); |
||||
|
||||
// Listen to tab changes to update the tab label
|
||||
scopedObservable(this.$scope, this.keepTab.observable).subscribe((tabs:any) => { |
||||
this.updateFocusAnchorLabel(tabs.active); |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* Recompute the current tab focus label |
||||
*/ |
||||
public updateFocusAnchorLabel(tabName:string):string { |
||||
const tabLabel = this.I18n.t('js.label_work_package_details_you_are_here', { |
||||
tab: this.I18n.t('js.work_packages.tabs.' + tabName), |
||||
type: this.workPackage.type.name, |
||||
subject: this.workPackage.subject |
||||
}); |
||||
|
||||
return this.focusAnchorLabel = tabLabel; |
||||
} |
||||
|
||||
public canViewWorkPackageWatchers() { |
||||
return !!(this.workPackage && this.workPackage.watchers); |
||||
} |
||||
} |
||||
|
||||
wpControllersModule.controller('WorkPackageViewController', WorkPackageViewController); |
@ -1,11 +1,11 @@ |
||||
<wp-single-view></wp-single-view> |
||||
|
||||
<div class="attributes-group" ng-if="workPackage"> |
||||
<div class="attributes-group" ng-if="$ctrl.workPackage"> |
||||
<div class="attributes-group--header"> |
||||
<div class="attributes-group--header-container"> |
||||
<h3 class="attributes-group--header-text">{{ vm.I18n.t('js.label_latest_activity') }}</h3> |
||||
</div> |
||||
</div> |
||||
|
||||
<activity-panel template="overview" work-package="workPackage"></activity-panel> |
||||
<activity-panel template="overview" work-package="$ctrl.workPackage"></activity-panel> |
||||
</div> |
||||
|
Loading…
Reference in new issue