Unverified Commit a813d4e4 authored by Kyle Keating's avatar Kyle Keating Committed by GitHub

Hide the leave group button if allowLeavingGroups is false (#2123)

allowLeavingGroups is a new service level config setting that can globally override the the UI to hide the leave button for a group. This is necessary for section groups in LMS where groups are indeed private, but also can’t be left.
parent 25266f9e
......@@ -22,9 +22,8 @@ function GroupListItem({
onExpand,
toastMessenger,
}) {
const canLeaveGroup = group.type === 'private';
const activityUrl = group.links.html;
const hasActionMenu = activityUrl || canLeaveGroup;
const hasActionMenu = activityUrl || group.canLeave;
const isSelectable = !group.scopes.enforced || group.isScopedToUri;
const focusedGroupId = useStore(store => store.focusedGroupId());
......@@ -111,7 +110,7 @@ function GroupListItem({
/>
</li>
)}
{canLeaveGroup && (
{group.canLeave && (
<li>
<MenuItem
icon="leave"
......
......@@ -26,6 +26,7 @@ describe('GroupListItem', () => {
enforced: false,
},
type: 'private',
canLeave: true,
};
fakeStore = {
......@@ -199,6 +200,7 @@ describe('GroupListItem', () => {
it('does not show submenu toggle if there are no available actions', () => {
fakeGroup.links.html = null;
fakeGroup.type = 'open';
fakeGroup.canLeave = false;
const wrapper = createGroupListItem(fakeGroup);
assert.isFalse(wrapper.find('MenuItem').prop('isExpanded'));
});
......@@ -227,6 +229,7 @@ describe('GroupListItem', () => {
it('does not show "Leave" action if user cannot leave', () => {
fakeGroup.type = 'open';
fakeGroup.canLeave = false;
const wrapper = createGroupListItem(fakeGroup, {
isExpanded: true,
});
......
......@@ -342,7 +342,7 @@ export default function groups(
// metadata on them that will be used elsewhere in the app.
const isLoggedIn = token !== null;
const groups = await filterGroups(
combineGroups(myGroups, featuredGroups, documentUri),
combineGroups(myGroups, featuredGroups, documentUri, settings),
isLoggedIn,
directLinkedAnnotationGroupId,
directLinkedGroupId
......
import escapeStringRegexp from 'escape-string-regexp';
import serviceConfig from '../service-config';
/**
* Should users be able to leave private groups of which they
* are a member? Users may leave private groups unless
* explicitly disallowed in the service configuration of the
* `settings` object.
*
* @param {object} settings
* @return {boolean}
*/
function allowLeavingGroups(settings) {
const config = serviceConfig(settings) || {};
return typeof config.allowLeavingGroups === 'boolean'
? config.allowLeavingGroups
: true;
}
/**
* Combine groups from multiple api calls together to form a unique list of groups.
......@@ -9,8 +26,9 @@ import escapeStringRegexp from 'escape-string-regexp';
* @param {Group[]} userGroups - groups the user is a member of
* @param {Group[]} featuredGroups - all other groups, may include some duplicates from the userGroups
* @param {string} uri - uri of the current page
* @param {object} settings - The settings object.
*/
export function combineGroups(userGroups, featuredGroups, uri) {
export function combineGroups(userGroups, featuredGroups, uri, settings) {
const worldGroup = featuredGroups.find(g => g.id === '__world__');
if (worldGroup) {
userGroups.unshift(worldGroup);
......@@ -25,6 +43,14 @@ export function combineGroups(userGroups, featuredGroups, uri) {
const groups = userGroups.concat(featuredGroups);
// Set the `canLeave` property. Groups can be left if they are private unless
// the global `allowLeavingGroups` value is false in the config settings object.
groups.forEach(group => {
group.canLeave = !allowLeavingGroups(settings)
? false
: group.type === 'private';
});
// Add isScopedToUri property indicating whether a group is within scope
// of the given uri. If the scope check cannot be performed, isScopedToUri
// defaults to true.
......
import { combineGroups } from '../groups';
import { combineGroups, $imports } from '../groups';
describe('sidebar.util.groups', () => {
let fakeServiceConfig;
describe('combineGroups', () => {
it('labels groups in both lists as isMember true', () => {
beforeEach(() => {
fakeServiceConfig = sinon.stub().returns(null);
$imports.$mock({
'../service-config': fakeServiceConfig,
});
});
it('labels groups in both lists as `isMember` true', () => {
const userGroups = [{ id: 'groupa', name: 'GroupA' }];
const featuredGroups = [{ id: 'groupa', name: 'GroupA' }];
const groups = combineGroups(
......@@ -14,6 +22,55 @@ describe('sidebar.util.groups', () => {
assert.equal(groupA.isMember, true);
});
it('sets `canLeave` to true if a group is private and `allowLeavingGroups` is null', () => {
const userGroups = [{ id: 'groupa', name: 'GroupA', type: 'private' }];
const featuredGroups = [{ id: 'groupb', name: 'GroupB', type: 'open' }];
const groups = combineGroups(
userGroups,
featuredGroups,
'https://foo.com/bar'
);
const groupA = groups.find(g => g.id === 'groupa');
const groupB = groups.find(g => g.id === 'groupb');
assert.equal(groupA.canLeave, true);
assert.equal(groupB.canLeave, false);
});
it('sets `canLeave` to true if a group is private and `allowLeavingGroups` is not a boolean', () => {
fakeServiceConfig.returns({
allowLeavingGroups: () => {},
});
const userGroups = [{ id: 'groupa', name: 'GroupA', type: 'private' }];
const featuredGroups = [{ id: 'groupb', name: 'GroupB', type: 'open' }];
const groups = combineGroups(
userGroups,
featuredGroups,
'https://foo.com/bar'
);
const groupA = groups.find(g => g.id === 'groupa');
const groupB = groups.find(g => g.id === 'groupb');
assert.equal(groupA.canLeave, true);
assert.equal(groupB.canLeave, false);
});
it('sets `canLeave` to false for all groups if `allowLeavingGroups` is false', () => {
fakeServiceConfig.returns({
allowLeavingGroups: false,
});
const userGroups = [{ id: 'groupa', name: 'GroupA', type: 'private' }];
const featuredGroups = [{ id: 'groupb', name: 'GroupB', type: 'open' }];
const groups = combineGroups(
userGroups,
featuredGroups,
'https://foo.com/bar'
);
const groupA = groups.find(g => g.id === 'groupa');
const groupB = groups.find(g => g.id === 'groupb');
assert.equal(groupA.canLeave, false);
assert.equal(groupB.canLeave, false);
});
it('combines groups from both lists uniquely', () => {
const userGroups = [
{ id: 'groupa', name: 'GroupA' },
......@@ -32,7 +89,7 @@ describe('sidebar.util.groups', () => {
assert.deepEqual(ids, ['__world__', 'groupa', 'groupb']);
});
it('adds isMember attribute to each group', () => {
it('adds `isMember` attribute to each group', () => {
const userGroups = [{ id: 'groupa', name: 'GroupA' }];
const featuredGroups = [
{ id: 'groupb', name: 'GroupB' },
......
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