DEV: Plugin-api methods for user-notifications route customizations (#24873)
This commit is contained in:
parent
f7aefffea7
commit
c051bfc2fc
|
@ -523,6 +523,7 @@ GEM
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
aarch64-linux
|
aarch64-linux
|
||||||
arm64-darwin-20
|
arm64-darwin-20
|
||||||
|
arm64-darwin-21
|
||||||
arm64-darwin-22
|
arm64-darwin-22
|
||||||
x86_64-darwin-18
|
x86_64-darwin-18
|
||||||
x86_64-darwin-19
|
x86_64-darwin-19
|
||||||
|
|
|
@ -11,6 +11,11 @@ import { iconHTML } from "discourse-common/lib/icon-library";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
|
|
||||||
|
const _beforeLoadMoreCallbacks = [];
|
||||||
|
export function addBeforeLoadMoreCallback(fn) {
|
||||||
|
_beforeLoadMoreCallbacks.push(fn);
|
||||||
|
}
|
||||||
|
|
||||||
export default class UserNotificationsController extends Controller {
|
export default class UserNotificationsController extends Controller {
|
||||||
@service modal;
|
@service modal;
|
||||||
@service appEvents;
|
@service appEvents;
|
||||||
|
@ -102,6 +107,14 @@ export default class UserNotificationsController extends Controller {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
loadMore() {
|
loadMore() {
|
||||||
|
if (
|
||||||
|
_beforeLoadMoreCallbacks.length &&
|
||||||
|
!_beforeLoadMoreCallbacks.some((fn) => fn(this))
|
||||||
|
) {
|
||||||
|
// Return early if any callbacks return false, short-circuiting the default loading more logic
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.model.loadMore();
|
this.model.loadMore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import { addUserMenuProfileTabItem } from "discourse/components/user-menu/profil
|
||||||
import { addDiscoveryQueryParam } from "discourse/controllers/discovery/list";
|
import { addDiscoveryQueryParam } from "discourse/controllers/discovery/list";
|
||||||
import { registerFullPageSearchType } from "discourse/controllers/full-page-search";
|
import { registerFullPageSearchType } from "discourse/controllers/full-page-search";
|
||||||
import { registerCustomPostMessageCallback as registerCustomPostMessageCallback1 } from "discourse/controllers/topic";
|
import { registerCustomPostMessageCallback as registerCustomPostMessageCallback1 } from "discourse/controllers/topic";
|
||||||
|
import { addBeforeLoadMoreCallback as addBeforeLoadMoreNotificationsCallback } from "discourse/controllers/user-notifications";
|
||||||
import { registerCustomUserNavMessagesDropdownRow } from "discourse/controllers/user-private-messages";
|
import { registerCustomUserNavMessagesDropdownRow } from "discourse/controllers/user-private-messages";
|
||||||
import {
|
import {
|
||||||
addExtraIconRenderer,
|
addExtraIconRenderer,
|
||||||
|
@ -88,6 +89,7 @@ import {
|
||||||
addSaveableUserOptionField,
|
addSaveableUserOptionField,
|
||||||
} from "discourse/models/user";
|
} from "discourse/models/user";
|
||||||
import { setNewCategoryDefaultColors } from "discourse/routes/new-category";
|
import { setNewCategoryDefaultColors } from "discourse/routes/new-category";
|
||||||
|
import { setNotificationsLimit } from "discourse/routes/user-notifications";
|
||||||
import { addComposerSaveErrorCallback } from "discourse/services/composer";
|
import { addComposerSaveErrorCallback } from "discourse/services/composer";
|
||||||
import {
|
import {
|
||||||
addToHeaderIcons,
|
addToHeaderIcons,
|
||||||
|
@ -141,7 +143,7 @@ import { modifySelectKit } from "select-kit/mixins/plugin-api";
|
||||||
// docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md whenever you change the version
|
// docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md whenever you change the version
|
||||||
// using the format described at https://keepachangelog.com/en/1.0.0/.
|
// using the format described at https://keepachangelog.com/en/1.0.0/.
|
||||||
|
|
||||||
export const PLUGIN_API_VERSION = "1.18.0";
|
export const PLUGIN_API_VERSION = "1.19.0";
|
||||||
|
|
||||||
// This helper prevents us from applying the same `modifyClass` over and over in test mode.
|
// This helper prevents us from applying the same `modifyClass` over and over in test mode.
|
||||||
function canModify(klass, type, resolverName, changes) {
|
function canModify(klass, type, resolverName, changes) {
|
||||||
|
@ -819,6 +821,21 @@ class PluginApi {
|
||||||
registerCustomPostMessageCallback1(type, callback);
|
registerCustomPostMessageCallback1(type, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a callback that will be evaluated when infinite scrolling would cause
|
||||||
|
* more notifications to be loaded. This can be used to prevent loading more unless
|
||||||
|
* a specific condition is met.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* api.addBeforeLoadMoreNotificationsCallback((controller) => {
|
||||||
|
* return controller.allowLoadMore;
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
addBeforeLoadMoreNotificationsCallback(fn) {
|
||||||
|
addBeforeLoadMoreNotificationsCallback(fn);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes a setting associated with a widget. For example, if
|
* Changes a setting associated with a widget. For example, if
|
||||||
* you wanted small avatars in the post stream:
|
* you wanted small avatars in the post stream:
|
||||||
|
@ -1773,6 +1790,18 @@ class PluginApi {
|
||||||
setNewCategoryDefaultColors(backgroundColor, textColor);
|
setNewCategoryDefaultColors(backgroundColor, textColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the number of notifications that are loaded at /my/notifications
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* api.setNotificationsLimit(20)
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
**/
|
||||||
|
setNotificationsLimit(limit) {
|
||||||
|
setNotificationsLimit(limit);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a callback to modify search results before displaying them.
|
* Add a callback to modify search results before displaying them.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,6 +2,13 @@ import ViewingActionType from "discourse/mixins/viewing-action-type";
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
import I18n from "discourse-i18n";
|
import I18n from "discourse-i18n";
|
||||||
|
|
||||||
|
const DEFAULT_LIMIT = 60;
|
||||||
|
let limit = DEFAULT_LIMIT;
|
||||||
|
|
||||||
|
export function setNotificationsLimit(newLimit) {
|
||||||
|
limit = newLimit;
|
||||||
|
}
|
||||||
|
|
||||||
export default DiscourseRoute.extend(ViewingActionType, {
|
export default DiscourseRoute.extend(ViewingActionType, {
|
||||||
controllerName: "user-notifications",
|
controllerName: "user-notifications",
|
||||||
queryParams: { filter: { refreshModel: true } },
|
queryParams: { filter: { refreshModel: true } },
|
||||||
|
@ -16,6 +23,7 @@ export default DiscourseRoute.extend(ViewingActionType, {
|
||||||
return this.store.find("notification", {
|
return this.store.find("notification", {
|
||||||
username,
|
username,
|
||||||
filter: params.filter,
|
filter: params.filter,
|
||||||
|
limit,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -27,6 +27,10 @@
|
||||||
<UserMenu::MenuItem @item={{item}} />
|
<UserMenu::MenuItem @item={{item}} />
|
||||||
{{/each}}
|
{{/each}}
|
||||||
<ConditionalLoadingSpinner @condition={{this.loading}} />
|
<ConditionalLoadingSpinner @condition={{this.loading}} />
|
||||||
|
<PluginOutlet
|
||||||
|
@name="user-notifications-list-bottom"
|
||||||
|
@outletArgs={{hash controller=this}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
|
@ -7,6 +7,14 @@ in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.19.0] - 2023-12-13
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added `setNotificationsLimit` function, which sets a new limit for how many notifications are loaded for the user notifications route
|
||||||
|
|
||||||
|
- Added `addBeforeLoadMoreNotificationsCallback` function, which takes a function as the argument. All added callbacks are evaluated before `loadMore` is triggered for user notifications. If any callback returns false, notifications will not be loaded.
|
||||||
|
|
||||||
## [1.18.0] - 2023-12-1
|
## [1.18.0] - 2023-12-1
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -52,6 +52,10 @@ module PageObjects
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def click_primary_navigation_item(name)
|
||||||
|
page.find(primary_navigation_selector(name)).click
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def primary_navigation_selector(name)
|
def primary_navigation_selector(name)
|
||||||
|
|
|
@ -27,6 +27,10 @@ module PageObjects
|
||||||
def has_no_notification?(notification)
|
def has_no_notification?(notification)
|
||||||
page.has_no_css?(".notification a[href='#{notification.url}']")
|
page.has_no_css?(".notification a[href='#{notification.url}']")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def has_notification_count_of?(count)
|
||||||
|
page.has_css?(".notification", count: count)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
describe "User notifications", type: :system do
|
describe "User notifications", type: :system do
|
||||||
fab!(:user)
|
fab!(:user)
|
||||||
let(:user_notifications_page) { PageObjects::Pages::UserNotifications.new }
|
let(:user_notifications_page) { PageObjects::Pages::UserNotifications.new }
|
||||||
|
let(:user_page) { PageObjects::Pages::User.new }
|
||||||
|
|
||||||
fab!(:read_notification) { Fabricate(:notification, user: user, read: true) }
|
fab!(:read_notification) { Fabricate(:notification, user: user, read: true) }
|
||||||
fab!(:unread_notification) { Fabricate(:notification, user: user, read: false) }
|
fab!(:unread_notification) { Fabricate(:notification, user: user, read: false) }
|
||||||
|
@ -10,7 +11,7 @@ describe "User notifications", type: :system do
|
||||||
before { sign_in(user) }
|
before { sign_in(user) }
|
||||||
|
|
||||||
describe "filtering" do
|
describe "filtering" do
|
||||||
it "saves custom picture and system assigned pictures" do
|
it "correctly filters all / read / unread notifications" do
|
||||||
user_notifications_page.visit(user)
|
user_notifications_page.visit(user)
|
||||||
user_notifications_page.filter_dropdown
|
user_notifications_page.filter_dropdown
|
||||||
expect(user_notifications_page).to have_selected_filter_value("all")
|
expect(user_notifications_page).to have_selected_filter_value("all")
|
||||||
|
@ -28,4 +29,26 @@ describe "User notifications", type: :system do
|
||||||
expect(user_notifications_page).to have_notification(unread_notification)
|
expect(user_notifications_page).to have_notification(unread_notification)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "setNotificationLimit & addBeforeLoadMoreNotificationsCallback plugin-api functions" do
|
||||||
|
it "Allows blocking loading via callback and limit" do
|
||||||
|
user_page.visit(user)
|
||||||
|
|
||||||
|
page.execute_script <<~JS
|
||||||
|
require("discourse/lib/plugin-api").withPluginApi("1.19.0", (api) => {
|
||||||
|
api.setNotificationsLimit(1);
|
||||||
|
|
||||||
|
api.addBeforeLoadMoreNotificationsCallback(() => {
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
})
|
||||||
|
JS
|
||||||
|
|
||||||
|
user_page.click_primary_navigation_item("notifications")
|
||||||
|
|
||||||
|
# It is 1 here because we blocked infinite scrolling. Even though the limit is 1,
|
||||||
|
# without the callback, we would have 2 items here as it immediately fires another request.
|
||||||
|
expect(user_notifications_page).to have_notification_count_of(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue