diff --git a/netbox/project-static/dist/netbox.js b/netbox/project-static/dist/netbox.js index f430604f9..e88aa3ad7 100644 Binary files a/netbox/project-static/dist/netbox.js and b/netbox/project-static/dist/netbox.js differ diff --git a/netbox/project-static/dist/netbox.js.map b/netbox/project-static/dist/netbox.js.map index 753576bc3..59bc99bd3 100644 Binary files a/netbox/project-static/dist/netbox.js.map and b/netbox/project-static/dist/netbox.js.map differ 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..057a324e4 --- /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..2ae22ede0 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'; diff --git a/netbox/project-static/src/stores/secret.ts b/netbox/project-static/src/stores/secret.ts new file mode 100644 index 000000000..bfb3bea6b --- /dev/null +++ b/netbox/project-static/src/stores/secret.ts @@ -0,0 +1,6 @@ +import { createState } from '../state'; + +export const secretState = createState<{ hidden: boolean }>( + { hidden: true }, + { persist: true, key: 'netbox-secret' }, +); diff --git a/netbox/templates/wireless/inc/authentication_attrs.html b/netbox/templates/wireless/inc/authentication_attrs.html index ed4c7546c..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 8b45b0116..01c64db1d 100644 --- a/netbox/wireless/forms/model_forms.py +++ b/netbox/wireless/forms/model_forms.py @@ -1,3 +1,4 @@ +from django.forms import PasswordInput from django.utils.translation import gettext as _ from dcim.models import Device, Interface, Location, Region, Site, SiteGroup from ipam.models import VLAN, VLANGroup @@ -101,6 +102,10 @@ class WirelessLANForm(TenancyForm, NetBoxModelForm): 'status': StaticSelect, 'auth_type': StaticSelect, 'auth_cipher': StaticSelect, + 'auth_psk': PasswordInput( + render_value=True, + attrs={'data-toggle': 'password'} + ), } @@ -206,6 +211,10 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm): 'status': StaticSelect, 'auth_type': StaticSelect, 'auth_cipher': StaticSelect, + 'auth_psk': PasswordInput( + render_value=True, + attrs={'data-toggle': 'password'} + ), } labels = { 'auth_type': 'Type',