UX: Tweaks to group pages.

This commit is contained in:
Guo Xiang Tan 2018-03-29 14:57:10 +08:00
parent 27f06505b1
commit 52e75eaee9
29 changed files with 468 additions and 253 deletions

View File

@ -3,6 +3,8 @@ import { popupAjaxError } from 'discourse/lib/ajax-error';
import showModal from 'discourse/lib/show-modal';
export default Ember.Component.extend({
classNames: ["group-membership-button"],
@computed("model.public_admission", "userIsGroupUser")
canJoinGroup(publicAdmission, userIsGroupUser) {
return publicAdmission && !userIsGroupUser;

View File

@ -124,16 +124,21 @@ const Group = RestModel.extend({
return mentionableLevel === '99';
},
@computed("visibility_level")
isPrivate(visibilityLevel) {
return visibilityLevel !== 0;
},
@observes("visibility_level", "canEveryoneMention")
_updateAllowMembershipRequests() {
if (this.get('visibility_level') !== 0 || !this.get('canEveryoneMention')) {
if (this.get('isPrivate') || !this.get('canEveryoneMention')) {
this.set ('allow_membership_requests', false);
}
},
@observes("visibility_level")
_updatePublic() {
if (this.get('visibility_level') !== 0) {
if (this.get('isPrivate')) {
this.set('public', false);
this.set('allow_membership_requests', false);
}
@ -250,10 +255,6 @@ Group.reopenClass({
});
},
find(name) {
return ajax("/groups/" + name + ".json").then(result => Group.create(result.basic_group));
},
loadMembers(name, offset, limit, params) {
return ajax('/groups/' + name + '/members.json', {
data: _.extend({

View File

@ -107,6 +107,11 @@ export default Ember.Object.extend({
var adapter = this.adapterFor(type);
return adapter.find(this, type, findArgs, opts).then(result => {
var hydrated = this._hydrateFindResults(result, type, findArgs, opts);
if (result.extras) {
hydrated.set('extras', result.extras);
}
if (adapter.cache) {
const stale = adapter.findStale(this, type, findArgs, opts);
hydrated = this._updateStale(stale, hydrated);

View File

@ -1,13 +1,10 @@
import Group from 'discourse/models/group';
export default Discourse.Route.extend({
titleToken() {
return [ this.modelFor('group').get('name') ];
},
model(params) {
return Group.find(params.name);
return this.store.find("group", params.name);
},
serialize(model) {
@ -15,6 +12,6 @@ export default Discourse.Route.extend({
},
setupController(controller, model) {
controller.setProperties({ model, counts: this.get('counts') });
controller.setProperties({ model });
}
});

View File

@ -11,21 +11,9 @@
label="groups.leave"
disabled=updatingMembership}}
{{else if model.allow_membership_requests}}
{{#if userIsGroupUser}}
{{#if showMembershipStatus}}
{{d-button
class="btn-primary"
icon="user"
label="groups.is_group_user"
disabled=true}}
{{/if}}
{{else}}
{{d-button action="showRequestMembershipForm"
class="group-index-request"
disabled=loading
icon="user-plus"
label="groups.request"}}
{{/if}}
{{else}}
{{yield}}
{{d-button action="showRequestMembershipForm"
class="group-index-request"
disabled=loading
icon="user-plus"
label="groups.request"}}
{{/if}}

View File

@ -1,4 +1,14 @@
{{#mobile-nav class='group-nav' desktopClass="nav nav-pills" currentPath=currentPath}}
{{#if site.mobileView}}
<li>
{{#link-to "groups.index"}}
{{i18n "groups.index.all"}}
{{/link-to}}
</li>
{{else}}
{{group-dropdown content=group.extras.visible_group_names value=group.name}}
{{/if}}
{{#each tabs as |tab|}}
<li>
{{#link-to tab.route group title=tab.message class=tab.name}}

View File

@ -7,6 +7,7 @@
<table class='group-members'>
<thead>
{{group-index-toggle order=order desc=desc field='username_lower' i18nKey='username'}}
<th>{{i18n "groups.members.owner"}}</th>
{{group-index-toggle order=order desc=desc field='last_posted_at' i18nKey='last_post'}}
{{group-index-toggle order=order desc=desc field='last_seen_at' i18nKey='last_seen'}}
<th></th>
@ -16,10 +17,17 @@
{{#each model.members as |m|}}
<tr>
<td class='avatar'>
{{#user-info user=m skipName=skipName}}
{{#if m.owner}}<strong class="group-owner-label">{{i18n "groups.owner"}}</strong>{{/if}}
{{/user-info}}
{{user-info user=m skipName=skipName}}
</td>
<td>
{{#if m.owner}}
<strong class="group-owner-label">
{{d-icon "shield"}}
</strong>
{{/if}}
</td>
<td>
<span class="text">{{bound-date m.last_posted_at}}</span>
</td>

View File

@ -1,12 +1,5 @@
{{plugin-outlet name="before-group-container" args=(hash group=model)}}
{{#link-to "groups"}}
{{d-icon 'arrow-left'}}
{{i18n "groups.index.title"}}
{{/link-to}}
<hr>
<div class="container group {{model.name}}">
<div class='group-details-container'>
<div class='group-info'>
@ -36,21 +29,26 @@
<p>{{{model.bio_cooked}}}</p>
</div>
{{/if}}
<div class="group-details-button">
{{group-membership-button
class="inline"
model=model
showLogin='showLogin'}}
{{#if displayGroupMessageButton}}
{{d-button
action="messageGroup"
class="btn-primary group-message-button inline"
icon="envelope"
label="groups.message"}}
{{/if}}
</div>
</div>
<div class="list-controls">
<div class="container">
{{group-navigation group=model currentPath=application.currentPath tabs=tabs}}
{{#if displayGroupMessageButton}}
{{d-button
action="messageGroup"
class="btn-primary group-message-button"
icon="envelope"
label="groups.message"}}
{{/if}}
{{group-membership-button model=model showLogin='showLogin'}}
</div>
</div>

View File

@ -1,22 +1,24 @@
{{#d-section pageClass="groups"}}
<h1>{{i18n "groups.index.title"}}</h1>
<div class="groups-header">
{{#if currentUser.admin}}
{{d-button action="new"
class="groups-header-new pull-right"
icon="plus"
label="groups.new.title"}}
{{/if}}
{{#if currentUser.admin}}
<div class="list-controls">
{{group-admin-dropdown new="new"}}
<div class="groups-header-filters">
{{text-field value=filterInput
placeholderKey="groups.index.all_groups"
class="groups-header-filters-name no-blur"}}
{{combo-box value=type
content=types
clearable=true
allowAutoSelectFirst=false
placeholder="groups.index.filter"
class="groups-header-filters-type"}}
</div>
{{/if}}
<div class="groups-filter">
{{combo-box value=type
content=types
clearable=true
none="groups.index.all_groups"
class="groups-type-filter"}}
{{text-field value=filterInput
placeholderKey="groups.filter_name"
class="groups-name-filter no-blur"}}
</div>
{{#if model}}
@ -25,10 +27,10 @@
<div class='container'>
<table class="groups-table">
<thead>
<th></th>
{{directory-toggle field="name" labelKey="groups.group_name" order=order asc=asc}}
{{directory-toggle field="user_count" labelKey="groups.user_count" order=order asc=asc}}
<th>{{i18n "groups.index.group_type"}}</th>
<th>{{i18n "groups.membership"}}</th>
<th></th>
</thead>
<tbody>
@ -64,25 +66,31 @@
<td class="groups-user-count">{{group.user_count}}</td>
<td>
{{#group-membership-button model=group
showMembershipStatus=true
showLogin='showLogin'}}
{{d-button icon="ban"
label=(if group.automatic 'groups.automatic_group' 'groups.close_group')
disabled=true}}
{{/group-membership-button}}
<td class="groups-table-type">
{{#if group.public_admission}}
{{i18n 'groups.index.public'}}
{{else if group.isPrivate}}
{{d-icon "eye-slash"}}
{{i18n 'groups.index.private'}}
{{else}}
{{#if group.automatic}}
{{i18n 'groups.index.automatic'}}
{{else}}
{{i18n 'groups.index.closed'}}
{{/if}}
{{/if}}
</td>
<td class="group-user-status">
{{#if group.is_group_user}}
{{d-icon "user" title="groups.is_group_user"}}
{{/if}}
<td class="groups-table-membership">
<span>
{{#if group.is_group_owner}}
{{i18n "groups.index.is_group_owner"}}
{{else if group.is_group_user}}
{{i18n "groups.index.is_group_user"}}
{{/if}}
</span>
{{#if group.is_group_owner}}
{{d-icon "shield" title="groups.is_group_owner"}}
{{/if}}
{{group-membership-button model=group showLogin='showLogin'}}
</td>
</tr>
{{/each}}

View File

@ -1,29 +0,0 @@
import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box";
export default DropdownSelectBoxComponent.extend({
classNames: "groups-admin-dropdown pull-right",
headerIcon: ["bars", "caret-down"],
showFullTitle: false,
computeContent() {
const items = [
{
id: "new",
name: I18n.t("groups.new.title"),
description: I18n.t("groups.new.description"),
icon: "plus"
}
];
return items;
},
mutateValue(value) {
switch (value) {
case 'new': {
this.sendAction("new");
break;
}
}
},
});

View File

@ -0,0 +1,44 @@
import ComboBoxComponent from "select-kit/components/combo-box";
import DiscourseURL from "discourse/lib/url";
import { default as computed } from "ember-addons/ember-computed-decorators";
export default ComboBoxComponent.extend({
pluginApiIdentifiers: ["group-dropdown"],
classNames: "group-dropdown",
content: Ember.computed.alias("groups"),
tagName: "li",
caretDownIcon: "caret-right fa-fw",
caretUpIcon: "caret-down fa-fw",
allowAutoSelectFirst: false,
valueAttribute: 'name',
@computed("content")
filterable(content) {
return content && content.length >= 10;
},
computeHeaderContent() {
let content = this._super();
if (!this.get("hasSelection")) {
content.label = `<span>${I18n.t("groups.index.all")}</span>`;
}
return content;
},
@computed
collectionHeader() {
return `
<a href="${Discourse.getURL("/groups")}" class="group-dropdown-filter">
${I18n.t("groups.index.all").toLowerCase()}
</a>
`.htmlSafe();
},
actions: {
onSelect(groupName) {
DiscourseURL.routeTo(Discourse.getURL(`/groups/${groupName}`));
}
}
});

View File

@ -1,10 +1,10 @@
.directory {
margin-bottom: 100px;
.user-info {
margin-bottom: 0;
}
.period-chooser {
float: left;
}
@ -18,25 +18,25 @@
.spinner {
clear: both;
}
table {
width: 100%;
margin-bottom: 1em;
td, th {
padding: 0.5em;
text-align: left;
border-bottom: 1px solid $primary-low;
border-bottom: 1px solid $primary-low;
.number, .time-read {
font-size: $font-up-3;
color: $primary-medium;
color: $primary-medium;
}
.time-read {
white-space: nowrap;
}
}
th.sortable {
cursor: pointer;
white-space: nowrap;
@ -48,9 +48,9 @@
.d-icon-chevron-down, .d-icon-chevron-up {
margin-left: 0.5em;
}
&:hover {
background-color: $primary-low;
background-color: $primary-low;
}
}
}

View File

@ -2,6 +2,23 @@
background: rgba(230, 230, 230, 0.3);
padding: 20px;
margin-bottom: 15px;
position: relative;
.group-details-button {
position: absolute;
top: 20px;
right: 20px;
}
}
.group-outlet {
position: relative;
}
.group-username-filter {
position: absolute;
right: 0;
top: -49px;
}
.group-post {
@ -120,7 +137,7 @@ table.group-members {
}
th:first-child {
width: 60%;
width: 30%;
text-align: left;
}
@ -201,13 +218,8 @@ table.group-members {
}
}
.group-manage,
.groups-new-page {
.form-horizontal {
label {
font-weight: bold;
}
}
.group-form-save {
margin-right: 20px;
}
.group-manage-members {

View File

@ -5,15 +5,18 @@
}
}
.groups-filter {
display: inline-block;
float: right;
.groups-header {
margin-bottom: 30px;
}
.groups-type-filter {
.groups-header-filters {
display: inline-block;
.groups-header-filters-type {
vertical-align: middle;
}
.groups-name-filter {
.groups-header-filters-name {
vertical-align: middle;
margin: 0;
}
@ -39,8 +42,8 @@
border-bottom: 1px solid $primary-low;
td {
color: blend-primary-secondary(50%);
padding: 0.8em;
color: $primary-medium;
}
td.groups-info {
@ -54,9 +57,26 @@
}
td.groups-user-count {
font-size: $font-up-2
width: 17%;
font-size: $font-up-2;
}
}
td.groups-table-type {
width: 17%;
font-size: $font-up-1;
}
td.groups-table-membership {
.group-membership-button {
display: inline-block;
margin-left: 5px;
}
> span {
font-size: $font-up-1;
}
}
}
.groups-info {
.groups-info-name {

View File

@ -0,0 +1,76 @@
.select-kit {
&.combo-box {
&.group-dropdown {
min-width: auto;
.combo-box-header {
background: $primary-low;
color: $primary;
border: 1px solid transparent;
padding: 4.5px 5px 4.5px 10px;
font-size: $font-0;
transition: none;
.d-icon {
opacity: 1;
font-size: $font-0;
margin: 0;
}
}
&.is-expanded .tag-drop-header {
border: 1px solid $tertiary;
box-shadow: shadow("focus");
}
.select-kit-collection {
display: flex;
flex-direction: column;
padding: 0;
max-height: 300px;
.collection-header {
.group-dropdown-filter {
white-space: nowrap;
color: $primary;
font-size: $font-down-1;
line-height: $line-height-medium;
font-weight: bold;
display: block;
padding: 10px 5px;
&:hover {
text-decoration: underline;
}
}
}
}
.select-kit-filter .filter-input {
width: auto;
}
.select-kit-body {
width: auto;
min-width: 150px;
border-radius: 0;
box-shadow: shadow("dropdown");
}
.select-kit-row {
margin: 0;
font-size: $font-down-1;
font-weight: bold;
color: $tertiary;
&.no-content {
font-weight: normal;
}
}
&.is-expanded .select-kit-wrapper, .select-kit-wrapper {
display: none;
}
}
}
}

View File

@ -1,4 +1,12 @@
.group-nav {
.group-dropdown {
margin-right: 10px;
i {
color: $primary;
}
}
li {
float: left;

View File

@ -6,8 +6,8 @@
$filter-line-height: 1.5;
.groups-filter {
.groups-type-filter {
.groups-header-filters {
.groups-header-filters-type {
.select-kit-header {
line-height: $filter-line-height;
}

View File

@ -80,3 +80,8 @@ table.group-manage-logs {
}
}
}
.group-username-filter {
top: -57px;
height: 27px;
}

View File

@ -3,12 +3,14 @@
margin-top: 20px;
}
.groups-filter {
.groups-header-filters {
display: block;
float: none;
}
.groups-name-filter {
.groups-header-filters-name,
.groups-header-filters-type,
.groups-header-new {
margin-top: 10px;
}
}

View File

@ -109,7 +109,18 @@ class GroupsController < ApplicationController
end
format.json do
render_serialized(group, GroupShowSerializer, root: 'basic_group')
groups = Group.visible_groups(current_user)
if !guardian.is_staff?
groups = groups.where(automatic: false)
end
render_json_dump(
group: serialize_data(group, GroupShowSerializer, root: nil),
extras: {
visible_group_names: groups.pluck(:name)
}
)
end
end
end
@ -436,7 +447,8 @@ class GroupsController < ApplicationController
def find_group(param_name)
name = params.require(param_name)
group = Group.find_by("lower(name) = ?", name.downcase)
group = Group
group = group.find_by("lower(name) = ?", name.downcase)
guardian.ensure_can_see!(group)
group
end

View File

@ -448,15 +448,10 @@ en:
topics: "There are no topics by members of this group."
logs: "There are no logs for this group."
add: "Add"
join: "Join Group"
leave: "Leave Group"
request: "Request to Join Group"
filter_name: "filter by group name"
join: "Join"
leave: "Leave"
request: "Request"
message: "Message"
automatic_group: Automatic Group
close_group: Close Group
is_group_user: "You are a member of this group"
is_group_owner: "You are an owner of this group"
allow_membership_requests: "Allow users to send membership requests to group owners"
membership_request_template: "Custom template to display to users when sending a membership request"
membership_request:
@ -465,19 +460,31 @@ en:
reason: "Let the group owners know why you belong in this group"
membership: "Membership"
name: "Name"
user_count: "Members Count"
group_name: "Group name"
user_count: "Users"
bio: "About Group"
selector_placeholder: "enter username"
owner: "owner"
index:
title: "Groups"
all: "All Groups"
empty: "There are no visible groups."
filter: "Filter by group type"
all_groups: "All Groups"
owner_groups: "Groups I am an owner of"
close_groups: "Close Groups"
automatic_groups: "Automatic Groups"
automatic: "Automatic"
closed: "Closed"
public: "Public"
private: "Private"
public_groups: "Public Groups"
automatic_group: Automatic Group
close_group: Close Group
my_groups: "My Groups"
group_type: "Group type"
is_group_user: "Member"
is_group_owner: "Owner"
title:
one: "Group"
other: "Groups"
@ -492,6 +499,7 @@ en:
make_owner_description: "Make <b>%{username}</b> an owner of this group"
remove_owner: "Remove as Owner"
remove_owner_description: "Remove <b>%{username}</b> as an owner of this group"
owner: "Owner"
topics: "Topics"
posts: "Posts"
mentions: "Mentions"

View File

@ -1,94 +0,0 @@
require 'rails_helper'
describe GroupsController do
let(:group) { Fabricate(:group) }
describe 'show' do
it "ensures the group can be seen" do
Guardian.any_instance.expects(:can_see?).with(group).returns(false)
get :show, params: { id: group.name }, format: :json
expect(response).not_to be_success
end
it "responds with JSON" do
Guardian.any_instance.expects(:can_see?).with(group).returns(true)
get :show, params: { id: group.name }, format: :json
expect(response).to be_success
expect(::JSON.parse(response.body)['basic_group']['id']).to eq(group.id)
end
it "works even with an upper case group name" do
Guardian.any_instance.expects(:can_see?).with(group).returns(true)
get :show, params: { id: group.name.upcase }, format: :json
expect(response).to be_success
expect(::JSON.parse(response.body)['basic_group']['id']).to eq(group.id)
end
end
describe "posts" do
it "ensures the group can be seen" do
Guardian.any_instance.expects(:can_see?).with(group).returns(false)
get :posts, params: { group_id: group.name }, format: :json
expect(response).not_to be_success
end
it "calls `posts_for` and responds with JSON" do
Guardian.any_instance.expects(:can_see?).with(group).returns(true)
Group.any_instance.expects(:posts_for).returns(Group.none)
get :posts, params: { group_id: group.name }, format: :json
expect(response).to be_success
end
end
describe "members" do
it "ensures the group can be seen" do
Guardian.any_instance.expects(:can_see?).with(group).returns(false)
get :members, params: { group_id: group.name }, format: :json
expect(response).not_to be_success
end
it "calls `posts_for` and responds with JSON" do
Guardian.any_instance.expects(:can_see?).with(group).returns(true)
get :posts, params: { group_id: group.name }, format: :json
expect(response).to be_success
end
it "ensures that membership can be paginated" do
5.times { group.add(Fabricate(:user)) }
usernames = group.users.map { |m| m.username }.sort
get :members, params: { group_id: group.name, limit: 3 }, format: :json
expect(response).to be_success
members = JSON.parse(response.body)["members"]
expect(members.map { |m| m['username'] }).to eq(usernames[0..2])
get :members, params: { group_id: group.name, limit: 3, offset: 3 }, format: :json
expect(response).to be_success
members = JSON.parse(response.body)["members"]
expect(members.map { |m| m['username'] }).to eq(usernames[3..4])
end
end
describe '.posts_feed' do
it 'renders RSS' do
get :posts_feed, params: { group_id: group.name }, format: :rss
expect(response).to be_success
expect(response.content_type).to eq('application/rss+xml')
end
end
describe '.mentions_feed' do
it 'renders RSS' do
get :mentions_feed, params: { group_id: group.name }, format: :rss
expect(response).to be_success
expect(response.content_type).to eq('application/rss+xml')
end
it 'fails when disabled' do
SiteSetting.enable_mentions = false
get :mentions_feed, params: { group_id: group.name }, format: :rss
expect(response).not_to be_success
end
end
end

View File

@ -206,6 +206,47 @@ describe GroupsController do
end
describe '#show' do
it "ensures the group can be seen" do
sign_in(Fabricate(:user))
group.update!(visibility_level: Group.visibility_levels[:owners])
get "/groups/#{group.name}.json"
expect(response.status).to eq(403)
end
it "returns the right response" do
sign_in(user)
get "/groups/#{group.name}.json"
expect(response.status).to eq(200)
response_body = JSON.parse(response.body)
expect(response_body['group']['id']).to eq(group.id)
expect(response_body['extras']["visible_group_names"]).to eq([group.name])
end
context 'as an admin' do
it "returns the right response" do
sign_in(Fabricate(:admin))
get "/groups/#{group.name}.json"
expect(response.status).to eq(200)
response_body = JSON.parse(response.body)
expect(response_body['group']['id']).to eq(group.id)
groups = Group::AUTO_GROUPS.keys
groups.delete(:everyone)
groups.push(group.name)
expect(response_body['extras']["visible_group_names"])
.to contain_exactly(*groups.map(&:to_s))
end
end
it 'should respond to HTML' do
group.update_attribute(:bio_cooked, 'testing group bio')
@ -228,13 +269,91 @@ describe GroupsController do
expect(response.status).to eq(200)
response_body = JSON.parse(response.body)['basic_group']
response_body = JSON.parse(response.body)['group']
expect(response_body["id"]).to eq(group.id)
end
end
end
describe "#posts" do
it "ensures the group can be seen" do
sign_in(Fabricate(:user))
group.update!(visibility_level: Group.visibility_levels[:owners])
get "/groups/#{group.name}/posts.json"
expect(response.status).to eq(403)
end
it "calls `posts_for` and responds with JSON" do
sign_in(user)
post = Fabricate(:post, user: user)
get "/groups/#{group.name}/posts.json"
expect(response.status).to eq(200)
expect(JSON.parse(response.body).first["id"]).to eq(post.id)
end
end
describe "#members" do
it "ensures the group can be seen" do
sign_in(Fabricate(:user))
group.update!(visibility_level: Group.visibility_levels[:owners])
get "/groups/#{group.name}/members.json"
expect(response.status).to eq(403)
end
it "ensures that membership can be paginated" do
5.times { group.add(Fabricate(:user)) }
usernames = group.users.map { |m| m.username }.sort
get "/groups/#{group.name}/members.json", params: { limit: 3 }
expect(response.status).to eq(200)
members = JSON.parse(response.body)["members"]
expect(members.map { |m| m['username'] }).to eq(usernames[0..2])
get "/groups/#{group.name}/members.json", params: { limit: 3, offset: 3 }
expect(response.status).to eq(200)
members = JSON.parse(response.body)["members"]
expect(members.map { |m| m['username'] }).to eq(usernames[3..5])
end
end
describe '#posts_feed' do
it 'renders RSS' do
get "/groups/#{group.name}/posts.rss"
expect(response.status).to eq(200)
expect(response.content_type).to eq('application/rss+xml')
end
end
describe '#mentions_feed' do
it 'renders RSS' do
get "/groups/#{group.name}/mentions.rss"
expect(response.status).to eq(200)
expect(response.content_type).to eq('application/rss+xml')
end
it 'fails when disabled' do
SiteSetting.enable_mentions = false
get "/groups/#{group.name}/mentions.rss"
expect(response.status).to eq(404)
end
end
describe '#mentionable' do
it "should return the right response" do
sign_in(user)

View File

@ -11,8 +11,8 @@ acceptance("Group logs", {
];
};
server.get('/groups/snorlax.json', () => { // eslint-disable-line no-undef
return response({"basic_group":{"id":41,"automatic":false,"name":"snorlax","user_count":1,"alias_level":0,"visible":true,"automatic_membership_email_domains":"","automatic_membership_retroactive":false,"primary_group":true,"title":"Team Snorlax","grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":"","flair_bg_color":"","flair_color":"","bio_raw":"","bio_cooked":null,"public":true,"is_group_user":true,"is_group_owner":true}});
server.get('/groups/snorlax', () => { // eslint-disable-line no-undef
return response({"group":{"id":41,"automatic":false,"name":"snorlax","user_count":1,"alias_level":0,"visible":true,"automatic_membership_email_domains":"","automatic_membership_retroactive":false,"primary_group":true,"title":"Team Snorlax","grant_trust_level":null,"incoming_email":null,"has_messages":false,"flair_url":"","flair_bg_color":"","flair_color":"","bio_raw":"","bio_cooked":null,"public":true,"is_group_user":true,"is_group_owner":true}});
});
// Workaround while awaiting https://github.com/tildeio/route-recognizer/issues/53

View File

@ -45,6 +45,15 @@ QUnit.test("Anonymous Viewing Group", assert => {
assert.ok(find(".nav-pills li a[title='Logs']").length === 0, 'it should not show Logs tab if user is not admin');
assert.ok(count('.group-post') > 0, "it lists stream items");
});
selectKit('.group-dropdown').expand();
andThen(() => {
assert.equal(
find('.select-kit-row').text().trim(), 'discourse',
'it displays the right row'
);
});
});
QUnit.test("User Viewing Group", assert => {

View File

@ -19,7 +19,7 @@ QUnit.test("Creating a new group", assert => {
visit("/groups");
selectKit('.groups-admin-dropdown').expand().selectRowByValue("new");
click(".groups-header-new");
fillIn("input[name='name']", '1');
andThen(() => {

View File

@ -1,6 +1,6 @@
export default {
"/groups/discourse.json":{
"basic_group":{
"/groups/discourse":{
"group":{
"id":47,
"automatic":false,
"name":"discourse",
@ -14,6 +14,9 @@ export default {
"is_group_owner":true,
"mentionable":true,
"messageable":true
},
"extras": {
"visible_group_names": ["discourse"]
}
},
"/topics/groups/discourse.json":{

View File

@ -53,7 +53,7 @@ export default function(helpers) {
this.get('/widgets/:widget_id', function(request) {
const w = _widgets.findBy('id', parseInt(request.params.widget_id));
if (w) {
return response({widget: w});
return response({ widget: w, extras: { hello: 'world' }});
} else {
return response(404);
}

View File

@ -49,14 +49,17 @@ QUnit.test('createRecord with a record as attributes returns that record from th
QUnit.test('find', assert => {
const store = createStore();
return store.find('widget', 123).then(function(w) {
assert.equal(w.get('name'), 'Trout Lure');
assert.equal(w.get('id'), 123);
assert.ok(!w.get('isNew'), 'found records are not new');
assert.equal(w.get('extras.hello'), 'world', "extra attributes are set");
// A second find by id returns the same object
store.find('widget', 123).then(function(w2) {
assert.equal(w, w2);
assert.equal(w.get('extras.hello'), 'world', "extra attributes are set");
});
});
});