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 8cfcd78  Improve the navigation of distribution pages
8cfcd78 is described below

commit 8cfcd789ce00e1c8e12d15abbcf390edae23aa2f
Author: Sean B. Palmer <[email protected]>
AuthorDate: Thu Aug 7 19:52:33 2025 +0100

    Improve the navigation of distribution pages
---
 atr/htm.py                 | 14 +++++++++-
 atr/routes/distribution.py | 64 +++++++++++++++++++++++++++++++++++++---------
 2 files changed, 65 insertions(+), 13 deletions(-)

diff --git a/atr/htm.py b/atr/htm.py
index 6fece29..c4cddaa 100644
--- a/atr/htm.py
+++ b/atr/htm.py
@@ -70,7 +70,11 @@ class Block:
     def append(self, element: htpy.Element) -> None:
         self.elements.append(element)
 
-    def collect(self) -> htpy.Element:
+    def collect(self, separator: str | None = None) -> htpy.Element:
+        if separator is not None:
+            separated: list[htpy.Element | str] = [separator] * (2 * 
len(self.elements) - 1)
+            separated[::2] = self.elements
+            self.elements = separated
         if self.element is None:
             return htpy.div[*self.elements]
         return self.element[*self.elements]
@@ -111,6 +115,14 @@ class Block:
     def pre(self) -> BlockElementCallable:
         return BlockElementCallable(self, htpy.pre)
 
+    @property
+    def span(self) -> BlockElementCallable:
+        return BlockElementCallable(self, htpy.span)
+
+    @property
+    def strong(self) -> BlockElementCallable:
+        return BlockElementCallable(self, htpy.strong)
+
     @property
     def summary(self) -> BlockElementCallable:
         return BlockElementCallable(self, htpy.summary)
diff --git a/atr/routes/distribution.py b/atr/routes/distribution.py
index acf6a21..c3988eb 100644
--- a/atr/routes/distribution.py
+++ b/atr/routes/distribution.py
@@ -20,7 +20,7 @@ from __future__ import annotations
 import dataclasses
 import datetime
 import json
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Literal
 
 import aiohttp
 import htpy
@@ -43,6 +43,8 @@ import atr.util as util
 if TYPE_CHECKING:
     import werkzeug.wrappers.response as response
 
+type Phase = Literal["COMPOSE", "VOTE", "FINISH"]
+
 
 class ArtifactHubAvailableVersion(schema.Lax):
     ts: int
@@ -200,6 +202,9 @@ async def list_get(session: routes.CommitterSession, 
project: str, version: str)
         ).all()
 
     block = htm.Block()
+    back_url = util.as_url(finish.selected, project_name=project, 
version_name=version)
+    _nav(block, back_url, back_anchor=f"Finish {project} {version}", 
phase="FINISH")
+
     # Distribution list for project-version
     block.h1["Distribution list for ", htpy.em[f"{project}-{version}"]]
     if not distributions:
@@ -211,6 +216,13 @@ async def list_get(session: routes.CommitterSession, 
project: str, version: str)
         )
     block.p["Here are all of the distributions recorded for this release."]
 
+    ## Actions
+    block.p[
+        "You can also ",
+        htpy.a(href=util.as_url(record, project=project, 
version=version))["record a distribution"],
+        ".",
+    ]
+
     ## Distributions
     block.h2["Distributions"]
     for distribution in distributions:
@@ -245,12 +257,6 @@ async def list_get(session: routes.CommitterSession, 
project: str, version: str)
         )
         block.append(htpy.div(".mb-3")[delete_form_element])
 
-    ## Actions
-    block.h2["Actions"]
-    block.p[htpy.a(href=util.as_url(record, project=project, 
version=version))["Record a distribution"]]
-    block.p[
-        htpy.a(href=util.as_url(finish.selected, project_name=project, 
version_name=version))["Return to release page"]
-    ]
     title = f"Distribution list for {project} {version}"
     return await template.blank(title, content=block.collect())
 
@@ -287,6 +293,9 @@ async def _distribute_page(fpv: FormProjectVersion, *, 
extra_content: htpy.Eleme
     # Render the explanation and form
     block = htm.Block()
 
+    back_url = util.as_url(finish.selected, project_name=fpv.project, 
version_name=fpv.version)
+    _nav(block, back_url, back_anchor=f"Finish {fpv.project} {fpv.version}", 
phase="FINISH")
+
     # Record a manual distribution
     block.h1["Record a manual distribution"]
     if extra_content:
@@ -298,14 +307,13 @@ async def _distribute_page(fpv: FormProjectVersion, *, 
extra_content: htpy.Eleme
         htpy.span(".atr-phase-three.atr-phase-label")["FINISH"],
         " phase using the form below.",
     ]
-    block.append(forms.render_columns(fpv.form, action=quart.request.path, 
descriptions=True))
     block.p[
-        "Or view the ",
-        htpy.a(href=util.as_url(list_get, project=fpv.project, 
version=fpv.version))["distribution list"],
-        ", or return to the ",
-        htpy.a(href=util.as_url(finish.selected, project_name=fpv.project, 
version_name=fpv.version))["release page"],
+        "You can also ",
+        htpy.a(href=util.as_url(list_get, project=fpv.project, 
version=fpv.version))["view the distribution list"],
         ".",
     ]
+    block.append(forms.render_columns(fpv.form, action=quart.request.path, 
descriptions=True))
+
     # Render the page
     return await template.blank("Record a manual distribution", 
content=block.collect())
 
@@ -436,6 +444,38 @@ def _distribute_post_table(block: htm.Block, dd: 
DistributeData) -> None:
     block.table(".table.table-striped.table-bordered")[tbody]
 
 
+# TODO: Move this to an appropriate module
+def _nav(container: htm.Block, back_url: str, back_anchor: str, phase: Phase) 
-> None:
+    classes = ".d-flex.justify-content-between.align-items-center"
+    block = htm.Block(htpy.p(classes))
+    block.a(".atr-back-link", href=back_url)[f"← Back to {back_anchor}"]
+    span = htm.Block(htpy.span)
+
+    def _phase(actual: Phase, expected: Phase) -> None:
+        nonlocal span
+        match expected:
+            case "COMPOSE":
+                symbol = "①"
+            case "VOTE":
+                symbol = "②"
+            case "FINISH":
+                symbol = "③"
+        if actual == expected:
+            span.strong(f".atr-phase-{actual}.atr-phase-symbol")[symbol]
+            span.span(f".atr-phase-{actual}.atr-phase-label")[actual]
+        else:
+            span.span(".atr-phase-symbol-other")[symbol]
+
+    _phase(phase, "COMPOSE")
+    span.span(".atr-phase-arrow")["→"]
+    _phase(phase, "VOTE")
+    span.span(".atr-phase-arrow")["→"]
+    _phase(phase, "FINISH")
+
+    block.append(span.collect(separator=" "))
+    container.append(block.collect())
+
+
 def _platform_upload_date(  # noqa: C901
     platform: sql.DistributionPlatform,
     data: basic.JSON,


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

Reply via email to