This is an automated email from the ASF dual-hosted git repository.

sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-release.git


The following commit(s) were added to refs/heads/main by this push:
     new d276954  Add a table of contents to distribution list pages
d276954 is described below

commit d276954b01cc698026c16d581645a0a413b894e9
Author: Sean B. Palmer <[email protected]>
AuthorDate: Mon Aug 11 14:27:51 2025 +0100

    Add a table of contents to distribution list pages
---
 atr/htm.py                 | 19 +++++++++++++++++--
 atr/models/sql.py          | 14 ++++++++++++++
 atr/routes/distribution.py | 14 ++++++++++++--
 3 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/atr/htm.py b/atr/htm.py
index c4cddaa..43d5f98 100644
--- a/atr/htm.py
+++ b/atr/htm.py
@@ -57,6 +57,8 @@ class BlockElementCallable:
 
 
 class Block:
+    __match_args__ = ("elements",)
+
     def __init__(self, element: htpy.Element | None = None, *elements: 
htpy.Element):
         self.element = element
         self.elements: list[htpy.Element | str] = list(elements)
@@ -67,8 +69,13 @@ class Block:
     def __repr__(self) -> str:
         return f"{self.element!r}[*{self.elements!r}]"
 
-    def append(self, element: htpy.Element) -> None:
-        self.elements.append(element)
+    def append(self, eob: Block | htpy.Element) -> None:
+        match eob:
+            case Block():
+                # TODO: Does not support separator
+                self.elements.append(eob.collect())
+            case htpy.Element():
+                self.elements.append(eob)
 
     def collect(self, separator: str | None = None) -> htpy.Element:
         if separator is not None:
@@ -107,6 +114,10 @@ class Block:
     def h3(self) -> BlockElementCallable:
         return BlockElementCallable(self, htpy.h3)
 
+    @property
+    def li(self) -> BlockElementCallable:
+        return BlockElementCallable(self, htpy.li)
+
     @property
     def p(self) -> BlockElementCallable:
         return BlockElementCallable(self, htpy.p)
@@ -133,3 +144,7 @@ class Block:
 
     def text(self, text: str) -> None:
         self.elements.append(text)
+
+    @property
+    def ul(self) -> BlockElementCallable:
+        return BlockElementCallable(self, htpy.ul)
diff --git a/atr/models/sql.py b/atr/models/sql.py
index 2bd71a3..7fd2f01 100644
--- a/atr/models/sql.py
+++ b/atr/models/sql.py
@@ -845,6 +845,20 @@ class Distribution(sqlmodel.SQLModel, table=True):
     # So we do not store it in the database
     # api_response: Any = 
sqlmodel.Field(sa_column=sqlalchemy.Column(sqlalchemy.JSON))
 
+    @property
+    def identifier(self) -> str:
+        def normal(text: str) -> str:
+            return text.replace(" ", "_").lower()
+
+        name = normal(self.platform.value.name)
+        package = normal(self.package)
+        version = normal(self.version)
+        return f"{name}-{package}-{version}"
+
+    @property
+    def title(self) -> str:
+        return f"{self.platform.value.name} {self.package} {self.version}"
+
 
 # # DistributionChannel: Project
 # class DistributionChannel(sqlmodel.SQLModel, table=True):
diff --git a/atr/routes/distribution.py b/atr/routes/distribution.py
index 621dbce..2b0bc77 100644
--- a/atr/routes/distribution.py
+++ b/atr/routes/distribution.py
@@ -257,6 +257,12 @@ async def list_get(session: routes.CommitterSession, 
project: str, version: str)
         )
     block.p["Here are all of the distributions recorded for this release."]
     block.p[record_a_distribution]
+    # Table of contents
+    ul_toc = htm.Block(htpy.ul)
+    for distribution in distributions:
+        a = 
htpy.a(href=f"#distribution-{distribution.identifier}")[distribution.title]
+        ul_toc.li[a]
+    block.append(ul_toc)
 
     ## Distributions
     block.h2["Distributions"]
@@ -272,7 +278,11 @@ async def list_get(session: routes.CommitterSession, 
project: str, version: str)
         )
 
         ### Platform package version
-        block.h3[f"{distribution.platform.value.name} {distribution.package} 
{distribution.version}"]
+        block.h3(
+            # Cannot use "#id" here, because the ID contains "."
+            # If an ID contains ".", htpy parses that as a class
+            id=f"distribution-{distribution.identifier}"
+        )[distribution.title]
         tbody = htpy.tbody[
             _html_tr("Release name", distribution.release_name),
             _html_tr("Platform", distribution.platform.value.name),
@@ -479,7 +489,7 @@ def _html_nav(container: htm.Block, back_url: str, 
back_anchor: str, phase: Phas
     _phase(phase, "FINISH")
 
     block.append(span.collect(separator=" "))
-    container.append(block.collect())
+    container.append(block)
 
 
 def _html_nav_phase(block: htm.Block, project: str, version: str, staging: 
bool) -> None:


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to