mirror of
https://github.com/discourse/discourse.git
synced 2025-05-26 08:51:52 +08:00
FEATURE: Quick access panels in user menu (#8073)
* Extract QuickAccessPanel from UserNotifications. * FEATURE: Quick access panels in user menu. This feature adds quick access panels for bookmarks and personal messages. It allows uses to browse recent items directly in the user menu, without being redirected to the full pages. * REFACTOR: Use QuickAccessItem for messages. Reusing `DefaultNotificationItem` feels nice but it actually requires a lot of extra work that is not needed for a quick access item. Also, `DefaultNotificationItem` shows an incorrect tooptip ("unread private message"), and it is not trivial to remove / override that. * Use a plain JS object instead. An Ember object was required when `DefaultNotificationItem` was used. * Prefix instead suffix `_` for private helpers. * Set to null instead of deleting object keys. JavaScript engines can optimize object property access based on the object’s shape. https://mathiasbynens.be/notes/shapes-ics * Change trivial try/catch to one-liners. * Return the promise in case needs to be waited on. * Refactor showAll to a link with href * Store `emptyStatePlaceholderItemText` in state. * Store items in Session singleton instead. We can drop `staleItems` (and `findStaleItems`) altogether. Because `(old) items === staleItems` when switching back to a quick access panel. * Add `limit` parameter to the `user_actions` API. * Explicitly import Session instead.
This commit is contained in:
79
test/javascripts/fixtures/private_messages_fixtures.js.es6
Normal file
79
test/javascripts/fixtures/private_messages_fixtures.js.es6
Normal file
@ -0,0 +1,79 @@
|
||||
/*jshint maxlen:10000000 */
|
||||
export default {
|
||||
"/topics/private-messages/eviltrout.json": {
|
||||
users: [
|
||||
{
|
||||
id: 19,
|
||||
username: "eviltrout",
|
||||
name: null,
|
||||
avatar_template: "/letter_avatar_proxy/v4/letter/t/f9ae1b/{size}.png"
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
username: "mixtape",
|
||||
name: null,
|
||||
avatar_template: "/letter_avatar_proxy/v4/letter/m/34f0e0/{size}.png"
|
||||
}
|
||||
],
|
||||
primary_groups: [],
|
||||
topic_list: {
|
||||
can_create_topic: true,
|
||||
draft: null,
|
||||
draft_key: "new_topic",
|
||||
draft_sequence: 33,
|
||||
per_page: 30,
|
||||
topics: [
|
||||
{
|
||||
id: 174,
|
||||
title: "BUG: Can not render emoji properly :/",
|
||||
fancy_title: "BUG: Can not render emoji properly :confused:",
|
||||
slug: "bug-can-not-render-emoji-properly",
|
||||
posts_count: 1,
|
||||
reply_count: 0,
|
||||
highest_post_number: 2,
|
||||
image_url: null,
|
||||
created_at: "2019-07-26T01:29:24.008Z",
|
||||
last_posted_at: "2019-07-26T01:29:24.177Z",
|
||||
bumped: true,
|
||||
bumped_at: "2019-07-26T01:29:24.177Z",
|
||||
unseen: false,
|
||||
last_read_post_number: 2,
|
||||
unread: 0,
|
||||
new_posts: 0,
|
||||
pinned: false,
|
||||
unpinned: null,
|
||||
visible: true,
|
||||
closed: false,
|
||||
archived: false,
|
||||
notification_level: 3,
|
||||
bookmarked: false,
|
||||
liked: false,
|
||||
views: 5,
|
||||
like_count: 0,
|
||||
has_summary: false,
|
||||
archetype: "private_message",
|
||||
last_poster_username: "mixtape",
|
||||
category_id: null,
|
||||
pinned_globally: false,
|
||||
featured_link: null,
|
||||
posters: [
|
||||
{
|
||||
extras: "latest single",
|
||||
description: "Original Poster, Most Recent Poster",
|
||||
user_id: 13,
|
||||
primary_group_id: null
|
||||
}
|
||||
],
|
||||
participants: [
|
||||
{
|
||||
extras: "latest",
|
||||
description: null,
|
||||
user_id: 13,
|
||||
primary_group_id: null
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
@ -302,7 +302,7 @@ export default {
|
||||
acting_username: "Abhishek_Gupta",
|
||||
acting_name: "Abhishek Gupta",
|
||||
acting_user_id: 8021,
|
||||
title: "How to check the user level via ajax?",
|
||||
title: "How to check the user level via ajax? :/",
|
||||
deleted: false,
|
||||
hidden: false,
|
||||
moderator_action: false,
|
||||
|
@ -139,7 +139,7 @@ export default function() {
|
||||
});
|
||||
|
||||
this.get("/topics/private-messages/eviltrout.json", () => {
|
||||
return response({ topic_list: { topics: [] } });
|
||||
return response(fixturesByUrl["/topics/private-messages/eviltrout.json"]);
|
||||
});
|
||||
|
||||
this.get("/topics/feature_stats.json", () => {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import Store from "discourse/models/store";
|
||||
import RestAdapter from "discourse/adapters/rest";
|
||||
import KeyValueStore from "discourse/lib/key-value-store";
|
||||
import TopicListAdapter from "discourse/adapters/topic-list";
|
||||
import TopicTrackingState from "discourse/models/topic-tracking-state";
|
||||
import { buildResolver } from "discourse-common/resolver";
|
||||
|
||||
@ -16,6 +17,11 @@ export default function() {
|
||||
}
|
||||
return this._restAdapter;
|
||||
}
|
||||
if (type === "adapter:topicList") {
|
||||
this._topicListAdapter =
|
||||
this._topicListAdapter || TopicListAdapter.create({ owner: this });
|
||||
return this._topicListAdapter;
|
||||
}
|
||||
if (type === "key-value-store:main") {
|
||||
this._kvs = this._kvs || new KeyValueStore();
|
||||
return this._kvs;
|
||||
|
@ -1,3 +1,4 @@
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
import { moduleForWidget, widgetTest } from "helpers/widget-test";
|
||||
|
||||
moduleForWidget("user-menu");
|
||||
@ -8,9 +9,9 @@ widgetTest("basics", {
|
||||
test(assert) {
|
||||
assert.ok(find(".user-menu").length);
|
||||
assert.ok(find(".user-activity-link").length);
|
||||
assert.ok(find(".user-notifications-link").length);
|
||||
assert.ok(find(".user-bookmarks-link").length);
|
||||
assert.ok(find(".user-preferences-link").length);
|
||||
assert.ok(find(".notifications").length);
|
||||
assert.ok(find(".quick-access-panel").length);
|
||||
assert.ok(find(".dismiss-link").length);
|
||||
}
|
||||
});
|
||||
@ -18,8 +19,8 @@ widgetTest("basics", {
|
||||
widgetTest("notifications", {
|
||||
template: '{{mount-widget widget="user-menu"}}',
|
||||
|
||||
test(assert) {
|
||||
const $links = find(".notifications li a");
|
||||
async test(assert) {
|
||||
const $links = find(".quick-access-panel li a");
|
||||
|
||||
assert.equal($links.length, 5);
|
||||
assert.ok($links[0].href.includes("/t/a-slug/123"));
|
||||
@ -62,6 +63,13 @@ widgetTest("notifications", {
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
const routeToStub = sandbox.stub(DiscourseURL, "routeTo");
|
||||
await click(".user-notifications-link");
|
||||
assert.ok(
|
||||
routeToStub.calledWith(find(".user-notifications-link")[0].href),
|
||||
"a second click should redirect to the full notifications page"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@ -73,6 +81,7 @@ widgetTest("log out", {
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await click(".user-activity-link");
|
||||
assert.ok(find(".logout").length);
|
||||
|
||||
await click(".logout");
|
||||
@ -97,8 +106,63 @@ widgetTest("private messages - enabled", {
|
||||
this.siteSettings.enable_personal_messages = true;
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.ok(find(".user-pms-link").length);
|
||||
async test(assert) {
|
||||
const userPmsLink = find(".user-pms-link")[0];
|
||||
assert.ok(userPmsLink);
|
||||
await click(".user-pms-link");
|
||||
|
||||
const message = find(".quick-access-panel li a")[0];
|
||||
assert.ok(message);
|
||||
|
||||
assert.ok(
|
||||
message.href.includes("/t/bug-can-not-render-emoji-properly/174/2"),
|
||||
"should link to the next unread post"
|
||||
);
|
||||
assert.ok(
|
||||
message.innerHTML.includes("mixtape"),
|
||||
"should include the last poster's username"
|
||||
);
|
||||
assert.ok(
|
||||
message.innerHTML.match(/<img.*class="emoji".*>/),
|
||||
"should correctly render emoji in message title"
|
||||
);
|
||||
|
||||
const routeToStub = sandbox.stub(DiscourseURL, "routeTo");
|
||||
await click(".user-pms-link");
|
||||
assert.ok(
|
||||
routeToStub.calledWith(userPmsLink.href),
|
||||
"a second click should redirect to the full private messages page"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
widgetTest("bookmarks", {
|
||||
template: '{{mount-widget widget="user-menu"}}',
|
||||
|
||||
async test(assert) {
|
||||
await click(".user-bookmarks-link");
|
||||
|
||||
const bookmark = find(".quick-access-panel li a")[0];
|
||||
assert.ok(bookmark);
|
||||
|
||||
assert.ok(
|
||||
bookmark.href.includes("/t/how-to-check-the-user-level-via-ajax/11993")
|
||||
);
|
||||
assert.ok(
|
||||
bookmark.innerHTML.includes("Abhishek_Gupta"),
|
||||
"should include the last poster's username"
|
||||
);
|
||||
assert.ok(
|
||||
bookmark.innerHTML.match(/<img.*class="emoji".*>/),
|
||||
"should correctly render emoji in bookmark title"
|
||||
);
|
||||
|
||||
const routeToStub = sandbox.stub(DiscourseURL, "routeTo");
|
||||
await click(".user-bookmarks-link");
|
||||
assert.ok(
|
||||
routeToStub.calledWith(find(".user-bookmarks-link")[0].href),
|
||||
"a second click should redirect to the full bookmarks page"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@ -115,7 +179,9 @@ widgetTest("anonymous", {
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await click(".user-activity-link");
|
||||
assert.ok(find(".enable-anonymous").length);
|
||||
|
||||
await click(".enable-anonymous");
|
||||
assert.ok(this.anonymous);
|
||||
}
|
||||
@ -128,7 +194,8 @@ widgetTest("anonymous - disabled", {
|
||||
this.siteSettings.allow_anonymous_posting = false;
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
async test(assert) {
|
||||
await click(".user-activity-link");
|
||||
assert.ok(!find(".enable-anonymous").length);
|
||||
}
|
||||
});
|
||||
@ -141,12 +208,14 @@ widgetTest("anonymous - switch back", {
|
||||
this.currentUser.setProperties({ is_anonymous: true });
|
||||
this.siteSettings.allow_anonymous_posting = true;
|
||||
|
||||
this.on("toggleAnonymous", () => (this.anonymous = true));
|
||||
this.on("toggleAnonymous", () => (this.anonymous = false));
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await click(".user-activity-link");
|
||||
assert.ok(find(".disable-anonymous").length);
|
||||
|
||||
await click(".disable-anonymous");
|
||||
assert.ok(this.anonymous);
|
||||
assert.notOk(this.anonymous);
|
||||
}
|
||||
});
|
||||
|
Reference in New Issue
Block a user