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

tn 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 244640e  add slugify filter, create a common init method, add a modal 
dialog without confirm
244640e is described below

commit 244640edbf43efa7234afb73dc639fb64d2c2d1f
Author: Thomas Neidhart <[email protected]>
AuthorDate: Tue Apr 1 09:46:35 2025 +0200

    add slugify filter, create a common init method, add a modal dialog without 
confirm
---
 atr/filters.py                     | 26 +++++++++++++++++++++
 atr/server.py                      |  3 +++
 atr/static/js/atr.js               | 40 +++++++++++++++++++++++++++++++--
 atr/templates/draft-add.html       | 38 +++----------------------------
 atr/templates/draft-directory.html | 38 +++----------------------------
 atr/templates/draft-review.html    | 21 +++++++++++++----
 atr/templates/macros/dialog.html   | 46 ++++++++++++++++++++++++++++++++------
 7 files changed, 129 insertions(+), 83 deletions(-)

diff --git a/atr/filters.py b/atr/filters.py
new file mode 100644
index 0000000..e1dab48
--- /dev/null
+++ b/atr/filters.py
@@ -0,0 +1,26 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from typing import Any
+
+import asfquart.base as base
+
+
+def register_filters(app: base.QuartApp) -> None:
+    @app.template_filter("slugify")
+    def slugify(value: Any) -> str:
+        return str(value).lower().replace(" ", "-").replace("_", 
"-").replace("/", "-").replace(".", "-")
diff --git a/atr/server.py b/atr/server.py
index cac3c7f..e62d89b 100644
--- a/atr/server.py
+++ b/atr/server.py
@@ -40,6 +40,7 @@ import atr.preload as preload
 import atr.ssh as ssh
 import atr.user as user
 import atr.util as util
+from atr.filters import register_filters
 
 # TODO: Technically this is a global variable
 # We should probably find a cleaner way to do this
@@ -200,6 +201,8 @@ def create_app(app_config: type[config.AppConfig]) -> 
base.QuartApp:
     register_routes(app)
     blueprints.register(app)
 
+    register_filters(app)
+
     config_mode = config.get_mode()
 
     app_setup_context(app)
diff --git a/atr/static/js/atr.js b/atr/static/js/atr.js
index 5582be2..b194273 100644
--- a/atr/static/js/atr.js
+++ b/atr/static/js/atr.js
@@ -1,4 +1,40 @@
+function init() {
+    document.addEventListener("DOMContentLoaded", function () {
+        const copyButtons = document.querySelectorAll(".atr-copy-btn");
+
+        copyButtons.forEach(button => {
+            button.addEventListener("click", function () {
+                const targetId = this.getAttribute("data-clipboard-target");
+                const targetElement = document.querySelector(targetId);
+
+                if (targetElement) {
+                    const textToCopy = targetElement.textContent;
+
+                    navigator.clipboard.writeText(textToCopy)
+                        .then(() => {
+                            const originalText = this.innerHTML;
+                            this.innerHTML = '<i class="bi bi-check2"></i> 
Copied!';
+
+                            // Reset the button text after 2000ms
+                            setTimeout(() => {
+                                this.innerHTML = originalText;
+                            }, 2000);
+                        })
+                        .catch(err => {
+                            console.error("Failed to copy: ", err);
+                            this.innerHTML = '<i class="bi 
bi-exclamation-triangle"></i> Failed!';
+
+                            setTimeout(() => {
+                                this.innerHTML = '<i class="bi 
bi-clipboard"></i> Copy';
+                            }, 2000);
+                        });
+                }
+            });
+        });
+    });
+}
+
 function updateDeleteButton(inputElement, buttonId) {
-  let button = document.getElementById(buttonId);
-  button.disabled = inputElement.value !== "DELETE";
+    let button = document.getElementById(buttonId);
+    button.disabled = inputElement.value !== "DELETE";
 }
diff --git a/atr/templates/draft-add.html b/atr/templates/draft-add.html
index 259c9dd..ca91333 100644
--- a/atr/templates/draft-add.html
+++ b/atr/templates/draft-add.html
@@ -50,10 +50,10 @@
             </div>
             <div class="card-footer bg-light border-1 pt-4 pb-4 
position-relative">
               <button class="btn btn-sm btn-outline-secondary atr-copy-btn 
fs-6 position-absolute top-0 end-0 m-2"
-                      data-clipboard-target="#cmd-newdraft-{{ 
project.name|replace('.', '-') }}">
+                      data-clipboard-target="#cmd-newdraft-{{ 
project.name|slugify }}">
                 <i class="bi bi-clipboard"></i> Copy
               </button>
-              <pre class="small mb-0" id="cmd-newdraft-{{ 
project.name|replace('.', '-') }}">rsync -av -e 'ssh -p 2222' your/files/ \
+              <pre class="small mb-0" id="cmd-newdraft-{{ project.name|slugify 
}}">rsync -av -e 'ssh -p 2222' your/files/ \
     {{ asf_id }}@{{ server_domain }}:/{{ project.name }}/VERSION/</pre>
             </div>
           </div>
@@ -125,38 +125,6 @@
     {% block javascripts %}
       {{ super() }}
       <script>
-          document.addEventListener("DOMContentLoaded", function() {
-              const copyButtons = document.querySelectorAll(".atr-copy-btn");
-
-              copyButtons.forEach(button => {
-                  button.addEventListener("click", function() {
-                      const targetId = 
this.getAttribute("data-clipboard-target");
-                      const targetElement = document.querySelector(targetId);
-
-                      if (targetElement) {
-                          const textToCopy = targetElement.textContent;
-
-                          navigator.clipboard.writeText(textToCopy)
-                              .then(() => {
-                                  const originalText = this.innerHTML;
-                                  this.innerHTML = '<i class="bi 
bi-check2"></i> Copied!';
-
-                                  // Reset the button text after 2000ms
-                                  setTimeout(() => {
-                                      this.innerHTML = originalText;
-                                  }, 2000);
-                              })
-                              .catch(err => {
-                                  console.error("Failed to copy: ", err);
-                                  this.innerHTML = '<i class="bi 
bi-exclamation-triangle"></i> Failed!';
-
-                                  setTimeout(() => {
-                                      this.innerHTML = '<i class="bi 
bi-clipboard"></i> Copy';
-                                  }, 2000);
-                              });
-                      }
-                  });
-              });
-          });
+          init();
       </script>
     {% endblock javascripts %}
diff --git a/atr/templates/draft-directory.html 
b/atr/templates/draft-directory.html
index 6a32c75..a744d48 100644
--- a/atr/templates/draft-directory.html
+++ b/atr/templates/draft-directory.html
@@ -56,10 +56,10 @@
           </div>
           <div class="card-footer bg-light border-1 pt-4 pb-4 
position-relative">
             <button class="btn btn-sm btn-outline-secondary atr-copy-btn fs-6 
position-absolute top-0 end-0 m-2"
-                    data-clipboard-target="#cmd-{{ release.name|replace('.', 
'-') }}">
+                    data-clipboard-target="#cmd-{{ release.name|slugify }}">
               <i class="bi bi-clipboard"></i> Copy
             </button>
-            <pre class="small mb-0" id="cmd-{{ release.name|replace('.', '-') 
}}">rsync -av -e 'ssh -p 2222' your/files/ \
+            <pre class="small mb-0" id="cmd-{{ release.name|slugify }}">rsync 
-av -e 'ssh -p 2222' your/files/ \
     {{ asf_id }}@{{ server_domain }}:/{{ release.project.name }}/{{ 
release.version }}/</pre>
           </div>
         </div>
@@ -78,38 +78,6 @@
 {% block javascripts %}
   {{ super() }}
   <script>
-      document.addEventListener("DOMContentLoaded", function() {
-          const copyButtons = document.querySelectorAll(".atr-copy-btn");
-
-          copyButtons.forEach(button => {
-              button.addEventListener("click", function() {
-                  const targetId = this.getAttribute("data-clipboard-target");
-                  const targetElement = document.querySelector(targetId);
-
-                  if (targetElement) {
-                      const textToCopy = targetElement.textContent;
-
-                      navigator.clipboard.writeText(textToCopy)
-                          .then(() => {
-                              const originalText = this.innerHTML;
-                              this.innerHTML = '<i class="bi bi-check2"></i> 
Copied!';
-
-                              // Reset the button text after 2000ms
-                              setTimeout(() => {
-                                  this.innerHTML = originalText;
-                              }, 2000);
-                          })
-                          .catch(err => {
-                              console.error("Failed to copy: ", err);
-                              this.innerHTML = '<i class="bi 
bi-exclamation-triangle"></i> Failed!';
-
-                              setTimeout(() => {
-                                  this.innerHTML = '<i class="bi 
bi-clipboard"></i> Copy';
-                              }, 2000);
-                          });
-                  }
-              });
-          });
-      });
+      init();
   </script>
 {% endblock javascripts %}
diff --git a/atr/templates/draft-review.html b/atr/templates/draft-review.html
index 85181be..23f7bee 100644
--- a/atr/templates/draft-review.html
+++ b/atr/templates/draft-review.html
@@ -100,11 +100,11 @@
                        class="btn btn-sm btn-outline-primary fs-6 small 
ms-2">Review file</a>
                     <button class="btn btn-sm btn-outline-danger"
                             data-bs-toggle="modal"
-                            data-bs-target="#delete-{{ path }}">Delete 
file</button>
+                            data-bs-target="#delete-{{ path|slugify }}">Delete 
file</button>
                   </td>
                 </tr>
                 {% set file_id = path|string %}
-                {{ dialog.delete_modal_with_confirm(file_id, "Delete file", 
"file", as_url(routes.draft.delete_file, project_name=project_name, 
version_name=version_name) , delete_file_form, "file_path") }}
+                {{ dialog.delete_modal(file_id, "Delete file", "file", 
as_url(routes.draft.delete_file, project_name=project_name, 
version_name=version_name) , delete_file_form, "file_path") }}
               {% endfor %}
             </tbody>
           </table>
@@ -158,9 +158,22 @@
         <a href="{{ as_url(routes.draft.add_file, 
project_name=release.project.name, version_name=release.version) }}">Upload a 
file in the browser</a>, or use the command below to add or modify files in 
this release using rsync:
       </p>
     </div>
-    <pre class="card-footer bg-light border-1 pt-4 small">
+    <div class="card-footer bg-light border-1 pt-4 pb-4 position-relative">
+      <button class="btn btn-sm btn-outline-secondary atr-copy-btn fs-6 
position-absolute top-0 end-0 m-2"
+              data-clipboard-target="#cmd-newdraft-{{ 
release.project.name|slugify }}">
+        <i class="bi bi-clipboard"></i> Copy
+      </button>
+      <pre class="small mb-0" id="cmd-newdraft-{{ release.project.name|slugify 
}}">
 rsync -av -e 'ssh -p 2222' your/files/ \
     {{ asf_id }}@{{ server_domain }}:/{{ project_name }}/{{ version_name }}/
-    </pre>
+      </pre>
+    </div>
   </div>
 {% endblock content %}
+
+{% block javascripts %}
+  {{ super() }}
+  <script>
+      init();
+  </script>
+{% endblock javascripts %}
diff --git a/atr/templates/macros/dialog.html b/atr/templates/macros/dialog.html
index 07b9b92..22189dd 100644
--- a/atr/templates/macros/dialog.html
+++ b/atr/templates/macros/dialog.html
@@ -1,15 +1,16 @@
 {% macro delete_modal_with_confirm(id, title, item, action, form, field_name) 
%}
+  {% set element_id = id|slugify %}
   <div class="modal modal-lg fade"
-       id="delete-{{ id }}"
+       id="delete-{{ element_id }}"
        data-bs-backdrop="static"
        data-bs-keyboard="false"
        tabindex="-1"
-       aria-labelledby="delete-{{ id }}-label"
+       aria-labelledby="delete-{{ element_id }}-label"
        aria-hidden="true">
     <div class="modal-dialog border-primary">
       <div class="modal-content">
         <div class="modal-header bg-danger bg-opacity-10 text-danger">
-          <h1 class="modal-title fs-5" id="delete-{{ id }}-label">{{ title 
}}</h1>
+          <h1 class="modal-title fs-5" id="delete-{{ element_id }}-label">{{ 
title }}</h1>
           <button type="button"
                   class="btn-close"
                   data-bs-dismiss="modal"
@@ -21,19 +22,50 @@
             {{ form.hidden_tag() }}
             {{ form[field_name](value_=id, hidden=True) }}
             <div class="mb-3">
-              <label for="confirm_delete_{{ id }}" class="form-label">
+              <label for="confirm_delete_{{ element_id }}" class="form-label">
                 Type <strong>DELETE</strong> to confirm:
               </label>
               <input class="form-control mt-2"
-                     id="confirm_delete_{{ id }}"
+                     id="confirm_delete_{{ element_id }}"
                      name="confirm_delete"
                      placeholder="DELETE"
                      required=""
                      type="text"
                      value=""
-                     onkeyup="updateDeleteButton(this, 'delete-button-{{ id 
}}')" />
+                     onkeyup="updateDeleteButton(this, 'delete-button-{{ 
element_id }}')" />
             </div>
-            {{ form.submit(class_="btn btn-danger", id_="delete-button-" + id, 
disabled=True) }}
+            {{ form.submit(class_="btn btn-danger", id_="delete-button-" + 
element_id, disabled=True) }}
+          </form>
+        </div>
+      </div>
+    </div>
+  </div>
+{% endmacro %}
+
+{% macro delete_modal(id, title, item, action, form, field_name) %}
+  {% set element_id = id|slugify %}
+  <div class="modal modal-lg fade"
+       id="delete-{{ element_id }}"
+       data-bs-backdrop="static"
+       data-bs-keyboard="false"
+       tabindex="-1"
+       aria-labelledby="delete-{{ element_id }}-label"
+       aria-hidden="true">
+    <div class="modal-dialog border-primary">
+      <div class="modal-content">
+        <div class="modal-header bg-danger bg-opacity-10 text-danger">
+          <h1 class="modal-title fs-5" id="delete-{{ element_id }}-label">{{ 
title }}</h1>
+          <button type="button"
+                  class="btn-close"
+                  data-bs-dismiss="modal"
+                  aria-label="Close"></button>
+        </div>
+        <div class="modal-body">
+          <p class="text-muted mb-3">Warning: This action will permanently 
delete this {{ item }} and cannot be undone.</p>
+          <form method="post" action="{{ action }}">
+            {{ form.hidden_tag() }}
+            {{ form[field_name](value_=id, hidden=True) }}
+            {{ form.submit(class_="btn btn-danger", id_="delete-button-" + 
element_id) }}
           </form>
         </div>
       </div>


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

Reply via email to