From a8b5192efd43bcbf64ffe7ae44e5c5b7f3be0b51 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 17 Dec 2015 18:06:04 +1100 Subject: [PATCH] FEATURE: User page refactor Re-organise user page so it is easier to find interesting info split it into tabs - Introduce notifications and messages tabs - Stop couting stuff for the user page to speed up rendering - Suppress more information when viewing your own profile --- .../controllers/user-private-messages.js.es6 | 25 +++++ .../discourse/controllers/user.js.es6 | 31 ++--- .../mixins/viewing-action-type.js.es6 | 1 + .../javascripts/discourse/models/user.js.es6 | 13 ++- .../discourse/routes/app-route-map.js.es6 | 16 ++- ...s6 => build-private-messages-route.js.es6} | 2 +- .../routes/user-activity-replies.js.es6 | 2 +- .../discourse/routes/user-activity.js.es6 | 18 --- ...js.es6 => user-notifications-edits.js.es6} | 0 .../routes/user-notifications-index.js.es6 | 5 + ... user-notifications-likes-received.js.es6} | 2 +- ...es6 => user-notifications-mentions.js.es6} | 0 ...s6 => user-notifications-responses.js.es6} | 2 +- .../routes/user-notifications.js.es6 | 5 + .../routes/user-private-messages-group.js.es6 | 6 +- .../routes/user-private-messages-index.js.es6 | 2 +- .../routes/user-private-messages-mine.js.es6 | 2 +- .../user-private-messages-unread.js.es6 | 2 +- .../routes/user-private-messages.js.es6 | 33 +++++- .../discourse/routes/user-statistics.js.es6 | 2 + .../discourse/templates/user-topics-list.hbs | 8 -- .../discourse/templates/user/activity.hbs | 41 +++++++ .../discourse/templates/user/messages.hbs | 43 +++++++ .../templates/user/notifications-index.hbs | 34 ++++++ .../templates/user/notifications.hbs | 55 ++++----- .../discourse/templates/user/preferences.hbs | 18 +-- .../discourse/templates/user/user.hbs | 106 +++++------------- app/assets/stylesheets/common/base/user.scss | 31 +++++ .../common/components/navs.css.scss | 4 +- app/assets/stylesheets/desktop/user.scss | 13 ++- app/controllers/users_controller.rb | 7 +- app/models/user.rb | 4 - app/serializers/basic_group_serializer.rb | 3 +- app/serializers/user_serializer.rb | 10 +- config/locales/client.en.yml | 2 +- config/routes.rb | 1 + ...151219045559_add_has_messages_to_groups.rb | 15 +++ lib/topic_creator.rb | 1 + 38 files changed, 371 insertions(+), 194 deletions(-) create mode 100644 app/assets/javascripts/discourse/controllers/user-private-messages.js.es6 rename app/assets/javascripts/discourse/routes/{build-user-topic-list-route.js.es6 => build-private-messages-route.js.es6} (92%) rename app/assets/javascripts/discourse/routes/{user-activity-edits.js.es6 => user-notifications-edits.js.es6} (100%) create mode 100644 app/assets/javascripts/discourse/routes/user-notifications-index.js.es6 rename app/assets/javascripts/discourse/routes/{user-activity-likes-received.js.es6 => user-notifications-likes-received.js.es6} (77%) rename app/assets/javascripts/discourse/routes/{user-activity-mentions.js.es6 => user-notifications-mentions.js.es6} (100%) rename app/assets/javascripts/discourse/routes/{user-activity-posts.js.es6 => user-notifications-responses.js.es6} (80%) create mode 100644 app/assets/javascripts/discourse/routes/user-statistics.js.es6 create mode 100644 app/assets/javascripts/discourse/templates/user/messages.hbs create mode 100644 app/assets/javascripts/discourse/templates/user/notifications-index.hbs create mode 100644 db/migrate/20151219045559_add_has_messages_to_groups.rb diff --git a/app/assets/javascripts/discourse/controllers/user-private-messages.js.es6 b/app/assets/javascripts/discourse/controllers/user-private-messages.js.es6 new file mode 100644 index 00000000000..7b7664e7574 --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/user-private-messages.js.es6 @@ -0,0 +1,25 @@ +import computed from 'ember-addons/ember-computed-decorators'; + +export default Ember.Controller.extend({ + + pmView: false, + + privateMessagesActive: Em.computed.equal('pmView', 'index'), + privateMessagesMineActive: Em.computed.equal('pmView', 'mine'), + privateMessagesUnreadActive: Em.computed.equal('pmView', 'unread'), + isGroup: Em.computed.equal('pmView', 'groups'), + + + @computed('model.groups', 'groupFilter', 'pmView') + groupPMStats(groups, filter, pmView) { + if (groups) { + return groups.filter(group => group.has_messages) + .map(g => { + return { + name: g.name, + active: (g.name === filter && pmView === "groups") + }; + }); + } + } +}); diff --git a/app/assets/javascripts/discourse/controllers/user.js.es6 b/app/assets/javascripts/discourse/controllers/user.js.es6 index 49889e5c023..2985920618e 100644 --- a/app/assets/javascripts/discourse/controllers/user.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user.js.es6 @@ -6,7 +6,6 @@ import User from 'discourse/models/user'; export default Ember.Controller.extend(CanCheckEmails, { indexStream: false, - pmView: false, userActionType: null, needs: ['user-notifications', 'user-topics-list'], @@ -28,11 +27,14 @@ export default Ember.Controller.extend(CanCheckEmails, { }, @computed('viewingSelf', 'currentUser.admin') - canSeePrivateMessages(viewingSelf, isAdmin) { + showPrivateMessages(viewingSelf, isAdmin) { return this.siteSettings.enable_private_messages && (viewingSelf || isAdmin); }, - canSeeNotificationHistory: Em.computed.alias('canSeePrivateMessages'), + @computed('viewingSelf', 'currentUser.admin') + canSeeNotificationHistory(viewingSelf, isAdmin) { + return viewingSelf || isAdmin; + }, @computed("content.badge_count") showBadges(badgeCount) { @@ -45,6 +47,12 @@ export default Ember.Controller.extend(CanCheckEmails, { (userActionType === UserAction.TYPES.messages_received); }, + @computed("indexStream", "userActionType") + showActionTypeSummary(indexStream,userActionType, showPMs) { + return (indexStream || userActionType) && !showPMs; + }, + + @computed() canInviteToForum() { return User.currentProp('can_invite_to_forum'); @@ -64,23 +72,6 @@ export default Ember.Controller.extend(CanCheckEmails, { } }, - privateMessagesActive: Em.computed.equal('pmView', 'index'), - privateMessagesMineActive: Em.computed.equal('pmView', 'mine'), - privateMessagesUnreadActive: Em.computed.equal('pmView', 'unread'), - - @computed('model.private_messages_stats.groups', 'groupFilter', 'pmView') - groupPMStats(stats,filter,pmView) { - if (stats) { - return stats.map(g => { - return { - name: g.name, - count: g.count, - active: (g.name === filter && pmView === 'groups') - }; - }); - } - }, - actions: { expandProfile() { this.set('forceExpand', true); diff --git a/app/assets/javascripts/discourse/mixins/viewing-action-type.js.es6 b/app/assets/javascripts/discourse/mixins/viewing-action-type.js.es6 index 35084dcf1fa..1da5529cd13 100644 --- a/app/assets/javascripts/discourse/mixins/viewing-action-type.js.es6 +++ b/app/assets/javascripts/discourse/mixins/viewing-action-type.js.es6 @@ -3,4 +3,5 @@ export default { this.controllerFor('user').set('userActionType', userActionType); this.controllerFor('user-activity').set('userActionType', userActionType); } + }; diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6 index 97c611ab89e..2dbeea5763c 100644 --- a/app/assets/javascripts/discourse/models/user.js.es6 +++ b/app/assets/javascripts/discourse/models/user.js.es6 @@ -199,6 +199,15 @@ const User = RestModel.extend({ ua.action_type === UserAction.TYPES.topics; }, + @computed("groups.@each") + displayGroups() { + const groups = this.get('groups'); + const filtered = groups.filter(group => { + return !group.automatic || group.name === "moderators"; + }); + return filtered.length === 0 ? null : filtered; + }, + // The user's stat count, excluding PMs. @computed("statsExcludingPms.@each.count") statsCountNonPM() { @@ -233,8 +242,8 @@ const User = RestModel.extend({ })); } - if (!Em.isEmpty(json.user.custom_groups)) { - json.user.custom_groups = json.user.custom_groups.map(g => Group.create(g)); + if (!Em.isEmpty(json.user.groups)) { + json.user.groups = json.user.groups.map(g => Group.create(g)); } if (json.user.invited_by) { 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 d67e0a78660..39bee49123f 100644 --- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 +++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 @@ -58,13 +58,20 @@ export default function() { this.resource('users'); this.resource('user', { path: '/users/:username' }, function() { this.resource('userActivity', { path: '/activity' }, function() { - _.map(Discourse.UserAction.TYPES, (id, userAction) => { - this.route(userAction, { path: userAction.replace('_', '-') }); - }); + this.route('topics'); + this.route('replies'); + this.route('likesGiven', {path: 'likes-given'}); + this.route('bookmarks'); + }); + + this.resource('userNotifications', {path: '/notifications'}, function(){ + this.route('responses'); + this.route('likesReceived', { path: 'likes-received'}); + this.route('mentions'); + this.route('edits'); }); this.route('badges'); - this.route('notifications'); this.route('flaggedPosts', { path: '/flagged-posts' }); this.route('deletedPosts', { path: '/deleted-posts' }); @@ -85,6 +92,7 @@ export default function() { this.resource('userInvited', { path: '/invited' }, function() { this.route('show', { path: '/:filter' }); }); + }); this.route('signup', {path: '/signup'}); diff --git a/app/assets/javascripts/discourse/routes/build-user-topic-list-route.js.es6 b/app/assets/javascripts/discourse/routes/build-private-messages-route.js.es6 similarity index 92% rename from app/assets/javascripts/discourse/routes/build-user-topic-list-route.js.es6 rename to app/assets/javascripts/discourse/routes/build-private-messages-route.js.es6 index 5704cd96dbf..cef72ed152d 100644 --- a/app/assets/javascripts/discourse/routes/build-user-topic-list-route.js.es6 +++ b/app/assets/javascripts/discourse/routes/build-private-messages-route.js.es6 @@ -24,7 +24,7 @@ export default (viewName, path) => { showParticipants: true }); - this.controllerFor("user").set("pmView", viewName); + this.controllerFor("userPrivateMessages").set("pmView", viewName); this.searchService.set('contextType', 'private_messages'); }, diff --git a/app/assets/javascripts/discourse/routes/user-activity-replies.js.es6 b/app/assets/javascripts/discourse/routes/user-activity-replies.js.es6 index 28e11587f4b..62607c9a164 100644 --- a/app/assets/javascripts/discourse/routes/user-activity-replies.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-activity-replies.js.es6 @@ -2,5 +2,5 @@ import UserActivityStreamRoute from "discourse/routes/user-activity-stream"; import UserAction from "discourse/models/user-action"; export default UserActivityStreamRoute.extend({ - userActionType: UserAction.TYPES["replies"] + userActionType: UserAction.TYPES["posts"] }); diff --git a/app/assets/javascripts/discourse/routes/user-activity.js.es6 b/app/assets/javascripts/discourse/routes/user-activity.js.es6 index 5f217303260..546e135cbef 100644 --- a/app/assets/javascripts/discourse/routes/user-activity.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-activity.js.es6 @@ -1,5 +1,3 @@ -import Draft from 'discourse/models/draft'; - export default Discourse.Route.extend({ model() { return this.modelFor("user"); @@ -7,21 +5,5 @@ export default Discourse.Route.extend({ setupController(controller, user) { this.controllerFor("user-activity").set("model", user); - - // Bring up a draft - const composerController = this.controllerFor("composer"); - controller.set("model", user); - if (this.currentUser) { - Draft.get("new_private_message").then(function(data) { - if (data.draft) { - composerController.open({ - draft: data.draft, - draftKey: "new_private_message", - ignoreIfChanged: true, - draftSequence: data.draft_sequence - }); - } - }); - } } }); diff --git a/app/assets/javascripts/discourse/routes/user-activity-edits.js.es6 b/app/assets/javascripts/discourse/routes/user-notifications-edits.js.es6 similarity index 100% rename from app/assets/javascripts/discourse/routes/user-activity-edits.js.es6 rename to app/assets/javascripts/discourse/routes/user-notifications-edits.js.es6 diff --git a/app/assets/javascripts/discourse/routes/user-notifications-index.js.es6 b/app/assets/javascripts/discourse/routes/user-notifications-index.js.es6 new file mode 100644 index 00000000000..7fb891d6bb0 --- /dev/null +++ b/app/assets/javascripts/discourse/routes/user-notifications-index.js.es6 @@ -0,0 +1,5 @@ +export default Discourse.Route.extend({ + renderTemplate() { + this.render("user/notifications-index"); + } +}); diff --git a/app/assets/javascripts/discourse/routes/user-activity-likes-received.js.es6 b/app/assets/javascripts/discourse/routes/user-notifications-likes-received.js.es6 similarity index 77% rename from app/assets/javascripts/discourse/routes/user-activity-likes-received.js.es6 rename to app/assets/javascripts/discourse/routes/user-notifications-likes-received.js.es6 index a533005648b..7206e7705d7 100644 --- a/app/assets/javascripts/discourse/routes/user-activity-likes-received.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-notifications-likes-received.js.es6 @@ -2,5 +2,5 @@ import UserActivityStreamRoute from "discourse/routes/user-activity-stream"; import UserAction from "discourse/models/user-action"; export default UserActivityStreamRoute.extend({ - userActionType: UserAction.TYPES["likes_received"] + userActionType: UserAction.TYPES["likes_received"], }); diff --git a/app/assets/javascripts/discourse/routes/user-activity-mentions.js.es6 b/app/assets/javascripts/discourse/routes/user-notifications-mentions.js.es6 similarity index 100% rename from app/assets/javascripts/discourse/routes/user-activity-mentions.js.es6 rename to app/assets/javascripts/discourse/routes/user-notifications-mentions.js.es6 diff --git a/app/assets/javascripts/discourse/routes/user-activity-posts.js.es6 b/app/assets/javascripts/discourse/routes/user-notifications-responses.js.es6 similarity index 80% rename from app/assets/javascripts/discourse/routes/user-activity-posts.js.es6 rename to app/assets/javascripts/discourse/routes/user-notifications-responses.js.es6 index 62607c9a164..28e11587f4b 100644 --- a/app/assets/javascripts/discourse/routes/user-activity-posts.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-notifications-responses.js.es6 @@ -2,5 +2,5 @@ import UserActivityStreamRoute from "discourse/routes/user-activity-stream"; import UserAction from "discourse/models/user-action"; export default UserActivityStreamRoute.extend({ - userActionType: UserAction.TYPES["posts"] + userActionType: UserAction.TYPES["replies"] }); diff --git a/app/assets/javascripts/discourse/routes/user-notifications.js.es6 b/app/assets/javascripts/discourse/routes/user-notifications.js.es6 index 7c2384db01b..cfb91acdb7d 100644 --- a/app/assets/javascripts/discourse/routes/user-notifications.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-notifications.js.es6 @@ -1,6 +1,11 @@ import ViewingActionType from "discourse/mixins/viewing-action-type"; export default Discourse.Route.extend(ViewingActionType, { + + renderTemplate() { + this.render('user/notifications'); + }, + actions: { didTransition() { this.controllerFor("user-notifications")._showFooter(); diff --git a/app/assets/javascripts/discourse/routes/user-private-messages-group.js.es6 b/app/assets/javascripts/discourse/routes/user-private-messages-group.js.es6 index 173641b1db7..7e962ee8646 100644 --- a/app/assets/javascripts/discourse/routes/user-private-messages-group.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-private-messages-group.js.es6 @@ -1,5 +1,5 @@ import Group from 'discourse/models/group'; -import createPMRoute from "discourse/routes/build-user-topic-list-route"; +import createPMRoute from "discourse/routes/build-private-messages-route"; export default createPMRoute('groups', 'private-messages-groups').extend({ model(params) { @@ -13,13 +13,13 @@ export default createPMRoute('groups', 'private-messages-groups').extend({ const groupName = _.last(model.get("filter").split('/')); Group.findAll().then(groups => { const group = _.first(groups.filterBy("name", groupName)); - this.controllerFor("user-topics-list").set("group", group); + this.controllerFor("user-private-messages").set("group", group); }); }, setupController(controller, model) { this._super.apply(this, arguments); const group = _.last(model.get("filter").split('/')); - this.controllerFor("user").set("groupFilter", group); + this.controllerFor("userPrivateMessages").set("groupFilter", group); } }); diff --git a/app/assets/javascripts/discourse/routes/user-private-messages-index.js.es6 b/app/assets/javascripts/discourse/routes/user-private-messages-index.js.es6 index 5265bfb6703..d1e2bf3c275 100644 --- a/app/assets/javascripts/discourse/routes/user-private-messages-index.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-private-messages-index.js.es6 @@ -1,3 +1,3 @@ -import createPMRoute from "discourse/routes/build-user-topic-list-route"; +import createPMRoute from "discourse/routes/build-private-messages-route"; export default createPMRoute('index', 'private-messages'); diff --git a/app/assets/javascripts/discourse/routes/user-private-messages-mine.js.es6 b/app/assets/javascripts/discourse/routes/user-private-messages-mine.js.es6 index 47db6999246..b2cf029e5d4 100644 --- a/app/assets/javascripts/discourse/routes/user-private-messages-mine.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-private-messages-mine.js.es6 @@ -1,3 +1,3 @@ -import createPMRoute from "discourse/routes/build-user-topic-list-route"; +import createPMRoute from "discourse/routes/build-private-messages-route"; export default createPMRoute('mine', 'private-messages-sent'); diff --git a/app/assets/javascripts/discourse/routes/user-private-messages-unread.js.es6 b/app/assets/javascripts/discourse/routes/user-private-messages-unread.js.es6 index 19e2a5167d0..062ef732894 100644 --- a/app/assets/javascripts/discourse/routes/user-private-messages-unread.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-private-messages-unread.js.es6 @@ -1,3 +1,3 @@ -import createPMRoute from "discourse/routes/build-user-topic-list-route"; +import createPMRoute from "discourse/routes/build-private-messages-route"; export default createPMRoute('unread', 'private-messages-unread'); diff --git a/app/assets/javascripts/discourse/routes/user-private-messages.js.es6 b/app/assets/javascripts/discourse/routes/user-private-messages.js.es6 index 328a304ca59..b1074f80ae1 100644 --- a/app/assets/javascripts/discourse/routes/user-private-messages.js.es6 +++ b/app/assets/javascripts/discourse/routes/user-private-messages.js.es6 @@ -1,6 +1,35 @@ -import UserActivityRoute from 'discourse/routes/user-activity'; +import Draft from 'discourse/models/draft'; + +export default Discourse.Route.extend({ + + renderTemplate() { + this.render('user/messages'); + }, + + + model() { + return this.modelFor("user"); + }, + + setupController(controller, user) { + this._super(); + // Bring up a draft + const composerController = this.controllerFor("composer"); + controller.set("model", user); + if (this.currentUser) { + Draft.get("new_private_message").then(function(data) { + if (data.draft) { + composerController.open({ + draft: data.draft, + draftKey: "new_private_message", + ignoreIfChanged: true, + draftSequence: data.draft_sequence + }); + } + }); + } + }, -export default UserActivityRoute.extend({ actions: { willTransition: function() { this._super(); diff --git a/app/assets/javascripts/discourse/routes/user-statistics.js.es6 b/app/assets/javascripts/discourse/routes/user-statistics.js.es6 new file mode 100644 index 00000000000..610a1048990 --- /dev/null +++ b/app/assets/javascripts/discourse/routes/user-statistics.js.es6 @@ -0,0 +1,2 @@ +export default Discourse.Route.extend({ +}); diff --git a/app/assets/javascripts/discourse/templates/user-topics-list.hbs b/app/assets/javascripts/discourse/templates/user-topics-list.hbs index a2aae2de1b3..c9462573047 100644 --- a/app/assets/javascripts/discourse/templates/user-topics-list.hbs +++ b/app/assets/javascripts/discourse/templates/user-topics-list.hbs @@ -1,11 +1,3 @@ -
- {{#if group}} - {{group-notifications-button group=group}} - {{/if}} - {{#if showNewPM}} - {{d-button class="btn-primary pull-right new-private-message" action="composePrivateMessage" icon="envelope" label="user.new_private_message"}} - {{/if}} -
{{basic-topic-list topicList=model hideCategory=hideCategory diff --git a/app/assets/javascripts/discourse/templates/user/activity.hbs b/app/assets/javascripts/discourse/templates/user/activity.hbs index c24cd68950a..2c3d03ab526 100644 --- a/app/assets/javascripts/discourse/templates/user/activity.hbs +++ b/app/assets/javascripts/discourse/templates/user/activity.hbs @@ -1 +1,42 @@ +
+ + + {{#if viewingSelf}} +
+ {{d-button action="exportUserArchive" label="user.download_archive" icon="download"}} +
+ {{/if}} + +
+ +
{{outlet}} +
+ diff --git a/app/assets/javascripts/discourse/templates/user/messages.hbs b/app/assets/javascripts/discourse/templates/user/messages.hbs new file mode 100644 index 00000000000..5e404cb1728 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/user/messages.hbs @@ -0,0 +1,43 @@ +
+ + + {{d-button class="btn-primary new-private-message" action="composePrivateMessage" icon="envelope" label="user.new_private_message"}} +
+ +
+ +{{#if isGroup}} +
+ {{group-notifications-button group=group}} +
+{{/if}} + +{{outlet}} +
diff --git a/app/assets/javascripts/discourse/templates/user/notifications-index.hbs b/app/assets/javascripts/discourse/templates/user/notifications-index.hbs new file mode 100644 index 00000000000..9ca0b0b99b1 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/user/notifications-index.hbs @@ -0,0 +1,34 @@ +{{#if model.error}} +
+ {{#if model.forbidden}} + {{i18n 'errors.reasons.forbidden'}} + {{else}} + {{i18n 'errors.desc.unknown'}} + {{/if}} +
+{{/if}} + +{{#if showDismissButton}} +
+ +
+{{/if}} + +{{#each n in model}} +
+ {{notification-item notification=n}} + + {{format-date n.created_at leaveAgo="true"}} + +
+{{/each}} + +{{#conditional-loading-spinner condition=loading}} + {{#unless model.canLoadMore}} + {{#if showDismissButton}} +
+ +
+ {{/if}} + {{/unless}} +{{/conditional-loading-spinner}} diff --git a/app/assets/javascripts/discourse/templates/user/notifications.hbs b/app/assets/javascripts/discourse/templates/user/notifications.hbs index 9ca0b0b99b1..ac8c6353e55 100644 --- a/app/assets/javascripts/discourse/templates/user/notifications.hbs +++ b/app/assets/javascripts/discourse/templates/user/notifications.hbs @@ -1,34 +1,25 @@ -{{#if model.error}} -
- {{#if model.forbidden}} - {{i18n 'errors.reasons.forbidden'}} - {{else}} - {{i18n 'errors.desc.unknown'}} - {{/if}} -
-{{/if}} -{{#if showDismissButton}} -
- -
-{{/if}} +
+ +
-{{#each n in model}} -
- {{notification-item notification=n}} - - {{format-date n.created_at leaveAgo="true"}} - -
-{{/each}} - -{{#conditional-loading-spinner condition=loading}} - {{#unless model.canLoadMore}} - {{#if showDismissButton}} -
- -
- {{/if}} - {{/unless}} -{{/conditional-loading-spinner}} +
+ {{outlet}} +
diff --git a/app/assets/javascripts/discourse/templates/user/preferences.hbs b/app/assets/javascripts/discourse/templates/user/preferences.hbs index 643757fc791..c18a9afe5fc 100644 --- a/app/assets/javascripts/discourse/templates/user/preferences.hbs +++ b/app/assets/javascripts/discourse/templates/user/preferences.hbs @@ -237,15 +237,8 @@ {{category-group categories=model.mutedCategories blacklist=selectedCategories}}
{{i18n 'user.muted_categories_instructions'}}
- - -
- - {{#if siteSettings.automatically_unpin_topics}} - {{preference-checkbox labelKey="user.automatically_unpin_topics" checked=model.automatically_unpin_topics}} - {{/if}} - @@ -258,6 +251,13 @@
{{i18n 'user.muted_users_instructions'}}
+ {{#if siteSettings.automatically_unpin_topics}} +
+ + {{preference-checkbox labelKey="user.automatically_unpin_topics" checked=model.automatically_unpin_topics}} +
+ {{/if}} + {{plugin-outlet "user-custom-controls"}}
diff --git a/app/assets/javascripts/discourse/templates/user/user.hbs b/app/assets/javascripts/discourse/templates/user/user.hbs index ae0d50b06ab..db367894528 100644 --- a/app/assets/javascripts/discourse/templates/user/user.hbs +++ b/app/assets/javascripts/discourse/templates/user/user.hbs @@ -1,6 +1,7 @@
+ {{#unless collapsedInfo}}
{{#if model.number_of_flags_given}}
{{model.number_of_flags_given}} {{i18n 'user.staff_counters.flags_given'}}
@@ -26,6 +27,8 @@
{{model.number_of_warnings}} {{i18n 'user.staff_counters.warnings_received'}}
{{/if}}
+ {{/unless}} +
@@ -40,18 +43,9 @@ {{/if}} - {{#if viewingSelf}} -
  • {{fa-icon "sign-out"}}{{i18n 'user.log_out'}}
  • - {{/if}} {{#if currentUser.staff}}
  • {{fa-icon "wrench"}}{{i18n 'admin.user.show_admin_profile'}}
  • {{/if}} - {{#if model.can_edit}} -
  • {{#link-to 'preferences' class="btn"}}{{fa-icon "cog"}}{{i18n 'user.preferences'}}{{/link-to}}
  • - {{/if}} - {{#if canInviteToForum}} -
  • {{#link-to 'userInvited' class="btn"}}{{fa-icon "user-plus"}}{{i18n 'user.invited.title'}}{{/link-to}}
  • - {{/if}} {{#if collapsedInfo}} {{#if viewingSelf}}
  • {{fa-icon "angle-double-down"}}{{i18n 'user.expand_profile'}}
  • @@ -109,6 +103,8 @@
    + + {{#unless collapsedInfo}}
    {{#if model.created_at}} @@ -135,10 +131,10 @@ {{/if}} {{/if}} - {{#if model.custom_groups}} -
    {{i18n 'groups.title' count=model.custom_groups.length}}
    + {{#if model.displayGroups}} +
    {{i18n 'groups.title' count=model.displayGroups.length}}
    - {{#each group in model.custom_groups}} + {{#each group in model.displayGroups}} {{#link-to 'group' group class="group-link"}}{{group.name}}{{/link-to}} {{/each}}
    @@ -149,76 +145,34 @@
    {{plugin-outlet "user-profile-secondary"}}
    + {{/unless}}
    -
    -
    + {{#if canInviteToForum}} +
  • {{#link-to 'userInvited'}}{{fa-icon "user-plus"}}{{i18n 'user.invited.title'}}{{/link-to}}
  • + {{/if}} + {{#if showBadges}} +
  • {{#link-to 'user.badges'}}{{fa-icon "certificate"}}{{i18n 'badges.title'}}{{/link-to}}
  • + {{/if}} + {{#if model.can_edit}} +
  • {{#link-to 'preferences'}}{{fa-icon "cog"}}{{i18n 'user.preferences'}}{{/link-to}}
  • + {{/if}} + -
    - {{outlet}} -
    + {{outlet}}
    diff --git a/app/assets/stylesheets/common/base/user.scss b/app/assets/stylesheets/common/base/user.scss index 3eeb787e9f2..d532078bfaa 100644 --- a/app/assets/stylesheets/common/base/user.scss +++ b/app/assets/stylesheets/common/base/user.scss @@ -131,3 +131,34 @@ } } + +.user-nav { + width: 100%; + padding: 0; + margin: 0; + li { + padding: 0; + a { + color: dark-light-choose(scale-color($primary, $lightness: 40%), scale-color($secondary, $lightness: 40%)); + padding: 5px; + min-width: 90px; + display: inline-block; + text-align: center; + border-bottom: 3px solid transparent; + } + a.active, a:hover { + color: $primary; + border-bottom: 3px solid dark-light-choose(scale-color($primary, $lightness: 20%), scale-color($secondary, $lightness: 20%)); + } + display: inline-block; + text-decoration: none; + margin: 5px 0px; + .fa { + margin-right: 5px; + } + .fa.fa-comment { + margin-right: 2px; + } + } +} + diff --git a/app/assets/stylesheets/common/components/navs.css.scss b/app/assets/stylesheets/common/components/navs.css.scss index d29d05a3d02..c10d684305c 100644 --- a/app/assets/stylesheets/common/components/navs.css.scss +++ b/app/assets/stylesheets/common/components/navs.css.scss @@ -65,13 +65,13 @@ color: $primary; } } - .active > a, + .active > a, & li > a.active { color: $secondary; background-color: $quaternary; } - .active > a::after, + .active > a::after, & li > a.active::after { left: 90%; top: 33%; diff --git a/app/assets/stylesheets/desktop/user.scss b/app/assets/stylesheets/desktop/user.scss index 1cfdfab7ef8..1ae8d69e696 100644 --- a/app/assets/stylesheets/desktop/user.scss +++ b/app/assets/stylesheets/desktop/user.scss @@ -231,7 +231,6 @@ background-position: center center; background-size: cover; width: 100%; - margin-bottom: 10px; overflow: hidden; &.group { @@ -642,3 +641,15 @@ margin-top: 0; } } + + +.user-right .group-notification-menu { + float: right; + margin-bottom: 5px; +} +.user-right.messages .topic-list { + thead, th.views, td.views { + display: none; + } +} + diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 213442d11d2..3e510bb25d1 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -33,9 +33,10 @@ class UsersController < ApplicationController @user = fetch_user_from_params(include_inactive: current_user.try(:staff?)) user_serializer = UserSerializer.new(@user, scope: guardian, root: 'user') - if params[:stats].to_s == "false" - user_serializer.omit_stats = true - end + + # TODO remove this options from serializer + user_serializer.omit_stats = true + topic_id = params[:include_post_count_for].to_i if topic_id != 0 user_serializer.topic_post_count = {topic_id => Post.where(topic_id: topic_id, user_id: @user.id).count } diff --git a/app/models/user.rb b/app/models/user.rb index 1a3dbd47e49..a9784dd6f9b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -141,10 +141,6 @@ class User < ActiveRecord::Base SiteSetting.min_username_length.to_i..SiteSetting.max_username_length.to_i end - def custom_groups - groups.where(automatic: false, visible: true) - end - def self.username_available?(username) lower = username.downcase User.where(username_lower: lower).blank? && !SiteSetting.reserved_usernames.split("|").include?(username) diff --git a/app/serializers/basic_group_serializer.rb b/app/serializers/basic_group_serializer.rb index 925ac236504..d9a50ef124b 100644 --- a/app/serializers/basic_group_serializer.rb +++ b/app/serializers/basic_group_serializer.rb @@ -11,7 +11,8 @@ class BasicGroupSerializer < ApplicationSerializer :title, :grant_trust_level, :incoming_email, - :notification_level + :notification_level, + :has_messages def include_incoming_email? scope.is_staff? diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb index 476601b0fbd..06abd889a1e 100644 --- a/app/serializers/user_serializer.rb +++ b/app/serializers/user_serializer.rb @@ -70,7 +70,7 @@ class UserSerializer < BasicUserSerializer :automatically_unpin_topics has_one :invited_by, embed: :object, serializer: BasicUserSerializer - has_many :custom_groups, embed: :object, serializer: BasicGroupSerializer + has_many :groups, embed: :object, serializer: BasicGroupSerializer has_many :featured_user_badges, embed: :ids, serializer: UserBadgeSerializer, root: :user_badges has_one :card_badge, embed: :object, serializer: BadgeSerializer @@ -118,6 +118,14 @@ class UserSerializer < BasicUserSerializer ### ATTRIBUTES ### + def groups + if scope.is_admin? || object.id == scope.user.try(:id) + object.groups + else + object.groups.where(visible: true) + end + end + def include_email? object.id && object.id == scope.user.try(:id) end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index b44e809b708..0eb1e2fa7d6 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -378,7 +378,6 @@ en: "6": "Responses" "7": "Mentions" "9": "Quotes" - "10": "Starred" "11": "Edits" "12": "Sent Items" "13": "Inbox" @@ -448,6 +447,7 @@ en: invited_by: "Invited By" trust_level: "Trust Level" notifications: "Notifications" + statistics: "Stats" desktop_notifications: label: "Desktop Notifications" not_supported: "Notifications are not supported on this browser. Sorry." diff --git a/config/routes.rb b/config/routes.rb index c74d7740407..3f7f8c8f2d6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -305,6 +305,7 @@ Discourse::Application.routes.draw do get "users/:username/activity/:filter" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT} get "users/:username/badges" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT} get "users/:username/notifications" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT} + get "users/:username/notifications/:filter" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT} get "users/:username/pending" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT} delete "users/:username" => "users#destroy", constraints: {username: USERNAME_ROUTE_FORMAT} # The external_id constraint is to allow periods to be used in the value without becoming part of the format. ie: foo.bar.json diff --git a/db/migrate/20151219045559_add_has_messages_to_groups.rb b/db/migrate/20151219045559_add_has_messages_to_groups.rb new file mode 100644 index 00000000000..e4f4fcbefaa --- /dev/null +++ b/db/migrate/20151219045559_add_has_messages_to_groups.rb @@ -0,0 +1,15 @@ +class AddHasMessagesToGroups < ActiveRecord::Migration + def up + add_column :groups, :has_messages, :boolean, default: false, null: false + + execute <