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',
|
||||
function ($log, $rootScope, $scope, $state, $stateParams, $modal, Session,
|
||||
Preference, TimelineEvent, Comment, TimelineEventTypes, story,
|
||||
Story, creator, tasks, Task, DSCacheFactory, User,
|
||||
Story, creator, tasks, Task, DSCacheFactory, User, $q,
|
||||
storyboardApiBase, SubscriptionList, CurrentUser,
|
||||
SessionModalService, moment, $document) {
|
||||
'use strict';
|
||||
@ -325,6 +325,51 @@ angular.module('sb.story').controller('StoryDetailController',
|
||||
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
|
||||
// ###################################################################
|
||||
|
@ -18,11 +18,20 @@
|
||||
* Controller for the "new story" modal popup.
|
||||
*/
|
||||
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';
|
||||
|
||||
var currentUser = CurrentUser.resolve();
|
||||
|
||||
$scope.projects = Project.browse({});
|
||||
$scope.story = new Story({title: ''});
|
||||
|
||||
currentUser.then(function(user) {
|
||||
$scope.story = new Story({
|
||||
title: '',
|
||||
users: [user]
|
||||
});
|
||||
});
|
||||
|
||||
$scope.tasks = [new Task({
|
||||
title: '',
|
||||
@ -153,5 +162,51 @@ angular.module('sb.story').controller('StoryModalController',
|
||||
$scope.selectNewProject = function (model, task) {
|
||||
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) 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
|
||||
@ -17,6 +18,11 @@
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<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
|
||||
src="'/inline/story_detail.html'"
|
||||
ng-hide="showEditForm">
|
||||
@ -91,59 +97,158 @@
|
||||
|
||||
<!-- Template for the header and description -->
|
||||
<script type="text/ng-template" id="/inline/story_detail_form.html">
|
||||
<form name="storyForm">
|
||||
<div class="form-group">
|
||||
<textarea type="text"
|
||||
class="form-control context-edit h1"
|
||||
ng-model="story.title"
|
||||
required
|
||||
ng-disabled="isUpdating"
|
||||
maxlength="255"
|
||||
placeholder="Story Title">
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="form-group" ng-show="previewStory">
|
||||
<insert-markdown content="story.description">
|
||||
</insert-markdown>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<textarea placeholder="Enter a story description here"
|
||||
class="form-control context-edit"
|
||||
msd-elastic
|
||||
rows="3"
|
||||
required
|
||||
ng-disabled="isUpdating"
|
||||
ng-model="story.description">
|
||||
</textarea>
|
||||
</div>
|
||||
<hr>
|
||||
<form name="storyForm" role="form" class="form-horizontal">
|
||||
<div class="form-group has-feedback"
|
||||
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"
|
||||
required
|
||||
focus
|
||||
maxlength="100"
|
||||
placeholder="Story title"
|
||||
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="clearfix">
|
||||
<div class="pull-right">
|
||||
<div class="btn" ng-show="isUpdating">
|
||||
<i class="fa fa-spinner fa-lg fa-spin"></i>
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
<hr ng-show="preview">
|
||||
<div class="form-group">
|
||||
<label for="description"
|
||||
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
|
||||
placeholder="Enter a story description here."
|
||||
ng-disabled="isUpdating">
|
||||
</textarea>
|
||||
</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="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="!storyForm.$valid">
|
||||
Save
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
ng-click="cancel()">
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
<button type="button"
|
||||
class="btn btn-primary"
|
||||
ng-click="update()"
|
||||
ng-disabled="!storyForm.$valid">
|
||||
Save
|
||||
class="btn btn-link"
|
||||
ng-click="remove()" permission="is_superuser">
|
||||
Remove this story
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-default"
|
||||
ng-click="cancel()">
|
||||
Cancel
|
||||
class="btn btn-primary"
|
||||
ng-click="previewStory = !previewStory">
|
||||
Toggle Preview
|
||||
</button>
|
||||
</div>
|
||||
<button type="button"
|
||||
class="btn btn-link"
|
||||
ng-click="remove()" permission="is_superuser">
|
||||
Remove this story
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-primary"
|
||||
ng-click="previewStory = !previewStory">
|
||||
Toggle Preview
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
|
@ -49,6 +49,69 @@
|
||||
</textarea>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
Reference in New Issue
Block a user