UX: Tweaks to group pages.
This commit is contained in:
parent
27f06505b1
commit
52e75eaee9
|
@ -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;
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
|
@ -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}`));
|
||||
}
|
||||
}
|
||||
});
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,12 @@
|
|||
.group-nav {
|
||||
.group-dropdown {
|
||||
margin-right: 10px;
|
||||
|
||||
i {
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
float: left;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -80,3 +80,8 @@ table.group-manage-logs {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.group-username-filter {
|
||||
top: -57px;
|
||||
height: 27px;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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(() => {
|
||||
|
|
|
@ -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":{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue