diff --git a/src/content/content.css b/src/content/content.css
index f50cc84..f737a76 100644
--- a/src/content/content.css
+++ b/src/content/content.css
@@ -220,6 +220,18 @@
.ss-ps-add:hover { background: rgba(74, 222, 128, 0.15); }
.ss-ps-add:disabled { border-color: #333; cursor: default; }
+.ss-ad-ignore {
+ margin-left: 4px;
+ padding: 2px 6px;
+ font-size: 11px;
+ background: transparent;
+ border: 1px solid #555;
+ border-radius: 4px;
+ color: #888;
+ cursor: pointer;
+}
+.ss-ad-ignore:hover { border-color: #888; color: #ccc; }
+
/* Floating reveal mode indicator */
.ss-reveal-badge {
position: fixed;
diff --git a/src/content/content.js b/src/content/content.js
index 4e69f94..552fd65 100644
--- a/src/content/content.js
+++ b/src/content/content.js
@@ -16,6 +16,8 @@
let mappings = [];
let identity = {};
let settings = { enabled: true, revealMode: false, showHighlights: false };
+ // Values the user has permanently dismissed from auto-detect warnings
+ let ignoredDetections = new Set();
try {
const configEl = document.querySelector('script[data-ss-config]');
@@ -278,7 +280,8 @@
// 4. Auto-detect: scan the FINAL text for unconfigured PII
// Auto-redact if enabled, otherwise just warn
if (settings.autoDetect !== false) {
- const warnings = autoDetectPII(finalText, identity, { detectProperNouns: settings.detectProperNouns === true });
+ const warnings = autoDetectPII(finalText, identity, { detectProperNouns: settings.detectProperNouns === true })
+ .filter(w => !ignoredDetections.has(w.value));
if (warnings.length > 0) {
// Auto-redact detected PII in the outbound text
if (settings.autoRedactDetected !== false) {
@@ -516,6 +519,7 @@
${w.name}
${w.value.length > 30 ? w.value.slice(0, 27) + '...' : w.value}
${w.hint}
+
`
).join('');
@@ -533,11 +537,24 @@
warningEl.classList.add('visible');
- // Close button
+ // Close button — hides for this session
warningEl.querySelector('.ss-ad-close').addEventListener('click', () => {
warningEl.classList.remove('visible');
});
+ // Ignore buttons — permanently dismiss a specific value
+ warningEl.querySelectorAll('.ss-ad-ignore').forEach(btn => {
+ btn.addEventListener('click', () => {
+ const val = decodeURIComponent(btn.dataset.value);
+ ignoredDetections.add(val);
+ setStorageData('ss_ignored_detections', [...ignoredDetections]);
+ btn.closest('.ss-ad-item').remove();
+ if (!warningEl.querySelector('.ss-ad-item')) {
+ warningEl.classList.remove('visible');
+ }
+ });
+ });
+
// Auto-dismiss after 15 seconds
if (warningTimeout) clearTimeout(warningTimeout);
warningTimeout = setTimeout(() => {
@@ -1348,6 +1365,7 @@
${settings.autoAddDetected !== false
? ``
: ''}
+
`;
}).join('');
@@ -1410,6 +1428,19 @@
btn.disabled = true;
});
});
+
+ // Ignore buttons — permanently dismiss a specific value
+ preSendWarningEl.querySelectorAll('.ss-ad-ignore').forEach(btn => {
+ btn.addEventListener('click', () => {
+ const val = decodeURIComponent(btn.dataset.value);
+ ignoredDetections.add(val);
+ setStorageData('ss_ignored_detections', [...ignoredDetections]);
+ btn.closest('.ss-ps-item').remove();
+ if (!preSendWarningEl.querySelector('.ss-ps-item')) {
+ preSendWarningEl.classList.remove('visible');
+ }
+ });
+ });
}
// Replace all occurrences of `real` with `fake` in an input or contenteditable element
@@ -1464,7 +1495,8 @@
return;
}
- const warnings = autoDetectPII(text, identity, { detectProperNouns: settings.detectProperNouns === true });
+ const warnings = autoDetectPII(text, identity, { detectProperNouns: settings.detectProperNouns === true })
+ .filter(w => !ignoredDetections.has(w.value));
if (warnings.length > 0) {
showPreSendWarning(warnings, target);
} else if (preSendWarningEl) {
@@ -1542,6 +1574,11 @@
document.addEventListener('DOMContentLoaded', boot);
}
+ // Load permanently-ignored detections from storage
+ getStorageData('ss_ignored_detections').then(data => {
+ if (Array.isArray(data)) ignoredDetections = new Set(data);
+ });
+
// Also update badge when settings change
const origCheckReveal = checkRevealToggle;
checkRevealToggle = function () {