From 7ac4abfa613e5b6cc57b6e2ed9eefee2f07d23fc Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Sun, 19 Oct 2025 21:40:23 -0400 Subject: [PATCH] Improve admin list hydration and visibility --- js/ui/profileModalController.js | 78 +++++++++++++++++++++---- tests/profile-modal-controller.test.mjs | 9 ++- 2 files changed, 73 insertions(+), 14 deletions(-) diff --git a/js/ui/profileModalController.js b/js/ui/profileModalController.js index 0a67b095..c94b5c50 100644 --- a/js/ui/profileModalController.js +++ b/js/ui/profileModalController.js @@ -3055,6 +3055,44 @@ export class ProfileModalController { } } + normalizeAdminListEntries(entries) { + const collected = []; + const seen = new Set(); + + const append = (value) => { + if (typeof value !== "string") { + return; + } + const trimmed = value.trim(); + if (!trimmed || seen.has(trimmed)) { + return; + } + seen.add(trimmed); + collected.push(trimmed); + }; + + if (Array.isArray(entries)) { + entries.forEach(append); + } else if (entries && typeof entries?.[Symbol.iterator] === "function") { + for (const entry of entries) { + append(entry); + } + } else if (entries && typeof entries === "object") { + Object.values(entries).forEach(append); + } + + try { + collected.sort((a, b) => a.localeCompare(b)); + } catch (error) { + devLogger.warn( + "[profileModal] Failed to sort admin list entries, using fallback order.", + error, + ); + } + + return collected; + } + renderAdminList(listEl, emptyEl, entries, options = {}) { if (!(listEl instanceof HTMLElement) || !(emptyEl instanceof HTMLElement)) { return; @@ -3071,17 +3109,31 @@ export class ProfileModalController { const entriesNeedingFetch = new Set(); listEl.innerHTML = ""; - const values = Array.isArray(entries) ? [...entries] : []; - values.sort((a, b) => a.localeCompare(b)); + + const values = this.normalizeAdminListEntries(entries); + + const toggleHiddenState = (element, shouldHide) => { + if (!(element instanceof HTMLElement)) { + return; + } + + if (shouldHide) { + element.classList.add("hidden"); + element.setAttribute("hidden", ""); + } else { + element.classList.remove("hidden"); + element.removeAttribute("hidden"); + } + }; if (!values.length) { - emptyEl.classList.remove("hidden"); - listEl.classList.add("hidden"); + toggleHiddenState(emptyEl, false); + toggleHiddenState(listEl, true); return; } - emptyEl.classList.add("hidden"); - listEl.classList.remove("hidden"); + toggleHiddenState(emptyEl, true); + toggleHiddenState(listEl, false); values.forEach((npub) => { const item = document.createElement("li"); @@ -3162,11 +3214,15 @@ export class ProfileModalController { } const isSuperAdmin = this.services.accessControl.isSuperAdmin(actorNpub); - const editors = this.services.accessControl - .getEditors() - .filter((npub) => npub && npub !== this.adminSuperNpub); - const whitelist = this.services.accessControl.getWhitelist(); - const blacklist = this.services.accessControl.getBlacklist(); + const editors = this.normalizeAdminListEntries( + this.services.accessControl.getEditors(), + ).filter((npub) => npub && npub !== this.adminSuperNpub); + const whitelist = this.normalizeAdminListEntries( + this.services.accessControl.getWhitelist(), + ); + const blacklist = this.normalizeAdminListEntries( + this.services.accessControl.getBlacklist(), + ); this.renderAdminList( this.adminModeratorList, diff --git a/tests/profile-modal-controller.test.mjs b/tests/profile-modal-controller.test.mjs index 87feb1ad..73c1868a 100644 --- a/tests/profile-modal-controller.test.mjs +++ b/tests/profile-modal-controller.test.mjs @@ -594,9 +594,9 @@ test('admin mutations invoke accessControl stubs and update admin DOM', async () }, canEditAdminLists: () => true, isSuperAdmin: () => true, - getEditors: () => ['npub1moderator'], - getWhitelist: () => ['npub1allow'], - getBlacklist: () => ['npub1block'], + getEditors: () => new Set(['npub1moderator']), + getWhitelist: () => new Set(['npub1allow']), + getBlacklist: () => new Set(['npub1block']), addModerator: async (actor, target) => { accessEvents.push(['addModerator', actor, target]); return { ok: true }; @@ -644,10 +644,13 @@ test('admin mutations invoke accessControl stubs and update admin DOM', async () assert.equal(controller.navButtons.admin.classList.contains('hidden'), false); assert.equal(controller.moderatorSection.classList.contains('hidden'), false); assert.equal(controller.adminModeratorList.querySelectorAll('li').length, 1); + assert.equal(controller.adminModeratorList.hasAttribute('hidden'), false); assert.equal( controller.whitelistList.querySelectorAll('button').length > 0, true, ); + assert.equal(controller.whitelistList.classList.contains('hidden'), false); + assert.equal(controller.whitelistList.hasAttribute('hidden'), false); controller.moderatorInput.value = 'npub1newmoderator'; await controller.handleAddModerator();