Commit 3c163a06 authored by Hannah Stepanek's avatar Hannah Stepanek

Use group section in group list

parent 64ae09ab
......@@ -26,9 +26,6 @@ function GroupListController(
) {
this.groups = groups;
// Track which non-selectable groups have their group details expanded.
this.groupDetailsExpanded = {};
this.createNewGroup = function() {
$window.open(serviceUrl('groups.new'), '_blank');
};
......@@ -90,23 +87,6 @@ function GroupListController(
groups.focus(groupId);
};
this.isGroupDetailsExpanded = function(groupId) {
if (!(groupId in this.groupDetailsExpanded)) {
this.groupDetailsExpanded[groupId] = false;
}
return this.groupDetailsExpanded[groupId];
};
/**
* Toggle the expanded setting on un-selectable groups.
*/
this.toggleGroupDetails = function(event, groupId) {
event.stopPropagation();
// Call the isGroupDetailsExpanded method so that if the groupId doesn't exist,
// it gets added before toggling it.
this.groupDetailsExpanded[groupId] = !this.isGroupDetailsExpanded(groupId);
};
/**
* Show the share link for the group if it is not a third-party group
* AND if the URL needed is present in the group object. We should be able
......
......@@ -3,6 +3,7 @@
const angular = require('angular');
const immutable = require('seamless-immutable');
const { events } = require('../../services/analytics');
const groupList = require('../group-list');
const util = require('../../directive/test/util');
......@@ -33,17 +34,6 @@ describe('groupList', function() {
isScopedToUri: true,
});
const restrictedOutOfScopeGroup = immutable({
id: 'restrictedoos',
links: {
html: 'https://hypothes.is/groups/restricto',
},
name: 'Restricted',
organization: groupFixtures.defaultOrganization(),
type: 'restricted',
isScopedToUri: false,
});
const publicGroup = immutable({
id: '__world__',
links: {
......@@ -85,11 +75,7 @@ describe('groupList', function() {
fakeAnalytics = {
track: sinon.stub(),
events: {
GROUP_LEAVE: 'groupLeave',
GROUP_SWITCH: 'groupSwitch',
GROUP_VIEW_ACTIVITY: 'groupViewActivity',
},
events,
};
fakeServiceUrl = sinon.stub();
......@@ -385,6 +371,7 @@ describe('groupList', function() {
'_blank'
);
});
describe('group section visibility', () => {
[
{
......@@ -393,7 +380,7 @@ describe('groupList', function() {
currentlyViewingGroups: [publicGroup],
featuredGroups: [restrictedGroup],
myGroups: [],
expectedSections: ['Currently Viewing', 'Featured Groups'],
expectedSections: ["'Currently Viewing'", "'Featured Groups'"],
},
{
description:
......@@ -401,14 +388,14 @@ describe('groupList', function() {
currentlyViewingGroups: [],
featuredGroups: [restrictedGroup],
myGroups: [publicGroup],
expectedSections: ['Featured Groups', 'My Groups'],
expectedSections: ["'Featured Groups'", "'My Groups'"],
},
{
description: 'shows My Groups section when there are my groups',
currentlyViewingGroups: [],
featuredGroups: [],
myGroups: [publicGroup, privateGroup],
expectedSections: ['My Groups'],
expectedSections: ["'My Groups'"],
},
].forEach(
({
......@@ -433,76 +420,21 @@ describe('groupList', function() {
const showGroupsMenu = element.ctrl.showGroupsMenu();
const dropdownToggle = element.find('.dropdown-toggle');
const arrowIcon = element.find('.h-icon-arrow-drop-down');
const sectionHeader = element.find('.dropdown-menu__section-heading');
const section = element.find('.dropdown-menu__section');
const dropdownOptions = element.find(
'.dropdown-community-groups-menu__row'
);
const groupListSection = element.find('group-list-section');
assert.isTrue(showGroupsMenu);
assert.lengthOf(dropdownToggle, 1);
assert.lengthOf(arrowIcon, 1);
sectionHeader.each(function() {
assert.isTrue(expectedSections.includes(this.textContent));
assert.lengthOf(groupListSection, expectedSections.length);
groupListSection.each(function() {
assert.isTrue(
expectedSections.includes(this.getAttribute('heading'))
);
});
// Plus one for the create private group section.
assert.lengthOf(section, expectedSections.length + 1);
assert.lengthOf(dropdownOptions, 3);
});
}
);
});
describe('group details expanded on out of scope groups', () => {
it('sets the default for the given groupid to false and returns it', () => {
const element = createGroupList();
const expanded = element.ctrl.isGroupDetailsExpanded('groupid');
assert.isFalse(expanded);
assert.isFalse(element.ctrl.groupDetailsExpanded.groupid);
});
it('gets expanded value for the given groupid if already present', () => {
const element = createGroupList();
element.ctrl.groupDetailsExpanded = { groupid: true };
const expanded = element.ctrl.isGroupDetailsExpanded('groupid');
assert.isTrue(expanded);
});
it('toggles the expanded value for the given groupid', () => {
const element = createGroupList();
let fakeEvent = { stopPropagation: sinon.stub() };
element.ctrl.toggleGroupDetails(fakeEvent, 'groupid');
assert.isTrue(element.ctrl.groupDetailsExpanded.groupid);
element.ctrl.toggleGroupDetails(fakeEvent, 'groupid');
assert.isFalse(element.ctrl.groupDetailsExpanded.groupid);
});
it('stops the event from propogating when toggling', () => {
const element = createGroupList();
let fakeEvent = { stopPropagation: sinon.spy() };
element.ctrl.toggleGroupDetails(fakeEvent, 'groupid');
sinon.assert.called(fakeEvent.stopPropagation);
});
});
it('displays out of scope groups as non-selectable', () => {
fakeFeatures.flagEnabled.withArgs('community_groups').returns(true);
// In order to show the group drop down there must be at least two groups.
groups = [publicGroup, restrictedOutOfScopeGroup];
fakeStore.getMyGroups.returns(groups);
const element = createGroupList();
const notSelectable = element.find('.group-item--out-of-scope');
assert.lengthOf(notSelectable, 1);
});
describe('group menu visibility', () => {
it('is hidden when third party service and only one group', function() {
......@@ -585,14 +517,12 @@ describe('groupList', function() {
const showGroupsMenu = element.ctrl.showGroupsMenu();
const dropdownToggle = element.find('.dropdown-toggle');
const arrowIcon = element.find('.h-icon-arrow-drop-down');
const dropdownOptions = element.find(
'.dropdown-community-groups-menu__row'
);
const groupListSection = element.find('.group-list-section');
assert.isTrue(showGroupsMenu);
assert.lengthOf(dropdownToggle, 1);
assert.lengthOf(arrowIcon, 1);
assert.lengthOf(dropdownOptions, 3);
assert.lengthOf(groupListSection, 1);
});
it('is not shown when community_groups feature flag is on and there is only one group', function() {
......@@ -605,14 +535,12 @@ describe('groupList', function() {
const showGroupsMenu = element.ctrl.showGroupsMenu();
const dropdownToggle = element.find('.dropdown-toggle');
const arrowIcon = element.find('.h-icon-arrow-drop-down');
const dropdownOptions = element.find(
'.dropdown-community-groups-menu__row'
);
const groupListSection = element.find('.group-list-section');
assert.isFalse(showGroupsMenu);
assert.lengthOf(dropdownToggle, 0);
assert.lengthOf(arrowIcon, 0);
assert.lengthOf(dropdownOptions, 0);
assert.lengthOf(groupListSection, 0);
});
});
......
<div class="pull-right"
dropdown
keyboard-nav>
<div class="pull-right" dropdown keyboard-nav>
<!-- Show a drop down menu if showGroupsMenu is true. -->
<div class="dropdown-toggle"
dropdown-toggle
data-toggle="dropdown"
role="button"
tabindex="0"
ng-if="vm.showGroupsMenu()">
<img class="group-list-label__icon group-list-label__icon--organization"
ng-src="{{ vm.focusedIcon() }}"
alt="{{ vm.orgName(vm.groups.focused().id)}}"
ng-if="vm.focusedIcon()">
<i class="group-list-label__icon h-icon-{{ vm.focusedIconClass() }}"
ng-if="!vm.focusedIcon()"></i><!-- nospace
!--><span class="group-list-label__label"><a class="group-list-label__toggle">{{vm.groups.focused().name}}</a><!-- nospace
!--><i class="h-icon-arrow-drop-down"></i></span>
<div
class="dropdown-toggle"
dropdown-toggle
data-toggle="dropdown"
role="button"
tabindex="0"
ng-if="vm.showGroupsMenu()"
>
<img
class="group-list-label__icon group-list-label__icon--organization"
ng-src="{{ vm.focusedIcon() }}"
alt="{{ vm.orgName(vm.groups.focused().id)}}"
ng-if="vm.focusedIcon()"
/>
<i
class="group-list-label__icon h-icon-{{ vm.focusedIconClass() }}"
ng-if="!vm.focusedIcon()"
></i
><!-- nospace
!--><span class="group-list-label__label"
><a class="group-list-label__toggle">{{vm.groups.focused().name}}</a
><!-- nospace
!--><i class="h-icon-arrow-drop-down"></i
></span>
</div>
<!-- Do not show a drop down menu if showGroupsMenu is false. -->
<div ng-if="!vm.showGroupsMenu()">
<img class="group-list-label__icon group-list-label__icon--organization"
ng-src="{{ vm.focusedIcon() }}"
alt="{{ vm.orgName(vm.groups.focused().id)}}"
ng-if="vm.focusedIcon()">
<i class="group-list-label__icon h-icon-{{ vm.focusedIconClass() }}"
ng-if="!vm.focusedIcon()"></i><!-- nospace
!--><span class="group-list-label__label">{{vm.groups.focused().name}}</span>
<img
class="group-list-label__icon group-list-label__icon--organization"
ng-src="{{ vm.focusedIcon() }}"
alt="{{ vm.orgName(vm.groups.focused().id)}}"
ng-if="vm.focusedIcon()"
/>
<i
class="group-list-label__icon h-icon-{{ vm.focusedIconClass() }}"
ng-if="!vm.focusedIcon()"
></i
><!-- nospace
!--><span class="group-list-label__label"
>{{vm.groups.focused().name}}</span
>
</div>
<!-- Only build the drop down menu if showGroupsMenu is true. -->
<!-- Original groups menu. -->
<div class="dropdown-menu__top-arrow" ng-if="vm.showGroupsMenu() && !vm.isFeatureFlagEnabled('community_groups')"></div>
<ul class="dropdown-menu pull-none" role="menu" ng-if="vm.showGroupsMenu() && !vm.isFeatureFlagEnabled('community_groups')">
<li class="dropdown-menu__row dropdown-menu__row--unpadded "
ng-repeat="group in vm.groupOrganizations() track by group.id">
<div ng-class="{'group-item': true, selected: group.id == vm.groups.focused().id}"
ng-click="vm.focusGroup(group.id)">
<div
class="dropdown-menu__top-arrow"
ng-if="vm.showGroupsMenu() && !vm.isFeatureFlagEnabled('community_groups')"
></div>
<ul
class="dropdown-menu pull-none"
role="menu"
ng-if="vm.showGroupsMenu() && !vm.isFeatureFlagEnabled('community_groups')"
>
<li
class="dropdown-menu__row dropdown-menu__row--unpadded "
ng-repeat="group in vm.groupOrganizations() track by group.id"
>
<div
ng-class="{'group-item': true, selected: group.id == vm.groups.focused().id}"
ng-click="vm.focusGroup(group.id)"
>
<!-- the group icon !-->
<div class="group-menu-icon-container">
<img class="group-list-label__icon group-list-label__icon--organization"
<img
class="group-list-label__icon group-list-label__icon--organization"
alt="{{ vm.orgName(group.id) }}"
ng-src="{{ group.logo }}"
ng-if="group.logo">
ng-if="group.logo"
/>
</div>
<!-- the group name and share link !-->
<div class="group-details">
<div class="group-name-container">
<a class="group-name-link"
href=""
title="{{ group.type === 'private' ? 'Show and create annotations in ' + group.name : 'Show public annotations' }}">
{{group.name}}
<a
class="group-name-link"
href=""
title="{{ group.type === 'private' ? 'Show and create annotations in ' + group.name : 'Show public annotations' }}"
>
{{group.name}}
</a>
</div>
<div class="share-link-container" ng-click="$event.stopPropagation()" ng-if="vm.shouldShowActivityLink(group.id)">
<a class="share-link"
href="{{group.links.html}}"
target="_blank"
ng-click="vm.viewGroupActivity()">
<div
class="share-link-container"
ng-click="$event.stopPropagation()"
ng-if="vm.shouldShowActivityLink(group.id)"
>
<a
class="share-link"
href="{{group.links.html}}"
target="_blank"
ng-click="vm.viewGroupActivity()"
>
View group activity
<span ng-if="group.type === 'private'">
and invite others
......@@ -65,19 +101,31 @@
</div>
</div>
<!-- the 'Leave group' icon !-->
<div class="group-cancel-icon-container" ng-click="$event.stopPropagation()">
<i class="h-icon-cancel-outline btn--cancel"
ng-if="group.type === 'private'"
ng-click="vm.leaveGroup(group.id)"
title="Leave '{{group.name}}'"></i>
<div
class="group-cancel-icon-container"
ng-click="$event.stopPropagation()"
>
<i
class="h-icon-cancel-outline btn--cancel"
ng-if="group.type === 'private'"
ng-click="vm.leaveGroup(group.id)"
title="Leave '{{group.name}}'"
></i>
</div>
</div>
</li>
<li ng-if="vm.auth.status === 'logged-in' && !vm.isThirdPartyUser()" class="dropdown-menu__row dropdown-menu__row--unpadded new-group-btn">
<li
ng-if="vm.auth.status === 'logged-in' && !vm.isThirdPartyUser()"
class="dropdown-menu__row dropdown-menu__row--unpadded new-group-btn"
>
<div class="group-item" ng-click="vm.createNewGroup()">
<div class="group-icon-container"><i class="h-icon-add"></i></div>
<div class="group-details">
<a href="" class="group-name-link" title="Create a new group to share annotations">
<a
href=""
class="group-name-link"
title="Create a new group to share annotations"
>
New private group
</a>
</div>
......@@ -86,124 +134,49 @@
</ul>
<!-- Show new menu if community_groups feature flag is enabled. -->
<div class="dropdown-menu" role="menu" ng-if="vm.showGroupsMenu() && vm.isFeatureFlagEnabled('community_groups')">
<!-- Display Currently Viewing. -->
<h2 class="dropdown-menu__section-heading" ng-if="vm.currentlyViewingGroupOrganizations().length > 0">Currently Viewing</h2>
<ul class="dropdown-menu__section" ng-if="vm.currentlyViewingGroupOrganizations().length > 0">
<li class="dropdown-community-groups-menu__row dropdown-menu__row--unpadded"
ng-repeat="group in vm.currentlyViewingGroupOrganizations() track by group.id">
<div ng-class="{'group-item-community-groups': true, 'is-selected': group.id == vm.groups.focused().id}"
ng-click="vm.focusGroup(group.id)" tabindex="0">
<!-- the group icon !-->
<div class="group-menu-icon-container">
<img class="group-list-label__icon group-list-label__icon--organization"
alt="{{ vm.orgName(group.id) }}"
ng-src="{{ group.logo }}"
ng-if="group.logo">
</div>
<!-- the group name and share link !-->
<div class="group-details-community-groups">
<a class="group-name-link"
href=""
title="{{ group.type === 'private' ? 'Show and create annotations in ' + group.name : 'Show public annotations' }}">
{{group.name}}
</a>
</div>
</li>
</ul>
<!-- Display Featured groups section. -->
<h2 class="dropdown-menu__section-heading" ng-if="vm.featuredGroupOrganizations().length > 0">Featured Groups</h2>
<ul class="dropdown-menu__section" ng-if="vm.featuredGroupOrganizations().length > 0">
<li class="dropdown-community-groups-menu__row dropdown-menu__row--unpadded"
ng-repeat="group in vm.featuredGroupOrganizations() track by group.id">
<div ng-class="{'group-item-community-groups': true, 'is-selected': group.id == vm.groups.focused().id}"
ng-click="vm.focusGroup(group.id)" tabindex="0">
<!-- the group icon !-->
<div class="group-menu-icon-container">
<img class="group-list-label__icon group-list-label__icon--organization"
alt="{{ vm.orgName(group.id) }}"
ng-src="{{ group.logo }}"
ng-if="group.logo">
</div>
<!-- the group name and share link !-->
<div class="group-details-community-groups">
<a class="group-name-link"
href=""
title="{{ group.type === 'private' ? 'Show and create annotations in ' + group.name : 'Show public annotations' }}">
{{group.name}}
</a>
</div>
</li>
</ul>
<div
class="dropdown-menu"
role="menu"
ng-if="vm.showGroupsMenu() && vm.isFeatureFlagEnabled('community_groups')"
>
<!-- Currently Viewing -->
<group-list-section
class="group-list-section"
heading="'Currently Viewing'"
section-groups="vm.currentlyViewingGroupOrganizations()"
ng-if="vm.currentlyViewingGroupOrganizations().length > 0"
>
</group-list-section>
<!-- Featured Groups -->
<group-list-section
class="group-list-section"
heading="'Featured Groups'"
section-groups="vm.featuredGroupOrganizations()"
ng-if="vm.featuredGroupOrganizations().length > 0"
>
</group-list-section>
<!-- Display My Groups groups section if user is logged in. -->
<h2 class="dropdown-menu__section-heading" ng-if="vm.myGroupOrganizations().length > 0">My Groups</h2>
<ul class="dropdown-menu__section" ng-if="vm.myGroupOrganizations().length > 0">
<li class="dropdown-community-groups-menu__row dropdown-menu__row--unpadded"
ng-repeat="group in vm.myGroupOrganizations() track by group.id">
<!-- Show the group like normal if it is scoped to this page -->
<div ng-class="{'group-item-community-groups': true, 'is-selected': group.id == vm.groups.focused().id}"
ng-click="vm.focusGroup(group.id)" tabindex="0" ng-if="group.isScopedToUri">
<!-- the group icon !-->
<div class="group-menu-icon-container">
<img class="group-list-label__icon group-list-label__icon--organization"
alt="{{ vm.orgName(group.id) }}"
ng-src="{{ group.logo }}"
ng-if="group.logo">
</div>
<!-- the group name and share link -->
<div class="group-details-community-groups">
<a class="group-name-link"
href=""
title="{{ group.type === 'private' ? 'Show and create annotations in ' + group.name : 'Show public annotations' }}">
{{group.name}}
</a>
</div>
</div>
<!-- Show the group as not selectable if it is not scoped to this page !-->
<div class="group-item--out-of-scope"
ng-class="{'group-item-community-groups': true, 'is-selected': group.id == vm.groups.focused().id}"
ng-click="vm.toggleGroupDetails($event, group.id)" tabindex="0" ng-if="!group.isScopedToUri">
<!-- the group icon !-->
<div class="group-menu-icon-container">
<img class="group-list-label__icon group-list-label__icon--organization"
alt="{{ vm.orgName(group.id) }}"
ng-src="{{ group.logo }}"
ng-if="group.logo">
</div>
<!-- the group name and share link !-->
<div ng-class="{'group-details-community-groups': true, expanded: vm.isGroupDetailsExpanded(group.id)}">
<svg class="svg-icon group__icon--unavailable" xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 24 24">
<path fill="none" d="M0 0h24v24H0V0z"/>
<path d="M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"/>
</svg>
<a class="group-name-link"
href=""
title="Group not annotatable on this domain.">
{{group.name}}
</a><br>
<p class="group-details__toggle">Why is this group unavailable?</p>
<p class="group-details__unavailable-message">
This group has been restricted to selected domains by its administrators.
</p>
<p class="group-details__actions">
<a class="button button--text group-details__group-page-link" href="{{group.links.html}}"
target="_blank"
ng-click="vm.viewGroupActivity()">Go to group page</a>
</p>
</div>
</div>
</li>
</ul>
<!-- My Groups -->
<group-list-section
class="group-list-section"
heading="'My Groups'"
section-groups="vm.myGroupOrganizations()"
disable-oos-group-selection="true"
ng-if="vm.myGroupOrganizations().length > 0"
>
</group-list-section>
<ul class="dropdown-menu__section dropdown-menu__section--no-header">
<li ng-if="vm.auth.status === 'logged-in' && !vm.isThirdPartyUser()" class="dropdown-community-groups-menu__row dropdown-menu__row--unpadded new-group-btn">
<div class="group-item-community-groups" ng-click="vm.createNewGroup()" tabindex="0">
<li
ng-if="vm.auth.status === 'logged-in' && !vm.isThirdPartyUser()"
class="dropdown-community-groups-menu__row dropdown-menu__row--unpadded new-group-btn"
>
<div
class="group-item-community-groups"
ng-click="vm.createNewGroup()"
tabindex="0"
>
<div class="group-icon-container"><i class="h-icon-add"></i></div>
<div class="group-details-community-groups">
New private group
......
......@@ -9,7 +9,7 @@ $group-list-spacing-below: 50px;
.dropdown-menu {
width: $group-list-width;
max-height: 500px; // fallback for browsers lacking support for vh/calc
max-height: 500px; // fallback for browsers lacking support for vh/calc
max-height: calc(100vh - #{$top-bar-height} - #{$group-list-spacing-below});
overflow-y: auto;
......@@ -21,26 +21,11 @@ $group-list-spacing-below: 50px;
}
.dropdown-menu__section--no-header {
border-top: solid 1px rgba(0, 0, 0, 0.15);
.group-details {
font-weight: 400;
}
}
.dropdown-menu__section-heading {
color: $gray-light;
font-size: 12px;
line-height: 1;
margin: 1px 1px 0;
padding: 12px 10px 0;
text-transform: uppercase;
&:not(:first-child) {
border-top: solid 1px rgba(0, 0, 0, 0.15);
}
}
.group-item {
display: flex;
flex-direction: row;
......@@ -90,11 +75,6 @@ $group-list-spacing-below: 50px;
}
}
.group-item--out-of-scope {
background-color: $gray-lightest;
color: $gray-light;
}
.group-icon-container {
margin-right: 10px;
}
......@@ -113,13 +93,6 @@ $group-list-spacing-below: 50px;
margin-right: 2px;
}
.group__icon--unavailable {
fill: $gray-light;
float: right;
height: 20px;
width: auto;
}
.group-details {
flex-grow: 1;
flex-shrink: 1;
......@@ -146,31 +119,6 @@ $group-list-spacing-below: 50px;
}
}
.group-details__toggle {
font-size: $body1-font-size;
font-style: italic;
margin: 0;
text-decoration: underline;
}
.group-details__unavailable-message {
font-size: $body1-font-size;
line-height: 1.5;
white-space: normal;
width: $group-list-width - 60px;
}
.group-details__actions {
text-align: right;
}
.group-details__group-page-link {
color: inherit;
font-size: $body1-font-size;
text-decoration: underline;
text-transform: uppercase;
}
.new-group-btn {
background-color: $gray-lightest;
......@@ -209,7 +157,7 @@ $group-list-spacing-below: 50px;
// the drop-down list when clicked
.group-list-label__label {
font-size: $body2-font-size;
font-weight:bold;
font-weight: bold;
display: inline-block;
}
......@@ -225,7 +173,6 @@ $group-list-spacing-below: 50px;
color: inherit;
}
.open {
& > .group-list__toggle {
background: $gray-lighter;
......
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