- Move ai_analyze tool execution to Service Worker to avoid postMessage timeouts; system prompt built in app layer and passed to SW - Add full response JSON display for LLM API logs (fetch on expand) - Improve PostMessage logging: use source labels (应用页面/SW) instead of direction, filter debug panel messages, support request-response linking - Add waitForStorageRestore() to ensure RPC handlers return complete data - Remove syncTasksToClients() in favor of paginated RPC queries - Better VideoGenerationFailedError detection for business failures - Clean up debug console.log statements 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
146 lines
4.2 KiB
JavaScript
146 lines
4.2 KiB
JavaScript
/**
|
|
* SW Debug Panel - PostMessage Entry Component
|
|
*/
|
|
|
|
import { formatTime, escapeHtml } from './utils.js';
|
|
|
|
/**
|
|
* Get a display-friendly label for the client type
|
|
* @param {string} clientType - The client type ('main', 'debug', 'other')
|
|
* @returns {string}
|
|
*/
|
|
function getClientTypeLabel(clientType) {
|
|
switch (clientType) {
|
|
case 'main':
|
|
return '应用页面';
|
|
case 'debug':
|
|
return '调试面板';
|
|
default:
|
|
return '其他';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a CSS class for the client type badge
|
|
* @param {string} clientType - The client type
|
|
* @returns {string}
|
|
*/
|
|
function getClientTypeClass(clientType) {
|
|
switch (clientType) {
|
|
case 'main':
|
|
return 'client-type-main';
|
|
case 'debug':
|
|
return 'client-type-debug';
|
|
default:
|
|
return 'client-type-other';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Format JSON data for display (no truncation - show all data)
|
|
* @param {any} data
|
|
* @returns {string}
|
|
*/
|
|
function formatData(data) {
|
|
if (data === undefined) return '<span class="pm-undefined">undefined</span>';
|
|
if (data === null) return '<span class="pm-null">null</span>';
|
|
|
|
try {
|
|
const str = JSON.stringify(data, null, 2);
|
|
return escapeHtml(str);
|
|
} catch {
|
|
return escapeHtml(String(data));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a preview of the message data (collapsed row preview)
|
|
* @param {any} data
|
|
* @returns {string}
|
|
*/
|
|
function getDataPreview(data) {
|
|
if (data === undefined || data === null) return '';
|
|
|
|
try {
|
|
const str = JSON.stringify(data);
|
|
// Show more content in preview (500 chars), CSS handles overflow
|
|
if (str.length > 500) {
|
|
return escapeHtml(str.slice(0, 500)) + '...';
|
|
}
|
|
return escapeHtml(str);
|
|
} catch {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a PostMessage log entry DOM element
|
|
* @param {object} log - The log entry object
|
|
* @param {boolean} isExpanded - Initial expanded state
|
|
* @param {Function} onToggle - Callback when expand state changes (id, expanded)
|
|
* @returns {HTMLElement}
|
|
*/
|
|
export function createPostMessageEntry(log, isExpanded = false, onToggle = null) {
|
|
const entry = document.createElement('div');
|
|
// 使用 log-entry 作为基础类,与 Fetch 日志统一
|
|
entry.className = `log-entry pm-entry${isExpanded ? ' expanded' : ''}`;
|
|
entry.dataset.id = log.id;
|
|
|
|
// 来源标签:从 SW 角度看,receive = 应用页面发送,send = SW 发送
|
|
const sourceLabel = log.direction === 'receive' ? '应用页面' : 'SW';
|
|
const sourceClass = log.direction === 'receive' ? 'source-main' : 'source-sw';
|
|
|
|
const messageType = log.messageType || 'unknown';
|
|
const dataPreview = getDataPreview(log.data);
|
|
|
|
entry.innerHTML = `
|
|
<div class="log-header pm-header">
|
|
<span class="log-toggle"><span class="arrow">▶</span></span>
|
|
<span class="log-time pm-time">${formatTime(log.timestamp)}</span>
|
|
<span class="pm-source ${sourceClass}">${sourceLabel}</span>
|
|
<span class="pm-type">${escapeHtml(messageType)}</span>
|
|
<span class="log-url pm-preview">${dataPreview}</span>
|
|
</div>
|
|
<div class="log-details pm-details">
|
|
<div class="detail-section">
|
|
<h4>基本信息</h4>
|
|
<pre>来源: ${sourceLabel}
|
|
消息类型: ${messageType}
|
|
${log.clientUrl ? `页面: ${log.clientUrl}` : ''}
|
|
${log.clientId ? `ClientID: ${log.clientId}` : ''}
|
|
时间: ${new Date(log.timestamp).toLocaleString('zh-CN')}</pre>
|
|
</div>
|
|
<div class="detail-section">
|
|
<h4>消息数据</h4>
|
|
<pre>${formatData(log.data)}</pre>
|
|
</div>
|
|
${log.response !== undefined ? `
|
|
<div class="detail-section">
|
|
<h4>响应数据</h4>
|
|
<pre style="border-left: 3px solid var(--success-color);">${formatData(log.response)}</pre>
|
|
</div>
|
|
` : ''}
|
|
${log.error ? `
|
|
<div class="detail-section">
|
|
<h4>错误信息</h4>
|
|
<pre style="color: var(--error-color);">${escapeHtml(log.error)}</pre>
|
|
</div>
|
|
` : ''}
|
|
</div>
|
|
`;
|
|
|
|
// Toggle expand on toggle button click
|
|
const toggleBtn = entry.querySelector('.log-toggle');
|
|
if (toggleBtn) {
|
|
toggleBtn.addEventListener('click', (e) => {
|
|
e.stopPropagation();
|
|
const isNowExpanded = entry.classList.toggle('expanded');
|
|
if (onToggle) {
|
|
onToggle(log.id, isNowExpanded);
|
|
}
|
|
});
|
|
}
|
|
|
|
return entry;
|
|
}
|