feat: 修改兜底模式样式,增加线程间隔设置和相关UI组件
This commit is contained in:
+67
-1
@@ -50,7 +50,7 @@ initializeSessionStorageAccess();
|
||||
// 状态管理(chrome.storage.session + chrome.storage.local)
|
||||
// ============================================================
|
||||
|
||||
const PERSISTED_SETTING_DEFAULTS = {
|
||||
const LEGACY_PERSISTED_SETTING_DEFAULTS = {
|
||||
panelMode: 'cpa', // Step 1 / Step 9 的来源模式:cpa | sub2api。
|
||||
vpsUrl: '', // VPS 面板地址,可手动填写。
|
||||
vpsPassword: '', // VPS 面板登录密码,可手动填写。
|
||||
@@ -61,6 +61,18 @@ const PERSISTED_SETTING_DEFAULTS = {
|
||||
sub2apiGroupName: DEFAULT_SUB2API_GROUP_NAME, // SUB2API 创建账号时绑定的分组名。
|
||||
customPassword: '', // 自定义账号密码;留空时由程序自动生成随机密码。
|
||||
autoRunSkipFailures: false, // 自动运行遇到失败步骤后,是否继续执行后续流程。
|
||||
autoRunFallbackThreadIntervalMinutes: 0, // 兜底模式下,两轮线程之间的等待分钟数。
|
||||
autoRunDelayEnabled: false, // 自动运行是否启用启动前倒计时。
|
||||
autoRunDelayMinutes: 30, // 自动运行倒计时分钟数。
|
||||
autoStepDelaySeconds: null, // 自动运行每一步执行前的额外等待秒数;0 或空表示不延迟。
|
||||
mailProvider: '163', // 验证码邮箱来源(163 / 163-vip / qq / inbucket)。
|
||||
autoRunSkipFailures: false, // 自动运行遇到失败步骤后,是否继续执行后续流程。
|
||||
autoRunDelayEnabled: false, // 自动运行是否启用启动前倒计时。
|
||||
autoRunDelayMinutes: 30, // 自动运行倒计时分钟数。
|
||||
autoStepDelaySeconds: null, // 自动运行每一步执行前的额外等待秒数;0 或空表示不延迟。
|
||||
mailProvider: '163', // 验证码邮箱来源(163 / 163-vip / qq / inbucket)。
|
||||
autoRunSkipFailures: false, // 自动运行遇到失败步骤后,是否继续执行后续流程。
|
||||
autoRunFallbackThreadIntervalMinutes: 0, // 兜底模式下,两轮线程之间的等待分钟数。
|
||||
autoRunDelayEnabled: false, // 自动运行是否启用启动前倒计时。
|
||||
autoRunDelayMinutes: 30, // 自动运行倒计时分钟数。
|
||||
autoStepDelaySeconds: null, // 自动运行每一步执行前的额外等待秒数;0 或空表示不延迟。
|
||||
@@ -73,6 +85,30 @@ const PERSISTED_SETTING_DEFAULTS = {
|
||||
hotmailAccounts: [],
|
||||
};
|
||||
|
||||
const PERSISTED_SETTING_DEFAULTS = {
|
||||
panelMode: 'cpa',
|
||||
vpsUrl: '',
|
||||
vpsPassword: '',
|
||||
localCpaStep9Mode: DEFAULT_LOCAL_CPA_STEP9_MODE,
|
||||
sub2apiUrl: DEFAULT_SUB2API_URL,
|
||||
sub2apiEmail: '',
|
||||
sub2apiPassword: '',
|
||||
sub2apiGroupName: DEFAULT_SUB2API_GROUP_NAME,
|
||||
customPassword: '',
|
||||
autoRunSkipFailures: false,
|
||||
autoRunFallbackThreadIntervalMinutes: 0,
|
||||
autoRunDelayEnabled: false,
|
||||
autoRunDelayMinutes: 30,
|
||||
autoStepDelaySeconds: null,
|
||||
mailProvider: '163',
|
||||
emailGenerator: 'duck',
|
||||
inbucketHost: '',
|
||||
inbucketMailbox: '',
|
||||
cloudflareDomain: '',
|
||||
cloudflareDomains: [],
|
||||
hotmailAccounts: [],
|
||||
};
|
||||
|
||||
const PERSISTED_SETTING_KEYS = Object.keys(PERSISTED_SETTING_DEFAULTS);
|
||||
const SETTINGS_EXPORT_SCHEMA_VERSION = 1;
|
||||
const SETTINGS_EXPORT_FILENAME_PREFIX = 'multipage-settings';
|
||||
@@ -123,6 +159,23 @@ function normalizeAutoRunDelayMinutes(value) {
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeAutoRunFallbackThreadIntervalMinutes(value) {
|
||||
const rawValue = String(value ?? '').trim();
|
||||
if (!rawValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const numeric = Number(rawValue);
|
||||
if (!Number.isFinite(numeric)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Math.min(
|
||||
AUTO_RUN_DELAY_MAX_MINUTES,
|
||||
Math.max(0, Math.floor(numeric))
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeAutoStepDelaySeconds(value, fallback = null) {
|
||||
const rawValue = String(value ?? '').trim();
|
||||
if (!rawValue) {
|
||||
@@ -256,6 +309,8 @@ function normalizePersistentSettingValue(key, value) {
|
||||
case 'autoRunSkipFailures':
|
||||
case 'autoRunDelayEnabled':
|
||||
return Boolean(value);
|
||||
case 'autoRunFallbackThreadIntervalMinutes':
|
||||
return normalizeAutoRunFallbackThreadIntervalMinutes(value);
|
||||
case 'autoRunDelayMinutes':
|
||||
return normalizeAutoRunDelayMinutes(value);
|
||||
case 'autoStepDelaySeconds':
|
||||
@@ -3435,6 +3490,7 @@ async function autoRunLoop(totalRuns, options = {}) {
|
||||
vpsPassword: prevState.vpsPassword,
|
||||
customPassword: prevState.customPassword,
|
||||
autoRunSkipFailures: prevState.autoRunSkipFailures,
|
||||
autoRunFallbackThreadIntervalMinutes: prevState.autoRunFallbackThreadIntervalMinutes,
|
||||
autoRunDelayEnabled: prevState.autoRunDelayEnabled,
|
||||
autoRunDelayMinutes: prevState.autoRunDelayMinutes,
|
||||
autoStepDelaySeconds: prevState.autoStepDelaySeconds,
|
||||
@@ -3481,6 +3537,16 @@ async function autoRunLoop(totalRuns, options = {}) {
|
||||
successfulRuns += 1;
|
||||
autoRunCurrentRun = successfulRuns;
|
||||
await addLog(`=== 目标 ${successfulRuns}/${totalRuns} 轮已完成(第 ${attemptRuns} 次尝试成功)===`, 'ok');
|
||||
const fallbackThreadIntervalMinutes = normalizeAutoRunFallbackThreadIntervalMinutes(
|
||||
(await getState()).autoRunFallbackThreadIntervalMinutes
|
||||
);
|
||||
if (autoRunSkipFailures && totalRuns > 1 && successfulRuns < totalRuns && fallbackThreadIntervalMinutes > 0) {
|
||||
await addLog(
|
||||
`兜底模式:第 ${successfulRuns}/${totalRuns} 轮已完成,等待 ${fallbackThreadIntervalMinutes} 分钟后再启动下一轮新线程。`,
|
||||
'info'
|
||||
);
|
||||
await sleepWithStop(fallbackThreadIntervalMinutes * 60 * 1000);
|
||||
}
|
||||
continue;
|
||||
} catch (err) {
|
||||
if (isStopError(err)) {
|
||||
|
||||
@@ -721,6 +721,72 @@ header {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.fallback-inline {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.fallback-thread-interval {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.toggle-switch {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
flex: 0 0 auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.toggle-switch > span:not(.toggle-switch-track) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toggle-switch input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.toggle-switch-track {
|
||||
width: 38px;
|
||||
height: 22px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--border);
|
||||
background: var(--bg-elevated);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 2px;
|
||||
transition: background var(--transition), border-color var(--transition), box-shadow var(--transition);
|
||||
}
|
||||
|
||||
.toggle-switch-thumb {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
background: var(--bg-base);
|
||||
box-shadow: var(--shadow-sm);
|
||||
transition: transform var(--transition), background var(--transition);
|
||||
}
|
||||
|
||||
.toggle-switch input:checked + .toggle-switch-track {
|
||||
background: var(--blue-soft);
|
||||
border-color: var(--blue);
|
||||
}
|
||||
|
||||
.toggle-switch input:checked + .toggle-switch-track .toggle-switch-thumb {
|
||||
transform: translateX(16px);
|
||||
background: var(--blue);
|
||||
}
|
||||
|
||||
.toggle-switch input:disabled + .toggle-switch-track {
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
.auto-delay-inline {
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
@@ -1196,6 +1262,24 @@ header {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.modal-option-row {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.modal-option-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.modal-option-label input[type="checkbox"] {
|
||||
accent-color: var(--blue);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.modal-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
@@ -172,12 +172,24 @@
|
||||
<button id="btn-fetch-email" class="btn btn-outline btn-sm data-inline-btn" type="button">获取</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-row data-check-row">
|
||||
<div class="data-row">
|
||||
<span class="data-label">兜底</span>
|
||||
<label class="data-check" for="input-auto-skip-failures">
|
||||
<input type="checkbox" id="input-auto-skip-failures" />
|
||||
<span>出现错误无法继续时,直接丢弃当前线程并新开一轮,直到补足目标运行次数</span>
|
||||
</label>
|
||||
<div class="data-inline fallback-inline">
|
||||
<label class="toggle-switch" for="input-auto-skip-failures">
|
||||
<input type="checkbox" id="input-auto-skip-failures" />
|
||||
<span class="toggle-switch-track" aria-hidden="true">
|
||||
<span class="toggle-switch-thumb"></span>
|
||||
</span>
|
||||
</label>
|
||||
<div class="fallback-thread-interval">
|
||||
<span class="auto-delay-caption">线程间隔</span>
|
||||
<div class="auto-delay-controls">
|
||||
<input type="number" id="input-auto-skip-failures-thread-interval-minutes" class="data-input auto-delay-input" value="0"
|
||||
min="0" max="1440" step="1" title="兜底模式下,两轮线程之间的等待分钟数" />
|
||||
<span class="data-unit">分钟</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
<span class="data-label">延迟</span>
|
||||
@@ -202,8 +214,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-row">
|
||||
<div class="data-row">
|
||||
<span class="data-label">OAuth</span>
|
||||
<span id="display-oauth-url" class="data-value mono truncate">等待中...</span>
|
||||
</div>
|
||||
@@ -359,6 +370,12 @@
|
||||
<button id="btn-auto-start-close" class="modal-close" type="button" aria-label="关闭">×</button>
|
||||
</div>
|
||||
<p id="auto-start-message" class="modal-message">检测到已有流程进度,选择继续当前还是重新开始。</p>
|
||||
<div id="modal-option-row" class="modal-option-row" hidden>
|
||||
<label class="modal-option-label" for="modal-option-input">
|
||||
<input type="checkbox" id="modal-option-input" />
|
||||
<span id="modal-option-text">不再提示</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="modal-actions">
|
||||
<button id="btn-auto-start-cancel" class="btn btn-ghost btn-sm" type="button">取消</button>
|
||||
<button id="btn-auto-start-restart" class="btn btn-outline btn-sm" type="button">重新开始</button>
|
||||
@@ -373,4 +390,4 @@
|
||||
<script src="sidepanel.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+160
-3
@@ -83,12 +83,16 @@ const inputCfDomain = document.getElementById('input-cf-domain');
|
||||
const btnCfDomainMode = document.getElementById('btn-cf-domain-mode');
|
||||
const inputRunCount = document.getElementById('input-run-count');
|
||||
const inputAutoSkipFailures = document.getElementById('input-auto-skip-failures');
|
||||
const inputAutoSkipFailuresThreadIntervalMinutes = document.getElementById('input-auto-skip-failures-thread-interval-minutes');
|
||||
const inputAutoDelayEnabled = document.getElementById('input-auto-delay-enabled');
|
||||
const inputAutoDelayMinutes = document.getElementById('input-auto-delay-minutes');
|
||||
const inputAutoStepDelaySeconds = document.getElementById('input-auto-step-delay-seconds');
|
||||
const autoStartModal = document.getElementById('auto-start-modal');
|
||||
const autoStartTitle = autoStartModal?.querySelector('.modal-title');
|
||||
const autoStartMessage = document.getElementById('auto-start-message');
|
||||
const modalOptionRow = document.getElementById('modal-option-row');
|
||||
const modalOptionInput = document.getElementById('modal-option-input');
|
||||
const modalOptionText = document.getElementById('modal-option-text');
|
||||
const btnAutoStartClose = document.getElementById('btn-auto-start-close');
|
||||
const btnAutoStartCancel = document.getElementById('btn-auto-start-cancel');
|
||||
const btnAutoStartRestart = document.getElementById('btn-auto-start-restart');
|
||||
@@ -109,9 +113,13 @@ const SKIPPABLE_STEPS = new Set([1, 2, 3, 4, 5, 6, 7, 8, 9]);
|
||||
const AUTO_DELAY_MIN_MINUTES = 1;
|
||||
const AUTO_DELAY_MAX_MINUTES = 1440;
|
||||
const AUTO_DELAY_DEFAULT_MINUTES = 30;
|
||||
const AUTO_FALLBACK_THREAD_INTERVAL_MIN_MINUTES = 0;
|
||||
const AUTO_FALLBACK_THREAD_INTERVAL_MAX_MINUTES = 1440;
|
||||
const AUTO_FALLBACK_THREAD_INTERVAL_DEFAULT_MINUTES = 0;
|
||||
const AUTO_STEP_DELAY_MIN_SECONDS = 0;
|
||||
const AUTO_STEP_DELAY_MAX_SECONDS = 600;
|
||||
const DEFAULT_LOCAL_CPA_STEP9_MODE = 'submit';
|
||||
const AUTO_SKIP_FAILURES_PROMPT_DISMISSED_STORAGE_KEY = 'multipage-auto-skip-failures-prompt-dismissed';
|
||||
|
||||
let latestState = null;
|
||||
let currentAutoRun = {
|
||||
@@ -128,6 +136,7 @@ let settingsAutoSaveTimer = null;
|
||||
let cloudflareDomainEditMode = false;
|
||||
let modalChoiceResolver = null;
|
||||
let currentModalActions = [];
|
||||
let modalResultBuilder = null;
|
||||
let scheduledCountdownTimer = null;
|
||||
let hotmailActionInFlight = false;
|
||||
let hotmailListExpanded = false;
|
||||
@@ -198,6 +207,17 @@ function dismissToast(toast) {
|
||||
toast.addEventListener('animationend', () => toast.remove());
|
||||
}
|
||||
|
||||
function resetActionModalOption() {
|
||||
if (!modalOptionRow || !modalOptionInput || !modalOptionText) {
|
||||
return;
|
||||
}
|
||||
|
||||
modalOptionRow.hidden = true;
|
||||
modalOptionInput.checked = false;
|
||||
modalOptionInput.disabled = false;
|
||||
modalOptionText.textContent = '不再提示';
|
||||
}
|
||||
|
||||
function resetActionModalButtons() {
|
||||
const buttons = [btnAutoStartCancel, btnAutoStartRestart, btnAutoStartContinue];
|
||||
buttons.forEach((button) => {
|
||||
@@ -224,18 +244,40 @@ function configureActionModalButton(button, action) {
|
||||
button.onclick = () => resolveModalChoice(action.id);
|
||||
}
|
||||
|
||||
function configureActionModalOption(option) {
|
||||
if (!modalOptionRow || !modalOptionInput || !modalOptionText) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!option) {
|
||||
resetActionModalOption();
|
||||
return;
|
||||
}
|
||||
|
||||
modalOptionRow.hidden = false;
|
||||
modalOptionInput.checked = Boolean(option.checked);
|
||||
modalOptionInput.disabled = Boolean(option.disabled);
|
||||
modalOptionText.textContent = option.label || '不再提示';
|
||||
}
|
||||
|
||||
function resolveModalChoice(choice) {
|
||||
const optionChecked = Boolean(modalOptionInput?.checked);
|
||||
const result = typeof modalResultBuilder === 'function'
|
||||
? modalResultBuilder(choice, { optionChecked })
|
||||
: choice;
|
||||
if (modalChoiceResolver) {
|
||||
modalChoiceResolver(choice);
|
||||
modalChoiceResolver(result);
|
||||
modalChoiceResolver = null;
|
||||
}
|
||||
modalResultBuilder = null;
|
||||
resetActionModalButtons();
|
||||
resetActionModalOption();
|
||||
if (autoStartModal) {
|
||||
autoStartModal.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
function openActionModal({ title, message, actions }) {
|
||||
function openActionModal({ title, message, actions, option, buildResult }) {
|
||||
if (!autoStartModal) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
@@ -244,12 +286,15 @@ function openActionModal({ title, message, actions }) {
|
||||
resolveModalChoice(null);
|
||||
}
|
||||
|
||||
resetActionModalButtons();
|
||||
autoStartTitle.textContent = title;
|
||||
autoStartMessage.textContent = message;
|
||||
currentModalActions = actions || [];
|
||||
modalResultBuilder = typeof buildResult === 'function' ? buildResult : null;
|
||||
configureActionModalButton(btnAutoStartCancel, currentModalActions[0]);
|
||||
configureActionModalButton(btnAutoStartRestart, currentModalActions[1]);
|
||||
configureActionModalButton(btnAutoStartContinue, currentModalActions[2]);
|
||||
configureActionModalOption(option);
|
||||
autoStartModal.hidden = false;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
@@ -285,6 +330,42 @@ async function openConfirmModal({ title, message, confirmLabel = '确认', confi
|
||||
return choice === 'confirm';
|
||||
}
|
||||
|
||||
function isAutoSkipFailuresPromptDismissed() {
|
||||
return localStorage.getItem(AUTO_SKIP_FAILURES_PROMPT_DISMISSED_STORAGE_KEY) === '1';
|
||||
}
|
||||
|
||||
function setAutoSkipFailuresPromptDismissed(dismissed) {
|
||||
if (dismissed) {
|
||||
localStorage.setItem(AUTO_SKIP_FAILURES_PROMPT_DISMISSED_STORAGE_KEY, '1');
|
||||
} else {
|
||||
localStorage.removeItem(AUTO_SKIP_FAILURES_PROMPT_DISMISSED_STORAGE_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
async function openAutoSkipFailuresConfirmModal() {
|
||||
const result = await openActionModal({
|
||||
title: '兜底说明',
|
||||
message: '开启后,当某一轮失败且无法继续时,会直接放弃当前线程,重新开新一轮,直到补足目标运行次数。线程间隔只在开启兜底且运行次数大于 1 时生效。',
|
||||
actions: [
|
||||
{ id: null, label: '取消', variant: 'btn-ghost' },
|
||||
{ id: 'confirm', label: '确认开启', variant: 'btn-primary' },
|
||||
],
|
||||
option: {
|
||||
label: '不再提示',
|
||||
checked: false,
|
||||
},
|
||||
buildResult: (choice, meta) => ({
|
||||
choice,
|
||||
optionChecked: Boolean(meta?.optionChecked),
|
||||
}),
|
||||
});
|
||||
|
||||
return {
|
||||
confirmed: result?.choice === 'confirm',
|
||||
dismissPrompt: Boolean(result?.optionChecked),
|
||||
};
|
||||
}
|
||||
|
||||
function updateConfigMenuControls() {
|
||||
const disabled = configActionInFlight || settingsSaveInFlight;
|
||||
const importLocked = disabled
|
||||
@@ -450,6 +531,23 @@ function normalizeAutoDelayMinutes(value) {
|
||||
return Math.min(AUTO_DELAY_MAX_MINUTES, Math.max(AUTO_DELAY_MIN_MINUTES, Math.floor(numeric)));
|
||||
}
|
||||
|
||||
function normalizeAutoRunThreadIntervalMinutes(value) {
|
||||
const rawValue = String(value ?? '').trim();
|
||||
if (!rawValue) {
|
||||
return AUTO_FALLBACK_THREAD_INTERVAL_DEFAULT_MINUTES;
|
||||
}
|
||||
|
||||
const numeric = Number(rawValue);
|
||||
if (!Number.isFinite(numeric)) {
|
||||
return AUTO_FALLBACK_THREAD_INTERVAL_DEFAULT_MINUTES;
|
||||
}
|
||||
|
||||
return Math.min(
|
||||
AUTO_FALLBACK_THREAD_INTERVAL_MAX_MINUTES,
|
||||
Math.max(AUTO_FALLBACK_THREAD_INTERVAL_MIN_MINUTES, Math.floor(numeric))
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeAutoStepDelaySeconds(value) {
|
||||
const rawValue = String(value ?? '').trim();
|
||||
if (!rawValue) {
|
||||
@@ -469,6 +567,19 @@ function formatAutoStepDelayInputValue(value) {
|
||||
return normalized === null ? '' : String(normalized);
|
||||
}
|
||||
|
||||
function getRunCountValue() {
|
||||
return Math.min(50, Math.max(1, parseInt(inputRunCount.value, 10) || 1));
|
||||
}
|
||||
|
||||
function updateFallbackThreadIntervalInputState() {
|
||||
if (!inputAutoSkipFailuresThreadIntervalMinutes) {
|
||||
return;
|
||||
}
|
||||
|
||||
const enabled = inputAutoSkipFailures.checked && getRunCountValue() > 1;
|
||||
inputAutoSkipFailuresThreadIntervalMinutes.disabled = !enabled;
|
||||
}
|
||||
|
||||
function updateAutoDelayInputState() {
|
||||
const scheduled = isAutoRunScheduledPhase();
|
||||
inputAutoDelayEnabled.disabled = scheduled;
|
||||
@@ -637,6 +748,7 @@ function collectSettingsPayload() {
|
||||
cloudflareDomain: selectedCloudflareDomain,
|
||||
cloudflareDomains: domains,
|
||||
autoRunSkipFailures: inputAutoSkipFailures.checked,
|
||||
autoRunFallbackThreadIntervalMinutes: normalizeAutoRunThreadIntervalMinutes(inputAutoSkipFailuresThreadIntervalMinutes.value),
|
||||
autoRunDelayEnabled: inputAutoDelayEnabled.checked,
|
||||
autoRunDelayMinutes: normalizeAutoDelayMinutes(inputAutoDelayMinutes.value),
|
||||
autoStepDelaySeconds: normalizeAutoStepDelaySeconds(inputAutoStepDelaySeconds.value),
|
||||
@@ -818,6 +930,7 @@ function applyAutoRunStatus(payload = currentAutoRun) {
|
||||
}
|
||||
|
||||
updateAutoDelayInputState();
|
||||
updateFallbackThreadIntervalInputState();
|
||||
syncScheduledCountdownTicker();
|
||||
updateStopButtonState(scheduled || paused || locked || Object.values(getStepStatuses()).some(status => status === 'running'));
|
||||
updateConfigMenuControls();
|
||||
@@ -879,6 +992,7 @@ function applySettingsState(state) {
|
||||
renderCloudflareDomainOptions(state?.cloudflareDomain || '');
|
||||
setCloudflareDomainEditMode(false, { clearInput: true });
|
||||
inputAutoSkipFailures.checked = Boolean(state?.autoRunSkipFailures);
|
||||
inputAutoSkipFailuresThreadIntervalMinutes.value = String(normalizeAutoRunThreadIntervalMinutes(state?.autoRunFallbackThreadIntervalMinutes));
|
||||
inputAutoDelayEnabled.checked = Boolean(state?.autoRunDelayEnabled);
|
||||
inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(state?.autoRunDelayMinutes));
|
||||
inputAutoStepDelaySeconds.value = formatAutoStepDelayInputValue(state?.autoStepDelaySeconds);
|
||||
@@ -889,6 +1003,7 @@ function applySettingsState(state) {
|
||||
applyAutoRunStatus(state);
|
||||
markSettingsDirty(false);
|
||||
updateAutoDelayInputState();
|
||||
updateFallbackThreadIntervalInputState();
|
||||
updatePanelModeUI();
|
||||
updateMailProviderUI();
|
||||
updateButtonStates();
|
||||
@@ -2384,11 +2499,43 @@ inputInbucketHost.addEventListener('blur', () => {
|
||||
saveSettings({ silent: true }).catch(() => { });
|
||||
});
|
||||
|
||||
inputAutoSkipFailures.addEventListener('change', () => {
|
||||
inputRunCount.addEventListener('input', () => {
|
||||
updateFallbackThreadIntervalInputState();
|
||||
});
|
||||
inputRunCount.addEventListener('blur', () => {
|
||||
inputRunCount.value = String(getRunCountValue());
|
||||
updateFallbackThreadIntervalInputState();
|
||||
});
|
||||
|
||||
inputAutoSkipFailures.addEventListener('change', async () => {
|
||||
if (inputAutoSkipFailures.checked && !isAutoSkipFailuresPromptDismissed()) {
|
||||
const result = await openAutoSkipFailuresConfirmModal();
|
||||
if (!result.confirmed) {
|
||||
inputAutoSkipFailures.checked = false;
|
||||
updateFallbackThreadIntervalInputState();
|
||||
return;
|
||||
}
|
||||
if (result.dismissPrompt) {
|
||||
setAutoSkipFailuresPromptDismissed(true);
|
||||
}
|
||||
}
|
||||
|
||||
updateFallbackThreadIntervalInputState();
|
||||
markSettingsDirty(true);
|
||||
saveSettings({ silent: true }).catch(() => { });
|
||||
});
|
||||
|
||||
inputAutoSkipFailuresThreadIntervalMinutes.addEventListener('input', () => {
|
||||
markSettingsDirty(true);
|
||||
scheduleSettingsAutoSave();
|
||||
});
|
||||
inputAutoSkipFailuresThreadIntervalMinutes.addEventListener('blur', () => {
|
||||
inputAutoSkipFailuresThreadIntervalMinutes.value = String(
|
||||
normalizeAutoRunThreadIntervalMinutes(inputAutoSkipFailuresThreadIntervalMinutes.value)
|
||||
);
|
||||
saveSettings({ silent: true }).catch(() => { });
|
||||
});
|
||||
|
||||
inputAutoDelayEnabled.addEventListener('change', () => {
|
||||
updateAutoDelayInputState();
|
||||
markSettingsDirty(true);
|
||||
@@ -2507,6 +2654,10 @@ chrome.runtime.onMessage.addListener((message) => {
|
||||
inputEmail.value = getCurrentHotmailEmail();
|
||||
}
|
||||
}
|
||||
if (message.payload.autoRunSkipFailures !== undefined) {
|
||||
inputAutoSkipFailures.checked = Boolean(message.payload.autoRunSkipFailures);
|
||||
updateFallbackThreadIntervalInputState();
|
||||
}
|
||||
if (message.payload.autoRunDelayEnabled !== undefined) {
|
||||
inputAutoDelayEnabled.checked = Boolean(message.payload.autoRunDelayEnabled);
|
||||
updateAutoDelayInputState();
|
||||
@@ -2514,6 +2665,12 @@ chrome.runtime.onMessage.addListener((message) => {
|
||||
if (message.payload.autoRunDelayMinutes !== undefined) {
|
||||
inputAutoDelayMinutes.value = String(normalizeAutoDelayMinutes(message.payload.autoRunDelayMinutes));
|
||||
}
|
||||
if (message.payload.autoRunFallbackThreadIntervalMinutes !== undefined) {
|
||||
inputAutoSkipFailuresThreadIntervalMinutes.value = String(
|
||||
normalizeAutoRunThreadIntervalMinutes(message.payload.autoRunFallbackThreadIntervalMinutes)
|
||||
);
|
||||
updateFallbackThreadIntervalInputState();
|
||||
}
|
||||
if (message.payload.autoStepDelaySeconds !== undefined) {
|
||||
inputAutoStepDelaySeconds.value = formatAutoStepDelayInputValue(message.payload.autoStepDelaySeconds);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user