diff --git a/netbox/project-static/src/buttons/index.ts b/netbox/project-static/src/buttons/index.ts index fe2ccaaef..6c1c0db0b 100644 --- a/netbox/project-static/src/buttons/index.ts +++ b/netbox/project-static/src/buttons/index.ts @@ -5,6 +5,7 @@ import { initReslug } from './reslug'; import { initSelectAll } from './selectAll'; import { initSelectMultiple } from './selectMultiple'; import { initMarkdownPreviews } from './markdownPreview'; +import { initSecretToggle } from './secretToggle'; export function initButtons(): void { for (const func of [ @@ -15,6 +16,7 @@ export function initButtons(): void { initSelectMultiple, initMoveButtons, initMarkdownPreviews, + initSecretToggle, ]) { func(); } diff --git a/netbox/project-static/src/buttons/secretToggle.ts b/netbox/project-static/src/buttons/secretToggle.ts new file mode 100644 index 000000000..ba26a2474 --- /dev/null +++ b/netbox/project-static/src/buttons/secretToggle.ts @@ -0,0 +1,77 @@ +import { secretState } from '../stores'; +import { getElement, getElements, isTruthy } from '../util'; + +import type { StateManager } from '../state'; + +type SecretState = { hidden: boolean }; + +/** + * Change toggle button's text and attribute to reflect the current state. + * + * @param hidden `true` if the current state is hidden, `false` otherwise. + * @param button Toggle element. + */ +function toggleSecretButton(hidden: boolean, button: HTMLButtonElement): void { + button.setAttribute('data-secret-visibility', hidden ? 'hidden' : 'shown'); + button.innerText = hidden ? 'Show Secret' : 'Hide Secret'; +} + +/** + * Show secret. + */ +function showSecret(): void { + const secret = getElement('secret') + if (isTruthy(secret)) { + const value = secret.getAttribute('data-secret') + if (isTruthy(value)) { + secret.innerText = value + } + } +} + +/** + * Hide secret. + */ +function hideSecret(): void { + const secret = getElement('secret') + if (isTruthy(secret)) { + const value = secret.getAttribute('data-secret') + if (isTruthy(value)) { + secret.innerText = '••••••••' + } + } +} + +/** + * Update secret state and visualization when the button is clicked. + * + * @param state State instance. + * @param button Toggle element. + */ +function handleSecretToggle(state: StateManager, button: HTMLButtonElement): void { + state.set('hidden', !state.get('hidden')) + const hidden = state.get('hidden'); + + if (hidden) { + hideSecret(); + } else { + showSecret(); + } + toggleSecretButton(hidden, button); +} + +/** + * Initialize secret toggle button. + */ +export function initSecretToggle(): void { + hideSecret() + for (const button of getElements('button.toggle-secret')) { + button.addEventListener( + 'click', + event => { + handleSecretToggle(secretState, event.currentTarget as HTMLButtonElement); + }, + false, + ); + } +} diff --git a/netbox/project-static/src/stores/index.ts b/netbox/project-static/src/stores/index.ts index d4644e619..b3ea85141 100644 --- a/netbox/project-static/src/stores/index.ts +++ b/netbox/project-static/src/stores/index.ts @@ -1,3 +1,4 @@ export * from './objectDepth'; export * from './rackImages'; export * from './previousPkCheck'; +export * from './secret'; \ No newline at end of file diff --git a/netbox/project-static/src/stores/secret.ts b/netbox/project-static/src/stores/secret.ts new file mode 100644 index 000000000..5c2aa4fe9 --- /dev/null +++ b/netbox/project-static/src/stores/secret.ts @@ -0,0 +1,7 @@ +import { createState } from '../state'; + +export const secretState = createState<{ hidden: boolean }>( + { hidden: true }, + { persist: true, key: 'netbox-secret' }, + ); + \ No newline at end of file diff --git a/netbox/templates/base/base.html b/netbox/templates/base/base.html index 64a365639..138a92b6d 100644 --- a/netbox/templates/base/base.html +++ b/netbox/templates/base/base.html @@ -101,24 +101,6 @@ } window.addEventListener('resize', function(){ checkSideNav() }); checkSideNav(); - - window.addEventListener('DOMContentLoaded', function() { - secretToggle = document.querySelector('.secret-toggle') - secret = document.querySelector('.secret') - secret_value = secret.innerHTML - obfuscated = "••••••••" - secret.innerHTML = obfuscated - - secretToggle.addEventListener('click', function() { - if (secretToggle.classList.contains('active')) { - secret.innerHTML = secret_value - secretToggle.innerHTML = 'Hide' - } else { - secret.innerHTML = obfuscated - secretToggle.innerHTML = 'Show' - } - }) - }) {# Page layout #} diff --git a/netbox/templates/wireless/inc/authentication_attrs.html b/netbox/templates/wireless/inc/authentication_attrs.html index a28567160..08b2d9065 100644 --- a/netbox/templates/wireless/inc/authentication_attrs.html +++ b/netbox/templates/wireless/inc/authentication_attrs.html @@ -14,7 +14,12 @@ PSK - {{ object.auth_psk|placeholder }} + + {{ object.auth_psk|placeholder }} + {% if object.auth_psk %} + + {% endif %} + diff --git a/netbox/wireless/forms/model_forms.py b/netbox/wireless/forms/model_forms.py index b1a47137d..01c64db1d 100644 --- a/netbox/wireless/forms/model_forms.py +++ b/netbox/wireless/forms/model_forms.py @@ -102,7 +102,10 @@ class WirelessLANForm(TenancyForm, NetBoxModelForm): 'status': StaticSelect, 'auth_type': StaticSelect, 'auth_cipher': StaticSelect, - 'auth_psk': PasswordInput(attrs={'data-toggle': 'password'}) + 'auth_psk': PasswordInput( + render_value=True, + attrs={'data-toggle': 'password'} + ), } @@ -208,7 +211,10 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm): 'status': StaticSelect, 'auth_type': StaticSelect, 'auth_cipher': StaticSelect, - 'auth_psk': PasswordInput(attrs={'data-toggle': 'password'}), + 'auth_psk': PasswordInput( + render_value=True, + attrs={'data-toggle': 'password'} + ), } labels = { 'auth_type': 'Type',