Merge "Allow teams to be added to the permission list for private stories"
This commit is contained in:
commit
28b4809425
@ -123,6 +123,7 @@
|
|||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<input id="user"
|
<input id="user"
|
||||||
type="text"
|
type="text"
|
||||||
|
autocomplete="off"
|
||||||
placeholder="Click to add a user"
|
placeholder="Click to add a user"
|
||||||
ng-model="asyncUser"
|
ng-model="asyncUser"
|
||||||
typeahead-wait-ms="200"
|
typeahead-wait-ms="200"
|
||||||
|
@ -106,6 +106,7 @@
|
|||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<input id="user"
|
<input id="user"
|
||||||
type="text"
|
type="text"
|
||||||
|
autocomplete="off"
|
||||||
placeholder="Click to add a user"
|
placeholder="Click to add a user"
|
||||||
ng-model="asyncUser"
|
ng-model="asyncUser"
|
||||||
typeahead-wait-ms="200"
|
typeahead-wait-ms="200"
|
||||||
|
@ -24,7 +24,7 @@ angular.module('sb.story').controller('StoryDetailController',
|
|||||||
Story, Project, Branch, creator, tasks, Task, DSCacheFactory,
|
Story, Project, Branch, creator, tasks, Task, DSCacheFactory,
|
||||||
User, $q, storyboardApiBase, SessionModalService, moment,
|
User, $q, storyboardApiBase, SessionModalService, moment,
|
||||||
$document, $anchorScroll, $timeout, $location, currentUser,
|
$document, $anchorScroll, $timeout, $location, currentUser,
|
||||||
enableEditableComments, Tags, worklists) {
|
enableEditableComments, Tags, worklists, Team) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var pageSize = Preference.get('story_detail_page_size');
|
var pageSize = Preference.get('story_detail_page_size');
|
||||||
@ -532,51 +532,82 @@ angular.module('sb.story').controller('StoryDetailController',
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User typeahead search method.
|
* User/team typeahead search method.
|
||||||
*/
|
*/
|
||||||
$scope.searchUsers = function (value, array) {
|
$scope.searchActors = function (value, users, teams) {
|
||||||
var userIds = array.map(function(user){return user.id;});
|
var userIds = users.map(function(user){return user.id;});
|
||||||
|
var teamIds = teams.map(function(team){return team.id;});
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
|
var usersDeferred = $q.defer();
|
||||||
|
var teamsDeferred = $q.defer();
|
||||||
|
|
||||||
User.browse({full_name: value, limit: 10},
|
User.browse({full_name: value, limit: 10},
|
||||||
function(searchResults) {
|
function(searchResults) {
|
||||||
var results = [];
|
var results = [];
|
||||||
angular.forEach(searchResults, function(result) {
|
angular.forEach(searchResults, function(result) {
|
||||||
if (userIds.indexOf(result.id) === -1) {
|
if (userIds.indexOf(result.id) === -1) {
|
||||||
|
result.name = result.full_name;
|
||||||
|
result.type = 'user';
|
||||||
results.push(result);
|
results.push(result);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
deferred.resolve(results);
|
usersDeferred.resolve(results);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Team.browse({name: value, limit: 10},
|
||||||
|
function(searchResults) {
|
||||||
|
var results = [];
|
||||||
|
angular.forEach(searchResults, function(result) {
|
||||||
|
if (teamIds.indexOf(result.id) === -1) {
|
||||||
|
result.type = 'team';
|
||||||
|
results.push(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
teamsDeferred.resolve(results);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
var searches = [teamsDeferred.promise, usersDeferred.promise];
|
||||||
|
$q.all(searches).then(function(searchResults) {
|
||||||
|
var results = [];
|
||||||
|
angular.forEach(searchResults, function(promise) {
|
||||||
|
angular.forEach(promise, function(result) {
|
||||||
|
results.push(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
deferred.resolve(results);
|
||||||
|
});
|
||||||
|
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats the user name.
|
* Add a new user or team to one of the permission levels.
|
||||||
*/
|
*/
|
||||||
$scope.formatUserName = function (model) {
|
$scope.addActor = function (model) {
|
||||||
if (!!model) {
|
if (model.type === 'user') {
|
||||||
return model.name;
|
$scope.story.users.push(model);
|
||||||
|
} else if (model.type === 'team') {
|
||||||
|
$scope.story.teams.push(model);
|
||||||
}
|
}
|
||||||
return '';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new user to one of the permission levels.
|
* Remove a user from the permissions.
|
||||||
*/
|
|
||||||
$scope.addUser = function (model) {
|
|
||||||
$scope.story.users.push(model);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a user from one of the permission levels.
|
|
||||||
*/
|
*/
|
||||||
$scope.removeUser = function (model) {
|
$scope.removeUser = function (model) {
|
||||||
var idx = $scope.story.users.indexOf(model);
|
var idx = $scope.story.users.indexOf(model);
|
||||||
$scope.story.users.splice(idx, 1);
|
$scope.story.users.splice(idx, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a team from the permissions.
|
||||||
|
*/
|
||||||
|
$scope.removeTeam = function(model) {
|
||||||
|
var idx = $scope.story.teams.indexOf(model);
|
||||||
|
$scope.story.teams.splice(idx, 1);
|
||||||
|
};
|
||||||
|
|
||||||
// ###################################################################
|
// ###################################################################
|
||||||
// Task Management
|
// Task Management
|
||||||
// ###################################################################
|
// ###################################################################
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
angular.module('sb.story').controller('StoryModalController',
|
angular.module('sb.story').controller('StoryModalController',
|
||||||
function ($scope, $modalInstance, params, Project, Story, Task, User,
|
function ($scope, $modalInstance, params, Project, Story, Task, User,
|
||||||
$q, CurrentUser) {
|
Team, $q, CurrentUser) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var currentUser = CurrentUser.resolve();
|
var currentUser = CurrentUser.resolve();
|
||||||
@ -29,7 +29,8 @@ angular.module('sb.story').controller('StoryModalController',
|
|||||||
currentUser.then(function(user) {
|
currentUser.then(function(user) {
|
||||||
$scope.story = new Story({
|
$scope.story = new Story({
|
||||||
title: '',
|
title: '',
|
||||||
users: [user]
|
users: [user],
|
||||||
|
teams: []
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -164,49 +165,80 @@ angular.module('sb.story').controller('StoryModalController',
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User typeahead search method.
|
* User/team typeahead search method.
|
||||||
*/
|
*/
|
||||||
$scope.searchUsers = function (value, array) {
|
$scope.searchActors = function (value, users, teams) {
|
||||||
|
var userIds = users.map(function(user){return user.id;});
|
||||||
|
var teamIds = teams.map(function(team){return team.id;});
|
||||||
var deferred = $q.defer();
|
var deferred = $q.defer();
|
||||||
|
var usersDeferred = $q.defer();
|
||||||
|
var teamsDeferred = $q.defer();
|
||||||
|
|
||||||
User.browse({full_name: value, limit: 10},
|
User.browse({full_name: value, limit: 10},
|
||||||
function(searchResults) {
|
function(searchResults) {
|
||||||
var results = [];
|
var results = [];
|
||||||
angular.forEach(searchResults, function(result) {
|
angular.forEach(searchResults, function(result) {
|
||||||
if (array.indexOf(result.id) === -1) {
|
if (userIds.indexOf(result.id) === -1) {
|
||||||
|
result.name = result.full_name;
|
||||||
|
result.type = 'user';
|
||||||
results.push(result);
|
results.push(result);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
deferred.resolve(results);
|
usersDeferred.resolve(results);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Team.browse({name: value, limit: 10},
|
||||||
|
function(searchResults) {
|
||||||
|
var results = [];
|
||||||
|
angular.forEach(searchResults, function(result) {
|
||||||
|
if (teamIds.indexOf(result.id) === -1) {
|
||||||
|
result.type = 'team';
|
||||||
|
results.push(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
teamsDeferred.resolve(results);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
var searches = [teamsDeferred.promise, usersDeferred.promise];
|
||||||
|
$q.all(searches).then(function(searchResults) {
|
||||||
|
var results = [];
|
||||||
|
angular.forEach(searchResults, function(promise) {
|
||||||
|
angular.forEach(promise, function(result) {
|
||||||
|
results.push(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
deferred.resolve(results);
|
||||||
|
});
|
||||||
|
|
||||||
return deferred.promise;
|
return deferred.promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats the user name.
|
* Add a new user or team to one of the permission levels.
|
||||||
*/
|
*/
|
||||||
$scope.formatUserName = function (model) {
|
$scope.addActor = function (model) {
|
||||||
if (!!model) {
|
if (model.type === 'user') {
|
||||||
return model.name;
|
$scope.story.users.push(model);
|
||||||
|
} else if (model.type === 'team') {
|
||||||
|
$scope.story.teams.push(model);
|
||||||
}
|
}
|
||||||
return '';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new user to one of the permission levels.
|
* Remove a user from the permissions.
|
||||||
*/
|
|
||||||
$scope.addUser = function (model) {
|
|
||||||
$scope.story.users.push(model);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a user from one of the permission levels.
|
|
||||||
*/
|
*/
|
||||||
$scope.removeUser = function (model) {
|
$scope.removeUser = function (model) {
|
||||||
var idx = $scope.story.users.indexOf(model);
|
var idx = $scope.story.users.indexOf(model);
|
||||||
$scope.story.users.splice(idx, 1);
|
$scope.story.users.splice(idx, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a team from the permissions.
|
||||||
|
*/
|
||||||
|
$scope.removeTeam = function(model) {
|
||||||
|
var idx = $scope.story.teams.indexOf(model);
|
||||||
|
$scope.story.teams.splice(idx, 1);
|
||||||
|
};
|
||||||
})
|
})
|
||||||
;
|
;
|
||||||
|
@ -187,31 +187,43 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-6 col-sm-offset-3"
|
<div class="col-md-6 col-md-offset-3"
|
||||||
ng-show="story.private">
|
ng-show="story.private">
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Users that can see this story</th>
|
<th>Teams and Users that can see this story</th>
|
||||||
<th class="text-right">
|
<th class="text-right">
|
||||||
<small>
|
<small>
|
||||||
<a href
|
<a href
|
||||||
ng-click="showAddUser = !showAddUser">
|
ng-click="showAddUser = !showAddUser">
|
||||||
<i class="fa fa-plus" ng-if="!showAddUser"></i>
|
<i class="fa fa-plus" ng-if="!showAddUser"></i>
|
||||||
<i class="fa fa-minus" ng-if="showAddUser"></i>
|
<i class="fa fa-minus" ng-if="showAddUser"></i>
|
||||||
Add User
|
Add Team or User
|
||||||
</a>
|
</a>
|
||||||
</small>
|
</small>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
<tr ng-repeat="team in story.teams">
|
||||||
|
<td colspan="2">
|
||||||
|
<i class="fa fa-sb-team"></i>
|
||||||
|
{{ team.name }}
|
||||||
|
<a class="close"
|
||||||
|
ng-click="removeTeam(team)"
|
||||||
|
ng-show="story.teams.length > 1 || story.users.length > 0">
|
||||||
|
×
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr ng-repeat="user in story.users">
|
<tr ng-repeat="user in story.users">
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
|
<i class="fa fa-sb-user"></i>
|
||||||
{{user.full_name}}
|
{{user.full_name}}
|
||||||
<a class="close"
|
<a class="close"
|
||||||
ng-click="removeUser(user)"
|
ng-click="removeUser(user)"
|
||||||
ng-show="story.users.length > 1">
|
ng-show="story.users.length > 1 || story.teams.length > 0">
|
||||||
×
|
×
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
@ -220,15 +232,16 @@
|
|||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<input id="user"
|
<input id="user"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Click to add a user"
|
autocomplete="off"
|
||||||
|
placeholder="Click to add a team or user"
|
||||||
ng-model="asyncUser"
|
ng-model="asyncUser"
|
||||||
typeahead-wait-ms="200"
|
typeahead-wait-ms="200"
|
||||||
typeahead-editable="false"
|
typeahead-editable="false"
|
||||||
typeahead="user as user.full_name for user in
|
typeahead="actor as actor.name for actor in
|
||||||
searchUsers($viewValue, story.users)"
|
searchActors($viewValue, story.users, story.teams)"
|
||||||
typeahead-loading="loadingUsers"
|
typeahead-loading="loadingUsers"
|
||||||
typeahead-input-formatter="formatUserName($model)"
|
typeahead-on-select="addActor($model)"
|
||||||
typeahead-on-select="addUser($model)"
|
typeahead-template-url="/inline/actor-typeahead-item.html"
|
||||||
class="form-control input-sm"
|
class="form-control input-sm"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
@ -275,6 +288,14 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/ng-template" id="/inline/actor-typeahead-item.html">
|
||||||
|
<a tabindex="-1">
|
||||||
|
<i ng-class="'fa fa-sb-' + match.model.type"></i>
|
||||||
|
<span ng-bind-html="match.model.name | typeaheadHighlight:query"></span>
|
||||||
|
</a>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<!-- Template for the list of relevant worklists -->
|
<!-- Template for the list of relevant worklists -->
|
||||||
<script type="text/ng-template" id="/inline/worklists.html">
|
<script type="text/ng-template" id="/inline/worklists.html">
|
||||||
<table class="table table-striped table-condensed">
|
<table class="table table-striped table-condensed">
|
||||||
|
@ -64,53 +64,69 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-6 col-sm-offset-3"
|
<div class="row">
|
||||||
ng-show="story.private">
|
<div class="col-md-6 col-md-offset-3"
|
||||||
<table class="table table-striped">
|
ng-show="story.private">
|
||||||
<thead>
|
<table class="table table-striped">
|
||||||
<tr>
|
<thead>
|
||||||
<th>Users that can see this story</th>
|
<tr>
|
||||||
<th class="text-right">
|
<th>Teams and Users that can see this story</th>
|
||||||
<small>
|
<th class="text-right">
|
||||||
<a href
|
<small>
|
||||||
ng-click="showAddUser = !showAddUser">
|
<a href
|
||||||
<i class="fa fa-plus" ng-if="!showAddUser"></i>
|
ng-click="showAddUser = !showAddUser">
|
||||||
<i class="fa fa-minus" ng-if="showAddUser"></i>
|
<i class="fa fa-plus" ng-if="!showAddUser"></i>
|
||||||
Add User
|
<i class="fa fa-minus" ng-if="showAddUser"></i>
|
||||||
|
Add Team or User
|
||||||
|
</a>
|
||||||
|
</small>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="team in story.teams">
|
||||||
|
<td colspan="2">
|
||||||
|
<i class="fa fa-sb-team"></i>
|
||||||
|
{{ team.name }}
|
||||||
|
<a class="close"
|
||||||
|
ng-click="removeTeam(team)"
|
||||||
|
ng-show="story.teams.length > 1 || story.users.length > 0">
|
||||||
|
×
|
||||||
</a>
|
</a>
|
||||||
</small>
|
</td>
|
||||||
</th>
|
</tr>
|
||||||
</tr>
|
<tr ng-repeat="user in story.users">
|
||||||
</thead>
|
<td colspan="2">
|
||||||
<tbody>
|
<i class="fa fa-sb-user"></i>
|
||||||
<tr ng-repeat="user in story.users">
|
{{user.full_name}}
|
||||||
<td colspan="2">
|
<a class="close"
|
||||||
{{user.full_name}}
|
ng-click="removeUser(user)"
|
||||||
<a class="close"
|
ng-show="story.users.length > 1 || story.teams.length > 0">
|
||||||
ng-click="removeUser(user)">
|
×
|
||||||
×
|
</a>
|
||||||
</a>
|
</td>
|
||||||
</td>
|
</tr>
|
||||||
</tr>
|
<tr ng-show="showAddUser">
|
||||||
<tr ng-show="showAddUser">
|
<td colspan="2">
|
||||||
<td colspan="2">
|
<input id="user"
|
||||||
<input id="user"
|
type="text"
|
||||||
type="text"
|
autocomplete="off"
|
||||||
placeholder="Click to add a user"
|
placeholder="Click to add a team or user"
|
||||||
ng-model="asyncUser"
|
ng-model="asyncUser"
|
||||||
typeahead-wait-ms="200"
|
typeahead-wait-ms="200"
|
||||||
typeahead-editable="false"
|
typeahead-editable="false"
|
||||||
typeahead="user as user.full_name for user in
|
typeahead="actor as actor.name for actor in
|
||||||
searchUsers($viewValue, story.users)"
|
searchActors($viewValue, story.users, story.teams)"
|
||||||
typeahead-loading="loadingUsers"
|
typeahead-loading="loadingUsers"
|
||||||
typeahead-input-formatter="formatUserName($model)"
|
typeahead-on-select="addActor($model)"
|
||||||
typeahead-on-select="addUser($model)"
|
typeahead-template-url="/inline/actor-typeahead-item.html"
|
||||||
class="form-control input-sm"
|
class="form-control input-sm"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -163,6 +179,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/ng-template" id="/inline/actor-typeahead-item.html">
|
||||||
|
<a tabindex="-1">
|
||||||
|
<i ng-class="'fa fa-sb-' + match.model.type"></i>
|
||||||
|
<span ng-bind-html="match.model.name | typeaheadHighlight:query"></span>
|
||||||
|
</a>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<!-- Template for story metadata -->
|
<!-- Template for story metadata -->
|
||||||
<script type="text/ng-template" id="/inline/task_row.html">
|
<script type="text/ng-template" id="/inline/task_row.html">
|
||||||
<td>
|
<td>
|
||||||
|
Loading…
Reference in New Issue
Block a user