527 lines
27 KiB
HTML
527 lines
27 KiB
HTML
<!--
|
|
~ Copyright (c) 2015-2016 Codethink Limited
|
|
~
|
|
~ 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.
|
|
-->
|
|
<div class="container-fluid">
|
|
<div ng-include
|
|
src="'/inline/worklist_title.html'"
|
|
ng-hide="editing">
|
|
</div>
|
|
<hr ng-show="editing">
|
|
<div ng-include
|
|
src="'/inline/edit_worklist.html'"
|
|
ng-show="editing">
|
|
</div>
|
|
<hr ng-show="editing">
|
|
<div ng-show="(permissions.editWorklist || permissions.moveItems) && !worklist.automatic"
|
|
ng-include src="'/inline/worklist.html'"></div>
|
|
<div ng-show="!(permissions.editWorklist || permissions.moveItems) || worklist.automatic"
|
|
ng-include src="'/inline/worklist_static.html'"></div>
|
|
</div>
|
|
|
|
<script type="text/ng-template" id="/inline/worklist_title.html">
|
|
<div class="row">
|
|
<div class="col-sm-12" ng-show="!editing">
|
|
<div class="alert alert-warning" ng-show="worklist.archived">
|
|
<p>
|
|
<i class="fa fa-archive"></i>
|
|
<strong>This worklist is archived</strong>.
|
|
It can still be interacted with, but won't show up in search results.
|
|
</p>
|
|
<div class="text-center alert-button">
|
|
<button type="button"
|
|
class="btn btn-success"
|
|
ng-click="unarchive()"
|
|
ng-show="permissions.editWorklist">
|
|
Unarchive this Worklist
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="alert alert-danger" ng-show="worklist.private">
|
|
<i class="fa fa-eye-slash"></i>
|
|
<strong>This worklist is private</strong>.
|
|
<span ng-show="permissions.editWorklist">
|
|
Edit this worklist to change the privacy settings.
|
|
</span>
|
|
</div>
|
|
<h1 view-title>
|
|
{{worklist.title}}
|
|
<small ng-show="isLoggedIn">
|
|
<a ng-click="toggleEditMode()"
|
|
ng-show="permissions.editWorklist">
|
|
<i class="fa fa-pencil"></i>
|
|
</a>
|
|
<subscribe resource="worklist"
|
|
resource-id="worklist.id">
|
|
</subscribe>
|
|
</small>
|
|
</h1>
|
|
</div>
|
|
</div>
|
|
</script>
|
|
|
|
<script type="text/ng-template" id="/inline/edit_worklist.html">
|
|
<div class="row">
|
|
<div class="col-sm-12" ng-show="editing">
|
|
<form name="worklistForm" role="form" class="form-horizontal">
|
|
<div class="form-group">
|
|
<label for="title" class="col-sm-2 control-label">
|
|
Title
|
|
</label>
|
|
<div class="col-sm-10">
|
|
<input id="title"
|
|
focus
|
|
type="text"
|
|
class="form-control"
|
|
ng-model="worklist.title"
|
|
required
|
|
maxlength="100"
|
|
placeholder="Worklist title">
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="private" class="col-sm-2 control-label">
|
|
Private
|
|
</label>
|
|
<div class="col-sm-10 checkbox">
|
|
<input id="private"
|
|
type="checkbox"
|
|
class="modal-checkbox"
|
|
ng-model="worklist.private"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="automatic" class="col-sm-2 control-label">
|
|
Automatic
|
|
</label>
|
|
<div class="col-sm-10 checkbox">
|
|
<input id="automatic"
|
|
type="checkbox"
|
|
class="modal-checkbox"
|
|
ng-model="worklist.automatic"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="form-group" ng-show="worklist.automatic">
|
|
<div class="col-sm-12">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th colspan="4">
|
|
Criteria
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr ng-repeat="filter in worklist.filters">
|
|
<td colspan="3">
|
|
<span ng-show="worklist.filters.indexOf(filter) > 0">
|
|
or
|
|
</span>
|
|
{{filter.type == 'Story' ? 'Stories' : 'Tasks'}}
|
|
where
|
|
<span ng-repeat="criterion in filter.filter_criteria">
|
|
{{criterion.field | capitalize}}
|
|
{{criterion.negative ? 'is not' : 'is'}}
|
|
{{criterion.title}}
|
|
<span ng-hide="filter.filter_criteria.indexOf(criterion)
|
|
== filter.filter_criteria.length - 1">
|
|
and
|
|
</span>
|
|
</span>
|
|
</td>
|
|
<td class="text-right">
|
|
<a href class="close"
|
|
ng-click="removeFilter(filter)">×</a>
|
|
</td>
|
|
</tr>
|
|
<tr ng-show="showAddFilter">
|
|
<td class="center-vertical col-sm-2">
|
|
<span ng-show="worklist.filters.length > 0">
|
|
or
|
|
</span>
|
|
<span class="dropdown" dropdown>
|
|
<a class="btn btn-xs btn-default dropdown-toggle"
|
|
dropdown-toggle>
|
|
{{newFilter.type == 'Story' ? 'Stories' : 'Tasks'}}
|
|
<i class="fa fa-caret-down"></i>
|
|
</a>
|
|
<ul class="dropdown-menu">
|
|
<li ng-repeat="type in ['Story', 'Task']">
|
|
<a href ng-click="setType(type)">
|
|
{{type == 'Story' ? 'Stories' : 'Tasks'}}
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</span>
|
|
</td>
|
|
<td class="col-sm-7">
|
|
<span ng-repeat="criterion in newFilter.filter_criteria"
|
|
ng-controller="SearchCriteriaController"
|
|
ng-init="init([newFilter.type])">
|
|
<span class="center-vertical worklist-criterion"
|
|
style="display: inline-block">
|
|
<span class="dropdown" dropdown>
|
|
<a class="btn btn-xs btn-default dropdown-toggle"
|
|
dropdown-toggle>
|
|
{{criterion.negative ? 'not matching' : 'matching'}}
|
|
<i class="fa fa-caret-down"></i>
|
|
</a>
|
|
<ul class="dropdown-menu">
|
|
<li ng-repeat="not in [false, true]">
|
|
<a href
|
|
ng-click="criterion.negative = not">
|
|
{{not ? 'not matching' : 'matching'}}
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</span>
|
|
<div tag-complete="criteria as criteria.title for criteria in searchForCriteria($viewValue)"
|
|
tag-complete-tags="criteria"
|
|
tag-complete-label-field="title"
|
|
tag-complete-option-template-url="'app/search/template/typeahead_criteria_item.html'"
|
|
tag-complete-tag-template-url="'app/search/template/criteria_tag_item.html'"
|
|
tag-complete-loading="loadingCriteria = isLoading"
|
|
tag-complete-on-select="setCriterion(criterion, tag)"
|
|
tag-remove-callback="removeTag(criterion)"
|
|
max-tags="1"
|
|
placeholder="Click to select a filter.">
|
|
</div>
|
|
</span>
|
|
<span ng-hide="newFilter.filter_criteria.indexOf(criterion)
|
|
== newFilter.filter_criteria.length - 1">
|
|
and
|
|
</span>
|
|
</span>
|
|
</td>
|
|
<td class="center-vertical col-sm-1">
|
|
<a href ng-click="addCriterion(newFilter)">
|
|
<i class="fa fa-plus-circle"></i>
|
|
and...
|
|
</a>
|
|
</td>
|
|
<td class="text-right center-vertical col-sm-3">
|
|
<a href class="btn btn-primary"
|
|
ng-click="saveNewFilter()"
|
|
ng-disabled="!checkNewFilter()">Save</a>
|
|
<a href class="btn btn-default"
|
|
ng-click="showAddFilter = !showAddFilter">Cancel</a>
|
|
</td>
|
|
</tr>
|
|
<tr ng-show="!showAddFilter">
|
|
<td colspan="4" class="text-center">
|
|
<a href ng-click="showAddFilter = !showAddFilter">
|
|
<i class="fa fa-plus-circle"></i> or...
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-sm-6">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Owners</th>
|
|
<th class="text-right">
|
|
<small>
|
|
<a href
|
|
ng-click="showAddOwner = !showAddOwner">
|
|
<i class="fa fa-plus" ng-if="!showAddOwner"></i>
|
|
<i class="fa fa-minus" ng-if="showAddOwner"></i>
|
|
Add Owner
|
|
</a>
|
|
</small>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr ng-repeat="owner in owners">
|
|
<td colspan="2">
|
|
{{owner.full_name}}
|
|
<a class="close"
|
|
ng-show="owners.length > 1"
|
|
ng-click="removeUser(owner, owners, worklist.owners)">
|
|
×
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
<tr ng-show="showAddOwner">
|
|
<td colspan="2">
|
|
<input id="owner"
|
|
type="text"
|
|
placeholder="Click to add an owner"
|
|
ng-model="asyncOwner"
|
|
typeahead-wait-ms="200"
|
|
typeahead-editable="false"
|
|
typeahead="user as user.full_name for user in
|
|
searchUsers($viewValue, worklist.owners)"
|
|
typeahead-loading="loadingUsers"
|
|
typeahead-input-formatter="formatUserName($model)"
|
|
typeahead-on-select="addUser($model, owners, worklist.owners)"
|
|
class="form-control input-sm"
|
|
/>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="col-sm-6">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Users</th>
|
|
<th class="text-right">
|
|
<small>
|
|
<a href
|
|
ng-click="showAddUser = !showAddUser">
|
|
<i class="fa fa-plus" ng-if="!showAddUser"></i>
|
|
<i class="fa fa-minus" ng-if="showAddUser"></i>
|
|
Add User
|
|
</a>
|
|
</small>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr ng-repeat="user in users">
|
|
<td colspan="2">
|
|
{{user.full_name}}
|
|
<a class="close"
|
|
ng-click="removeUser(user, users, worklist.users)">
|
|
×
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
<tr ng-show="showAddUser">
|
|
<td colspan="2">
|
|
<input id="user"
|
|
type="text"
|
|
placeholder="Click to add a user"
|
|
ng-model="asyncUser"
|
|
typeahead-wait-ms="200"
|
|
typeahead-editable="false"
|
|
typeahead="user as user.full_name for user in
|
|
searchUsers($viewValue, worklist.users)"
|
|
typeahead-loading="loadingUsers"
|
|
typeahead-input-formatter="formatUserName($model)"
|
|
typeahead-on-select="addUser($model, users, worklist.users)"
|
|
class="form-control input-sm"
|
|
/>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="clearfix">
|
|
<div class="pull-right">
|
|
<div class="btn" ng-show="isUpdating">
|
|
<i class="fa fa-spinner fa-lg fa-spin"></i>
|
|
</div>
|
|
<button type="button"
|
|
class="btn btn-primary"
|
|
ng-click="update()"
|
|
ng-disabled="!worklistForm.$valid">
|
|
Save
|
|
</button>
|
|
<button type="button"
|
|
class="btn btn-default"
|
|
ng-click="toggleEditMode()">
|
|
Cancel
|
|
</button>
|
|
</div>
|
|
<button type="button"
|
|
class="btn btn-danger"
|
|
ng-click="remove()"
|
|
ng-show="permissions.editWorklist">
|
|
Archive worklist
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</script>
|
|
|
|
<script type="text/ng-template" id="/inline/worklist.html">
|
|
<div class="row">
|
|
<div class="col-sm-offset-3 col-sm-6">
|
|
<div class="worklist">
|
|
<div class="kanban-lane-contents"
|
|
as-sortable="sortableOptions"
|
|
ng-model="worklist.items">
|
|
<div class="kanban-card"
|
|
ng-class="{'kanban-card-due': isDue(item),
|
|
'kanban-card-late': isLate(item)}"
|
|
as-sortable-item
|
|
ng-repeat="item in worklist.items"
|
|
ng-switch="item.item_type">
|
|
<div as-sortable-item-handle ng-switch-when="story">
|
|
<div class="row">
|
|
<div class="col-xs-1">
|
|
<i class="fa fa-sb-story text-muted"></i>
|
|
</div>
|
|
<div class="col-xs-10">
|
|
<a href="#!/story/{{item.story.id}}">
|
|
{{item.story.title}}
|
|
</a>
|
|
</div>
|
|
<div class="col-xs-1">
|
|
<button type="button" class="close" title="Remove"
|
|
ng-click="removeListItem(item); $event.stopPropagation();">
|
|
×
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="row target-date" ng-show="item.resolved_due_date">
|
|
<div class="col-xs-1">
|
|
<i class="fa fa-clock-o text-muted"></i>
|
|
</div>
|
|
<div class="col-xs-11">
|
|
<span time-moment
|
|
eventdate="item.resolved_due_date.date"
|
|
format-string="'MMM Do, YYYY'">
|
|
</span>
|
|
<br/>
|
|
<span class="text-muted">{{item.resolved_due_date.name}}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div as-sortable-item-handle ng-switch-when="task">
|
|
<div class="row">
|
|
<div class="col-xs-1">
|
|
<i class="fa fa-tasks text-muted"></i>
|
|
</div>
|
|
<div class="col-xs-10">
|
|
<a href="#!/story/{{item.task.story_id}}">
|
|
{{item.task.title}}
|
|
</a>
|
|
</div>
|
|
<div class="col-xs-1">
|
|
<button type="button" class="close" title="Remove"
|
|
ng-click="removeListItem(item); $event.stopPropagation()">
|
|
×
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="row target-date" ng-show="item.resolved_due_date">
|
|
<div class="col-xs-1">
|
|
<i class="fa fa-clock-o text-muted"></i>
|
|
</div>
|
|
<div class="col-xs-10">
|
|
<span time-moment
|
|
eventdate="item.resolved_due_date.date"
|
|
format-string="'MMM Do, YYYY'">
|
|
</span>
|
|
<br/>
|
|
<span class="text-muted">{{item.resolved_due_date.name}}</span>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-xs-12">
|
|
<user-typeahead ng-show="item.task.assignee_id"
|
|
ng-model="item.task.assignee_id"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="text-center text-muted">
|
|
<button ng-click="addItem()"
|
|
class="btn btn-kanban-lane">
|
|
Add a card...
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</script>
|
|
|
|
<script type="text/ng-template" id="/inline/worklist_static.html">
|
|
<div class="row">
|
|
<div class="col-sm-offset-3 col-sm-6">
|
|
<div class="worklist">
|
|
<div class="kanban-lane-contents">
|
|
<div class="kanban-card"
|
|
ng-class="{'kanban-card-due': isDue(item),
|
|
'kanban-card-late': isLate(item)}"
|
|
ng-repeat="item in worklist.items"
|
|
ng-switch="item.item_type">
|
|
<div ng-switch-when="story">
|
|
<div class="row">
|
|
<div class="col-xs-1">
|
|
<i class="fa fa-sb-story text-muted"></i>
|
|
</div>
|
|
<div class="col-xs-11">
|
|
<a href="#!/story/{{item.story.id}}">
|
|
{{item.story.title}}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="row target-date" ng-show="item.resolved_due_date">
|
|
<div class="col-xs-1">
|
|
<i class="fa fa-clock-o text-muted"></i>
|
|
</div>
|
|
<div class="col-xs-11">
|
|
<span time-moment
|
|
eventdate="item.resolved_due_date.date"
|
|
format-string="'MMM Do, YYYY'">
|
|
</span>
|
|
<br/>
|
|
<span class="text-muted">{{item.resolved_due_date.name}}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div ng-switch-when="task">
|
|
<div class="row">
|
|
<div class="col-xs-1">
|
|
<i class="fa fa-tasks text-muted"></i>
|
|
</div>
|
|
<div class="col-xs-11">
|
|
<a href="#!/story/{{item.task.story_id}}">
|
|
{{item.task.title}}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="row target-date" ng-show="item.resolved_due_date">
|
|
<div class="col-xs-1">
|
|
<i class="fa fa-clock-o text-muted"></i>
|
|
</div>
|
|
<div class="col-xs-10">
|
|
<span time-moment
|
|
eventdate="item.resolved_due_date.date"
|
|
format-string="'MMM Do, YYYY'">
|
|
</span>
|
|
<br/>
|
|
<span class="text-muted">{{item.resolved_due_date.name}}</span>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-xs-12">
|
|
<user-typeahead ng-show="item.task.assignee_id"
|
|
ng-model="item.task.assignee_id"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</script>
|