function escapeHtml(value) { return String(value) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); } function renderNode(node) { if (node.type === 'workflow') { const badgeClass = node.active ? 'bg-success' : 'bg-secondary'; const badgeText = node.active ? '有効' : '無効'; return `
  • ${escapeHtml(node.name)} ${badgeText}
  • `; } return `
  • 📁 ${escapeHtml(node.name)}
  • `; } function renderFolderTree(tree) { if (!tree || tree.length === 0) return ''; return tree.map(renderNode).join('\n'); } const EXECUTION_BADGE = { success: 'bg-success', error: 'bg-danger', crashed: 'bg-danger', running: 'bg-primary', waiting: 'bg-warning text-dark', canceled: 'bg-secondary', new: 'bg-secondary', unknown: 'bg-secondary', }; const EXECUTION_STATUS_LABEL = { success: '成功', error: 'エラー', crashed: 'クラッシュ', running: '実行中', waiting: '待機中', canceled: 'キャンセル', new: '新規', unknown: '不明', }; function formatJst(isoString) { if (!isoString) return ''; const utc = new Date(isoString); const jst = new Date(utc.getTime() + 9 * 60 * 60 * 1000); const pad = (n) => String(n).padStart(2, '0'); return `${jst.getUTCFullYear()}-${pad(jst.getUTCMonth() + 1)}-${pad(jst.getUTCDate())} ${pad(jst.getUTCHours())}:${pad(jst.getUTCMinutes())}:${pad(jst.getUTCSeconds())}`; } function renderExecutionList(executions) { if (!executions || executions.length === 0) { return '

    実行履歴なし

    '; } const rows = executions .map((e) => { const badgeClass = EXECUTION_BADGE[e.status] || 'bg-secondary'; const statusLabel = EXECUTION_STATUS_LABEL[e.status] || e.status; return ` ${escapeHtml(formatJst(e.startedAt))} ${escapeHtml(statusLabel)} `; }) .join('\n'); return `${rows}
    開始日時(JST)状態
    `; } function renderExecutionDetail(execution) { const runData = (execution.data && execution.data.resultData && execution.data.resultData.runData) || {}; const rows = Object.entries(runData) .map(([nodeName, runs]) => { const lastRun = runs[runs.length - 1] || {}; const hasError = Boolean(lastRun.error); const badgeClass = hasError ? 'bg-danger' : 'bg-success'; const badgeText = hasError ? 'エラー' : '成功'; const errorMessage = hasError ? escapeHtml(lastRun.error.message || '') : ''; return ` ${escapeHtml(nodeName)} ${badgeText} ${errorMessage} `; }) .join('\n'); return `${rows}
    ノード結果エラー内容
    `; } function renderN8nPage(tree) { const treeHtml = renderFolderTree(tree); return ` n8nワークフロー

    ワークフロー一覧

      ${treeHtml}

    実行履歴

    ワークフローを選択してください

    実行詳細

    実行を選択してください

    `; } module.exports = { renderFolderTree, renderExecutionList, renderExecutionDetail, renderN8nPage };