Merge "Add UI for making stories private to a list of people"
This commit is contained in:
commit
10c54bab47
@ -20,7 +20,7 @@
|
|||||||
angular.module('sb.story').controller('StoryDetailController',
|
angular.module('sb.story').controller('StoryDetailController',
|
||||||
function ($log, $rootScope, $scope, $state, $stateParams, $modal, Session,
|
function ($log, $rootScope, $scope, $state, $stateParams, $modal, Session,
|
||||||
Preference, TimelineEvent, Comment, TimelineEventTypes, story,
|
Preference, TimelineEvent, Comment, TimelineEventTypes, story,
|
||||||
Story, creator, tasks, Task, DSCacheFactory, User,
|
Story, creator, tasks, Task, DSCacheFactory, User, $q,
|
||||||
storyboardApiBase, SubscriptionList, CurrentUser,
|
storyboardApiBase, SubscriptionList, CurrentUser,
|
||||||
SessionModalService, moment, $document) {
|
SessionModalService, moment, $document) {
|
||||||
'use strict';
|
'use strict';
|
||||||
@ -325,6 +325,51 @@ angular.module('sb.story').controller('StoryDetailController',
|
|||||||
SessionModalService.showLoginRequiredModal();
|
SessionModalService.showLoginRequiredModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User typeahead search method.
|
||||||
|
*/
|
||||||
|
$scope.searchUsers = function (value, array) {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
|
||||||
|
User.browse({full_name: value, limit: 10},
|
||||||
|
function(searchResults) {
|
||||||
|
var results = [];
|
||||||
|
angular.forEach(searchResults, function(result) {
|
||||||
|
if (array.indexOf(result.id) === -1) {
|
||||||
|
results.push(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
deferred.resolve(results);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return deferred.promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the user name.
|
||||||
|
*/
|
||||||
|
$scope.formatUserName = function (model) {
|
||||||
|
if (!!model) {
|
||||||
|
return model.name;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new user to one of the permission levels.
|
||||||
|
*/
|
||||||
|
$scope.addUser = function (model) {
|
||||||
|
$scope.story.users.push(model);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a user from one of the permission levels.
|
||||||
|
*/
|
||||||
|
$scope.removeUser = function (model) {
|
||||||
|
var idx = $scope.story.users.indexOf(model);
|
||||||
|
$scope.story.users.splice(idx, 1);
|
||||||
|
};
|
||||||
|
|
||||||
// ###################################################################
|
// ###################################################################
|
||||||
// Task Management
|
// Task Management
|
||||||
// ###################################################################
|
// ###################################################################
|
||||||
|
@ -18,11 +18,20 @@
|
|||||||
* Controller for the "new story" modal popup.
|
* Controller for the "new story" modal popup.
|
||||||
*/
|
*/
|
||||||
angular.module('sb.story').controller('StoryModalController',
|
angular.module('sb.story').controller('StoryModalController',
|
||||||
function ($scope, $modalInstance, params, Project, Story, Task) {
|
function ($scope, $modalInstance, params, Project, Story, Task, User,
|
||||||
|
$q, CurrentUser) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var currentUser = CurrentUser.resolve();
|
||||||
|
|
||||||
$scope.projects = Project.browse({});
|
$scope.projects = Project.browse({});
|
||||||
$scope.story = new Story({title: ''});
|
|
||||||
|
currentUser.then(function(user) {
|
||||||
|
$scope.story = new Story({
|
||||||
|
title: '',
|
||||||
|
users: [user]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
$scope.tasks = [new Task({
|
$scope.tasks = [new Task({
|
||||||
title: '',
|
title: '',
|
||||||
@ -153,5 +162,51 @@ angular.module('sb.story').controller('StoryModalController',
|
|||||||
$scope.selectNewProject = function (model, task) {
|
$scope.selectNewProject = function (model, task) {
|
||||||
task.project_id = model.id;
|
task.project_id = model.id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User typeahead search method.
|
||||||
|
*/
|
||||||
|
$scope.searchUsers = function (value, array) {
|
||||||
|
var deferred = $q.defer();
|
||||||
|
|
||||||
|
User.browse({full_name: value, limit: 10},
|
||||||
|
function(searchResults) {
|
||||||
|
var results = [];
|
||||||
|
angular.forEach(searchResults, function(result) {
|
||||||
|
if (array.indexOf(result.id) === -1) {
|
||||||
|
results.push(result);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
deferred.resolve(results);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return deferred.promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the user name.
|
||||||
|
*/
|
||||||
|
$scope.formatUserName = function (model) {
|
||||||
|
if (!!model) {
|
||||||
|
return model.name;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new user to one of the permission levels.
|
||||||
|
*/
|
||||||
|
$scope.addUser = function (model) {
|
||||||
|
$scope.story.users.push(model);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a user from one of the permission levels.
|
||||||
|
*/
|
||||||
|
$scope.removeUser = function (model) {
|
||||||
|
var idx = $scope.story.users.indexOf(model);
|
||||||
|
$scope.story.users.splice(idx, 1);
|
||||||
|
};
|
||||||
|
|
||||||
})
|
})
|
||||||
;
|
;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<!--
|
<!--
|
||||||
~ Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
~ 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
|
~ 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
|
~ not use this file except in compliance with the License. You may obtain
|
||||||
@ -17,6 +18,11 @@
|
|||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
|
<div class="alert alert-danger" ng-show="story.private">
|
||||||
|
<i class="fa fa-eye-slash"></i>
|
||||||
|
<strong>This story is private</strong>.
|
||||||
|
Edit this story to change the privacy settings.
|
||||||
|
</div>
|
||||||
<div ng-include
|
<div ng-include
|
||||||
src="'/inline/story_detail.html'"
|
src="'/inline/story_detail.html'"
|
||||||
ng-hide="showEditForm">
|
ng-hide="showEditForm">
|
||||||
@ -91,32 +97,130 @@
|
|||||||
|
|
||||||
<!-- Template for the header and description -->
|
<!-- Template for the header and description -->
|
||||||
<script type="text/ng-template" id="/inline/story_detail_form.html">
|
<script type="text/ng-template" id="/inline/story_detail_form.html">
|
||||||
<form name="storyForm">
|
<hr>
|
||||||
<div class="form-group">
|
<form name="storyForm" role="form" class="form-horizontal">
|
||||||
<textarea type="text"
|
<div class="form-group has-feedback"
|
||||||
class="form-control context-edit h1"
|
ng-class="{'has-error': storyForm.title.$invalid,
|
||||||
|
'has-success': !storyForm.title.$invalid}">
|
||||||
|
<label for="title" class="col-sm-2 control-label">
|
||||||
|
Title
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input id="title"
|
||||||
|
name="title"
|
||||||
|
type="text"
|
||||||
|
class="form-control"
|
||||||
ng-model="story.title"
|
ng-model="story.title"
|
||||||
required
|
required
|
||||||
ng-disabled="isUpdating"
|
focus
|
||||||
maxlength="255"
|
maxlength="100"
|
||||||
placeholder="Story Title">
|
placeholder="Story title"
|
||||||
</textarea>
|
ng-disabled="isUpdating">
|
||||||
|
<span class="form-control-feedback"
|
||||||
|
ng-show="storyForm.title.$invalid">
|
||||||
|
<i class="fa fa-times fa-lg"></i>
|
||||||
|
</span>
|
||||||
|
<span class="form-control-feedback"
|
||||||
|
ng-show="!storyForm.title.$invalid">
|
||||||
|
<i class="fa fa-check fa-lg"></i>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div class="help-block text-danger"
|
||||||
|
ng-show="storyForm.title.$invalid">
|
||||||
|
<span ng-show="storyForm.title.$error.required">
|
||||||
|
A story title is required.
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group" ng-show="previewStory">
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr ng-show="preview">
|
||||||
|
<div class="form-group" ng-show="preview">
|
||||||
|
<div class="col-sm-offset-1 col-sm-10">
|
||||||
<insert-markdown content="story.description">
|
<insert-markdown content="story.description">
|
||||||
</insert-markdown>
|
</insert-markdown>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr ng-show="preview">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<textarea placeholder="Enter a story description here"
|
<label for="description"
|
||||||
class="form-control context-edit"
|
class="col-sm-2 control-label">
|
||||||
|
Description
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<textarea id="description"
|
||||||
|
class="form-control"
|
||||||
|
ng-model="story.description"
|
||||||
msd-elastic
|
msd-elastic
|
||||||
rows="3"
|
placeholder="Enter a story description here."
|
||||||
required
|
ng-disabled="isUpdating">
|
||||||
ng-disabled="isUpdating"
|
|
||||||
ng-model="story.description">
|
|
||||||
</textarea>
|
</textarea>
|
||||||
</div>
|
</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="story.private"
|
||||||
|
ng-disabled="isUpdating"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6 col-sm-offset-3"
|
||||||
|
ng-show="story.private">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Users that can see this story</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 story.users">
|
||||||
|
<td colspan="2">
|
||||||
|
{{user.full_name}}
|
||||||
|
<a class="close"
|
||||||
|
ng-click="removeUser(user)"
|
||||||
|
ng-show="story.users.length > 1">
|
||||||
|
×
|
||||||
|
</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, story.users)"
|
||||||
|
typeahead-loading="loadingUsers"
|
||||||
|
typeahead-input-formatter="formatUserName($model)"
|
||||||
|
typeahead-on-select="addUser($model)"
|
||||||
|
class="form-control input-sm"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
<div class="clearfix">
|
<div class="clearfix">
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<div class="btn" ng-show="isUpdating">
|
<div class="btn" ng-show="isUpdating">
|
||||||
@ -145,6 +249,7 @@
|
|||||||
Toggle Preview
|
Toggle Preview
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -49,6 +49,69 @@
|
|||||||
</textarea>
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</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="story.private"
|
||||||
|
ng-disabled="isSaving"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6 col-sm-offset-3"
|
||||||
|
ng-show="story.private">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Users that can see this story</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 story.users">
|
||||||
|
<td colspan="2">
|
||||||
|
{{user.full_name}}
|
||||||
|
<a class="close"
|
||||||
|
ng-click="removeUser(user)">
|
||||||
|
×
|
||||||
|
</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, story.users)"
|
||||||
|
typeahead-loading="loadingUsers"
|
||||||
|
typeahead-input-formatter="formatUserName($model)"
|
||||||
|
typeahead-on-select="addUser($model)"
|
||||||
|
class="form-control input-sm"
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user