Skip to content
Snippets Groups Projects
Commit 54120207 authored by Luke "Jared" Bennett's avatar Luke "Jared" Bennett Committed by Phil Hughes
Browse files

Better Explore Groups view

parent 54beb93a
No related branches found
No related tags found
No related merge requests found
Showing with 335 additions and 48 deletions
Loading
Loading
@@ -44,6 +44,7 @@ import GroupsList from './groups_list';
import ProjectsList from './projects_list';
import MiniPipelineGraph from './mini_pipeline_graph_dropdown';
import BlobLinePermalinkUpdater from './blob/blob_line_permalink_updater';
import Landing from './landing';
import BlobForkSuggestion from './blob/blob_fork_suggestion';
import UserCallout from './user_callout';
import { ProtectedTagCreate, ProtectedTagEditList } from './protected_tags';
Loading
Loading
@@ -148,8 +149,19 @@ const ShortcutsBlob = require('./shortcuts_blob');
new ProjectsList();
break;
case 'dashboard:groups:index':
new GroupsList();
break;
case 'explore:groups:index':
new GroupsList();
const landingElement = document.querySelector('.js-explore-groups-landing');
if (!landingElement) break;
const exploreGroupsLanding = new Landing(
landingElement,
landingElement.querySelector('.dismiss-button'),
'explore_groups_landing_dismissed',
);
exploreGroupsLanding.toggle();
break;
case 'projects:milestones:new':
case 'projects:milestones:edit':
Loading
Loading
import Cookies from 'js-cookie';
class Landing {
constructor(landingElement, dismissButton, cookieName) {
this.landingElement = landingElement;
this.cookieName = cookieName;
this.dismissButton = dismissButton;
this.eventWrapper = {};
}
toggle() {
const isDismissed = this.isDismissed();
this.landingElement.classList.toggle('hidden', isDismissed);
if (!isDismissed) this.addEvents();
}
addEvents() {
this.eventWrapper.dismissLanding = this.dismissLanding.bind(this);
this.dismissButton.addEventListener('click', this.eventWrapper.dismissLanding);
}
removeEvents() {
this.dismissButton.removeEventListener('click', this.eventWrapper.dismissLanding);
}
dismissLanding() {
this.landingElement.classList.add('hidden');
Cookies.set(this.cookieName, 'true', { expires: 365 });
}
isDismissed() {
return Cookies.get(this.cookieName) === 'true';
}
}
export default Landing;
Loading
Loading
@@ -254,6 +254,63 @@
padding: 10px 0;
}
 
.landing {
margin-bottom: $gl-padding;
overflow: hidden;
display: flex;
position: relative;
border: 1px solid $blue-300;
border-radius: $border-radius-default;
background-color: $blue-25;
justify-content: center;
.dismiss-button {
position: absolute;
right: 6px;
top: 6px;
cursor: pointer;
color: $blue-300;
z-index: 1;
border: none;
background-color: transparent;
&:hover,
&:focus {
border: none;
color: $blue-400;
}
}
.svg-container {
align-self: center;
}
.inner-content {
text-align: left;
white-space: nowrap;
h4 {
color: $gl-text-color;
font-size: 17px;
}
p {
color: $gl-text-color;
margin-bottom: $gl-padding;
}
}
@media (max-width: $screen-sm-min) {
flex-direction: column;
.inner-content {
white-space: normal;
padding: 0 28px;
text-align: center;
}
}
}
.empty-state {
margin: 100px 0 0;
 
Loading
Loading
Loading
Loading
@@ -424,6 +424,11 @@ table {
}
}
 
.bordered-box {
border: 1px solid $border-color;
border-radius: $border-radius-default;
}
.str-truncated {
&-60 {
@include str-truncated(60%);
Loading
Loading
Loading
Loading
@@ -93,11 +93,6 @@
top: $gl-padding-top;
}
 
.bordered-box {
border: 1px solid $border-color;
border-radius: $border-radius-default;
}
.content-list {
li {
padding: 18px $gl-padding $gl-padding;
Loading
Loading
@@ -139,42 +134,9 @@
}
}
 
.landing {
margin-bottom: $gl-padding;
overflow: hidden;
.dismiss-icon {
position: absolute;
right: $cycle-analytics-box-padding;
cursor: pointer;
color: $cycle-analytics-dismiss-icon-color;
}
.svg-container {
text-align: center;
svg {
width: 136px;
height: 136px;
}
}
.inner-content {
@media (max-width: $screen-xs-max) {
padding: 0 28px;
text-align: center;
}
h4 {
color: $gl-text-color;
font-size: 17px;
}
p {
color: $cycle-analytics-box-text-color;
margin-bottom: $gl-padding;
}
}
.landing svg {
width: 136px;
height: 136px;
}
 
.fa-spinner {
Loading
Loading
Loading
Loading
@@ -88,3 +88,26 @@
color: $gl-text-color-secondary;
margin-top: 10px;
}
.explore-groups.landing {
margin-top: 10px;
.inner-content {
padding: 0;
p {
margin: 7px 0 0;
max-width: 480px;
padding: 0 $gl-padding;
@media (max-width: $screen-sm-min) {
margin: 0 auto;
}
}
}
svg {
width: 62px;
height: 50px;
}
}
Loading
Loading
@@ -2,10 +2,10 @@
%ul.nav-links
= nav_link(page: dashboard_groups_path) do
= link_to dashboard_groups_path, title: 'Your groups' do
Your Groups
Your groups
= nav_link(page: explore_groups_path) do
= link_to explore_groups_path, title: 'Explore groups' do
Explore Groups
= link_to explore_groups_path, title: 'Explore public groups' do
Explore public groups
.nav-controls
= render 'shared/groups/search_form'
= render 'shared/groups/dropdown'
Loading
Loading
Loading
Loading
@@ -7,6 +7,15 @@
= render 'explore/head'
= render 'nav'
 
- if cookies[:explore_groups_landing_dismissed] != 'true'
.explore-groups.landing.content-block.js-explore-groups-landing.hidden
%button.dismiss-button{ type: 'button', 'aria-label' => 'Dismiss' }= icon('times')
.svg-container
= custom_icon('icon_explore_groups_splash')
.inner-content
%p Below you will find all the groups that are public.
%p You can easily contribute to them by requesting to join these groups.
- if @groups.present?
= render 'groups'
- else
Loading
Loading
<svg xmlns="http://www.w3.org/2000/svg" width="62" height="50" viewBox="260 141 62 50" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="a" d="M24.6 7.7H56c3.3 0 6 2.7 6 6V44c0 3.3-2.7 6-6 6H6c-3.3 0-6-2.7-6-6V4.8C0 2 2.2 0 4.8 0h12c1.5 0 3 1 4 2l3.8 5.7z"/><mask id="e" width="62" height="50" x="0" y="0" fill="#fff"><use xlink:href="#a"/></mask><path id="b" d="M4.2 13c3.7 0 4-1.7 4-4.5S7 4.8 4.2 4.8 0 5.8 0 8.5C0 11.3.5 13 4.2 13z"/><mask id="f" width="10.7" height="10.7" x="-1.2" y="-1.2"><path fill="#fff" d="M-1.2 3.6H9.5v10.7H-1.2z"/><use xlink:href="#b"/></mask><path id="c" d="M4.2 13c3.7 0 4-1.7 4-4.5S7 4.8 4.2 4.8 0 5.8 0 8.5C0 11.3.5 13 4.2 13z"/><mask id="g" width="10.7" height="10.7" x="-1.2" y="-1.2"><path fill="#fff" d="M-1.2 3.6H9.5v10.7H-1.2z"/><use xlink:href="#c"/></mask><path id="d" d="M5.4 16c4.7 0 5.3-2.3 5.3-6 0-3.5-1.7-4.6-5.3-4.6C1.7 5.4 0 6.4 0 10s.6 6 5.4 6z"/><mask id="h" width="13.1" height="13.1" x="-1.2" y="-1.2"><path fill="#fff" d="M-1.2 4.2h13v13H-1z"/><use xlink:href="#d"/></mask></defs><g fill="none" fill-rule="evenodd" transform="translate(260 141)"><use fill="#FFF" stroke="#EEE" stroke-width="4.8" mask="url(#e)" xlink:href="#a"/><g transform="translate(33.98 22.62)"><use fill="#B5A7DD" xlink:href="#b"/><use stroke="#FFF" stroke-width="2.4" mask="url(#f)" xlink:href="#b"/><ellipse cx="4.2" cy="3" fill="#B5A7DD" stroke="#FFF" stroke-width="1.2" rx="3" ry="3"/></g><g transform="translate(19.673 22.62)"><use fill="#B5A7DD" xlink:href="#c"/><use stroke="#FFF" stroke-width="2.4" mask="url(#g)" xlink:href="#c"/><ellipse cx="4.2" cy="3" fill="#B5A7DD" stroke="#FFF" stroke-width="1.2" rx="3" ry="3"/></g><g transform="translate(25.635 21.43)"><use fill="#B5A7DD" xlink:href="#d"/><use stroke="#FFF" stroke-width="2.4" mask="url(#h)" xlink:href="#d"/><ellipse cx="5.4" cy="3.6" fill="#B5A7DD" stroke="#FFF" stroke-width="1.2" rx="3.6" ry="3.6"/></g></g></svg>
require 'spec_helper'
 
describe 'Explore Groups page', js: true, feature: true do
describe 'Explore Groups page', :js, :feature do
let!(:user) { create :user }
let!(:group) { create(:group) }
let!(:public_group) { create(:group, :public) }
Loading
Loading
@@ -46,19 +46,39 @@ describe 'Explore Groups page', js: true, feature: true do
it 'shows non-archived projects count' do
# Initially project is not archived
expect(find('.js-groups-list-holder .content-list li:first-child .stats span:first-child')).to have_text("1")
# Archive project
empty_project.archive!
visit explore_groups_path
 
# Check project count
expect(find('.js-groups-list-holder .content-list li:first-child .stats span:first-child')).to have_text("0")
# Unarchive project
empty_project.unarchive!
visit explore_groups_path
 
# Check project count
expect(find('.js-groups-list-holder .content-list li:first-child .stats span:first-child')).to have_text("1")
expect(find('.js-groups-list-holder .content-list li:first-child .stats span:first-child')).to have_text("1")
end
describe 'landing component' do
it 'should show a landing component' do
expect(page).to have_content('Below you will find all the groups that are public.')
end
it 'should be dismissable' do
find('.dismiss-button').click
expect(page).not_to have_content('Below you will find all the groups that are public.')
end
it 'should persistently not show once dismissed' do
find('.dismiss-button').click
visit explore_groups_path
expect(page).not_to have_content('Below you will find all the groups that are public.')
end
end
end
Loading
Loading
@@ -35,6 +35,7 @@ feature 'Create New Merge Request', feature: true, js: true do
expect(page).to have_content('Target branch')
 
first('.js-target-branch').click
first('.dropdown-target-branch .dropdown-content')
first('.dropdown-target-branch .dropdown-content a', text: 'v1.1.0').click
 
expect(page).to have_content "b83d6e3"
Loading
Loading
import Landing from '~/landing';
import Cookies from 'js-cookie';
describe('Landing', function () {
describe('class constructor', function () {
beforeEach(function () {
this.landingElement = {};
this.dismissButton = {};
this.cookieName = 'cookie_name';
this.landing = new Landing(this.landingElement, this.dismissButton, this.cookieName);
});
it('should set .landing', function () {
expect(this.landing.landingElement).toBe(this.landingElement);
});
it('should set .cookieName', function () {
expect(this.landing.cookieName).toBe(this.cookieName);
});
it('should set .dismissButton', function () {
expect(this.landing.dismissButton).toBe(this.dismissButton);
});
it('should set .eventWrapper', function () {
expect(this.landing.eventWrapper).toEqual({});
});
});
describe('toggle', function () {
beforeEach(function () {
this.isDismissed = false;
this.landingElement = { classList: jasmine.createSpyObj('classList', ['toggle']) };
this.landing = {
isDismissed: () => {},
addEvents: () => {},
landingElement: this.landingElement,
};
spyOn(this.landing, 'isDismissed').and.returnValue(this.isDismissed);
spyOn(this.landing, 'addEvents');
Landing.prototype.toggle.call(this.landing);
});
it('should call .isDismissed', function () {
expect(this.landing.isDismissed).toHaveBeenCalled();
});
it('should call .classList.toggle', function () {
expect(this.landingElement.classList.toggle).toHaveBeenCalledWith('hidden', this.isDismissed);
});
it('should call .addEvents', function () {
expect(this.landing.addEvents).toHaveBeenCalled();
});
describe('if isDismissed is true', function () {
beforeEach(function () {
this.isDismissed = true;
this.landingElement = { classList: jasmine.createSpyObj('classList', ['toggle']) };
this.landing = {
isDismissed: () => {},
addEvents: () => {},
landingElement: this.landingElement,
};
spyOn(this.landing, 'isDismissed').and.returnValue(this.isDismissed);
spyOn(this.landing, 'addEvents');
this.landing.isDismissed.calls.reset();
Landing.prototype.toggle.call(this.landing);
});
it('should not call .addEvents', function () {
expect(this.landing.addEvents).not.toHaveBeenCalled();
});
});
});
describe('addEvents', function () {
beforeEach(function () {
this.dismissButton = jasmine.createSpyObj('dismissButton', ['addEventListener']);
this.eventWrapper = {};
this.landing = {
eventWrapper: this.eventWrapper,
dismissButton: this.dismissButton,
dismissLanding: () => {},
};
Landing.prototype.addEvents.call(this.landing);
});
it('should set .eventWrapper.dismissLanding', function () {
expect(this.eventWrapper.dismissLanding).toEqual(jasmine.any(Function));
});
it('should call .addEventListener', function () {
expect(this.dismissButton.addEventListener).toHaveBeenCalledWith('click', this.eventWrapper.dismissLanding);
});
});
describe('removeEvents', function () {
beforeEach(function () {
this.dismissButton = jasmine.createSpyObj('dismissButton', ['removeEventListener']);
this.eventWrapper = { dismissLanding: () => {} };
this.landing = {
eventWrapper: this.eventWrapper,
dismissButton: this.dismissButton,
};
Landing.prototype.removeEvents.call(this.landing);
});
it('should call .removeEventListener', function () {
expect(this.dismissButton.removeEventListener).toHaveBeenCalledWith('click', this.eventWrapper.dismissLanding);
});
});
describe('dismissLanding', function () {
beforeEach(function () {
this.landingElement = { classList: jasmine.createSpyObj('classList', ['add']) };
this.cookieName = 'cookie_name';
this.landing = { landingElement: this.landingElement, cookieName: this.cookieName };
spyOn(Cookies, 'set');
Landing.prototype.dismissLanding.call(this.landing);
});
it('should call .classList.add', function () {
expect(this.landingElement.classList.add).toHaveBeenCalledWith('hidden');
});
it('should call Cookies.set', function () {
expect(Cookies.set).toHaveBeenCalledWith(this.cookieName, 'true', { expires: 365 });
});
});
describe('isDismissed', function () {
beforeEach(function () {
this.cookieName = 'cookie_name';
this.landing = { cookieName: this.cookieName };
spyOn(Cookies, 'get').and.returnValue('true');
this.isDismissed = Landing.prototype.isDismissed.call(this.landing);
});
it('should call Cookies.get', function () {
expect(Cookies.get).toHaveBeenCalledWith(this.cookieName);
});
it('should return a boolean', function () {
expect(typeof this.isDismissed).toEqual('boolean');
});
});
});
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment