Page MenuHomePhabricator

PersonalDashboard: Shared feed REST API for the dashboard feed scaffold
Closed, ResolvedPublic5 Estimated Story Points

Description

Summary

Add a REST endpoint that returns merged, normalized feed items for a requested set of named sources, so a feed module can populate the shared feed scaffold introduced in r1329722 (T433900) with one request and page past its first batch. Today, ReviewChanges issues up to ten Action API requests per load, merges and normalizes them in JavaScript, and cannot go past the 100 recently-edited changes handed over in getJsConfigVars().

See related task: T433900: Factor out a shared feed scaffold for dashboard modules

Technical notes

The endpoint is the server half of the feed-data contract useFeedState() already defines: { items, isLoading, error }, where every item carries a unique id. A response is { items: FeedItem[], continue: <opaque token>|null }; the client keeps isLoading and error, so a module's whole data layer becomes one loader passed to useFeedState() instead of a composable per source.

Shape: GET /personaldashboard/v0/feed/{sources}?limit=12&continue=<token>, where {sources} is a pipe-separated list. The sources identify the resource, so they belong in the path; limit and continue modulate the representation and are optional, so they stay in the query string, matching core routes like /v1/page/{title}/history?older_than=. Keeping the continue token out of the path also avoids percent-encoded slashes in a path segment, which proxies handle inconsistently.

Sources come from a registry keyed by name so a consumer outside PersonalDashboard can register one and reuse the scaffold without patching this extension; the three Review Changes sources are the first implementations, and ActiveDiscussions' DiscussionTools query is a candidate to follow.

Server-side, this moves work the client currently repeats: the recentchanges param building and continuation loop in useRecentChangesFeed.js, normalizeFeedItem(), and selectEvenlyAcrossFeeds(). The merge belongs on the server deliberately — an even split across sources with title dedup and backfill when a source runs dry is only decidable where all the sources are, and it's what lets one request answer a multi-source feed. ReviewChanges::getRecentlyEditedItems() already builds the FeedItem shape through ChangesListQuery, so the normalization contract exists — it just needs to become the endpoint's response schema, documented and versioned as something other extensions can depend on.

Ordering is deterministic newest-first. The random sampling the three composables do today via getRandomItems() can't survive a continue token — you can't paginate coherently through a random sample — so it comes out of the fetch path. getRandomItems() stays exported from ext.personalDashboard.common, and a client that wants a shuffled view asks for a page larger than it displays and samples what it got. ReviewChanges should do exactly that when it migrates: its sampling isn't decorative, it spreads reviewers across different changes so two people don't independently review the same top-of-recentchanges edit. Requesting limit=12 and rendering all twelve would quietly drop that.

Pagination is the reason the cap goes away: the continue token encodes each source's own offset, so the full-list view's "Load more" control asks for the next page rather than slicing a fixed batch that was capped at 100 before it reached the browser. $wgPersonalDashboardRecentlyEditedItems can then shrink to a first-page payload or be dropped, taking those items out of the HTML.

Responses are user-scoped (watchlist, recently-edited, and the ORES/patrol filters that vary by user rights), so this is private, session-authenticated, and consequently uncacheable at the edge.

Acceptance criteria

  • A versioned REST endpoint returns merged, normalized feed items for a requested set of registered sources, ordered newest-first, with an opaque continue token and a documented item schema.
  • Review Changes loads its feed from the endpoint in a single request, with client-side param building, pagination, merging, and normalization removed, and over-fetches so it can keep sampling client-side.
  • "Load more" fetches subsequent pages rather than stopping at the initial batch
  • An extension outside PersonalDashboard can register a feed source without patching PersonalDashboard. Say, we could introduce a new Feed interface with a getItems() method that returns a FeedItem – essentially porting the current feedHelper.js to the backend.

Event Timeline

Samwalton9-WMF renamed this task from [DRAFT] PersonalDashboard: Shared feed REST API for the dashboard feed scaffold to PersonalDashboard: Shared feed REST API for the dashboard feed scaffold.Sep 1 2026, 3:24 PM
Samwalton9-WMF triaged this task as High priority.
Samwalton9-WMF set the point value for this task to 5.
MusikAnimal changed the task status from Open to In Progress.Sep 1 2026, 3:25 PM
MusikAnimal claimed this task.
MusikAnimal moved this task from Ready to In Progress on the Moderator-Tools-Team (Kanban) board.

Change #1337967 had a related patch set uploaded (by MusikAnimal; author: MusikAnimal):

[mediawiki/extensions/PersonalDashboard@master] Add a feed source interface and its registry

https://gerrit.wikimedia.org/r/1337967

Change #1337968 had a related patch set uploaded (by MusikAnimal; author: MusikAnimal):

[mediawiki/extensions/PersonalDashboard@master] Add the three Review Changes feed sources

https://gerrit.wikimedia.org/r/1337968

Change #1338015 had a related patch set uploaded (by MusikAnimal; author: MusikAnimal):

[mediawiki/extensions/PersonalDashboard@master] Add FeedMerger, and a dedup key for it to work on

https://gerrit.wikimedia.org/r/1338015

Change #1338055 had a related patch set uploaded (by MusikAnimal; author: MusikAnimal):

[mediawiki/extensions/PersonalDashboard@master] Serve the merged feed over a REST endpoint

https://gerrit.wikimedia.org/r/1338055

Change #1338088 had a related patch set uploaded (by MusikAnimal; author: MusikAnimal):

[mediawiki/extensions/PersonalDashboard@master] Attach machine-learning scores to feed items

https://gerrit.wikimedia.org/r/1338088

Adding to API Platform sprint board so we can do a light code review for the new API module. @KineticPelagic -- since it looks like you're on chore duty today, could you take a look?

Adding to API Platform sprint board so we can do a light code review for the new API module. @KineticPelagic -- since it looks like you're on chore duty today, could you take a look?

Yes, will review!

Change #1338299 had a related patch set uploaded (by MusikAnimal; author: MusikAnimal):

[integration/config@master] zuul: add ORES and Wikibase as phan dependency of PersonalDashboard

https://gerrit.wikimedia.org/r/1338299

Change #1337967 merged by jenkins-bot:

[mediawiki/extensions/PersonalDashboard@master] Add a feed source interface and its registry

https://gerrit.wikimedia.org/r/1337967

Change #1338299 merged by jenkins-bot:

[integration/config@master] Zuul: [mediawiki/extensions/PersonalDashboard] Add ORES & Wikibase phan deps

https://gerrit.wikimedia.org/r/1338299

Mentioned in SAL (#wikimedia-releng) [2026-09-10T18:56:18Z] <James_F> Zuul: [mediawiki/extensions/PersonalDashboard] Add ORES & Wikibase phan deps for T436570 and T437491

Change #1337968 merged by jenkins-bot:

[mediawiki/extensions/PersonalDashboard@master] Add the three Review Changes feed sources

https://gerrit.wikimedia.org/r/1337968

Change #1338015 merged by jenkins-bot:

[mediawiki/extensions/PersonalDashboard@master] Add FeedMerger, and a dedup key for it to work on

https://gerrit.wikimedia.org/r/1338015

Change #1338055 merged by jenkins-bot:

[mediawiki/extensions/PersonalDashboard@master] Serve the merged feed over a REST endpoint

https://gerrit.wikimedia.org/r/1338055

Change #1338088 merged by jenkins-bot:

[mediawiki/extensions/PersonalDashboard@master] Attach machine-learning scores to feed items

https://gerrit.wikimedia.org/r/1338088

@KineticPelagic noting that this got signoff from y'all and internal +2 from us, so you can move it on your board at your leisure.

MusikAnimal updated the task description. (Show Details)
MusikAnimal moved this task from QA to Done on the Moderator-Tools-Team (Kanban) board.

Confirmed on testwiki. We only did not confirm an external feed from another extension works, but it was reviewed. We've QA'd everything we can.