Support choosing the sort type when creating or editing a user query (#8954)

* Support choosing the sort type when creating or editing a user query

Changes
- User queries can now store a sort field (sort type), not only the sort
  direction. The create and edit forms expose a single combined dropdown
  (field + direction) that reuses the existing `index.menu.sort.*` options,
  matching the global reading-settings sort UI.
- The "Bookmark current query" action now also remembers the current sort
  field, where it previously kept only the order direction.
- Relabel the query sort control from "Sort by date" to "Sort by"; other
  languages are marked for re-translation (// TODO).
- Add a CHANGELOG entry and credit the contributor in CREDITS.

Implementation
- `FreshRSS_UserQuery`: add an optional `sort` property mirroring `order`
  (constructor parsing, `toArray()`, `getSort()` falling back to the user
  default sort, and a `hasParameters()` check).
- `configureController`: split the combined dropdown value into `sort` and
  `order`, validating the field against the implemented sort types
  (`id`, `c.name`, `date`, `f.name`, `length`, `link`, `title`, `rand`);
  separate `sort`/`order` request parameters are still accepted so the
  "bookmark current query" flow keeps working.
- Views render the combined dropdown and persist `sort` as a hidden field.
- `p/api/query.php`: back-fill `sort` from the saved query when the request
  does not provide one, mirroring the existing `order` handling.
- Add unit tests covering the sort round-trip and `toArray()` inclusion.

Compatibility
- No database or schema change: user queries are stored in the per-user PHP
  config array, which keeps arbitrary keys verbatim, so no migration is
  required.
- Upgrade: existing queries without `sort` fall back to the user default
  sort; behaviour is unchanged until a sort is explicitly chosen.
- Downgrade: older versions ignore the extra `sort` key and keep working;
  re-saving under an old version simply drops the key with no data loss.
- Shared query URLs without a `sort` parameter remain valid.

* Refresh README translation statistics

* i18n: fr

---------

Co-authored-by: Alexandre Alapetite <alexandre@alapetite.fr>
This commit is contained in:
i @manandAlexandre Alapetite authored and GitHub committed 2026-11-02 21:43:05 +01:00
1 parent d03296f074
commit 4e8a258b01
40 files changed
+160 -60

No files matched your search

+16 -4
View File
@@ -15,6 +15,7 @@ class FreshRSS_UserQuery {
/** XML-encoded name */
private string $name = '';
private string $order = '';
private string $sort = '';
private readonly FreshRSS_BooleanSearch $search;
private int $state = 0;
private string $url = '';
@@ -45,7 +46,7 @@ class FreshRSS_UserQuery {
}
/**
* @param array{get?:string,name?:string,order?:string,search?:string,state?:int,url?:string,token?:string,
* @param array{get?:string,name?:string,order?:string,sort?:string,search?:string,state?:int,url?:string,token?:string,
* shareRss?:bool,shareOpml?:bool,includeUserLabels?:bool,excludeArticleTags?:bool,userLabelPrefix?:string,
* publishLabelsInsteadOfTags?:bool,description?:string,imageUrl?:string} $query
* @param array<FreshRSS_Category> $categories
@@ -72,6 +73,9 @@ class FreshRSS_UserQuery {
if (isset($query['order'])) {
$this->order = $query['order'];
}
if (isset($query['sort'])) {
$this->sort = $query['sort'];
}
if (empty($query['url'])) {
if (!empty($query)) {
$link = $query;
@@ -136,7 +140,7 @@ class FreshRSS_UserQuery {
/**
* Convert the current object to an array.
*
* @return array{get?:string,name?:string,order?:string,search?:string,
* @return array{get?:string,name?:string,order?:string,sort?:string,search?:string,
* state?:int,url?:string,token?:string,shareRss?:bool,shareOpml?:bool,
* includeUserLabels?:bool,excludeArticleTags?:bool,userLabelPrefix?:string,description?:string,imageUrl?:string}
*/
@@ -145,6 +149,7 @@ class FreshRSS_UserQuery {
'get' => $this->get,
'name' => $this->name,
'order' => $this->order,
'sort' => $this->sort,
'search' => $this->search->toString(expandUserQueries: false),
'state' => $this->state,
'url' => $this->url,
@@ -238,6 +243,9 @@ class FreshRSS_UserQuery {
if ($this->order !== '' && $this->order !== FreshRSS_Context::userConf()->sort_order) {
return true;
}
if ($this->sort !== '' && $this->sort !== FreshRSS_Context::userConf()->sort) {
return true;
}
return false;
}
@@ -268,6 +276,10 @@ class FreshRSS_UserQuery {
return $this->order ?: FreshRSS_Context::userConf()->sort_order;
}
public function getSort(): string {
return $this->sort ?: FreshRSS_Context::userConf()->sort;
}
public function getSearch(): FreshRSS_BooleanSearch {
return $this->search;
}
@@ -394,9 +406,9 @@ class FreshRSS_UserQuery {
/**
* Remove queries where $get is appearing.
* @param string $get the get attribute which should be removed.
* @param array<int,array{get?:string,name?:string,order?:string,search?:string,state?:int,url?:string,token?:string,
* @param array<int,array{get?:string,name?:string,order?:string,sort?:string,search?:string,state?:int,url?:string,token?:string,
* shareRss?:bool,shareOpml?:bool,description?:string,imageUrl?:string}> $queries an array of queries.
* @return array<int,array{get?:string,name?:string,order?:string,search?:string,state?:int,url?:string,token?:string,
* @return array<int,array{get?:string,name?:string,order?:string,sort?:string,search?:string,state?:int,url?:string,token?:string,
* shareRss?:bool,shareOpml?:bool,description?:string,imageUrl?:string}> without queries where $get is appearing.
*/
public static function remove_query_by_get(string $get, array $queries): array {