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 a3a6fbd  Add a tools page for candidate draft files
a3a6fbd is described below

commit a3a6fbd766d3562b3143a9b98d6b47ef88ddac26
Author: Sean B. Palmer <[email protected]>
AuthorDate: Tue Mar 25 19:30:24 2025 +0200

    Add a tools page for candidate draft files
---
 atr/routes/files.py            | 45 ++++++++++++++++++++++++++++++++++++++++++
 atr/templates/files-list.html  | 30 +++++++++++++++++-----------
 atr/templates/files-tools.html | 35 ++++++++++++++++++++++++++++++++
 3 files changed, 98 insertions(+), 12 deletions(-)

diff --git a/atr/routes/files.py b/atr/routes/files.py
index b6543fe..2e064de 100644
--- a/atr/routes/files.py
+++ b/atr/routes/files.py
@@ -461,3 +461,48 @@ async def root_files_checks(session: CommitterSession, 
project_name: str, versio
         all_tasks_completed=all_tasks_completed,
         format_file_size=routes.format_file_size,
     )
+
+
+@committer_route("/files/tools/<project_name>/<version_name>/<path:file_path>")
+async def root_files_tools(session: CommitterSession, project_name: str, 
version_name: str, file_path: str) -> str:
+    """Show the tools for a specific file."""
+    # Check that the user has access to the project
+    if not any((p.name == project_name) for p in (await 
session.user_projects)):
+        raise base.ASFQuartException("You do not have access to this project", 
errorcode=403)
+
+    async with db.session() as data:
+        # Check that the release exists
+        release = await data.release(name=f"{project_name}-{version_name}", 
_project=True).demand(
+            base.ASFQuartException("Release does not exist", errorcode=404)
+        )
+
+        full_path = str(util.get_candidate_draft_dir() / project_name / 
version_name / file_path)
+
+        # Check that the file exists
+        if not await aiofiles.os.path.exists(full_path):
+            raise base.ASFQuartException("File does not exist", errorcode=404)
+
+        modified = int(await aiofiles.os.path.getmtime(full_path))
+        file_size = await aiofiles.os.path.getsize(full_path)
+
+    file_data = {
+        "filename": pathlib.Path(file_path).name,
+        "bytes_size": file_size,
+        "uploaded": datetime.datetime.fromtimestamp(modified, tz=datetime.UTC),
+    }
+
+    return await quart.render_template(
+        "files-tools.html",
+        project_name=project_name,
+        version_name=version_name,
+        file_path=file_path,
+        file_data=file_data,
+        release=release,
+        format_file_size=routes.format_file_size,
+    )
+
+
+@committer_route("/files/delete/<project_name>/<version_name>/<path:file_path>",
 methods=["POST"])
+async def root_files_delete(session: CommitterSession, project_name: str, 
version_name: str, file_path: str) -> str:
+    """Delete a specific file from the release candidate."""
+    return ""
diff --git a/atr/templates/files-list.html b/atr/templates/files-list.html
index 33d94ee..305fea5 100644
--- a/atr/templates/files-list.html
+++ b/atr/templates/files-list.html
@@ -10,7 +10,9 @@
 
 {% block content %}
   <h1>Files for {{ release.project.display_name }} {{ version_name }}</h1>
-  <p class="intro">This page shows the files for the {{ project_name }} {{ 
version_name }} candidate draft.</p>
+  <p class="intro">
+    This page shows the files for the {{ project_name }} {{ version_name }} 
<strong>candidate draft</strong>.
+  </p>
 
   <div class="card mb-4">
     <div class="card-header d-flex justify-content-between align-items-center">
@@ -57,8 +59,7 @@
             <thead>
               <tr>
                 <th>Path</th>
-                <th>Warnings and errors</th>
-                <th>Checks</th>
+                <th>Tools, checks, warnings, and errors</th>
               </tr>
             </thead>
             <tbody>
@@ -73,12 +74,10 @@
                       <a href="{{ url_for('root_download', 
phase='candidate-draft', project=release.project.name, version=release.version, 
path=path) }}">{{ path }}</a>
                     {% endif %}
                   </td>
-                  <td>
-                    {% for warning in warnings[path] %}<div class="alert 
alert-warning p-0 px-2 mt-0 mb-2">{{ warning }}</div>{% endfor %}
-                    {% for error in errors[path] %}<div class="alert 
alert-danger p-0 px-2 mt-0 mb-2">{{ error }}</div>{% endfor %}
-                  </td>
                   <td>
                     {% if path in tasks and tasks[path]|length > 0 %}
+                      <a href="{{ url_for('root_files_tools', 
project_name=project_name, version_name=version_name, file_path=path) 
}}">Tools</a> ·
+                      <a href="{{ url_for('root_files_checks', 
project_name=project_name, version_name=version_name, file_path=path) }}">Check 
results</a>
                       {% set completed_count = namespace(value=0) %}
                       {% set failed_count = namespace(value=0) %}
                       {% set active_count = namespace(value=0) %}
@@ -96,7 +95,7 @@
                         {% endif %}
                       {% endfor %}
 
-                      <div class="d-flex flex-wrap gap-2 mb-2">
+                      <div class="d-flex flex-wrap gap-2 mt-2 mb-3">
                         {% if completed_count.value > 0 %}<span class="badge 
bg-success">{{ completed_count.value }} Passed</span>{% endif %}
                         {% if failed_count.value > 0 %}
                           <span class="badge bg-danger">{{ failed_count.value 
}} {{ "Issue" if failed_count.value == 1 else "Issues" }}</span>
@@ -104,13 +103,20 @@
                         {% if active_count.value > 0 %}<span class="badge 
bg-info">{{ active_count.value }} Running</span>{% endif %}
                         {% if queued_count.value > 0 %}<span class="badge 
bg-secondary">{{ queued_count.value }} Pending</span>{% endif %}
                       </div>
-
-                      <a href="{{ url_for('root_files_checks', 
project_name=project_name, version_name=version_name, file_path=path) }}">
-                        View all check results
-                      </a>
                     {% else %}
+                      <a href="{{ url_for('root_files_tools', 
project_name=project_name, version_name=version_name, file_path=path) 
}}">Tools</a> ·
                       No check results
                     {% endif %}
+                    {% for warning in warnings[path] %}
+                      <div class="alert alert-warning p-1 px-2 mt-2 mb-2">
+                        <i class="fas fa-exclamation-triangle"></i> {{ warning 
}}
+                      </div>
+                    {% endfor %}
+                    {% for error in errors[path] %}
+                      <div class="alert alert-danger p-1 px-2 mt-2 mb-2">
+                        <i class="fas fa-exclamation-triangle"></i> {{ error }}
+                      </div>
+                    {% endfor %}
                   </td>
                 </tr>
               {% endfor %}
diff --git a/atr/templates/files-tools.html b/atr/templates/files-tools.html
new file mode 100644
index 0000000..25aac5e
--- /dev/null
+++ b/atr/templates/files-tools.html
@@ -0,0 +1,35 @@
+{% extends "layouts/base.html" %}
+
+{% block title %}
+  File tools ~ ATR
+{% endblock title %}
+
+{% block description %}
+  Manage a file in the candidate draft using tools.
+{% endblock description %}
+
+{% block content %}
+  <a href="{{ url_for('root_files_list', project_name=project_name, 
version_name=version_name) }}"
+     class="back-link">← Back to Files List</a>
+
+  <div class="p-3 mb-4 bg-light border rounded">
+    <h2 class="mt-0">File details</h2>
+    <p>
+      <strong>Filename:</strong> {{ file_data.filename }}
+    </p>
+    <p>
+      <strong>Size:</strong> {{ format_file_size(file_data.bytes_size) }}
+    </p>
+    <p class="mb-0">
+      <strong>Uploaded:</strong> {{ file_data.uploaded.strftime("%Y-%m-%d 
%H:%M UTC") }}
+    </p>
+  </div>
+
+  <h2>Tools</h2>
+  <h3>Delete file</h3>
+  <p>This tool deletes the file from the candidate draft.</p>
+  <form method="post"
+        action="{{ url_for('root_files_delete', project_name=project_name, 
version_name=version_name, file_path=file_path) }}">
+    <button type="submit" class="btn btn-danger" disabled>Delete file</button>
+  </form>
+{% endblock content %}


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

Reply via email to