parent
c2439d20ce
commit
3d9b7266b3
@ -0,0 +1,166 @@ |
|||||||
|
<div class="toolbar-container"> |
||||||
|
<div toolbar id="toolbar"> |
||||||
|
<h2 title="{{workPackage.props.subject}}"><a href="" ng-bind="type.props.name" /> {{workPackage.props.subject}}</h2> |
||||||
|
|
||||||
|
<ul id="toolbar-items"> |
||||||
|
<li class="toolbar-item"> |
||||||
|
<button class="button -alt-highlight" |
||||||
|
has-dropdown-menu |
||||||
|
target="TasksDropdownMenu" |
||||||
|
locals="availableTypes,projectIdentifier" |
||||||
|
ng-disabled="cannot('work_package', 'create')"> |
||||||
|
<i class="button--icon icon-add"></i> |
||||||
|
<span class="button--text" ng-bind="::I18n.t('js.toolbar.unselected_title')"></span> |
||||||
|
<i class="button--dropdown-indicator"></i> |
||||||
|
</button> |
||||||
|
</li> |
||||||
|
<li class="toolbar-item" feature-flag="detailsView"> |
||||||
|
<ul id="work-packages-view-mode-selection" class="toolbar-button-group"> |
||||||
|
<li> |
||||||
|
<label for="work-packages-list-view-button" class="hidden-for-sighted"> |
||||||
|
{{ getActivationActionLabel(isDetailsViewActive()) + ' ' + I18n.t('js.button_list_view') }} |
||||||
|
</label> |
||||||
|
<button id="work-packages-list-view-button" |
||||||
|
accesskey="{{ !isDetailsViewActive() ? '' : '8' }}" |
||||||
|
class="button" |
||||||
|
title="{{ getActivationActionLabel(isDetailsViewActive()) + ' ' + I18n.t('js.button_list_view') }}" |
||||||
|
ng-click="closeDetailsView()" |
||||||
|
ng-class="{ '-active': !isDetailsViewActive() }"> |
||||||
|
<i class="icon-table-view button--icon"></i> |
||||||
|
</button> |
||||||
|
</li> |
||||||
|
<li feature-flag="detailsView"> |
||||||
|
<label for="work-packages-details-view-button" class="hidden-for-sighted"> |
||||||
|
{{ getActivationActionLabel(!isDetailsViewActive()) + ' ' + I18n.t('js.button_details_view') }} |
||||||
|
</label> |
||||||
|
<button class="hide" |
||||||
|
ng-click="openOverviewTab()" |
||||||
|
accesskey="{{ isDetailsViewActive() ? '' : '8' }}"></button> |
||||||
|
<button id="work-packages-details-view-button" |
||||||
|
class="button" |
||||||
|
title="{{ getActivationActionLabel(!isDetailsViewActive()) + ' ' + I18n.t('js.button_details_view') }}" |
||||||
|
ng-class="{ '-active': isDetailsViewActive() }" |
||||||
|
ng-click="openLatestTab()"> |
||||||
|
<i class="icon-table-detail-view button--icon"></i> |
||||||
|
</button> |
||||||
|
</li> |
||||||
|
<li> |
||||||
|
<label for="work-packages-show-view-button" class="hidden-for-sighted"> |
||||||
|
{{ getActivationActionLabel(!isShowViewActive()) + ' ' + I18n.t('js.button_show_view') }} |
||||||
|
</label> |
||||||
|
<button id="work-packages-list-view-button" |
||||||
|
accesskey="{{ isShowViewActive() ? '' : '9' }}" |
||||||
|
class="button" |
||||||
|
title="{{ getActivationActionLabel(!isShowViewActive()) + ' ' + I18n.t('js.button_show_view') }}" |
||||||
|
ng-click="showWorkPackageShowView()" |
||||||
|
ng-class="{ '-active': isShowViewActive() }"> |
||||||
|
<i class="icon-table-view button--icon"></i> |
||||||
|
</button> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
</li> |
||||||
|
<li class="toolbar-item"> |
||||||
|
<label for="work-packages-settings-button" class="hidden-for-sighted"> |
||||||
|
{{ I18n.t('js.button_settings') }} |
||||||
|
</label> |
||||||
|
<button id="work-packages-settings-button" |
||||||
|
title="{{ I18n.t('js.button_settings') }}" |
||||||
|
class="button last work-packages-settings-button" |
||||||
|
has-dropdown-menu |
||||||
|
target="SettingsDropdownMenu" |
||||||
|
locals="query"> |
||||||
|
<i class="button--icon icon-settings"></i> |
||||||
|
<i class="button--dropdown-indicator"></i> |
||||||
|
</button> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="work-packages--filters-optional-container" ng-show="showFiltersOptions"> |
||||||
|
<div query-form id="query_form_content" class="hide-when-print"> |
||||||
|
<query-filters></query-filters> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<back-url></back-url> |
||||||
|
|
||||||
|
|
||||||
|
<div class="work-packages--split-view"> |
||||||
|
<div class="work-packages--left"> |
||||||
|
<div class="attributes-group"> |
||||||
|
|
||||||
|
<div class="attributes-group--header"> |
||||||
|
<div class="attributes-group--header-container"> |
||||||
|
<h3 class="attributes-group--header-text"> |
||||||
|
{{ I18n.t('js.label_description') }} |
||||||
|
</h3> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="single-attribute wiki"> |
||||||
|
<work-package-field field="'description'"></work-package-field> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div ng-repeat="group in vm.groupedFields" ng-hide="vm.hideEmptyFields && vm.isGroupHideable(vm.groupedFields, group.groupName, vm.workPackage)" class="attributes-group"> |
||||||
|
|
||||||
|
<div class="attributes-group--header"> |
||||||
|
<div class="attributes-group--header-container"> |
||||||
|
<h3 class="attributes-group--header-text" |
||||||
|
ng-bind="I18n.t('js.work_packages.property_groups.' + group.groupName)"></h3> |
||||||
|
</div> |
||||||
|
<div class="attributes-group--header-toggle"> |
||||||
|
<panel-expander tabindex="-1" ng-if="vm.showToggleButton() && $first" |
||||||
|
collapsed="vm.hideEmptyFields" |
||||||
|
expand-text="{{ I18n.t('js.label_show_attributes') }}" |
||||||
|
collapse-text="{{ I18n.t('js.label_hide_attributes') }}"> |
||||||
|
</panel-expander> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<dl class="attributes-key-value"> |
||||||
|
<dt |
||||||
|
ng-hide="vm.hideEmptyFields && vm.isFieldHideable(vm.workPackage, field)" |
||||||
|
ng-if="vm.isSpecified(vm.workPackage, field)" |
||||||
|
ng-repeat-start="field in group.attributes" class="attributes-key-value--key"> |
||||||
|
{{vm.getLabel(vm.workPackage, field)}} |
||||||
|
<span class="required" ng-if="vm.hasNiceStar(vm.workPackage, field)"> *</span> |
||||||
|
</dt> |
||||||
|
<dd |
||||||
|
ng-hide="vm.hideEmptyFields && vm.isFieldHideable(vm.workPackage, field)" |
||||||
|
ng-if="vm.isSpecified(vm.workPackage, field)" |
||||||
|
ng-repeat-end |
||||||
|
class="attributes-key-value--value-container"> |
||||||
|
<work-package-field field="field"></work-package-field> |
||||||
|
</dd> |
||||||
|
</dl> |
||||||
|
</div> |
||||||
|
|
||||||
|
<work-package-attachments edit work-package="vm.workPackage"></work-package-attachments> |
||||||
|
|
||||||
|
</div> |
||||||
|
<div class="work-packages--right"> |
||||||
|
<div id="tabs"> |
||||||
|
<ul class="tabrow"> |
||||||
|
<!-- The hrefs with empty URLs are necessary for IE10 to focus these links |
||||||
|
properly. Thus, don't remove the hrefs or the empty URLs! --> |
||||||
|
<li ui-sref="work-packages.show.activity({})" |
||||||
|
ui-sref-active="selected"> |
||||||
|
<a href="" ng-bind="I18n.t('js.work_packages.tabs.activity')"/> |
||||||
|
</li> |
||||||
|
<li ui-sref="work-packages.show.relations({})" |
||||||
|
ui-sref-active="selected"> |
||||||
|
<a href="" ng-bind="I18n.t('js.work_packages.tabs.relations')"/> |
||||||
|
</li> |
||||||
|
<li ng-if="canViewWorkPackageWatchers()" |
||||||
|
ui-sref="work-packages.show.watchers({})" |
||||||
|
ui-sref-active="selected"> |
||||||
|
<a href="" ng-bind="I18n.t('js.work_packages.tabs.watchers')"/> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
<div class="tabcontent" ui-view> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
@ -0,0 +1,206 @@ |
|||||||
|
//-- 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($scope, |
||||||
|
$state, |
||||||
|
latestTab, |
||||||
|
workPackage, |
||||||
|
I18n, |
||||||
|
RELATION_TYPES, |
||||||
|
RELATION_IDENTIFIERS, |
||||||
|
$q, |
||||||
|
WorkPackagesHelper, |
||||||
|
PathHelper, |
||||||
|
UsersHelper, |
||||||
|
ConfigurationService, |
||||||
|
WorkPackageService, |
||||||
|
CommonRelationsHandler, |
||||||
|
ChildrenRelationsHandler, |
||||||
|
ParentRelationsHandler |
||||||
|
) { |
||||||
|
$scope.$on('$stateChangeSuccess', function(event, toState){ |
||||||
|
latestTab.registerState(toState.name); |
||||||
|
}); |
||||||
|
|
||||||
|
$scope.$on('workPackageRefreshRequired', function(e, callback) { |
||||||
|
refreshWorkPackage(callback); |
||||||
|
}); |
||||||
|
|
||||||
|
// initialization
|
||||||
|
setWorkPackageScopeProperties(workPackage); |
||||||
|
|
||||||
|
$scope.I18n = I18n; |
||||||
|
$scope.$parent.preselectedWorkPackageId = $scope.workPackage.props.id; |
||||||
|
$scope.maxDescriptionLength = 800; |
||||||
|
|
||||||
|
function refreshWorkPackage(callback) { |
||||||
|
WorkPackageService.getWorkPackage($scope.workPackage.props.id) |
||||||
|
.then(function(workPackage) { |
||||||
|
setWorkPackageScopeProperties(workPackage); |
||||||
|
$scope.$broadcast('workPackageRefreshed'); |
||||||
|
if (callback) { |
||||||
|
callback(workPackage); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
$scope.refreshWorkPackage = refreshWorkPackage; // expose to child controllers
|
||||||
|
|
||||||
|
// Inform parent that work package is loaded so back url can be maintained
|
||||||
|
$scope.$emit('workPackgeLoaded'); |
||||||
|
|
||||||
|
function outputMessage(message, isError) { |
||||||
|
$scope.$emit('flashMessage', { |
||||||
|
isError: !!isError, |
||||||
|
text: message |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
function outputError(error) { |
||||||
|
outputMessage(error.message, true); |
||||||
|
} |
||||||
|
|
||||||
|
$scope.outputMessage = outputMessage; // expose to child controllers
|
||||||
|
$scope.outputError = outputError; // expose to child controllers
|
||||||
|
|
||||||
|
function setWorkPackageScopeProperties(workPackage){ |
||||||
|
$scope.workPackage = workPackage; |
||||||
|
$scope.isWatched = !!workPackage.links.unwatch; |
||||||
|
|
||||||
|
if (workPackage.links.watch === undefined) { |
||||||
|
$scope.toggleWatchLink = workPackage.links.unwatch; |
||||||
|
} else { |
||||||
|
$scope.toggleWatchLink = workPackage.links.watch; |
||||||
|
} |
||||||
|
|
||||||
|
// autocomplete path
|
||||||
|
var projectId = workPackage.embedded.project.props.id; |
||||||
|
$scope.autocompletePath = PathHelper.staticWorkPackagesAutocompletePath(projectId); |
||||||
|
|
||||||
|
// activities and latest activities
|
||||||
|
$scope.activitiesSortedInDescendingOrder = ConfigurationService.commentsSortedInDescendingOrder(); |
||||||
|
$scope.activities = displayedActivities($scope.workPackage); |
||||||
|
|
||||||
|
// watchers
|
||||||
|
if(workPackage.links.watchers) { |
||||||
|
$scope.watchers = workPackage.embedded.watchers.embedded.elements; |
||||||
|
} |
||||||
|
|
||||||
|
$scope.showStaticPagePath = PathHelper.staticWorkPackagePath($scope.workPackage.props.id); |
||||||
|
|
||||||
|
// Type
|
||||||
|
$scope.type = workPackage.embedded.type; |
||||||
|
|
||||||
|
// Author
|
||||||
|
$scope.author = workPackage.embedded.author; |
||||||
|
$scope.authorPath = PathHelper.staticUserPath($scope.author.props.id); |
||||||
|
$scope.authorActive = UsersHelper.isActive($scope.author); |
||||||
|
|
||||||
|
// Attachments
|
||||||
|
$scope.attachments = workPackage.embedded.attachments.embedded.elements; |
||||||
|
|
||||||
|
// relations
|
||||||
|
$q.all(WorkPackagesHelper.getParent(workPackage)).then(function(parents) { |
||||||
|
var relationsHandler = new ParentRelationsHandler(workPackage, parents, 'parent'); |
||||||
|
$scope.wpParent = relationsHandler; |
||||||
|
}); |
||||||
|
|
||||||
|
$q.all(WorkPackagesHelper.getChildren(workPackage)).then(function(children) { |
||||||
|
var relationsHandler = new ChildrenRelationsHandler(workPackage, children); |
||||||
|
$scope.wpChildren = relationsHandler; |
||||||
|
}); |
||||||
|
|
||||||
|
function relationTypeIterator(key) { |
||||||
|
$q.all(WorkPackagesHelper.getRelationsOfType( |
||||||
|
workPackage, |
||||||
|
RELATION_TYPES[key]) |
||||||
|
).then(function(relations) { |
||||||
|
var relationsHandler = new CommonRelationsHandler(workPackage, |
||||||
|
relations, |
||||||
|
RELATION_IDENTIFIERS[key]); |
||||||
|
$scope[key] = relationsHandler; |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
for (var key in RELATION_TYPES) { |
||||||
|
if (RELATION_TYPES.hasOwnProperty(key)) { |
||||||
|
relationTypeIterator(key); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
$scope.toggleWatch = function() { |
||||||
|
var fetchOptions = { |
||||||
|
method: $scope.toggleWatchLink.props.method |
||||||
|
}; |
||||||
|
|
||||||
|
if($scope.toggleWatchLink.props.payload !== undefined) { |
||||||
|
fetchOptions.contentType = 'application/json; charset=utf-8'; |
||||||
|
fetchOptions.data = JSON.stringify($scope.toggleWatchLink.props.payload); |
||||||
|
} |
||||||
|
|
||||||
|
$scope.toggleWatchLink |
||||||
|
.fetch({ajax: fetchOptions}) |
||||||
|
.then(refreshWorkPackage, outputError); |
||||||
|
}; |
||||||
|
|
||||||
|
$scope.canViewWorkPackageWatchers = function() { |
||||||
|
return !!($scope.workPackage && $scope.workPackage.embedded.watchers !== undefined); |
||||||
|
}; |
||||||
|
|
||||||
|
function displayedActivities(workPackage) { |
||||||
|
var activities = workPackage.embedded.activities; |
||||||
|
|
||||||
|
if ($scope.activitiesSortedInDescendingOrder) { |
||||||
|
activities.reverse(); |
||||||
|
} |
||||||
|
return activities; |
||||||
|
} |
||||||
|
|
||||||
|
// toggles
|
||||||
|
|
||||||
|
$scope.toggleStates = { |
||||||
|
hideFullDescription: true, |
||||||
|
hideAllAttributes: true |
||||||
|
}; |
||||||
|
|
||||||
|
function getFocusAnchorLabel(tab, workPackage) { |
||||||
|
var tabLabel = I18n.t('js.work_packages.tabs.' + tab), |
||||||
|
params = { |
||||||
|
tab: tabLabel, |
||||||
|
type: workPackage.props.type, |
||||||
|
subject: workPackage.props.subject |
||||||
|
}; |
||||||
|
|
||||||
|
return I18n.t('js.label_work_package_details_you_are_here', params); |
||||||
|
} |
||||||
|
|
||||||
|
$scope.focusAnchorLabel = getFocusAnchorLabel( |
||||||
|
$state.current.url.replace(/\//, ''), |
||||||
|
$scope.workPackage |
||||||
|
); |
||||||
|
}; |
Loading…
Reference in new issue