]> git.ipfire.org Git - thirdparty/public-inbox.git/commitdiff
www: add optional sortorder config for listing page ordering master
authorRafael Passos <rafael@rcpassos.me>
Tue, 12 May 2026 17:42:42 +0000 (14:42 -0300)
committerEric Wong <e@80x24.org>
Fri, 15 May 2026 21:49:05 +0000 (21:49 +0000)
Add a publicinbox.<name>.sortorder config key to control inbox
display order on the main listing page.  Lower values appear first,
inboxes without sortorder fall back to mtime-descending order below all
pinned inboxes.  Works with both direct config listing and extindex
all" paths.  Includes documentation in public-inbox-config(5) and
tests.

In my use case, we are hosting our list, and also mirroring the
lore.kernel lists. I want to pin our list to the top, because its the
main purpose of our installation.  I am running with this patch in
"https://lore.kernel.ime.usp.br/" where "kernel.ime" (our list) is
pinned to the top.

Reviewed-by: Eric Wong <e@80x24.org>
Signed-off-by: Rafael Passos <rafael@rcpassos.me>
Documentation/public-inbox-config.pod
lib/PublicInbox/Config.pm
lib/PublicInbox/WwwListing.pm
t/www_listing.t

index 328d50ffa1ca66f68a2403e0854135f3d41dc3f1..b4ddd29d92aac55a74d1c89a61bf0ce92b6f7bc1 100644 (file)
@@ -151,6 +151,16 @@ not affect messages which are already indexed.
 
 Default: C<0>
 
+=item publicinbox.<name>.sortorder
+
+Integer controlling the display order of this inbox on the main
+listing page.  Lower values appear first.  Inboxes without this
+setting are listed after all sorted inboxes, ordered by last
+modification time (descending).  This is useful for pinning
+important or frequently-accessed inboxes to the top of the list.
+
+Default: none (sorted by modification time descending)
+
 =item publicinbox.<name>.indexSequentialShard
 
 See L<public-inbox-index(1)/publicInbox.indexSequentialShard>
index 5bb1d8fbb40ed194a01888101c8eca96f6cbb543..c2031346ff76ae35c28c5b4e50a0181e993f2243 100644 (file)
@@ -470,7 +470,7 @@ sub _fill_ibx {
                $ibx->{$k} = $v if defined $v;
        }
        for my $k (qw(filter newsgroup replyto httpbackendmax feedmax
-                       indexlevel indexsequentialshard boost)) {
+                       indexlevel indexsequentialshard boost sortorder)) {
                my $v = get_1($self, "$pfx.$k") // next;
                $ibx->{$k} = $v;
        }
index dc246e444b51da98b387beac94fbd11a3f08f1ea..835d41cfcc2ee6c8ca26122d7107194683028ebe 100644 (file)
@@ -12,6 +12,7 @@ use PublicInbox::ConfigIter;
 use PublicInbox::WwwStream;
 use URI::Escape qw(uri_escape_utf8);
 use PublicInbox::MID qw(mid_escape);
+use POSIX qw(Inf);
 
 sub ibx_entry {
        my ($ctx, $ibx, $ce) = @_;
@@ -32,8 +33,9 @@ EOM
                $url = ascii_html(prurl($ctx->{env}, $url));
                $tmp .= qq(  <a\nhref="$url">$url</a>\n);
        }
+       my $so = $ibx->{sortorder} // Inf;
        push(@{$ctx->{-list}}, (scalar(@_) == 3 ? # $misc in use, already sorted
-                               $tmp : [ $ce->{-modified}, $tmp ] ));
+                               [$so, $tmp] : [$so, $ce->{-modified}, $tmp] ));
 }
 
 sub list_match_i { # ConfigIter callback
@@ -222,9 +224,20 @@ sub psgi_triple {
                $code = 200;
                if ($mset) { # already sorted, so search bar:
                        print $zfh mset_nav_top($ctx, $mset);
-               } else { # sort config dump by ->modified
+                       # FIXME: make PublicInbox::MiscIdx index sortorder
+                       # then use Xapian::MultiValueKeyMaker or
+                       # Search::Xapian::MultiValueSorter (old) in
+                       # PublicInbox::MiscSearch
                        @$list = map { $_->[1] }
-                               sort { $b->[0] <=> $a->[0] } @$list;
+                               sort { $a->[0] <=> $b->[0] } @$list;
+               } else { # sort by sortorder (asc), then modified (desc)
+                       my $so; # outside of sort block to reduce allocations
+                       # $list = [ [$sortorder, {-modified}, $raw_html], ... ]
+                       @$list = map { $_->[2] }
+                               sort {
+                                       $so = $a->[0] <=> $b->[0];
+                                       $so ? $so : $b->[1] <=> $a->[1]
+                               } @$list;
                }
                print $zfh '<pre>', join("\n", @$list); # big
                print $zfh mset_footer($ctx, $mset) if $mset;
index ff75655dfc4a8ff4bb230f473e0f9b5fc07446c9..c6124f014a14055edfed4e11f7cbd667eed97d27 100644 (file)
@@ -207,6 +207,33 @@ EOM
        undef $sock;
        tiny_test($json, $host, $port, 1);
 
+       # test sortorder config
+       undef $td;
+       open $fh, '>>', $cfgfile;
+       print $fh <<"";
+[publicinbox "bare"]
+       sortorder = 1
+[publicinbox "v2"]
+       sortorder = 2
+
+       close $fh;
+       my $sock_so = tcp_server();
+       my ($host_so, $port_so) = tcp_host_port($sock_so);
+       $td = start_script($cmd, $env, { 3 => $sock_so });
+       {
+               my $http = HTTP::Tiny->new;
+               my $res = $http->get("http://$host_so:$port_so/");
+               is($res->{status}, 200, 'got listing with sortorder');
+               my $c = $res->{content};
+               my $bare_pos = index($c, '/bare');
+               my $v2_pos = index($c, '/v2');
+               my $alt_pos = index($c, '/alt');
+               ok($bare_pos < $v2_pos,
+                       'bare (sortorder=1) before v2 (sortorder=2)');
+               ok($v2_pos < $alt_pos,
+                       'v2 (sortorder=2) before alt (no sortorder)');
+       }
+
        # grok-pull sleeps a long while some places:
        # https://lore.kernel.org/tools/20211013110344.GA10632@dcvr/
        skip 'TEST_GROK unset', 12 unless $ENV{TEST_GROK};