Toggle credentials in instance detail view
This commit is contained in:
parent
69a0c5bd5d
commit
461565cdd4
2 changed files with 96 additions and 3 deletions
|
|
@ -220,8 +220,17 @@
|
|||
{% if instance.connection_credentials %}
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4>{% translate "Connection Credentials" %}</h4>
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h4 class="mb-0">{% translate "Connection Credentials" %}</h4>
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline-secondary"
|
||||
id="toggle-credentials-btn"
|
||||
data-show-text="{% translate "Show All" %}"
|
||||
data-hide-text="{% translate "Hide All" %}"
|
||||
onclick="toggleAllCredentials()">
|
||||
<i class="bi bi-eye me-1"></i>
|
||||
<span id="toggle-credentials-text">{% translate "Show All" %}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
|
|
@ -230,6 +239,7 @@
|
|||
<tr>
|
||||
<th>{% translate "Name" %}</th>
|
||||
<th>{% translate "Value" %}</th>
|
||||
<th style="width: 50px;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -240,7 +250,17 @@
|
|||
{% if key == "error" %}
|
||||
<span class="text-danger">{{ value }}</span>
|
||||
{% else %}
|
||||
<code>{{ value }}</code>
|
||||
<code class="credential-value" data-value="{{ value }}">••••••••••••</code>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-center">
|
||||
{% if key != "error" %}
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-link p-0 credential-toggle"
|
||||
onclick="toggleCredential(this)"
|
||||
title="{% translate 'Show/Hide' %}">
|
||||
<i class="bi bi-eye"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -248,6 +268,10 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="text-muted small mt-2">
|
||||
<i class="bi bi-info-circle me-1"></i>
|
||||
{% translate "Click the eye icon to reveal individual credentials, or use 'Show All' to reveal all at once." %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -286,6 +310,7 @@
|
|||
{% endblock content %}
|
||||
{% block extra_js %}
|
||||
<script src="{% static 'js/local-time.js' %}"></script>
|
||||
<script src="{% static 'js/credentials.js' %}"></script>
|
||||
<script>
|
||||
// Initialize Bootstrap popovers for help text
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
|
|
|
|||
68
src/servala/static/js/credentials.js
Normal file
68
src/servala/static/js/credentials.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
const CREDENTIAL_MASK = '••••••••••••';
|
||||
|
||||
function toggleCredential(button) {
|
||||
const row = button.closest('tr');
|
||||
const codeEl = row.querySelector('.credential-value');
|
||||
const icon = button.querySelector('i');
|
||||
|
||||
if (!codeEl) return;
|
||||
|
||||
const isHidden = codeEl.textContent === CREDENTIAL_MASK;
|
||||
|
||||
if (isHidden) {
|
||||
codeEl.textContent = codeEl.getAttribute('data-value');
|
||||
icon.classList.remove('bi-eye');
|
||||
icon.classList.add('bi-eye-slash');
|
||||
} else {
|
||||
codeEl.textContent = CREDENTIAL_MASK;
|
||||
icon.classList.remove('bi-eye-slash');
|
||||
icon.classList.add('bi-eye');
|
||||
}
|
||||
|
||||
updateShowAllButton();
|
||||
}
|
||||
|
||||
function toggleAllCredentials() {
|
||||
const credentials = document.querySelectorAll('.credential-value');
|
||||
const anyHidden = Array.from(credentials).some(el => el.textContent === CREDENTIAL_MASK);
|
||||
|
||||
credentials.forEach(function (codeEl) {
|
||||
const row = codeEl.closest('tr');
|
||||
const button = row.querySelector('.credential-toggle');
|
||||
const icon = button ? button.querySelector('i') : null;
|
||||
|
||||
if (anyHidden) {
|
||||
codeEl.textContent = codeEl.getAttribute('data-value');
|
||||
if (icon) {
|
||||
icon.classList.remove('bi-eye');
|
||||
icon.classList.add('bi-eye-slash');
|
||||
}
|
||||
} else {
|
||||
codeEl.textContent = CREDENTIAL_MASK;
|
||||
if (icon) {
|
||||
icon.classList.remove('bi-eye-slash');
|
||||
icon.classList.add('bi-eye');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
updateShowAllButton();
|
||||
}
|
||||
|
||||
function updateShowAllButton() {
|
||||
const credentials = document.querySelectorAll('.credential-value');
|
||||
const anyHidden = Array.from(credentials).some(el => el.textContent === CREDENTIAL_MASK);
|
||||
const toggleBtn = document.getElementById('toggle-credentials-btn');
|
||||
const toggleText = document.getElementById('toggle-credentials-text');
|
||||
const toggleIcon = toggleBtn ? toggleBtn.querySelector('i') : null;
|
||||
|
||||
if (toggleText && toggleBtn) {
|
||||
const showText = toggleBtn.getAttribute('data-show-text') || 'Show All';
|
||||
const hideText = toggleBtn.getAttribute('data-hide-text') || 'Hide All';
|
||||
toggleText.textContent = anyHidden ? showText : hideText;
|
||||
}
|
||||
if (toggleIcon) {
|
||||
toggleIcon.classList.toggle('bi-eye', anyHidden);
|
||||
toggleIcon.classList.toggle('bi-eye-slash', !anyHidden);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue