feat: upgrade custom email pool with manager UI and entry states

(cherry picked from commit 3cf5f22d40a4ef563a3d06751bbb25b003d4ef1e)
This commit is contained in:
朴圣佑
2026-04-24 13:33:59 +08:00
committed by QLHazyCoder
parent 20c634646e
commit f480af0375
7 changed files with 975 additions and 74 deletions
+195 -67
View File
@@ -177,6 +177,22 @@ const rowEmailGenerator = document.getElementById('row-email-generator');
const selectEmailGenerator = document.getElementById('select-email-generator');
const rowCustomEmailPool = document.getElementById('row-custom-email-pool');
const inputCustomEmailPool = document.getElementById('input-custom-email-pool');
const btnCustomEmailPoolRefresh = document.getElementById('btn-custom-email-pool-refresh');
const btnCustomEmailPoolClearUsed = document.getElementById('btn-custom-email-pool-clear-used');
const btnCustomEmailPoolDeleteAll = document.getElementById('btn-custom-email-pool-delete-all');
const inputCustomEmailPoolImport = document.getElementById('input-custom-email-pool-import');
const btnCustomEmailPoolImport = document.getElementById('btn-custom-email-pool-import');
const customEmailPoolSummary = document.getElementById('custom-email-pool-summary');
const inputCustomEmailPoolSearch = document.getElementById('input-custom-email-pool-search');
const selectCustomEmailPoolFilter = document.getElementById('select-custom-email-pool-filter');
const checkboxCustomEmailPoolSelectAll = document.getElementById('checkbox-custom-email-pool-select-all');
const customEmailPoolSelectionSummary = document.getElementById('custom-email-pool-selection-summary');
const btnCustomEmailPoolBulkUsed = document.getElementById('btn-custom-email-pool-bulk-used');
const btnCustomEmailPoolBulkUnused = document.getElementById('btn-custom-email-pool-bulk-unused');
const btnCustomEmailPoolBulkEnable = document.getElementById('btn-custom-email-pool-bulk-enable');
const btnCustomEmailPoolBulkDisable = document.getElementById('btn-custom-email-pool-bulk-disable');
const btnCustomEmailPoolBulkDelete = document.getElementById('btn-custom-email-pool-bulk-delete');
const customEmailPoolList = document.getElementById('custom-email-pool-list');
const rowTempEmailBaseUrl = document.getElementById('row-temp-email-base-url');
const inputTempEmailBaseUrl = document.getElementById('input-temp-email-base-url');
const rowTempEmailAdminAuth = document.getElementById('row-temp-email-admin-auth');
@@ -869,44 +885,7 @@ let configActionInFlight = false;
let currentReleaseSnapshot = null;
let currentContributionContentSnapshot = null;
let contributionContentSnapshotRequestInFlight = null;
let phoneVerificationSectionExpanded = true;
function readPhoneVerificationSectionExpanded() {
try {
return globalThis.localStorage?.getItem(PHONE_VERIFICATION_SECTION_EXPANDED_STORAGE_KEY) !== '0';
} catch (err) {
return true;
}
}
function persistPhoneVerificationSectionExpanded(expanded) {
try {
globalThis.localStorage?.setItem(
PHONE_VERIFICATION_SECTION_EXPANDED_STORAGE_KEY,
expanded ? '1' : '0'
);
} catch (err) {
// Ignore storage errors; in-memory state is sufficient for current session.
}
}
function setPhoneVerificationSectionExpanded(expanded) {
phoneVerificationSectionExpanded = Boolean(expanded);
persistPhoneVerificationSectionExpanded(phoneVerificationSectionExpanded);
updatePhoneVerificationSettingsUI();
}
function togglePhoneVerificationSectionExpanded() {
if (!inputPhoneVerificationEnabled?.checked) {
return;
}
setPhoneVerificationSectionExpanded(!phoneVerificationSectionExpanded);
}
function initPhoneVerificationSectionExpandedState() {
phoneVerificationSectionExpanded = readPhoneVerificationSectionExpanded();
updatePhoneVerificationSettingsUI();
}
let customEmailPoolEntriesState = [];
const EYE_OPEN_ICON = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/><circle cx="12" cy="12" r="3"/></svg>';
const EYE_CLOSED_ICON = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17.94 17.94A10.94 10.94 0 0 1 12 19C5 19 1 12 1 12a21.77 21.77 0 0 1 5.06-6.94"/><path d="M9.9 4.24A10.94 10.94 0 0 1 12 5c7 0 11 7 11 7a21.86 21.86 0 0 1-2.16 3.19"/><path d="M1 1l22 22"/><path d="M14.12 14.12a3 3 0 1 1-4.24-4.24"/></svg>';
@@ -1982,6 +1961,85 @@ function normalizeCustomEmailPoolEntries(value = '') {
.filter((item) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(item));
}
function normalizeCustomEmailPoolEntryEmail(value = '') {
return String(value || '').trim().toLowerCase();
}
function createCustomEmailPoolEntryId() {
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
return crypto.randomUUID();
}
return `custom-pool-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
}
function normalizeCustomEmailPoolEntryObjects(value = []) {
const source = Array.isArray(value) ? value : [];
const seenEmails = new Set();
const entries = [];
for (const rawEntry of source) {
const asObject = rawEntry && typeof rawEntry === 'object'
? rawEntry
: { email: rawEntry };
const email = normalizeCustomEmailPoolEntryEmail(asObject.email || '');
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
continue;
}
if (seenEmails.has(email)) {
continue;
}
seenEmails.add(email);
entries.push({
id: String(asObject.id || createCustomEmailPoolEntryId()),
email,
enabled: asObject.enabled !== undefined ? Boolean(asObject.enabled) : true,
used: Boolean(asObject.used),
note: String(asObject.note || '').trim(),
lastUsedAt: Number.isFinite(Number(asObject.lastUsedAt)) ? Number(asObject.lastUsedAt) : 0,
});
}
return entries;
}
function getNormalizedCustomEmailPoolEntriesState() {
const entries = (typeof customEmailPoolEntriesState !== 'undefined' && Array.isArray(customEmailPoolEntriesState))
? customEmailPoolEntriesState
: [];
return normalizeCustomEmailPoolEntryObjects(entries);
}
function getActiveCustomEmailPoolEmails(entries = getNormalizedCustomEmailPoolEntriesState()) {
return normalizeCustomEmailPoolEntryObjects(entries)
.filter((entry) => entry.enabled && !entry.used)
.map((entry) => entry.email);
}
function setCustomEmailPoolEntriesState(entries = [], options = {}) {
const { syncInput = true } = options;
customEmailPoolEntriesState = normalizeCustomEmailPoolEntryObjects(entries);
if (syncInput && inputCustomEmailPool) {
inputCustomEmailPool.value = getActiveCustomEmailPoolEmails(customEmailPoolEntriesState).join('\n');
}
}
function restoreCustomEmailPoolEntriesFromState(state = {}) {
const rawEntries = Array.isArray(state?.customEmailPoolEntries)
? state.customEmailPoolEntries
: [];
if (rawEntries.length > 0) {
return normalizeCustomEmailPoolEntryObjects(rawEntries);
}
return normalizeCustomEmailPoolEntries(state?.customEmailPool).map((email) => ({
id: createCustomEmailPoolEntryId(),
email,
enabled: true,
used: false,
note: '',
lastUsedAt: 0,
}));
}
function usesCustomEmailPoolGenerator(provider = selectMailProvider.value) {
return !isCustomMailProvider(provider)
&& !isLuckmailProvider(provider)
@@ -1997,6 +2055,12 @@ function usesCustomMailProviderPool(provider = selectMailProvider.value) {
}
function getCustomEmailPoolSize() {
if (typeof customEmailPoolEntriesState !== 'undefined' && Array.isArray(customEmailPoolEntriesState)) {
const activeEntries = getActiveCustomEmailPoolEmails(customEmailPoolEntriesState);
if (activeEntries.length > 0 || customEmailPoolEntriesState.length > 0) {
return activeEntries.length;
}
}
return normalizeCustomEmailPoolEntries(inputCustomEmailPool?.value).length;
}
@@ -2802,27 +2866,14 @@ function collectSettingsPayload() {
id: normalizeHeroSmsCountryId(latestState?.heroSmsCountryId, 0),
label: normalizeHeroSmsCountryLabel(latestState?.heroSmsCountryLabel),
};
const heroSmsCountryFallback = phoneSmsProviderValue === heroProviderValue
? (typeof syncHeroSmsFallbackSelectionOrderFromSelect === 'function'
? syncHeroSmsFallbackSelectionOrderFromSelect()
.filter((country) => Number(country.id) !== Number(heroSmsCountry.id))
: [])
: normalizeHeroSmsCountryFallbackList(
Array.isArray(latestState?.heroSmsCountryFallback) ? latestState.heroSmsCountryFallback : []
);
const payPalAccounts = typeof getPayPalAccounts === 'function'
? getPayPalAccounts(latestState)
: (Array.isArray(latestState?.paypalAccounts) ? latestState.paypalAccounts : []);
const currentPayPalAccount = typeof getCurrentPayPalAccount === 'function'
? getCurrentPayPalAccount(latestState)
: payPalAccounts.find((account) => account?.id === String(latestState?.currentPayPalAccountId || '').trim()) || null;
const plusPaymentMethod = typeof getSelectedPlusPaymentMethod === 'function'
? getSelectedPlusPaymentMethod()
: (String(
(typeof selectPlusPaymentMethod !== 'undefined' && selectPlusPaymentMethod
? selectPlusPaymentMethod.value
: latestState?.plusPaymentMethod) || ''
).trim().toLowerCase() === 'gopay' ? 'gopay' : 'paypal');
const normalizedCustomEmailPool = typeof getActiveCustomEmailPoolEmails === 'function'
? getActiveCustomEmailPoolEmails()
: (typeof normalizeCustomEmailPoolEntries === 'function'
? normalizeCustomEmailPoolEntries(inputCustomEmailPool?.value)
: []);
const normalizedCustomEmailPoolEntries = typeof getNormalizedCustomEmailPoolEntriesState === 'function'
? getNormalizedCustomEmailPoolEntriesState()
: [];
return {
...(contributionModeEnabled ? {} : {
panelMode: selectPanelMode.value,
@@ -2876,9 +2927,8 @@ function collectSettingsPayload() {
customMailProviderPool: typeof normalizeCustomEmailPoolEntries === 'function'
? normalizeCustomEmailPoolEntries(inputCustomMailProviderPool?.value)
: [],
customEmailPool: typeof normalizeCustomEmailPoolEntries === 'function'
? normalizeCustomEmailPoolEntries(inputCustomEmailPool?.value)
: [],
customEmailPool: normalizedCustomEmailPool,
customEmailPoolEntries: normalizedCustomEmailPoolEntries,
autoDeleteUsedIcloudAlias: checkboxAutoDeleteIcloud?.checked,
icloudHostPreference: selectIcloudHostPreference?.value || 'auto',
icloudTargetMailboxType: normalizedIcloudTargetMailboxType,
@@ -6980,9 +7030,7 @@ function applySettingsState(state) {
if (inputCustomMailProviderPool) {
inputCustomMailProviderPool.value = normalizeCustomEmailPoolEntries(state?.customMailProviderPool).join('\n');
}
if (inputCustomEmailPool) {
inputCustomEmailPool.value = normalizeCustomEmailPoolEntries(state?.customEmailPool).join('\n');
}
setCustomEmailPoolEntriesState(restoreCustomEmailPoolEntriesFromState(state));
setHotmailServiceMode(state?.hotmailServiceMode);
inputHotmailRemoteBaseUrl.value = state?.hotmailRemoteBaseUrl || '';
inputHotmailLocalBaseUrl.value = state?.hotmailLocalBaseUrl || '';
@@ -7179,6 +7227,7 @@ function applySettingsState(state) {
}
updatePanelModeUI();
updateMailProviderUI();
queueCustomEmailPoolRefresh();
if (isLuckmailProvider(state?.mailProvider)) {
queueLuckmailPurchaseRefresh();
}
@@ -8130,6 +8179,11 @@ function updateMailProviderUI() {
}
if (typeof rowCustomEmailPool !== 'undefined' && rowCustomEmailPool) {
rowCustomEmailPool.style.display = useCustomEmailPool ? '' : 'none';
if (useCustomEmailPool) {
queueCustomEmailPoolRefresh();
} else {
resetCustomEmailPoolManager();
}
}
if (cloudflareTempEmailSection) {
cloudflareTempEmailSection.style.display = showCloudflareTempEmailSettings ? '' : 'none';
@@ -8642,8 +8696,8 @@ async function fetchGeneratedEmail(options = {}) {
mail2925Mode: getSelectedMail2925Mode(),
...(getSelectedEmailGenerator() === CUSTOM_EMAIL_POOL_GENERATOR
? {
customEmailPool: normalizeCustomEmailPoolEntries(inputCustomEmailPool?.value),
}
customEmailPool: getActiveCustomEmailPoolEmails(),
}
: {}),
...buildManagedAliasBaseEmailPayload(),
},
@@ -8976,6 +9030,70 @@ const bindLuckmailEvents = luckmailManager?.bindLuckmailEvents
|| (() => { });
bindLuckmailEvents();
const customEmailPoolManager = window.SidepanelCustomEmailPoolManager?.createCustomEmailPoolManager({
dom: {
btnCustomEmailPoolRefresh,
btnCustomEmailPoolClearUsed,
btnCustomEmailPoolDeleteAll,
inputCustomEmailPoolImport,
btnCustomEmailPoolImport,
customEmailPoolSummary,
inputCustomEmailPoolSearch,
selectCustomEmailPoolFilter,
checkboxCustomEmailPoolSelectAll,
customEmailPoolSelectionSummary,
btnCustomEmailPoolBulkUsed,
btnCustomEmailPoolBulkUnused,
btnCustomEmailPoolBulkEnable,
btnCustomEmailPoolBulkDisable,
btnCustomEmailPoolBulkDelete,
customEmailPoolList,
},
helpers: {
copyTextToClipboard,
escapeHtml,
openConfirmModal,
showToast,
},
state: {
getEntries: () => getNormalizedCustomEmailPoolEntriesState(),
setEntries: (entries) => {
setCustomEmailPoolEntriesState(entries);
},
getCurrentEmail: () => String(inputEmail?.value || latestState?.email || '').trim().toLowerCase(),
isVisible: () => Boolean(rowCustomEmailPool) && rowCustomEmailPool.style.display !== 'none',
},
actions: {
persistEntries: async () => {
syncRunCountFromConfiguredEmailPool();
updateMailProviderUI();
markSettingsDirty(true);
await saveSettings({ silent: true });
},
setRuntimeEmail: async (email) => {
await setRuntimeEmailState(email);
syncLatestState({ email });
if (inputEmail) {
inputEmail.value = email || '';
}
},
},
constants: {
copyIcon: COPY_ICON,
},
});
const queueCustomEmailPoolRefresh = customEmailPoolManager?.queueCustomEmailPoolRefresh
|| (() => { });
const refreshCustomEmailPoolEntries = customEmailPoolManager?.refreshCustomEmailPoolEntries
|| (async () => { });
const renderCustomEmailPoolEntries = customEmailPoolManager?.renderCustomEmailPoolEntries
|| (() => { });
const resetCustomEmailPoolManager = customEmailPoolManager?.reset
|| (() => { });
const bindCustomEmailPoolEvents = customEmailPoolManager?.bindEvents
|| (() => { });
bindCustomEmailPoolEvents();
const accountRecordsManager = window.SidepanelAccountRecordsManager?.createAccountRecordsManager({
state: {
getLatestState: () => latestState,
@@ -11171,6 +11289,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
logArea.innerHTML = '';
resetIcloudManager();
resetLuckmailManager();
resetCustomEmailPoolManager();
document.querySelectorAll('.step-row').forEach(row => row.className = 'step-row');
document.querySelectorAll('.step-status').forEach(el => el.textContent = '');
syncAutoRunState({
@@ -11200,6 +11319,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
syncLatestState(message.payload);
if (message.payload.email !== undefined) {
inputEmail.value = message.payload.email || '';
queueCustomEmailPoolRefresh();
}
if (
message.payload.password !== undefined
@@ -11424,6 +11544,14 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
setManagedAliasBaseEmailInputForProvider('2925', latestState);
}
}
if (message.payload.customEmailPoolEntries !== undefined || message.payload.customEmailPool !== undefined) {
setCustomEmailPoolEntriesState(restoreCustomEmailPoolEntriesFromState({
...latestState,
...message.payload,
}));
syncRunCountFromConfiguredEmailPool();
queueCustomEmailPoolRefresh();
}
if (message.payload.luckmailApiKey !== undefined) {
inputLuckmailApiKey.value = message.payload.luckmailApiKey || '';
}