Skip to content

Instantly share code, notes, and snippets.

@23maverick23
Last active September 23, 2025 22:14
Show Gist options
  • Save 23maverick23/a9c8847a609529f57f6bdd3cf53d7bba to your computer and use it in GitHub Desktop.
Save 23maverick23/a9c8847a609529f57f6bdd3cf53d7bba to your computer and use it in GitHub Desktop.
NS: User Script: Claude Connectors Filter
// ==UserScript==
// @name Claude Connectors Filter
// @namespace http://tampermonkey.net/
// @version 1.0.1
// @description Filter connectors with configurable username - NetSuite themed
// @author rymoio (https://rymo.io/)
// @match https://claude.ai/settings/connectors*
// @icon https://www.google.com/s2/favicons?sz=64&domain=claude.ai
// @require https://openuserjs.org/src/libs/sizzle/GM_config.js
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @downloadURL https://gist.githubusercontent.com/23maverick23/a9c8847a609529f57f6bdd3cf53d7bba/raw/claude_connectors_filter_us.js
// @updateURL https://gist.githubusercontent.com/23maverick23/a9c8847a609529f57f6bdd3cf53d7bba/raw/claude_connectors_filter_us.js
// ==/UserScript==
(function() {
'use strict';
// NetSuite Ocean Palette & Brand Colors
const COLORS = {
// Ocean Palette (Primary Brand Colors)
ocean180: '#13212C', // Darkest - primary text, headers
ocean150: '#264759', // Dark - secondary text
ocean120: '#36677D', // PRIMARY BRAND COLOR - main actions, headers
ocean60: '#94BFCE', // Light - accents, highlights
ocean30: '#E7F2F5', // Very light - borders, dividers
ocean10: '#F5FAFC', // Lightest - subtle backgrounds
// Semantic Accent Colors
pine: '#86B596', // SUCCESS - positive metrics, growth
rose: '#FF8675', // ERROR/NEGATIVE - warnings, declines
yellow: '#E2C06B', // WARNING - highlights, action items
// Base Colors
white: '#FFFFFF', // Card backgrounds
neutral: '#F1EFED', // Page background
// Aliases for easy use
primary: '#36677D', // Ocean 120
textPrimary: '#13212C', // Ocean 180
textSecondary: '#264759', // Ocean 150
border: '#E7F2F5', // Ocean 30
pageBackground: '#F1EFED',
cardBackground: '#FFFFFF'
};
let isFiltered = false;
let configInitialized = false;
// Simple fallback storage if GM_config fails
function getStoredValue(key, defaultValue) {
try {
if (typeof GM_getValue !== 'undefined') {
return GM_getValue(key, defaultValue);
}
} catch (e) {
console.warn('GM_getValue not available, using localStorage');
}
return localStorage.getItem(`connectorFilter_${key}`) || defaultValue;
}
function setStoredValue(key, value) {
try {
if (typeof GM_setValue !== 'undefined') {
GM_setValue(key, value);
}
} catch (e) {
console.warn('GM_setValue not available, using localStorage');
}
localStorage.setItem(`connectorFilter_${key}`, value);
}
// Initialize GM_config with error handling (removed color setting)
function initConfig() {
try {
if (typeof GM_config !== 'undefined') {
GM_config.init({
'id': 'ConnectorFilterConfig',
'title': 'Connector Filter Settings',
'fields': {
'username': {
'label': 'Username to filter by',
'type': 'text',
'default': '',
'title': 'Enter the username prefix to show (case insensitive)'
}
},
'css': `
#ConnectorFilterConfig {
background: ${COLORS.cardBackground} !important;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
border: 1px solid ${COLORS.border} !important;
border-radius: 8px !important;
}
#ConnectorFilterConfig .config_header {
background: ${COLORS.primary} !important;
color: ${COLORS.white} !important;
padding: 20px !important;
font-weight: 600 !important;
border-radius: 8px 8px 0 0 !important;
}
#ConnectorFilterConfig .section_header {
background: ${COLORS.ocean10} !important;
color: ${COLORS.textPrimary} !important;
padding: 12px 20px !important;
font-weight: 500 !important;
}
#ConnectorFilterConfig .field_label {
color: ${COLORS.textPrimary} !important;
font-weight: 500 !important;
margin-bottom: 8px !important;
}
#ConnectorFilterConfig input[type="text"] {
border: 2px solid ${COLORS.border} !important;
border-radius: 6px !important;
padding: 12px 16px !important;
font-size: 14px !important;
color: ${COLORS.textPrimary} !important;
background: ${COLORS.white} !important;
}
#ConnectorFilterConfig input[type="text"]:focus {
border-color: ${COLORS.primary} !important;
outline: none !important;
box-shadow: 0 0 0 3px ${COLORS.ocean30} !important;
}
#ConnectorFilterConfig .saveclose_buttons {
background: ${COLORS.ocean10} !important;
padding: 20px !important;
border-radius: 0 0 8px 8px !important;
}
#ConnectorFilterConfig .saveclose_buttons input {
background: ${COLORS.primary} !important;
color: ${COLORS.white} !important;
border: none !important;
padding: 12px 24px !important;
border-radius: 6px !important;
margin-right: 12px !important;
cursor: pointer !important;
font-weight: 500 !important;
transition: all 0.2s ease !important;
}
#ConnectorFilterConfig .saveclose_buttons input:hover {
background: ${COLORS.ocean150} !important;
transform: translateY(-1px) !important;
}
#ConnectorFilterConfig .saveclose_buttons input[value="Cancel"] {
background: ${COLORS.neutral} !important;
color: ${COLORS.textSecondary} !important;
}
#ConnectorFilterConfig .saveclose_buttons input[value="Cancel"]:hover {
background: ${COLORS.border} !important;
}
`
});
GM_config.onSave = function() {
console.log('Config saved via GM_config');
updateButtons();
};
configInitialized = true;
console.log('GM_config initialized successfully');
}
} catch (e) {
console.warn('GM_config initialization failed:', e);
configInitialized = false;
}
}
function getUsername() {
if (configInitialized && typeof GM_config !== 'undefined') {
try {
return GM_config.get('username').toLowerCase().trim();
} catch (e) {
console.warn('GM_config.get failed:', e);
}
}
return getStoredValue('username', 'rmorrissey').toLowerCase().trim();
}
function openSettings() {
if (configInitialized && typeof GM_config !== 'undefined') {
try {
GM_config.open();
return;
} catch (e) {
console.warn('GM_config.open failed:', e);
}
}
// Fallback: simple prompt-based settings
const currentUsername = getStoredValue('username', 'rmorrissey');
const newUsername = prompt('Enter username to filter by:', currentUsername);
if (newUsername !== null && newUsername.trim()) {
setStoredValue('username', newUsername.trim());
console.log('Username updated via prompt:', newUsername.trim());
updateButtons();
}
}
function findConnectorRows() {
const flexRows = document.querySelectorAll('.flex.flex-row.gap-3.items-center');
console.log(`Found ${flexRows.length} potential connector rows`);
return Array.from(flexRows);
}
function filterConnectors() {
const username = getUsername();
console.log(`=== FILTERING CONNECTORS FOR: "${username}" ===`);
const rows = findConnectorRows();
if (rows.length === 0) {
console.error('No connector rows found! Make sure the page is fully loaded.');
alert('No connector rows found! Make sure the page is fully loaded.');
return;
}
if (!username) {
console.error('No username configured!');
alert('Please configure a username first (click Settings button)');
return;
}
let hiddenCount = 0;
let visibleCount = 0;
rows.forEach((row, index) => {
const allText = row.textContent.toLowerCase();
console.log(`Row ${index} text:`, row.textContent.trim());
const hasUsername = allText.includes(username);
if (hasUsername) {
console.log(`✅ Row ${index}: KEEPING (contains "${username}")`);
row.style.display = '';
// Use subtle ocean10 background with pine border for matched rows
row.style.backgroundColor = COLORS.ocean10;
row.style.borderLeft = `4px solid ${COLORS.pine}`;
row.style.paddingLeft = '12px';
visibleCount++;
} else {
console.log(`❌ Row ${index}: HIDING (no "${username}" found)`);
row.style.display = 'none';
hiddenCount++;
}
});
console.log(`=== FILTER COMPLETE ===`);
console.log(`Hidden: ${hiddenCount} rows`);
console.log(`Visible: ${visibleCount} rows`);
isFiltered = true;
updateButtons();
}
function showAllConnectors() {
console.log('=== SHOWING ALL CONNECTORS ===');
const rows = findConnectorRows();
rows.forEach((row, index) => {
console.log(`Showing row ${index}`);
row.style.display = '';
row.style.backgroundColor = '';
row.style.borderLeft = '';
row.style.paddingLeft = '';
});
console.log(`=== SHOW ALL COMPLETE ===`);
console.log(`Restored ${rows.length} rows`);
isFiltered = false;
updateButtons();
}
function updateButtons() {
const filterBtn = document.getElementById('connector-filter-btn');
const settingsBtn = document.getElementById('connector-settings-btn');
if (filterBtn) {
if (isFiltered) {
filterBtn.textContent = 'Show All Connectors';
filterBtn.style.background = COLORS.pine; // Success green for active state
filterBtn.style.borderColor = COLORS.pine;
} else {
const username = getUsername();
filterBtn.textContent = username ? `Filter: ${username}` : 'Filter Connectors';
filterBtn.style.background = COLORS.primary;
filterBtn.style.borderColor = COLORS.primary;
}
}
console.log('Buttons updated');
}
function createButtons() {
console.log('Creating buttons...');
// Remove existing buttons if present
['connector-filter-btn', 'connector-settings-btn'].forEach(id => {
const existing = document.getElementById(id);
if (existing) {
console.log(`Removing existing button: ${id}`);
existing.remove();
}
});
// Create filter button
const filterButton = document.createElement('button');
filterButton.id = 'connector-filter-btn';
const username = getUsername();
filterButton.textContent = username ? `Filter: ${username}` : 'Filter Connectors';
filterButton.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
z-index: 9999;
padding: 12px 20px;
background: ${COLORS.primary};
color: ${COLORS.white};
border: 2px solid ${COLORS.primary};
border-radius: 8px;
cursor: pointer;
font-weight: 600;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
box-shadow: 0 4px 12px rgba(54, 103, 125, 0.2);
transition: all 0.2s ease;
font-size: 14px;
`;
// Create settings button
const settingsButton = document.createElement('button');
settingsButton.id = 'connector-settings-btn';
settingsButton.innerHTML = '⚙️ Settings';
settingsButton.style.cssText = `
position: fixed;
top: 75px;
right: 20px;
z-index: 9999;
padding: 10px 16px;
background: ${COLORS.ocean60};
color: ${COLORS.textPrimary};
border: 2px solid ${COLORS.ocean60};
border-radius: 8px;
cursor: pointer;
font-weight: 500;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
box-shadow: 0 2px 8px rgba(148, 191, 206, 0.3);
transition: all 0.2s ease;
font-size: 13px;
`;
// Add hover effects
filterButton.addEventListener('mouseenter', () => {
if (isFiltered) {
filterButton.style.background = '#6fa085'; // Darker pine
filterButton.style.borderColor = '#6fa085';
} else {
filterButton.style.background = COLORS.ocean150;
filterButton.style.borderColor = COLORS.ocean150;
}
filterButton.style.transform = 'translateY(-2px)';
filterButton.style.boxShadow = '0 6px 16px rgba(54, 103, 125, 0.3)';
});
filterButton.addEventListener('mouseleave', () => {
if (isFiltered) {
filterButton.style.background = COLORS.pine;
filterButton.style.borderColor = COLORS.pine;
} else {
filterButton.style.background = COLORS.primary;
filterButton.style.borderColor = COLORS.primary;
}
filterButton.style.transform = 'translateY(0)';
filterButton.style.boxShadow = '0 4px 12px rgba(54, 103, 125, 0.2)';
});
settingsButton.addEventListener('mouseenter', () => {
settingsButton.style.background = COLORS.ocean30;
settingsButton.style.borderColor = COLORS.ocean30;
settingsButton.style.transform = 'translateY(-1px)';
});
settingsButton.addEventListener('mouseleave', () => {
settingsButton.style.background = COLORS.ocean60;
settingsButton.style.borderColor = COLORS.ocean60;
settingsButton.style.transform = 'translateY(0)';
});
// Add click handlers
filterButton.addEventListener('click', () => {
console.log('=== FILTER BUTTON CLICKED ===');
console.log('Current state - isFiltered:', isFiltered);
if (isFiltered) {
showAllConnectors();
} else {
filterConnectors();
}
});
settingsButton.addEventListener('click', () => {
console.log('=== SETTINGS BUTTON CLICKED ===');
openSettings();
});
document.body.appendChild(filterButton);
document.body.appendChild(settingsButton);
console.log('Both buttons added to page');
}
// Register menu command as backup
if (typeof GM_registerMenuCommand !== 'undefined') {
GM_registerMenuCommand('Open Connector Filter Settings', openSettings);
}
// Initialize everything
function initialize() {
console.log('=== INITIALIZING CONNECTOR FILTER ===');
console.log('Document ready state:', document.readyState);
initConfig();
console.log('Current username setting:', getUsername());
console.log('GM_config initialized:', configInitialized);
createButtons();
}
// Wait for DOM to be ready, then initialize
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initialize);
} else {
initialize();
}
// Also try after delays to ensure it works
setTimeout(initialize, 1000);
setTimeout(initialize, 3000);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment