Merge "Complex priorities UI in stories"
This commit is contained in:
commit
661b1b961f
@ -30,7 +30,7 @@
|
||||
<i class="fa fa-caret-right"></i>
|
||||
</a>
|
||||
<br ng-if="!!minimalPager" />
|
||||
<span class="btn-group" dropdown>
|
||||
<span ng-if="!!onPageSize" class="btn-group" dropdown>
|
||||
<div>
|
||||
<button class="btn btn-xs btn-default"
|
||||
dropdown-toggle>
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||
* Copyright (c) 2016 Codethink Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License'); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
@ -23,7 +24,7 @@ angular.module('sb.story').controller('StoryDetailController',
|
||||
Story, Project, Branch, creator, tasks, Task, DSCacheFactory,
|
||||
User, $q, storyboardApiBase, SessionModalService, moment,
|
||||
$document, $anchorScroll, $timeout, $location, currentUser,
|
||||
enableEditableComments, Tags) {
|
||||
enableEditableComments, Tags, worklists) {
|
||||
'use strict';
|
||||
|
||||
var pageSize = Preference.get('story_detail_page_size');
|
||||
@ -85,8 +86,7 @@ angular.module('sb.story').controller('StoryDetailController',
|
||||
story_id: $scope.story.id,
|
||||
branch_id: branch.id,
|
||||
project_id: project.id,
|
||||
status: 'todo',
|
||||
priority: 'medium'
|
||||
status: 'todo'
|
||||
});
|
||||
$scope.projects[project.name]
|
||||
.branchNames.push(branch.name);
|
||||
@ -97,6 +97,61 @@ angular.module('sb.story').controller('StoryDetailController',
|
||||
|
||||
angular.forEach(tasks, mapTaskToProject);
|
||||
|
||||
/**
|
||||
* All worklists containing this story or tasks within it, with
|
||||
* information about which task is relevant added.
|
||||
*
|
||||
* @type {[Worklist]}
|
||||
*/
|
||||
function setWorklists() {
|
||||
function isNotArchived(card) {
|
||||
return !card.archived;
|
||||
}
|
||||
|
||||
var taskIds = $scope.tasks.map(function(task) {
|
||||
return task.id;
|
||||
});
|
||||
for (var i = 0; i < worklists.length; i++) {
|
||||
var worklist = worklists[i];
|
||||
worklist.relatedItems = [];
|
||||
worklist.items = worklist.items.filter(isNotArchived);
|
||||
for (var j = 0; j < worklist.items.length; j++) {
|
||||
var item = worklist.items[j];
|
||||
if (item.item_type === 'story') {
|
||||
if (item.item_id === story.id) {
|
||||
worklist.relatedItems.push(item);
|
||||
}
|
||||
} else if (item.item_type === 'task') {
|
||||
if (taskIds.indexOf(item.item_id) > -1) {
|
||||
worklist.relatedItems.push(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$scope.worklists = worklists.map(function(list) {
|
||||
if (list.relatedItems.length > 0) {
|
||||
return list;
|
||||
}
|
||||
}).filter(function(list) { return list; });
|
||||
}
|
||||
|
||||
setWorklists();
|
||||
|
||||
$scope.showWorklistsModal = function() {
|
||||
var modalInstance = $modal.open({
|
||||
templateUrl: 'app/stories/template/worklists.html',
|
||||
controller: 'StoryWorklistsController',
|
||||
resolve: {
|
||||
worklists: function () {
|
||||
return $scope.worklists;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Return the modal's promise.
|
||||
return modalInstance.result;
|
||||
};
|
||||
|
||||
// Load the preference for each display event.
|
||||
function reloadPagePreferences() {
|
||||
TimelineEventTypes.forEach(function (type) {
|
||||
@ -531,8 +586,7 @@ angular.module('sb.story').controller('StoryDetailController',
|
||||
*/
|
||||
$scope.newTask = new Task({
|
||||
story_id: $scope.story.id,
|
||||
status: 'todo',
|
||||
priority: 'medium'
|
||||
status: 'todo'
|
||||
});
|
||||
|
||||
/**
|
||||
|
33
src/app/stories/controller/story_worklists_controller.js
Normal file
33
src/app/stories/controller/story_worklists_controller.js
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Codethink Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License'); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Modal to display worklists related to stories
|
||||
*/
|
||||
angular.module('sb.story').controller('StoryWorklistsController',
|
||||
function($scope, $modalInstance, worklists) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Close this modal.
|
||||
*/
|
||||
$scope.close = function () {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
|
||||
$scope.worklists = worklists;
|
||||
}
|
||||
);
|
@ -75,6 +75,19 @@ angular.module('sb.story', ['ui.router', 'sb.services', 'sb.util',
|
||||
return {};
|
||||
});
|
||||
return user;
|
||||
},
|
||||
worklists: function(Worklist, $stateParams, CurrentUser) {
|
||||
var userPromise = CurrentUser.resolve();
|
||||
|
||||
return userPromise.then(function(user) {
|
||||
return Worklist.browse({
|
||||
story_id: $stateParams.storyId,
|
||||
subscriber_id: user.id,
|
||||
hide_lanes: ''
|
||||
}).$promise;
|
||||
}, function() {
|
||||
return [];
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -23,6 +23,14 @@
|
||||
<strong>This story is private</strong>.
|
||||
Edit this story to change the privacy settings.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="hidden-xs hidden-sm col-sm-3 pull-right"
|
||||
ng-show="worklists.length > 0 && !showEditForm">
|
||||
<div ng-include src="'/inline/worklists.html'"></div>
|
||||
</div>
|
||||
<div ng-include
|
||||
src="'/inline/story_detail.html'"
|
||||
ng-hide="showEditForm">
|
||||
@ -31,6 +39,15 @@
|
||||
src="'/inline/story_detail_form.html'"
|
||||
ng-show="showEditForm">
|
||||
</div>
|
||||
<hr class="visible-sm" />
|
||||
<div class="col-xs-12 visible-sm"
|
||||
ng-show="worklists.length > 0 && !showEditForm">
|
||||
<div ng-include src="'/inline/worklists.html'"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<hr/>
|
||||
<div ng-include src="'/inline/task_list.html'"></div>
|
||||
<hr/>
|
||||
@ -257,6 +274,58 @@
|
||||
</form>
|
||||
</script>
|
||||
|
||||
|
||||
<!-- Template for the list of relevant worklists -->
|
||||
<script type="text/ng-template" id="/inline/worklists.html">
|
||||
<table class="table table-striped table-condensed">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>In worklists you subscribed to</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="worklist in worklists.slice(0, 5)">
|
||||
<td>
|
||||
<a href="/#!/worklist/{{worklist.id}}">{{worklist.title}}</a>
|
||||
<span class="text-muted pull-right" ng-show="worklist.automatic">
|
||||
(automatic)
|
||||
</span>
|
||||
<div ng-click="showItems = !showItems">
|
||||
<a href>
|
||||
<i class="fa"
|
||||
ng-class="{'fa-caret-right': !showItems,
|
||||
'fa-caret-down': showItems}"></i>
|
||||
<small>
|
||||
{{showItems ? 'Hide' : 'Show'}} items...
|
||||
</small>
|
||||
</a>
|
||||
</div>
|
||||
<table class="table table-striped table-condensed subtable" ng-show="showItems">
|
||||
<tr ng-repeat="item in worklist.relatedItems | orderBy: 'list_position'">
|
||||
<td>
|
||||
{{item.item_type | capitalize}} {{item.item_id}}
|
||||
<span class="pull-right">
|
||||
{{item.list_position + 1}} of {{worklist.items.length}}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-if="worklists.length > 5">
|
||||
<td class="text-center">
|
||||
<a href ng-click="showWorklistsModal()">More...</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody ng-if="worklists.length < 1">
|
||||
<tr>
|
||||
<td colspan="2">No worklists related to this story</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<!-- Template for the tags list and controls -->
|
||||
<script type="text/ng-template" id="/inline/tags.html">
|
||||
<strong>Tags</strong>
|
||||
@ -383,7 +452,7 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<div class="col-xs-3">
|
||||
<user-typeahead
|
||||
ng-model="task.assignee_id"
|
||||
enabled="isLoggedIn"
|
||||
@ -400,13 +469,6 @@
|
||||
status="{{ task.status }}"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<task-priority-dropdown
|
||||
editable="{{isLoggedIn}}"
|
||||
on-change="updateTask(task, 'priority', priority)"
|
||||
priority="{{newTask.priority}}"
|
||||
/>
|
||||
</div>
|
||||
<!-- Review link should go here once implemented in the API -->
|
||||
</div>
|
||||
<div class="row button-row" ng-show="showDetail">
|
||||
@ -523,7 +585,7 @@
|
||||
placeholder="Enter task name"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<div class="col-xs-3">
|
||||
<user-typeahead
|
||||
auto-focus="false"
|
||||
ng-model="projects[name].branches[branchName].newTask.assignee_id"
|
||||
@ -542,15 +604,8 @@
|
||||
status="{{projects[name].branches[branchName].newTask.status}}"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<task-priority-dropdown
|
||||
editable="{{isLoggedIn}}"
|
||||
on-change="updateTask(projects[name].branches[branchName].newTask, 'priority', priority)"
|
||||
priority="{{projects[name].branches[branchName].newTask.priority}}"
|
||||
/>
|
||||
</div>
|
||||
<!-- Review link should go here once implemented in the API -->
|
||||
<div class="col-xs-2 text-right">
|
||||
<div class="col-xs-2 text-right col-xs-offset-1">
|
||||
<button ng-click="createTask(projects[name].branches[branchName].newTask,
|
||||
projects[name].branches[branchName])"
|
||||
class="btn btn-primary">
|
||||
@ -619,7 +674,7 @@
|
||||
placeholder="Enter task name"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<div class="col-xs-3">
|
||||
<user-typeahead
|
||||
auto-focus="false"
|
||||
ng-model="newTask.assignee_id"
|
||||
@ -639,14 +694,7 @@
|
||||
/>
|
||||
</div>
|
||||
<!-- Review link should go here once implemented in the API -->
|
||||
<div class="col-xs-2">
|
||||
<task-priority-dropdown
|
||||
editable="{{isLoggedIn}}"
|
||||
on-change="updateTask(newTask, 'priority', priority)"
|
||||
priority="{{newTask.priority}}"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-xs-2 text-right">
|
||||
<div class="col-xs-2 text-right col-xs-offset-1">
|
||||
<button ng-click="createTask(newTask)"
|
||||
class="btn btn-primary">
|
||||
Save
|
||||
|
41
src/app/stories/template/worklists.html
Normal file
41
src/app/stories/template/worklists.html
Normal file
@ -0,0 +1,41 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<button type="button" class="close" aria-hidden="true"
|
||||
ng-click="close()">×</button>
|
||||
<h3 class="panel-title">In worklists you're subscribed to</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-striped">
|
||||
<tbody>
|
||||
<tr ng-repeat="worklist in worklists">
|
||||
<td>
|
||||
<a href="/#!/worklist/{{worklist.id}}">{{worklist.title}}</a>
|
||||
<span class="text-muted pull-right" ng-show="worklist.automatic">
|
||||
(automatic)
|
||||
</span>
|
||||
<div ng-click="showItems = !showItems">
|
||||
<a href>
|
||||
<i class="fa"
|
||||
ng-class="{'fa-caret-right': !showItems,
|
||||
'fa-caret-down': showItems}"></i>
|
||||
<small>
|
||||
{{showItems ? 'Hide' : 'Show'}} items...
|
||||
</small>
|
||||
</a>
|
||||
</div>
|
||||
<table class="table table-striped table-condensed subtable" ng-show="showItems">
|
||||
<tr ng-repeat="item in worklist.relatedItems | orderBy: 'list_position'">
|
||||
<td>
|
||||
{{item.item_type | capitalize}} {{item.item_id}}
|
||||
<span class="pull-right">
|
||||
{{item.list_position + 1}} of {{worklist.items.length}}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
@ -76,3 +76,7 @@ tr.selected-row {
|
||||
background-color: @brand-primary !important;
|
||||
color: @navbar-default-color;
|
||||
}
|
||||
|
||||
.subtable {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
25
src/theme/base/stories.less
Normal file
25
src/theme/base/stories.less
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Codethink Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Story view styles
|
||||
*/
|
||||
|
||||
/* "Related Worklists" table style */
|
||||
.position-label {
|
||||
margin-left: 5px;
|
||||
}
|
@ -50,3 +50,4 @@
|
||||
@import './base/edit_tasks.less';
|
||||
@import './base/boards_worklists.less';
|
||||
@import './base/calendar.less';
|
||||
@import './base/stories.less';
|
||||
|
Loading…
Reference in New Issue
Block a user