From b983661b41a30a8c306095484ce167fabdd06988 Mon Sep 17 00:00:00 2001
From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com>
Date: Fri, 16 Jan 2026 10:26:21 -0500
Subject: [PATCH] Add seed-only moderation indicator
---
components/profile-modal.html | 8 ++++++++
js/services/moderationService.js | 35 ++++++++++++++++++++++++++++++++
js/services/trustBootstrap.js | 3 +++
js/ui/profileModalController.js | 16 ++++++++++++++-
4 files changed, 61 insertions(+), 1 deletion(-)
diff --git a/components/profile-modal.html b/components/profile-modal.html
index 50b317e0..64216637 100644
--- a/components/profile-modal.html
+++ b/components/profile-modal.html
@@ -304,6 +304,14 @@
0
+
+ ●
+ Seeded moderators only
+
diff --git a/js/services/moderationService.js b/js/services/moderationService.js
index 0cc17b01..31c0c563 100644
--- a/js/services/moderationService.js
+++ b/js/services/moderationService.js
@@ -497,6 +497,7 @@ export class ModerationService {
this.trustedMuteLists = new Map();
this.trustedMutedAuthors = new Map();
this.trustedMuteSubscriptions = new Map();
+ this.trustedSeedOnly = false;
this.emitter = new SimpleEventEmitter((message, error) => {
try {
@@ -549,6 +550,35 @@ export class ModerationService {
return merged;
}
+ computeTrustedSeedOnly() {
+ const trustedContacts =
+ this.trustedContacts instanceof Set ? this.trustedContacts : new Set();
+ const trustedSeedContacts =
+ this.trustedSeedContacts instanceof Set ? this.trustedSeedContacts : new Set();
+
+ if (!trustedSeedContacts.size || trustedContacts.size !== trustedSeedContacts.size) {
+ return false;
+ }
+
+ for (const value of trustedContacts) {
+ if (!trustedSeedContacts.has(value)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ updateTrustedSeedOnlyStatus() {
+ const nextValue = this.computeTrustedSeedOnly();
+ if (nextValue === this.trustedSeedOnly) {
+ return;
+ }
+
+ this.trustedSeedOnly = nextValue;
+ this.emit("trusted-seed-only", { seedOnly: nextValue });
+ }
+
rebuildTrustedContacts(nextContacts = new Set(), { previous = null } = {}) {
const sanitized = new Set();
@@ -580,6 +610,7 @@ export class ModerationService {
const seededNext = this.mergeSeedsIntoSet(sanitized);
this.trustedContacts = seededNext;
+ this.updateTrustedSeedOnlyStatus();
this.emit("contacts", { size: seededNext.size });
this.recomputeAllSummaries();
this.reconcileTrustedMuteSubscriptions(previousContacts, seededNext);
@@ -681,6 +712,10 @@ export class ModerationService {
this.rebuildTrustedContacts(this.viewerContacts, { previous: previousContacts });
}
+ isTrustedSeedOnly() {
+ return this.trustedSeedOnly === true;
+ }
+
logThresholdTransitions({
eventId = "",
reportType = "",
diff --git a/js/services/trustBootstrap.js b/js/services/trustBootstrap.js
index 24ba4f67..4f029bb5 100644
--- a/js/services/trustBootstrap.js
+++ b/js/services/trustBootstrap.js
@@ -117,6 +117,9 @@ export async function bootstrapTrustedSeeds() {
});
devLogger.info(`[trustBootstrap] Applying ${seeds.size} trusted seeds`, Array.from(seeds));
moderationService.setTrustedSeeds(seeds);
+ if (typeof moderationService.updateTrustedSeedOnlyStatus === "function") {
+ moderationService.updateTrustedSeedOnlyStatus();
+ }
if (
moderationService &&
typeof moderationService.recomputeAllSummaries === "function"
diff --git a/js/ui/profileModalController.js b/js/ui/profileModalController.js
index 25d5770e..d8b8d8b6 100644
--- a/js/ui/profileModalController.js
+++ b/js/ui/profileModalController.js
@@ -1421,6 +1421,8 @@ export class ProfileModalController {
document.getElementById("profileModerationTrustedMuteCount") || null;
this.moderationTrustedReportCount =
document.getElementById("profileModerationTrustedReportCount") || null;
+ this.moderationSeedOnlyIndicator =
+ document.getElementById("profileModerationSeedOnlyIndicator") || null;
this.moderationHideControlsGroup =
this.moderationSettingsCard?.querySelector(
"[data-role=\"trusted-hide-controls\"]",
@@ -7140,6 +7142,7 @@ export class ProfileModalController {
trustedContactsCount: 0,
trustedMuteContributors: 0,
trustedReportContributors: 0,
+ trustedSeedOnly: false,
};
const service = this.moderationService;
@@ -7147,6 +7150,12 @@ export class ProfileModalController {
return summary;
}
+ if (typeof service.isTrustedSeedOnly === "function") {
+ summary.trustedSeedOnly = service.isTrustedSeedOnly();
+ } else if (typeof service.trustedSeedOnly === "boolean") {
+ summary.trustedSeedOnly = service.trustedSeedOnly;
+ }
+
const trustedContacts =
service.trustedContacts instanceof Set
? service.trustedContacts
@@ -7225,7 +7234,8 @@ export class ProfileModalController {
if (
!(this.moderationTrustedContactsCount instanceof HTMLElement) &&
!(this.moderationTrustedMuteCount instanceof HTMLElement) &&
- !(this.moderationTrustedReportCount instanceof HTMLElement)
+ !(this.moderationTrustedReportCount instanceof HTMLElement) &&
+ !(this.moderationSeedOnlyIndicator instanceof HTMLElement)
) {
return;
}
@@ -7249,6 +7259,10 @@ export class ProfileModalController {
summary.trustedReportContributors,
);
}
+
+ if (this.moderationSeedOnlyIndicator instanceof HTMLElement) {
+ this.moderationSeedOnlyIndicator.hidden = !summary.trustedSeedOnly;
+ }
}
async handleModerationSettingsSave() {