This is an automated email from the ASF dual-hosted git repository. wave pushed a commit to branch precheck-djhtml in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
commit af20929d85aa713ee31ea8d7135f75c0849df989 Author: Dave Fisher <[email protected]> AuthorDate: Mon Dec 8 14:02:55 2025 -0800 Switch to djhtml from djLint --- .pre-commit-config.yaml | 35 +- atr/admin/templates/all-releases.html | 10 +- atr/admin/templates/data-browser.html | 94 ++--- atr/admin/templates/delete-release.html | 8 +- atr/admin/templates/ldap-lookup.html | 8 +- atr/admin/templates/performance.html | 156 ++++--- atr/admin/templates/tasks.html | 18 +- atr/admin/templates/toggle-admin-view.html | 6 +- atr/admin/templates/update-keys.html | 252 ++++++----- atr/admin/templates/update-projects.html | 254 ++++++------ atr/admin/templates/validation.html | 8 +- atr/policy/third-party-licenses.html | 2 +- atr/templates/about.html | 32 +- atr/templates/blank.html | 4 +- atr/templates/check-selected.html | 224 +++++----- atr/templates/committee-directory.html | 552 ++++++++++++------------- atr/templates/committee-view.html | 2 - atr/templates/delete-committee-keys.html | 2 - atr/templates/download-all.html | 2 - atr/templates/draft-tools.html | 4 +- atr/templates/error.html | 2 - atr/templates/includes/topnav.html | 642 ++++++++++++++--------------- atr/templates/index-committer.html | 32 +- atr/templates/index-public.html | 2 - atr/templates/layouts/base.html | 42 +- atr/templates/notfound.html | 2 - atr/templates/project-select.html | 2 - atr/templates/projects.html | 226 +++++----- atr/templates/release-select.html | 2 - atr/templates/releases-finished.html | 2 - atr/templates/releases.html | 18 +- atr/templates/report-selected-path.html | 172 ++++---- atr/templates/resolve-tabulated.html | 2 - atr/templates/tutorial.html | 12 +- atr/templates/user-ssh-keys.html | 2 +- 35 files changed, 1382 insertions(+), 1451 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5e8516f..cb65e96 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -49,22 +49,27 @@ repos: rev: v0.11.0.1 hooks: - id: shellcheck -- repo: https://github.com/Riverside-Healthcare/djLint - rev: v1.36.4 +- repo: https://github.com/rtts/djhtml + rev: 3.0.10 hooks: - - id: djlint - files: "atr/templates/.*\\.html$" - types_or: ['html'] - args: - - --profile=jinja - - --lint - - id: djlint - name: Format HTML templates - files: "atr/templates/.*\\.html$" - types_or: ['html'] - args: - - --profile=jinja - - --reformat + - id: djhtml + files: .*/.*\.html$ +#- repo: https://github.com/Riverside-Healthcare/djLint +# rev: v1.36.4 +# hooks: +# - id: djlint +# files: "atr/templates/.*\\.html$" +# types_or: ['html'] +# args: +# - --profile=jinja +# - --lint +# - id: djlint +# name: Format HTML templates +# files: "atr/templates/.*\\.html$" +# types_or: ['html'] +# args: +# - --profile=jinja +# - --reformat - repo: https://github.com/thibaudcolas/pre-commit-stylelint rev: v16.25.0 hooks: diff --git a/atr/admin/templates/all-releases.html b/atr/admin/templates/all-releases.html index 4b688da..6c93920 100644 --- a/atr/admin/templates/all-releases.html +++ b/atr/admin/templates/all-releases.html @@ -1,12 +1,8 @@ {% extends "layouts/base.html" %} -{% block title %} - All releases ~ ATR Admin -{% endblock title %} +{%- block title -%}All releases ~ ATR Admin{%- endblock title -%} -{% block description %} - View all releases across all stages and phases, for debugging. -{% endblock description %} +{%- block description -%}View all releases across all stages and phases, for debugging.{%- endblock description -%} {% block content %} <h1>All releases</h1> @@ -26,7 +22,7 @@ <tr> <td> {% if release.project %} - <a href="{{ release_as_url(release) }}">{{ release.name }}</a> + <a href="{{ release_as_url(release) }}">{{ release.name }}</a> {% else %} {{ release.name }} {% endif %} diff --git a/atr/admin/templates/data-browser.html b/atr/admin/templates/data-browser.html index ad09444..37045d2 100644 --- a/atr/admin/templates/data-browser.html +++ b/atr/admin/templates/data-browser.html @@ -1,66 +1,62 @@ {% extends "layouts/base-admin.html" %} -{% block title %} - Data browser ~ ATR -{% endblock title %} +{%- block title -%}Data browser ~ ATR{%- endblock title -%} -{% block description %} - Browse all records in the database. -{% endblock description %} +{%- block description -%}Browse all records in the database.{%- endblock description -%} {% block stylesheets %} {{ super() }} <style> - .page-model-nav { - margin: 1rem 0; - padding: 0.5rem; - background: #f5f5f5; - border-radius: 4px; - } + .page-model-nav { + margin: 1rem 0; + padding: 0.5rem; + background: #f5f5f5; + border-radius: 4px; + } - .page-model-nav a { - margin-right: 1rem; - padding: 0.25rem 0.5rem; - text-decoration: none; - color: #333; - } + .page-model-nav a { + margin-right: 1rem; + padding: 0.25rem 0.5rem; + text-decoration: none; + color: #333; + } - .page-model-nav a.active { - background: #333; - color: white; - border-radius: 2px; - } + .page-model-nav a.active { + background: #333; + color: white; + border-radius: 2px; + } - .page-record { - border: 1px solid #ddd; - padding: 1rem; - margin-bottom: 1rem; - border-radius: 4px; - } + .page-record { + border: 1px solid #ddd; + padding: 1rem; + margin-bottom: 1rem; + border-radius: 4px; + } - .page-record pre { - background: #f5f5f5; - padding: 0.5rem; - border-radius: 2px; - overflow-x: auto; - } + .page-record pre { + background: #f5f5f5; + padding: 0.5rem; + border-radius: 2px; + overflow-x: auto; + } - .page-record-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 0.5rem; - } + .page-record-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 0.5rem; + } - .page-record-meta { - color: #666; - font-size: 0.9em; - } + .page-record-meta { + color: #666; + font-size: 0.9em; + } - .page-no-records { - color: #666; - font-style: italic; - } + .page-no-records { + color: #666; + font-style: italic; + } </style> {% endblock stylesheets %} diff --git a/atr/admin/templates/delete-release.html b/atr/admin/templates/delete-release.html index 2e721a8..56cba07 100644 --- a/atr/admin/templates/delete-release.html +++ b/atr/admin/templates/delete-release.html @@ -1,12 +1,8 @@ {% extends "layouts/base.html" %} -{% block title %} - Delete release ~ ATR Admin -{% endblock title %} +{%- block title -%}Delete release ~ ATR Admin{%- endblock title -%} -{% block description %} - Permanently delete a release and all associated data. -{% endblock description %} +{%- block description -%}Permanently delete a release and all associated data.{%- endblock description -%} {% block content %} <h1>Delete release</h1> diff --git a/atr/admin/templates/ldap-lookup.html b/atr/admin/templates/ldap-lookup.html index 47bbe06..7278e96 100644 --- a/atr/admin/templates/ldap-lookup.html +++ b/atr/admin/templates/ldap-lookup.html @@ -1,12 +1,8 @@ {% extends "layouts/base-admin.html" %} -{% block title %} - LDAP lookup ~ ATR -{% endblock title %} +{%- block title -%}LDAP lookup ~ ATR{%- endblock title -%} -{% block description %} - Perform a lookup in the ASF LDAP directory. -{% endblock description %} +{%- block description -%}Perform a lookup in the ASF LDAP directory.{%- endblock description -%} {% block content %} <h1>LDAP lookup</h1> diff --git a/atr/admin/templates/performance.html b/atr/admin/templates/performance.html index a1f1d97..b5f49b2 100644 --- a/atr/admin/templates/performance.html +++ b/atr/admin/templates/performance.html @@ -1,88 +1,86 @@ {% extends "layouts/base-admin.html" %} -{% block title %} - Performance dashboard -{% endblock title %} +{%- block title -%}Performance dashboard{%- endblock title -%} {% block stylesheets %} {{ super() }} <style> - .page-performance-stats { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); - gap: 1rem; - margin: 1rem 0; - } - - .page-route-card { - background: #fff; - border-radius: 8px; - padding: 1rem; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - } - - .page-route-card.slow { - border-left: 4px solid #dc3545; - } - - .page-route-card.medium { - border-left: 4px solid #ffc107; - } - - .page-route-card.fast { - border-left: 4px solid #28a745; - } - - .page-route-card h3 { - margin: 0 0 0.5rem 0; - font-size: 1.1rem; - font-family: monospace; - } - - .page-route-meta { - display: flex; - gap: 1rem; - font-size: 0.9rem; - color: #666; - margin-bottom: 1rem; - } - - .page-timing-grid { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 1rem; - margin-bottom: 1rem; - } - - .page-timing-section h4 { - margin: 0 0 0.5rem 0; - font-size: 0.9rem; - color: #444; - } - - .page-timing-section dl { - margin: 0; - font-size: 0.85rem; - } - - .page-timing-section dt { - color: #666; - float: left; - clear: left; - margin-right: 0.5rem; - } - - .page-timing-section dd { - margin: 0; - font-family: monospace; - } - - .page-last-seen { - font-size: 0.8rem; - color: #666; - border-top: 1px solid #eee; - padding-top: 0.5rem; - } + .page-performance-stats { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 1rem; + margin: 1rem 0; + } + + .page-route-card { + background: #fff; + border-radius: 8px; + padding: 1rem; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + } + + .page-route-card.slow { + border-left: 4px solid #dc3545; + } + + .page-route-card.medium { + border-left: 4px solid #ffc107; + } + + .page-route-card.fast { + border-left: 4px solid #28a745; + } + + .page-route-card h3 { + margin: 0 0 0.5rem 0; + font-size: 1.1rem; + font-family: monospace; + } + + .page-route-meta { + display: flex; + gap: 1rem; + font-size: 0.9rem; + color: #666; + margin-bottom: 1rem; + } + + .page-timing-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 1rem; + margin-bottom: 1rem; + } + + .page-timing-section h4 { + margin: 0 0 0.5rem 0; + font-size: 0.9rem; + color: #444; + } + + .page-timing-section dl { + margin: 0; + font-size: 0.85rem; + } + + .page-timing-section dt { + color: #666; + float: left; + clear: left; + margin-right: 0.5rem; + } + + .page-timing-section dd { + margin: 0; + font-family: monospace; + } + + .page-last-seen { + font-size: 0.8rem; + color: #666; + border-top: 1px solid #eee; + padding-top: 0.5rem; + } </style> {% endblock stylesheets %} diff --git a/atr/admin/templates/tasks.html b/atr/admin/templates/tasks.html index b934a48..3a72def 100644 --- a/atr/admin/templates/tasks.html +++ b/atr/admin/templates/tasks.html @@ -1,8 +1,6 @@ {% extends "layouts/base-admin.html" %} -{% block title %} - Executed Tasks ~ ATR -{% endblock %} +{%- block title -%}Executed Tasks ~ ATR{%- endblock -%} {% block stylesheets %} {{ super() }} @@ -11,7 +9,7 @@ <style> .gridjs-pages button { - color: unset; + color: unset; } </style> {% endblock stylesheets %} @@ -30,16 +28,16 @@ new gridjs.Grid({ columns: [ { - name: 'ID', - width: '40px' + name: 'ID', + width: '40px' }, { - name: 'Task Type', - width: '140px' + name: 'Task Type', + width: '140px' }, { - name: 'Task Status', - width: '60px' + name: 'Task Status', + width: '60px' }, { name: 'Added', diff --git a/atr/admin/templates/toggle-admin-view.html b/atr/admin/templates/toggle-admin-view.html index 2dd7bf9..6d2b594 100644 --- a/atr/admin/templates/toggle-admin-view.html +++ b/atr/admin/templates/toggle-admin-view.html @@ -1,10 +1,8 @@ {% extends "layouts/base-admin.html" %} -{% block title %}Toggle admin view{% endblock title %} +{%- block title -%}Toggle admin view{%- endblock title -%} -{% block description %} - Switch between administrator and regular user views. -{% endblock description %} +{%- block description -%}Switch between administrator and regular user views.{%- endblock description -%} {% block content %} <h1>Toggle admin view</h1> diff --git a/atr/admin/templates/update-keys.html b/atr/admin/templates/update-keys.html index 2184c12..6fd31b6 100644 --- a/atr/admin/templates/update-keys.html +++ b/atr/admin/templates/update-keys.html @@ -1,152 +1,148 @@ {% extends "layouts/base-admin.html" %} -{% block title %} - Update keys ~ ATR -{% endblock title %} +{%- block title -%}Update keys ~ ATR{%- endblock title -%} -{% block description %} - Update keys from remote data sources. -{% endblock description %} +{%- block description -%}Update keys from remote data sources.{%- endblock description -%} {% block stylesheets %} - {{ super() }} - <style> - .page-form-group { - margin-bottom: 1rem; - } - - button { - margin-top: 1rem; - padding: 0.5rem 1rem; - background: #036; - color: white; - border: none; - border-radius: 4px; - cursor: pointer; - font-weight: 500; - } - - button:hover { - background: #047; - } - - button:disabled { - color: gray; - } - - .page-warning { - margin: 1.5rem 0; - padding: 1rem; - background: #fff3cd; - border: 1px solid #ffeeba; - border-radius: 4px; - color: #856404; - } - - .page-warning p:last-child { - margin-bottom: 0; - } - - .page-warning strong { - color: #533f03; - } - - .page-status-message { - margin: 1.5rem 0; - padding: 1rem; - border-radius: 4px; - } - - .page-status-message.success { - background: #d4edda; - border: 1px solid #c3e6cb; - color: #155724; - } - - .page-status-message.error { - background: #f8d7da; - border: 1px solid #f5c6cb; - color: #721c24; - } - </style> + {{ super() }} + <style> + .page-form-group { + margin-bottom: 1rem; + } + + button { + margin-top: 1rem; + padding: 0.5rem 1rem; + background: #036; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-weight: 500; + } + + button:hover { + background: #047; + } + + button:disabled { + color: gray; + } + + .page-warning { + margin: 1.5rem 0; + padding: 1rem; + background: #fff3cd; + border: 1px solid #ffeeba; + border-radius: 4px; + color: #856404; + } + + .page-warning p:last-child { + margin-bottom: 0; + } + + .page-warning strong { + color: #533f03; + } + + .page-status-message { + margin: 1.5rem 0; + padding: 1rem; + border-radius: 4px; + } + + .page-status-message.success { + background: #d4edda; + border: 1px solid #c3e6cb; + color: #155724; + } + + .page-status-message.error { + background: #f8d7da; + border: 1px solid #f5c6cb; + color: #721c24; + } + </style> {% endblock stylesheets %} {% block content %} - <h1>Update keys</h1> - <p> - This page allows you to update keys in the database from remote data sources. - </p> - - <div class="page-warning"> + <h1>Update keys</h1> <p> - <strong>Note:</strong> This operation will update all keys from remote KEYS files. + This page allows you to update keys in the database from remote data sources. </p> - </div> - <div id="status"></div> + <div class="page-warning"> + <p> + <strong>Note:</strong> This operation will update all keys from remote KEYS files. + </p> + </div> - {{ empty_form }} + <div id="status"></div> - {% if previous_output %} - <h2>Previous output</h2> - <pre>{{ previous_output }}</pre> - {% endif %} + {{ empty_form }} - <script> - document.addEventListener('DOMContentLoaded', () => { - const form = document.querySelector('form'); - const button = form.querySelector('button[type="submit"]'); + {% if previous_output %} + <h2>Previous output</h2> + <pre>{{ previous_output }}</pre> + {% endif %} - form.addEventListener('submit', async (e) => { - e.preventDefault(); + <script> + document.addEventListener('DOMContentLoaded', () => { + const form = document.querySelector('form'); + const button = form.querySelector('button[type="submit"]'); - button.disabled = true; - document.body.style.cursor = "wait"; + form.addEventListener('submit', async (e) => { + e.preventDefault(); - const statusElement = document.getElementById("status"); - while (statusElement.firstChild) { - statusElement.firstChild.remove(); - } + button.disabled = true; + document.body.style.cursor = "wait"; - const csrfToken = document.querySelector("input[name='csrf_token']").value; + const statusElement = document.getElementById("status"); + while (statusElement.firstChild) { + statusElement.firstChild.remove(); + } - try { - const response = await fetch(window.location.href, { - method: "POST", - headers: { - "X-CSRFToken": csrfToken + const csrfToken = document.querySelector("input[name='csrf_token']").value; + + try { + const response = await fetch(window.location.href, { + method: "POST", + headers: { + "X-CSRFToken": csrfToken + } + }); + + if (!response.ok) { + addStatusMessage(statusElement, "Could not make network request", "error"); + return + } + + const data = await response.json(); + addStatusMessage(statusElement, data.message, data.category) + } catch (error) { + addStatusMessage(statusElement, error, "error") + } finally { + button.disabled = false; + document.body.style.cursor = "default"; } }); - - if (!response.ok) { - addStatusMessage(statusElement, "Could not make network request", "error"); - return + }); + + function addStatusMessage(parentElement, message, category) { + const divElement = document.createElement("div"); + divElement.classList.add("page-status-message"); + divElement.classList.add(category); + if (category === "error") { + const prefixElement = document.createElement("strong"); + const textElement = document.createTextNode("Error: "); + prefixElement.appendChild(textElement); + divElement.appendChild(prefixElement); } - - const data = await response.json(); - addStatusMessage(statusElement, data.message, data.category) - } catch (error) { - addStatusMessage(statusElement, error, "error") - } finally { - button.disabled = false; - document.body.style.cursor = "default"; + const textNode = document.createTextNode(message); + divElement.appendChild(textNode); + parentElement.appendChild(divElement); } - }); - }); - - function addStatusMessage(parentElement, message, category) { - const divElement = document.createElement("div"); - divElement.classList.add("page-status-message"); - divElement.classList.add(category); - if (category === "error") { - const prefixElement = document.createElement("strong"); - const textElement = document.createTextNode("Error: "); - prefixElement.appendChild(textElement); - divElement.appendChild(prefixElement); - } - const textNode = document.createTextNode(message); - divElement.appendChild(textNode); - parentElement.appendChild(divElement); - } - </script> + </script> {% endblock content %} diff --git a/atr/admin/templates/update-projects.html b/atr/admin/templates/update-projects.html index a0f73cc..dcda398 100644 --- a/atr/admin/templates/update-projects.html +++ b/atr/admin/templates/update-projects.html @@ -1,152 +1,148 @@ {% extends "layouts/base-admin.html" %} -{% block title %} - Update projects ~ ATR -{% endblock title %} +{%- block title -%}Update projects ~ ATR{%- endblock title -%} -{% block description %} - Update PMCs and podlings from remote data sources. -{% endblock description %} +{%- block description -%}Update PMCs and podlings from remote data sources.{%- endblock description -%} {% block stylesheets %} - {{ super() }} - <style> - .page-form-group { - margin-bottom: 1rem; - } - - button { - margin-top: 1rem; - padding: 0.5rem 1rem; - background: #036; - color: white; - border: none; - border-radius: 4px; - cursor: pointer; - font-weight: 500; - } - - button:hover { - background: #047; - } - - button:disabled { - color: gray; - } - - .page-warning { - margin: 1.5rem 0; - padding: 1rem; - background: #fff3cd; - border: 1px solid #ffeeba; - border-radius: 4px; - color: #856404; - } - - .page-warning p:last-child { - margin-bottom: 0; - } - - .page-warning strong { - color: #533f03; - } - - .page-status-message { - margin: 1.5rem 0; - padding: 1rem; - border-radius: 4px; - } - - .page-status-message.success { - background: #d4edda; - border: 1px solid #c3e6cb; - color: #155724; - } - - .page-status-message.error { - background: #f8d7da; - border: 1px solid #f5c6cb; - color: #721c24; - } - </style> + {{ super() }} + <style> + .page-form-group { + margin-bottom: 1rem; + } + + button { + margin-top: 1rem; + padding: 0.5rem 1rem; + background: #036; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-weight: 500; + } + + button:hover { + background: #047; + } + + button:disabled { + color: gray; + } + + .page-warning { + margin: 1.5rem 0; + padding: 1rem; + background: #fff3cd; + border: 1px solid #ffeeba; + border-radius: 4px; + color: #856404; + } + + .page-warning p:last-child { + margin-bottom: 0; + } + + .page-warning strong { + color: #533f03; + } + + .page-status-message { + margin: 1.5rem 0; + padding: 1rem; + border-radius: 4px; + } + + .page-status-message.success { + background: #d4edda; + border: 1px solid #c3e6cb; + color: #155724; + } + + .page-status-message.error { + background: #f8d7da; + border: 1px solid #f5c6cb; + color: #721c24; + } + </style> {% endblock stylesheets %} {% block content %} - <h1>Update projects</h1> - <p> - This page allows you to update PMC and podling information in the database from remote data sources. - </p> - - <div class="page-warning"> + <h1>Update projects</h1> <p> - <strong>Note:</strong> This operation will update all project information, including: + This page allows you to update PMC and podling information in the database from remote data sources. </p> - <ul> - <li>PMC member lists and release manager assignments</li> - <li>Podling status and basic information</li> - <li>Project metadata and relationships</li> - </ul> - </div> - <div id="status"></div> + <div class="page-warning"> + <p> + <strong>Note:</strong> This operation will update all project information, including: + </p> + <ul> + <li>PMC member lists and release manager assignments</li> + <li>Podling status and basic information</li> + <li>Project metadata and relationships</li> + </ul> + </div> - {{ empty_form }} + <div id="status"></div> - <script> - document.addEventListener('DOMContentLoaded', () => { - const form = document.querySelector('form'); - const button = form.querySelector('button[type="submit"]'); + {{ empty_form }} - form.addEventListener('submit', async (e) => { - e.preventDefault(); + <script> + document.addEventListener('DOMContentLoaded', () => { + const form = document.querySelector('form'); + const button = form.querySelector('button[type="submit"]'); - button.disabled = true; - document.body.style.cursor = "wait"; + form.addEventListener('submit', async (e) => { + e.preventDefault(); - const statusElement = document.getElementById("status"); - while (statusElement.firstChild) { - statusElement.firstChild.remove(); - } + button.disabled = true; + document.body.style.cursor = "wait"; - const csrfToken = document.querySelector("input[name='csrf_token']").value; + const statusElement = document.getElementById("status"); + while (statusElement.firstChild) { + statusElement.firstChild.remove(); + } - try { - const response = await fetch(window.location.href, { - method: "POST", - headers: { - "X-CSRFToken": csrfToken + const csrfToken = document.querySelector("input[name='csrf_token']").value; + + try { + const response = await fetch(window.location.href, { + method: "POST", + headers: { + "X-CSRFToken": csrfToken + } + }); + + if (!response.ok) { + addStatusMessage(statusElement, "Could not make network request", "error"); + return + } + + const data = await response.json(); + addStatusMessage(statusElement, data.message, data.category) + } catch (error) { + addStatusMessage(statusElement, error, "error") + } finally { + button.disabled = false; + document.body.style.cursor = "default"; } }); - - if (!response.ok) { - addStatusMessage(statusElement, "Could not make network request", "error"); - return + }); + + function addStatusMessage(parentElement, message, category) { + const divElement = document.createElement("div"); + divElement.classList.add("page-status-message"); + divElement.classList.add(category); + if (category === "error") { + const prefixElement = document.createElement("strong"); + const textElement = document.createTextNode("Error: "); + prefixElement.appendChild(textElement); + divElement.appendChild(prefixElement); } - - const data = await response.json(); - addStatusMessage(statusElement, data.message, data.category) - } catch (error) { - addStatusMessage(statusElement, error, "error") - } finally { - button.disabled = false; - document.body.style.cursor = "default"; + const textNode = document.createTextNode(message); + divElement.appendChild(textNode); + parentElement.appendChild(divElement); } - }); - }); - - function addStatusMessage(parentElement, message, category) { - const divElement = document.createElement("div"); - divElement.classList.add("page-status-message"); - divElement.classList.add(category); - if (category === "error") { - const prefixElement = document.createElement("strong"); - const textElement = document.createTextNode("Error: "); - prefixElement.appendChild(textElement); - divElement.appendChild(prefixElement); - } - const textNode = document.createTextNode(message); - divElement.appendChild(textNode); - parentElement.appendChild(divElement); - } - </script> + </script> {% endblock content %} diff --git a/atr/admin/templates/validation.html b/atr/admin/templates/validation.html index a57ea85..79ef7aa 100644 --- a/atr/admin/templates/validation.html +++ b/atr/admin/templates/validation.html @@ -1,12 +1,8 @@ {% extends "layouts/base.html" %} -{% block title %} - Validation ~ ATR Admin -{% endblock title %} +{%- block title -%}Validation ~ ATR Admin{%- endblock title -%} -{% block description %} - Results of running server data validators. -{% endblock description %} +{%- block description -%}Results of running server data validators.{%- endblock description -%} {% block content %} <h1>Validation</h1> diff --git a/atr/policy/third-party-licenses.html b/atr/policy/third-party-licenses.html index 12b6099..8f9932c 100644 --- a/atr/policy/third-party-licenses.html +++ b/atr/policy/third-party-licenses.html @@ -1,5 +1,5 @@ <p>Title: ASF 3rd Party License Policy -license: https://www.apache.org/licenses/LICENSE-2.0</p> + license: https://www.apache.org/licenses/LICENSE-2.0</p> <p>[TOC]</p> <h2>Purpose {#audience}</h2> <p>This policy provides licensing guidance to Apache Software Foundation projects. It identifies the acceptable diff --git a/atr/templates/about.html b/atr/templates/about.html index 3e11f82..6aa969d 100644 --- a/atr/templates/about.html +++ b/atr/templates/about.html @@ -1,32 +1,30 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}About ATR ~ ATR{%- endblock title -%} {%- block description -%}About ATR ~ ATR{%- endblock description -%} -{# djlint:on #} {% block stylesheets %} {{ super() }} <style> - img { - border: 1px solid #cccccc; - box-shadow: 0 0 1rem rgba(0, 0, 0, 0.2); - margin: 1rem 0; - max-width: 50%; - } + img { + border: 1px solid #cccccc; + box-shadow: 0 0 1rem rgba(0, 0, 0, 0.2); + margin: 1rem 0; + max-width: 50%; + } - table { - border: 1px solid #eeeeee; - } + table { + border: 1px solid #eeeeee; + } - th.step { - width: 15%; - } + th.step { + width: 15%; + } - td { - width: 28.333%; - } + td { + width: 28.333%; + } </style> {% endblock stylesheets %} diff --git a/atr/templates/blank.html b/atr/templates/blank.html index 68d47d6..0994483 100644 --- a/atr/templates/blank.html +++ b/atr/templates/blank.html @@ -1,10 +1,8 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}{{ title }} ~ ATR{%- endblock title -%} {%- block description -%}{{ description }}{%- endblock description -%} -{# djlint:on #} {% block content %} {{ content }} @@ -17,5 +15,5 @@ {% endif %} {% if init_js %}<script> init(); -</script>{% endif %} + </script>{% endif %} {% endblock javascripts %} diff --git a/atr/templates/check-selected.html b/atr/templates/check-selected.html index 5884761..8ae75d3 100644 --- a/atr/templates/check-selected.html +++ b/atr/templates/check-selected.html @@ -1,42 +1,40 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}{{ release.project.display_name }} {{ version_name }} ~ ATR{%- endblock title -%} {%- block description -%}Review page for the {{ release.project.display_name }} {{ version_name }} candidate{%- endblock description -%} -{# djlint:on #} {% import 'macros/dialog.html' as dialog %} {% block stylesheets %} {{ super() }} <style> - .page-table-striped-odd { - background-color: #eeeeee; + .page-table-striped-odd { + background-color: #eeeeee; + } + + .page-icon-cell { + width: 2em; + text-align: center; + } + + table tr { + border-bottom: none; + } + + #poll-progress-container { + height: 6px; + } + + @keyframes poll-grow { + from { + width: 0%; } - .page-icon-cell { - width: 2em; - text-align: center; - } - - table tr { - border-bottom: none; - } - - #poll-progress-container { - height: 6px; - } - - @keyframes poll-grow { - from { - width: 0%; - } - - to { - width: 100%; - } + to { + width: 100%; } + } </style> {% endblock stylesheets %} @@ -200,106 +198,106 @@ {% block javascripts %} {{ super() }} <script> - init(); + init(); - (function() { - const banner = document.getElementById("ongoing-tasks-banner"); - if (!banner) return; + (function() { + const banner = document.getElementById("ongoing-tasks-banner"); + if (!banner) return; - const apiUrl = banner.dataset.apiUrl; - if (!apiUrl) return; + const apiUrl = banner.dataset.apiUrl; + if (!apiUrl) return; - const countSpan = document.getElementById("ongoing-tasks-count"); - const textSpan = document.getElementById("ongoing-tasks-text"); - const voteButton = document.getElementById("start-vote-button"); - const progress = document.getElementById("poll-progress"); - const pollInterval = 3000; + const countSpan = document.getElementById("ongoing-tasks-count"); + const textSpan = document.getElementById("ongoing-tasks-text"); + const voteButton = document.getElementById("start-vote-button"); + const progress = document.getElementById("poll-progress"); + const pollInterval = 3000; - let currentCount = parseInt(countSpan?.textContent || "0", 10); - if (currentCount === 0) return; + let currentCount = parseInt(countSpan?.textContent || "0", 10); + if (currentCount === 0) return; - function restartProgress() { - if (!progress) return; - progress.style.animation = "none"; - progress.offsetHeight; - progress.style.animation = `poll-grow ${pollInterval}ms linear forwards`; - } + function restartProgress() { + if (!progress) return; + progress.style.animation = "none"; + progress.offsetHeight; + progress.style.animation = `poll-grow ${pollInterval}ms linear forwards`; + } - function updateBanner(count) { - if (!countSpan || !textSpan) return; + function updateBanner(count) { + if (!countSpan || !textSpan) return; - currentCount = count; - countSpan.textContent = count; + currentCount = count; + countSpan.textContent = count; - const taskWord = count === 1 ? "task" : "tasks"; - const isAre = count === 1 ? "is" : "are"; + const taskWord = count === 1 ? "task" : "tasks"; + const isAre = count === 1 ? "is" : "are"; // TODO: Migrate away from setting innerHTML - textSpan.innerHTML = `There ${isAre} currently <strong id="ongoing-tasks-count">${count}</strong> background verification ${taskWord} running for the latest revision. Results shown below may be incomplete or outdated until the tasks finish.`; + textSpan.innerHTML = `There ${isAre} currently <strong id="ongoing-tasks-count">${count}</strong> background verification ${taskWord} running for the latest revision. Results shown below may be incomplete or outdated until the tasks finish.`; - if (count === 0) { + if (count === 0) { // Banner always exists, but we hide it - banner.classList.add("d-none"); - enableVoteButton(); - } - } - - function enableVoteButton() { - if (!voteButton) return; - if (!voteButton.classList.contains("disabled")) return; - - const voteHref = voteButton.dataset.voteHref || voteButton.getAttribute("href"); - if (!voteHref || voteHref === "#") return; - - voteButton.classList.remove("disabled"); - voteButton.removeAttribute("aria-disabled"); - voteButton.removeAttribute("tabindex"); - voteButton.removeAttribute("role"); - voteButton.setAttribute("href", voteHref); - voteButton.setAttribute("title", "Start a vote on this draft"); - } - - function pollOngoingTasks() { - if (currentCount === 0) return; - - if (progress) { - progress.style.animation = "none"; - progress.style.width = "100%"; - progress.classList.remove("bg-warning"); - progress.classList.add("bg-info", "progress-bar-striped", "progress-bar-animated"); - } - fetch(apiUrl) - .then(response => { - if (!response.ok) throw new Error(`HTTP ${response.status}`); - return response.json(); - }) - .then(data => { - if (progress) { - progress.classList.remove("bg-info", "progress-bar-striped", "progress-bar-animated"); - progress.classList.add("bg-warning"); - } - const newCount = data.ongoing || 0; - if (newCount !== currentCount) { - updateBanner(newCount); - } - if (newCount > 0) { - restartProgress(); - setTimeout(pollOngoingTasks, pollInterval); - } - }) - .catch(error => { - console.error("Error polling ongoing tasks:", error); - if (progress) { - progress.classList.remove("bg-info", "progress-bar-striped", "progress-bar-animated"); - progress.classList.add("bg-warning"); - } - restartProgress(); + banner.classList.add("d-none"); + enableVoteButton(); + } + } + + function enableVoteButton() { + if (!voteButton) return; + if (!voteButton.classList.contains("disabled")) return; + + const voteHref = voteButton.dataset.voteHref || voteButton.getAttribute("href"); + if (!voteHref || voteHref === "#") return; + + voteButton.classList.remove("disabled"); + voteButton.removeAttribute("aria-disabled"); + voteButton.removeAttribute("tabindex"); + voteButton.removeAttribute("role"); + voteButton.setAttribute("href", voteHref); + voteButton.setAttribute("title", "Start a vote on this draft"); + } + + function pollOngoingTasks() { + if (currentCount === 0) return; + + if (progress) { + progress.style.animation = "none"; + progress.style.width = "100%"; + progress.classList.remove("bg-warning"); + progress.classList.add("bg-info", "progress-bar-striped", "progress-bar-animated"); + } + fetch(apiUrl) + .then(response => { + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); + }) + .then(data => { + if (progress) { + progress.classList.remove("bg-info", "progress-bar-striped", "progress-bar-animated"); + progress.classList.add("bg-warning"); + } + const newCount = data.ongoing || 0; + if (newCount !== currentCount) { + updateBanner(newCount); + } + if (newCount > 0) { + restartProgress(); + setTimeout(pollOngoingTasks, pollInterval); + } + }) + .catch(error => { + console.error("Error polling ongoing tasks:", error); + if (progress) { + progress.classList.remove("bg-info", "progress-bar-striped", "progress-bar-animated"); + progress.classList.add("bg-warning"); + } + restartProgress(); // Double the interval when there's an error - setTimeout(pollOngoingTasks, pollInterval * 2); - }); - } + setTimeout(pollOngoingTasks, pollInterval * 2); + }); + } - restartProgress(); - setTimeout(pollOngoingTasks, pollInterval); - })(); + restartProgress(); + setTimeout(pollOngoingTasks, pollInterval); + })(); </script> {% endblock javascripts %} diff --git a/atr/templates/committee-directory.html b/atr/templates/committee-directory.html index 81157ae..23c9e58 100644 --- a/atr/templates/committee-directory.html +++ b/atr/templates/committee-directory.html @@ -1,325 +1,323 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}Committee directory ~ ATR{%- endblock title -%} {%- block description -%}List of all ASF committees and their assated projects.{%- endblock description -%} -{# djlint:on #} {% block stylesheets %} - {{ super() }} - <style> - .page-committee-title-link:hover { - cursor: pointer; - } + {{ super() }} + <style> + .page-committee-title-link:hover { + cursor: pointer; + } - .page-logo { - max-height: 100%; - width: auto; - object-fit: contain; - } + .page-logo { + max-height: 100%; + width: auto; + object-fit: contain; + } - .page-logo-container { - height: 48px; - width: 100%; - display: flex; - justify-content: center; - align-items: center; - } + .page-logo-container { + height: 48px; + width: 100%; + display: flex; + justify-content: center; + align-items: center; + } - .page-project-subcard { - min-height: 96px; - background-color: #f8f9fa; - } + .page-project-subcard { + min-height: 96px; + background-color: #f8f9fa; + } - .page-project-subcard:hover { - border-color: gray; - cursor: pointer; - } + .page-project-subcard:hover { + border-color: gray; + cursor: pointer; + } - .page-project-subcard-categories { - font-size: 0.8em; - } + .page-project-subcard-categories { + font-size: 0.8em; + } - .page-project-inactive { - opacity: 0.6; - } - </style> + .page-project-inactive { + opacity: 0.6; + } + </style> {% endblock stylesheets %} {% block content %} - <h1>Committee directory</h1> - <p>Current ASF committees and their projects:</p> + <h1>Committee directory</h1> + <p>Current ASF committees and their projects:</p> - <div class="mb-3"> - <input type="text" - id="project-filter" - aria-label="Project name filter" - class="form-control d-inline-block w-auto" /> - <button type="button" class="btn btn-primary" id="filter-button">Filter all</button> - {% if current_user %} - <button type="button" - class="btn btn-secondary ms-2" - id="filter-participant-button" - aria-pressed="false" - data-showing="participant"> + <div class="mb-3"> + <input type="text" + id="project-filter" + aria-label="Project name filter" + class="form-control d-inline-block w-auto" /> + <button type="button" class="btn btn-primary" id="filter-button">Filter all</button> {% if current_user %} - Show all committees - {% else %} - Show my committees + <button type="button" + class="btn btn-secondary ms-2" + id="filter-participant-button" + aria-pressed="false" + data-showing="participant"> + {% if current_user %} + Show all committees + {% else %} + Show my committees + {% endif %} + </button> {% endif %} - </button> - {% endif %} - </div> + </div> - <div class="mb-3"> - <p> - Total count: <span id="committee-count">{{ committees|length }}</span> - </p> - </div> + <div class="mb-3"> + <p> + Total count: <span id="committee-count">{{ committees|length }}</span> + </p> + </div> - <div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4"> - {% for committee in committees %} - {% set is_part = false %} - {% if current_user and committee %} - {% if (current_user.uid in committee.committee_members) or - (current_user.uid in committee.committers) or - (current_user.uid in committee.release_managers) %} - {% set is_part = true %} + <div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4"> + {% for committee in committees %} + {% set is_part = false %} + {% if current_user and committee %} + {% if (current_user.uid in committee.committee_members) or + (current_user.uid in committee.committers) or + (current_user.uid in committee.release_managers) %} + {% set is_part = true %} + {% endif %} {% endif %} - {% endif %} - <div class="col"> - <div class="card h-100 shadow-sm page-project-card" - data-is-participant="{{ 'true' if is_part else 'false' }}"> - <div class="card-body"> - <div class="row mb-3 align-items-center"> - <div class="col"> - <h3 class="card-title fs-4 mb-0"> - <a href="{{ as_url(get.committees.view, name=committee.name) }}" - class="text-decoration-none text-dark page-committee-title-link">{{ committee.display_name }}</a> - </h3> - </div> - <div class="col-5 col-lg-4 text-center"> - <div class="page-logo-container"> - {% if (committee.name == "incubator") or committee.name.startswith("incubator-") %} - <img src="https://www.apache.org/logos/res/incubator/default.png" - alt="" - class="page-logo" - onerror="this.style.display='none';" /> - {% else %} - <img src="https://www.apache.org/logos/res/{{ committee.name }}/default.png" - alt="" - class="page-logo" - onerror="this.style.display='none';" /> - {% endif %} - </div> - </div> - </div> - <div class="mt-3 page-project-list-container"> - {% set max_initial_projects = 2 %} - {% if committee.projects %} - {% for project in committee.projects|sort(attribute="name") %} - <div class="card mb-3 shadow-sm page-project-subcard {% if loop.index > max_initial_projects %}page-project-extra d-none{% endif %} {% if project.status.value.lower() != "active" %}page-project-inactive{% endif %}" - data-project-url="{{ as_url(get.projects.view, name=project.name) }}"> - <div class="card-body p-3 d-flex flex-column h-100"> - <div class="d-flex justify-content-between align-items-start"> - <p class="mb-1 me-2 fs-6"> - <a href="{{ as_url(get.projects.view, name=project.name) }}" - class="text-decoration-none stretched-link">{{ project.display_name }}</a> - </p> - <div> - {% if project.status.value.lower() != "active" %} - <span class="badge text-bg-secondary ms-1">{{ project.status.value.lower() }}</span> - {% endif %} + <div class="col"> + <div class="card h-100 shadow-sm page-project-card" + data-is-participant="{{ 'true' if is_part else 'false' }}"> + <div class="card-body"> + <div class="row mb-3 align-items-center"> + <div class="col"> + <h3 class="card-title fs-4 mb-0"> + <a href="{{ as_url(get.committees.view, name=committee.name) }}" + class="text-decoration-none text-dark page-committee-title-link">{{ committee.display_name }}</a> + </h3> + </div> + <div class="col-5 col-lg-4 text-center"> + <div class="page-logo-container"> + {% if (committee.name == "incubator") or committee.name.startswith("incubator-") %} + <img src="https://www.apache.org/logos/res/incubator/default.png" + alt="" + class="page-logo" + onerror="this.style.display='none';" /> + {% else %} + <img src="https://www.apache.org/logos/res/{{ committee.name }}/default.png" + alt="" + class="page-logo" + onerror="this.style.display='none';" /> + {% endif %} + </div> </div> - </div> - <div class="mb-1 page-project-subcard-categories"> - {% set categories = project.category.split(', ') if project.category else [] %} - {% for category in categories %} - {% if category != "retired" %}<span class="badge text-bg-primary me-1">{{ category }}</span>{% endif %} - {% endfor %} - {% set langs = project.programming_languages.split(', ') if project.programming_languages else [] %} - {% for lang in langs[:1] %}<span class="badge text-bg-success me-1">{{ lang }}</span>{% endfor %} - </div> </div> - </div> - {% endfor %} - {% if committee.projects|length > max_initial_projects %} - <button type="button" - class="btn btn-sm btn-outline-secondary mt-2 page-toggle-committee-projects" - aria-expanded="false" - data-text-show="Show {{ committee.projects|length - max_initial_projects }} more projects..." - data-text-hide="Show less..."> - Show {{ committee.projects|length - max_initial_projects }} more projects... - </button> - {% endif %} + <div class="mt-3 page-project-list-container"> + {% set max_initial_projects = 2 %} + {% if committee.projects %} + {% for project in committee.projects|sort(attribute="name") %} + <div class="card mb-3 shadow-sm page-project-subcard {% if loop.index > max_initial_projects %}page-project-extra d-none{% endif %} {% if project.status.value.lower() != "active" %}page-project-inactive{% endif %}" + data-project-url="{{ as_url(get.projects.view, name=project.name) }}"> + <div class="card-body p-3 d-flex flex-column h-100"> + <div class="d-flex justify-content-between align-items-start"> + <p class="mb-1 me-2 fs-6"> + <a href="{{ as_url(get.projects.view, name=project.name) }}" + class="text-decoration-none stretched-link">{{ project.display_name }}</a> + </p> + <div> + {% if project.status.value.lower() != "active" %} + <span class="badge text-bg-secondary ms-1">{{ project.status.value.lower() }}</span> + {% endif %} + </div> + </div> + <div class="mb-1 page-project-subcard-categories"> + {% set categories = project.category.split(', ') if project.category else [] %} + {% for category in categories %} + {% if category != "retired" %}<span class="badge text-bg-primary me-1">{{ category }}</span>{% endif %} + {% endfor %} + {% set langs = project.programming_languages.split(', ') if project.programming_languages else [] %} + {% for lang in langs[:1] %}<span class="badge text-bg-success me-1">{{ lang }}</span>{% endfor %} + </div> + </div> + </div> + {% endfor %} + {% if committee.projects|length > max_initial_projects %} + <button type="button" + class="btn btn-sm btn-outline-secondary mt-2 page-toggle-committee-projects" + aria-expanded="false" + data-text-show="Show {{ committee.projects|length - max_initial_projects }} more projects..." + data-text-hide="Show less..."> + Show {{ committee.projects|length - max_initial_projects }} more projects... + </button> + {% endif %} {# Add an else clause here if we decide to show an alternative to an empty card #} - {% endif %} - </div> - {% if current_user and is_part and (not committee_is_standing(committee.name)) %} - <a href="{{ as_url(get.projects.add_project, committee_name=committee.name) }}" - title="Create a project for {{ committee.display_name }}" - class="text-decoration-none d-block mt-4 mb-3"> - <div class="card h-100 shadow-sm atr-cursor-pointer page-project-subcard"> - <div class="card-body d-flex align-items-center text-secondary p-3"> - <div> - <i class="bi bi-plus-circle me-2"></i>Create project - <br /> - <small class="text-muted">for {{ committee.display_name }}</small> + {% endif %} </div> - </div> + {% if current_user and is_part and (not committee_is_standing(committee.name)) %} + <a href="{{ as_url(get.projects.add_project, committee_name=committee.name) }}" + title="Create a project for {{ committee.display_name }}" + class="text-decoration-none d-block mt-4 mb-3"> + <div class="card h-100 shadow-sm atr-cursor-pointer page-project-subcard"> + <div class="card-body d-flex align-items-center text-secondary p-3"> + <div> + <i class="bi bi-plus-circle me-2"></i>Create project + <br /> + <small class="text-muted">for {{ committee.display_name }}</small> + </div> + </div> + </div> + </a> + {% endif %} </div> - </a> - {% endif %} - </div> + </div> </div> - </div> - {% endfor %} - </div> +{% endfor %} +</div> {% endblock content %} {% block javascripts %} - {{ super() }} - <script> - let allCommitteeCards = []; + {{ super() }} + <script> + let allCommitteeCards = []; - function filterCommitteesByText() { - const projectFilter = document.getElementById("project-filter").value; - const cards = allCommitteeCards; - let visibleCount = 0; + function filterCommitteesByText() { + const projectFilter = document.getElementById("project-filter").value; + const cards = allCommitteeCards; + let visibleCount = 0; - if (participantButton && participantButton.dataset.showing === "participant") { - participantButton.dataset.showing = "all"; - participantButton.textContent = "Show my committees"; - participantButton.setAttribute("aria-pressed", "false"); - } + if (participantButton && participantButton.dataset.showing === "participant") { + participantButton.dataset.showing = "all"; + participantButton.textContent = "Show my committees"; + participantButton.setAttribute("aria-pressed", "false"); + } - for (let card of cards) { - const nameElement = card.querySelector(".card-title"); - const name = nameElement.textContent.trim(); - if (!projectFilter) { - card.parentElement.hidden = false; - visibleCount++; - } else { - let regex; - try { - regex = new RegExp(projectFilter, "i"); - } catch (e) { - const escapedFilter = projectFilter.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); - regex = new RegExp(escapedFilter, "i"); - } - card.parentElement.hidden = !name.match(regex); - if (!card.parentElement.hidden) { - visibleCount++; - } - } - } - document.getElementById("committee-count").textContent = visibleCount; - } + for (let card of cards) { + const nameElement = card.querySelector(".card-title"); + const name = nameElement.textContent.trim(); + if (!projectFilter) { + card.parentElement.hidden = false; + visibleCount++; + } else { + let regex; + try { + regex = new RegExp(projectFilter, "i"); + } catch (e) { + const escapedFilter = projectFilter.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + regex = new RegExp(escapedFilter, "i"); + } + card.parentElement.hidden = !name.match(regex); + if (!card.parentElement.hidden) { + visibleCount++; + } + } + } + document.getElementById("committee-count").textContent = visibleCount; + } // Add event listeners - document.getElementById("filter-button").addEventListener("click", filterCommitteesByText); - document.getElementById("project-filter").addEventListener("keydown", function(event) { - if (event.key === "Enter") { - filterCommitteesByText(); - event.preventDefault(); - } - }); + document.getElementById("filter-button").addEventListener("click", filterCommitteesByText); + document.getElementById("project-filter").addEventListener("keydown", function(event) { + if (event.key === "Enter") { + filterCommitteesByText(); + event.preventDefault(); + } + }); - const participantButton = document.getElementById("filter-participant-button"); - if (participantButton) { - participantButton.addEventListener("click", function() { - const showing = this.dataset.showing; - const cards = allCommitteeCards; - let visibleCount = 0; + const participantButton = document.getElementById("filter-participant-button"); + if (participantButton) { + participantButton.addEventListener("click", function() { + const showing = this.dataset.showing; + const cards = allCommitteeCards; + let visibleCount = 0; - if (showing === "all") { - cards.forEach(card => { - const isParticipant = card.dataset.isParticipant === "true"; - card.parentElement.hidden = !isParticipant; - if (!card.parentElement.hidden) { - visibleCount++; - } - }); - this.textContent = "Show all committees"; - this.dataset.showing = "participant"; - this.setAttribute("aria-pressed", "true"); - } else { - cards.forEach(card => { - card.parentElement.hidden = false; - visibleCount++; - }); - this.textContent = "Show my committees"; - this.dataset.showing = "all"; - this.setAttribute("aria-pressed", "false"); - } - document.getElementById("project-filter").value = ""; - document.getElementById("committee-count").textContent = visibleCount; - }); - } + if (showing === "all") { + cards.forEach(card => { + const isParticipant = card.dataset.isParticipant === "true"; + card.parentElement.hidden = !isParticipant; + if (!card.parentElement.hidden) { + visibleCount++; + } + }); + this.textContent = "Show all committees"; + this.dataset.showing = "participant"; + this.setAttribute("aria-pressed", "true"); + } else { + cards.forEach(card => { + card.parentElement.hidden = false; + visibleCount++; + }); + this.textContent = "Show my committees"; + this.dataset.showing = "all"; + this.setAttribute("aria-pressed", "false"); + } + document.getElementById("project-filter").value = ""; + document.getElementById("committee-count").textContent = visibleCount; + }); + } - document.addEventListener("DOMContentLoaded", function() { - allCommitteeCards = Array.from(document.querySelectorAll(".page-project-card")); - const cards = allCommitteeCards; - const committeeCountSpan = document.getElementById("committee-count"); - let initialVisibleCount = 0; - const initialShowingMode = participantButton ? participantButton.dataset.showing : "all"; + document.addEventListener("DOMContentLoaded", function() { + allCommitteeCards = Array.from(document.querySelectorAll(".page-project-card")); + const cards = allCommitteeCards; + const committeeCountSpan = document.getElementById("committee-count"); + let initialVisibleCount = 0; + const initialShowingMode = participantButton ? participantButton.dataset.showing : "all"; - if (participantButton) { - if (initialShowingMode === "participant") { - participantButton.setAttribute("aria-pressed", "true"); - } else { - participantButton.setAttribute("aria-pressed", "false"); - } - } + if (participantButton) { + if (initialShowingMode === "participant") { + participantButton.setAttribute("aria-pressed", "true"); + } else { + participantButton.setAttribute("aria-pressed", "false"); + } + } - if (initialShowingMode === "participant") { - cards.forEach(card => { - const isParticipant = card.dataset.isParticipant === "true"; - card.parentElement.hidden = !isParticipant; - if (!card.parentElement.hidden) { - initialVisibleCount++; - } - }); - } else { - cards.forEach(card => { - card.parentElement.hidden = false; - initialVisibleCount++; - }); - } - committeeCountSpan.textContent = initialVisibleCount; + if (initialShowingMode === "participant") { + cards.forEach(card => { + const isParticipant = card.dataset.isParticipant === "true"; + card.parentElement.hidden = !isParticipant; + if (!card.parentElement.hidden) { + initialVisibleCount++; + } + }); + } else { + cards.forEach(card => { + card.parentElement.hidden = false; + initialVisibleCount++; + }); + } + committeeCountSpan.textContent = initialVisibleCount; // Add a click listener to project subcards to handle navigation // TODO: Improve accessibility - document.querySelectorAll(".page-project-subcard").forEach(function(subcard) { - subcard.addEventListener("click", function(event) { - if (this.dataset.projectUrl) { - window.location.href = this.dataset.projectUrl; - } - }); - }); + document.querySelectorAll(".page-project-subcard").forEach(function(subcard) { + subcard.addEventListener("click", function(event) { + if (this.dataset.projectUrl) { + window.location.href = this.dataset.projectUrl; + } + }); + }); // Add a click listener for toggling project visibility within each committee - document.querySelectorAll(".page-toggle-committee-projects").forEach(function(button) { - button.addEventListener("click", function() { - const projectListContainer = this.closest(".page-project-list-container"); - if (projectListContainer) { - const extraProjects = projectListContainer.querySelectorAll(".page-project-extra"); - extraProjects.forEach(function(proj) { - proj.classList.toggle("d-none"); - }); + document.querySelectorAll(".page-toggle-committee-projects").forEach(function(button) { + button.addEventListener("click", function() { + const projectListContainer = this.closest(".page-project-list-container"); + if (projectListContainer) { + const extraProjects = projectListContainer.querySelectorAll(".page-project-extra"); + extraProjects.forEach(function(proj) { + proj.classList.toggle("d-none"); + }); - const isExpanded = this.getAttribute("aria-expanded") === "true"; - if (isExpanded) { - this.textContent = this.dataset.textShow; - this.setAttribute("aria-expanded", "false"); - } else { - this.textContent = this.dataset.textHide; - this.setAttribute("aria-expanded", "true"); - } - } - }); - }); - }); - </script> + const isExpanded = this.getAttribute("aria-expanded") === "true"; + if (isExpanded) { + this.textContent = this.dataset.textShow; + this.setAttribute("aria-expanded", "false"); + } else { + this.textContent = this.dataset.textHide; + this.setAttribute("aria-expanded", "true"); + } + } + }); + }); + }); + </script> {% endblock javascripts %} diff --git a/atr/templates/committee-view.html b/atr/templates/committee-view.html index 1319d3b..c7fd3bb 100644 --- a/atr/templates/committee-view.html +++ b/atr/templates/committee-view.html @@ -1,10 +1,8 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}Committee ~ ATR{%- endblock title -%} {%- block description -%}Information regarding an Apachommittee.{%- endblock description -%} -{# djlint:on #} {% block content %} <h1>{{ committee.display_name }}</h1> diff --git a/atr/templates/delete-committee-keys.html b/atr/templates/delete-committee-keys.html index f16938b..afbf30a 100644 --- a/atr/templates/delete-committee-keys.html +++ b/atr/templates/delete-committee-keys.html @@ -2,11 +2,9 @@ {% import "macros/forms.html" as forms %} -{# djlint:off #} {%- block title -%}Delete committee keys{%- endblock title -%} {%- block description -%}Delete committee keys{%- endblock description -%} -{# djlint:on #} {% block content %} <div class="container mx-auto p-4"> diff --git a/atr/templates/download-all.html b/atr/templates/download-all.html index b91d6ca..109eb5d 100644 --- a/atr/templates/download-all.html +++ b/atr/templates/download-all.html @@ -1,10 +1,8 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}Download {{ release.project.display_name }} {{ release.version }} ~ ATR{%- endblock title -%} {%- block description -%}Download commands for {{ release.project.display_name }} {{ release.version }}.{%- endblock description -%} -{# djlint:on #} {% block content %} {% set phase = release.phase.value %} diff --git a/atr/templates/draft-tools.html b/atr/templates/draft-tools.html index 1cb1fb8..163465b 100644 --- a/atr/templates/draft-tools.html +++ b/atr/templates/draft-tools.html @@ -1,10 +1,8 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}File tools ~ ATR{%- endblock title -%} {%- block description -%}Manage a file in the candidate draft using tools.{%- endblock description -%} -{# djlint:on #} {% block content %} <a href="{{ as_url(get.compose.selected, project_name=project_name, version_name=version_name) }}" @@ -28,7 +26,7 @@ <p>Generate an SHA256 or SHA512 hash file for this file.</p> <div class="alert alert-warning"> <i class="bi bi-exclamation-triangle me-2"></i> IMPORTANT: The ASF security team <a href="https://infra.apache.org/release-signing.html#sha-checksum" - class="alert-link">recommends using SHA512</a> as the hash algorithm. + class="alert-link">recommends using SHA512</a> as the hash algorithm. Please select SHA512 unless you have a specific reason to use SHA256. </div> <div class="d-flex gap-2 mb-4"> diff --git a/atr/templates/error.html b/atr/templates/error.html index 8602be6..56fc640 100644 --- a/atr/templates/error.html +++ b/atr/templates/error.html @@ -1,10 +1,8 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}Error ~ ATR{%- endblock title -%} {%- block description -%}An error occurred while processing your request.{%- endblock description -%} -{# djlint:on #} {% block content %} <div> diff --git a/atr/templates/includes/topnav.html b/atr/templates/includes/topnav.html index 67269a9..daa1c47 100644 --- a/atr/templates/includes/topnav.html +++ b/atr/templates/includes/topnav.html @@ -31,339 +31,339 @@ id="menuCandidates" aria-labelledby="dropdownCandidates"> <li> - <a class="dropdown-item" href="{{ as_url(get.root.index) }}"><i class="bi bi-play-circle"></i> - Candidates</a> - </li> - {% set unfinished_releases = unfinished_releases_fn(current_user.uid) %} - {% if unfinished_releases %} - {% for project_short_display_name, project_name, releases in unfinished_releases %} - <li> - <hr class="dropdown-divider" /> - </li> - <li> - <a class="dropdown-item fw-bold" - href="{{ as_url(get.projects.view, name=project_name) }}">{{ project_short_display_name }}</a> + <a class="dropdown-item" href="{{ as_url(get.root.index) }}"><i class="bi bi-play-circle"></i> + Candidates</a> </li> - {% for release in releases %} + {% set unfinished_releases = unfinished_releases_fn(current_user.uid) %} + {% if unfinished_releases %} + {% for project_short_display_name, project_name, releases in unfinished_releases %} + <li> + <hr class="dropdown-divider" /> + </li> + <li> + <a class="dropdown-item fw-bold" + href="{{ as_url(get.projects.view, name=project_name) }}">{{ project_short_display_name }}</a> + </li> + {% for release in releases %} + <li> + <a class="dropdown-item" href="{{ release_as_url(release) }}"><i class="bi bi-tag"></i> + {{ release.version }}</a> + </li> + {% endfor %} + {% endfor %} + {% endif %} + {% set user_projects = user_projects_fn(current_user.uid) %} + {% if user_projects %} + {% set max_projects = 8 %} + <li> + <hr class="dropdown-divider" /> + </li> <li> - <a class="dropdown-item" href="{{ release_as_url(release) }}"><i class="bi bi-tag"></i> - {{ release.version }}</a> + <a class="dropdown-item fw-bold" href="{{ as_url(get.root.index) }}">Start a release</a> + </li> + {% for project_name, project_full_name in user_projects[:max_projects] %} + <li> + <a class="dropdown-item" + href="{{ as_url(get.start.selected, project_name=project_name) }}"><i class="bi bi-plus-circle"></i> + {{ project_full_name.removeprefix("Apache ").removesuffix(" (Incubating)") }}</a> + </li> + {% endfor %} + {% if user_projects|length > max_projects %} + <li> + <a class="dropdown-item" href="{{ as_url(get.root.index) }}"><i class="bi bi-three-dots"></i> {{ user_projects|length - max_projects }} more</a> + </li> + {% endif %} + {% endif %} + </ul> + </li> + {% endif %} + <li class="nav-item dropdown"> + <button class="nav-link dropdown-toggle btn" + id="dropdownCatalog" + type="button" + data-bs-toggle="dropdown" + aria-expanded="false" + aria-controls="menuCatalog">Releases</button> + <ul class="dropdown-menu" + id="menuCatalog" + aria-labelledby="dropdownCatalog"> + <li> + <a class="dropdown-item" href="{{ as_url(get.release.releases) }}"><i class="bi bi-view-list"></i> + Catalog</a> </li> - {% endfor %} - {% endfor %} - {% endif %} - {% set user_projects = user_projects_fn(current_user.uid) %} - {% if user_projects %} - {% set max_projects = 8 %} - <li> - <hr class="dropdown-divider" /> - </li> - <li> - <a class="dropdown-item fw-bold" href="{{ as_url(get.root.index) }}">Start a release</a> - </li> - {% for project_name, project_full_name in user_projects[:max_projects] %} - <li> - <a class="dropdown-item" - href="{{ as_url(get.start.selected, project_name=project_name) }}"><i class="bi bi-plus-circle"></i> - {{ project_full_name.removeprefix("Apache ").removesuffix(" (Incubating)") }}</a> - </li> - {% endfor %} - {% if user_projects|length > max_projects %} - <li> - <a class="dropdown-item" href="{{ as_url(get.root.index) }}"><i class="bi bi-three-dots"></i> {{ user_projects|length - max_projects }} more</a> - </li> - {% endif %} - {% endif %} -</ul> -</li> -{% endif %} -<li class="nav-item dropdown"> - <button class="nav-link dropdown-toggle btn" - id="dropdownCatalog" - type="button" - data-bs-toggle="dropdown" - aria-expanded="false" - aria-controls="menuCatalog">Releases</button> - <ul class="dropdown-menu" - id="menuCatalog" - aria-labelledby="dropdownCatalog"> - <li> - <a class="dropdown-item" href="{{ as_url(get.release.releases) }}"><i class="bi bi-view-list"></i> - Catalog</a> -</li> -<li> -<a class="dropdown-item" href="{{ as_url(get.committees.directory) }}"><i class="bi bi-collection"></i> -Committees</a> -</li> -<li> + <li> + <a class="dropdown-item" href="{{ as_url(get.committees.directory) }}"><i class="bi bi-collection"></i> + Committees</a> + </li> + <li> {# This path is handled by the frontend proxy server #} {# https://djlint.com/docs/ignoring-code/ #} {# djlint:off J018 #} <a class="dropdown-item" href="/downloads/"><i class="bi bi-download"></i> Downloads</a> {# djlint:on #} -</li> -</ul> -</li> -{% if current_user %} - <li class="nav-item dropdown"> - <button class="nav-link dropdown-toggle btn" - id="dropdownConfigure" - type="button" - data-bs-toggle="dropdown" - aria-expanded="false" - aria-controls="menuCandidates">Configure</button> - <ul class="dropdown-menu" - id="menuConfigure" - aria-labelledby="dropdownConfigure"> - <li> - <a class="dropdown-item" href="{{ as_url(get.committees.directory) }}"><i class="bi bi-collection"></i> - Committees</a> - </li> - <li> - <a class="dropdown-item" href="{{ as_url(get.projects.projects) }}"><i class="bi bi-collection"></i> -Projects</a> -</li> + </li> + </ul> + </li> + {% if current_user %} + <li class="nav-item dropdown"> + <button class="nav-link dropdown-toggle btn" + id="dropdownConfigure" + type="button" + data-bs-toggle="dropdown" + aria-expanded="false" + aria-controls="menuCandidates">Configure</button> + <ul class="dropdown-menu" + id="menuConfigure" + aria-labelledby="dropdownConfigure"> + <li> + <a class="dropdown-item" href="{{ as_url(get.committees.directory) }}"><i class="bi bi-collection"></i> + Committees</a> + </li> + <li> + <a class="dropdown-item" href="{{ as_url(get.projects.projects) }}"><i class="bi bi-collection"></i> + Projects</a> + </li> <!-- <li> <a class="dropdown-item" href="{{ as_url(get.keys.keys) }}"><i class="bi bi-key"></i> Public keys</a> </li> --> -<li> -<a class="dropdown-item" href="{{ as_url(get.tokens.tokens) }}"><i class="bi bi-key"></i> -API tokens</a> -</li> -</ul> -</li> -{% endif %} -<li class="nav-item dropdown"> - <button class="nav-link dropdown-toggle btn" - id="dropdownHelp" - type="button" - data-bs-toggle="dropdown" - aria-expanded="false" - aria-controls="menuHelp">Help</button> - <ul class="dropdown-menu" id="menuHelp" aria-labelledby="dropdownHelp"> - {% if current_user %} - <li> - <a class="dropdown-item" href="{{ as_url(get.root.tutorial) }}"><i class="bi bi-book"></i> - Tutorial</a> - </li> -{% endif %} -<li> -<a class="dropdown-item" href="{{ as_url(get.docs.index) }}"><i class="bi bi-book"></i> -Documentation</a> -</li> -<li> -<a class="dropdown-item" href="{{ as_url(get.root.policies) }}"><i class="bi bi-book"></i> -ASF Policies</a> -</li> -{% if current_user %} - <li> + <li> + <a class="dropdown-item" href="{{ as_url(get.tokens.tokens) }}"><i class="bi bi-key"></i> + API tokens</a> + </li> + </ul> + </li> + {% endif %} + <li class="nav-item dropdown"> + <button class="nav-link dropdown-toggle btn" + id="dropdownHelp" + type="button" + data-bs-toggle="dropdown" + aria-expanded="false" + aria-controls="menuHelp">Help</button> + <ul class="dropdown-menu" id="menuHelp" aria-labelledby="dropdownHelp"> + {% if current_user %} + <li> + <a class="dropdown-item" href="{{ as_url(get.root.tutorial) }}"><i class="bi bi-book"></i> + Tutorial</a> + </li> + {% endif %} + <li> + <a class="dropdown-item" href="{{ as_url(get.docs.index) }}"><i class="bi bi-book"></i> + Documentation</a> + </li> + <li> + <a class="dropdown-item" href="{{ as_url(get.root.policies) }}"><i class="bi bi-book"></i> + ASF Policies</a> + </li> + {% if current_user %} + <li> {# djlint:off J018 #} <a class="dropdown-item" href="/api/docs"><i class="bi bi-file-earmark-code"></i> - OpenAPI</a> {# djlint:on #} - </li> - <li> - <hr class="dropdown-divider" /> - </li> - <li> - <a class="dropdown-item" - href="https://github.com/apache/tooling-docs/" - target="_blank"><i class="bi bi-github"></i> Tooling Docs</a> - </li> - <li> - <hr class="dropdown-divider" /> - </li> - <li> - <a class="dropdown-item" - href="https://github.com/apache/tooling-trusted-releases" - target="_blank"><i class="bi bi-github"></i> Trusted Releases</a> - </li> - <li> - <a class="dropdown-item" - href="https://github.com/apache/tooling-releases-client" - target="_blank"><i class="bi bi-github"></i> Trusted Releases Client</a> - </li> - <li> - <a class="dropdown-item" - href="https://github.com/apache/tooling-actions" - target="_blank"><i class="bi bi-github"></i> Trusted Releases Actions</a> - </li> -{% endif %} -</ul> -</li> -{% if is_viewing_as_admin_fn(current_user.uid) %} - <li class="nav-item dropdown"> - <button class="nav-link dropdown-toggle btn" - id="dropdownAdmin" - type="button" - data-bs-toggle="dropdown" - aria-expanded="false" - aria-controls="menuAdmin">Admin</button> - <ul class="dropdown-menu" id="menuAdmin" aria-labelledby="dropdownAdmin"> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.all_releases) }}" - {% if request.endpoint == 'atr_admin_all_releases' %}class="active"{% endif %}><i class="bi bi-list-ul"></i> All releases</a> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.browse_as_get) }}" - {% if request.endpoint == 'atr_admin_browse_as_get' %}class="active"{% endif %}><i class="bi bi-person-plus"></i> Browse as user</a> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.consistency) }}" - {% if request.endpoint == 'atr_admin_consistency' %}class="active"{% endif %}><i class="bi bi-arrow-repeat"></i> Consistency</a> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.data) }}" - {% if request.endpoint == 'atr_admin_data' %}class="active"{% endif %}><i class="bi bi-database"></i> Browse database</a> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.delete_committee_keys_get) }}" - {% if request.endpoint == 'atr_admin_delete_committee_keys_get' %}class="active"{% endif %}><i class="bi bi-trash"></i> Delete committee keys</a> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.delete_release_get) }}" - {% if request.endpoint == 'atr_admin_delete_release_get' %}class="active"{% endif %}><i class="bi bi-trash"></i> Delete release</a> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.env) }}" - {% if request.endpoint == 'atr_admin_env' %}class="active"{% endif %}><i class="bi bi-gear"></i> Environment</a> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.keys_check_get) }}" - {% if request.endpoint == 'atr_admin_keys_check_get' %}class="active"{% endif %}><i class="bi bi-key"></i> Keys check</a> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.keys_regenerate_all_get) }}" - {% if request.endpoint == 'atr_admin_keys_regenerate_all_get' %}class="active"{% endif %}><i class="bi bi-key"></i> Regenerate all keys</a> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.keys_update_get) }}" - {% if request.endpoint == 'atr_admin_keys_update_get' %}class="active"{% endif %}><i class="bi bi-key"></i> Update keys</a> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.ldap_get) }}" - {% if request.endpoint == 'atr_admin_ldap_get' %}class="active"{% endif %}><i class="bi bi-person-plus"></i> LDAP search</a> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.performance) }}" - {% if request.endpoint == 'atr_admin_performance' %}class="active"{% endif %}><i class="bi bi-speedometer2"></i> Page performance</a> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.projects_update_get) }}" - {% if request.endpoint == 'atr_admin_projects_update_get' %}class="active"{% endif %}><i class="bi bi-arrow-repeat"></i> Update projects</a> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.tasks_) }}" - {% if request.endpoint == 'atr_admin_tasks_' %}class="active"{% endif %}><i class="bi bi-list-task"></i> Background tasks</a> - </li> - <li> - <hr class="dropdown-divider" /> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.tasks_recent, minutes=5) }}"><i class="bi bi-clock-history"></i> Recent tasks</a> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.toggle_view_get) }}" - {% if request.endpoint == 'atr_admin_toggle_view_get' %}class="active"{% endif %}><i class="bi bi-person-badge"></i> Toggle admin view</a> - </li> - <li> - <a class="dropdown-item" - href="{{ as_url(admin.validate_) }}" - {% if request.endpoint == 'atr_admin_validate_' %}class="active"{% endif %}><i class="bi bi-arrow-repeat"></i> Validate</a> - </li> - </ul> - </li> -{% endif %} -</ul> -<ul class="navbar-nav"> - <li class="nav-item dropdown"> - <button class="nav-link dropdown-toggle btn" - id="dropdownUser" - type="button" - data-bs-toggle="dropdown" - aria-expanded="false" - aria-controls="menuUser"> - Log - {% if current_user %} - out - {% else %} - in - {% endif %} - </button> - <ul class="dropdown-menu dropdown-menu-end" - id="menuUser" - aria-labelledby="dropdownUser"> - <div class="user-menu"> - {% if current_user %} - <span>{{ current_user.fullname }}</span> - (<code>{{ current_user.uid }}</code>) - <br /> - <a href="#" - onclick="location.href='/auth?logout=/';" - class="logout-link btn btn-sm btn-outline-secondary mt-2">Log out</a> - {% else %} - <a href="#" - onclick="location.href='/auth?login=' + window.location.pathname;" - class="login-link btn btn-sm btn-secondary">Log in</a> + OpenAPI</a> {# djlint:on #} + </li> + <li> + <hr class="dropdown-divider" /> + </li> + <li> + <a class="dropdown-item" + href="https://github.com/apache/tooling-docs/" + target="_blank"><i class="bi bi-github"></i> Tooling Docs</a> + </li> + <li> + <hr class="dropdown-divider" /> + </li> + <li> + <a class="dropdown-item" + href="https://github.com/apache/tooling-trusted-releases" + target="_blank"><i class="bi bi-github"></i> Trusted Releases</a> + </li> + <li> + <a class="dropdown-item" + href="https://github.com/apache/tooling-releases-client" + target="_blank"><i class="bi bi-github"></i> Trusted Releases Client</a> + </li> + <li> + <a class="dropdown-item" + href="https://github.com/apache/tooling-actions" + target="_blank"><i class="bi bi-github"></i> Trusted Releases Actions</a> + </li> + {% endif %} + </ul> + </li> + {% if is_viewing_as_admin_fn(current_user.uid) %} + <li class="nav-item dropdown"> + <button class="nav-link dropdown-toggle btn" + id="dropdownAdmin" + type="button" + data-bs-toggle="dropdown" + aria-expanded="false" + aria-controls="menuAdmin">Admin</button> + <ul class="dropdown-menu" id="menuAdmin" aria-labelledby="dropdownAdmin"> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.all_releases) }}" + {% if request.endpoint == 'atr_admin_all_releases' %}class="active"{% endif %}><i class="bi bi-list-ul"></i> All releases</a> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.browse_as_get) }}" + {% if request.endpoint == 'atr_admin_browse_as_get' %}class="active"{% endif %}><i class="bi bi-person-plus"></i> Browse as user</a> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.consistency) }}" + {% if request.endpoint == 'atr_admin_consistency' %}class="active"{% endif %}><i class="bi bi-arrow-repeat"></i> Consistency</a> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.data) }}" + {% if request.endpoint == 'atr_admin_data' %}class="active"{% endif %}><i class="bi bi-database"></i> Browse database</a> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.delete_committee_keys_get) }}" + {% if request.endpoint == 'atr_admin_delete_committee_keys_get' %}class="active"{% endif %}><i class="bi bi-trash"></i> Delete committee keys</a> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.delete_release_get) }}" + {% if request.endpoint == 'atr_admin_delete_release_get' %}class="active"{% endif %}><i class="bi bi-trash"></i> Delete release</a> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.env) }}" + {% if request.endpoint == 'atr_admin_env' %}class="active"{% endif %}><i class="bi bi-gear"></i> Environment</a> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.keys_check_get) }}" + {% if request.endpoint == 'atr_admin_keys_check_get' %}class="active"{% endif %}><i class="bi bi-key"></i> Keys check</a> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.keys_regenerate_all_get) }}" + {% if request.endpoint == 'atr_admin_keys_regenerate_all_get' %}class="active"{% endif %}><i class="bi bi-key"></i> Regenerate all keys</a> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.keys_update_get) }}" + {% if request.endpoint == 'atr_admin_keys_update_get' %}class="active"{% endif %}><i class="bi bi-key"></i> Update keys</a> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.ldap_get) }}" + {% if request.endpoint == 'atr_admin_ldap_get' %}class="active"{% endif %}><i class="bi bi-person-plus"></i> LDAP search</a> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.performance) }}" + {% if request.endpoint == 'atr_admin_performance' %}class="active"{% endif %}><i class="bi bi-speedometer2"></i> Page performance</a> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.projects_update_get) }}" + {% if request.endpoint == 'atr_admin_projects_update_get' %}class="active"{% endif %}><i class="bi bi-arrow-repeat"></i> Update projects</a> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.tasks_) }}" + {% if request.endpoint == 'atr_admin_tasks_' %}class="active"{% endif %}><i class="bi bi-list-task"></i> Background tasks</a> + </li> + <li> + <hr class="dropdown-divider" /> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.tasks_recent, minutes=5) }}"><i class="bi bi-clock-history"></i> Recent tasks</a> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.toggle_view_get) }}" + {% if request.endpoint == 'atr_admin_toggle_view_get' %}class="active"{% endif %}><i class="bi bi-person-badge"></i> Toggle admin view</a> + </li> + <li> + <a class="dropdown-item" + href="{{ as_url(admin.validate_) }}" + {% if request.endpoint == 'atr_admin_validate_' %}class="active"{% endif %}><i class="bi bi-arrow-repeat"></i> Validate</a> + </li> + </ul> + </li> {% endif %} - </div> - </ul> - </li> - <li class="nav-item dropdown"> - <button class="nav-link dropdown-toggle btn" - id="dropdownASF" - type="button" - data-bs-toggle="dropdown" - aria-expanded="false" - aria-controls="menuASF">About The ASF</button> - <ul class="dropdown-menu dropdown-menu-end" - id="menuASF" - aria-labelledby="dropdownASF"> - <li> - <a class="dropdown-item" href="https://www.apache.org/">Foundation</a> - </li> - <li> - <hr class="dropdown-divider" /> - </li> - <li> - <a class="dropdown-item" href="https://www.apache.org/licenses/">License</a> - </li> - <li> - <a class="dropdown-item" - href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a> - </li> - <li> - <a class="dropdown-item" - href="https://www.apache.org/foundation/thanks.html">Thanks</a> - </li> - <li> - <hr class="dropdown-divider" /> - </li> - <li> - <a class="dropdown-item" href="https://www.apache.org/security/">Security</a> - </li> - <li> - <a class="dropdown-item" - href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy Policy</a> - </li> - </ul> - </li> -</ul> -</div> -</div> + </ul> + <ul class="navbar-nav"> + <li class="nav-item dropdown"> + <button class="nav-link dropdown-toggle btn" + id="dropdownUser" + type="button" + data-bs-toggle="dropdown" + aria-expanded="false" + aria-controls="menuUser"> + Log + {% if current_user %} + out + {% else %} + in + {% endif %} + </button> + <ul class="dropdown-menu dropdown-menu-end" + id="menuUser" + aria-labelledby="dropdownUser"> + <div class="user-menu"> + {% if current_user %} + <span>{{ current_user.fullname }}</span> + (<code>{{ current_user.uid }}</code>) + <br /> + <a href="#" + onclick="location.href='/auth?logout=/';" + class="logout-link btn btn-sm btn-outline-secondary mt-2">Log out</a> + {% else %} + <a href="#" + onclick="location.href='/auth?login=' + window.location.pathname;" + class="login-link btn btn-sm btn-secondary">Log in</a> + {% endif %} + </div> + </ul> + </li> + <li class="nav-item dropdown"> + <button class="nav-link dropdown-toggle btn" + id="dropdownASF" + type="button" + data-bs-toggle="dropdown" + aria-expanded="false" + aria-controls="menuASF">About The ASF</button> + <ul class="dropdown-menu dropdown-menu-end" + id="menuASF" + aria-labelledby="dropdownASF"> + <li> + <a class="dropdown-item" href="https://www.apache.org/">Foundation</a> + </li> + <li> + <hr class="dropdown-divider" /> + </li> + <li> + <a class="dropdown-item" href="https://www.apache.org/licenses/">License</a> + </li> + <li> + <a class="dropdown-item" + href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a> + </li> + <li> + <a class="dropdown-item" + href="https://www.apache.org/foundation/thanks.html">Thanks</a> + </li> + <li> + <hr class="dropdown-divider" /> + </li> + <li> + <a class="dropdown-item" href="https://www.apache.org/security/">Security</a> + </li> + <li> + <a class="dropdown-item" + href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy Policy</a> + </li> + </ul> + </li> + </ul> + </div> + </div> </nav> diff --git a/atr/templates/index-committer.html b/atr/templates/index-committer.html index 2a5d3df..2011d4e 100644 --- a/atr/templates/index-committer.html +++ b/atr/templates/index-committer.html @@ -1,29 +1,27 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}Select a release ~ ATR{%- endblock title -%} {%- block description -%}Select a release ~ ATR{%- endblock description -%} -{# djlint:on #} {% block stylesheets %} {{ super() }} <style> - .page-card { - min-width: 18rem; - min-height: 105px; - } - - .page-version { - border-bottom: 1px solid #aaaaaa; - padding-bottom: 1rem; - } - - .page-logo { - max-height: 72px; - background-color: #ffffff; - padding-left: 0.5rem; - } + .page-card { + min-width: 18rem; + min-height: 105px; + } + + .page-version { + border-bottom: 1px solid #aaaaaa; + padding-bottom: 1rem; + } + + .page-logo { + max-height: 72px; + background-color: #ffffff; + padding-left: 0.5rem; + } </style> {% endblock stylesheets %} diff --git a/atr/templates/index-public.html b/atr/templates/index-public.html index fee83ce..98a03dc 100644 --- a/atr/templates/index-public.html +++ b/atr/templates/index-public.html @@ -1,10 +1,8 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}Apache Trusted Releases{%- endblock title -%} {%- block description -%}Apache Trusted Releases{%- endblock description -%} -{# djlint:on #} {% block content %} <h1>Apache Trusted Releases</h1> diff --git a/atr/templates/layouts/base.html b/atr/templates/layouts/base.html index 9d05757..5dd1f9e 100644 --- a/atr/templates/layouts/base.html +++ b/atr/templates/layouts/base.html @@ -17,31 +17,31 @@ href="{{ static_url('css/bootstrap-icons.min.css') }}" /> <link rel="stylesheet" href="{{ static_url('css/bootstrap.custom.css') }}" /> <style> - body { - padding-top: 72px; - } + body { + padding-top: 72px; + } - .fixed-top { - position: fixed; - } + .fixed-top { + position: fixed; + } - .asf-logo { - height: 42px; - margin-left: 6px; - } + .asf-logo { + height: 42px; + margin-left: 6px; + } - .trusted-releases { - position: relative; - top: -10px; - margin-left: 10px; - font-weight: 650 !important; - } + .trusted-releases { + position: relative; + top: -10px; + margin-left: 10px; + font-weight: 650 !important; + } - .navbar-adp-offset { - position: relative; - top: 3px; - margin-left: 16px; - } + .navbar-adp-offset { + position: relative; + top: 3px; + margin-left: 16px; + } </style> {% endblock stylesheets %} {% block head_extra %} diff --git a/atr/templates/notfound.html b/atr/templates/notfound.html index 92425ca..8416c7f 100644 --- a/atr/templates/notfound.html +++ b/atr/templates/notfound.html @@ -1,10 +1,8 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}404 ~ ATR{%- endblock title -%} {%- block description -%}An error occurred while cessing your request.{%- endblock description -%} -{# djlint:on #} {% block content %} <div> diff --git a/atr/templates/project-select.html b/atr/templates/project-select.html index 5ba0c4b..0b0f7b0 100644 --- a/atr/templates/project-select.html +++ b/atr/templates/project-select.html @@ -1,10 +1,8 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}Select a project ~ ATR{%- endblock title -%} {%- block description -%}Select a project ~ ATR{%- endblock description -%} -{# djlint:on #} {% block content %} diff --git a/atr/templates/projects.html b/atr/templates/projects.html index 38aeea4..442779e 100644 --- a/atr/templates/projects.html +++ b/atr/templates/projects.html @@ -1,10 +1,8 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}Projects ~ ATR{%- endblock title -%} {%- block description -%}Directory of current ASF projs and their releases.{%- endblock description -%} -{# djlint:on #} {% block content %} <h1>Projects</h1> @@ -32,148 +30,148 @@ {% set is_part = false %} {% if current_user and project.committee %} {% if current_user.uid in project.committee.committee_members or - current_user.uid in project.committee.committers or - current_user.uid in project.committee.release_managers %} - {% set is_part = true %} - {% endif %} + current_user.uid in project.committee.committers or + current_user.uid in project.committee.release_managers %} + {% set is_part = true %} {% endif %} - <div class="col"> - <div class="card h-100 shadow-sm atr-cursor-pointer page-project-card {{ '' if project.status.value.lower() == 'active' else 'bg-body-secondary' }}" - data-project-url="{{ as_url(get.projects.view, name=project.name) }}" - data-is-participant="{{ 'true' if is_part else 'false' }}"> - <div class="card-body"> - <div class="row g-1"> - <div class="col-sm"> - <h3 class="card-title fs-4 mb-3">{{ project.display_name }}</h3> - </div> - {% if project.status.value.lower() != 'active' %} - <div class="col-sm-2"> - <span class="badge text-bg-secondary">{{ project.status.value.lower() }}</span> - </div> - {% endif %} + {% endif %} + <div class="col"> + <div class="card h-100 shadow-sm atr-cursor-pointer page-project-card {{ '' if project.status.value.lower() == 'active' else 'bg-body-secondary' }}" + data-project-url="{{ as_url(get.projects.view, name=project.name) }}" + data-is-participant="{{ 'true' if is_part else 'false' }}"> + <div class="card-body"> + <div class="row g-1"> + <div class="col-sm"> + <h3 class="card-title fs-4 mb-3">{{ project.display_name }}</h3> </div> - {% if project.category %} - <div class="row g-1"> - {% set categories = project.category.split(', ') %} - {% for category in categories if category != "retired" %} - <div class="col-sm-auto"> - <span class="badge text-bg-primary">{{ category }}</span> - </div> - {% endfor %} - </div> - {% endif %} - {% if project.programming_languages %} - <div class="row g-1"> - {% set langs = project.programming_languages.split(', ') %} - {% for lang in langs %} - <div class="col-sm-auto"> - <span class="badge text-bg-success">{{ lang }}</span> - </div> - {% endfor %} + {% if project.status.value.lower() != 'active' %} + <div class="col-sm-2"> + <span class="badge text-bg-secondary">{{ project.status.value.lower() }}</span> </div> {% endif %} + </div> + {% if project.category %} + <div class="row g-1"> + {% set categories = project.category.split(', ') %} + {% for category in categories if category != "retired" %} + <div class="col-sm-auto"> + <span class="badge text-bg-primary">{{ category }}</span> + </div> + {% endfor %} + </div> + {% endif %} + {% if project.programming_languages %} + <div class="row g-1"> + {% set langs = project.programming_languages.split(', ') %} + {% for lang in langs %} + <div class="col-sm-auto"> + <span class="badge text-bg-success">{{ lang }}</span> + </div> + {% endfor %} + </div> + {% endif %} {# TODO: Could add "or is_viewing_as_admin_fn(current_user.uid)" #} {# But then the page is noisy for admins #} - {% if project.created_by == current_user.uid %} - <div class="mt-3"> - <form method="post" - action="{{ as_url(post.projects.delete) }}" - class="d-inline-block m-0" - onsubmit="return confirm('Are you sure you want to delete the project \'{{ project.display_name }}\'? This cannot be undone.');"> - {{ empty_form.hidden_tag() }} + {% if project.created_by == current_user.uid %} + <div class="mt-3"> + <form method="post" + action="{{ as_url(post.projects.delete) }}" + class="d-inline-block m-0" + onsubmit="return confirm('Are you sure you want to delete the project \'{{ project.display_name }}\'? This cannot be undone.');"> + {{ empty_form.hidden_tag() }} - <input type="hidden" name="project_name" value="{{ project.name }}" /> - <button type="submit" - class="btn btn-sm btn-outline-danger" - title="Delete {{ project.display_name }}"> - <i class="bi bi-trash"></i> Delete project - </button> - </form> - </div> - {% endif %} + <input type="hidden" name="project_name" value="{{ project.name }}" /> + <button type="submit" + class="btn btn-sm btn-outline-danger" + title="Delete {{ project.display_name }}"> + <i class="bi bi-trash"></i> Delete project + </button> + </form> + </div> + {% endif %} - </div> </div> </div> - {% endfor %} - </div> + </div> +{% endfor %} +</div> {% endblock content %} {% block javascripts %} {{ super() }} <script> - function filter() { - const projectFilter = document.getElementById("project-filter").value; - const cards = document.querySelectorAll(".page-project-card"); - let visibleCount = 0; - for (let card of cards) { - const nameElement = card.querySelector(".card-title"); - const name = nameElement.innerHTML; - if (!projectFilter) { - card.parentElement.hidden = false; - visibleCount++; - } else { - card.parentElement.hidden = !name.match(new RegExp(projectFilter, 'i')); - if (!card.parentElement.hidden) { - visibleCount++; - } - } + function filter() { + const projectFilter = document.getElementById("project-filter").value; + const cards = document.querySelectorAll(".page-project-card"); + let visibleCount = 0; + for (let card of cards) { + const nameElement = card.querySelector(".card-title"); + const name = nameElement.innerHTML; + if (!projectFilter) { + card.parentElement.hidden = false; + visibleCount++; + } else { + card.parentElement.hidden = !name.match(new RegExp(projectFilter, 'i')); + if (!card.parentElement.hidden) { + visibleCount++; } - document.getElementById("project-count").textContent = visibleCount; + } } + document.getElementById("project-count").textContent = visibleCount; + } // Add event listeners - document.getElementById("filter-button").addEventListener("click", filter); - document.getElementById("project-filter").addEventListener("keydown", function(event) { - if (event.key === "Enter") { - filter(); - event.preventDefault(); - } - }); + document.getElementById("filter-button").addEventListener("click", filter); + document.getElementById("project-filter").addEventListener("keydown", function(event) { + if (event.key === "Enter") { + filter(); + event.preventDefault(); + } + }); // Add click handlers for project cards - document.querySelectorAll(".page-project-card").forEach(function(card) { - card.addEventListener("click", function(event) { + document.querySelectorAll(".page-project-card").forEach(function(card) { + card.addEventListener("click", function(event) { // Prevent card navigation if click is inside a form - if (event.target.closest("form")) { - return; - } - window.location.href = this.getAttribute("data-project-url"); - }); + if (event.target.closest("form")) { + return; + } + window.location.href = this.getAttribute("data-project-url"); }); + }); // Participant filter logic - const participantButton = document.getElementById("filter-participant-button"); - participantButton.addEventListener("click", function() { - const showing = this.dataset.showing; - const cards = document.querySelectorAll(".page-project-card"); - let visibleCount = 0; + const participantButton = document.getElementById("filter-participant-button"); + participantButton.addEventListener("click", function() { + const showing = this.dataset.showing; + const cards = document.querySelectorAll(".page-project-card"); + let visibleCount = 0; - if (showing === "all") { + if (showing === "all") { // Switch to showing only participant projects - cards.forEach(card => { - const isParticipant = card.dataset.isParticipant === 'true'; - card.parentElement.hidden = !isParticipant; - if (!card.parentElement.hidden) { - visibleCount++; - } - }); - this.textContent = "Show all projects"; - this.dataset.showing = "participant"; - } else { - // Switch to showing all projects - cards.forEach(card => { - card.parentElement.hidden = false; - visibleCount++; - }); - this.textContent = "Show my projects"; - this.dataset.showing = "all"; + cards.forEach(card => { + const isParticipant = card.dataset.isParticipant === 'true'; + card.parentElement.hidden = !isParticipant; + if (!card.parentElement.hidden) { + visibleCount++; } + }); + this.textContent = "Show all projects"; + this.dataset.showing = "participant"; + } else { + // Switch to showing all projects + cards.forEach(card => { + card.parentElement.hidden = false; + visibleCount++; + }); + this.textContent = "Show my projects"; + this.dataset.showing = "all"; + } // Reset text filter when toggling participant view - document.getElementById("project-filter").value = ""; + document.getElementById("project-filter").value = ""; // Update count - document.getElementById("project-count").textContent = visibleCount; - }); + document.getElementById("project-count").textContent = visibleCount; + }); </script> {% endblock javascripts %} diff --git a/atr/templates/release-select.html b/atr/templates/release-select.html index 2793894..9a179fd 100644 --- a/atr/templates/release-select.html +++ b/atr/templates/release-select.html @@ -1,10 +1,8 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}Select a release of {{ project.display_name }} ~ ATR{%- endblock title -%} {%- block description -%}Select a release of {{ project.display_name }} ~ ATR{%- endblock description -%} -{# djlint:on #} {% block content %} <p class="atr-breadcrumbs"> diff --git a/atr/templates/releases-finished.html b/atr/templates/releases-finished.html index ecf202f..c57ba4d 100644 --- a/atr/templates/releases-finished.html +++ b/atr/templates/releases-finished.html @@ -1,10 +1,8 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}Releases of {{ project.display_name }} ~ ATR{%- endblock title -%} {%- block description -%}All of the finished releases of {{ project.display_name }} ATR.{%- endblock description -%} -{# djlint:on #} {% block content %} <p> diff --git a/atr/templates/releases.html b/atr/templates/releases.html index ec95042..4e5111f 100644 --- a/atr/templates/releases.html +++ b/atr/templates/releases.html @@ -1,23 +1,21 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}Releases ~ ATR{%- endblock title -%} {%- block description -%}Review public releases.{%- endblock description -%} -{# djlint:on #} {% block stylesheets %} {{ super() }} <style> - .page-release-meta-item::after { - content: "•"; - margin-left: 1rem; - color: #ccc; - } + .page-release-meta-item::after { + content: "•"; + margin-left: 1rem; + color: #ccc; + } - .page-release-meta-item:last-child::after { - content: none; - } + .page-release-meta-item:last-child::after { + content: none; + } </style> {% endblock stylesheets %} diff --git a/atr/templates/report-selected-path.html b/atr/templates/report-selected-path.html index 4bce635..89e44ed 100644 --- a/atr/templates/report-selected-path.html +++ b/atr/templates/report-selected-path.html @@ -1,21 +1,19 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}Report for {{ release.short_display_name }} {{ package.filename }} ~ ATR{%- endblock title -%} {%- block description -%}Show the report for the {{ release.short_display_name }} {{ package.filename }} candidate draft file.{%- endblock description -%} -{# djlint:on #} {% block stylesheets %} {{ super() }} <style> - .page-member-path-hide { - display: none !important; - } + .page-member-path-hide { + display: none !important; + } - .page-member-visible-odd { - background-color: rgba(0, 0, 0, 0.05); - } + .page-member-visible-odd { + background-color: rgba(0, 0, 0, 0.05); + } </style> {% endblock stylesheets %} @@ -54,11 +52,11 @@ </div> {% if primary_results %} {% set status_counts = { - "success": primary_results|selectattr("status.value", "equalto", "success")|list|length, - "failure": primary_results|selectattr("status.value", "equalto", "failure")|list|length, - "warning": primary_results|selectattr("status.value", "equalto", "warning")|list|length, - "exception": primary_results|selectattr("status.value", "equalto", "exception")|list|length - } %} + "success": primary_results|selectattr("status.value", "equalto", "success")|list|length, + "failure": primary_results|selectattr("status.value", "equalto", "failure")|list|length, + "warning": primary_results|selectattr("status.value", "equalto", "warning")|list|length, + "exception": primary_results|selectattr("status.value", "equalto", "exception")|list|length + } %} {% set earliest_checked = primary_results|min(attribute="created") %} {% set latest_checked = primary_results|max(attribute="created") %} <p> @@ -340,89 +338,89 @@ {% block javascripts %} {{ super() }} <script> - function toggleAllDetails() { - const details = document.querySelectorAll("details"); + function toggleAllDetails() { + const details = document.querySelectorAll("details"); // Check if any are closed - const anyClosed = Array.from(details).some(detail => !detail.open); + const anyClosed = Array.from(details).some(detail => !detail.open); // If any are closed, open all // Otherwise, close all - details.forEach(detail => detail.open = anyClosed); - } + details.forEach(detail => detail.open = anyClosed); + } - function toggleStatusVisibility(type, status) { - const btn = document.getElementById(`btn-toggle-${type}-${status}`); - const targets = document.querySelectorAll(`.atr-result-${type}.atr-result-status-${status}`); - if (!targets.length) return; - let elementsCurrentlyHidden = targets[0].classList.contains("atr-hide"); - targets.forEach(el => { - if (elementsCurrentlyHidden) { - el.classList.remove("atr-hide"); - } else { - el.classList.add("atr-hide"); - } - }); - const bsSt = (status === "failure" || status === "exception") ? "danger" : status; - const cntMatch = btn.textContent.match(/\((\d+)\)/); - if (!cntMatch) { - console.error("Button text regex mismatch for:", btn.textContent); - return; - } - const cnt = cntMatch[0]; - const newButtonAction = elementsCurrentlyHidden ? "Hide" : "Show"; - btn.querySelector("span").textContent = newButtonAction; - if (newButtonAction === "Hide") { - btn.classList.remove(`btn-outline-${bsSt}`); - btn.classList.add(`btn-${bsSt}`); - } else { - btn.classList.remove(`btn-${bsSt}`); - btn.classList.add(`btn-outline-${bsSt}`); - } - if (type === "member") { - updateMemberStriping(); - } else if (type === "primary") { - updatePrimaryStriping(); - } + function toggleStatusVisibility(type, status) { + const btn = document.getElementById(`btn-toggle-${type}-${status}`); + const targets = document.querySelectorAll(`.atr-result-${type}.atr-result-status-${status}`); + if (!targets.length) return; + let elementsCurrentlyHidden = targets[0].classList.contains("atr-hide"); + targets.forEach(el => { + if (elementsCurrentlyHidden) { + el.classList.remove("atr-hide"); + } else { + el.classList.add("atr-hide"); + } + }); + const bsSt = (status === "failure" || status === "exception") ? "danger" : status; + const cntMatch = btn.textContent.match(/\((\d+)\)/); + if (!cntMatch) { + console.error("Button text regex mismatch for:", btn.textContent); + return; } - - function restripeVisibleRows(rowSelector, stripeClass) { - let visibleIdx = 0; - document.querySelectorAll(rowSelector).forEach(row => { - row.classList.remove(stripeClass); - const hidden = row.classList.contains("atr-hide") || row.classList.contains("page-member-path-hide"); - if (!hidden) { - if (visibleIdx % 2 === 0) row.classList.add(stripeClass); - visibleIdx++; - } - }); + const cnt = cntMatch[0]; + const newButtonAction = elementsCurrentlyHidden ? "Hide" : "Show"; + btn.querySelector("span").textContent = newButtonAction; + if (newButtonAction === "Hide") { + btn.classList.remove(`btn-outline-${bsSt}`); + btn.classList.add(`btn-${bsSt}`); + } else { + btn.classList.remove(`btn-${bsSt}`); + btn.classList.add(`btn-outline-${bsSt}`); } - - function updatePrimaryStriping() { - restripeVisibleRows(".atr-result-primary", "page-member-visible-odd"); + if (type === "member") { + updateMemberStriping(); + } else if (type === "primary") { + updatePrimaryStriping(); } + } - function updateMemberStriping() { - restripeVisibleRows(".atr-result-member", "page-member-visible-odd"); - } + function restripeVisibleRows(rowSelector, stripeClass) { + let visibleIdx = 0; + document.querySelectorAll(rowSelector).forEach(row => { + row.classList.remove(stripeClass); + const hidden = row.classList.contains("atr-hide") || row.classList.contains("page-member-path-hide"); + if (!hidden) { + if (visibleIdx % 2 === 0) row.classList.add(stripeClass); + visibleIdx++; + } + }); + } - const mpfInput = document.getElementById("member-path-filter"); - if (mpfInput) { - mpfInput.addEventListener("input", function() { - const filterText = this.value.toLowerCase(); - document.querySelectorAll(".atr-result-member").forEach(row => { - const pathCell = row.cells[0]; - let hide = false; - if (filterText) { - if (!pathCell.textContent.toLowerCase().includes(filterText)) { - hide = true; - } - } - row.classList.toggle("page-member-path-hide", hide); - }); - updateMemberStriping(); - }); - } - updatePrimaryStriping(); - updateMemberStriping(); + function updatePrimaryStriping() { + restripeVisibleRows(".atr-result-primary", "page-member-visible-odd"); + } + + function updateMemberStriping() { + restripeVisibleRows(".atr-result-member", "page-member-visible-odd"); + } + + const mpfInput = document.getElementById("member-path-filter"); + if (mpfInput) { + mpfInput.addEventListener("input", function() { + const filterText = this.value.toLowerCase(); + document.querySelectorAll(".atr-result-member").forEach(row => { + const pathCell = row.cells[0]; + let hide = false; + if (filterText) { + if (!pathCell.textContent.toLowerCase().includes(filterText)) { + hide = true; + } + } + row.classList.toggle("page-member-path-hide", hide); + }); + updateMemberStriping(); + }); + } + updatePrimaryStriping(); + updateMemberStriping(); </script> {% endblock javascripts %} diff --git a/atr/templates/resolve-tabulated.html b/atr/templates/resolve-tabulated.html index a998786..843d72c 100644 --- a/atr/templates/resolve-tabulated.html +++ b/atr/templates/resolve-tabulated.html @@ -1,10 +1,8 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block title -%}Resolve vote ~ ATR{%- endblock title -%} {%- block description -%}Resolve vote for a release.{%- endblock description -%} -{# djlint:on #} {% block content %} <p> diff --git a/atr/templates/tutorial.html b/atr/templates/tutorial.html index a5a16af..7ee8ee0 100644 --- a/atr/templates/tutorial.html +++ b/atr/templates/tutorial.html @@ -1,20 +1,18 @@ {% extends "layouts/base.html" %} -{# djlint:off #} {%- block description -%}Tutorial for release managers ~ ATR{%- endblock description -%} {%- block title -%}Tutorial for release managers ~ ATR{%- endblock title -%} -{# djlint:on #} {% block stylesheets %} {{ super() }}<style> img { - border: 1px < !-- djlint:on -->solid #cccccc; - box-shadow: 0 0 1rem rgba(0, 0, 0, 0.2); - margin: 1rem 0; - max-width: 50%; + border: 1px < !-- djlint:on -->solid #cccccc; + box-shadow: 0 0 1rem rgba(0, 0, 0, 0.2); + margin: 1rem 0; + max-width: 50%; } -</style> + </style> {% endblock stylesheets %} {% block content %} diff --git a/atr/templates/user-ssh-keys.html b/atr/templates/user-ssh-keys.html index 95662d9..c0c4490 100644 --- a/atr/templates/user-ssh-keys.html +++ b/atr/templates/user-ssh-keys.html @@ -11,7 +11,7 @@ {% set key_comment = key_parts[2] if key_parts|length > 2 else 'key' %} <p> We have the SSH key <a href="{{ as_url(get.keys.keys, _anchor='ssh-key-' + key.fingerprint) }}" - title="{{ key.fingerprint }}"><code>{{- key_comment | trim -}}</code></a> on file for you. You can also <a href="{{ as_url(get.keys.ssh_add) }}">add another SSH key</a>. + title="{{ key.fingerprint }}"><code>{{- key_comment | trim -}}</code></a> on file for you. You can also <a href="{{ as_url(get.keys.ssh_add) }}">add another SSH key</a>. </p> {% elif key_count > 1 %} <p>We have the following SSH keys on file for you:</p> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
