feat: add support for running status in account run history and UI
- Enhanced account run history to include 'running' status with appropriate translations and summaries. - Updated logging status to handle new error message format. - Introduced new properties for task progress in create-plus-checkout step. - Modified fill-plus-checkout step to handle additional error details. - Updated account records manager to display running status and summary correctly. - Added CSS styles for running status in account records. - Implemented logic to refresh account run history based on auto-run state changes. - Added tests for running status and idle log restart functionality in auto-run steps. - Improved account records manager tests to validate running state display and failure details.
This commit is contained in:
@@ -21,19 +21,25 @@
|
||||
success: {
|
||||
label: '成',
|
||||
className: 'is-success',
|
||||
matches: (record) => record.finalStatus === 'success',
|
||||
matches: (record) => getRecordDisplayStatus(record) === 'success',
|
||||
metaLabel: '成功',
|
||||
},
|
||||
running: {
|
||||
label: '运行',
|
||||
className: 'is-running',
|
||||
matches: (record) => getRecordDisplayStatus(record) === 'running',
|
||||
metaLabel: '运行中',
|
||||
},
|
||||
failed: {
|
||||
label: '失',
|
||||
className: 'is-failed',
|
||||
matches: (record) => record.finalStatus === 'failed',
|
||||
matches: (record) => getRecordDisplayStatus(record) === 'failed',
|
||||
metaLabel: '失败',
|
||||
},
|
||||
stopped: {
|
||||
label: '停',
|
||||
className: 'is-stopped',
|
||||
matches: (record) => record.finalStatus === 'stopped',
|
||||
matches: (record) => getRecordDisplayStatus(record) === 'stopped',
|
||||
metaLabel: '停止',
|
||||
},
|
||||
retry: {
|
||||
@@ -96,6 +102,58 @@
|
||||
: identifier.toLowerCase();
|
||||
}
|
||||
|
||||
function getRecordDisplayStatus(record = {}) {
|
||||
return String(record.displayStatus || record.finalStatus || '').trim().toLowerCase();
|
||||
}
|
||||
|
||||
function isAutoRunRecordDisplayRunning(currentState = {}) {
|
||||
const phase = String(currentState.autoRunPhase || '').trim().toLowerCase();
|
||||
return Boolean(currentState.autoRunning)
|
||||
&& ['running', 'waiting_step', 'waiting_email', 'retrying'].includes(phase);
|
||||
}
|
||||
|
||||
function buildCurrentAccountRecordId(currentState = {}) {
|
||||
const accountIdentifierType = String(currentState.accountIdentifierType || '').trim().toLowerCase();
|
||||
const email = String(currentState.email || '').trim();
|
||||
const phoneNumber = String(
|
||||
currentState.signupPhoneNumber
|
||||
|| currentState.phoneNumber
|
||||
|| currentState.phone
|
||||
|| ''
|
||||
).trim();
|
||||
const accountIdentifier = String(
|
||||
currentState.accountIdentifier
|
||||
|| (accountIdentifierType === 'phone' ? phoneNumber : email)
|
||||
|| ''
|
||||
).trim();
|
||||
return buildRecordId({
|
||||
accountIdentifierType,
|
||||
accountIdentifier,
|
||||
email,
|
||||
phoneNumber,
|
||||
});
|
||||
}
|
||||
|
||||
function applyRunningDisplayState(record = {}, currentState = {}) {
|
||||
if (!isAutoRunRecordDisplayRunning(currentState)) {
|
||||
return record;
|
||||
}
|
||||
if (getRecordDisplayStatus(record) === 'success') {
|
||||
return record;
|
||||
}
|
||||
|
||||
const currentRecordId = buildCurrentAccountRecordId(currentState);
|
||||
if (!currentRecordId || buildRecordId(record) !== currentRecordId) {
|
||||
return record;
|
||||
}
|
||||
|
||||
return {
|
||||
...record,
|
||||
displayStatus: 'running',
|
||||
displaySummary: '正在运行',
|
||||
};
|
||||
}
|
||||
|
||||
function getRecordIdentifierType(record = {}) {
|
||||
const rawType = String(record.accountIdentifierType || '').trim().toLowerCase();
|
||||
if (rawType === 'phone') {
|
||||
@@ -167,18 +225,22 @@
|
||||
return (Array.isArray(currentState?.accountRunHistory) ? currentState.accountRunHistory : [])
|
||||
.filter((item) => item && typeof item === 'object')
|
||||
.slice()
|
||||
.sort((left, right) => normalizeTimestamp(right.finishedAt) - normalizeTimestamp(left.finishedAt));
|
||||
.sort((left, right) => normalizeTimestamp(right.finishedAt) - normalizeTimestamp(left.finishedAt))
|
||||
.map((record) => applyRunningDisplayState(record, currentState));
|
||||
}
|
||||
|
||||
function summarizeAccountRunHistory(records = []) {
|
||||
return records.reduce((summary, record) => {
|
||||
const retryCount = normalizeRetryCount(record.retryCount);
|
||||
const status = getRecordDisplayStatus(record);
|
||||
summary.total += 1;
|
||||
if (record.finalStatus === 'success') {
|
||||
if (status === 'success') {
|
||||
summary.success += 1;
|
||||
} else if (record.finalStatus === 'failed') {
|
||||
} else if (status === 'running') {
|
||||
summary.running += 1;
|
||||
} else if (status === 'failed') {
|
||||
summary.failed += 1;
|
||||
} else if (record.finalStatus === 'stopped') {
|
||||
} else if (status === 'stopped') {
|
||||
summary.stopped += 1;
|
||||
}
|
||||
if (retryCount > 0) {
|
||||
@@ -189,6 +251,7 @@
|
||||
}, {
|
||||
total: 0,
|
||||
success: 0,
|
||||
running: 0,
|
||||
failed: 0,
|
||||
stopped: 0,
|
||||
retryRecordCount: 0,
|
||||
@@ -227,21 +290,44 @@
|
||||
}
|
||||
|
||||
function getStatusMeta(record = {}) {
|
||||
if (record.finalStatus === 'success') {
|
||||
const status = getRecordDisplayStatus(record);
|
||||
if (status === 'success') {
|
||||
return { kind: 'success', label: '成功' };
|
||||
}
|
||||
if (record.finalStatus === 'stopped') {
|
||||
if (status === 'running') {
|
||||
return { kind: 'running', label: '正在运行' };
|
||||
}
|
||||
if (status === 'stopped') {
|
||||
return { kind: 'stopped', label: '停止' };
|
||||
}
|
||||
return { kind: 'failed', label: '失败' };
|
||||
}
|
||||
|
||||
function getRecordSummaryText(record = {}) {
|
||||
if (record.finalStatus === 'success') {
|
||||
const status = getRecordDisplayStatus(record);
|
||||
if (record.displaySummary) {
|
||||
return String(record.displaySummary || '').trim();
|
||||
}
|
||||
if (status === 'success') {
|
||||
return '流程完成';
|
||||
}
|
||||
if (status === 'running') {
|
||||
return '正在运行';
|
||||
}
|
||||
|
||||
return String(record.failureLabel || '').trim() || '流程失败';
|
||||
return String(record.failureDetail || record.reason || '').trim()
|
||||
|| String(record.failureLabel || '').trim()
|
||||
|| '流程失败';
|
||||
}
|
||||
|
||||
function getRecordTooltipText(record = {}, summaryText = '') {
|
||||
const recordTitle = getRecordTitle(record);
|
||||
const status = getRecordDisplayStatus(record);
|
||||
const detail = String(record.displaySummary || record.failureDetail || record.reason || '').trim();
|
||||
if (status === 'success' || status === 'running' || !detail || detail === recordTitle) {
|
||||
return recordTitle;
|
||||
}
|
||||
return `${recordTitle}\n${detail}`;
|
||||
}
|
||||
|
||||
function getFilterConfig(filterKey = activeFilter) {
|
||||
@@ -378,6 +464,7 @@
|
||||
const summary = summarizeAccountRunHistory(allRecords);
|
||||
dom.accountRecordsStats.innerHTML = [
|
||||
createStatChip('all', summary.total),
|
||||
createStatChip('running', summary.running),
|
||||
createStatChip('success', summary.success),
|
||||
createStatChip('failed', summary.failed),
|
||||
createStatChip('stopped', summary.stopped),
|
||||
@@ -449,9 +536,9 @@
|
||||
const recordId = buildRecordId(record);
|
||||
const primaryIdentifier = getRecordPrimaryIdentifier(record) || '(空账号)';
|
||||
const secondaryIdentifier = getRecordSecondaryIdentifier(record);
|
||||
const recordTitle = getRecordTitle(record);
|
||||
const statusMeta = getStatusMeta(record);
|
||||
const summaryText = getRecordSummaryText(record);
|
||||
const recordTitle = getRecordTooltipText(record, summaryText);
|
||||
const retryCount = normalizeRetryCount(record.retryCount);
|
||||
const isSelected = selectedRecordIds.has(recordId);
|
||||
const itemClassNames = [
|
||||
|
||||
+20
-2
@@ -2985,6 +2985,12 @@ header {
|
||||
border-color: color-mix(in srgb, var(--green) 16%, var(--border));
|
||||
}
|
||||
|
||||
.account-records-stat.is-running {
|
||||
color: var(--blue);
|
||||
background: var(--blue-soft);
|
||||
border-color: color-mix(in srgb, var(--blue) 16%, var(--border));
|
||||
}
|
||||
|
||||
.account-records-stat.is-failed {
|
||||
color: var(--red);
|
||||
background: var(--red-soft);
|
||||
@@ -3158,8 +3164,11 @@ header {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow-wrap: anywhere;
|
||||
white-space: normal;
|
||||
color: var(--text-secondary);
|
||||
font-size: 11px;
|
||||
line-height: 1.4;
|
||||
@@ -3186,6 +3195,15 @@ header {
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
.account-record-item.is-running {
|
||||
border-color: color-mix(in srgb, var(--blue) 14%, var(--border-subtle));
|
||||
}
|
||||
|
||||
.account-record-item.is-running .account-record-item-status {
|
||||
background: var(--blue-soft);
|
||||
color: var(--blue);
|
||||
}
|
||||
|
||||
.account-record-item.is-failed {
|
||||
border-color: color-mix(in srgb, var(--red) 14%, var(--border-subtle));
|
||||
}
|
||||
|
||||
@@ -2065,6 +2065,23 @@ function syncLatestState(nextState) {
|
||||
renderAccountRecords(latestState);
|
||||
}
|
||||
|
||||
let accountRunHistoryRefreshTimer = null;
|
||||
|
||||
function scheduleAccountRunHistoryRefresh(delayMs = 150) {
|
||||
if (accountRunHistoryRefreshTimer) {
|
||||
clearTimeout(accountRunHistoryRefreshTimer);
|
||||
}
|
||||
accountRunHistoryRefreshTimer = setTimeout(() => {
|
||||
accountRunHistoryRefreshTimer = null;
|
||||
chrome.runtime.sendMessage({ type: 'GET_STATE', source: 'sidepanel' }).then(state => {
|
||||
syncLatestState(state);
|
||||
syncAutoRunState(state);
|
||||
updateStatusDisplay(latestState);
|
||||
updateButtonStates();
|
||||
}).catch(() => { });
|
||||
}, Math.max(0, Number(delayMs) || 0));
|
||||
}
|
||||
|
||||
function normalizeOperationDelayEnabled(value) {
|
||||
return typeof value === 'boolean' ? value : true;
|
||||
}
|
||||
@@ -13380,6 +13397,7 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
||||
appendLog(message.payload);
|
||||
if (message.payload.level === 'error') {
|
||||
showToast(message.payload.message, 'error');
|
||||
scheduleAccountRunHistoryRefresh();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -14135,6 +14153,9 @@ chrome.runtime.onMessage.addListener((message, _sender, sendResponse) => {
|
||||
applyAutoRunStatus(message.payload);
|
||||
updateStatusDisplay(latestState);
|
||||
updateButtonStates();
|
||||
if (!['scheduled', 'running', 'waiting_step', 'waiting_email', 'retrying', 'waiting_interval'].includes(message.payload.phase)) {
|
||||
scheduleAccountRunHistoryRefresh();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user