diff --git a/app/assets/javascripts/discourse/controllers/groups.js.es6 b/app/assets/javascripts/discourse/controllers/groups.js.es6
new file mode 100644
index 00000000000..d8ce08f3227
--- /dev/null
+++ b/app/assets/javascripts/discourse/controllers/groups.js.es6
@@ -0,0 +1,16 @@
+import { observes } from 'ember-addons/ember-computed-decorators';
+
+export default Ember.Controller.extend({
+ application: Ember.inject.controller(),
+
+ @observes("groups.canLoadMore")
+ _showFooter() {
+ this.set("application.showFooter", !this.get("groups.canLoadMore"));
+ },
+
+ actions: {
+ loadMore() {
+ this.get('groups').loadMore();
+ }
+ }
+});
diff --git a/app/assets/javascripts/discourse/models/group.js.es6 b/app/assets/javascripts/discourse/models/group.js.es6
index d3ca40baef7..38d4fb82ee2 100644
--- a/app/assets/javascripts/discourse/models/group.js.es6
+++ b/app/assets/javascripts/discourse/models/group.js.es6
@@ -1,8 +1,9 @@
import { ajax } from 'discourse/lib/ajax';
import { default as computed, observes } from "ember-addons/ember-computed-decorators";
import GroupHistory from 'discourse/models/group-history';
+import RestModel from 'discourse/models/rest';
-const Group = Discourse.Model.extend({
+const Group = RestModel.extend({
limit: 50,
offset: 0,
user_count: 0,
diff --git a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 b/app/assets/javascripts/discourse/routes/app-route-map.js.es6
index 4b23587a899..04da387763c 100644
--- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6
+++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6
@@ -50,6 +50,8 @@ export default function() {
this.route(defaultHomepage(), { path: '/' });
});
+ this.route('groups', { resetNamespace: true });
+
this.route('group', { path: '/groups/:name', resetNamespace: true }, function() {
this.route('members');
this.route('posts');
diff --git a/app/assets/javascripts/discourse/routes/groups.js.es6 b/app/assets/javascripts/discourse/routes/groups.js.es6
new file mode 100644
index 00000000000..b567f7f72cf
--- /dev/null
+++ b/app/assets/javascripts/discourse/routes/groups.js.es6
@@ -0,0 +1,13 @@
+export default Discourse.Route.extend({
+ titleToken() {
+ return I18n.t('groups.index');
+ },
+
+ model(params) {
+ return this.store.findAll('group', params);
+ },
+
+ setupController(controller, model) {
+ controller.set('groups', model);
+ }
+});
diff --git a/app/assets/javascripts/discourse/templates/groups.hbs b/app/assets/javascripts/discourse/templates/groups.hbs
new file mode 100644
index 00000000000..b4563aef8dd
--- /dev/null
+++ b/app/assets/javascripts/discourse/templates/groups.hbs
@@ -0,0 +1,39 @@
+{{#d-section pageClass="groups"}}
+ {{#load-more selector=".groups-table .groups-table-row" action="loadMore"}}
+
{{i18n "groups.index"}}
+
+
+
+
+ {{i18n "groups.name"}} |
+ {{i18n "groups.user_count"}} |
+
+
+
+ {{#each groups as |group|}}
+
+
+ {{#link-to "group.members" group.name}}
+ {{#if group.flair_url}}
+
+ {{avatar-flair
+ flairURL=group.flair_url
+ flairBgColor=group.flair_bg_color
+ flairColor=group.flair_color
+ groupName=group.name}}
+
+ {{/if}}
+
+ @{{group.name}}
+ {{/link-to}}
+ |
+ {{group.user_count}} |
+
+ {{/each}}
+
+
+
+ {{/load-more}}
+
+ {{conditional-loading-spinner condition=groups.loadingMore}}
+{{/d-section}}
diff --git a/app/assets/javascripts/discourse/widgets/hamburger-menu.js.es6 b/app/assets/javascripts/discourse/widgets/hamburger-menu.js.es6
index d670a89c6fa..452cc069891 100644
--- a/app/assets/javascripts/discourse/widgets/hamburger-menu.js.es6
+++ b/app/assets/javascripts/discourse/widgets/hamburger-menu.js.es6
@@ -103,6 +103,8 @@ export default createWidget('hamburger-menu', {
links.push({ route: 'users', className: 'user-directory-link', label: 'directory.title' });
}
+ links.push({ route: 'groups', className: 'groups-link', label: 'groups.index' });
+
if (this.siteSettings.tagging_enabled) {
links.push({ route: 'tags', label: 'tagging.tags' });
}
diff --git a/app/assets/stylesheets/common/base/group.scss b/app/assets/stylesheets/common/base/group.scss
index 09c4eb28991..ef205ef343d 100644
--- a/app/assets/stylesheets/common/base/group.scss
+++ b/app/assets/stylesheets/common/base/group.scss
@@ -111,9 +111,7 @@ table.group-members {
.group-details {
width: 100%;
-}
-.group-details {
span {
display: inline-block;
vertical-align: middle;
diff --git a/app/assets/stylesheets/common/base/groups.scss b/app/assets/stylesheets/common/base/groups.scss
new file mode 100644
index 00000000000..cb9e69f01ef
--- /dev/null
+++ b/app/assets/stylesheets/common/base/groups.scss
@@ -0,0 +1,45 @@
+.groups-page {
+ h1 {
+ margin: 20px 0px;
+ }
+}
+
+.groups-table {
+ width: 100%;
+
+ .groups-name {
+ span {
+ display: inline-block;
+ vertical-align: middle;
+ }
+
+ .avatar-flair {
+ $size: 30px;
+
+ background-size: $size;
+ height: $size;
+ width: $size;
+
+ i {
+ font-size: $size !important;
+ }
+ }
+ }
+
+ th {
+ border-bottom: 3px solid dark-light-diff($primary, $secondary, 90%, -60%);
+ padding: 5px 0px 5px 5px;
+ color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
+ font-weight: normal;
+ }
+
+ tr {
+ border-bottom: 1px solid dark-light-diff($primary, $secondary, 90%, -60%);
+
+ td {
+ text-align: center;
+ color: dark-light-diff($primary, $secondary, 50%, -50%);
+ padding: 0.8em 0;
+ }
+ }
+}
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index e4b5fc14331..dd0265ad5ff 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -10,6 +10,22 @@ class GroupsController < ApplicationController
skip_before_filter :preload_json, :check_xhr, only: [:posts_feed, :mentions_feed]
+ def index
+ page_size = 30
+ page = params[:page]&.to_i || 0
+
+ groups = Group.order(user_count: :desc, name: :asc)
+ .where(visible: true)
+ .offset(page * page_size)
+ .limit(page_size)
+
+ render json: {
+ groups: serialize_data(groups, BasicGroupSerializer),
+ total_rows_groups: Group.count,
+ load_more_groups: groups_path(page: page + 1)
+ }
+ end
+
def show
render_serialized(find_group(:id), GroupShowSerializer, root: 'basic_group')
end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index ba337b8443e..257ab7fbe22 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -417,6 +417,7 @@ en:
request: "Request to Join Group"
allow_membership_requests: "Allow users to send membership requests to group owners (Requires everyone to be able to mention the group)"
name: "Name"
+ user_count: "Number of Members"
bio: "About Group"
selector_placeholder: "Add members"
owner: "owner"
diff --git a/spec/fabricators/group_fabricator.rb b/spec/fabricators/group_fabricator.rb
index 0ec42da4c5e..d190d520e69 100644
--- a/spec/fabricators/group_fabricator.rb
+++ b/spec/fabricators/group_fabricator.rb
@@ -1,3 +1,3 @@
Fabricator(:group) do
- name 'my_group'
+ name { sequence(:name) { |n| "my_group_#{n}" } }
end
diff --git a/spec/integration/groups_spec.rb b/spec/integration/groups_spec.rb
index fbf620c4a38..cf2f0547777 100644
--- a/spec/integration/groups_spec.rb
+++ b/spec/integration/groups_spec.rb
@@ -12,6 +12,24 @@ describe "Groups" do
expect(response).to be_success
end
+ describe 'viewing groups' do
+ it 'should return the right response' do
+ group.update_attributes!(visible: true)
+ other_group = Fabricate(:group, name: '0000', visible: true)
+
+ get "/groups.json"
+
+ expect(response).to be_success
+
+ response_body = JSON.parse(response.body)
+
+ group_ids = response_body["groups"].map { |g| g["id"] }
+
+ expect(group_ids).to include(group.id, other_group.id)
+ expect(response_body["load_more_groups"]).to eq("/groups?page=1")
+ end
+ end
+
describe "checking if a group can be mentioned" do
it "should return the right response" do
sign_in(user)
diff --git a/test/javascripts/acceptance/groups-test.js.es6 b/test/javascripts/acceptance/groups-test.js.es6
index 6152326f52c..04c8e6f5bff 100644
--- a/test/javascripts/acceptance/groups-test.js.es6
+++ b/test/javascripts/acceptance/groups-test.js.es6
@@ -3,6 +3,20 @@ import { acceptance, logIn } from "helpers/qunit-helpers";
acceptance("Groups");
test("Browsing Groups", () => {
+ visit("/groups");
+
+ andThen(() => {
+ equal(count('.groups-table-row'), 18, 'it displays visible groups');
+ });
+
+ click("a[href='/groups/discourse/members']");
+
+ andThen(() => {
+ equal(find('.group-header').text().trim(), 'Awesome Team', "it displays the group page");
+ });
+});
+
+test("Viewing Group", () => {
visit("/groups/discourse");
andThen(() => {
@@ -34,7 +48,7 @@ test("Browsing Groups", () => {
});
});
-test("Admin Browsing Groups", () => {
+test("Admin Viewing Group", () => {
logIn();
Discourse.reset();
diff --git a/test/javascripts/fixtures/groups-fixtures.js.es6 b/test/javascripts/fixtures/groups-fixtures.js.es6
new file mode 100644
index 00000000000..078ffbd8578
--- /dev/null
+++ b/test/javascripts/fixtures/groups-fixtures.js.es6
@@ -0,0 +1,3 @@
+export default {
+ "/groups.json": {"groups":[{"id":1,"automatic":true,"name":"admins","user_count":2,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":3,"automatic":true,"name":"staff","user_count":2,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":10,"automatic":true,"name":"trust_level_0","user_count":2,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":11,"automatic":true,"name":"trust_level_1","user_count":2,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":12,"automatic":true,"name":"trust_level_2","user_count":2,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":13,"automatic":true,"name":"trust_level_3","user_count":2,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":14,"automatic":true,"name":"trust_level_4","user_count":2,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":2,"automatic":true,"name":"moderators","user_count":1,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":41,"automatic":false,"name":"my_group_0","user_count":0,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":42,"automatic":false,"name":"my_group_1","user_count":0,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":43,"automatic":false,"name":"my_group_2","user_count":0,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":44,"automatic":false,"name":"my_group_3","user_count":0,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":45,"automatic":false,"name":"my_group_4","user_count":0,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":46,"automatic":false,"name":"my_group_5","user_count":0,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":47,"automatic":false,"name":"my_group_6","user_count":0,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":48,"automatic":false,"name":"my_group_7","user_count":0,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":49,"automatic":false,"name":"my_group_8","user_count":0,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null},{"id":50,"automatic":false,"name":"discourse","user_count":0,"alias_level":0,"visible":true,"automatic_membership_email_domains":null,"automatic_membership_retroactive":false,"primary_group":false,"title":null,"grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":null,"flair_bg_color":null,"flair_color":null,"bio_raw":null,"bio_cooked":null,"public":false,"allow_membership_requests":false,"full_name":null}],"total_rows_groups":19,"load_more_groups":"/groups?page=1"}
+}
diff --git a/test/javascripts/helpers/create-pretender.js.es6 b/test/javascripts/helpers/create-pretender.js.es6
index fe1b4d1a294..c7f2f8cbceb 100644
--- a/test/javascripts/helpers/create-pretender.js.es6
+++ b/test/javascripts/helpers/create-pretender.js.es6
@@ -242,6 +242,10 @@ export default function() {
slug: request.params.slug } });
});
+ this.get("groups", () => {
+ return response(200, fixturesByUrl['/groups.json']);
+ });
+
this.get("/groups/discourse/topics.json", () => {
return response(200, fixturesByUrl['/groups/discourse/posts.json']);
});