From 3c6f774756b317164095b454e3d4940ab50b005b Mon Sep 17 00:00:00 2001 From: rjonesbsink Date: Tue, 28 Jul 2026 12:49:43 -0400 Subject: [PATCH] fix: feed_api_key field doesn't show its "stored" state after masking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up to #7. 07b9d1d already added data-secret="1" to feed_api_key in settings.php (fixing the actual data loss), but didn't touch config.js — the generic applySettingsToForm() has no idea about the _set sentinel the server sends for masked fields, so the field still LOOKS empty and the "external feed is disabled" banner still shows even when a key is in fact configured. Cosmetic next to the data loss, but still wrong, and called out explicitly in the #7 thread as a gap being left for a separate fix. loadApiKeys() now reads feed_api_key_set and shows the same "stored — leave blank to keep, type to replace" placeholder loadSlackConfig() already uses for its secret fields, and tracks a data-configured flag so updateFeedKeyBanner() reflects the real state instead of just checking whether the box happens to be non-empty. (Dropped the settings.php data-secret="1" hunk this branch used to carry — main already has it via 07b9d1d, identical text, so keeping it here was pure duplication.) --- assets/js/config.js | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/assets/js/config.js b/assets/js/config.js index 22eb0e5..4a71f3c 100644 --- a/assets/js/config.js +++ b/assets/js/config.js @@ -6071,10 +6071,16 @@ var input = document.getElementById('setFeedApiKey'); var banner = document.getElementById('feedKeyMissingBanner'); if (!input || !banner) return; - if (input.value.trim() === '') { - banner.classList.remove('d-none'); - } else { + // feed_api_key is a data-secret field: a blank value on load doesn't + // mean "not configured", it means "stored, not shown". Trust the + // configured flag set by loadApiKeys() unless the admin has typed + // a new value this session. + var hasTypedValue = input.value.trim() !== ''; + var isConfigured = input.dataset.configured === '1'; + if (hasTypedValue || isConfigured) { banner.classList.add('d-none'); + } else { + banner.classList.remove('d-none'); } } @@ -6082,6 +6088,19 @@ apiGet('settings').then(function (data) { var settings = data.settings || {}; applySettingsToForm(document.getElementById('apiKeysForm'), settings); + // feed_api_key is data-secret — the server never sends the real + // value, only a feed_api_key_set boolean. applySettingsToForm + // can't fill a field it wasn't given a value for, so handle the + // placeholder here (same "stored / not set" pattern as Slack's + // secret fields). + var feedInput = document.getElementById('setFeedApiKey'); + if (feedInput) { + feedInput.value = ''; + feedInput.dataset.configured = settings.feed_api_key_set ? '1' : '0'; + feedInput.placeholder = settings.feed_api_key_set + ? '•••• stored — leave blank to keep, type to replace' + : '(empty — feed disabled)'; + } updateFeedKeyBanner(); }).catch(function (err) { showAlert('Failed to load API keys: ' + err.message, 'danger');