Commit d52a855f authored by Nick Stenning's avatar Nick Stenning

Merge pull request #2588 from robertknight/t88-remove_self_from_group

T88 - Add ability to leave groups
parents 053ec08a 15b2422a
'use strict';
// @ngInject
function GroupListController($scope) {
function GroupListController($scope, $window) {
$scope.expandedGroupId = undefined;
// show the share link for the specified group or clear it if
......@@ -26,6 +26,15 @@ function GroupListController($scope) {
return a.name.localeCompare(b.name);
});
}
$scope.leaveGroup = function (groupId) {
var groupName = $scope.groups.get(groupId).name;
var message = 'Are you sure you want to leave the group "' +
groupName + '"?';
if ($window.confirm(message)) {
$scope.groups.leave(groupId);
}
}
}
/**
......
......@@ -44,7 +44,7 @@ describe('GroupListController', function () {
},{
public: true
}];
}
},
};
var sorted = $scope.sortedGroups();
......@@ -66,6 +66,7 @@ function isElementHidden(element) {
describe('groupList', function () {
var $compile;
var $scope;
var $window;
var GROUP_LINK = 'https://hypothes.is/groups/hdevs';
......@@ -78,15 +79,26 @@ describe('groupList', function () {
url: GROUP_LINK
}];
var fakeGroups = {
all: function () {
return groups;
},
get: function (id) {
var match = this.all().filter(function (group) {
return group.id === id;
});
return match.length > 0 ? match[0] : undefined;
},
leave: sinon.stub(),
};
before(function() {
angular.module('app', [])
.directive('groupList', groupList.directive)
.factory('groups', function () {
return {
all: function () {
return groups;
}
};
return fakeGroups;
});
});
......@@ -95,9 +107,10 @@ describe('groupList', function () {
angular.mock.module('h.templates');
});
beforeEach(angular.mock.inject(function (_$compile_, _$rootScope_) {
beforeEach(angular.mock.inject(function (_$compile_, _$rootScope_, _$window_) {
$compile = _$compile_;
$scope = _$rootScope_.$new();
$window = _$window_;
}));
function createGroupList() {
......@@ -132,4 +145,16 @@ describe('groupList', function () {
toggleLink.click();
assert.ok(isElementHidden(expander));
});
it('should leave group when the leave icon is clicked', function () {
var element = createGroupList();
var leaveLink = element.find('.h-icon-cancel-outline');
// accept prompt to leave group
$window.confirm = function () {
return true;
};
leaveLink.click();
assert.ok(fakeGroups.leave.calledWith('h-devs'));
});
});
......@@ -7,10 +7,12 @@
*/
'use strict';
var baseURI = require('document-base-uri');
var STORAGE_KEY = 'hypothesis.groups.focus';
// @ngInject
function groups(localStorage, session, $rootScope, features) {
function groups(localStorage, session, $rootScope, features, $http) {
// The currently focused group. This is the group that's shown as selected in
// the groups dropdown, the annotations displayed are filtered to only ones
// that belong to this group, and any new annotations that the user creates
......@@ -31,10 +33,28 @@ function groups(localStorage, session, $rootScope, features) {
}
};
/** Leave the group with the given ID.
* Returns a promise which resolves when the action completes.
*/
function leave(id) {
var response = $http({
method: 'POST',
url: baseURI + 'groups/' + id + '/leave',
});
// TODO - Optimistically call remove() to
// remove the group locally when
// https://github.com/hypothesis/h/pull/2587 has been merged
return response;
};
return {
all: all,
get: get,
leave: leave,
// Return the currently focused group. If no group is explicitly focused we
// will check localStorage to see if we have persisted a focused group from
// a previous session. Lastly, we fall back to the first group available.
......
'use strict';
var baseURI = require('document-base-uri');
var groups = require('../groups');
// Return a mock session service containing three groups.
......@@ -21,6 +23,7 @@ describe('groups', function() {
var fakeLocalStorage;
var fakeRootScope;
var fakeFeatures;
var fakeHttp;
var sandbox;
beforeEach(function() {
......@@ -37,6 +40,7 @@ describe('groups', function() {
fakeFeatures = {
flagEnabled: function() {return true;}
};
fakeHttp = sandbox.stub()
});
afterEach(function () {
......@@ -44,7 +48,8 @@ describe('groups', function() {
});
function service() {
return groups(fakeLocalStorage, fakeSession, fakeRootScope, fakeFeatures);
return groups(fakeLocalStorage, fakeSession, fakeRootScope,
fakeFeatures, fakeHttp);
}
describe('.all()', function() {
......@@ -126,4 +131,15 @@ describe('groups', function() {
assert.calledWithMatch(fakeLocalStorage.setItem, sinon.match.any, 'id3');
});
});
describe('.leave()', function () {
it('should call the /groups/<id>/leave service', function () {
var s = service();
s.leave('id2');
assert.calledWithMatch(fakeHttp, {
url: baseURI + 'groups/id2/leave',
method: 'POST'
});
});
});
});
......@@ -123,8 +123,17 @@ $group-list-width: 270px;
margin-right: 10px;
}
.group-cancel-icon-container {
// the 'Leave group' icon is shifted down slightly
// so that it lines up vertically with the 'chat heads' icon on the
// left-hand side of the groups list
padding-top: 3px;
margin-right: 2px;
}
.group-details {
margin-right: 20px;
flex-grow: 1;
flex-shrink: 1;
}
......
......@@ -285,6 +285,14 @@
padding: 2px;
}
// a light grey cancel/remove button which darkens on hover
.btn--cancel {
color: $color-silver;
&:hover {
color: darken($color-silver, 15%);
}
}
// Handles state transitions from "default" -> "loading" -> "success"
[status-button-state] .btn-message {
top: -999em;
......
......@@ -11,17 +11,12 @@
}
.publish-annotation-cancel-btn {
$color: #bbb;
margin-left: 5px;
@extend .btn--cancel;
color: $color;
margin-left: 5px;
font-weight: normal;
&__icon {
margin-right: 3px;
}
&:hover {
color: darken($color, 15%);
}
}
......@@ -15,11 +15,12 @@ $gray-lightest: #f9f9f9 !default;
$color-mine-shaft: #3A3A3A;
$color-dove-gray: #626262;
$color-silver-chalice: #a6a6a6;
$color-silver: #bbb;
$color-alto: #dedede;
$color-seashell: #f1f1f1;
$color-wild-sand: #f5f5f5;
// COLORS
//COLORS
$brand-color: #bd1c2b !default;
$button-text-color: $gray-dark !default;
......
......@@ -46,6 +46,13 @@
</div>
</div>
</div>
<!-- the 'Leave group' icon !-->
<div class="group-cancel-icon-container">
<i class="h-icon-cancel-outline btn--cancel"
ng-if="!group.public"
ng-click="leaveGroup(group.id)"
title="Leave '{{group.name}}'"></i>
</div>
</div>
</li>
<li class="new-group-btn">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment